Commit 560ec868 authored by shenyong's avatar shenyong

Merge branch 'dev_main' into dev_syong

parents 83f33d9f 92bec182
......@@ -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.
......@@ -54,6 +54,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
AdvManager.shared.initAdertisementSDK()
PMEmailManager.shareManager.restore()
SettingConfiguration.share.initData()
HapticManager.share.setupHapticEngine()
// 相册基本资源加载
PhotoManager.shared.config()
......
//
// 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>
......@@ -21,14 +21,12 @@ class CompressController : BaseViewController {
private var compressNav:CompressNavView?
// 排序
var currentSort : Int = 0 {
var currentSort : ResouceSortType = .largest {
didSet{
clearSelected()
}
}
// 资源类型 - 相册或者视频
var currentResourceType : CompressType = .compressPhoto
......@@ -122,25 +120,20 @@ class CompressController : BaseViewController {
let datas = Singleton.shared.resourceModel
if datas.count > 0 {
// 这里需要重新排序下
if self.currentSort == 0 {
self.resourceData = datas.sorted {$0.assetSize > $1.assetSize }
}else if self.currentSort == 1 {
self.resourceData = datas.sorted {$0.assetSize < $1.assetSize }
}else if self.currentSort == 2 {
self.resourceData = datas.sorted {$0.createDate > $1.createDate }
}else{
self.resourceData = datas.sorted {$0.createDate < $1.createDate }
}
self.resourceData = datas
self.sortByType(sortType: self.currentSort)
}else{
PMLoadingHUD.share.show()
PMLoadingHUD.share.show("Loading...", "Please wait on the screen. This might take several minutes.")
CompressViewModel().getAllPhotosToAssets(sortType: self.currentSort, assetType: self.currentResourceType) { [weak self] models in
guard let self else {return}
self.resourceData = models
Singleton.shared.resourceModel = self.resourceData
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
PMLoadingHUD.share.disMiss()
}
}
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
......@@ -238,20 +231,10 @@ extension CompressController:WaterfallMutiSectionDelegate,UICollectionViewDataSo
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionHeader {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "CompressCustomHeaderView", for: indexPath) as! CompressCustomHeaderView
header.callBack = {[weak self] text in
guard let self else {return}
let sortView = CompressSortView(frame: self.view.bounds)
// 这两行是为了进入页面的时候选中
sortView.currentIndex = self.currentSort
sortView.tableView.reloadData()
self.view.addSubview(sortView)
sortView.callBack = {[weak self] sortType in
header.sortViewSubmitCallBack = { [weak self] fileterModel in
guard let self else {return}
self.currentSort = sortType as! Int
self.sortByType(sortType: self.currentSort, header: header)
}
self.currentSort = fileterModel.sortType
self.sortByType(sortType: self.currentSort)
}
header.changeView.callBack = {[weak self] flag in
guard let self else {return}
......@@ -264,9 +247,13 @@ extension CompressController:WaterfallMutiSectionDelegate,UICollectionViewDataSo
if self.currentResourceType == .compressPhoto {
self.getViewData()
}else{
PMLoadingHUD.share.show("Loading...", "Please wait on the screen. This might take several minutes.")
CompressViewModel().getAllPhotosToAssets(sortType: self.currentSort, assetType: flag) { [weak self] models in
guard let self else {return}
self.resourceData = models
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
PMLoadingHUD.share.disMiss()
}
}
}
}
......@@ -284,34 +271,21 @@ extension CompressController:WaterfallMutiSectionDelegate,UICollectionViewDataSo
}
}
func sortByType(sortType:Int,header:CompressCustomHeaderView){
let viewModel = CompressViewModel()
func sortByType(sortType:ResouceSortType){
switch sortType {
case 0:
header.selectlabel.text = "Largest"
// 按照文件大小降序
self.resourceData = viewModel.sortRsource(resource: self.resourceData, sortType: 1, sortKind: 0)
break
case 1:
header.selectlabel.text = "Smallest"
// 按照文件大小升序
self.resourceData = viewModel.sortRsource(resource: self.resourceData, sortType: 0, sortKind: 0)
case .largest:
self.resourceData = self.resourceData.sorted { $0.assetSize > $1.assetSize }
break
case 2:
header.selectlabel.text = "Newest"
// 按照时间降序
self.resourceData = viewModel.sortRsource(resource: self.resourceData, sortType: 1, sortKind: 1)
case .smallest:
self.resourceData = self.resourceData.sorted { $0.assetSize < $1.assetSize }
break
case 3:
header.selectlabel.text = "Oldest"
// 按照时间升序
self.resourceData = viewModel.sortRsource(resource: self.resourceData, sortType: 0, sortKind: 1)
case .latest:
self.resourceData = self.resourceData.sorted { $0.createDate > $1.createDate }
break
default:
case .oldest:
self.resourceData = self.resourceData.sorted { $0.createDate < $1.createDate }
break
}
}
func updateSubmitButton(){
......
......@@ -9,7 +9,7 @@ import Foundation
class CompressCustomHeaderView: UICollectionReusableView{
var callBack: callBack<Any> = {text in }
var sortViewSubmitCallBack : (ResourceFilterBoxModel)->Void = {model in}
var modeData = [AssetModel]() {
didSet{
......@@ -51,35 +51,21 @@ class CompressCustomHeaderView: UICollectionReusableView{
return label
}()
lazy var btnView :UIView = {
let view = UIView()
view.backgroundColor = UIColor(red: 0.95, green: 0.96, blue: 0.99, alpha: 1)
view.layer.cornerRadius = 16
view.clipsToBounds = true
let tap = UITapGestureRecognizer()
tap.addTarget(self, action: #selector(selectQulity))
view.isUserInteractionEnabled = true
view.addGestureRecognizer(tap)
return view
// 筛选按钮
lazy var filterButton : UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "Frame 1"), for: .normal)
button.setTitle("The largest", for: .normal)
button.layer.cornerRadius = 14
button.clipsToBounds = true
button.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 0.1000)
button.titleLabel?.font = UIFont.systemFont(ofSize: 12, weight: .semibold)
button.setTitleColor(UIColor(red: 0.07, green: 0.07, blue: 0.07, alpha: 1), for: .normal)
button.addTarget(self, action: #selector(filterButtonAction), for: .touchUpInside)
button.isHidden = false
return button
}()
lazy var selectImageView :UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "ic_newest_similar")
return view
}()
lazy var selectlabel :UILabel = {
let label = UILabel()
label.text = "Largest"
label.textAlignment = .center
label.textColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
label.font = UIFont.systemFont(ofSize: 14, weight: .bold)
return label
}()
lazy var siezLabel :UILabel = {
let label = UILabel()
label.text = "1.02 GB"
......@@ -128,9 +114,7 @@ class CompressCustomHeaderView: UICollectionReusableView{
private func setUI(){
self.addSubview(self.titlelabel)
self.addSubview(self.btnView)
self.btnView.addSubview(self.selectImageView)
self.btnView.addSubview(self.selectlabel)
self.addSubview(self.filterButton)
self.addSubview(self.siezLabel)
self.addSubview(self.changeView)
self.addSubview(self.tipView)
......@@ -144,27 +128,17 @@ class CompressCustomHeaderView: UICollectionReusableView{
make.height.equalTo(28)
}
self.btnView.snp.makeConstraints { make in
self.filterButton.snp.makeConstraints { make in
make.centerY.equalTo(self.titlelabel.snp.centerY)
make.right.equalToSuperview().offset(0)
make.top.equalToSuperview().offset(12)
make.width.equalTo(103 * RScreenW())
make.height.equalTo(32)
}
self.selectImageView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(12)
make.centerY.equalToSuperview()
make.width.height.equalTo(20)
}
self.selectlabel.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-12)
make.top.equalToSuperview().offset(6)
make.width.equalTo(60 * RScreenW())
make.height.equalTo(20)
make.height.equalTo(28)
make.width.equalTo(98)
}
self.siezLabel.snp.makeConstraints { make in
make.left.equalTo(0)
make.right.equalTo(0)
make.top.equalTo(self.btnView.snp.bottom).offset(8)
make.top.equalTo(self.filterButton.snp.bottom).offset(8)
make.height.equalTo(20)
}
self.changeView.snp.makeConstraints { make in
......@@ -193,10 +167,20 @@ class CompressCustomHeaderView: UICollectionReusableView{
}
@objc func selectQulity(){
@objc func filterButtonAction(){
if let cWindow = cWindow {
let filterView : ResourceFilterBoxView = ResourceFilterBoxView.init(frame: cWindow.bounds)
// 添加毛玻璃效果
cWindow.showBlur()
callBack("selectedQulity")
cWindow.addSubview(filterView)
filterView.submitCallBack = {model in
DispatchQueue.main.async {
self.filterButton.setTitle(model.sortType.rawValue, for: .normal)
}
self.sortViewSubmitCallBack(model)
}
}
}
......
......@@ -67,7 +67,7 @@ class CompressViewModel{
/// 获取相册所有图片
/// - Returns: 图片信息
func getAllPhotosToAssets(sortType: Int, assetType : CompressType,_ finished: @escaping Finished){
func getAllPhotosToAssets(sortType: ResouceSortType, assetType : CompressType,_ finished: @escaping Finished){
var models : [AssetModel] = []
......@@ -108,11 +108,11 @@ class CompressViewModel{
group.leave()
if count == assetsArray.count {
// 默认按照文件大小排序
if sortType == 0 {
if sortType == .largest {
finished(models.sorted { $0.assetSize > $1.assetSize })
}else if sortType == 1 {
}else if sortType == .smallest {
finished(models.sorted { $0.assetSize < $1.assetSize })
}else if sortType == 2 {
}else if sortType == .latest {
finished(models.sorted { $0.createDate > $1.createDate })
}else{
finished(models.sorted { $0.createDate < $1.createDate })
......@@ -123,29 +123,6 @@ class CompressViewModel{
}
}
/// 对资源进行排序
/// - Parameters:
/// - resource: 原资源
/// - sortType: 排序的类型,升序或者降序。0-升序,1-降序
/// - sortKind: 排序的种类 大小或者时间 0-大小,1-时间
/// - Returns: 返回排序结果
func sortRsource(resource:[AssetModel],sortType:Int,sortKind:Int)->[AssetModel]{
if sortKind == 0 {
if sortType == 0 {
return resource.sorted { $0.assetSize < $1.assetSize }
}else{
return resource.sorted { $0.assetSize > $1.assetSize }
}
}else{
if sortType == 0 {
return resource.sorted { $0.createDate < $1.createDate }
}else{
return resource.sorted { $0.createDate > $1.createDate }
}
}
}
/// 视频压缩
/// - Parameters:
......
......@@ -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 {
......
......@@ -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 {
......
//
// 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":[]
}
]
......@@ -43,27 +43,9 @@ class PMFAQCell: UITableViewCell {
}
private func addattribed() -> NSMutableAttributedString {
var mutableText = NSMutableAttributedString(string: data?.answer ?? "")
mutableText.addAttributes([NSAttributedString.Key.font : UIFont.systemFont(ofSize: 14, weight: .semibold)], range: NSRange(location: 0, length: mutableText.length))
let rangs = ["PhoneManager",
"face recognition",
"similar photo comparison",
"edited/favorited status",
"Best Result",
"only with iPhones running iOS 14 or later",
"App Store's subscription terms and conditions",
"Settings",
"Apple ID profile","Subscriptions",
"Cancel Subscription",
"automatic scanning and analysis",
"only on recent additions or changes","Similar",
"within seconds of each other",
"same subject/person","consistent background","Best Result",
"favorites","Other","do not fit predefined classifications","interactive swiping mechanism",
"left","right","tap any item","creation date","red checkmark icon",
"Delete","Keep List","Move to Trash","trash bin icon","swiping feature","Videos","swipe left",
"swipe right","resource-intensive","by size or creation date","smart algorithms","final approval",
"explicit approval","offline processing","no personal data or photo content","Keep All","Settings icon","Media Library","Unkeep"]
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) {
......@@ -71,7 +53,9 @@ class PMFAQCell: UITableViewCell {
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: .bold)], range: NSRange(location: start, length: end))
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
......
......@@ -71,7 +71,7 @@ extension PMFAQController : UITableViewDelegate,UITableViewDataSource {
let current = openSet
openSet = indexPath.row
indexpaths = [indexPath]
if current > 0 {
if current >= 0 {
indexpaths.append(IndexPath(row: current, section: 0))
}
}
......@@ -82,6 +82,7 @@ extension PMFAQController : UITableViewDelegate,UITableViewDataSource {
struct FAQDataModel : Codable {
var problem:String
var answer:String
var bold:[String]?
init(problem: String, answer: String) {
self.problem = problem
self.answer = answer
......
......@@ -314,6 +314,11 @@ class HomeInfoViewController:BaseViewController {
showTipsVC()
self.tablewView.keepAllNoDataCallBack = {
self.ids = []
self.setDefaultPage()
}
}
......
......@@ -23,6 +23,7 @@ class PhotoDetailViewController : BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor(red: 0.95, green: 0.96, blue: 0.99, alpha: 1)
self.view.addSubview(self.closeButton)
self.closeButton.snp.makeConstraints { make in
......
......@@ -77,6 +77,9 @@ class PhotoRemoveViewController: BaseViewController {
// MARK: - 生命周期
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor(red: 0.95, green: 0.96, blue: 0.99, alpha: 1)
formatter.dateStyle = .medium
formatter.timeStyle = .none
if let type = self.mediaType {
......@@ -295,7 +298,8 @@ class PhotoRemoveViewController: BaseViewController {
photoView.mediaType = self.mediaType
photoView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(handlePan)))
view.addSubview(photoView)
photoView.frame = CGRectMake(15, statusBarHeight + 44, self.view.width - 30, self.view.height - 78 - safeHeight - statusBarHeight - 44)
photoView.frame = CGRectMake(0, 0, self.view.width - 30, 509 * RScreenH())
photoView.center = self.view.center
photoViews.append(photoView)
}
......@@ -405,7 +409,6 @@ class PhotoRemoveViewController: BaseViewController {
if actualTranslation.x < 0 {
// 删除操作,先存到单利
self.vibrate()
saveDataToDBAndSigtonTrash()
}
......@@ -471,7 +474,8 @@ class PhotoRemoveViewController: BaseViewController {
private func resetViewPosition(_ view: PhotosRemoveBaseView) {
UIView.animate(withDuration: 0.3) {
view.transform = .identity
view.frame = CGRectMake(15, statusBarHeight + 44, self.view.width - 30, self.view.height - 78 - safeHeight - statusBarHeight - 44)
view.frame = CGRectMake(0, 0, self.view.width - 30, 509 * RScreenH())
view.center = self.view.center
view.hideButtons()
}
}
......@@ -488,7 +492,8 @@ class PhotoRemoveViewController: BaseViewController {
// 创建新视图并更新内容
let newView = PhotosRemoveBaseView()
newView.frame = CGRectMake(15, statusBarHeight + 44, self.view.width - 30, self.view.height - 78 - safeHeight - statusBarHeight - 44)
newView.frame = CGRectMake(0, 0, self.view.width - 30, 509 * RScreenH())
newView.center = self.view.center
newView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(handlePan)))
newView.alpha = 0
view.addSubview(newView)
......@@ -547,16 +552,6 @@ class PhotoRemoveViewController: BaseViewController {
}
}
}
@objc func popCurrentPage(){
}
deinit {
NotificationCenter.default.removeObserver(self)
}
......
//
// HomeDetailDeleteView.swift
// PhoneManager
//
// Created by edy on 2025/5/19.
//
import UIKit
class HomeDetailDeleteView: UIView {
var deleteCallBack:(()->Void) = {}
lazy var deleteButton : UIButton = {
let view = UIButton()
view.setTitle("Delete", for: UIControl.State.normal)
view.setTitleColor(.white, for: .normal)
view.clipsToBounds = true
view.layer.cornerRadius = 23
view.backgroundColor = UIColor(red: 0.7, green: 0.7, blue: 0.7, alpha: 1)
view.addTarget(self, action: #selector(deleteButtonAction), for: .touchUpInside)
return view
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .white
self.addSubview(self.deleteButton)
self.deleteButton.snp.makeConstraints { make in
make.top.equalToSuperview().offset(16)
make.left.equalToSuperview().offset(15)
make.right.equalToSuperview().offset(-15)
make.height.equalTo(46)
}
}
@objc func deleteButtonAction(){
self.deleteCallBack()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
......@@ -13,12 +13,16 @@ class HomeInfoView :UIView {
var titleText : String?
var isDragEnd : Bool = false
var type : PhotsFileType?
var models:[HomeInfoTableItem] = []
var callBack:callBack<Any> = {text in}
var keepAllNoDataCallBack : ()->Void = {}
var deleteCallBack:callBack<[AssetModel]> = {array in }
var titleShowHideCallBack:callBack<Bool> = {isShow in}
......@@ -42,6 +46,7 @@ class HomeInfoView :UIView {
lazy var headerView:HomeInfoTitleView = {
let sview:HomeInfoTitleView = HomeInfoTitleView(frame: CGRect(x: 0, y: 0, width: width, height: 84))
sview.titleLabel.text = self.titleText
sview.type = self.type
sview.filterButton.isHidden = self.type != .similar && self.type != .SimilarVideos
return sview
}()
......@@ -308,6 +313,7 @@ class HomeInfoView :UIView {
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: deleteView.isHidden ? 12 : deleteView.height + 12 , right: 0)
self.nextRowButton.isHidden = !self.isShowNextRowButton()
}
}
......@@ -315,45 +321,28 @@ class HomeInfoView :UIView {
extension HomeInfoView:UITableViewDataSource,UITableViewDelegate {
@objc func nextRowButtonAction(){
self.tableScrollToNextRow()
}
// 重新设置models
func resetModels(){
var newArray : [HomeInfoTableItem] = []
for array in ids ?? [] {
var smodels:[ImageSeletedCollectionItem] = []
for id in array {
let smodel = ImageSeletedCollectionItem()
smodel.id = id
smodel.isSeleted = false
smodels.append(smodel)
}
let smodel = HomeInfoTableItem()
smodel.type = type
smodel.smodels = smodels
smodel.titleText = titleText
newArray.append(smodel)
}
self.models = newArray
self.tableScrollToNextRow()
}
/// 让表格自动滚动一行
private func tableScrollToNextRow() {
guard let indexPath = tableView.indexPathsForVisibleRows?.first else { return }
let nextRow = indexPath.row + 1
// let nextRow = self.isDragEnd == true ? indexPath.row + 1 : indexPath.row + 2
let nextRow = indexPath.row + 2
let nextSection = indexPath.section
// 获取最后一个cell 看看是不是存在
guard let lastIndexPath = tableView.indexPathsForVisibleRows?.last else {return}
let lastNextRow = lastIndexPath.row + 1
guard lastNextRow < tableView.numberOfRows(inSection: nextSection) else {
// 滚动到最底部
tableView.scrollToRow(at: lastIndexPath, at: .bottom, animated: true)
return
}
// 检查下一行是否存在
guard nextRow < tableView.numberOfRows(inSection: nextSection) else { return }
......@@ -370,6 +359,7 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate {
// 直接滚动到调整后的位置
tableView.setContentOffset(adjustedOffset, animated: true)
self.isDragEnd = false
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
......@@ -386,6 +376,10 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate {
tableView.bringSubviewToFront(self.headerView)
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
self.isDragEnd = true
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return models.count
......@@ -394,10 +388,25 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: HomeInfoTableViewCell.identifier, for: indexPath) as! HomeInfoTableViewCell
cell.saveKeepListFinishedCallback = {
self.ids?.remove(at: indexPath.section)
self.resetModels()
tableView.deleteRows(at: [indexPath], with: .automatic)
cell.saveKeepListFinishedCallback = {[weak self] index in
guard let self else {return}
self.ids?.remove(at: index.section)
self.models.remove(at: index.section)
DispatchQueue.main.async {
self.setTitleView()
}
// 禁用动画
UIView.performWithoutAnimation {
tableView.beginUpdates()
tableView.deleteRows(at: [index], with: .fade)
tableView.endUpdates()
}
if let data = self.ids {
if data.count <= 0 {
self.keepAllNoDataCallBack()
}
}
}
cell.type = self.type
......@@ -439,10 +448,10 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate {
for item in orgModels {
var array = item
if startDate != nil {
array = array.filter({$0.createDate > startDate!})
array = array.filter({$0.createDate >= startDate!})
}
if endDate != nil {
array = array.filter({$0.createDate < endDate!})
array = array.filter({$0.createDate <= endDate!})
}
if array.count >= 2 {
......@@ -490,6 +499,8 @@ class HomeInfoTitleView:UIView {
var sortViewSubmitCallBack : (ResourceFilterBoxModel)->Void = {model in}
var type : PhotsFileType?
lazy var titleLabel:UILabel = {
let sview:UILabel = UILabel()
......@@ -567,7 +578,12 @@ class HomeInfoTitleView:UIView {
let allNumberStr = "\(allNumber)"
let seletedCountStr = "\(seletedCount)"
let fullText = allNumberStr + " photos · \(seletedCountStr) selected"
var fullText = "0 photos · 0 selected"
if self.type == .SimilarVideos {
fullText = allNumberStr + " videos · \(seletedCountStr) selected"
}else {
fullText = allNumberStr + " photos · \(seletedCountStr) selected"
}
let attributedString2 = NSMutableAttributedString(string: fullText, attributes: [
......
......@@ -9,7 +9,7 @@ import Foundation
class HomePhotosDetailCustomHeaderView : UICollectionReusableView {
var sortCallback : ()->Void = {}
var sortViewSubmitCallBack : (ResourceFilterBoxModel)->Void = {model in}
lazy var modelTitlelabel :UILabel = {
let label = UILabel()
......@@ -20,33 +20,22 @@ class HomePhotosDetailCustomHeaderView : UICollectionReusableView {
return label
}()
lazy var btnView :UIView = {
let view = UIView()
view.backgroundColor = UIColor(red: 0.95, green: 0.96, blue: 0.99, alpha: 1)
view.layer.cornerRadius = 16
view.clipsToBounds = true
let tap = UITapGestureRecognizer()
tap.addTarget(self, action: #selector(sortAction))
view.isUserInteractionEnabled = true
view.addGestureRecognizer(tap)
return view
// 筛选按钮
lazy var filterButton : UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "Frame 1"), for: .normal)
button.setTitle("The largest", for: .normal)
button.layer.cornerRadius = 14
button.clipsToBounds = true
button.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 0.1000)
button.titleLabel?.font = UIFont.systemFont(ofSize: 12, weight: .semibold)
button.setTitleColor(UIColor(red: 0.07, green: 0.07, blue: 0.07, alpha: 1), for: .normal)
button.addTarget(self, action: #selector(filterButtonAction), for: .touchUpInside)
button.isHidden = false
return button
}()
lazy var selectImageView :UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "ic_newest_similar")
return view
}()
lazy var selectlabel :UILabel = {
let label = UILabel()
label.text = "Largest"
label.textAlignment = .center
label.textColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
label.font = UIFont.systemFont(ofSize: 14, weight: .bold)
return label
}()
lazy var countLabel :UILabel = {
let label = UILabel()
label.text = "0 Photos"
......@@ -59,13 +48,8 @@ class HomePhotosDetailCustomHeaderView : UICollectionReusableView {
private func setUI(){
self.addSubview(self.modelTitlelabel)
self.addSubview(self.btnView)
self.addSubview(self.countLabel)
self.btnView.addSubview(self.selectImageView)
self.btnView.addSubview(self.selectlabel)
self.addSubview(self.filterButton)
self.modelTitlelabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(0)
......@@ -73,29 +57,17 @@ class HomePhotosDetailCustomHeaderView : UICollectionReusableView {
make.width.equalTo(150 * RScreenW())
make.height.equalTo(28)
}
self.btnView.snp.makeConstraints { make in
self.filterButton.snp.makeConstraints { make in
make.centerY.equalTo(self.modelTitlelabel.snp.centerY)
make.right.equalToSuperview().offset(0)
make.top.equalToSuperview().offset(12)
make.width.equalTo(103 * RScreenW())
make.height.equalTo(32)
}
self.selectImageView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(12)
make.centerY.equalToSuperview()
make.width.height.equalTo(20)
}
self.selectlabel.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-12)
make.top.equalToSuperview().offset(6)
make.width.equalTo(60 * RScreenW())
make.height.equalTo(20)
make.height.equalTo(28)
make.width.equalTo(98)
}
self.countLabel.snp.makeConstraints { make in
make.left.equalTo(0)
make.right.equalTo(0)
make.top.equalTo(self.btnView.snp.bottom).offset(8)
make.top.equalTo(self.filterButton.snp.bottom).offset(8)
make.height.equalTo(20)
}
}
......@@ -112,7 +84,19 @@ class HomePhotosDetailCustomHeaderView : UICollectionReusableView {
setUI()
}
@objc func sortAction(){
sortCallback()
@objc func filterButtonAction(){
if let cWindow = cWindow {
let filterView : ResourceFilterBoxView = ResourceFilterBoxView.init(frame: cWindow.bounds)
// 添加毛玻璃效果
cWindow.showBlur()
cWindow.addSubview(filterView)
filterView.submitCallBack = {model in
DispatchQueue.main.async {
self.filterButton.setTitle(model.sortType.rawValue, for: .normal)
}
self.sortViewSubmitCallBack(model)
}
}
}
}
......@@ -8,7 +8,7 @@
import Foundation
class HomeVideoDetailCustomHeaderView : UICollectionReusableView {
var sortCallback : ()->Void = {}
var sortViewSubmitCallBack : (ResourceFilterBoxModel)->Void = {model in}
lazy var modelTitlelabel :UILabel = {
let label = UILabel()
......@@ -18,34 +18,19 @@ class HomeVideoDetailCustomHeaderView : UICollectionReusableView {
label.font = UIFont.systemFont(ofSize: 20, weight: .bold)
return label
}()
lazy var btnView :UIView = {
let view = UIView()
view.backgroundColor = UIColor(red: 0.95, green: 0.96, blue: 0.99, alpha: 1)
view.layer.cornerRadius = 16
view.clipsToBounds = true
let tap = UITapGestureRecognizer()
tap.addTarget(self, action: #selector(sortAction))
view.isUserInteractionEnabled = true
view.addGestureRecognizer(tap)
return view
}()
lazy var selectImageView :UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "ic_newest_similar")
return view
}()
lazy var selectlabel :UILabel = {
let label = UILabel()
label.text = "Largest"
label.textAlignment = .center
label.textColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
label.font = UIFont.systemFont(ofSize: 14, weight: .bold)
return label
// 筛选按钮
lazy var filterButton : UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "Frame 1"), for: .normal)
button.setTitle("The largest", for: .normal)
button.layer.cornerRadius = 14
button.clipsToBounds = true
button.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 0.1000)
button.titleLabel?.font = UIFont.systemFont(ofSize: 12, weight: .semibold)
button.setTitleColor(UIColor(red: 0.07, green: 0.07, blue: 0.07, alpha: 1), for: .normal)
button.addTarget(self, action: #selector(filterButtonAction), for: .touchUpInside)
button.isHidden = false
return button
}()
lazy var sizeLabel :UILabel = {
let label = UILabel()
......@@ -56,71 +41,13 @@ class HomeVideoDetailCustomHeaderView : UICollectionReusableView {
return label
}()
// lazy var tipBackView :UIView = {
// let view = UIView()
// view.backgroundColor = UIColor(red: 0.95, green: 0.96, blue: 0.99, alpha: 1)
// view.layer.cornerRadius = 8
// view.clipsToBounds = true
// return view
// }()
// lazy var tipImageView :UIImageView = {
// let view = UIImageView()
// view.image = UIImage(named: "ic_cmpress_home_nor")
// return view
// }()
//
// lazy var tipLabel :UILabel = {
// let label = UILabel()
// label.text = "Video Compress"
// label.textAlignment = .left
// label.numberOfLines = 0
// label.font = UIFont.systemFont(ofSize: 16, weight: .bold)
// return label
// }()
//
// lazy var tipDetailLabel :UILabel = {
// let label = UILabel()
// label.text = "Tap to start the process"
// label.textAlignment = .left
// label.numberOfLines = 0
// label.textColor = UIColor(red: 0.7, green: 0.7, blue: 0.7, alpha: 1)
// label.font = UIFont.systemFont(ofSize: 12, weight: .regular)
// return label
// }()
//
// lazy var saveSizeLabel :UILabel = {
// let label = UILabel()
// label.text = "13.5M"
// label.textAlignment = .right
// label.textColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1)
// label.font = UIFont.systemFont(ofSize: 16, weight: .bold)
// return label
// }()
//
// lazy var moreImageView :UIImageView = {
// let view = UIImageView()
// view.image = UIImage(named: "icon_left_setting_grey")
// return view
// }()
private func setUI(){
self.addSubview(self.modelTitlelabel)
self.addSubview(self.btnView)
self.addSubview(self.filterButton)
self.addSubview(self.sizeLabel)
self.btnView.addSubview(self.selectImageView)
self.btnView.addSubview(self.selectlabel)
// self.addSubview(self.tipBackView)
// self.tipBackView.addSubview(self.tipImageView)
// self.tipBackView.addSubview(self.tipLabel)
// self.tipBackView.addSubview(self.tipDetailLabel)
// self.tipBackView.addSubview(self.saveSizeLabel)
// self.tipBackView.addSubview(self.moreImageView)
self.modelTitlelabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(0)
......@@ -129,31 +56,23 @@ class HomeVideoDetailCustomHeaderView : UICollectionReusableView {
make.height.equalTo(28)
}
self.btnView.snp.makeConstraints { make in
make.right.equalToSuperview().offset(0)
make.top.equalToSuperview().offset(12)
make.width.equalTo(103 * RScreenW())
make.height.equalTo(32)
}
self.selectImageView.snp.makeConstraints { make in
make.left.equalToSuperview().offset(12)
make.centerY.equalToSuperview()
make.width.height.equalTo(20)
}
self.selectlabel.snp.makeConstraints { make in
make.right.equalToSuperview().offset(-12)
make.top.equalToSuperview().offset(6)
make.width.equalTo(60 * RScreenW())
make.height.equalTo(20)
}
self.sizeLabel.snp.makeConstraints { make in
make.left.equalTo(0)
make.right.equalTo(0)
make.top.equalTo(self.btnView.snp.bottom).offset(8)
make.top.equalTo(self.filterButton.snp.bottom).offset(8)
make.height.equalTo(20)
}
self.filterButton.snp.makeConstraints { make in
make.centerY.equalTo(self.modelTitlelabel.snp.centerY)
make.right.equalToSuperview().offset(0)
make.height.equalTo(28)
make.width.equalTo(98)
}
addSubview(compressionTipView)
compressionTipView.snp.makeConstraints { make in
......@@ -164,47 +83,6 @@ class HomeVideoDetailCustomHeaderView : UICollectionReusableView {
let tap = UITapGestureRecognizer(target: self, action: #selector(compressClick))
compressionTipView.addGestureRecognizer(tap)
// self.tipBackView.snp.makeConstraints { make in
// make.left.equalTo(0)
// make.right.equalTo(0)
// make.top.equalTo(self.sizeLabel.snp.bottom).offset(12)
// make.height.equalTo(70)
// }
//
// self.tipImageView.snp.makeConstraints { make in
// make.left.equalToSuperview().offset(15)
// make.centerY.equalToSuperview()
// make.width.height.equalTo(30)
//
// }
// self.tipLabel.snp.makeConstraints { make in
// make.left.equalTo(self.tipImageView.snp.right).offset(10)
// make.width.equalTo(150 * RScreenW())
// make.height.equalTo(22)
// make.top.equalToSuperview().offset(15)
// }
// self.tipDetailLabel.snp.makeConstraints { make in
// make.left.equalTo(self.tipImageView.snp.right).offset(10)
// make.width.equalTo(150 * RScreenW())
// make.height.equalTo(18)
// make.top.equalTo(self.tipLabel.snp.bottom).offset(0)
// }
//
// self.moreImageView.snp.makeConstraints { make in
// make.height.width.equalTo(20)
// make.right.equalToSuperview().offset(-15)
// make.centerY.equalToSuperview()
// }
//
// self.saveSizeLabel.snp.makeConstraints { make in
// make.centerY.equalToSuperview()
// make.right.equalTo(self.moreImageView.snp.left).offset(-10)
// make.height.equalTo(28)
// make.width.equalTo(100)
// }
}
override init(frame: CGRect) {
......@@ -219,8 +97,20 @@ class HomeVideoDetailCustomHeaderView : UICollectionReusableView {
setUI()
}
@objc func sortAction(){
sortCallback()
@objc func filterButtonAction(){
if let cWindow = cWindow {
let filterView : ResourceFilterBoxView = ResourceFilterBoxView.init(frame: cWindow.bounds)
// 添加毛玻璃效果
cWindow.showBlur()
cWindow.addSubview(filterView)
filterView.submitCallBack = {model in
DispatchQueue.main.async {
self.filterButton.setTitle(model.sortType.rawValue, for: .normal)
}
self.sortViewSubmitCallBack(model)
}
}
}
lazy var compressionTipView:VideocompressionHeadView = {
......
......@@ -56,6 +56,7 @@ class PhotosRemoveBaseView: UIView {
self.imageView.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer()
tap.addTarget(self, action: #selector(showDeatail))
imageView.backgroundColor = .white
self.imageView.addGestureRecognizer(tap)
}
......
......@@ -118,10 +118,15 @@ class ResourceFilterBoxView : UIView {
setUpUI()
}
func getMonthEn(month: Int )-> String{
func getMonthEn(month: Int) -> String {
// 检查输入是否在有效范围内(1-12)
guard (1...12).contains(month) else {
return "Invalid Month" // 或抛出错误
}
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US")
return formatter.monthSymbols[month]
return formatter.monthSymbols[month - 1]
}
override func removeFromSuperview() {
......@@ -240,6 +245,7 @@ class ResourceFilterBoxView : UIView {
components.year = year
components.month = month
components.day = 1 // 设置为当月第一天
components.timeZone = TimeZone(identifier: "UTC")
// 使用公历日历
let calendar = Calendar(identifier: .gregorian)
......@@ -260,6 +266,7 @@ class ResourceFilterBoxView : UIView {
components.year = nextYear
components.month = nextMonth
components.day = 1
components.timeZone = TimeZone(identifier: "UTC")
let calendar = Calendar(identifier: .gregorian)
guard let nextMonthFirstDay = calendar.date(from: components) else {
......@@ -318,7 +325,6 @@ class ResourceFilterBoxView : UIView {
self.startDateButton.dateButton.setTitle("From \(self.getMonthEn(month: month)) \(year)", for: .normal)
self.startDateButton.closeButton.isHidden = false
self.startDate = self.dateFrom(year: year, month: month)
}else {
self.endDateButton.dateButton.setTitle("To \(self.getMonthEn(month: month)) \(year)", for: .normal)
self.endDateButton.closeButton.isHidden = false
......
......@@ -9,6 +9,8 @@ import UIKit
class TrashSubView: UIView {
var type : TrashTypeEnum?
var clearTashDataCallBack : ()->Void = {}
var presentTashDetailViewClickCallBack : ()->Void = {}
......@@ -32,7 +34,7 @@ class TrashSubView: UIView {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "ic_delete_duplicates"), for: .normal)
button.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1)
button.setTitle("Empty the garbage", for: .normal)
button.setTitle("Empty Trash", for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 12, weight: .semibold)
button.layer.cornerRadius = 19
......@@ -43,6 +45,8 @@ class TrashSubView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
self.addTopShadow()
// 给当前视图添加手势
addTapGestureToSelf()
......
......@@ -146,14 +146,14 @@ extension YearMonthPickerView: UIPickerViewDataSource, UIPickerViewDelegate {
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return component == 0 ? months[row] : "\(years.reversed()[row])"
return component == 0 ? months[row] : "\(years[row])"
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if component == 0 {
selectedMonth = row
} else {
selectedYear = years.reversed()[row]
selectedYear = years[row]
}
}
......@@ -161,4 +161,13 @@ extension YearMonthPickerView: UIPickerViewDataSource, UIPickerViewDelegate {
return component == 0 ? self.width/2 : self.width/2
}
private var currentYear: Int {
return Calendar.current.component(.year, from: Date())
}
private var currentMonth: Int {
return Calendar.current.component(.month, from: Date())
}
}
......@@ -24,7 +24,7 @@ class HomeInfoTableViewCell:UITableViewCell {
var callBack:callBack<Any> = {text in}
var saveKeepListFinishedCallback : ()->Void = {}
var saveKeepListFinishedCallback : (IndexPath)->Void = {index in}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
......@@ -119,7 +119,6 @@ class HomeInfoTableViewCell:UITableViewCell {
UIView.transition(with: collectionView!, duration: 0.3, options: .transitionCrossDissolve, animations: {
self.collectionView?.reloadData()
// self.reloadCollectionView()
}, completion: nil)
}
}
......@@ -224,7 +223,7 @@ extension HomeInfoTableViewCell:UICollectionViewDelegate,UICollectionViewDataSou
cell.keepAllCallBack = {
//存到保留列表
saveAllDataToKeepList()
self.saveKeepListFinishedCallback()
self.saveKeepListFinishedCallback(indexPath)
}
// 存全部数据到保留列表
func saveAllDataToKeepList(){
......
......@@ -21,7 +21,8 @@ class PMLoadingHUD{
func show(_ title:String = "Deleting...",_ subTitle:String = "Please wait on the screen. This might take several minutes."){
disMiss()
DispatchQueue.main.async {
KEYWINDOW()?.addSubview(self.loadingView)
cWindow?.addSubview(self.loadingView)
cWindow?.bringSubviewToFront(self.loadingView)
self.loadingView.setTitleaAndSubTitle(title: title, subTitle: subTitle)
self.loadingView.animationView.play()
}
......
......@@ -70,6 +70,7 @@ class PMShowImgCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
backgroundColor = .clear
clipsToBounds = true
}
......
......@@ -51,6 +51,8 @@ class PMShowImgVideoController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor(red: 0.95, green: 0.96, blue: 0.99, alpha: 1)
}
override func viewWillAppear(_ animated: Bool) {
......@@ -92,6 +94,7 @@ class PMShowImgVideoController: BaseViewController {
col.delegate = self;
col.dataSource = self;
col.showsHorizontalScrollIndicator = false
col.backgroundColor = .clear
col.isPagingEnabled = true
col.register(PMShowImgCell.self, forCellWithReuseIdentifier: PMShowImgCellID)
col.register(PMShowVideoCell.self, forCellWithReuseIdentifier: PMShowVideoCellID)
......@@ -108,6 +111,7 @@ class PMShowImgVideoController: BaseViewController {
let col = UICollectionView(frame: CGRect(), collectionViewLayout: flowlayout)
col.delegate = self;
col.dataSource = self;
col.register(PMShowItemCell.self, forCellWithReuseIdentifier: PMShowItemCellID)
col.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "UICollectionViewCell")
col.showsHorizontalScrollIndicator = false
......
......@@ -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
......
......@@ -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;
......
......@@ -46,12 +46,10 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
self.titleView.titleLabel.textColor = UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1)
modelData = getSettingViewInfo()
self.view.addSubview(tableView)
self.tableView.reloadData()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.tableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
......@@ -176,11 +174,27 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
case settingLabels.RemoveAfterImport.rawValue:
SettingConfiguration.share.config.removeImg = !SettingConfiguration.share.config.removeImg
tableView.reloadRows(at: [indexPath], with: .none)
tableView.reloadData()
vibrate()
break
case settingLabels.Widgets.rawValue:
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 }
......@@ -203,12 +217,15 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
case settingLabels.Vibration.rawValue:
SettingConfiguration.share.config.vibration = !(SettingConfiguration.share.config.vibration ?? false)
tableView.reloadRows(at: [indexPath], with: .none)
tableView.reloadData()
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:
......@@ -216,6 +233,8 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
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)
......@@ -225,7 +244,6 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
}
}
// MARK: - 隐私空间PIN
private func secretspace() -> Void {
if SettingConfiguration.share.config.secret?.count ?? 0 == 4 {
......@@ -267,6 +285,7 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
}else{
SettingConfiguration.share.config.faceId = false
self.tableView.reloadRows(at: [indexPath], with: .none)
tableView.reloadData()
}
}
......@@ -312,13 +331,27 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
}
alert.show()
}else{
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 {
......@@ -333,7 +366,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
......
......@@ -12,13 +12,13 @@ class TrashViewController: BaseViewController {
var dissmisCallBack:()->Void = {}
var source:[TrashTypeEnum] = [.video,.other,.shot,.chat]
var source:[TrashTypeEnum] = [.video,.other,.shot]
var contentH:CGFloat = 0
var contentScrollView:UIScrollView!
var delBtn:UIButton!
var currentType:TrashTypeEnum = .other
let pageCount = 4 // 总页数
let pageCount = 3 // 总页数
var currentPage = 1 {
didSet{
self.setDelButtonUI()
......@@ -61,7 +61,7 @@ class TrashViewController: BaseViewController {
func configUI(){
view.backgroundColor = .white
contentScrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: ScreenW, height: contentH))
contentScrollView.contentSize = CGSize(width: ScreenW*4, height: view.height)
contentScrollView.contentSize = CGSize(width: ScreenW * CGFloat(self.source.count), height: view.height)
contentScrollView.isPagingEnabled = true
contentScrollView.showsHorizontalScrollIndicator = false
contentScrollView.showsVerticalScrollIndicator = false
......@@ -98,13 +98,11 @@ class TrashViewController: BaseViewController {
contentScrollView.addSubview(videoView)
contentScrollView.addSubview(otherView)
contentScrollView.addSubview(shotView)
contentScrollView.addSubview(chatView)
videoView.deleteButton = delBtn
otherView.deleteButton = delBtn
shotView.deleteButton = delBtn
chatView.deleteButton = delBtn
}
override func viewWillLayoutSubviews() {
......@@ -114,11 +112,10 @@ class TrashViewController: BaseViewController {
let viewHeight = self.view.bounds.height
contentH = viewHeight - 108
contentScrollView.frame = CGRect(x: 0, y: 34, width: viewWidth, height: contentH)
contentScrollView.contentSize = CGSize(width: viewWidth*4, height: contentH)
contentScrollView.contentSize = CGSize(width: viewWidth * CGFloat(self.source.count), height: contentH)
videoView.frame = CGRect(x: 0, y: 0, width: viewWidth, height: contentH)
otherView.frame = CGRect(x: viewWidth, y: 0, width: viewWidth, height: contentH)
shotView.frame = CGRect(x: viewWidth*2, y: 0, width: viewWidth, height: contentH)
chatView.frame = CGRect(x: viewWidth*3, y: 0, width: viewWidth, height: contentH)
}
lazy var videoView:TrashContenView = {
......@@ -139,54 +136,8 @@ class TrashViewController: BaseViewController {
return shotView
}()
lazy var chatView:TrashContenView = {
let chatView = TrashContenView()
chatView.trashType = .chat
return chatView
}()
//
// lazy var collectionView:UICollectionView = {
// let layout = UICollectionViewFlowLayout()
// layout.itemSize = CGSize(width: view.width, height: view.height)
// layout.scrollDirection = .horizontal
// layout.minimumInteritemSpacing = 0
// layout.minimumLineSpacing = 0
// let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.width, height: view.height), collectionViewLayout:layout)
// collectionView.isPagingEnabled = true
// collectionView.delegate = self
// collectionView.backgroundColor = .white
// collectionView.dataSource = self
// collectionView.register(UINib(nibName: "TrashContenViewCell", bundle: nil), forCellWithReuseIdentifier: "TrashContenViewCell0")
// collectionView.register(UINib(nibName: "TrashContenViewCell", bundle: nil), forCellWithReuseIdentifier: "TrashContenViewCell1")
// collectionView.register(UINib(nibName: "TrashContenViewCell", bundle: nil), forCellWithReuseIdentifier: "TrashContenViewCell2")
// collectionView.register(UINib(nibName: "TrashContenViewCell", bundle: nil), forCellWithReuseIdentifier: "TrashContenViewCell3")
//
// return collectionView
// }()
}
//extension TrashViewController:UICollectionViewDelegate,UICollectionViewDataSource{
//
// func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// return source.count
// }
//
// func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TrashContenViewCell\(indexPath.row)", for: indexPath) as! TrashContenViewCell
// cell.trashType = source[indexPath.row]
// return cell
// }
//
//}
extension TrashViewController:UIScrollViewDelegate{
func scrollViewDidScroll(_ scrollView: UIScrollView){
......@@ -233,9 +184,6 @@ extension TrashViewController:UIScrollViewDelegate{
if self.currentPage == 3 {
return (TrashTypeEnum.shot,self.shotView)
}
if self.currentPage == 4 {
return (TrashTypeEnum.chat,self.chatView)
}
return (TrashTypeEnum.video,self.videoView)
}
......
......@@ -11,7 +11,6 @@ enum TrashTypeEnum : String, CaseIterable{
case video = "Video"
case other = "Other"
case shot = "Screenshot"
case chat = "Chat"
var dbType:Int{
switch self {
......@@ -21,8 +20,6 @@ enum TrashTypeEnum : String, CaseIterable{
return 1
case .shot:
return 2
case .chat:
return 3
}
}
}
......
......@@ -39,8 +39,6 @@ class TrashContenTitleCell: UICollectionViewCell {
scrollLine.frame = lineTwo.frame
case .shot:
scrollLine.frame = lineThree.frame
case .chat:
scrollLine.frame = lineFour.frame
}
}
}
......@@ -131,16 +129,6 @@ class TrashContenTitleCell: UICollectionViewCell {
}
}
case .chat:
if offset < ScreenW * 3{
UIView.animate(withDuration: 0.2) {
weakSelf.scrollLine.frame = weakSelf.lineThree.frame
}
}else{
UIView.animate(withDuration: 0.2) {
weakSelf.scrollLine.frame = weakSelf.lineFour.frame
}
}
}
}
}
......
......@@ -29,7 +29,7 @@ class TrashContenView: UIView {
var deleteButton : UIButton?
var scrollLine:UIView!
let lineW:CGFloat = (ScreenW - 62) / 4.0
let lineW:CGFloat = (ScreenW - 62) / 3.0
var dataSource:[AssetModel] = [] {
didSet{
......@@ -48,11 +48,6 @@ class TrashContenView: UIView {
}
func getData(){
// dataSource = TrashDatabase.shared.queryByMediaType(trashType.dbType).compactMap({ (localIdentifier: String, assetSize: Double, createDate: Date, mediaType: Int) in
// return AssetModel.init(localIdentifier: localIdentifier, assetSize: assetSize, createDate: createDate)
// })
collectionView.reloadData()
}
......@@ -81,7 +76,6 @@ class TrashContenView: UIView {
collectionView.backgroundColor = UIColor.colorWithHex(hexStr: "#F2F6FC")
collectionView.dataSource = self
collectionView.register(UINib(nibName: "TrashContenAssetCell", bundle: nil), forCellWithReuseIdentifier: "TrashContenAssetCell")
// collectionView.register(UINib(nibName: "TrashContenTitleCell", bundle: nil), forCellWithReuseIdentifier: "TrashContenTitleCell")
addSubview(collectionView)
......@@ -134,14 +128,9 @@ class TrashContenView: UIView {
lineThree.backgroundColor = UIColor.colorWithHex(hexStr: "#E5E5E5")
topView.addSubview(lineThree)
lineFour = UIView()
lineFour.backgroundColor = UIColor.colorWithHex(hexStr: "#E5E5E5")
topView.addSubview(lineFour)
lineOne.frame = CGRect(x: 16, y: 62, width: lineW, height: 6)
lineTwo.frame = CGRect(x: 10+lineOne.rightX, y: 62, width: lineW, height: 6)
lineThree.frame = CGRect(x: 10+lineTwo.rightX, y: 62, width: lineW, height: 6)
lineFour.frame = CGRect(x: 10+lineThree.rightX, y: 62, width: lineW, height: 6)
scrollLine = UIView()
......@@ -218,23 +207,6 @@ class TrashContenView: UIView {
}else{
weakSelf.scrollLine.frame = weakSelf.lineThree.frame
}
case .chat:
if page == 4{
if offset < ScreenW * 3{
UIView.animate(withDuration: 0.2) {
weakSelf.scrollLine.frame = weakSelf.lineThree.frame
}
}else{
UIView.animate(withDuration: 0.2) {
weakSelf.scrollLine.frame = weakSelf.lineFour.frame
}
}
}else{
weakSelf.scrollLine.frame = weakSelf.lineFour.frame
}
}
}
}
......@@ -245,8 +217,6 @@ class TrashContenView: UIView {
lineOne.cornerCut(radius: 2, corner: .allCorners)
lineTwo.cornerCut(radius: 2, corner: .allCorners)
lineThree.cornerCut(radius: 2, corner: .allCorners)
lineFour.cornerCut(radius: 2, corner: .allCorners)
// collectionView.frame = self.bounds
}
var trashType:TrashTypeEnum = .video{
......@@ -258,8 +228,6 @@ class TrashContenView: UIView {
scrollLine.frame = lineTwo.frame
case .shot:
scrollLine.frame = lineThree.frame
case .chat:
scrollLine.frame = lineFour.frame
}
getData()
}
......
......@@ -103,8 +103,6 @@ class TrashDefaultView: UIView {
case .other,.shot:
jumpToPhotosDetailPage(type: type)
break
case .chat:
break
}
}
}
......@@ -113,14 +111,6 @@ class TrashDefaultView: UIView {
self.responderViewController()?.dismiss(animated: true, completion: {
NotificationCenter.default.post(name: TrashDefaultView.jumpToPhotosDetailPageName, object: nil,userInfo: ["type":self.mediaType?.rawValue ?? ""])
})
// PhotoDataManager.manager.loadFromFileSystem { model in
// let data = type == .other ? model.otherModelArray[4] : model.otherModelArray[2]
// let vc:HomePhotosDetailViewController = HomePhotosDetailViewController(model: data)
// vc.mediaType = type == .other ? .Other : PhotsFileType.screenshots
// vc.dealData()
// self.responderViewController()?.navigationController?.pushViewController(vc, animated: true)
// }
}
func jumpToVideoDetailPage(type: TrashTypeEnum){
self.responderViewController()?.dismiss(animated: true, completion: {
......
......@@ -24,7 +24,7 @@ class PMWidgetExampleController: UIViewController ,UIScrollViewDelegate{
var current = 0 {
didSet{
if current == 0 {
if current <= 0 {
ReturnAction.isHidden = true
}else{
ReturnAction.isHidden = false
......@@ -34,6 +34,20 @@ class PMWidgetExampleController: UIViewController ,UIScrollViewDelegate{
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) {
......@@ -46,16 +60,6 @@ class PMWidgetExampleController: UIViewController ,UIScrollViewDelegate{
}
}
}
}
var type = 0 {
didSet{
PMWidgetMainScroll.isHidden = !(type == 0)
PMWidgetLockScroll.isHidden = type == 0
current = 0
}
}
override func viewDidLoad() {
super.viewDidLoad()
......@@ -69,6 +73,7 @@ class PMWidgetExampleController: UIViewController ,UIScrollViewDelegate{
PMWidgetMainScroll.delegate = self;
PMWidgetLockScroll.delegate = self
type = 0
self.navigationController?.isNavigationBarHidden = true
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
......@@ -84,6 +89,7 @@ class PMWidgetExampleController: UIViewController ,UIScrollViewDelegate{
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{
......@@ -111,11 +117,13 @@ class PMWidgetExampleController: UIViewController ,UIScrollViewDelegate{
@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()
}
}
}
......
......@@ -13,6 +13,7 @@ class PMWidgetGuideStartController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.isNavigationBarHidden = true
}
@IBAction func StartNextAction(_ sender: Any) {
......
......@@ -19,7 +19,7 @@
<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="42"/>
<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"/>
......@@ -28,20 +28,29 @@
</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="131" width="321" height="43"/>
<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="194" width="347" height="43"/>
<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="257" width="325" height="442"/>
<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"/>
......@@ -68,13 +77,13 @@
<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 firstItem="Gk6-53-p7B" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="34" id="6tN-4g-d9M"/>
<constraint firstAttribute="trailing" secondItem="jAN-Lj-ySf" secondAttribute="trailing" constant="23" id="9jt-yG-2C3"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="Gk6-53-p7B" secondAttribute="trailing" constant="34" id="GSF-eJ-WeK"/>
<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"/>
......
......@@ -63,10 +63,12 @@ class WidgetViewController: BaseViewController {
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 {
......@@ -90,15 +92,14 @@ class WidgetViewController: BaseViewController {
}else{
isJumpExample = true
let guide = PMWidgetGuideStartController()
guide.modalPresentationStyle = .overFullScreen
let guideM = UINavigationController(rootViewController: guide)
guideM.modalPresentationStyle = .overFullScreen
guide.callblock = {[weak self] in
guide.dismiss(animated: true)
guard let self = self else { return }
let example = PMWidgetExampleController()
example.modalPresentationStyle = .overFullScreen
self.present(example, animated: true)
guide.navigationController?.pushViewController(example, animated: true)
}
self.present(guide, animated: true)
self.present(guideM, animated: true)
}
}
......@@ -207,7 +208,7 @@ class WidgetViewController: BaseViewController {
private lazy var setWidgetBtn: UIButton = {
let btn = UIButton(type: .custom)
btn.setTitle("Set Widget", for: .normal)
btn.titleLabel?.font = UIFont.systemFont(ofSize: 16)
btn.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
btn.setTitleColor(.white, for: .normal)
btn.addTarget(self, action: #selector(setWidgetTouch), for: .touchUpInside)
view.addSubview(btn)
......
......@@ -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
......
......@@ -29,6 +29,10 @@ class PMScaleImageView: UIView , UIScrollViewDelegate {
size.width = self.width
size.height = size.height * (self.width / (self.icon?.size.width ?? 1))
}
if size.height > self.height {
size.height = self.height
size.width = size.width * (self.height / (self.icon?.size.height ?? 1))
}
self.showImg.snp.remakeConstraints({ make in
make.left.equalToSuperview().offset((self.width - size.width)/2.0 )
make.top.equalToSuperview().offset((self.height - size.height)/2.0 )
......
......@@ -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)
......
......@@ -7,6 +7,8 @@
import Foundation
import AudioToolbox
import CoreHaptics
extension Int {
......@@ -122,15 +124,15 @@ extension CGFloat {
extension NSObject {
public func vibrate(_ all:Bool? = false) -> Void {
public func vibrate(_ all:Bool? = nil) -> Void {
if all != nil {
DispatchQueue.main.async {
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
HapticManager.share.triggerHapticFeedback()
}
}else{
if SettingConfiguration.share.config.vibration ?? false {
DispatchQueue.main.async {
AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))
HapticManager.share.triggerHapticFeedback()
}
}
}
......@@ -153,3 +155,38 @@ extension UISwitch {
}
}
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: .medium)
genter.prepare()
return genter
}()
// 触发震动反馈
func triggerHapticFeedback() {
generator.impactOccurred()
}
}
......@@ -16,6 +16,9 @@ class PMFaceIDManger: NSObject {
}
class func request() -> Bool {
if isAvailable() == false {
return false
}
let context = LAContext()
return context.biometricType == .faceID
}
......
......@@ -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