Commit 1312c125 authored by CZ1004's avatar CZ1004

Merge branch 'dev_main' into dev_zhaoqian

* dev_main:
  1
  设置界面 和 其它优化
  【修改】删除方法
  设置及二级界面
  设置及二级界面

# Conflicts:
#	PhoneManager/Class/Page/Home/Controller/HomePhotosDetailViewController.swift
parents 881bb320 446e6dd9
......@@ -2,7 +2,7 @@
// LockSreen.swift
// LockSreen
//
// Created by edy on 2025/5/12.
// Created by edy on 2025/5/19.
//
import WidgetKit
......@@ -115,3 +115,4 @@ struct lockArcShape: Shape {
return path
}
}
......@@ -2,12 +2,13 @@
// LockSreenBundle.swift
// LockSreen
//
// Created by edy on 2025/5/12.
// Created by edy on 2025/5/19.
//
import WidgetKit
import SwiftUI
let kind: String = "LockSreen"
let kind1: String = "LockSreen1"
......@@ -56,3 +57,4 @@ struct LockBothSreen: Widget {
.supportedFamilies([.accessoryRectangular])
}
}
......@@ -11,6 +11,9 @@
0496DEF32D9E3F58005B2834 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04BD915D2D9D68AD00055CEB /* WidgetKit.framework */; };
0496DEF42D9E3F58005B2834 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04BD915F2D9D68AD00055CEB /* SwiftUI.framework */; };
0496DEFF2D9E3F59005B2834 /* widgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 0496DEF22D9E3F57005B2834 /* widgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
049F146C2DDB1F64007B5A9B /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04BD915D2D9D68AD00055CEB /* WidgetKit.framework */; };
049F146D2DDB1F64007B5A9B /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04BD915F2D9D68AD00055CEB /* SwiftUI.framework */; };
049F14782DDB1F66007B5A9B /* LockSreenExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 049F146B2DDB1F64007B5A9B /* LockSreenExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
04BBB4E62DC0748F00D7E3AB /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04BBB4E52DC0748F00D7E3AB /* StoreKit.framework */; };
04CF31702DA7E78F001C87CA /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 04BD7A442DA3BA1700A24C4B /* Intents.framework */; };
04CF31772DA7E790001C87CA /* ChargeShow.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 04CF316F2DA7E78F001C87CA /* ChargeShow.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
......@@ -28,6 +31,13 @@
remoteGlobalIDString = 0496DEF12D9E3F57005B2834;
remoteInfo = widgetExtension;
};
049F14762DDB1F66007B5A9B /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = EB388E532D8A61A800629B0D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 049F146A2DDB1F64007B5A9B;
remoteInfo = LockSreenExtension;
};
04CF31752DA7E78F001C87CA /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = EB388E532D8A61A800629B0D /* Project object */;
......@@ -56,6 +66,7 @@
files = (
0496DEFF2D9E3F59005B2834 /* widgetExtension.appex in Embed Foundation Extensions */,
04CF31772DA7E790001C87CA /* ChargeShow.appex in Embed Foundation Extensions */,
049F14782DDB1F66007B5A9B /* LockSreenExtension.appex in Embed Foundation Extensions */,
);
name = "Embed Foundation Extensions";
runOnlyForDeploymentPostprocessing = 0;
......@@ -65,6 +76,8 @@
/* Begin PBXFileReference section */
0496DEF22D9E3F57005B2834 /* widgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = widgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
0496DF042D9E3FA7005B2834 /* widgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = widgetExtension.entitlements; sourceTree = "<group>"; };
049F146B2DDB1F64007B5A9B /* LockSreenExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = LockSreenExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
049F147F2DDB210B007B5A9B /* LockSreenExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LockSreenExtension.entitlements; sourceTree = "<group>"; };
04BBB4E52DC0748F00D7E3AB /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
04BD7A442DA3BA1700A24C4B /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; };
04BD7A4F2DA3BA1700A24C4B /* IntentsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IntentsUI.framework; path = System/Library/Frameworks/IntentsUI.framework; sourceTree = SDKROOT; };
......@@ -94,6 +107,13 @@
);
target = 0496DEF12D9E3F57005B2834 /* widgetExtension */;
};
049F147C2DDB1F66007B5A9B /* Exceptions for "LockSreen" folder in "LockSreenExtension" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Info.plist,
);
target = 049F146A2DDB1F64007B5A9B /* LockSreenExtension */;
};
04CF317B2DA7E790001C87CA /* Exceptions for "ChargeShow" folder in "ChargeShow" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
......@@ -120,6 +140,14 @@
path = widget;
sourceTree = "<group>";
};
049F146E2DDB1F64007B5A9B /* LockSreen */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
049F147C2DDB1F66007B5A9B /* Exceptions for "LockSreen" folder in "LockSreenExtension" target */,
);
path = LockSreen;
sourceTree = "<group>";
};
04CF31712DA7E78F001C87CA /* ChargeShow */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
......@@ -148,6 +176,15 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
049F14682DDB1F64007B5A9B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
049F146D2DDB1F64007B5A9B /* SwiftUI.framework in Frameworks */,
049F146C2DDB1F64007B5A9B /* WidgetKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
04CF316C2DA7E78F001C87CA /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
......@@ -196,11 +233,13 @@
EB388E522D8A61A800629B0D = {
isa = PBXGroup;
children = (
049F147F2DDB210B007B5A9B /* LockSreenExtension.entitlements */,
04CF317C2DA7E7BE001C87CA /* Intents.intentdefinition */,
0496DF042D9E3FA7005B2834 /* widgetExtension.entitlements */,
EB388E5D2D8A61A800629B0D /* PhoneManager */,
0496DEF52D9E3F58005B2834 /* widget */,
04CF31712DA7E78F001C87CA /* ChargeShow */,
049F146E2DDB1F64007B5A9B /* LockSreen */,
EB388E5C2D8A61A800629B0D /* Products */,
CB2ACD1E9442B4500087E831 /* Pods */,
27ECDADD9059AB5043B8E1E9 /* Frameworks */,
......@@ -213,6 +252,7 @@
EB388E5B2D8A61A800629B0D /* PhoneManager.app */,
0496DEF22D9E3F57005B2834 /* widgetExtension.appex */,
04CF316F2DA7E78F001C87CA /* ChargeShow.appex */,
049F146B2DDB1F64007B5A9B /* LockSreenExtension.appex */,
);
name = Products;
sourceTree = "<group>";
......@@ -240,6 +280,28 @@
productReference = 0496DEF22D9E3F57005B2834 /* widgetExtension.appex */;
productType = "com.apple.product-type.app-extension";
};
049F146A2DDB1F64007B5A9B /* LockSreenExtension */ = {
isa = PBXNativeTarget;
buildConfigurationList = 049F14792DDB1F66007B5A9B /* Build configuration list for PBXNativeTarget "LockSreenExtension" */;
buildPhases = (
049F14672DDB1F64007B5A9B /* Sources */,
049F14682DDB1F64007B5A9B /* Frameworks */,
049F14692DDB1F64007B5A9B /* Resources */,
);
buildRules = (
);
dependencies = (
);
fileSystemSynchronizedGroups = (
049F146E2DDB1F64007B5A9B /* LockSreen */,
);
name = LockSreenExtension;
packageProductDependencies = (
);
productName = LockSreenExtension;
productReference = 049F146B2DDB1F64007B5A9B /* LockSreenExtension.appex */;
productType = "com.apple.product-type.app-extension";
};
04CF316E2DA7E78F001C87CA /* ChargeShow */ = {
isa = PBXNativeTarget;
buildConfigurationList = 04CF31782DA7E790001C87CA /* Build configuration list for PBXNativeTarget "ChargeShow" */;
......@@ -278,6 +340,7 @@
dependencies = (
0496DEFE2D9E3F59005B2834 /* PBXTargetDependency */,
04CF31762DA7E78F001C87CA /* PBXTargetDependency */,
049F14772DDB1F66007B5A9B /* PBXTargetDependency */,
);
fileSystemSynchronizedGroups = (
EB388E5D2D8A61A800629B0D /* PhoneManager */,
......@@ -300,6 +363,9 @@
0496DEF12D9E3F57005B2834 = {
CreatedOnToolsVersion = 16.2;
};
049F146A2DDB1F64007B5A9B = {
CreatedOnToolsVersion = 16.2;
};
04CF316E2DA7E78F001C87CA = {
CreatedOnToolsVersion = 16.2;
};
......@@ -330,6 +396,7 @@
EB388E5A2D8A61A800629B0D /* PhoneManager */,
0496DEF12D9E3F57005B2834 /* widgetExtension */,
04CF316E2DA7E78F001C87CA /* ChargeShow */,
049F146A2DDB1F64007B5A9B /* LockSreenExtension */,
);
};
/* End PBXProject section */
......@@ -342,6 +409,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
049F14692DDB1F64007B5A9B /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
04CF316D2DA7E78F001C87CA /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
......@@ -425,6 +499,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
049F14672DDB1F64007B5A9B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
04CF316B2DA7E78F001C87CA /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
......@@ -449,6 +530,11 @@
target = 0496DEF12D9E3F57005B2834 /* widgetExtension */;
targetProxy = 0496DEFD2D9E3F59005B2834 /* PBXContainerItemProxy */;
};
049F14772DDB1F66007B5A9B /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 049F146A2DDB1F64007B5A9B /* LockSreenExtension */;
targetProxy = 049F14762DDB1F66007B5A9B /* PBXContainerItemProxy */;
};
04CF31762DA7E78F001C87CA /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 04CF316E2DA7E78F001C87CA /* ChargeShow */;
......@@ -525,6 +611,72 @@
};
name = Release;
};
049F147A2DDB1F66007B5A9B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = LockSreenExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 6K23946NQ5;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = LockSreen/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = LockSreen;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.app.phonemanager.lockSreenWidget;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
049F147B2DDB1F66007B5A9B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = LockSreenExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 6K23946NQ5;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = LockSreen/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = LockSreen;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.app.phonemanager.lockSreenWidget;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
04CF31792DA7E790001C87CA /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
......@@ -813,6 +965,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
049F14792DDB1F66007B5A9B /* Build configuration list for PBXNativeTarget "LockSreenExtension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
049F147A2DDB1F66007B5A9B /* Debug */,
049F147B2DDB1F66007B5A9B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
04CF31782DA7E790001C87CA /* Build configuration list for PBXNativeTarget "ChargeShow" */ = {
isa = XCConfigurationList;
buildConfigurations = (
......
......@@ -48,6 +48,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
AdvManager.shared.initAdertisementSDK()
PMEmailManager.shareManager.restore()
SettingConfiguration.share.initData()
HapticManager.share.setupHapticEngine()
// 相册基本资源加载
PhotoManager.shared.config()
......
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "ic_hints_faq-+.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ic_hints_faq-+@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_hints_faq-+@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Frame.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Frame.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Group_1171275098.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Group_1171275098@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Group_1171275098@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Group_1171275095.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Group_1171275095@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Group_1171275095@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Group_1171275096.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Group_1171275096@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Group_1171275096@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Group_1171275155.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Group_1171275155@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Group_1171275155@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Group_1171275097.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Group_1171275097@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Group_1171275097@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Group_1171275074.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Group_1171275074@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Group_1171275074@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Group_1171275076.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Group_1171275076@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Group_1171275076@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Group_1171275077.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Group_1171275077@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Group_1171275077@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Group_1171275154.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Group_1171275154@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Group_1171275154@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Group_1171275099.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Group_1171275099@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Group_1171275099@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Frame.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Group_1171275083.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Group_1171275083@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Group_1171275083@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
//
// PMAboutUsController.swift
// PhoneManager
//
// Created by edy on 2025/5/19.
//
import UIKit
import MessageUI
class PMAboutUsController: BaseViewController, MFMailComposeViewControllerDelegate {
@IBOutlet weak var despLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
titleView.model.title = "About Us"
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setConfigs()
addClick()
}
private func setConfigs() -> Void {
var mutableText:NSMutableAttributedString = NSMutableAttributedString(attributedString: despLabel.attributedText ?? NSMutableAttributedString(string: ""))
let paragraph = NSMutableParagraphStyle()
paragraph.lineSpacing = 2
mutableText.addAttributes([NSAttributedString.Key.paragraphStyle : paragraph], range: NSRange(location: 0, length: mutableText.length))
if let rang = mutableText.string.range(of: "OUR APPROACH") {
let startIndex = rang.lowerBound
let endIndex = rang.upperBound
let start = mutableText.string.distance(from: mutableText.string.startIndex, to: startIndex)
let end = mutableText.string.distance(from: mutableText.string.startIndex, to: endIndex)
mutableText.addAttributes([NSAttributedString.Key.font : UIFont.systemFont(ofSize: 16, weight: .bold)], range: NSRange(location: start, length: end - start))
}
if let rang = mutableText.string.range(of: "apps.columbusdev.com") {
let startIndex = rang.lowerBound
let endIndex = rang.upperBound
let start = mutableText.string.distance(from: mutableText.string.startIndex, to: startIndex)
let end = mutableText.string.distance(from: mutableText.string.startIndex, to: endIndex)
mutableText.addAttributes([NSAttributedString.Key.font : UIFont.systemFont(ofSize: 14, weight: .regular),NSAttributedString.Key.foregroundColor:UIColor.colorWithHex(hexStr: "#0082FF"),.underlineStyle:NSUnderlineStyle.single.rawValue,.underlineColor:UIColor.colorWithHex(hexStr: "#0082FF")],
range: NSRange(location: start, length: end - start))
}
if let rang = mutableText.string.range(of: "ligaili1217@163.com") {
let startIndex = rang.lowerBound
let endIndex = rang.upperBound
let start = mutableText.string.distance(from: mutableText.string.startIndex, to: startIndex)
let end = mutableText.string.distance(from: mutableText.string.startIndex, to: endIndex)
mutableText.addAttributes([NSAttributedString.Key.font : UIFont.systemFont(ofSize: 14, weight: .regular),NSAttributedString.Key.foregroundColor:UIColor.colorWithHex(hexStr: "#0082FF"),.underlineStyle:NSUnderlineStyle.single.rawValue,.underlineColor:UIColor.colorWithHex(hexStr: "#0082FF")],
range: NSRange(location: start, length: end - start))
}
despLabel.attributedText = mutableText
}
private func addClick() -> Void {
let click = ["apps.columbusdev.com","ligaili1217@163.com"]
despLabel.AddTapped(click) {[weak self] text in
guard let self = self else { return }
if text == click[0] {
guard let url = URL(string: "https://apps.columbusdev.com/") else { return }
UIApplication.shared.open(url)
}else{
self.sendMail()
}
}
}
private func sendMail() -> Void {
let email = "ligaili1217@163.com"
let subject = ""//邮件主题
let body = ""//邮件正文
let defaultURL = URL(string: "mailto:\(email)?subject=\(subject)&body=\(body)")
let application = UIApplication.shared
if let url = defaultURL,application.canOpenURL(url) {
application.open(url)
}else{
print("Unable to send email")
PMAlert(title: nil, messsage: "", action: ["Ok"])
}
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: (any Error)?) {
controller.dismiss(animated: true)
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="PMAboutUsController" customModule="PhoneManager" customModuleProvider="target">
<connections>
<outlet property="despLabel" destination="zuX-UN-ngF" id="z6D-sl-gOi"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tXM-qs-7LP">
<rect key="frame" x="16" y="139" width="361" height="679"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="TrU-Y1-jr0">
<rect key="frame" x="0.0" y="0.0" width="361" height="583.33333333333337"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zuX-UN-ngF">
<rect key="frame" x="16" y="16" width="329" height="551.33333333333337"/>
<mutableString key="text">OUR APPROACH
Curiosity drives our exploration. Dedication fuels our efforts.Collaboration binds us together. At the core of everything we do are the people we serve.

We persevere through challenges and find joy in our shared progress. We recognize that collective wisdom surpasses individual insights.

We respect every voice, understanding that diverse perspectives enrich our work. We approach each task with open minds and a hunger to learn.

We know that excellence is achieved through consistent, incremental growth. We value clarity and simplicity in all we create. We stay flexible, ready to pivot when needed.

We welcome change as an opportunity to evolve and keep moving forward. We understand setbacks are stepping stones to success. We take risks, learn from failures, and use them as motivation to improve. We're committed to our unique way of working and making a difference. 

apps.columbusdev.com
ligaili1217@163.com

©2025 2025 Columbus Trading. All rights reserved.</mutableString>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.94901960784313721" green="0.96470588235294119" blue="0.9882352941176471" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="zuX-UN-ngF" firstAttribute="leading" secondItem="TrU-Y1-jr0" secondAttribute="leading" constant="16" id="GRf-GR-BeP"/>
<constraint firstAttribute="trailing" secondItem="zuX-UN-ngF" secondAttribute="trailing" constant="16" id="NQJ-41-oOR"/>
<constraint firstItem="zuX-UN-ngF" firstAttribute="top" secondItem="TrU-Y1-jr0" secondAttribute="top" constant="16" id="cXh-Xx-LFC"/>
<constraint firstAttribute="bottom" secondItem="zuX-UN-ngF" secondAttribute="bottom" constant="16" id="sCh-Wo-z7z"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="Radius">
<real key="value" value="12"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="TrU-Y1-jr0" secondAttribute="bottom" id="2Yf-R2-5ee"/>
<constraint firstAttribute="trailing" secondItem="TrU-Y1-jr0" secondAttribute="trailing" id="3P5-fh-O54"/>
<constraint firstItem="TrU-Y1-jr0" firstAttribute="top" secondItem="tXM-qs-7LP" secondAttribute="top" id="SSk-ev-Zpu"/>
<constraint firstItem="TrU-Y1-jr0" firstAttribute="centerX" secondItem="tXM-qs-7LP" secondAttribute="centerX" id="lV6-id-DLi"/>
<constraint firstItem="TrU-Y1-jr0" firstAttribute="leading" secondItem="tXM-qs-7LP" secondAttribute="leading" id="qgC-EG-fwb"/>
</constraints>
</scrollView>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="tXM-qs-7LP" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="80" id="7gF-2c-7Yc"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="tXM-qs-7LP" secondAttribute="bottom" id="PVp-uI-af2"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="tXM-qs-7LP" secondAttribute="trailing" constant="16" id="lbt-x9-4qq"/>
<constraint firstItem="tXM-qs-7LP" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="16" id="lu9-Zo-4Sa"/>
</constraints>
<point key="canvasLocation" x="131" y="-12"/>
</view>
</objects>
<resources>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
......@@ -177,8 +177,10 @@ extension CompressController:WaterfallMutiSectionDelegate,UICollectionViewDataSo
// 这里临时管理一个当前选择的资源
if choose == true && !self.selectedModel.contains(model) {
self.selectedModel.append(model)
self.vibrate()
}
if choose == false && self.selectedModel.contains(model){
self.vibrate()
if let index = selectedModel.firstIndex(of: model) {
selectedModel.remove(at: index)
}
......
......@@ -234,6 +234,7 @@ class CompressQualityController : BaseViewController{
self.mediumQualityView.selectedImageView.image = UIImage(named: "ic_sel_com")
self.highQualityView.selectedImageView.image = UIImage(named: "ic_sel_com")
setButtonTitleByType(type: .low)
self.vibrate()
}
self.mediumQualityView.callBack = {[weak self] type in
......@@ -246,6 +247,7 @@ class CompressQualityController : BaseViewController{
self.mediumQualityView.selectedImageView.image = UIImage(named: "ic_unsel_com")
self.highQualityView.selectedImageView.image = UIImage(named: "ic_sel_com")
setButtonTitleByType(type: .mid)
self.vibrate()
}
self.highQualityView.callBack = {[weak self] type in
......@@ -258,6 +260,7 @@ class CompressQualityController : BaseViewController{
self.mediumQualityView.selectedImageView.image = UIImage(named: "ic_sel_com")
self.highQualityView.selectedImageView.image = UIImage(named: "ic_unsel_com")
setButtonTitleByType(type: .high)
self.vibrate()
}
......
......@@ -138,7 +138,7 @@ extension ContactBackupDetailViewController:UITableViewDelegate,UITableViewDataS
let sectionTitle = sectionTitles[indexPath.section]
let contact = sectionedContacts[sectionTitle]?[indexPath.row]
cell.model = contact
cell.nameLabel.text = contact?.fullName
cell.nameLabel.text = contact?.fullName.count ?? 0 > 0 ? contact?.fullName : "Untitled contact person"
return cell
}
......
......@@ -140,7 +140,7 @@ extension ContactAllView : UITableViewDataSource,UITableViewDelegate {
let sectionTitle = sectionTitles[indexPath.section]
let contact = sectionedContacts[sectionTitle]?[indexPath.row]
cell.model = contact
cell.nameLabel.text = contact?.fullName
cell.nameLabel.text = contact?.fullName.count ?? 0 > 0 ? contact?.fullName : "Untitled contact person"
if self.selectedContacts.contains(where: { $0.identifier == contact!.identifier }) {
cell.selectButton.isSelected = true
}else {
......@@ -153,7 +153,7 @@ extension ContactAllView : UITableViewDataSource,UITableViewDelegate {
}else{
self.selectedContacts.removeAll(where: { $0.identifier == model.identifier })
}
self.vibrate()
DispatchQueue.main.async {
// 判断button是否显示
if self.selectedContacts.count > 0 {
......
......@@ -130,6 +130,7 @@ extension ContactDupNormalView : UITableViewDelegate,UITableViewDataSource{
cell.model = self.dataSourceModel[indexPath.section][indexPath.row]
cell.cellSelectCallCack = {[weak self]index,choose in
guard let self else {return}
self.vibrate()
if choose {
self.saveSelectModel(index: index)
}else {
......
......@@ -159,7 +159,7 @@ extension ContactNormalIncomView : UITableViewDataSource,UITableViewDelegate {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomContactAllViewTableViewCell", for: indexPath) as! CustomContactAllViewTableViewCell
let contact = self.dataSourceModel[indexPath.row]
cell.model = contact
cell.nameLabel.text = contact.fullName
cell.nameLabel.text = contact.fullName.count > 0 ? contact.fullName : "Untitled contact person"
if self.selectedContacts.contains(where: { $0.identifier == contact.identifier }) {
cell.selectButton.isSelected = true
}else {
......@@ -167,6 +167,7 @@ extension ContactNormalIncomView : UITableViewDataSource,UITableViewDelegate {
}
cell.buttonSelectCallBack = {[weak self] model,selected in
guard let self else {return}
self.vibrate()
if selected {
self.selectedContacts.append(model)
}else{
......
//
// PMEmailSupportCell.swift
// PhoneManager
//
// Created by edy on 2025/5/19.
//
import UIKit
class PMEmailSupportCell: UITableViewCell {
static let id = "PMEmailSupportCell"
@IBOutlet weak var esLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
var data:FAQDataModel? {
didSet{
esLabel.text = data?.problem ?? ""
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="123" id="KGk-i7-Jjw" customClass="PMEmailSupportCell" customModule="PhoneManager" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="358" height="123"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="358" height="123"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4SX-Xi-udm">
<rect key="frame" x="0.0" y="0.0" width="358" height="113"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="How can I recover deleted photos or videos?" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6bs-U1-uqM">
<rect key="frame" x="16" y="16" width="286" height="81"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="24" id="KBB-uU-vBe"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="14"/>
<color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_left_setting_grey" translatesAutoresizingMaskIntoConstraints="NO" id="eLs-7W-DBt">
<rect key="frame" x="318" y="46.666666666666664" width="20" height="19.999999999999993"/>
<constraints>
<constraint firstAttribute="width" constant="20" id="5pq-Lw-7Bh"/>
<constraint firstAttribute="height" constant="20" id="EcB-PY-v2P"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" red="0.94901960784313721" green="0.96470588235294119" blue="0.9882352941176471" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="eLs-7W-DBt" firstAttribute="centerY" secondItem="4SX-Xi-udm" secondAttribute="centerY" id="C0l-FW-4EX"/>
<constraint firstItem="6bs-U1-uqM" firstAttribute="top" secondItem="4SX-Xi-udm" secondAttribute="top" constant="16" id="GDj-00-bNe"/>
<constraint firstAttribute="trailing" secondItem="eLs-7W-DBt" secondAttribute="trailing" constant="20" id="HAG-83-qxo"/>
<constraint firstAttribute="bottom" secondItem="6bs-U1-uqM" secondAttribute="bottom" constant="16" id="aE0-zU-2xe"/>
<constraint firstItem="6bs-U1-uqM" firstAttribute="leading" secondItem="4SX-Xi-udm" secondAttribute="leading" constant="16" id="hZh-1Y-B5K"/>
<constraint firstItem="eLs-7W-DBt" firstAttribute="leading" secondItem="6bs-U1-uqM" secondAttribute="trailing" constant="16" id="nGx-nB-DAR"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="Radius">
<real key="value" value="12"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="4SX-Xi-udm" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="ClS-G3-1nM"/>
<constraint firstItem="4SX-Xi-udm" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" id="doE-qG-Em3"/>
<constraint firstAttribute="bottom" secondItem="4SX-Xi-udm" secondAttribute="bottom" constant="10" id="g8u-yZ-V1p"/>
<constraint firstAttribute="trailing" secondItem="4SX-Xi-udm" secondAttribute="trailing" id="iXi-hr-caF"/>
</constraints>
</tableViewCellContentView>
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
<color key="backgroundColor" red="0.94901960784313721" green="0.96470588235294119" blue="0.9882352941176471" alpha="1" colorSpace="calibratedRGB"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="Radius">
<real key="value" value="12"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<outlet property="esLabel" destination="6bs-U1-uqM" id="o8k-8Q-cLR"/>
</connections>
<point key="canvasLocation" x="158.77862595419847" y="16.549295774647888"/>
</tableViewCell>
</objects>
<resources>
<image name="icon_left_setting_grey" width="20" height="20"/>
</resources>
</document>
//
// PMEmailSupportController.swift
// PhoneManager
//
// Created by edy on 2025/5/19.
//
import UIKit
import MessageUI
class PMEmailSupportController: BaseViewController {
@IBOutlet weak var emailTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
titleView.model.title = "Email support"
setup()
}
func setup() -> Void {
emailTableView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview().inset(marginLR)
make.top.equalTo(titleView.snp.bottom).offset(10)
}
emailTableView.sectionHeaderHeight = 40
if #available(iOS 15.0, *) {
emailTableView.sectionHeaderTopPadding = 0
} else {
// Fallback on earlier versions
}
emailTableView.register(UINib(nibName: PMEmailSupportCell.id, bundle: nil), forCellReuseIdentifier: PMEmailSupportCell.id)
emailTableView.showsVerticalScrollIndicator = false
let file = Bundle.main.bundleURL.appendingPathComponent("PMEmailSupportData.json")
do{
let dictData = try Data(contentsOf: file)
dataSource = try JSONDecoder().decode([FAQDataModel].self, from: dictData)
}catch{ }
}
var dataSource:[FAQDataModel] = [] {
didSet {
self.emailTableView.reloadData()
}
}
}
extension PMEmailSupportController : UITableViewDelegate,UITableViewDataSource,MFMailComposeViewControllerDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: PMEmailSupportCell.id, for: indexPath) as! PMEmailSupportCell
cell.selectionStyle = .none
cell.data = dataSource[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = UILabel()
header.text = "Please select a request from the following list."
header.textColor = UIColor.colorWithHex(hexStr: "#999999")
header.font = UIFont.systemFont(ofSize: 12)
header.backgroundColor = .white
return header
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let data = dataSource[indexPath.row]
if data.problem != "Other" {
let support = PMEmailSupportDetailController()
support.data = data
self.navigationController?.pushViewController(support, animated: true)
}else{
if MFMailComposeViewController.canSendMail() {
let mail = MFMailComposeViewController()
mail.mailComposeDelegate = self
mail.setSubject("My PhoneManager Experience")
mail.setToRecipients(["ligaili1217@163.com"]) // 收件人地址
let body = String(format: "\n\n%@. iOS %@.%@\n%@", UIDevice.current.detailedModel,UIDevice.current.systemVersion,UIDevice.current.version(),UIDevice.current.identifierForVendor?.uuidString ?? "")
mail.setMessageBody(body, isHTML: false)
self.present(mail, animated: true, completion: nil)
} else {
print("无法发送邮件")
PMAlert(title: nil, messsage: "Unable to send email", action: ["Ok"])
}
}
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: (any Error)?) {
controller.dismiss(animated: true)
}
}
extension UIDevice {
var detailedModel: String {
var systemInfo = utsname()
uname(&systemInfo)
let machineMirror = Mirror(reflecting: systemInfo.machine)
return machineMirror.children.reduce("") { identifier, element in
guard let value = element.value as? Int8, value != 0 else { return identifier }
return identifier + String(UnicodeScalar(UInt8(value)))
}
}
func version() -> String {
let infoDictionary = Bundle.main.infoDictionary
let appVersion = infoDictionary?["CFBundleShortVersionString"] as? String ?? "" // 版本号
let buildNumber = infoDictionary?["CFBundleVersion"] as? String ?? "" // 构建号
return String(format: "App version:%@(%@)",appVersion ,buildNumber)
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="PMEmailSupportController" customModule="PhoneManager" customModuleProvider="target">
<connections>
<outlet property="emailTableView" destination="MCG-EC-mOS" id="PTm-bW-gx1"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="-1" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="MCG-EC-mOS">
<rect key="frame" x="15" y="80" width="363" height="691"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<connections>
<outlet property="dataSource" destination="-1" id="sPO-YK-o5T"/>
<outlet property="delegate" destination="-1" id="VjH-qj-Jd5"/>
</connections>
</tableView>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<point key="canvasLocation" x="117" y="-11"/>
</view>
</objects>
<resources>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
//
// PMEmailSupportDetailController.swift
// PhoneManager
//
// Created by edy on 2025/5/19.
//
import UIKit
class PMEmailSupportDetailController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
setuup()
}
var data:FAQDataModel?
private func setuup() -> Void {
scroll.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview().inset(marginLR)
make.top.equalTo(titleView.snp.bottom).offset(20)
}
tl.snp.makeConstraints { make in
make.left.top.equalToSuperview()
make.width.equalToSuperview()
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tl.text = data?.problem ?? ""
let attribued = addattribed()
self.view.layoutIfNeeded()
let bound = attribued.boundingRect(with: CGSizeMake(view.width - marginLR * 2 - 16 * 2, .infinity), options: .usesLineFragmentOrigin, context: nil)
textView.attributedText = attribued
textView.snp.makeConstraints { make in
make.left.right.equalTo(tl)
make.top.equalTo(tl.snp.bottom).offset(10)
make.height.equalTo(bound.height+(marginLR * 2 + 16 * 2 + 10))
}
DispatchQueue.main.async {
self.scroll.contentSize = CGSizeMake(0, CGRectGetMaxY(self.textView.frame))
}
}
private lazy var tl: UILabel = {
let l = UILabel()
l.font = UIFont.systemFont(ofSize: 14, weight: .bold)
l.textColor = UIColor.colorWithHex(hexStr: "#333333")
l.numberOfLines = 0
scroll.addSubview(l)
return l
}()
private lazy var textView: UITextView = {
let tv = UITextView()
tv.isUserInteractionEnabled = false
tv.Radius = 12
tv.backgroundColor = UIColor.colorWithHex(hexStr: "#F2F6FC")
tv.textContainerInset = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
scroll.addSubview(tv)
return tv
}()
private lazy var scroll: UIScrollView = {
let s = UIScrollView()
s.showsVerticalScrollIndicator = false
s.contentInsetAdjustmentBehavior = .never
view.addSubview(s)
return s
}()
private func addattribed() -> NSMutableAttributedString {
let mutableText = NSMutableAttributedString(string: data?.answer ?? "")
let param = NSMutableParagraphStyle()
param.lineSpacing = 5
mutableText.addAttributes([NSAttributedString.Key.font : UIFont.systemFont(ofSize: 14, weight: .regular),.paragraphStyle:param], range: NSRange(location: 0, length: mutableText.length))
let rangs = data?.bold ?? []
let famat = NSSet(array: rangs)
for text in famat {
if let rang = mutableText.string.range(of: text as! String) {
let startIndex = rang.lowerBound
let endIndex = rang.upperBound
let start = mutableText.string.distance(from: mutableText.string.startIndex, to: startIndex)
let end = mutableText.string.distance(from: mutableText.string.startIndex, to: endIndex)
if end < (data?.answer.count ?? 0) {
mutableText.addAttributes([NSAttributedString.Key.font : UIFont.systemFont(ofSize: 14, weight: .bold)], range: NSRange(location: start, length: end - start))
}
}
}
return mutableText
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="PMEmailSupportDetailController" customModuleProvider="target">
<connections>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
</view>
</objects>
</document>
[
{
"problem":"How to Recover Deleted Photos or Videos?",
"answer":"If you accidentally delete photos or videos through PhoneManager cleanup, iOS will temporarily store them in the \"Recently Deleted\" album for 30 days (they still occupy storage space during this period). To recover: Open the Photos app on your iPhone, go to the \"Recently Deleted\" album, tap \"Select\" in the top-right corner, check the files you need, then tap \"Recover\"; for batch recovery, directly tap \"Recover All\". Note that this album contains both manually deleted files and PhoneManager-cleaned content, and the system will permanently erase them after 30 days. Act promptly to avoid data loss.",
"bold":["\"Recently Deleted\" album","30 days","Photos","\"Select\"","\"Recover All\"","both manually deleted files and PhoneManager-cleaned content","permanently erase them after 30 days"]
},
{
"problem":"Why Isn’t Storage Space Freed Up After Cleanup?",
"answer":"Due to iOS system limitations, photos/videos deleted via PhoneManager are temporarily stored in the \"Recently Deleted\" album for 30 days (they continue to occupy storage space during this period). To free up space immediately, manually empty the album: Open the Photos app on your iPhone, go to the \"Recently Deleted\" album, tap \"Select\" > \"Delete All\" in the top-right corner to permanently remove files. Note that this action will delete both manually removed content and PhoneManager-cleaned files, and data cannot be recovered. Ensure no important files remain before proceeding.",
"bold":["\"Recently Deleted\" album" , "30 days","Photos","\"Select\"" , "\"Delete All\"","both manually removed content and PhoneManager-cleaned files","data cannot be recovered"]
},
{
"problem":"How to Cancel Subscription?",
"answer":"Since subscription management and payment processes are exclusively controlled by Apple to ensure account security, cancel your PhoneManager subscription via these steps: Open iPhone Settings, tap your Apple ID profile at the top, go to Subscriptions, select PhoneManager, then tap Cancel Subscription. This will stop auto-renewal, but you can continue using the service until the current subscription period ends.",
"bold":["exclusively controlled by Apple","Apple ID profile","Subscriptions","PhoneManager","Cancel Subscription"]
},
{
"problem":"Why Can't I Allow PhoneManager to Access My Photos?",
"answer":"If the \"Allow Photo Access\" option is missing in settings, it may be due to Screen Time restrictions enabling permission controls. Adjust as follows: Open iPhone Settings, go to Screen Time > Content & Privacy Restrictions > Photos, and ensure Allow Changes is enabled. Afterward, force close and restart PhoneManager to reactivate the permission request. This action will not compromise existing photo data security—permission adjustments are solely for optimizing app functionality interactions.",
"bold":["Screen Time restrictions","iPhone Settings","Screen Time > Content & Privacy Restrictions > Photos","Allow Changes","will not compromise existing photo data security"]
},
{
"problem":"Other",
"answer":"",
"bold":[]
}
]
//
// PMFAQCell.swift
// PhoneManager
//
// Created by edy on 2025/5/16.
//
import UIKit
class PMFAQCell: UITableViewCell {
static let id = "PMFAQCell"
var callblock:(()->Void) = {}
@IBOutlet weak var PMFAQOpen: UIButton!
@IBOutlet weak var problem: UILabel!
@IBOutlet weak var anwser: UILabel!
var isOpen:Bool = false
@IBOutlet weak var topContraint: NSLayoutConstraint!
@IBAction func OpenActions(_ sender: Any) {
callblock()
}
var data:FAQDataModel? {
didSet{
problem.text = data?.problem
if isOpen {
self.topContraint.constant = 16;
PMFAQOpen.isSelected = true
anwser.attributedText = addattribed()
}else{
self.topContraint.constant = 0;
PMFAQOpen.isSelected = false
anwser.attributedText = nil
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
}
private func addattribed() -> NSMutableAttributedString {
let mutableText = NSMutableAttributedString(string: data?.answer ?? "")
mutableText.addAttributes([NSAttributedString.Key.font : UIFont.systemFont(ofSize: 14, weight: .regular)], range: NSRange(location: 0, length: mutableText.length))
let rangs = data?.bold ?? []
let famat = NSSet(array: rangs)
for text in famat {
if let rang = mutableText.string.range(of: text as! String) {
let startIndex = rang.lowerBound
let endIndex = rang.upperBound
let start = mutableText.string.distance(from: mutableText.string.startIndex, to: startIndex)
let end = mutableText.string.distance(from: mutableText.string.startIndex, to: endIndex)
if end < (data?.answer.count ?? 0) {
mutableText.addAttributes([NSAttributedString.Key.font : UIFont.systemFont(ofSize: 14, weight: .bold)], range: NSRange(location: start, length: end - start))
}
}
}
return mutableText
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="117" id="KGk-i7-Jjw" customClass="PMFAQCell" customModule="PhoneManager" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="394" height="117"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="KGk-i7-Jjw" id="H2p-sc-9uM">
<rect key="frame" x="0.0" y="0.0" width="394" height="117"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="LI7-ek-n5r">
<rect key="frame" x="0.0" y="0.0" width="394" height="102"/>
<subviews>
<button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="aR1-rL-mMz">
<rect key="frame" x="24" y="26" width="28" height="28"/>
<constraints>
<constraint firstAttribute="height" constant="28" id="K94-s3-vct"/>
<constraint firstAttribute="width" constant="28" id="wah-5C-OTg"/>
</constraints>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" image="ic_hints_faq-+"/>
<state key="selected" image="ic_hints_faq-"/>
<connections>
<action selector="OpenActions:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="QBR-6R-L8q"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Why don't l have free space on myphone after the cleaning process?" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="FV7-Dy-QOC">
<rect key="frame" x="64" y="25.666666666666664" width="306" height="28.666666666666664"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="12"/>
<color key="textColor" red="0.066666666666666666" green="0.066666666666666666" blue="0.066666666666666666" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5Ww-Bj-ymx">
<rect key="frame" x="24" y="54" width="346" height="25"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" id="ZKt-Ht-FOb"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/>
<color key="textColor" red="0.066666666666666666" green="0.066666666666666666" blue="0.066666666666666666" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="0.94901960784313721" green="0.96470588235294119" blue="0.9882352941176471" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="5Ww-Bj-ymx" firstAttribute="leading" secondItem="aR1-rL-mMz" secondAttribute="leading" id="Pfx-40-F4C"/>
<constraint firstAttribute="trailing" secondItem="FV7-Dy-QOC" secondAttribute="trailing" constant="24" id="R8i-5I-WGq"/>
<constraint firstItem="5Ww-Bj-ymx" firstAttribute="trailing" secondItem="FV7-Dy-QOC" secondAttribute="trailing" id="UBE-xe-efw"/>
<constraint firstItem="aR1-rL-mMz" firstAttribute="leading" secondItem="LI7-ek-n5r" secondAttribute="leading" constant="24" id="Ufh-Ts-jrV"/>
<constraint firstItem="5Ww-Bj-ymx" firstAttribute="top" secondItem="aR1-rL-mMz" secondAttribute="bottom" id="d17-JK-Uky"/>
<constraint firstItem="FV7-Dy-QOC" firstAttribute="centerY" secondItem="aR1-rL-mMz" secondAttribute="centerY" id="daf-Yq-Hwf"/>
<constraint firstAttribute="bottom" secondItem="5Ww-Bj-ymx" secondAttribute="bottom" constant="23" id="ewW-dW-1bR"/>
<constraint firstItem="FV7-Dy-QOC" firstAttribute="leading" secondItem="aR1-rL-mMz" secondAttribute="trailing" constant="12" id="pDR-fl-MNx"/>
<constraint firstItem="aR1-rL-mMz" firstAttribute="top" secondItem="LI7-ek-n5r" secondAttribute="top" constant="26" id="x74-ey-2Qq"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="Radius">
<real key="value" value="8"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="LI7-ek-n5r" secondAttribute="bottom" constant="15" id="MN0-Mh-jHR"/>
<constraint firstAttribute="trailing" secondItem="LI7-ek-n5r" secondAttribute="trailing" id="WWh-Ey-LIp"/>
<constraint firstItem="LI7-ek-n5r" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="cte-Ua-YEn"/>
<constraint firstItem="LI7-ek-n5r" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" id="nYi-NM-JQZ"/>
</constraints>
</tableViewCellContentView>
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
<connections>
<outlet property="PMFAQOpen" destination="aR1-rL-mMz" id="uDp-gy-zMD"/>
<outlet property="anwser" destination="5Ww-Bj-ymx" id="S5P-P6-m9V"/>
<outlet property="problem" destination="FV7-Dy-QOC" id="w8n-e3-MRz"/>
<outlet property="topContraint" destination="d17-JK-Uky" id="BWK-zy-B8a"/>
</connections>
<point key="canvasLocation" x="186.25954198473281" y="14.43661971830986"/>
</tableViewCell>
</objects>
<resources>
<image name="ic_hints_faq-" width="28" height="28"/>
<image name="ic_hints_faq-+" width="28" height="28"/>
</resources>
</document>
[
{
"problem":"Why isn't storage space freed up after cleaning my phone?",
"answer":"The cleaning process follows iOS system design: deleted photos/videos are temporarily moved to the Recently Deleted album (retained for 30 days) and still occupy storage. To permanently free up space, open the Photos app on your iPhone, navigate to the Recently Deleted album, select items you wish to remove, and tap Delete. Note that this action irreversibly erases files from your device, so confirm you no longer need them before proceeding."
},
{
"problem":"How Do I Recover Deleted Photos/Videos?",
"answer":"Deleted photos/videos are temporarily preserved in the Recently Deleted album for 30 days (aligned with iOS Photos app protocols), allowing recovery if removed accidentally. To restore them, open the Photos app, navigate to the Recently Deleted album, tap Select (top-right corner), choose the files to retrieve, and tap Recover. For bulk restoration, use Recover All after selecting all items. Note that this album retains content deleted both manually and via cleanup tools. After 30 days, iOS automatically removes these files permanently, so ensure timely action."
},
{
"problem":"Does PhoneManager Guarantee That My Photos Will Not Be Uploaded Anywhere? ",
"answer":"PhoneManager operates entirely offline and requires no internet connection, ensuring your photos are never uploaded to external servers. All scanning, analysis, and PhoneManager processes occur locally on your device. The app only requests access to your photo library to evaluate attributes like edits, favorites, or facial recognition data for organizing purposes. No photo content or metadata is shared externally—the. The sole reports generated are anonymous technical logs (e.g., app performance issues) that contain no personal or image-related information. Your privacy remains protected throughout the process."
},
{
"problem":"How Does PhoneManager Choose the Best Photos?",
"answer":"PhoneManager employs advanced algorithms incorporating face recognition, similar photo comparison, and evaluation of edited/favorited status to analyze your gallery. Based on these criteria, it dynamically flags one photo in a group as the Best Result. While the selection prioritizes technical quality and metadata insights, we strongly recommend reviewing these suggestions to ensure they align with your personal preferences, as human judgment may differ from algorithmic evaluations",
"bold":["PhoneManager","face recognition, similar photo comparison","edited/favorited status","Best Result"]
},
{
"problem":"Can I Use PhoneManager on All My Other Apple Devices?",
"answer":"PhoneManager is currently compatible only with iPhones running iOS 14 or later. The number of devices covered under your subscription/license is governed by the App Store's subscription terms and conditions. Support for additional Apple devices (e.g., iPads, Macs) is unavailable at this time.",
"bold":["PhoneManager","only with iPhones running iOS 14 or later","App Store's subscription terms and conditions"]
},
{
"problem":"How Can I Cancel My Subscription?",
"answer":"To cancel your PhoneManager subscription, follow Apple's standard subscription management process: Open Settings on your iPhone, tap your Apple ID profile at the top, select Subscriptions, then choose PhoneManager. Tap the Cancel Subscription button at the bottom of the screen. Note that this action stops automatic renewal but preserves access until the end of your current billing cycle.",
"bold":["PhoneManager","Settings","Apple ID profile","Subscriptions","Cancel Subscription"]
},
{
"problem":"How Do I Scan the Photos in My Photos Library?",
"answer":"PhoneManager initiates automatic scanning and analysis of your photo library upon first launch. For large collections, this process may require significant time and device resources. Please allow the scan to complete uninterrupted—results will display once finished. Subsequent scans optimize efficiency by focusing only on recent additions or changes, leveraging cached data from the initial scan. While first-time usage demands patience, future interactions will be faster and resource-light.",
"bold":["PhoneManager","automatic scanning and analysis","only on recent additions or changes"]
},
{
"problem":"What Is Categorized as “Similar”?",
"answer":"The “Similar” category groups photos captured within seconds of each other, featuring the same subject/person in a consistent background with minor variations (e.g., poses, angles). For instance, multiple shots of someone posing differently in front of a landmark. To simplify cleanup, PhoneManager uses advanced algorithms analyzing factors like clarity and composition to flag one photo as the Best Result and suggests removing others. Photos marked as favorites are automatically excluded from selection. Before confirming cleanup, review suggested groups to ensure alignment with your preferences.",
"bold":["Similar","within seconds of each other","same subject/person","consistent background","PhoneManager","Best Result","favorites"]
},
{
"problem":"What Is Categorized as \"Other\"?",
"answer":"The “Other” category includes photos that do not fit predefined classifications (e.g., duplicates, similar shots). Unlike automated suggestions in other groups, PhoneManager refrains from labeling items here as \"good\" or \"bad.\" Instead, it employs an interactive swiping mechanism—swipe left to mark photos for deletion or right to retain them—giving you full control over curation. Prioritize reviewing this category manually to ensure no unintended files are removed.",
"bold":["Other","do not fit predefined classifications","interactive swiping mechanism","PhoneManager","left","right"]
},
{
"problem":"How Can I Review All Photos in a Certain Category?",
"answer":"To review photos within a category, tap any item to enlarge it for closer inspection. In the “Similar” category, photos are grouped into sets organized by creation date—scroll vertically to browse all sets and tap one to examine its contents. For subcategories without grouped sets, scroll freely through individual photos and tap to view details. Use this process to thoroughly evaluate suggestions before finalizing cleanup decisions.",
"bold":["tap any item","Similar","creation date"]
},
{
"problem":"How Can I Remove Unwanted Photos?",
"answer":"PhoneManager automatically flags suggested photos for deletion with a red checkmark icon based on algorithmic analysis. To proceed, select the marked items and tap Delete—but ensure any photos you wish to retain are moved to your Keep List first. For manual review in the “Similar” category, open a grouped set, inspect the app’s Best Result recommendation, and tap Move to Trash to approve deletions. To override suggestions, unmark photos you want to keep (or add them to your Keep List), re-mark unwanted items, then finalize by tapping the trash bin icon and confirming Delete. Always verify selections, as deletions are permanent.",
"bold":["PhoneManager","red checkmark icon","Delete","Keep List","Similar","Best Result","Move to Trash","trash bin icon"]
},
{
"problem":"How Do I Use the Swiping Feature?",
"answer":"The swiping feature in PhoneManager provides an efficient way to review photos in the Videos and Other categories. Simply swipe left on a photo to mark it for removal or swipe right to add it to your Keep List. This intuitive gesture-based system streamlines the cleanup process while ensuring you retain full control over final decisions.",
"bold":["PhoneManager","swiping feature","Videos","Other","swipe left","swipe right","Keep List"]
},
{
"problem":"Can I Clean My Videos Using PhoneManager?",
"answer":"Yes, PhoneManager supports video cleanup by organizing all videos under the Videos category. While similarity-based sorting for videos is resource-intensive, you can manually sort them by size or creation date and use the swipe-left gesture to mark items for deletion or swipe-right to retain them in your Keep List. This streamlined approach balances technical constraints with user control, allowing efficient curation of large video libraries.",
"bold":["PhoneManager","resource-intensive","Videos","by size or creation date","swipe left","swipe right","Keep List"]
},
{
"problem":"Should I Review All the Photos PhoneManager Scanned?",
"answer":"While PhoneManager employs smart algorithms to group photos and suggest Best Result recommendations, we strongly advise reviewing all flagged items before deletion. The app streamlines organization and prioritizes accuracy, but personal preferences may differ from algorithmic logic. Retain full control by verifying selections—your final approval ensures no essential photos are inadvertently removed.",
"bold":["PhoneManager","smart algorithms","Best Result","final approval"]
},
{
"problem":"Is PhoneManager Safe? How Can I Trust PhoneManager?",
"answer":"PhoneManager prioritizes safety and user control: All cleanup actions require explicit approval, and no files are deleted without your final confirmation. The app operates with offline processing (no photo uploads) and uses permissions solely to analyze local metadata (e.g., edits, favorites) for suggestions. While its algorithms streamline decisions, your manual review ensures alignment with personal preferences. Additionally, no personal data or photo content is shared externally—only anonymous technical logs are generated for app optimization. Trust is built through transparency and your retained authority over every deletion.",
"bold":["PhoneManager","explicit approval","offline processing","no personal data or photo content"]
},
{
"problem":"How Do I Add Photos to My Keep List?",
"answer":"To add photos/videos to your Keep List, open a grouped set in the “Similar” category and tap the Keep All button (lower-left corner) to save the entire collection. For individual items in the Videos or “Other” categories, simply swipe right to add them to your Keep List. To review or edit saved content, access your Keep List through the Settings icon (upper-right corner of the Media Library). If you wish to remove items, select the files within the Keep List and tap Unkeep (upper-right corner) to return them to the scan results. All changes take effect immediately, ensuring seamless control over your curated collection.",
"bold":["Keep List","Similar","Keep All","Videos","Other","swipe right","Settings icon","Media Library","Unkeep"]
},
]
//
// PMFAQController.swift
// PhoneManager
//
// Created by edy on 2025/5/16.
//
import UIKit
class PMFAQController: BaseViewController {
@IBOutlet weak var TableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.TableView.delegate = self
self.TableView.dataSource = self
self.TableView.showsVerticalScrollIndicator = false
self.TableView.showsHorizontalScrollIndicator = false
self.titleView.model.title = "FAQ"
self.TableView.register(UINib(nibName: PMFAQCell.id, bundle: nil), forCellReuseIdentifier: PMFAQCell.id)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let file = Bundle.main.bundleURL.appendingPathComponent("PMFAQData.json")
do{
let dictData = try Data(contentsOf: file)
dataSource = try JSONDecoder().decode([FAQDataModel].self, from: dictData)
}catch{ }
self.TableView.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(15)
make.bottom.equalToSuperview()
make.top.equalTo(self.titleView.snp.bottom).offset(10)
}
}
@IBAction func BackToAction(_ sender: Any) {
self.navigationController?.popViewController(animated: true)
}
var openSet = -1
var dataSource:[FAQDataModel] = [] {
didSet {
self.TableView.reloadData()
}
}
}
extension PMFAQController : UITableViewDelegate,UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: PMFAQCell.id, for: indexPath) as! PMFAQCell
cell.isOpen = openSet == indexPath.row
cell.data = dataSource[indexPath.row]
cell.selectionStyle = .none
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
var indexpaths:[IndexPath] = []
if openSet == indexPath.row {
openSet = -1
indexpaths = [indexPath]
}else{
let current = openSet
openSet = indexPath.row
indexpaths = [indexPath]
if current >= 0 {
indexpaths.append(IndexPath(row: current, section: 0))
}
}
tableView.reloadRows(at: indexpaths, with: .automatic)
}
}
struct FAQDataModel : Codable {
var problem:String
var answer:String
var bold:[String]?
init(problem: String, answer: String) {
self.problem = problem
self.answer = answer
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="PMFAQController" customModule="PhoneManager" customModuleProvider="target">
<connections>
<outlet property="TableView" destination="q9T-FF-R37" id="xaI-v2-Arc"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView clipsSubviews="YES" contentMode="scaleToFill" fixedFrame="YES" alwaysBounceVertical="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" style="plain" separatorStyle="none" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="-1" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="q9T-FF-R37">
<rect key="frame" x="15" y="127" width="363" height="691"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<connections>
<outlet property="dataSource" destination="-1" id="7C4-p0-iYH"/>
<outlet property="delegate" destination="-1" id="vwG-gm-Uru"/>
</connections>
</tableView>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<point key="canvasLocation" x="131" y="-12"/>
</view>
</objects>
<resources>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
//
// PMHintsController.swift
// PhoneManager
//
// Created by edy on 2025/5/16.
//
import UIKit
class PMHintsController: BaseViewController , UIScrollViewDelegate {
@IBOutlet weak var PMHintsPage: UIPageControl!
@IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
PMHintsPage.numberOfPages = 5
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
ScrollToCurrent(scrollView)
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if decelerate {
ScrollToCurrent(scrollView)
}
}
private func ScrollToCurrent(_ scroll:UIScrollView) -> Void {
let orx = scroll.contentOffset.x / scroll.width
PMHintsPage.currentPage = Int(round(orx))
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="PMHintsController" customModule="PhoneManager" customModuleProvider="target">
<connections>
<outlet property="PMHintsPage" destination="Hjf-zs-Luc" id="ywa-r1-gMa"/>
<outlet property="scrollView" destination="jgO-hZ-9Df" id="HkE-qu-bV6"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jgO-hZ-9Df">
<rect key="frame" x="0.0" y="119" width="393" height="613.33333333333337"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="uZH-h3-Fkz">
<rect key="frame" x="0.0" y="0.0" width="1965" height="613.33333333333337"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5Xa-3c-aHx">
<rect key="frame" x="0.0" y="0.0" width="393" height="613.33333333333337"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" spacing="18" translatesAutoresizingMaskIntoConstraints="NO" id="ngA-9i-uKc">
<rect key="frame" x="40" y="41.333333333333314" width="313" height="530.66666666666674"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2 Duplicates" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tNx-bS-tcw">
<rect key="frame" x="0.0" y="0.0" width="313" height="19.333333333333332"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="tips_duplicates_1" translatesAutoresizingMaskIntoConstraints="NO" id="H33-nl-3al">
<rect key="frame" x="0.0" y="37.333333333333314" width="313" height="152.66666666666666"/>
<constraints>
<constraint firstAttribute="width" secondItem="H33-nl-3al" secondAttribute="height" multiplier="281:137" id="yld-7C-nEV"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2 Duplicates" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DdZ-J7-5Kl">
<rect key="frame" x="0.0" y="207.99999999999997" width="313" height="19.333333333333343"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="tips_duplicates_2" translatesAutoresizingMaskIntoConstraints="NO" id="fbi-32-E9s">
<rect key="frame" x="0.0" y="245.33333333333331" width="313" height="152.33333333333331"/>
<constraints>
<constraint firstAttribute="width" secondItem="fbi-32-E9s" secondAttribute="height" multiplier="281:137" id="ge1-Q5-cNm"/>
</constraints>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="center" spacing="18" translatesAutoresizingMaskIntoConstraints="NO" id="gJQ-p8-Usv">
<rect key="frame" x="0.0" y="415.66666666666663" width="313" height="115"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Duplicates" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QZP-ld-Qdn">
<rect key="frame" x="94.333333333333343" y="0.0" width="124.66666666666666" height="30"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="25"/>
<color key="textColor" red="0.10196078431372549" green="0.10196078431372549" blue="0.10196078431372549" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CfK-fg-ZIg">
<rect key="frame" x="2.3333333333333428" y="48" width="308.33333333333326" height="67"/>
<string key="text">These are duplicate photos - they are completely identical to each other. Immediately delete all duplicate items and keep the original version.</string>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="ngA-9i-uKc" firstAttribute="centerY" secondItem="5Xa-3c-aHx" secondAttribute="centerY" id="7Jh-TE-Owr"/>
<constraint firstItem="ngA-9i-uKc" firstAttribute="leading" secondItem="5Xa-3c-aHx" secondAttribute="leading" constant="40" id="8ED-4c-WNC"/>
<constraint firstAttribute="trailing" secondItem="ngA-9i-uKc" secondAttribute="trailing" constant="40" id="meh-Mt-0K2"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="hlo-KY-MjE">
<rect key="frame" x="393" y="0.0" width="393" height="613.33333333333337"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" spacing="18" translatesAutoresizingMaskIntoConstraints="NO" id="2Yh-GL-Q2t">
<rect key="frame" x="40" y="41.333333333333314" width="313" height="530.66666666666674"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2 Similar" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="IhS-Gp-baN">
<rect key="frame" x="0.0" y="0.0" width="313" height="19.333333333333332"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="tips_similar_1" translatesAutoresizingMaskIntoConstraints="NO" id="kvj-jW-PoF">
<rect key="frame" x="0.0" y="37.333333333333314" width="313" height="152.66666666666666"/>
<constraints>
<constraint firstAttribute="width" secondItem="kvj-jW-PoF" secondAttribute="height" multiplier="281:137" id="IaD-TY-qFl"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="2 Similar" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GIs-vI-kWE">
<rect key="frame" x="0.0" y="207.99999999999997" width="313" height="19.333333333333343"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="tips_similar_2" translatesAutoresizingMaskIntoConstraints="NO" id="x0D-ou-xRd">
<rect key="frame" x="0.0" y="245.33333333333331" width="313" height="152.33333333333331"/>
<constraints>
<constraint firstAttribute="width" secondItem="x0D-ou-xRd" secondAttribute="height" multiplier="281:137" id="J9F-Fe-BXn"/>
</constraints>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="center" spacing="18" translatesAutoresizingMaskIntoConstraints="NO" id="jsL-Yg-DRw">
<rect key="frame" x="0.0" y="415.66666666666663" width="313" height="115"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Similar photos" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qDj-bm-OSE">
<rect key="frame" x="73.000000000000014" y="0.0" width="167.33333333333337" height="30"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="25"/>
<color key="textColor" red="0.1019607843" green="0.1019607843" blue="0.1019607843" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RUE-zC-XhU">
<rect key="frame" x="5" y="48" width="303" height="67"/>
<string key="text">We will group similar photos together and provide recommendations for the best photos. Please safely view and select the photos you want to move to the trash can.</string>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="2Yh-GL-Q2t" secondAttribute="trailing" constant="40" id="4Pl-zY-orU"/>
<constraint firstItem="2Yh-GL-Q2t" firstAttribute="centerY" secondItem="hlo-KY-MjE" secondAttribute="centerY" id="JRL-Y6-MBU"/>
<constraint firstItem="2Yh-GL-Q2t" firstAttribute="leading" secondItem="hlo-KY-MjE" secondAttribute="leading" constant="40" id="yn8-PT-z7E"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ees-5Q-f0P">
<rect key="frame" x="786" y="0.0" width="393" height="613.33333333333337"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" spacing="55" translatesAutoresizingMaskIntoConstraints="NO" id="4BK-NH-6jQ">
<rect key="frame" x="40" y="40" width="313" height="533.33333333333337"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="tips_sreenshot" translatesAutoresizingMaskIntoConstraints="NO" id="zkZ-Px-VS8">
<rect key="frame" x="0.0" y="0.0" width="313" height="363.33333333333331"/>
<constraints>
<constraint firstAttribute="width" secondItem="zkZ-Px-VS8" secondAttribute="height" multiplier="341:396" id="BtW-U1-uWU"/>
</constraints>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="center" spacing="18" translatesAutoresizingMaskIntoConstraints="NO" id="PHa-RC-gM7">
<rect key="frame" x="0.0" y="418.33333333333337" width="313" height="115"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="ScreenShot" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hAl-SL-XaU">
<rect key="frame" x="88" y="0.0" width="137" height="30"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="25"/>
<color key="textColor" red="0.1019607843" green="0.1019607843" blue="0.1019607843" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nv3-gd-dfh">
<rect key="frame" x="4.6666666666666288" y="48" width="303.66666666666669" height="67"/>
<string key="text">We will group similar screenshots together so that you can view them faster! Please safely view and select the customer cut-off you want to move to the trash can.</string>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="4BK-NH-6jQ" firstAttribute="centerY" secondItem="ees-5Q-f0P" secondAttribute="centerY" id="7B1-dU-YwN"/>
<constraint firstAttribute="trailing" secondItem="4BK-NH-6jQ" secondAttribute="trailing" constant="40" id="PPh-AP-WMn"/>
<constraint firstItem="4BK-NH-6jQ" firstAttribute="leading" secondItem="ees-5Q-f0P" secondAttribute="leading" constant="40" id="sfc-4O-uuC"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yeQ-s0-3eu">
<rect key="frame" x="1179" y="0.0" width="393" height="613.33333333333337"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" spacing="82" translatesAutoresizingMaskIntoConstraints="NO" id="Tcf-97-ZCs">
<rect key="frame" x="40" y="33.666666666666629" width="313" height="546"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="tips_video" translatesAutoresizingMaskIntoConstraints="NO" id="qjS-Jv-Tsc">
<rect key="frame" x="0.0" y="0.0" width="313" height="365.66666666666669"/>
<constraints>
<constraint firstAttribute="width" secondItem="qjS-Jv-Tsc" secondAttribute="height" multiplier="261:305" id="DHC-sQ-LFq"/>
</constraints>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="center" spacing="18" translatesAutoresizingMaskIntoConstraints="NO" id="VBe-cO-HJz">
<rect key="frame" x="0.0" y="447.66666666666674" width="313" height="98.333333333333371"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Video" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="orc-Z4-zrH">
<rect key="frame" x="122.66666666666674" y="0.0" width="67.666666666666686" height="30"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="25"/>
<color key="textColor" red="0.1019607843" green="0.1019607843" blue="0.1019607843" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="View all of your videos. Sort them by size or date. View the video that occupies the maximum space." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="acZ-y7-R3Q">
<rect key="frame" x="13.666666666666742" y="48" width="286" height="50.333333333333343"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="Tcf-97-ZCs" firstAttribute="centerY" secondItem="yeQ-s0-3eu" secondAttribute="centerY" id="X2i-bh-too"/>
<constraint firstAttribute="trailing" secondItem="Tcf-97-ZCs" secondAttribute="trailing" constant="40" id="X4R-xi-Qry"/>
<constraint firstItem="Tcf-97-ZCs" firstAttribute="leading" secondItem="yeQ-s0-3eu" secondAttribute="leading" constant="40" id="bc3-ng-O0m"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XAV-qr-EhO">
<rect key="frame" x="1572" y="0.0" width="393" height="613.33333333333337"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" spacing="82" translatesAutoresizingMaskIntoConstraints="NO" id="3FW-3K-xPh">
<rect key="frame" x="40" y="33.666666666666629" width="313" height="546"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="tips_photos" translatesAutoresizingMaskIntoConstraints="NO" id="g9Z-rw-Wgd">
<rect key="frame" x="0.0" y="0.0" width="313" height="365.66666666666669"/>
<constraints>
<constraint firstAttribute="width" secondItem="g9Z-rw-Wgd" secondAttribute="height" multiplier="261:305" id="cIq-cw-pde"/>
</constraints>
</imageView>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" alignment="center" spacing="18" translatesAutoresizingMaskIntoConstraints="NO" id="SLW-Qi-u2E">
<rect key="frame" x="0.0" y="447.66666666666674" width="313" height="98.333333333333371"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Other photos" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xCw-5n-Bw1">
<rect key="frame" x="79.666666666666728" y="0.0" width="153.66666666666663" height="30"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="25"/>
<color key="textColor" red="0.1019607843" green="0.1019607843" blue="0.1019607843" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="These are photos that do not belong to any category. Sort them by size or date. Delete unnecessary photos." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tdu-B0-lEf">
<rect key="frame" x="15.333333333333258" y="48" width="282.33333333333331" height="50.333333333333343"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="3FW-3K-xPh" firstAttribute="leading" secondItem="XAV-qr-EhO" secondAttribute="leading" constant="40" id="Q6a-QQ-yix"/>
<constraint firstItem="3FW-3K-xPh" firstAttribute="centerY" secondItem="XAV-qr-EhO" secondAttribute="centerY" id="Rgg-h4-E4a"/>
<constraint firstAttribute="trailing" secondItem="3FW-3K-xPh" secondAttribute="trailing" constant="40" id="rM8-db-kJS"/>
</constraints>
</view>
</subviews>
</stackView>
</subviews>
<constraints>
<constraint firstItem="uZH-h3-Fkz" firstAttribute="width" secondItem="jgO-hZ-9Df" secondAttribute="width" multiplier="5" id="MCy-xF-xJy"/>
<constraint firstItem="uZH-h3-Fkz" firstAttribute="leading" secondItem="jgO-hZ-9Df" secondAttribute="leading" id="QMt-c1-5cv"/>
<constraint firstAttribute="trailing" secondItem="uZH-h3-Fkz" secondAttribute="trailing" id="dk2-bv-Giy"/>
<constraint firstAttribute="bottom" secondItem="uZH-h3-Fkz" secondAttribute="bottom" id="sgl-Ro-1KY"/>
<constraint firstItem="uZH-h3-Fkz" firstAttribute="top" secondItem="jgO-hZ-9Df" secondAttribute="top" id="t3l-yX-EL3"/>
<constraint firstItem="uZH-h3-Fkz" firstAttribute="centerY" secondItem="jgO-hZ-9Df" secondAttribute="centerY" id="tvx-T9-QAi"/>
</constraints>
<connections>
<outlet property="delegate" destination="-1" id="OYZ-iA-wKM"/>
</connections>
</scrollView>
<pageControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" numberOfPages="3" translatesAutoresizingMaskIntoConstraints="NO" id="Hjf-zs-Luc">
<rect key="frame" x="160" y="762.33333333333337" width="73" height="25.666666666666629"/>
<constraints>
<constraint firstAttribute="height" constant="25.670000000000002" id="yjG-ks-gAd"/>
</constraints>
<color key="pageIndicatorTintColor" red="0.85098039219999999" green="0.85098039219999999" blue="0.85098039219999999" alpha="1" colorSpace="calibratedRGB"/>
<color key="currentPageIndicatorTintColor" red="0.0" green="0.50980392159999999" blue="1" alpha="1" colorSpace="calibratedRGB"/>
</pageControl>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="jgO-hZ-9Df" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="VTI-Ht-aHR"/>
<constraint firstItem="Hjf-zs-Luc" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="gNS-Nj-Ovw"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="jgO-hZ-9Df" secondAttribute="trailing" id="gX4-hK-kau"/>
<constraint firstItem="Hjf-zs-Luc" firstAttribute="top" secondItem="jgO-hZ-9Df" secondAttribute="bottom" constant="30" id="odB-3N-wAu"/>
<constraint firstItem="jgO-hZ-9Df" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="60" id="tsN-qu-WFf"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="Hjf-zs-Luc" secondAttribute="bottom" constant="30" id="wcY-cY-B4c"/>
</constraints>
<point key="canvasLocation" x="117" y="-11"/>
</view>
</objects>
<resources>
<image name="tips_duplicates_1" width="281" height="137.33332824707031"/>
<image name="tips_duplicates_2" width="281" height="137.33332824707031"/>
<image name="tips_photos" width="262" height="306"/>
<image name="tips_similar_1" width="281" height="137.33332824707031"/>
<image name="tips_similar_2" width="281" height="137.33332824707031"/>
<image name="tips_sreenshot" width="341" height="396"/>
<image name="tips_video" width="262" height="306"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
......@@ -520,6 +520,15 @@ extension HomePhotosDetailViewController:WaterfallMutiSectionDelegate,UICollecti
}else{
self.selectedModel.removeAll { $0.localIdentifier == self.resourceData[order].localIdentifier }
}
self.vibrate()
DispatchQueue.main.async {
if self.selectedModel.count > 0 {
self.deleteButton.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1)
}else{
self.deleteButton.backgroundColor = UIColor(red: 0.7, green: 0.7, blue: 0.7, alpha: 1)
self.deleteButton.setTitle("Delete", for: .normal)
}
}
}
return cell
......
......@@ -403,11 +403,14 @@ class PhotoRemoveViewController: BaseViewController {
// 清除单利数据
clearSigtonTrashData()
// 保留操作
self.vibrate()
saveDataToSigtonKeepList()
}
if actualTranslation.x < 0 {
// 删除操作,先存到单利
self.vibrate()
saveDataToDBAndSigtonTrash()
}
} else {
resetViewPosition(activeView)
......
......@@ -243,7 +243,7 @@ extension HomeInfoTableViewCell:UICollectionViewDelegate,UICollectionViewDataSou
cell.callBack = {[weak self] _ in
guard let self else {return}
vibrate()
self.checkSeletedAll()
self.callBack("changgeSeleted")
......
......@@ -183,6 +183,7 @@ extension MaintaiDetailViewController:UITableViewDelegate,UITableViewDataSource{
cell.source = viewModel.souces[indexPath.row]
cell.selectCallBack = {[weak self] selects in
guard let weakSelf = self else { return }
weakSelf.vibrate()
if let sIndex = selectIndex{
//已经有选中状态
Print("已经有选中数据",sIndex)
......
......@@ -165,6 +165,7 @@ extension MaintainViewListController:UICollectionViewDataSource,UICollectionView
cell.reloadData(viewModel.souces[indexPath.row], isSelect:isSelect)
cell.selectBlock = {[weak self] in
guard let weakSelf = self else { return }
weakSelf.vibrate()
weakSelf.dealPickAssetModel(row: indexPath.row,isSelect: isSelect)
weakSelf.collectionView.reloadData()
}
......
......@@ -493,7 +493,7 @@ class HomePayView:UIView {
@objc func switchValueChanged(_ sender: UISwitch) {
type = sender.isOn ? 0 : 1
self.vibrate()
}
@objc func restoreTouch() -> Void {
......
......@@ -68,6 +68,7 @@ class DelSuccessViewController: UIViewController {
}
@IBAction func closeClick(_ sender: Any) {
vibrate()
self.dismiss(animated: true)
}
......
......@@ -161,6 +161,7 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView == bottItems {
self.vibrate()
if selectSet.contains(indexPath.row) {
self.homeDataSource?[indexPath.row].isSeleted = false
selectSet.remove(indexPath.row)
......@@ -209,6 +210,7 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
cell.isCurrent = selectSet.contains(indexPath.row)
cell.callblock = {[weak self] in
guard let self = self else { return }
self.vibrate()
if self.selectSet.contains(indexPath.row){
self.homeDataSource?[indexPath.row].isSeleted = false
self.selectSet.remove(indexPath.row)
......@@ -228,6 +230,7 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
cell.reload()
cell.callblock = {[weak self] in
guard let self = self else { return }
self.vibrate()
if self.selectSet.contains(indexPath.row){
self.homeDataSource?[indexPath.row].isSeleted = false
self.selectSet.remove(indexPath.row)
......@@ -261,6 +264,7 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
cell.bestResultButton.isHidden = indexPath.row != 0
cell.callblock = {[weak self] in
guard let self = self else { return }
self.vibrate()
if self.selectSet.contains(indexPath.row){
self.homeDataSource?[indexPath.row].isSeleted = false
self.selectSet.remove(indexPath.row)
......@@ -304,6 +308,7 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
cell.bestResultButton.isHidden = indexPath.row != 0
cell.callblock = {[weak self] in
guard let self = self else { return }
self.vibrate()
if self.selectSet.contains(indexPath.row){
self.homeDataSource?[indexPath.row].isSeleted = false
self.selectSet.remove(indexPath.row)
......
......@@ -134,12 +134,14 @@ class SecretSetViewController: BaseViewController, UITextFieldDelegate {
}else{
// UserDefaults.standard.set(Secret, forKey: SecretViewController.psKey)
SettingConfiguration.share.config.secret = Secret
UserDefaults.standard.set("1", forKey: "SecretFirstShow")
let alert = UIAlertController(title: nil, message: "Your space is locked", preferredStyle: .alert)
self.present(alert, animated: true)
DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
alert.dismiss(animated: true) {
self.Callback(true)
self.PMClose()
_ = PMFaceIDManger.request()
}
}
}
......
......@@ -249,22 +249,28 @@ class SecretViewController: BaseViewController {
AdvManager.shared.finisedCallBack = {
self.AddAction = SecretActionView()
self.AddAction.show();
self.view.showBlur()
self.AddAction.callback = { idx in
self.view.hideBlur()
self.AddImagePicker(idx)
}
}
}else {
self.AddAction = SecretActionView()
self.view.showBlur()
self.AddAction.show();
self.AddAction.callback = { idx in
self.view.hideBlur()
self.AddImagePicker(idx)
}
}
}else {
self.AddAction = SecretActionView()
self.view.showBlur()
self.AddAction.show();
self.AddAction.callback = { idx in
self.view.hideBlur()
self.AddImagePicker(idx)
}
}
......@@ -320,6 +326,7 @@ extension SecretViewController : UICollectionViewDelegate,UICollectionViewDataSo
cell.isSelect = selectArray.contains((indexPath.row))
cell.imageText = dataSource[indexPath.row]
cell.callback = { [weak self] in
self?.vibrate()
self?.selectImgVideo(indexPath.row)
}
return cell
......@@ -419,7 +426,9 @@ extension SecretViewController : UIImagePickerControllerDelegate , UINavigationC
}
assetdels.append(set.phAsset!)
}
SecretPhotoManager.share.deleteAssets(assetdels)
if SettingConfiguration.share.config.removeImg {
SecretPhotoManager.share.deleteAssets(assetdels)
}
}else{
guard let d = data as? Data else { return }
if idx == 0 { // image
......
......@@ -8,17 +8,21 @@
import UIKit
import SnapKit
class SecretActionView: UIViewController {
class SecretActionView: UIViewController ,UIViewControllerTransitioningDelegate {
private var selectedViewBottomConstraint: Constraint?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .colorWithHex(hexStr: "#000000", alpha: 0.5)
view.backgroundColor = .clear//.colorWithHex(hexStr: "#000000", alpha: 0.5)
self.transitioningDelegate = self;
setUI()
addTapAction()
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return customDismissAnimator()
}
/// 添加背景点击消失
func addTapAction(){
......@@ -80,6 +84,7 @@ class SecretActionView: UIViewController {
var callback:((_ idx:Int)->Void)?
@objc private func actionTouch(_ sender:UIButton) -> Void {
self.dismiss(animated: true)
guard callback != nil else {
return
......@@ -89,13 +94,17 @@ class SecretActionView: UIViewController {
}
@objc private func touchDismiss(){
UIView.animate(withDuration: 0.2) {
// 更新约束
self.selectedViewBottomConstraint?.update(offset: 1000)
self.view.layoutIfNeeded()
}completion: { _ in
self.dismiss(animated: true)
// UIView.animate(withDuration: 0.2) {
// // 更新约束
// self.selectedViewBottomConstraint?.update(offset: 1000)
// self.view.layoutIfNeeded()
// }completion: { _ in
self.dismiss(animated: true)
guard callback != nil else {
return
}
callback!(0x12)
// }
}
......@@ -136,7 +145,7 @@ class SecretActionView: UIViewController {
let carma = UIButton(type: .custom)
carma.setImage(UIImage(named: "ic_video_secret"), for: .normal)
carma.backgroundColor = .colorWithHex(hexStr: "#F2F6FC")
carma.titleLabel?.font = UIFont.systemFont(ofSize: 16)
carma.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
carma.contentHorizontalAlignment = .leading
carma.layer.cornerRadius = 12
carma.tag = 0x10;
......@@ -153,7 +162,7 @@ class SecretActionView: UIViewController {
let Photo = UIButton(type: .custom)
Photo.setImage(UIImage(named: "ic_photo_secret"), for: .normal)
Photo.backgroundColor = .colorWithHex(hexStr: "#F2F6FC")
Photo.titleLabel?.font = UIFont.systemFont(ofSize: 16)
Photo.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
Photo.contentHorizontalAlignment = .leading
Photo.layer.cornerRadius = 12
Photo.tag = 0x11;
......
......@@ -62,7 +62,34 @@ struct RowInfoModel{
func getSettingViewInfo() -> [SettingModel] {
if SettingConfiguration.share.config.secret?.count ?? 0 != 4 {
return [
SettingModel(sectionTitle: "",rowInfo: [RowInfoModel(imageName: "",title: "")]),
SettingModel(sectionTitle: "E-mail",rowInfo: [RowInfoModel(imageName: "icon_set_secret_Email_l", title: "Log in")]),
SettingModel(sectionTitle: "Secret space",rowInfo: [RowInfoModel(imageName: "icon_set_secret_lock",title: "Use PIN" , isSwitch:true),
RowInfoModel(imageName: "icon_set_secret_Del",title: "Remove After Import",isSwitch:true)]),
SettingModel(sectionTitle: "Practical tools",rowInfo: [RowInfoModel(imageName: "icon_set_secret_Email_l", title: "Widgets")]),
SettingModel(sectionTitle: "Stay in touch",rowInfo: [RowInfoModel(imageName: "icon_set_secret_ins_setting", title: "Follow on Instagram"),
RowInfoModel(imageName: "icon_set_secret_rate_setting", title: "Rate Us"),
RowInfoModel(imageName: "icon_set_secret_share_setting", title: "Share Us"),]),
SettingModel(sectionTitle: "Other",rowInfo: [RowInfoModel(imageName: "icon_set_secret_Hint", title: "Hint"),
RowInfoModel(imageName: "icon_set_secret_keep", title: "Keep List"),
RowInfoModel(imageName: "icon_set_secret__vibration_setting", title: "Vibration",isSwitch:true)]),
SettingModel(sectionTitle: "Support",rowInfo: [RowInfoModel(imageName: "icon_set_secret_restore", title: "Resume purchase"),
RowInfoModel(imageName: "icon_set_secret_Email_support", title: "Email Support"),
RowInfoModel(imageName: "icon_set_secret_FAQ", title: "FAQ"),
RowInfoModel(imageName: "icon_set_secret_about_us", title: "About Us"),
RowInfoModel(imageName: "icon_set_secret_Privacy", title: "Privacy Policy"),]),]
} else {
if PMFaceIDManger.isAvailable() {
return [
SettingModel(sectionTitle: "",rowInfo: [RowInfoModel(imageName: "",title: "")]),
......@@ -71,6 +98,8 @@ func getSettingViewInfo() -> [SettingModel] {
SettingModel(sectionTitle: "Secret space",rowInfo: [RowInfoModel(imageName: "icon_set_secret_lock",title: "Use PIN" , isSwitch:true),
RowInfoModel(imageName: "icon_set_secret_Face",title: "Use Face ID",isSwitch:true),
RowInfoModel(imageName: "icon_set_secret_ChangePin",title: "Change PIN"),
RowInfoModel(imageName: "icon_set_secret_Del",title: "Remove After Import",isSwitch:true)]),
......@@ -90,7 +119,8 @@ func getSettingViewInfo() -> [SettingModel] {
RowInfoModel(imageName: "icon_set_secret_Email_support", title: "Email Support"),
RowInfoModel(imageName: "icon_set_secret_FAQ", title: "FAQ"),
RowInfoModel(imageName: "icon_set_secret_about_us", title: "About Us"),
RowInfoModel(imageName: "icon_set_secret_Privacy", title: "Privacy Policy"),]),]
RowInfoModel(imageName: "icon_set_secret_Privacy", title: "Privacy Policy"),]),
]
}else{
return [
SettingModel(sectionTitle: "",rowInfo: [RowInfoModel(imageName: "",title: "")]),
......@@ -99,7 +129,7 @@ func getSettingViewInfo() -> [SettingModel] {
SettingModel(sectionTitle: "Secret space",rowInfo: [RowInfoModel(imageName: "icon_set_secret_lock",title: "Use PIN" , isSwitch:true),
RowInfoModel(imageName: "icon_set_secret_Face",title: "Use Face ID",isSwitch:true),
RowInfoModel(imageName: "icon_set_secret_ChangePin",title: "Change PIN"),
RowInfoModel(imageName: "icon_set_secret_Del",title: "Remove After Import",isSwitch:true)]),
......@@ -122,37 +152,6 @@ func getSettingViewInfo() -> [SettingModel] {
RowInfoModel(imageName: "icon_set_secret_Privacy", title: "Privacy Policy"),]),]
}
}
return [
SettingModel(sectionTitle: "",rowInfo: [RowInfoModel(imageName: "",title: "")]),
SettingModel(sectionTitle: "E-mail",rowInfo: [RowInfoModel(imageName: "icon_set_secret_Email_l", title: "Log in")]),
SettingModel(sectionTitle: "Secret space",rowInfo: [RowInfoModel(imageName: "icon_set_secret_lock",title: "Use PIN" , isSwitch:true),
RowInfoModel(imageName: "icon_set_secret_Face",title: "Use Face ID",isSwitch:true),
RowInfoModel(imageName: "icon_set_secret_ChangePin",title: "Change PIN"),
RowInfoModel(imageName: "icon_set_secret_Del",title: "Remove After Import",isSwitch:true)]),
SettingModel(sectionTitle: "Practical tools",rowInfo: [RowInfoModel(imageName: "icon_set_secret_Email_l", title: "Widgets")]),
SettingModel(sectionTitle: "Stay in touch",rowInfo: [RowInfoModel(imageName: "icon_set_secret_ins_setting", title: "Follow on Instagram"),
RowInfoModel(imageName: "icon_set_secret_rate_setting", title: "Rate Us"),
RowInfoModel(imageName: "icon_set_secret_share_setting", title: "Share Us"),]),
SettingModel(sectionTitle: "Other",rowInfo: [RowInfoModel(imageName: "icon_set_secret_Hint", title: "Hint"),
RowInfoModel(imageName: "icon_set_secret_keep", title: "Keep List"),
RowInfoModel(imageName: "icon_set_secret__vibration_setting", title: "Vibration",isSwitch:true)]),
SettingModel(sectionTitle: "Support",rowInfo: [RowInfoModel(imageName: "icon_set_secret_restore", title: "Resume purchase"),
RowInfoModel(imageName: "icon_set_secret_Email_support", title: "Email Support"),
RowInfoModel(imageName: "icon_set_secret_FAQ", title: "FAQ"),
RowInfoModel(imageName: "icon_set_secret_about_us", title: "About Us"),
RowInfoModel(imageName: "icon_set_secret_Privacy", title: "Privacy Policy"),]),
]
}
class SettingConfiguration: NSObject {
......
......@@ -34,7 +34,7 @@ class SettingNormalCell : UITableViewCell {
lazy var fLabel : UILabel = {
let label = UILabel();
label.text = "ceshi"
label.font = UIFont(name: "PingFang SC-Bold", size: 14)
label.font = UIFont.systemFont(ofSize: 14, weight: .bold)
label.textColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
label.textAlignment = .left
return label
......
......@@ -55,7 +55,7 @@ class SettingSwitchCell : UITableViewCell {
lazy var fLabel : UILabel = {
let label = UILabel();
label.text = "ceshi"
label.font = UIFont(name: "PingFang SC-Bold", size: 14)
label.font = UIFont.systemFont(ofSize: 14, weight: .bold)
label.textColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
label.textAlignment = .left
return label
......
......@@ -163,10 +163,12 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
emailLoginSignOut()
break
case settingLabels.UsePIN.rawValue:
vibrate()
secretspace()
break
case settingLabels.UseFaceID.rawValue:
SetFaceID()
vibrate()
SetFaceID(indexPath)
break
case settingLabels.ChangePIN.rawValue:
changePIN()
......@@ -174,12 +176,30 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
case settingLabels.RemoveAfterImport.rawValue:
SettingConfiguration.share.config.removeImg = !SettingConfiguration.share.config.removeImg
tableView.reloadRows(at: [indexPath], with: .none)
vibrate()
break
case settingLabels.Widgets.rawValue:
let widget = WidgetViewController()
self.navigationController?.pushViewController(widget, animated: true)
var callblock:(()->Void) = {[weak self] in
guard let self = self else { return }
let widget = WidgetViewController()
self.navigationController?.pushViewController(widget, animated: true)
}
if AdvManager.shared.advTimeAfterInAPP <= 0{
if IAPManager.share.isSubscribed == false {
AdvManager.shared.showInterstitialAd(vc: self)
}else{
callblock()
}
}else {
callblock()
}
AdvManager.shared.finisedCallBack = {
callblock()
}
break
case settingLabels.FollowonInstagram.rawValue:
guard let url = URL(string: "https://www.instagram.com/phone.manager.app/") else { return }
UIApplication.shared.open(url)
break
case settingLabels.RateUs.rawValue:
self.review()
......@@ -188,6 +208,8 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
self.PhoneShare()
break
case settingLabels.Hint.rawValue:
let hint = PMHintsController()
self.navigationController?.pushViewController(hint, animated: true)
break
case settingLabels.KeepList.rawValue:
let vc = MaintainViewListController()
......@@ -196,17 +218,23 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
case settingLabels.Vibration.rawValue:
SettingConfiguration.share.config.vibration = !(SettingConfiguration.share.config.vibration ?? false)
tableView.reloadRows(at: [indexPath], with: .none)
vibrate(true)
break
case settingLabels.Resumepurchase.rawValue:
break
case settingLabels.EmailSupport.rawValue:
let emailSupport = PMEmailSupportController()
self.navigationController?.pushViewController(emailSupport, animated: true)
break
case settingLabels.FAQ.rawValue:
let faq = PMFAQController()
self.navigationController?.pushViewController(faq, animated: true)
break
case settingLabels.AboutUs.rawValue:
let AboutUs = PMAboutUsController()
self.navigationController?.pushViewController(AboutUs, animated: true)
break
case settingLabels.PrivacyPolicy.rawValue:
jumpWeb(detailModel.title)
......@@ -216,7 +244,6 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
}
}
// MARK: - 隐私空间PIN
private func secretspace() -> Void {
if SettingConfiguration.share.config.secret?.count ?? 0 == 4 {
......@@ -245,7 +272,7 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
}
// MARK: - 面容
private func SetFaceID() -> Void {
private func SetFaceID(_ indexPath:IndexPath) -> Void {
if SettingConfiguration.share.config.faceId == false {
if PMFaceIDManger.request() {
PMFaceIDManger.authenticateWithFaceID(reason: "Unlock privacy space") {[weak self] success, error in
......@@ -257,6 +284,7 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
}
}else{
SettingConfiguration.share.config.faceId = false
self.tableView.reloadRows(at: [indexPath], with: .none)
}
}
......@@ -292,22 +320,38 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
alert.callblock = { idx in
self.view.hideBlur()
if idx == 1 {
PMEmailManager.shareManager.signOut { success in
PMEmailManager.shareManager.signOut {[weak self] success in
if success {
EmailFilterManager.share.signOut()
self?.tableView.reloadData()
}
}
}
}
alert.show()
}else{
let vc:EmailLoginController = EmailLoginController()
vc.state = .home
self.navigationController?.pushViewController(vc, animated: true)
let callblock:(()->Void) = { [weak self] in
guard let self = self else { return }
let vc:EmailLoginController = EmailLoginController()
vc.state = .home
self.navigationController?.pushViewController(vc, animated: true)
self.tableView.reloadData()
}
if AdvManager.shared.advTimeAfterInAPP <= 0{
if IAPManager.share.isSubscribed == false {
AdvManager.shared.showInterstitialAd(vc: self)
}else{
callblock()
}
}else {
callblock()
}
AdvManager.shared.finisedCallBack = {
callblock()
}
}
}
// MARK: - 评分
private func review() -> Void {
let reviewURLString = "itms-apps://itunes.apple.com/app/id1530333201?action=write-review"
......@@ -321,7 +365,7 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
// MARK: - 分享
private func PhoneShare() -> Void {
let items: [Any] = [ URL(string: "itms-apps://itunes.apple.com/app/id1530333201")! ]
let items: [Any] = ["Want to organize your photo library and free up storage space? Try our app’s smart cleanup feature now!",URL(string: "https://apps.apple.com/app/id1530333201")! ]
let shareVc = UIActivityViewController(
activityItems: items,
applicationActivities: nil
......
//
// PMWidgetExampleController.swift
// PhoneManager
//
// Created by edy on 2025/5/16.
//
import UIKit
class PMWidgetExampleController: UIViewController ,UIScrollViewDelegate{
@IBOutlet weak var PMWidgetMainBtn: UIButton!
@IBOutlet weak var PMWidgetLockBtn: UIButton!
@IBOutlet weak var PMWidgetMainScroll: UIScrollView!
@IBOutlet weak var PMWidgetLockScroll: UIScrollView!
@IBOutlet weak var PMWidgetPage: UIPageControl!
@IBOutlet weak var ReturnAction: UIButton!
@IBOutlet weak var NextActions: UIButton!
var current = 0 {
didSet{
if current <= 0 {
ReturnAction.isHidden = true
}else{
ReturnAction.isHidden = false
}
NextActions.setTitle("Next", for: .normal)
if current == 4 {
NextActions.setTitle("Ok", for: .normal)
}
PMWidgetPage.currentPage = current
}
}
var type = 0 {
didSet{
PMWidgetMainScroll.isHidden = !(type == 0)
PMWidgetLockScroll.isHidden = type == 0
current = 0
animation()
}
}
private func animation() -> Void {
if type == 0 {
let orx = CGFloat(current) * self.PMWidgetMainScroll.width
UIView.animate(withDuration: 0.3) {
self.PMWidgetMainScroll.contentOffset = CGPointMake(orx, 0)
}
}else{
let orx = CGFloat(current) * self.PMWidgetLockScroll.width
UIView.animate(withDuration: 0.3) {
self.PMWidgetLockScroll.contentOffset = CGPointMake(orx, 0)
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
PMWidgetMainBtn.isSelected = true
PMWidgetMainBtn.setBackgroundImage(UIImage.Clear(.white), for: .normal)
PMWidgetMainBtn.setBackgroundImage(UIImage.Clear(UIColor.colorWithHex(hexStr: "#0082FF")), for: .selected)
PMWidgetLockBtn.setBackgroundImage(UIImage.Clear(.white), for: .normal)
PMWidgetLockBtn.setBackgroundImage(UIImage.Clear(UIColor.colorWithHex(hexStr: "#0082FF")), for: .selected)
PMWidgetPage.numberOfPages = 5
PMWidgetMainScroll.delegate = self;
PMWidgetLockScroll.delegate = self
type = 0
self.navigationController?.isNavigationBarHidden = true
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
ScrollToCurrent(scrollView)
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if decelerate {
ScrollToCurrent(scrollView)
}
}
private func ScrollToCurrent(_ scroll:UIScrollView) -> Void {
let orx = scroll.contentOffset.x / scroll.width
PMWidgetPage.currentPage = Int(round(orx))
current = Int(round(orx))
if orx == 0 {
ReturnAction.isHidden = true
}else{
ReturnAction.isHidden = false
}
NextActions.setTitle("Next", for: .normal)
if orx == 4 {
NextActions.setTitle("Ok", for: .normal)
}
}
@IBAction func PMWidgetActions(_ sender: UIButton) {
if sender.isSelected == false {
if sender == PMWidgetMainBtn {
PMWidgetLockBtn.isSelected = false
type = 0
}else{
PMWidgetMainBtn.isSelected = false
type = 1
}
sender.isSelected = true
}
}
@IBAction func BottomActions(_ sender: UIButton) {
if sender == ReturnAction {
self.current -= 1
animation()
}else{
if self.current == 4 {
self.dismiss(animated: true)
}else{
self.current += 1
animation()
}
}
}
@IBAction func PMClose(_ sender: Any) {
self.dismiss(animated: true)
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="PMWidgetExampleController" customModule="PhoneManager" customModuleProvider="target">
<connections>
<outlet property="NextActions" destination="GO7-6H-UQ4" id="hrD-0u-bsG"/>
<outlet property="PMWidgetLockBtn" destination="TFK-eC-5dN" id="lCr-xM-vj0"/>
<outlet property="PMWidgetLockScroll" destination="sjI-9n-Ju7" id="5SF-ag-qUl"/>
<outlet property="PMWidgetMainBtn" destination="C6M-IT-mef" id="weH-Vz-qX5"/>
<outlet property="PMWidgetMainScroll" destination="gGy-sG-s9Z" id="16j-hV-Vda"/>
<outlet property="PMWidgetPage" destination="aYN-96-jQ9" id="sl0-gB-LUX"/>
<outlet property="ReturnAction" destination="f2o-NG-Aqj" id="JVj-1T-JPb"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="image_76" translatesAutoresizingMaskIntoConstraints="NO" id="FYg-a3-i5o">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="7W8-aC-tu2">
<rect key="frame" x="352" y="69" width="26" height="42"/>
<constraints>
<constraint firstAttribute="height" constant="42" id="Kun-bL-krq"/>
</constraints>
<inset key="contentEdgeInsets" minX="10" minY="10" maxX="0.0" maxY="10"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" image="ic_widget_XXXXXXx"/>
<connections>
<action selector="PMClose:" destination="-1" eventType="touchUpInside" id="gqA-by-qHw"/>
</connections>
</button>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="rxS-gI-FCg">
<rect key="frame" x="49.666666666666657" y="131" width="294" height="40"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="C6M-IT-mef">
<rect key="frame" x="0.0" y="0.0" width="147" height="40"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="SyS-vf-fOG"/>
<constraint firstAttribute="width" constant="147" id="me0-mQ-bte"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Main screen">
<color key="titleColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
</state>
<state key="selected">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="PMWidgetActions:" destination="-1" eventType="touchUpInside" id="2bY-IZ-H4H"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="TFK-eC-5dN">
<rect key="frame" x="147" y="0.0" width="147" height="40"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Lock the screen">
<color key="titleColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
</state>
<state key="selected">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="PMWidgetActions:" destination="-1" eventType="touchUpInside" id="Z0X-xV-LMI"/>
</connections>
</button>
</subviews>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="Radius">
<real key="value" value="12"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="nQI-d2-eaf">
<rect key="frame" x="0.0" y="197" width="393" height="517"/>
<subviews>
<scrollView hidden="YES" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gGy-sG-s9Z">
<rect key="frame" x="0.0" y="0.0" width="121" height="517"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="RZR-Gz-KOY">
<rect key="frame" x="0.0" y="0.0" width="605" height="517"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="UoD-WB-1Ln">
<rect key="frame" x="0.0" y="0.0" width="121" height="517"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Long press the blank area until the application of jitter" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OfE-BZ-gFy">
<rect key="frame" x="65" y="5" width="0.0" height="33.666666666666664"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="33.670000000000002" id="JcP-rA-ocO"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_widget_Main_Q1" translatesAutoresizingMaskIntoConstraints="NO" id="cPV-d9-hjA">
<rect key="frame" x="-57.666666666666664" y="56.666666666666657" width="236.33333333333334" height="455.33333333333337"/>
<constraints>
<constraint firstAttribute="width" secondItem="cPV-d9-hjA" secondAttribute="height" multiplier="246:474" id="QHg-W2-hrG"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="cPV-d9-hjA" firstAttribute="top" secondItem="OfE-BZ-gFy" secondAttribute="bottom" constant="18" id="693-Tw-X5s"/>
<constraint firstItem="cPV-d9-hjA" firstAttribute="centerX" secondItem="UoD-WB-1Ln" secondAttribute="centerX" id="ZmB-GS-Wav"/>
<constraint firstAttribute="bottom" secondItem="cPV-d9-hjA" secondAttribute="bottom" constant="5" id="bPX-6B-cEo"/>
<constraint firstAttribute="trailing" secondItem="OfE-BZ-gFy" secondAttribute="trailing" constant="56" id="irQ-jJ-rYp"/>
<constraint firstItem="OfE-BZ-gFy" firstAttribute="leading" secondItem="UoD-WB-1Ln" secondAttribute="leading" constant="65" id="tAb-sW-Mel"/>
<constraint firstItem="OfE-BZ-gFy" firstAttribute="top" secondItem="UoD-WB-1Ln" secondAttribute="top" constant="5" id="yPU-5n-uQc"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bS6-mX-TrJ">
<rect key="frame" x="121" y="0.0" width="121" height="517"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Click &quot;Edit&quot; in the upper left corner and select &quot;Add Widget&quot;" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wCO-ns-Pm8">
<rect key="frame" x="65" y="5" width="0.0" height="33.666666666666664"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="33.670000000000002" id="5zG-6P-eYM"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_widget_Main_Q2" translatesAutoresizingMaskIntoConstraints="NO" id="0ts-5m-Ivt">
<rect key="frame" x="-57.666666666666664" y="56.666666666666657" width="236.33333333333334" height="455.33333333333337"/>
<constraints>
<constraint firstAttribute="width" secondItem="0ts-5m-Ivt" secondAttribute="height" multiplier="246:474" id="ZKd-KL-9d9"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="wCO-ns-Pm8" secondAttribute="trailing" constant="56" id="6Nu-48-JgP"/>
<constraint firstItem="0ts-5m-Ivt" firstAttribute="centerX" secondItem="bS6-mX-TrJ" secondAttribute="centerX" id="7Jk-xW-aUn"/>
<constraint firstItem="wCO-ns-Pm8" firstAttribute="leading" secondItem="bS6-mX-TrJ" secondAttribute="leading" constant="65" id="Bss-SQ-uMq"/>
<constraint firstItem="wCO-ns-Pm8" firstAttribute="top" secondItem="bS6-mX-TrJ" secondAttribute="top" constant="5" id="TgA-kQ-WKR"/>
<constraint firstItem="0ts-5m-Ivt" firstAttribute="top" secondItem="wCO-ns-Pm8" secondAttribute="bottom" constant="18" id="jWx-Wi-NlX"/>
<constraint firstAttribute="bottom" secondItem="0ts-5m-Ivt" secondAttribute="bottom" constant="5" id="qy1-eV-XGj"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="38K-UI-YND">
<rect key="frame" x="242" y="0.0" width="121" height="517"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Click on the search widget" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fpq-HG-uKt">
<rect key="frame" x="65" y="5" width="0.0" height="33.666666666666664"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="33.670000000000002" id="QWC-g8-lcc"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_widget_Main_Q4" translatesAutoresizingMaskIntoConstraints="NO" id="GQ8-BK-jRl">
<rect key="frame" x="-57.666666666666657" y="56.666666666666657" width="236.33333333333334" height="455.33333333333337"/>
<constraints>
<constraint firstAttribute="width" secondItem="GQ8-BK-jRl" secondAttribute="height" multiplier="246:474" id="hbZ-f2-o0C"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="fpq-HG-uKt" firstAttribute="leading" secondItem="38K-UI-YND" secondAttribute="leading" constant="65" id="1ri-g9-99i"/>
<constraint firstItem="GQ8-BK-jRl" firstAttribute="centerX" secondItem="38K-UI-YND" secondAttribute="centerX" id="9ED-Tb-jws"/>
<constraint firstAttribute="bottom" secondItem="GQ8-BK-jRl" secondAttribute="bottom" constant="5" id="A0P-9A-64e"/>
<constraint firstItem="fpq-HG-uKt" firstAttribute="top" secondItem="38K-UI-YND" secondAttribute="top" constant="5" id="HU7-Je-rc4"/>
<constraint firstAttribute="trailing" secondItem="fpq-HG-uKt" secondAttribute="trailing" constant="56" id="fho-aR-V3M"/>
<constraint firstItem="GQ8-BK-jRl" firstAttribute="top" secondItem="fpq-HG-uKt" secondAttribute="bottom" constant="18" id="wOJ-0D-zOA"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="mx1-3P-LAT">
<rect key="frame" x="363" y="0.0" width="121" height="517"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Search for &quot;Phone Manager&quot; and select the widget" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OAU-gT-85e">
<rect key="frame" x="65" y="5" width="0.0" height="33.666666666666664"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="33.670000000000002" id="IP7-WO-fsR"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_widget_Main_Q3" translatesAutoresizingMaskIntoConstraints="NO" id="sgh-a2-DOq">
<rect key="frame" x="-57.666666666666686" y="56.666666666666657" width="236.33333333333334" height="455.33333333333337"/>
<constraints>
<constraint firstAttribute="width" secondItem="sgh-a2-DOq" secondAttribute="height" multiplier="246:474" id="AB0-7F-PKV"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="OAU-gT-85e" firstAttribute="top" secondItem="mx1-3P-LAT" secondAttribute="top" constant="5" id="8jC-cU-mEA"/>
<constraint firstAttribute="bottom" secondItem="sgh-a2-DOq" secondAttribute="bottom" constant="5" id="JWC-dV-xzo"/>
<constraint firstItem="sgh-a2-DOq" firstAttribute="top" secondItem="OAU-gT-85e" secondAttribute="bottom" constant="18" id="M0G-Kk-WuH"/>
<constraint firstItem="OAU-gT-85e" firstAttribute="leading" secondItem="mx1-3P-LAT" secondAttribute="leading" constant="65" id="RXc-17-rSB"/>
<constraint firstItem="sgh-a2-DOq" firstAttribute="centerX" secondItem="mx1-3P-LAT" secondAttribute="centerX" id="mMB-e9-uIB"/>
<constraint firstAttribute="trailing" secondItem="OAU-gT-85e" secondAttribute="trailing" constant="56" id="y9u-Z7-eVY"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3I5-lG-oXe">
<rect key="frame" x="484" y="0.0" width="121" height="517"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Select the size and click &quot;Add Widget&quot;" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="9gN-lV-Lxv">
<rect key="frame" x="65" y="5" width="0.0" height="33.666666666666664"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="33.670000000000002" id="IJp-0j-03a"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_widget_Main_Q5" translatesAutoresizingMaskIntoConstraints="NO" id="jLC-Br-dJV">
<rect key="frame" x="-57.666666666666686" y="56.666666666666657" width="236.33333333333334" height="455.33333333333337"/>
<constraints>
<constraint firstAttribute="width" secondItem="jLC-Br-dJV" secondAttribute="height" multiplier="246:474" id="wkT-j0-ue5"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="jLC-Br-dJV" secondAttribute="bottom" constant="5" id="0yT-or-F9K"/>
<constraint firstItem="jLC-Br-dJV" firstAttribute="top" secondItem="9gN-lV-Lxv" secondAttribute="bottom" constant="18" id="6vl-bl-ewu"/>
<constraint firstItem="jLC-Br-dJV" firstAttribute="centerX" secondItem="3I5-lG-oXe" secondAttribute="centerX" id="Cuw-kl-9dO"/>
<constraint firstItem="9gN-lV-Lxv" firstAttribute="top" secondItem="3I5-lG-oXe" secondAttribute="top" constant="5" id="Tnc-mS-7DO"/>
<constraint firstAttribute="trailing" secondItem="9gN-lV-Lxv" secondAttribute="trailing" constant="56" id="Ww9-gR-RA3"/>
<constraint firstItem="9gN-lV-Lxv" firstAttribute="leading" secondItem="3I5-lG-oXe" secondAttribute="leading" constant="65" id="c7a-Gf-CAQ"/>
</constraints>
</view>
</subviews>
</stackView>
</subviews>
<constraints>
<constraint firstItem="RZR-Gz-KOY" firstAttribute="centerY" secondItem="gGy-sG-s9Z" secondAttribute="centerY" id="CCv-Gr-EGN"/>
<constraint firstAttribute="trailing" secondItem="RZR-Gz-KOY" secondAttribute="trailing" id="HY2-WG-HPc"/>
<constraint firstItem="RZR-Gz-KOY" firstAttribute="width" secondItem="gGy-sG-s9Z" secondAttribute="width" multiplier="5" id="b0N-7H-3cF"/>
<constraint firstAttribute="bottom" secondItem="RZR-Gz-KOY" secondAttribute="bottom" id="u9l-BR-B0Z"/>
<constraint firstItem="RZR-Gz-KOY" firstAttribute="top" secondItem="gGy-sG-s9Z" secondAttribute="top" id="uCM-N6-hWs"/>
<constraint firstItem="RZR-Gz-KOY" firstAttribute="leading" secondItem="gGy-sG-s9Z" secondAttribute="leading" id="xmE-jX-cIE"/>
</constraints>
</scrollView>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sjI-9n-Ju7">
<rect key="frame" x="0.0" y="0.0" width="393" height="517"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="xzD-8E-jbd">
<rect key="frame" x="0.0" y="0.0" width="1965" height="517"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zgR-w3-cDz">
<rect key="frame" x="0.0" y="0.0" width="393" height="517"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Long press the lock screen interface" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ftB-28-cB1">
<rect key="frame" x="65" y="5" width="272" height="33.666666666666664"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="33.670000000000002" id="J2P-bo-CYY"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_widget_Main_L1" translatesAutoresizingMaskIntoConstraints="NO" id="qH5-Rg-1ds">
<rect key="frame" x="78.333333333333329" y="56.666666666666657" width="236.33333333333337" height="455.33333333333337"/>
<constraints>
<constraint firstAttribute="width" secondItem="qH5-Rg-1ds" secondAttribute="height" multiplier="246:474" id="0PX-zL-YQi"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="qH5-Rg-1ds" firstAttribute="top" secondItem="ftB-28-cB1" secondAttribute="bottom" constant="18" id="3Xg-As-RCW"/>
<constraint firstItem="qH5-Rg-1ds" firstAttribute="centerX" secondItem="zgR-w3-cDz" secondAttribute="centerX" id="4eV-qZ-YYc"/>
<constraint firstAttribute="bottom" secondItem="qH5-Rg-1ds" secondAttribute="bottom" constant="5" id="9Ha-LK-PeR"/>
<constraint firstAttribute="trailing" secondItem="ftB-28-cB1" secondAttribute="trailing" constant="56" id="GLV-X4-hFO"/>
<constraint firstItem="ftB-28-cB1" firstAttribute="top" secondItem="zgR-w3-cDz" secondAttribute="top" constant="5" id="jow-iJ-q7P"/>
<constraint firstItem="ftB-28-cB1" firstAttribute="leading" secondItem="zgR-w3-cDz" secondAttribute="leading" constant="65" id="zQc-1z-GcK"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QIo-dp-mHq">
<rect key="frame" x="393" y="0.0" width="393" height="517"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Click the &quot;Customize&quot; button at the bottom" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="5ya-tC-fOw">
<rect key="frame" x="65" y="5" width="272" height="33.666666666666664"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="33.670000000000002" id="rNA-pk-eYl"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_widget_Main_L2" translatesAutoresizingMaskIntoConstraints="NO" id="Wlf-Lp-aIc">
<rect key="frame" x="78.333333333333329" y="56.666666666666657" width="236.33333333333337" height="455.33333333333337"/>
<constraints>
<constraint firstAttribute="width" secondItem="Wlf-Lp-aIc" secondAttribute="height" multiplier="246:474" id="2rl-PB-07D"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="5ya-tC-fOw" firstAttribute="leading" secondItem="QIo-dp-mHq" secondAttribute="leading" constant="65" id="CZn-cs-Bkr"/>
<constraint firstItem="5ya-tC-fOw" firstAttribute="top" secondItem="QIo-dp-mHq" secondAttribute="top" constant="5" id="W9M-hB-ofL"/>
<constraint firstAttribute="bottom" secondItem="Wlf-Lp-aIc" secondAttribute="bottom" constant="5" id="gOd-H0-5hJ"/>
<constraint firstItem="Wlf-Lp-aIc" firstAttribute="top" secondItem="5ya-tC-fOw" secondAttribute="bottom" constant="18" id="iqO-Ih-2Kl"/>
<constraint firstAttribute="trailing" secondItem="5ya-tC-fOw" secondAttribute="trailing" constant="56" id="muS-42-PmD"/>
<constraint firstItem="Wlf-Lp-aIc" firstAttribute="centerX" secondItem="QIo-dp-mHq" secondAttribute="centerX" id="pD2-V7-wBW"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4bD-wG-6di">
<rect key="frame" x="786" y="0.0" width="393" height="517"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Select the lock screen style" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ckG-6a-Zc0">
<rect key="frame" x="65" y="5" width="272" height="33.666666666666664"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="33.670000000000002" id="Oyy-Cl-sa8"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_widget_Main_L3" translatesAutoresizingMaskIntoConstraints="NO" id="ins-xu-M52">
<rect key="frame" x="78.333333333333385" y="56.666666666666657" width="236.33333333333337" height="455.33333333333337"/>
<constraints>
<constraint firstAttribute="width" secondItem="ins-xu-M52" secondAttribute="height" multiplier="246:474" id="sSX-XV-vK7"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="ckG-6a-Zc0" secondAttribute="trailing" constant="56" id="8Cb-Oa-a6h"/>
<constraint firstItem="ins-xu-M52" firstAttribute="centerX" secondItem="4bD-wG-6di" secondAttribute="centerX" id="8rW-l1-z7A"/>
<constraint firstItem="ins-xu-M52" firstAttribute="top" secondItem="ckG-6a-Zc0" secondAttribute="bottom" constant="18" id="Enn-c7-nCK"/>
<constraint firstItem="ckG-6a-Zc0" firstAttribute="top" secondItem="4bD-wG-6di" secondAttribute="top" constant="5" id="ZGc-7h-pCK"/>
<constraint firstAttribute="bottom" secondItem="ins-xu-M52" secondAttribute="bottom" constant="5" id="a2L-8B-WQd"/>
<constraint firstItem="ckG-6a-Zc0" firstAttribute="leading" secondItem="4bD-wG-6di" secondAttribute="leading" constant="65" id="yJ1-fe-KWQ"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="6b7-vI-kAX">
<rect key="frame" x="1179" y="0.0" width="393" height="517"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Click on the add widget in the lock screen area" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wcl-wB-jJK">
<rect key="frame" x="65" y="5" width="272" height="33.666666666666664"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="33.670000000000002" id="M7k-3R-Uk9"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_widget_Main_L4" translatesAutoresizingMaskIntoConstraints="NO" id="otQ-mD-woz">
<rect key="frame" x="78.333333333333272" y="56.666666666666657" width="236.33333333333337" height="455.33333333333337"/>
<constraints>
<constraint firstAttribute="width" secondItem="otQ-mD-woz" secondAttribute="height" multiplier="246:474" id="eDx-UV-a3w"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="otQ-mD-woz" secondAttribute="bottom" constant="5" id="3LL-zh-0le"/>
<constraint firstItem="otQ-mD-woz" firstAttribute="centerX" secondItem="6b7-vI-kAX" secondAttribute="centerX" id="ItX-rX-7a1"/>
<constraint firstAttribute="trailing" secondItem="Wcl-wB-jJK" secondAttribute="trailing" constant="56" id="RYD-E3-fje"/>
<constraint firstItem="Wcl-wB-jJK" firstAttribute="top" secondItem="6b7-vI-kAX" secondAttribute="top" constant="5" id="fq0-Qi-Blk"/>
<constraint firstItem="otQ-mD-woz" firstAttribute="top" secondItem="Wcl-wB-jJK" secondAttribute="bottom" constant="18" id="v3M-Td-4U6"/>
<constraint firstItem="Wcl-wB-jJK" firstAttribute="leading" secondItem="6b7-vI-kAX" secondAttribute="leading" constant="65" id="yuV-aG-OVe"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xrJ-S3-dWv">
<rect key="frame" x="1572" y="0.0" width="393" height="517"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Select Phone Manager and add widgets" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SJd-3G-fas">
<rect key="frame" x="65" y="5" width="272" height="33.666666666666664"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="33.670000000000002" id="cwO-nD-NxS"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_widget_Main_L5" translatesAutoresizingMaskIntoConstraints="NO" id="Jg0-mF-9x8">
<rect key="frame" x="78.333333333333272" y="56.666666666666657" width="236.33333333333337" height="455.33333333333337"/>
<constraints>
<constraint firstAttribute="width" secondItem="Jg0-mF-9x8" secondAttribute="height" multiplier="246:474" id="Mq5-TH-Gsj"/>
</constraints>
</imageView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="SJd-3G-fas" secondAttribute="trailing" constant="56" id="04u-t4-scZ"/>
<constraint firstItem="Jg0-mF-9x8" firstAttribute="centerX" secondItem="xrJ-S3-dWv" secondAttribute="centerX" id="OiU-4A-FTQ"/>
<constraint firstAttribute="bottom" secondItem="Jg0-mF-9x8" secondAttribute="bottom" constant="5" id="Vf5-FC-StY"/>
<constraint firstItem="Jg0-mF-9x8" firstAttribute="top" secondItem="SJd-3G-fas" secondAttribute="bottom" constant="18" id="qyg-Nr-Yu5"/>
<constraint firstItem="SJd-3G-fas" firstAttribute="top" secondItem="xrJ-S3-dWv" secondAttribute="top" constant="5" id="vdN-pZ-VBB"/>
<constraint firstItem="SJd-3G-fas" firstAttribute="leading" secondItem="xrJ-S3-dWv" secondAttribute="leading" constant="65" id="xNu-w7-ZjI"/>
</constraints>
</view>
</subviews>
</stackView>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="xzD-8E-jbd" secondAttribute="bottom" id="SCX-0h-oE5"/>
<constraint firstItem="xzD-8E-jbd" firstAttribute="width" secondItem="sjI-9n-Ju7" secondAttribute="width" multiplier="5" id="buq-M8-5GQ"/>
<constraint firstItem="xzD-8E-jbd" firstAttribute="top" secondItem="sjI-9n-Ju7" secondAttribute="top" id="jGT-U2-E6Q"/>
<constraint firstAttribute="trailing" secondItem="xzD-8E-jbd" secondAttribute="trailing" id="tjR-ld-mEE"/>
<constraint firstItem="xzD-8E-jbd" firstAttribute="leading" secondItem="sjI-9n-Ju7" secondAttribute="leading" id="xFV-wN-cTV"/>
<constraint firstItem="xzD-8E-jbd" firstAttribute="centerY" secondItem="sjI-9n-Ju7" secondAttribute="centerY" id="zjj-GX-f5r"/>
</constraints>
</scrollView>
</subviews>
</stackView>
<pageControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" numberOfPages="3" translatesAutoresizingMaskIntoConstraints="NO" id="aYN-96-jQ9">
<rect key="frame" x="160" y="734" width="73" height="0.0"/>
<color key="pageIndicatorTintColor" red="0.85098039215686272" green="0.85098039215686272" blue="0.85098039215686272" alpha="1" colorSpace="calibratedRGB"/>
<color key="currentPageIndicatorTintColor" red="0.0" green="0.50980392156862742" blue="1" alpha="1" colorSpace="calibratedRGB"/>
</pageControl>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="13" translatesAutoresizingMaskIntoConstraints="NO" id="8pI-BH-CCS">
<rect key="frame" x="16" y="752" width="361" height="46"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="f2o-NG-Aqj">
<rect key="frame" x="0.0" y="0.0" width="174" height="46"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="46" id="75d-1a-0h0"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Return">
<color key="titleColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
</state>
<state key="selected">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="Radius">
<real key="value" value="23"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<action selector="BottomActions:" destination="-1" eventType="touchUpInside" id="IBP-xA-1aC"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GO7-6H-UQ4">
<rect key="frame" x="187" y="0.0" width="174" height="46"/>
<color key="backgroundColor" red="0.0" green="0.50980392156862742" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="16"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Next">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<state key="selected">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="Radius">
<real key="value" value="23"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<action selector="BottomActions:" destination="-1" eventType="touchUpInside" id="3zi-3N-pKs"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="Radius">
<real key="value" value="12"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="aYN-96-jQ9" firstAttribute="top" secondItem="nQI-d2-eaf" secondAttribute="bottom" constant="20" id="2Ko-Eh-hHa"/>
<constraint firstItem="rxS-gI-FCg" firstAttribute="top" secondItem="7W8-aC-tu2" secondAttribute="bottom" constant="20" id="2LN-8U-UAE"/>
<constraint firstItem="rxS-gI-FCg" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="430-o4-72i"/>
<constraint firstItem="nQI-d2-eaf" firstAttribute="top" secondItem="rxS-gI-FCg" secondAttribute="bottom" constant="26" id="4Og-bM-A5t"/>
<constraint firstItem="7W8-aC-tu2" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="10" id="6eD-AS-Jyr"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="7W8-aC-tu2" secondAttribute="trailing" constant="15" id="8gY-oJ-j5T"/>
<constraint firstItem="FYg-a3-i5o" firstAttribute="trailing" secondItem="fnl-2z-Ty3" secondAttribute="trailing" id="GjD-oM-M9W"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="nQI-d2-eaf" secondAttribute="trailing" id="Jwc-XP-xAy"/>
<constraint firstItem="nQI-d2-eaf" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="LOg-do-7uM"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="8pI-BH-CCS" secondAttribute="trailing" constant="16" id="O5y-bo-ZDJ"/>
<constraint firstAttribute="bottom" secondItem="FYg-a3-i5o" secondAttribute="bottom" id="TdR-Tz-zVo"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="8pI-BH-CCS" secondAttribute="bottom" constant="20" id="ZJp-Ge-wa0"/>
<constraint firstItem="aYN-96-jQ9" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="ZhL-KG-ZIi"/>
<constraint firstItem="8pI-BH-CCS" firstAttribute="top" secondItem="aYN-96-jQ9" secondAttribute="bottom" constant="18" id="lCt-lC-b79"/>
<constraint firstItem="FYg-a3-i5o" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="smE-PW-7bq"/>
<constraint firstItem="FYg-a3-i5o" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="tUT-7w-HC5"/>
<constraint firstItem="8pI-BH-CCS" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="16" id="wCk-QT-HKb"/>
</constraints>
<point key="canvasLocation" x="130.53435114503816" y="-12.67605633802817"/>
</view>
</objects>
<resources>
<image name="ic_widget_Main_L1" width="246" height="474"/>
<image name="ic_widget_Main_L2" width="246" height="474"/>
<image name="ic_widget_Main_L3" width="246" height="474"/>
<image name="ic_widget_Main_L4" width="246" height="474"/>
<image name="ic_widget_Main_L5" width="246" height="474"/>
<image name="ic_widget_Main_Q1" width="246" height="474"/>
<image name="ic_widget_Main_Q2" width="246" height="474"/>
<image name="ic_widget_Main_Q3" width="246" height="474"/>
<image name="ic_widget_Main_Q4" width="245.66667175292969" height="473"/>
<image name="ic_widget_Main_Q5" width="246" height="474"/>
<image name="ic_widget_XXXXXXx" width="16" height="16"/>
<image name="image_76" width="375" height="812"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
//
// PMWidgetGuideStartController.swift
// PhoneManager
//
// Created by edy on 2025/5/16.
//
import UIKit
class PMWidgetGuideStartController: UIViewController {
var callblock:(()->Void) = {}
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.isNavigationBarHidden = true
}
@IBAction func StartNextAction(_ sender: Any) {
callblock()
}
@IBAction func PMClose(_ sender: Any) {
self.dismiss(animated: true)
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="PMWidgetGuideStartController" customModule="PhoneManager" customModuleProvider="target">
<connections>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Jx3-dI-rXt">
<rect key="frame" x="352" y="69" width="26" height="53"/>
<inset key="contentEdgeInsets" minX="10" minY="10" maxX="0.0" maxY="10"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" image="ic_widget_XXXXXXx"/>
<connections>
<action selector="PMClose:" destination="-1" eventType="touchUpInside" id="tNM-zg-9hj"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Add widgets to the home screen and the lock screen" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kbM-qf-WH2">
<rect key="frame" x="36" y="142" width="321" height="43"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="43" id="cTr-dF-GVf"/>
</constraints>
<fontDescription key="fontDescription" type="system" weight="semibold" pointSize="18"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jAN-Lj-ySf">
<rect key="frame" x="23" y="205" width="347" height="43"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="43" id="gWB-Me-UTE"/>
</constraints>
<string key="text">Easily monitor your battery and storage space with convenient widgets, providing convenience for your home screen and lock screen!</string>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/>
<color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_widget_guideus" translatesAutoresizingMaskIntoConstraints="NO" id="Gk6-53-p7B">
<rect key="frame" x="34" y="268" width="325" height="442"/>
<constraints>
<constraint firstAttribute="width" secondItem="Gk6-53-p7B" secondAttribute="height" multiplier="25:34" id="JRq-xy-nP7"/>
</constraints>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="FzB-PE-uL0">
<rect key="frame" x="16" y="740" width="361" height="58"/>
<color key="backgroundColor" red="0.0" green="0.50980392156862742" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="58" id="H0t-sX-uiu"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="18"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Start using"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="Radius">
<real key="value" value="29"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<action selector="StartNextAction:" destination="-1" eventType="touchUpInside" id="IEs-GE-8pA"/>
</connections>
</button>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" red="0.90588235294117647" green="0.94509803921568625" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="jAN-Lj-ySf" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" constant="23" id="0hg-ZZ-cgL"/>
<constraint firstItem="Gk6-53-p7B" firstAttribute="top" secondItem="jAN-Lj-ySf" secondAttribute="bottom" constant="20" id="5K8-RY-RRE"/>
<constraint firstItem="jAN-Lj-ySf" firstAttribute="top" secondItem="kbM-qf-WH2" secondAttribute="bottom" constant="20" id="5cu-aJ-ud2"/>
<constraint firstAttribute="trailing" secondItem="jAN-Lj-ySf" secondAttribute="trailing" constant="23" id="9jt-yG-2C3"/>
<constraint firstItem="FzB-PE-uL0" firstAttribute="top" secondItem="Gk6-53-p7B" secondAttribute="bottom" constant="30" id="Ibh-ZB-Pcv"/>
<constraint firstItem="kbM-qf-WH2" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="36" id="Ie5-Fi-9zn"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="FzB-PE-uL0" secondAttribute="trailing" constant="16" id="O1A-bz-tvz"/>
<constraint firstItem="FzB-PE-uL0" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="16" id="Vpm-N7-5Mh"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="FzB-PE-uL0" secondAttribute="bottom" constant="20" id="Xmg-Oj-olO"/>
<constraint firstItem="Gk6-53-p7B" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="c7j-De-NMq"/>
<constraint firstItem="kbM-qf-WH2" firstAttribute="top" secondItem="Jx3-dI-rXt" secondAttribute="bottom" constant="20" id="fkG-Qv-2W9"/>
<constraint firstAttribute="trailing" secondItem="kbM-qf-WH2" secondAttribute="trailing" constant="36" id="g6U-Wh-rBz"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="Jx3-dI-rXt" secondAttribute="trailing" constant="15" id="k0K-LP-VIv"/>
<constraint firstItem="Jx3-dI-rXt" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="10" id="vg9-KR-dTG"/>
</constraints>
<point key="canvasLocation" x="131" y="-12"/>
</view>
</objects>
<resources>
<image name="ic_widget_XXXXXXx" width="16" height="16"/>
<image name="ic_widget_guideus" width="306" height="442"/>
</resources>
</document>
......@@ -33,6 +33,14 @@ class WidgetViewController: BaseViewController {
super.viewDidLoad()
view.backgroundColor = .white
setUI()
let infoBut = UIButton(type: .custom)
infoBut.setImage(UIImage(named: "ic_widget_InfoRight"), for: .normal)
infoBut.addTarget(self, action: #selector(infoRightAction), for: .touchUpInside)
titleView.addSubview(infoBut)
infoBut.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-15)
make.centerY.equalTo(titleView.backBtn.centerY)
}
}
override func viewWillAppear(_ animated: Bool) {
......@@ -46,7 +54,53 @@ class WidgetViewController: BaseViewController {
var widgetIdx = 0
widgetIdx = widgets.rawValue * 10 + widgetMode
widgetAppgourp.share.PushWidgetData(widgetIdx, battery: Int(battery), storage: Int(storage))
PMAlert(messsage: "Set Widget Successfully")
let save = EmailSaveController()
save.state = .success
save.modalTransitionStyle = .crossDissolve
save.modalPresentationStyle = .overFullScreen
self.present(save, animated: true)
DispatchQueue.main.asyncAfter(deadline: .now()+1.5) {
save.dismiss(animated: true) {
self.dismiss(animated: true)
if self.isJumpExample == false {
self.jumpGuidePage()
}
}
}
}
var isJumpExample:Bool {
set {
UserDefaults.standard.set(newValue, forKey: "widgetStartIn")
UserDefaults.standard.synchronize()
}
get {
return UserDefaults.standard.bool(forKey: "widgetStartIn")
}
}
@objc private func infoRightAction() -> Void {
jumpGuidePage()
}
func jumpGuidePage() -> Void {
if isJumpExample {
let example = PMWidgetExampleController()
example.modalPresentationStyle = .overFullScreen
self.present(example, animated: true)
}else{
isJumpExample = true
let guide = PMWidgetGuideStartController()
let guideM = UINavigationController(rootViewController: guide)
guideM.modalPresentationStyle = .overFullScreen
guide.callblock = {[weak self] in
guard let self = self else { return }
let example = PMWidgetExampleController()
guide.navigationController?.pushViewController(example, animated: true)
}
self.present(guideM, animated: true)
}
}
func setUI() -> Void {
......
......@@ -39,6 +39,7 @@ class EmailFilterFAVORITECell: UITableViewCell {
@IBAction func selectActions(_ sender: UISwitch) {
// sender.isOn = !sender.isOn
self.vibrate()
callblock(sender.isOn)
}
......
......@@ -21,6 +21,7 @@ class EmailFilterKeywordCell: UITableViewCell {
}
@IBAction func switchValueChange(_ sender: UISwitch) {
self.vibrate()
callblock("switch",sender.isOn)
}
......
......@@ -12,6 +12,7 @@ class EmailSaveController: UIViewController {
enum SuccessfromState {
case keyword
case signout
case success
}
var state:SuccessfromState = .keyword
......@@ -32,6 +33,9 @@ class EmailSaveController: UIViewController {
case .signout:
messageBox.text = "Exit successfully"
messageBox.textColor = .black
case .success:
messageBox.text = "complete"
messageBox.textColor = .black
}
}
......
......@@ -172,6 +172,7 @@ extension EmailFilterController : UITableViewDelegate,UITableViewDataSource {
cell.callblock = {[weak self] select in
guard let self = self else { return }
self.filter.date = indexPath.row
self.vibrate()
tableView.reloadData()
}
cell.selectionStyle = .none
......
......@@ -192,6 +192,7 @@ extension EmailCleanListView : UITableViewDataSource,UITableViewDelegate {
cell.callblock = {[weak self] in
guard let self = self else { return }
self.selectSet(indexPath)
self.vibrate()
tableView.reloadData()
}
return cell
......
......@@ -247,6 +247,7 @@ extension EmailContentView :UITableViewDelegate,UITableViewDataSource{
}
cell.callblock = {[weak self] in
guard let self = self else { return }
self.vibrate()
self.selectAll(indexPath)
tableView.reloadData()
}
......
......@@ -1208,6 +1208,7 @@ class SecretPhotoManager: NSObject, PhotoPickerControllerDelegate , CameraContro
callback!(-1,result.photoAssets)
}
func deleteAssets(_ assets:[PHAsset] = []) -> Void {
if assets.count > 0 {
PMLoadingHUD.share.show()
......
......@@ -57,7 +57,80 @@ extension UILabel {
}
}
var handleTextTapKey = "handleTextTapKey"
var ClickLabelTextsJey = "ClickLabelTextsJey"
extension UILabel {
private var handleTextTap:((String)->Void)? {
set {
objc_setAssociatedObject(self, &handleTextTapKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
}
get {
return objc_getAssociatedObject(self, &handleTextTapKey) as? ((String) -> Void)
}
}
private var ClickLabelTexts:[String]? {
set {
objc_setAssociatedObject(self, &ClickLabelTextsJey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
return objc_getAssociatedObject(self, &ClickLabelTextsJey) as? [String]
}
}
public func AddTapped(_ ClickStrs:[String],handle:@escaping((String)->Void)) -> Void {
if ClickLabelTexts?.count ?? 0 > 0 {
return
}
let tap = UITapGestureRecognizer(target: self, action: #selector(labelTapped(_:)))
self.addGestureRecognizer(tap)
self.isUserInteractionEnabled = true
ClickLabelTexts = ClickStrs
handleTextTap = handle
}
func frameForStringRange(_ range: NSRange) -> CGRect? {
guard let attributedText = attributedText else { return nil }
let textStorage = NSTextStorage(attributedString: attributedText)
let layoutManager = NSLayoutManager()
textStorage.addLayoutManager(layoutManager)
let textContainer = NSTextContainer(size: bounds.size)
textContainer.lineFragmentPadding = 0
layoutManager.addTextContainer(textContainer)
var glyphRange = NSRange()
layoutManager.characterRange(
forGlyphRange: range,
actualGlyphRange: &glyphRange
)
return layoutManager.boundingRect(
forGlyphRange: glyphRange,
in: textContainer
)
}
@objc private func labelTapped(_ gesture: UITapGestureRecognizer) {
self.layoutIfNeeded()
// 判断点击范围
for text in (ClickLabelTexts ?? []) {
if let range = self.text?.range(of: text) {
let nsRange = NSRange(range, in: self.text ?? "")
guard var subStringFrame = self.frameForStringRange(nsRange) else { return }
let locationInLabel = gesture.location(in: self)
if CGRectContainsPoint(subStringFrame, locationInLabel) {
handleTextTap?(text)
}
}
}
}
func isTapLocationInTextRange(_ gesture: UITapGestureRecognizer, range: NSRange) -> Bool {
let layoutManager = NSLayoutManager()
let textContainer = NSTextContainer(size: .zero)
......
......@@ -6,6 +6,9 @@
//
import Foundation
import AudioToolbox
import CoreHaptics
extension Int {
......@@ -119,3 +122,71 @@ extension CGFloat {
}
}
extension NSObject {
public func vibrate(_ all:Bool? = nil) -> Void {
if all != nil {
DispatchQueue.main.async {
HapticManager.share.triggerHapticFeedback()
}
}else{
if SettingConfiguration.share.config.vibration ?? false {
DispatchQueue.main.async {
HapticManager.share.triggerHapticFeedback()
}
}
}
}
}
extension UISwitch {
@IBInspectable var isVibration:Bool {
set{
self.addTarget(self, action: #selector(valueChangeVibration), for: .valueChanged)
}
get{
return false
}
}
@objc func valueChangeVibration() -> Void {
self.vibrate(true)
}
}
class HapticManager {
static let share = HapticManager()
private var engine: CHHapticEngine?
init() {
setupHapticEngine()
}
func setupHapticEngine() {
guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return }
do {
engine = try CHHapticEngine()
try engine?.start()
generator.prepare()
} catch {
print("引擎初始化失败: \(error)")
}
}
private lazy var generator: UIImpactFeedbackGenerator = {
let genter = UIImpactFeedbackGenerator(style: .heavy)
genter.prepare()
return genter
}()
// 触发震动反馈
func triggerHapticFeedback() {
generator.impactOccurred()
}
}
......@@ -19,6 +19,8 @@
<string>684306808588-cl093f79dogls1a608bh8oclk3ia0rig.apps.googleusercontent.com</string>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>wechat</string>
<string>weixin</string>
<string>google</string>
<string>googlemail</string>
<string>googlegmail</string>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment