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])
}
}
This diff is collapsed.
......@@ -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>
This diff is collapsed.
//
// 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))
}
}
This diff is collapsed.
......@@ -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!)
}
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
// 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,8 +62,6 @@ struct RowInfoModel{
func getSettingViewInfo() -> [SettingModel] {
if SettingConfiguration.share.config.secret?.count ?? 0 != 4 {
if PMFaceIDManger.isAvailable() {
return [
SettingModel(sectionTitle: "",rowInfo: [RowInfoModel(imageName: "",title: "")]),
......@@ -91,7 +89,8 @@ func getSettingViewInfo() -> [SettingModel] {
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{
} else {
if PMFaceIDManger.isAvailable() {
return [
SettingModel(sectionTitle: "",rowInfo: [RowInfoModel(imageName: "",title: "")]),
......@@ -100,6 +99,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)]),
......@@ -119,9 +119,9 @@ 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: "")]),
......@@ -129,7 +129,6 @@ 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)]),
......@@ -150,9 +149,9 @@ 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"),]),]
}
}
}
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
......
This diff is collapsed.
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