Commit 2cf5ae73 authored by shenyong's avatar shenyong

Merge branch 'Advertisement' of gitlab.huolea.com:ShuMing/phonemanager into Advertisement

# Conflicts:
#	PhoneManager/Class/Page/Contact/View/Common/AlertView/BaseAlertView.swift
#	PhoneManager/Class/Page/Home/Controller/PhotoSlideViewController.swift
#	PhoneManager/Class/Page/Home/View/AnchorRotatableView.swift
#	PhoneManager/Class/Page/Secret/PMShowImgVideoController.swift
#	PhoneManager/Class/Page/Widget/View/WidgetBornThenView.swift
parents 1a939e25 52802867
......@@ -77,6 +77,13 @@
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
041E22DC2DCCD63B0028E917 /* Exceptions for "widget" folder in "PhoneManager" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
widgetLockSreenView.swift,
);
target = EB388E5A2D8A61A800629B0D /* PhoneManager */;
};
0496DF032D9E3F59005B2834 /* Exceptions for "widget" folder in "widgetExtension" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
......@@ -104,6 +111,7 @@
0496DEF52D9E3F58005B2834 /* widget */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
041E22DC2DCCD63B0028E917 /* Exceptions for "widget" folder in "PhoneManager" target */,
0496DF032D9E3F59005B2834 /* Exceptions for "widget" folder in "widgetExtension" target */,
);
path = widget;
......@@ -580,10 +588,12 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = PhoneManager/Info.plist;
INFOPLIST_KEY_NSCameraUsageDescription = "We need to obtain your camera permission in order to save the photos you take in the private album feature";
INFOPLIST_KEY_NSContactsUsageDescription = "Phone Manager needs access to your contacts to find and merge duplicate contacts";
INFOPLIST_KEY_NSLocalNetworkUsageDescription = "We need to access the network to load content";
INFOPLIST_KEY_NSMicrophoneUsageDescription = "We need to obtain your microphone permission in order to use it when shooting videos in the private album feature";
INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "We need to access your album in order to find the photos you want to change and update them";
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "We need to access your album in order to find the photos you want to change and update them";
INFOPLIST_KEY_NSUserTrackingUsageDescription = "We need your permission to track your usage habits in order to provide a more personalized advertising experience";
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UIMainStoryboardFile = Main;
......@@ -626,10 +636,12 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = PhoneManager/Info.plist;
INFOPLIST_KEY_NSCameraUsageDescription = "We need to obtain your camera permission in order to save the photos you take in the private album feature";
INFOPLIST_KEY_NSContactsUsageDescription = "Phone Manager needs access to your contacts to find and merge duplicate contacts";
INFOPLIST_KEY_NSLocalNetworkUsageDescription = "We need to access the network to load content";
INFOPLIST_KEY_NSMicrophoneUsageDescription = "We need to obtain your microphone permission in order to use it when shooting videos in the private album feature";
INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "We need to access your album in order to find the photos you want to change and update them";
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "We need to access your album in order to find the photos you want to change and update them";
INFOPLIST_KEY_NSUserTrackingUsageDescription = "We need your permission to track your usage habits in order to provide a more personalized advertising experience";
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UIMainStoryboardFile = Main;
......
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "button_switch_off.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "button_switch_off@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "button_switch_off@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "button_switch_on.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "button_switch_on@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "button_switch_on@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "emailSmall.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "ic_delete_duplicates.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ic_delete_duplicates@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_delete_duplicates@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "ic_sel_com.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ic_sel_com@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_sel_com@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "ic_switch_email.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ic_switch_email@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_switch_email@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "ic_unsel_com.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ic_unsel_com@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_unsel_com@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "ic_unsel_com_red.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ic_unsel_com_red@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_unsel_com_red@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "icon_add.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "icon_add@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "icon_add@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "icon_left_setting_grey.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "icon_left_setting_grey@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "icon_left_setting_grey@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "img_email.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "img_email@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "img_email@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
......@@ -6,6 +6,7 @@
//
import Foundation
import Contacts
class ContactBackupDetailViewController : BaseViewController {
......@@ -157,6 +158,7 @@ extension ContactBackupDetailViewController:UITableViewDelegate,UITableViewDataS
return 20
}
func setupCustomIndexView() {
customIndexView = nil
customIndexView = UIStackView()
customIndexView.axis = .vertical
customIndexView.alignment = .center
......@@ -166,9 +168,9 @@ extension ContactBackupDetailViewController:UITableViewDelegate,UITableViewDataS
self.customIndexView.snp.makeConstraints { make in
make.left.equalTo(self.tableView.snp.right).offset(0)
make.top.equalTo(self.subTitleLabel.snp.bottom).offset(77)
make.centerY.equalTo(self.view.snp.centerY)
make.width.equalTo(15 * RScreenW())
make.height.equalTo(354)
make.height.equalTo(self.sectionTitles.count * (14 + 2))
}
for (index, section) in sectionTitles.enumerated() {
......@@ -193,8 +195,17 @@ extension ContactBackupDetailViewController:UITableViewDelegate,UITableViewDataS
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let visibleRect = CGRect(origin: tableView.contentOffset, size: tableView.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.minY)
// 获取可见区域的中心点,稍微向下偏移以更准确地检测当前可见的 section
let visibleRect = CGRect(
origin: tableView.contentOffset,
size: tableView.bounds.size
)
// 将检测点从顶部边缘下移一些,例如下移10%的可见区域高度
let adjustedY = visibleRect.minY + visibleRect.height * 0.1
let visiblePoint = CGPoint(x: visibleRect.midX, y: adjustedY)
// 获取可见区域最顶部的单元格的 indexPath
if let visibleIndexPath = tableView.indexPathForRow(at: visiblePoint) {
let newIndex = visibleIndexPath.section
if newIndex != selectedIndex {
......@@ -218,7 +229,6 @@ extension ContactBackupDetailViewController:UITableViewDelegate,UITableViewDataS
let indexPath = IndexPath(row: 0, section: index)
tableView.scrollToRow(at: indexPath, at: .top, animated: true)
selectedIndex = index
updateIndexStyles()
}
}
......
......@@ -12,6 +12,7 @@ class CustomContactViewController: CNContactViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.allowsEditing = false
setupCancelButton()
}
......
......@@ -153,7 +153,7 @@ extension ContactAllView : UITableViewDataSource,UITableViewDelegate {
}else{
self.selectedContacts.removeAll(where: { $0.identifier == model.identifier })
}
DispatchQueue.main.async {
// 判断button是否显示
if self.selectedContacts.count > 0 {
......@@ -205,9 +205,9 @@ extension ContactAllView : UITableViewDataSource,UITableViewDelegate {
self.customIndexView.snp.makeConstraints { make in
make.left.equalTo(self.tableView.snp.right).offset(0)
make.top.equalTo(self.subTitleLabel.snp.bottom).offset(77)
make.centerY.equalTo(self.snp.centerY)
make.width.equalTo(15 * RScreenW())
make.height.equalTo(354)
make.height.equalTo(self.sectionTitles.count * (14 + 2))
}
for (index, section) in sectionTitles.enumerated() {
......@@ -232,8 +232,17 @@ extension ContactAllView : UITableViewDataSource,UITableViewDelegate {
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let visibleRect = CGRect(origin: tableView.contentOffset, size: tableView.bounds.size)
let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.minY)
// 获取可见区域的中心点,稍微向下偏移以更准确地检测当前可见的 section
let visibleRect = CGRect(
origin: tableView.contentOffset,
size: tableView.bounds.size
)
// 将检测点从顶部边缘下移一些,例如下移10%的可见区域高度
let adjustedY = visibleRect.minY + visibleRect.height * 0.1
let visiblePoint = CGPoint(x: visibleRect.midX, y: adjustedY)
// 获取可见区域最顶部的单元格的 indexPath
if let visibleIndexPath = tableView.indexPathForRow(at: visiblePoint) {
let newIndex = visibleIndexPath.section
if newIndex != selectedIndex {
......@@ -257,7 +266,6 @@ extension ContactAllView : UITableViewDataSource,UITableViewDelegate {
let indexPath = IndexPath(row: 0, section: index)
tableView.scrollToRow(at: indexPath, at: .top, animated: true)
selectedIndex = index
updateIndexStyles()
}
}
......@@ -271,12 +279,32 @@ extension ContactAllView : UITableViewDataSource,UITableViewDelegate {
guard let self else {return}
if isSure {
backupContactsByselect {
// 备份完成后删除
self.deleteContacts()
// 删除之前弹出是否真的需要删除
let alertVc = ContactDeleteAlertView()
alertVc.frame = (self.responderViewController()?.view.bounds)!
cWindow?.addSubview(alertVc)
alertVc.sureCallBack = {[weak self] isSure in
guard let self else {return}
if isSure {
// 提示是否删除
self.deleteContacts()
}
}
}
}else{
// 如果不备份,直接删除
self.deleteContacts()
// 删除之前弹出是否真的需要删除
let alertVc = ContactDeleteAlertView()
alertVc.frame = (self.responderViewController()?.view.bounds)!
cWindow?.addSubview(alertVc)
alertVc.sureCallBack = {[weak self] isSure in
guard let self else {return}
if isSure {
// 提示是否删除
self.deleteContacts()
}
}
}
}
}
......@@ -284,15 +312,15 @@ extension ContactAllView : UITableViewDataSource,UITableViewDelegate {
func backupContactsByselect(success:@escaping()->Void){
// 开始备份联系人,备份完成提示
let vm = BackupViewModel()
vm.backupPartialContacts(self.selectedContacts) { finised, error in
vm.backupPartialContacts(self.dataSourceModel) { finised, error in
if finised {
// 备份成功
success()
DispatchQueue.main.async {
let buAlertVc = ContactBackUpCompletedAlertView(frame: (cWindow?.bounds)!)
cWindow?.addSubview(buAlertVc)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
buAlertVc.removeFromSuperview()
success()
}
}
}else{
......
......@@ -99,7 +99,9 @@ class BackupViewModel {
decoder.dateDecodingStrategy = .iso8601
// 尝试解码为 BackupInfoModel 数组
let backupInfos = try decoder.decode([BackupInfoModel].self, from: jsonData)
completion(backupInfos, nil)
// 根据时间倒序下
let sortedModels = backupInfos.sorted { $0.backupTime > $1.backupTime }
completion(sortedModels, nil)
} catch {
Print(error.localizedDescription)
completion(nil, error)
......
//
// BaseAlertView.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import Foundation
import SnapKit
class BaseAlertView : UIView {
private var bottomConstraint: Constraint?
override init(frame: CGRect) {
super.init(frame: frame)
// 先显示背景,然后延迟显示弹框
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
UIView.animate(withDuration: 0.1) {
// 更新约束
self.bottomConstraint?.update(offset: 0)
self.layoutIfNeeded()
}
}
}
override func removeFromSuperview() {
UIView.animate(withDuration: 0.2) {
// 更新约束
self.backgroundColor = .clear
self.bottomConstraint?.update(offset: self.height)
self.layoutIfNeeded()
}completion: { _ in
super.removeFromSuperview()
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
......@@ -13,7 +13,7 @@ class ContactBacRestoreAlertView : UIView {
// 懒加载背景视图
private lazy var backgroundView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
view.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.4000)
return view
}()
......
......@@ -12,7 +12,7 @@ class ContactBackUpCompletedAlertView : UIView {
// 懒加载背景视图
private lazy var backgroundView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
view.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.4000)
return view
}()
......
......@@ -14,7 +14,7 @@ class ContactBackUpDeleteCompletedAlertView : UIView {
// 懒加载背景视图
private lazy var backgroundView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
view.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.4000)
return view
}()
......
......@@ -11,7 +11,7 @@ class ContactBackUpNoDataAlertView : UIView {
// 懒加载背景视图
private lazy var backgroundView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
view.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.4000)
return view
}()
......
......@@ -8,12 +8,13 @@
import Foundation
class ContactBackupAlertView : UIView {
var sureCallBack: (Bool)->Void = {isSure in }
// 懒加载背景视图
private lazy var backgroundView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
view.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.4000)
return view
}()
......@@ -124,7 +125,6 @@ class ContactBackupAlertView : UIView {
make.height.equalTo(46)
}
}
@objc private func dismissAlert() {
......
......@@ -13,7 +13,7 @@ class ContactDeleteAlertView : UIView {
// 懒加载背景视图
private lazy var backgroundView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
view.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.4000)
return view
}()
......
......@@ -13,7 +13,7 @@ class ContactMergeAlertView : UIView {
// 懒加载背景视图
private lazy var backgroundView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
view.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.4000)
return view
}()
......
......@@ -11,7 +11,7 @@ class ContactRestoreSuccessView : UIView {
// 懒加载背景视图
private lazy var backgroundView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.black.withAlphaComponent(0.5)
view.backgroundColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.4000)
return view
}()
......
......@@ -39,6 +39,19 @@ class HomeInfoViewController:BaseViewController {
let sview:HomeInfoView = HomeInfoView(frame: CGRect(x: 0, y: cY, width: view.width, height: view.height - cY), ids: ids,type: self.type,titleText: titleText)
sview.titleShowHideCallBack = {[weak self] isShow in
guard let self else {return}
if isShow && self.titleLabel.alpha == 0 {
UIView.animate(withDuration: 0.1) {
self.titleLabel.alpha = 1
}
}else if isShow == false && self.titleLabel.alpha == 1{
UIView.animate(withDuration: 0.1) {
self.titleLabel.alpha = 0
}
}
}
sview.callBack = {[weak self] isSeleted in
guard let self else {return}
......@@ -275,6 +288,16 @@ class HomeInfoViewController:BaseViewController {
return label
}()
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.font = .systemFont(ofSize: 14, weight: .bold)
label.textColor = UIColor.colorWithHex(hexStr: black3Color)
label.text = titleText
label.alpha = 0
label.sizeToFit()
return label
}()
var ids: [[AssetModel]]?
var titleText : String?
......@@ -373,6 +396,10 @@ class HomeInfoViewController:BaseViewController {
titleView.addSubview(seletedAllBtn)
titleLabel.x = titleView.backBtn.width + titleView.backBtn.x + 10
titleLabel.centerY = navCenterY
titleView.addSubview(titleLabel)
view.addSubview(tablewView)
view.addSubview(self.defaultImageView)
self.defaultImageView.snp.makeConstraints { make in
......
......@@ -62,7 +62,14 @@ class HomeViewController:BaseViewController {
case 3 :
DispatchQueue.main.async {[weak self] in
guard let self else {return}
//FIXME: 是否登录了谷歌邮箱
if false {
let vc:EmailCleanController = EmailCleanController()
self.navigationController?.pushViewController(vc, animated: true)
}else{
let vc:EmailLoginController = EmailLoginController()
self.navigationController?.pushViewController(vc, animated: true)
}
}
break
case 4 :
......@@ -142,9 +149,9 @@ class HomeViewController:BaseViewController {
let homeSimilarImageResourceUpdate = Notification.Name("HomeSimilarImageResourceUpdate")
NotificationCenter.default.addObserver(self, selector: #selector(handleHomeSimilarImageResourceUpdate(_:)), name: homeSimilarImageResourceUpdate, object: nil)
homeView = HomeView(frame: view.bounds)
homeView?.y = cWindow?.safeAreaInsets.top ?? 20
homeView?.height = view.height - (cWindow?.safeAreaInsets.top ?? 20)
homeView?.titleCallBack = {[weak self] model,type in
guard let self else {return}
......
//
// PhotoSlideViewController.swift
// AIClean
//
// Created by 赵前 on 2025/5/10.
//
import UIKit
class PhotoSlideViewController: BaseViewController {
// 按钮竖直方向偏移量
let buttonVerticalOffset : CGFloat = 20
// MARK: - 数据与视图
var dataSource: [AssetModel] = []
private var currentIndex = 0
private var nextIndex = 0
private lazy var topView: AnchorRotatableView = {
let view = AnchorRotatableView()
view.configure(anchorPoint: CGPoint(x: 0.5, y: 0.5))
return view
}()
private lazy var bottomView: AnchorRotatableView = {
let view = AnchorRotatableView()
view.configure(anchorPoint: CGPoint(x: 0.5, y: 0.5))
return view
}()
private let leftButton: UIButton = {
let btn = UIButton()
btn.setTitle("Left", for: .normal)
btn.backgroundColor = .systemBlue.withAlphaComponent(0.8)
btn.alpha = 0
btn.layer.cornerRadius = 8
return btn
}()
private let rightButton: UIButton = {
let btn = UIButton()
btn.setTitle("Right", for: .normal)
btn.backgroundColor = .systemBlue.withAlphaComponent(0.8)
btn.alpha = 0
btn.layer.cornerRadius = 8
return btn
}()
// MARK: - 生命周期
override func viewDidLoad() {
super.viewDidLoad()
setupData()
setupViews()
setupGestures()
}
// MARK: - 初始化方法
private func setupData() {
currentIndex = dataSource.count - 1
updateCardContent()
}
private func setupViews() {
// 卡片视图
view.addSubview(bottomView)
view.addSubview(topView)
topView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(100)
make.bottom.equalToSuperview().offset(-100)
make.left.equalToSuperview().offset(20)
make.right.equalToSuperview().offset(-20)
}
bottomView.snp.makeConstraints { make in
make.top.equalToSuperview().offset(100)
make.bottom.equalToSuperview().offset(-100)
make.left.equalToSuperview().offset(20)
make.right.equalToSuperview().offset(-20)
}
// 操作按钮
view.addSubview(leftButton)
view.addSubview(rightButton)
resetButtonsPosition()
}
private func resetButtonsPosition() {
leftButton.snp.makeConstraints { make in
make.height.width.equalTo(50)
make.centerX.equalTo(100)
make.centerY.equalTo(100)
}
rightButton.snp.makeConstraints { make in
make.height.width.equalTo(50)
make.centerX.equalTo(45)
make.centerY.equalTo(100)
}
}
private func setupGestures() {
let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
topView.addGestureRecognizer(pan)
}
// MARK: - 手势处理
@objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
let translation = gesture.translation(in: view)
let velocity = gesture.velocity(in: view)
switch gesture.state {
case .began:
break
case .changed:
let progress = translation.x * 2 / topView.bounds.size.width
updateCardTransform(translation: translation)
updateButtons(progress: progress,translation: translation)
case .ended, .cancelled:
endDragAnimation(velocity: velocity)
default: break
}
}
// MARK: - 新手势绑定
private func setupGesturesForNewTopView() {
// 移除旧手势
topView.gestureRecognizers?.forEach { topView.removeGestureRecognizer($0) }
// 添加新手势
let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
pan.delegate = self
topView.addGestureRecognizer(pan)
// 确保视图层级
view.bringSubviewToFront(bottomView)
view.bringSubviewToFront(topView)
view.bringSubviewToFront(leftButton)
view.bringSubviewToFront(rightButton)
}
private func updateCardTransform(translation: CGPoint) {
let progress = translation.x / topView.bounds.size.width
// 角度
let rotationAngle = topView.maxRotationAngle * progress
topView.transform = CGAffineTransform(translationX: translation.x, y: 0)
.rotated(by: rotationAngle)
}
private func updateButtons(progress: CGFloat,translation:CGPoint) {
// 计算X轴坐标 向右的时候progress为正数
if progress > 0 {
leftButton.isHidden = false
rightButton.isHidden = true
}else {
leftButton.isHidden = true
rightButton.isHidden = false
}
let leftX = min(translation.x + 25 , topView.bounds.size.width / 2)
let rightX = max(360 - abs(translation.x) , topView.bounds.size.width / 2)
// 计算Y轴坐标
let verY = min(100 + buttonVerticalOffset,100 + buttonVerticalOffset * abs(progress))
UIView.animate(withDuration: 0.1) {
self.leftButton.center = CGPoint(
x: leftX,
y:verY
)
self.rightButton.center = CGPoint(
x: rightX,
y: verY
)
// 渐变效果
let alpha = abs(progress)
self.leftButton.alpha = alpha
self.rightButton.alpha = alpha
}
}
private func endDragAnimation(velocity: CGPoint) {
let translation = topView.transform.tx
let shouldDisappear = abs(translation) > topView.bounds.size.width/2 || abs(velocity.x) > 800
self.leftButton.alpha = 0
self.rightButton.alpha = 0
shouldDisappear ? animateCardDisappear() : resetCardPosition()
}
private func animateCardDisappear() {
let direction: UISwipeGestureRecognizer.Direction = topView.transform.tx > 0 ? .right : .left
UIView.animate(withDuration: 0.4) {
let targetX = direction == .right ? self.view.bounds.width * 1.5 : -self.view.bounds.width * 1.5
self.topView.transform = CGAffineTransform(translationX: targetX, y: 0)
self.topView.alpha = 0
} completion: { _ in
self.handleCardDisappeared()
}
}
private func resetCardPosition() {
UIView.animate(withDuration: 0.6,
delay: 0,
usingSpringWithDamping: 0.6,
initialSpringVelocity: 0.5) {
self.topView.transform = .identity
self.resetButtonsPosition()
}
}
// MARK: - 数据更新
private func updateCardContent() {
guard dataSource.indices.contains(currentIndex) else { return }
// 获取资源
topView.imageView.image = PhotoAndVideoMananger.mananger.getImageFromAssetID(id: dataSource[currentIndex].localIdentifier)
// 预加载下一张
let next = currentIndex - 1 >= 0 ? currentIndex - 1 : dataSource.count - 1
bottomView.imageView.image = PhotoAndVideoMananger.mananger.getImageFromAssetID(id: dataSource[next].localIdentifier)
}
private func handleCardDisappeared() {
// 更新索引(循环逻辑)
currentIndex = currentIndex - 1 >= 0 ? currentIndex - 1 : dataSource.count - 1
// 交换视图层级
let temp = topView
topView = bottomView
bottomView = temp
// 重置视图状态
topView.transform = .identity
topView.alpha = 1
topView.isUserInteractionEnabled = true
// 重新绑定新手势
setupGesturesForNewTopView()
resetButtonsPosition()
updateCardContent()
// 重置底层视图位置
bottomView.snp.remakeConstraints { make in
make.top.equalToSuperview().offset(100)
make.bottom.equalToSuperview().offset(-100)
make.left.equalToSuperview().offset(20)
make.right.equalToSuperview().offset(-20)
}
bottomView.transform = .identity
bottomView.alpha = 1
}
}
extension PhotoSlideViewController: UIGestureRecognizerDelegate {
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}
//
// AnchorRotatableView.swift
// AIClean
//
// Created by 赵前 on 2025/5/10.
//
import Foundation
import UIKit
class AnchorRotatableView: UIView {
var maxRotationAngle: CGFloat = .pi/12
lazy var imageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
return iv
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
private func setupView() {
backgroundColor = .gray
layer.cornerRadius = 12
clipsToBounds = true
addSubview(imageView)
imageView.snp.makeConstraints {
$0.edges.equalToSuperview()
}
}
}
extension AnchorRotatableView {
func configure(anchorPoint: CGPoint) {
layer.anchorPoint = anchorPoint
}
}
......@@ -32,25 +32,25 @@ class HomeCollectionViewHeader : UICollectionReusableView {
return view
}()
private lazy var tipLabel:UILabel = {
let label = UILabel()
label.numberOfLines = 0 // 支持多行
return label
}()
// private lazy var tipLabel:UILabel = {
// let label = UILabel()
// label.numberOfLines = 0 // 支持多行
// return label
// }()
private func setupUI() {
// 文本
self.addSubview(self.tipLabel)
self.tipLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(8)
make.top.equalToSuperview().offset(4)
make.height.equalTo(17)
}
// self.addSubview(self.tipLabel)
// self.tipLabel.snp.makeConstraints { make in
// make.left.equalToSuperview().offset(8)
// make.top.equalToSuperview().offset(44)
// make.height.equalTo(17)
// }
self.addSubview(self.progressBar)
self.progressBar.snp.makeConstraints { make in
make.top.equalTo(self.tipLabel.snp.bottom).offset(12)
make.top.equalTo(self.snp.top).offset(12 + 44 + 17)
make.width.equalToSuperview().offset(-16)
make.height.equalTo(31)
make.left.equalToSuperview().offset(8)
......@@ -90,7 +90,7 @@ extension HomeCollectionViewHeader{
/// - Parameters:
/// - count: 文件数量
/// - fileSize: 文件总大小
func setFileAndCount(count:Int,fileSize:Double) {
func setFileAndCount(count:Int,fileSize:Double) -> NSMutableAttributedString {
let countString = "\(count)"
let fileSizeString = formatFileSize(fileSize)
......@@ -122,9 +122,9 @@ extension HomeCollectionViewHeader{
.foregroundColor: UIColor.colorWithHex(hexStr: black6Color)
], range: nsRange2)
}
return attributedText
// 将 attributedText 赋值给 UILabel
self.tipLabel.attributedText = attributedText
// self.tipLabel.attributedText = attributedText
}
}
......
......@@ -7,7 +7,7 @@
import UIKit
class HomeInfoView :UIView{
class HomeInfoView :UIView {
var ids:[[AssetModel]]?
......@@ -20,10 +20,11 @@ class HomeInfoView :UIView{
var callBack:callBack<Any> = {text in}
var deleteCallBack:callBack<[AssetModel]> = {array in }
var titleShowHideCallBack:callBack<Bool> = {isShow in}
lazy var tableView:UITableView = {
let sview:UITableView = UITableView.init(frame: bounds)
let sview:UITableView = UITableView(frame: bounds, style: .grouped) //UITableView.init(frame: bounds )
sview.backgroundColor = .clear
sview.separatorStyle = .none
sview.showsVerticalScrollIndicator = false
......@@ -35,16 +36,13 @@ class HomeInfoView :UIView{
sview.sectionHeaderTopPadding = 0
}
return sview
}()
lazy var headerView:HomeInfoTitleView = {
let sview:HomeInfoTitleView = HomeInfoTitleView(frame: CGRect(x: 0, y: 0, width: width, height: 84))
sview.titleLabel.text = self.titleText
tableView.addSubview(sview)
return sview
}()
......@@ -164,6 +162,7 @@ class HomeInfoView :UIView{
for section in 0..<self.tableView.numberOfSections {
for item in 0..<self.tableView.numberOfRows(inSection: section) {
if let cell = self.tableView.cellForRow(at: IndexPath(row: item, section: section)) as? HomeInfoTableViewCell {
cell.checkSeletedAll()
UIView.transition(with: cell.collectionView!, duration: 0.3, options: .transitionCrossDissolve, animations: {
cell.collectionView?.reloadData()
}, completion: nil)
......@@ -182,7 +181,6 @@ class HomeInfoView :UIView{
}
}
}
return selectedArray
}
......@@ -255,6 +253,20 @@ class HomeInfoView :UIView{
extension HomeInfoView:UITableViewDataSource,UITableViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let OffsetY = scrollView.contentOffset.y
let top = CGRectGetMaxY(self.headerView.titleLabel.frame) + 8
var orgy = OffsetY - top
if orgy < 0 {
orgy = 0
}
titleShowHideCallBack( OffsetY > top )
var farme = self.headerView.frame
farme.origin.y = orgy
self.headerView.frame = farme
tableView.bringSubviewToFront(self.headerView)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ids?.count ?? 0
......@@ -284,13 +296,11 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate {
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return headerView.height
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
return headerView
return UIView()
}
}
......
......@@ -9,7 +9,7 @@ import UIKit
class HomeNavView:UIView {
private var settingBtn:UIButton!
// private var settingBtn:UIButton!
private var proBtn:UIButton!
private lazy var homeTitle : UILabel = {
let label = UILabel()
......@@ -38,24 +38,22 @@ class HomeNavView:UIView {
self.addSubview(self.homeTitle)
self.homeTitle.snp.makeConstraints { make in
make.left.equalTo(15 + 8)
make.top.equalTo(8 + statusBarHeight)
make.top.equalTo(8)
make.height.equalTo(28)
make.width.equalTo(149)
}
// 设置按钮
self.settingBtn = UIButton()
self.settingBtn.setImage(UIImage(named: "ic_setting_com"), for: .normal)
self.settingBtn.addTarget(self, action: #selector(settingBtnClick), for: .touchUpInside)
self.addSubview(settingBtn)
self.settingBtn.snp.makeConstraints { make in
make.centerY.equalTo(self.homeTitle.snp.centerY)
make.right.equalTo(-marginLR)
make.width.height.equalTo(iconWH)
}
// self.settingBtn = UIButton()
// self.settingBtn.setImage(UIImage(named: "ic_setting_com"), for: .normal)
// self.settingBtn.addTarget(self, action: #selector(settingBtnClick), for: .touchUpInside)
// self.addSubview(settingBtn)
// self.settingBtn.snp.makeConstraints { make in
// make.centerY.equalTo(self.homeTitle.snp.centerY)
// make.right.equalTo(-marginLR)
// make.width.height.equalTo(iconWH)
//
// }
// 会员按钮
self.proBtn = UIButton(frame: CGRect(x: 0, y: 0, width: 70, height: iconWH))
self.proBtn.setBackgroundImage(UIImage(named: "ic_pro_home"), for: .normal)
......@@ -63,7 +61,7 @@ class HomeNavView:UIView {
self.addSubview(proBtn)
self.proBtn.snp.makeConstraints { make in
make.centerY.equalTo(self.homeTitle.snp.centerY)
make.right.equalTo(self.settingBtn.snp.left).offset(-8)
make.right.equalTo(self.snp.right).offset(-8-iconWH-marginLR)
make.width.equalTo(78)
make.height.equalTo(iconWH)
}
......@@ -73,11 +71,12 @@ class HomeNavView:UIView {
extension HomeNavView {
@objc private func settingBtnClick() {
let homeNavViewModel = HomeNavViewModel()
let settingViewController = SettingViewController()
homeNavViewModel.pushToDetailController(currentView: self, destnationController: settingViewController)
}
// @objc private func settingBtnClick() {
// let homeNavViewModel = HomeNavViewModel()
// let settingViewController = SettingViewController()
// homeNavViewModel.pushToDetailController(currentView: self, destnationController: settingViewController)
// }
@objc private func proBtnClick() {
if IAPManager.share.isSubscribed == false {
HomePayViewController.show {}
......
......@@ -11,6 +11,7 @@ import SnapKit
class HomeView:UIView {
private var homeTabbarView:HomeTabbarView?
private var settingBtn:UIButton!
private var homeNavView:HomeNavView?
......@@ -30,6 +31,17 @@ class HomeView:UIView {
var model:PhotosManagerModel?
var isScroll = false {
didSet {
if isScroll {
DispatchQueue.main.async {
self.tipLabel.attributedText = self.attribet
}
}
}
}
var attribet:NSAttributedString?
lazy var collectionView:UICollectionView = {
let cY:CGFloat = 16.RW()
......@@ -51,11 +63,19 @@ class HomeView:UIView {
if #available(iOS 11.0, *) {
sview.contentInsetAdjustmentBehavior = .never
}
sview.clipsToBounds = true
sview.backgroundColor = .clear
return sview
}()
private lazy var topNaviView: UIView = {
let backView = UIView()
backView.backgroundColor = UIColor(hex: "#DAEAFF")
addSubview(backView)
return backView
}()
override init(frame: CGRect) {
super.init(frame: frame)
......@@ -68,20 +88,21 @@ class HomeView:UIView {
}
func setTitle() {
self.attribet = self.homeHeader?.setFileAndCount(count: model?.allFileNumber ?? 0, fileSize: model?.allFileSize ?? 0)
DispatchQueue.main.async {[weak self] in
guard let self else {return}
self.homeHeader?.setFileAndCount(count: model?.allFileNumber ?? 0, fileSize: model?.allFileSize ?? 0)
self.homeHeader?.setNeedsLayout()
self.homeHeader?.layoutIfNeeded()
if isScroll == false {
self.tipLabel.attributedText = self.attribet
self.homeHeader?.setNeedsLayout()
self.homeHeader?.layoutIfNeeded()
}
}
}
private func setupUI() {
backgroundColor = .clear
clipsToBounds = true
homeTabbarView = HomeTabbarView(frame: CGRect(x: 0, y: 0, width: self.width, height: safeHeight + 66))
......@@ -102,14 +123,29 @@ class HomeView:UIView {
homeNavView = HomeNavView(frame: CGRect(x: 0, y: 0, width: width, height: statusBarHeight + 44))
topNaviView.snp.makeConstraints { make in
make.top.centerX.width.equalToSuperview()
make.height.equalTo(44)
}
self.addSubview(homeNavView!)
homeNavView?.snp.makeConstraints({ make in
make.top.centerX.width.equalToSuperview()
make.height.equalTo(statusBarHeight + 44)
make.height.equalTo(44)
})
self.settingBtn = UIButton()
self.settingBtn.setImage(UIImage(named: "ic_setting_com"), for: .normal)
self.settingBtn.addTarget(self, action: #selector(settingBtnClick), for: .touchUpInside)
self.addSubview(settingBtn)
self.settingBtn.snp.makeConstraints { make in
make.centerY.equalTo(self.homeNavView!.snp.centerY)
make.right.equalTo(-marginLR)
make.width.height.equalTo(iconWH)
}
bottomView = UIView(frame: CGRect(x: 0, y: 0, width: width, height: safeHeight + 10))
bottomView?.backgroundColor = .white
self.addSubview(bottomView!)
......@@ -118,15 +154,19 @@ class HomeView:UIView {
make.bottom.equalToSuperview().offset(10)
make.height.equalTo(safeHeight + 10)
})
self.insertSubview(collectionView, at: 0)
collectionView.snp.makeConstraints { make in
make.top.equalTo(self.homeNavView!.snp.bottom).offset(0)
make.centerX.equalToSuperview()
make.top.centerX.equalToSuperview()
make.width.equalToSuperview().offset(-2 * marginLR)
make.bottom.equalToSuperview().offset( -homeTabbarView!.height - 16)
}
self.addSubview(self.tipLabel)
self.tipLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(8+marginLR)
make.top.equalTo(self.collectionView.snp.top).offset(44)
make.height.equalTo(17)
}
}
func etCell(indexPath: IndexPath) -> UICollectionViewCell {
......@@ -134,10 +174,53 @@ class HomeView:UIView {
return UICollectionViewCell()
}
private lazy var tipLabel:UILabel = {
let label = UILabel()
label.numberOfLines = 0 // 支持多行
return label
}()
}
extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICollectionViewDelegate {
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
isScroll = true
}
func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
isScroll = true
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offsetY = scrollView.contentOffset.y
var changeY = offsetY
if changeY < 0 {
changeY = 0
}
var cframe = self.homeNavView?.frame
cframe?.origin.y = -changeY
self.homeNavView?.frame = cframe ?? CGRect()
var centerY = 22 + iconWH - offsetY
let setCenterY = settingBtn.center.y
if centerY < setCenterY {
centerY = setCenterY
}
tipLabel.centerY = centerY
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
isScroll = false // 拖动停止且无需减速
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
isScroll = false // 减速完全停止
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 2
......@@ -322,7 +405,7 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
func referenceSizeForHeader(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGSize {
if section == 0 {
if Singleton.shared.photoPermission == .authorized {
return CGSize(width: self.collectionView.width, height: 76)
return CGSize(width: self.collectionView.width, height: 76 + (self.homeNavView?.height ?? 0))
}else{
return CGSize(width: self.collectionView.width, height: 404)
}
......@@ -334,4 +417,12 @@ extension HomeView:WaterfallMutiSectionDelegate,UICollectionViewDataSource,UICol
let indexPath = IndexPath(item: 0, section: 0)
return self.collectionView.supplementaryView(forElementKind: UICollectionView.elementKindSectionHeader, at: indexPath)
}
@objc private func settingBtnClick() {
let homeNavViewModel = HomeNavViewModel()
let settingViewController = SettingViewController()
homeNavViewModel.pushToDetailController(currentView: self, destnationController: settingViewController)
}
}
......@@ -72,10 +72,21 @@ class HomeOtherCollectionCell: UICollectionViewCell {
return iv
}()
lazy var playerView: SecretVideoPlayer = {
let play = SecretVideoPlayer()
play.isUserInteractionEnabled = false
play.fromState = .home
play.Radius = 16
play.contentMode = .scaleAspectFill
play.isLooping = true
return play
}()
// MARK: - Lifecycle
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActive), name: Notification.Name("applicationDidBecomeActive"), object: nil)
}
required init?(coder: NSCoder) {
......@@ -87,16 +98,20 @@ class HomeOtherCollectionCell: UICollectionViewCell {
backgroundColor = .white
self.contentView.addSubview(self.titleLabel)
self.contentView.addSubview(self.imageView)
self.contentView.addSubview(self.playImageView)
self.contentView.addSubview(self.playerView)
// self.contentView.addSubview(self.playImageView)
self.imageView.addSubview(self.infoBackView)
self.playerView.addSubview(self.infoBackView)
self.infoBackView.addSubview(self.countLabel)
self.infoBackView.addSubview(self.sizeLabel)
self.infoBackView.addSubview(self.moreImageView)
}
@objc private func didBecomeActive() -> Void {
self.playerView.resume()
}
var model:HomePhotosModel? {
didSet {
......@@ -161,19 +176,35 @@ class HomeOtherCollectionCell: UICollectionViewCell {
// 从 PHAsset 获取 AVAsset
if let videoAsset = PhotoAndVideoMananger.mananger.getPHAsssetwithID(ids: [asset.localIdentifier]){
// 使用requestImageForAsset方法请求视频的第一帧图片
PHImageManager.default().requestImage(for: videoAsset, targetSize: CGSize(width: 400, height: 400), contentMode: PHImageContentMode.aspectFit, options: options) { image, _ in
// 处理获取到的图片
if let thumbnailImage = image {
// 使用获取到的图片,例如显示在UIImageView上
DispatchQueue.main.async {
// 确保在主线程更新UI
self.imageView.image = thumbnailImage
}
} else {
self.imageView.image = UIImage(named: "img_vedio_defpage")
print("无法获取图片")
}
}
let options = PHVideoRequestOptions()
options.version = .current
options.deliveryMode = .automatic // 根据需求调整视频质量:ml-citation{ref="2,7" data="citationList"}
PHImageManager.default().requestAVAsset(
forVideo: videoAsset,
options: options
) { (avAsset, audioMix, info) in
guard let avAsset = avAsset as? AVURLAsset else { return }
let videoURL = avAsset.url
print("视频地址: \(videoURL)")
DispatchQueue.main.async {
self.playerView.playVideo(from: videoURL)
}
}
// PHImageManager.default().requestImage(for: videoAsset, targetSize: CGSize(width: 400, height: 400), contentMode: PHImageContentMode.aspectFit, options: options) { image, _ in
// // 处理获取到的图片
// if let thumbnailImage = image {
// // 使用获取到的图片,例如显示在UIImageView上
// DispatchQueue.main.async {
// // 确保在主线程更新UI
// self.imageView.image = thumbnailImage
// }
// } else {
// self.imageView.image = UIImage(named: "img_vedio_defpage")
// print("无法获取图片")
// }
// }
}
}
}
......@@ -206,14 +237,16 @@ class HomeOtherCollectionCell: UICollectionViewCell {
make.height.equalTo(self.width - 32)
}
self.infoBackView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.height.equalTo(40)
}
self.playImageView.snp.makeConstraints { make in
make.width.height.equalTo(43)
make.center.equalTo(self.imageView.snp.center)
// self.playImageView.snp.makeConstraints { make in
// make.width.height.equalTo(43)
// make.center.equalTo(self.imageView.snp.center)
// }
self.playerView.snp.makeConstraints { make in
make.left.right.top.bottom.equalTo(imageView)
}
titleLabel.snp.makeConstraints { make in
......@@ -237,7 +270,10 @@ class HomeOtherCollectionCell: UICollectionViewCell {
make.right.equalToSuperview().offset(-12)
make.centerY.equalToSuperview()
}
// titleLabel.sizeToFit()
}
deinit {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name("applicationDidBecomeActive"), object: nil)
}
}
......@@ -54,7 +54,7 @@ class ImageCollectionCell:UICollectionViewCell {
backImageView = UIImageView()
backImageView?.isUserInteractionEnabled = true
backImageView?.contentMode = .scaleAspectFit
backImageView?.contentMode = .scaleAspectFill
backImageView?.clipsToBounds = true
backImageView?.layer.masksToBounds = true
backImageView?.isUserInteractionEnabled = true
......
......@@ -26,7 +26,6 @@ class HomePayModel: NSObject ,SKProductsRequestDelegate ,SKPaymentTransactionObs
private let productIdentifiers:[String] = ["com.app.phonemanager.week.member" , "com.app.phonemanager.lifetime.member"]
var isSubscribed:Bool = false
var isNoAd:Bool {
get {
......
......@@ -11,40 +11,62 @@ let PMShowImgCellID = "PMShowImgCell"
class PMShowImgCell: UICollectionViewCell {
var callblock:(()->Void) = {}
@objc private func selectTap() -> Void {
callblock()
}
var icon:UIImage = UIImage() {
didSet {
iconView.image = icon
var size = icon.size
if size.width != 0 && size.height != 0 {
if size.height < size.width {
let width = self.width
size = CGSize(width: width, height: size.height * (width/size.width) )
}else{
let width = self.width
let height = size.height * (width/size.width)
if height > self.height {
size = CGSize(width: width * (self.height/height), height: height )
}else {
size = CGSize(width: width, height: height )
}
}
}
iconView.snp.remakeConstraints { make in
make.centerX.centerY.equalToSuperview()
make.size.equalTo(size)
}
scaleImg.icon = icon
// iconView.image = icon
// var size = icon.size
// if size.width != 0 && size.height != 0 {
// if size.height < size.width {
// let width = self.width
// size = CGSize(width: width, height: size.height * (width/size.width) )
// }else{
// let width = self.width
// let height = size.height * (width/size.width)
// if height > self.height {
// size = CGSize(width: width * (self.height/height), height: height )
// }else {
// size = CGSize(width: width, height: height )
// }
// }
// }
//
// iconView.snp.remakeConstraints { make in
// make.centerX.centerY.equalToSuperview()
// make.size.equalTo(size)
// }
}
}
private lazy var iconView: UIImageView = {
let info = UIImageView()
info.contentMode = .scaleToFill
info.contentMode = .scaleAspectFill
contentView.addSubview(info)
info.clipsToBounds = true
return info
}()
lazy var selectBtn: UIButton = {
let select = UIButton(type: .custom)
select.setImage(UIImage(named: ""), for: .normal)
select.setImage(UIImage(named: ""), for: .selected)
select.addTarget(self, action: #selector(selectTap), for: .touchUpInside)
contentView.addSubview(select)
return select
}()
private lazy var scaleImg: PMScaleImageView = {
let img = PMScaleImageView()
contentView.addSubview(img)
return img
}()
override init(frame: CGRect) {
super.init(frame: frame)
setup()
......@@ -59,5 +81,13 @@ class PMShowImgCell: UICollectionViewCell {
iconView.snp.makeConstraints { make in
make.left.right.bottom.top.equalToSuperview()
}
scaleImg.snp.makeConstraints { make in
make.left.right.bottom.top.equalToSuperview()
}
selectBtn.snp.makeConstraints { make in
make.right.equalToSuperview()
make.width.height.equalTo(iconWH)
make.bottom.equalToSuperview().offset(-10)
}
}
}
......@@ -11,7 +11,7 @@ import UIKit
let PMShowItemCellID = "PMShowItemCell"
class PMShowItemCell: UICollectionViewCell {
var isCurrent:Bool = false {
didSet {
if isCurrent {
......@@ -37,6 +37,15 @@ class PMShowItemCell: UICollectionViewCell {
return ic
}()
private lazy var selectBtn: UIButton = {
let select = UIButton(type: .custom)
select.setImage(UIImage(named: ""), for: .normal)
select.setImage(UIImage(named: ""), for: .selected)
contentView.addSubview(select)
select.isUserInteractionEnabled = false
return select
}()
override init(frame: CGRect) {
super.init(frame: frame)
clipsToBounds = true
......@@ -52,6 +61,11 @@ class PMShowItemCell: UICollectionViewCell {
iconV.snp.makeConstraints { make in
make.left.right.top.bottom.equalToSuperview()
}
selectBtn.snp.makeConstraints { make in
make.right.equalToSuperview()
make.width.height.equalTo(iconWH)
make.bottom.equalToSuperview()
}
}
}
......@@ -29,41 +29,25 @@ class PMShowImgVideoController: BaseViewController {
var homeDataSource : [ImageSeletedCollectionItem]?
var currentIdx = 0
var selectSet = NSMutableSet()
var url : URL?
override func viewDidLoad() {
super.viewDidLoad()
configUI()
}
func configUI(){
// 垃圾桶临时入口
let trashBtn = UIButton()
trashBtn.setTitle("trash", for: .normal)
trashBtn.setTitleColor(.black, for: .normal)
trashBtn.addTarget(self, action: #selector(pushToTrash), for: .touchUpInside)
titleView.addSubview(trashBtn)
trashBtn.snp.makeConstraints { make in
make.right.equalTo(-16)
make.centerY.equalTo(titleView.titleLabel)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.MaxCollection.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(20)
make.top.top.equalTo(titleView.snp.bottom).offset(20)
make.bottom.equalToSuperview().inset(100)
make.top.equalTo(titleView.snp.bottom).offset(20)
make.bottom.equalToSuperview().inset(100 + (cWindow?.safeAreaInsets.bottom ?? 0))
}
self.bottItems.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.left.right.equalTo(MaxCollection)
make.top.equalTo(MaxCollection.snp.bottom)
make.bottom.equalToSuperview()
make.bottom.equalToSuperview().offset(-(cWindow?.safeAreaInsets.bottom ?? 0))
}
self.view.layoutIfNeeded()
self.MaxCollection.scrollToItem(at: IndexPath(row: currentIdx, section: 0), at: .centeredHorizontally, animated: false)
......@@ -88,27 +72,20 @@ class PMShowImgVideoController: BaseViewController {
private lazy var bottItems: UICollectionView = {
let flowlayout = UICollectionViewFlowLayout()
flowlayout.sectionInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
flowlayout.minimumInteritemSpacing = 0
flowlayout.sectionInset = UIEdgeInsets()
flowlayout.minimumInteritemSpacing = 10
flowlayout.minimumLineSpacing = 10
flowlayout.scrollDirection = .horizontal
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
col.isPagingEnabled = true
view.addSubview(col)
return col
}()
@objc func pushToTrash(){
let vc = TrashViewController()
self.present(vc, animated: true)
}
}
extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout{
......@@ -119,29 +96,52 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
let offsetx = MaxCollection.contentOffset.x
let width = collectView.width
let current:Int = Int(offsetx / width)
currentIdx = current
// currentIdx = current
bottItems.scrollToItem(at: IndexPath(row: current, section: 0), at: .left, animated: true)
}
}
private func setMaxCollection(collectionView:UICollectionView) -> Void {
if collectionView == bottItems {
let offsetX = collectionView.contentOffset.x
let idx = round(offsetX / (68 + 10))
UIView.animate(withDuration: 0.5) {
collectionView.contentOffset = CGPointMake( idx * (68 + 10) , 0)
}
MaxCollection.scrollToItem(at: IndexPath(row: Int(idx), section: 0), at: .centeredHorizontally, animated: true)
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
Print("1")
guard let collectView = scrollView as? UICollectionView else { return }
if collectView == MaxCollection {
bottItems.reloadData()
}
// if collectView == MaxCollection {
// bottItems.reloadData()
// }
self.setMaxCollection(collectionView: collectView)
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
Print("2")
if !decelerate {
guard let collectView = scrollView as? UICollectionView else { return }
self.setMaxCollection(collectionView: collectView)
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView == bottItems {
if currentIdx != indexPath.row {
currentIdx = indexPath.row
MaxCollection.scrollToItem(at: indexPath, at: .left, animated: false)
collectionView.reloadData()
if selectSet.contains(indexPath.row) {
selectSet.remove(indexPath.row)
}else{
selectSet.add(indexPath.row)
}
self.MaxCollection.reloadData()
collectionView.reloadData()
// if currentIdx != indexPath.row {
// currentIdx = indexPath.row
// MaxCollection.scrollToItem(at: indexPath, at: .left, animated: false)
// collectionView.reloadData()
// }
}
}
......@@ -149,7 +149,11 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
if self.state == .secret {
return imageVideoPath.count
}else {
return self.homeDataSource?.count ?? 0
if collectionView == MaxCollection{
return self.homeDataSource?.count ?? 0
}else{
return (self.homeDataSource?.count ?? 0) + 1
}
}
}
......@@ -197,12 +201,25 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
if collectionView == MaxCollection {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PMShowImgCellID, for: indexPath) as! PMShowImgCell
cell.icon = self.homeDataSource![indexPath.row].image ?? UIImage()
cell.isSelected = selectSet.contains(indexPath.row)
cell.callblock = {[weak self] in
guard let self = self else { return }
if self.selectSet.contains(indexPath.row){
self.selectSet.remove(indexPath.row)
}else{
self.selectSet.add(indexPath.row)
}
self.MaxCollection.reloadData()
self.bottItems.reloadData()
}
return cell
}else {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PMShowItemCellID, for: indexPath) as! PMShowItemCell
cell.icon = self.homeDataSource![indexPath.row].image ?? UIImage()
cell.isCurrent = (self.currentIdx == indexPath.row)
return cell
if indexPath.row < self.homeDataSource?.count ?? 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PMShowItemCellID, for: indexPath) as! PMShowItemCell
cell.icon = self.homeDataSource![indexPath.row].image ?? UIImage()
cell.isCurrent = selectSet.contains(indexPath.row) //(self.currentIdx == indexPath.row)
return cell
}
}
}
......@@ -226,13 +243,15 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
cell.type = 1
return cell
}else{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PMShowItemCellID, for: indexPath) as! PMShowItemCell
cell.icon = self.homeDataSource![indexPath.row].image ?? UIImage()
cell.isCurrent = (self.currentIdx == indexPath.row)
return cell
if indexPath.row < self.homeDataSource?.count ?? 0 {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PMShowItemCellID, for: indexPath) as! PMShowItemCell
cell.icon = self.homeDataSource![indexPath.row].image ?? UIImage()
cell.isCurrent = (self.currentIdx == indexPath.row)
return cell
}
}
}
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "", for: indexPath)
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "UICollectionViewCell", for: indexPath)
return cell
}
......@@ -240,11 +259,13 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
if collectionView == MaxCollection {
return collectionView.size
}
return CGSize(width: 68, height: 68)
if indexPath.row < self.homeDataSource?.count ?? 0 {
return CGSize(width: 68, height: 68)
}
return CGSize(width: collectionView.width - 68, height: 68)
}
/// 根据LocalIdentifier获取视频的URL
/// - Parameters:
/// - localIdentifier: 资源标识
......
......@@ -14,6 +14,11 @@ class SecretVideoPlayer: UIView {
private var player: AVPlayer?
var isLooping = false
enum PlayerFrom {
case home
case other
}
enum playState {
case start
case playing
......@@ -21,6 +26,8 @@ class SecretVideoPlayer: UIView {
case end
}
var fromState:PlayerFrom = .other
var state:playState = .start
override init(frame: CGRect) {
......@@ -49,8 +56,11 @@ class SecretVideoPlayer: UIView {
}
private func setupPlayerLayer() {
backgroundColor = .clear
let playerLayer = AVPlayerLayer()
playerLayer.videoGravity = .resizeAspect
playerLayer.backgroundColor = UIColor.clear.cgColor
playerLayer.shouldRasterize = true
playerLayer.rasterizationScale = UIScreen.main.scale
layer.addSublayer(playerLayer)
let tap = UITapGestureRecognizer(target: self, action: #selector(tapClick))
self.addGestureRecognizer(tap)
......@@ -60,6 +70,7 @@ class SecretVideoPlayer: UIView {
super.layoutSubviews()
if let playerLayer = layer.sublayers?.first as? AVPlayerLayer {
playerLayer.frame = bounds
}
}
......@@ -71,6 +82,12 @@ class SecretVideoPlayer: UIView {
player = AVPlayer(url: url!)
if let playerLayer = layer.sublayers?.first as? AVPlayerLayer {
playerLayer.player = player
if fromState == .home {
playerLayer.videoGravity = .resizeAspectFill
player?.isMuted = true
}else{
playerLayer.videoGravity = .resizeAspect
}
}
NotificationCenter.default.addObserver(
self,
......@@ -79,6 +96,7 @@ class SecretVideoPlayer: UIView {
object: player?.currentItem
)
state = .playing
player?.play()
}
......
......@@ -20,6 +20,18 @@ class WidgetPublicModel: NSObject {
return batt
}
public class func BatteryState() -> Bool {
let device = UIDevice.current
device.isBatteryMonitoringEnabled = true
switch device.batteryState {
case .charging:
return true
default:
return false
}
}
/// 已使用
/// - Returns: 已使用空间
......@@ -68,6 +80,10 @@ class WidgetPublicModel: NSObject {
return val
}
class func isLowPowerModeEnabled() -> Bool {
return ProcessInfo.processInfo.isLowPowerModeEnabled
}
}
class widgetAppgourp: NSObject {
......@@ -75,7 +91,12 @@ class widgetAppgourp: NSObject {
static let share = widgetAppgourp()
func PushWidgetData(_ widget:Int = 0 , battery:Int , storage:Int ) -> Void {
let data = WidgetData(userId: "", widget: widget, battery: battery, widgetStorage: storage)
let disk = WidgetPublicModel.getDiskSpace()
let allInt = Int(CGFloat(disk.0)/(1000.0 * 1000.0 * 1000.0))
let useInt = Int(CGFloat(disk.0 - disk.1)/(1000.0 * 1000.0 * 1000.0))
let state = (WidgetPublicModel.isLowPowerModeEnabled() ? "On" : "Off")
let data = WidgetData(userId: "", widget: widget, battery: battery, widgetStorage: storage,AllSpace: allInt , UseSpace: useInt ,batteryState:state ,isCharging: WidgetPublicModel.BatteryState())
if let sharedDefaults = UserDefaults(suiteName: "group.com.app.phonemanager") {
let encodedData = try? JSONEncoder().encode(data)
sharedDefaults.set(encodedData, forKey: "widgetSharedData")
......@@ -91,4 +112,8 @@ struct WidgetData: Codable {
var widget: Int
var battery: Int
var widgetStorage :Int
var AllSpace: Int
var UseSpace: Int
let batteryState: String
let isCharging: Bool
}
This diff is collapsed.
......@@ -24,13 +24,27 @@ class WidgetTopStackView: UIView {
if type == 0 {
battryBtn.isSelected = true
storageBtn.isSelected = false
battryBtn.backgroundColor = .white
storageBtn.backgroundColor = .clear
}else{
bronThem.isSelected = false
bronThem.backgroundColor = .clear
}else if type == 1{
battryBtn.isSelected = false
storageBtn.isSelected = true
battryBtn.backgroundColor = .clear
storageBtn.backgroundColor = .white
bronThem.isSelected = false
bronThem.backgroundColor = .clear
}else{
battryBtn.isSelected = false
storageBtn.isSelected = false
battryBtn.backgroundColor = .clear
storageBtn.backgroundColor = .clear
bronThem.isSelected = true
bronThem.backgroundColor = .white
}
}
}
......@@ -43,16 +57,37 @@ class WidgetTopStackView: UIView {
}
private func setUI() -> Void {
battryBtn.snp.makeConstraints { make in
make.left.top.bottom.equalToSuperview().inset(4)
make.right.equalTo(self.snp.centerX)
}
storageBtn.snp.makeConstraints { make in
make.right.top.bottom.equalToSuperview().inset(4)
make.left.equalTo(self.snp.centerX)
stack.snp.makeConstraints { make in
make.left.top.bottom.right.equalToSuperview().inset(4)
}
stack.addArrangedSubview(battryBtn)
stack.addArrangedSubview(storageBtn)
stack.addArrangedSubview(bronThem)
// battryBtn.snp.makeConstraints { make in
// make.left.top.bottom.equalToSuperview().inset(4)
// make.width.equalTo(self.snp.width).multipliedBy(1/3.0).offset(-8)
// }
// storageBtn.snp.makeConstraints { make in
// make.top.bottom.equalToSuperview().inset(4)
// make.left.equalTo(battryBtn.snp.right)
// make.width.equalTo(battryBtn.snp.width)
// }
// bronThem.snp.makeConstraints { make in
// make.right.top.bottom.equalToSuperview().inset(4)
// make.left.equalTo(storageBtn.snp.right)
// }
}
private lazy var stack: UIStackView = {
let stack = UIStackView()
stack.spacing = 2
stack.axis = .horizontal
stack.alignment = .fill
stack.distribution = .fillEqually
addSubview(stack)
return stack
}()
private lazy var battryBtn: UIButton = {
let b = UIButton(type: .custom)
b.tag = 0
......@@ -61,7 +96,6 @@ class WidgetTopStackView: UIView {
b.setTitleColor(.colorWithHex(hexStr: "#0082FF"), for: .selected)
b.addTarget(self, action: #selector(widgetTouchs(_:)), for: .touchUpInside)
b.layer.cornerRadius = 4
addSubview(b)
return b
}()
......@@ -73,7 +107,17 @@ class WidgetTopStackView: UIView {
b.setTitleColor(.colorWithHex(hexStr: "#0082FF"), for: .selected)
b.addTarget(self, action: #selector(widgetTouchs(_:)), for: .touchUpInside)
b.layer.cornerRadius = 4
addSubview(b)
return b
}()
private lazy var bronThem: UIButton = {
let b = UIButton(type: .custom)
b.tag = 2
b.setTitle("Both", for: .normal)
b.setTitleColor(.colorWithHex(hexStr: "#B3B3B3"), for: .normal)
b.setTitleColor(.colorWithHex(hexStr: "#0082FF"), for: .selected)
b.addTarget(self, action: #selector(widgetTouchs(_:)), for: .touchUpInside)
b.layer.cornerRadius = 4
return b
}()
......
......@@ -9,21 +9,23 @@ import UIKit
class WidgetViewController: BaseViewController {
enum widgetType {
case battery
case storage
enum widgetType:Int {
case battery = 0
case storage = 1
case bothThem = 2
}
var widgets:widgetType = .battery {
didSet {
topButs.type = (self.widgets == .battery ? 0 : 1)
batterySta.widgetType = (self.widgets == .battery ? 0 : 1)
topButs.type = self.widgets.rawValue
batterySta.widgetType = self.widgets.rawValue
}
}
var widgetMode = 0 {// 0 1 2
didSet{
batterySta.widgetMode = widgetMode
born.widgetMode = widgetMode
}
}
......@@ -33,11 +35,16 @@ class WidgetViewController: BaseViewController {
setUI()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
widgetMode = 0
}
@objc func setWidgetTouch() -> Void {
let battery = WidgetPublicModel.battery()
let storage = WidgetPublicModel.UseDiskSpace() * 100
var widgetIdx = 0
widgetIdx = (widgets == .battery ? 0 : 1) * 10 + widgetMode
widgetIdx = widgets.rawValue * 10 + widgetMode
widgetAppgourp.share.PushWidgetData(widgetIdx, battery: Int(battery), storage: Int(storage))
PMAlert("Set Widget Successfully")
}
......@@ -61,14 +68,19 @@ class WidgetViewController: BaseViewController {
make.centerX.equalToSuperview()
make.top.equalTo(batterySta.snp.bottom).offset(50)
}
born.snp.makeConstraints { make in
make.top.equalTo(batterySta.snp.top)
make.left.right.equalToSuperview().inset(30)
make.height.equalTo(born.snp.width)
}
statesBottom.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.size.equalTo(CGSize(width: 180, height: 40))
make.top.equalTo(widgetPageCtrol.snp.bottom).offset(50)
make.top.equalTo(born.snp.bottom).offset(20)
}
setWidgetBtn.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(15)
make.bottom.equalToSuperview().offset(-50)
make.bottom.equalToSuperview().offset(-30)
make.height.equalTo(46)
}
}
......@@ -84,24 +96,37 @@ class WidgetViewController: BaseViewController {
private lazy var topButs: WidgetTopStackView = {
let topbuts = WidgetTopStackView()
topbuts.type = (self.widgets == .battery ? 0 : 1)
topbuts.type = self.widgets.rawValue
topbuts.callback = { [weak self] idx in
self?.born.isHidden = true
if idx == 0 {
self?.widgets = .battery
self?.widgetPageCtrol.currentPage = 0
}else{
}else if idx == 1{
self?.widgets = .storage
self?.widgetPageCtrol.currentPage = 1
}else{
self?.born.isHidden = false
self?.widgets = .bothThem
self?.widgetPageCtrol.currentPage = 2
}
}
view.addSubview(topbuts)
return topbuts
}()
private lazy var born: WidgetBornThenView = {
let born = WidgetBornThenView()
born.layer.cornerRadius = 20
born.isHidden = true
view.addSubview(born)
return born
}()
private lazy var batterySta: WidgetBatteryStView = {
let stav = WidgetBatteryStView()
stav.layer.cornerRadius = 20
stav.widgetType = (self.widgets == .battery ? 0 : 1)
stav.widgetType = self.widgets.rawValue
stav.widgetMode = widgetMode
view.addSubview(stav)
return stav
......@@ -110,7 +135,7 @@ class WidgetViewController: BaseViewController {
private lazy var widgetPageCtrol: UIPageControl = {
let page = UIPageControl()
page.currentPage = 0
page.numberOfPages = 2
page.numberOfPages = 3
page.currentPageIndicatorTintColor = .colorWithHex(hexStr: "#0082FF")
page.pageIndicatorTintColor = .colorWithHex(hexStr: "#C6CEE0")
view.addSubview(page)
......
//
// EmailCleanListViewCell.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import UIKit
class EmailCleanListViewCell: UITableViewCell {
static let id = "EmailCleanListViewCell"
var callblock = {}
@IBOutlet weak var ListFirstL: UILabel!
@IBOutlet weak var selectBtn: UIButton!
@IBOutlet weak var ListDot: UIView!
@IBOutlet weak var groupName: UILabel!
@IBOutlet weak var descpText: UILabel!
@IBOutlet weak var descpText1: UILabel!
@IBOutlet weak var EmailTimeL: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
@IBAction func selectActions(_ sender: Any) {
callblock()
}
}
//
// EmailContentTabCell.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import UIKit
class EmailContentTabCell: UITableViewCell {
static let id = "EmailContentTabCell"
var callblock = {}
@IBOutlet weak var selectBtn: UIButton!
@IBOutlet weak var groupName: UILabel!
@IBOutlet weak var groupNumbers: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
@IBAction func selectActions(_ sender: Any) {
callblock()
}
}
<?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" id="KGk-i7-Jjw" customClass="EmailContentTabCell" customModule="PhoneManager" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="320" height="86"/>
<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="320" height="86"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HGx-M7-LQS">
<rect key="frame" x="15" y="0.0" width="290" height="74"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="SFC-9k-JL4">
<rect key="frame" x="6" y="15.000000000000004" width="44" height="44.333333333333343"/>
<inset key="contentEdgeInsets" minX="10" minY="10" maxX="10" maxY="10"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" image="ic_sel_com"/>
<state key="selected" image="ic_unsel_com_red"/>
<connections>
<action selector="selectActions:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="PTj-Zp-HqP"/>
</connections>
</button>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" spacing="1" translatesAutoresizingMaskIntoConstraints="NO" id="a94-EP-nFu">
<rect key="frame" x="50" y="18.333333333333332" width="92" height="37.333333333333343"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Social Media" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eH5-kI-3vv">
<rect key="frame" x="0.0" y="0.0" width="92" height="19.333333333333332"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0 Emails" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dgz-WN-aKh">
<rect key="frame" x="0.0" y="20.333333333333332" width="92" height="16.999999999999996"/>
<color key="backgroundColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="0.0" colorSpace="custom" customColorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="icon_left_setting_grey" translatesAutoresizingMaskIntoConstraints="NO" id="JWZ-DO-70m">
<rect key="frame" x="254" y="27" width="20" height="20"/>
</imageView>
</subviews>
<color key="backgroundColor" red="0.94901960784313721" green="0.96470588235294119" blue="0.9882352941176471" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="JWZ-DO-70m" secondAttribute="trailing" constant="16" id="9Be-SQ-UxW"/>
<constraint firstItem="SFC-9k-JL4" firstAttribute="centerY" secondItem="HGx-M7-LQS" secondAttribute="centerY" id="Gww-V3-ADp"/>
<constraint firstItem="SFC-9k-JL4" firstAttribute="leading" secondItem="HGx-M7-LQS" secondAttribute="leading" constant="6" id="MuS-Bu-Wyb"/>
<constraint firstItem="a94-EP-nFu" firstAttribute="centerY" secondItem="HGx-M7-LQS" secondAttribute="centerY" id="b2x-dx-sEC"/>
<constraint firstItem="a94-EP-nFu" firstAttribute="leading" secondItem="SFC-9k-JL4" secondAttribute="trailing" id="kS8-jn-NTj"/>
<constraint firstItem="JWZ-DO-70m" firstAttribute="centerY" secondItem="HGx-M7-LQS" secondAttribute="centerY" id="q4H-To-Ycj"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="Radius">
<real key="value" value="12"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="HGx-M7-LQS" secondAttribute="bottom" constant="12" id="5ow-Tb-b9b"/>
<constraint firstAttribute="trailing" secondItem="HGx-M7-LQS" secondAttribute="trailing" constant="15" id="7pZ-zP-neq"/>
<constraint firstItem="HGx-M7-LQS" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="15" id="o6P-oe-F5F"/>
<constraint firstItem="HGx-M7-LQS" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="z1a-C6-L0w"/>
</constraints>
</tableViewCellContentView>
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<connections>
<outlet property="groupName" destination="eH5-kI-3vv" id="SJQ-eI-X4U"/>
<outlet property="groupNumbers" destination="dgz-WN-aKh" id="HJh-jw-nFW"/>
<outlet property="selectBtn" destination="SFC-9k-JL4" id="4V0-CJ-STJ"/>
</connections>
<point key="canvasLocation" x="131" y="-11"/>
</tableViewCell>
</objects>
<resources>
<image name="ic_sel_com" width="24" height="24.333333969116211"/>
<image name="ic_unsel_com_red" width="24" height="24"/>
<image name="icon_left_setting_grey" width="20" height="20"/>
</resources>
</document>
//
// EmailFilterSelectCell.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import UIKit
class EmailFilterBaseCell: UITableViewCell {
var callblock:((Bool)->Void) = { select in}
var top:Bool = false
var bot:Bool = false
func reload() -> Void {
DispatchQueue.main.async {
if self.top && self.bot {
self.cornerCut(radius: 12, corner: [.allCorners])
}else if self.top {
self.cornerCut(radius: 12, corner: [.topLeft,.topRight])
}else if self.bot {
self.cornerCut(radius: 12, corner: [.bottomLeft,.bottomRight])
}else{
self.cornerCut(radius: 0, corner: [.allCorners])
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
}
@IBOutlet weak var titleL: UILabel!
}
<?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" id="KGk-i7-Jjw" customClass="EmailFilterBaseCell">
<rect key="frame" x="0.0" y="0.0" width="320" height="50"/>
<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="320" height="50"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bYm-Ap-ASH">
<rect key="frame" x="16" y="0.0" width="0.0" height="50"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="50" id="ByC-vP-p5G"/>
</constraints>
<fontDescription key="fontDescription" type="boldSystem" pointSize="14"/>
<color key="textColor" red="0.20000001788139343" green="0.20000001788139343" blue="0.20000001788139343" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
<real key="value" value="1"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
</subviews>
<color key="backgroundColor" red="0.9490196704864502" green="0.96470588445663452" blue="0.98823529481887817" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="bYm-Ap-ASH" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="64l-PN-erS"/>
<constraint firstItem="bYm-Ap-ASH" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="16" id="Phe-hO-ZzN"/>
<constraint firstAttribute="bottom" secondItem="bYm-Ap-ASH" secondAttribute="bottom" id="qz2-bx-e67"/>
</constraints>
</tableViewCellContentView>
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
<connections>
<outlet property="titleL" destination="bYm-Ap-ASH" id="mmr-1G-Kh5"/>
</connections>
<point key="canvasLocation" x="104" y="-11"/>
</tableViewCell>
</objects>
</document>
//
// EmailFilterSelectCell.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import UIKit
class EmailFilterSelectCell: EmailFilterBaseCell {
static let id = "EmailFilterSelectCell"
@IBOutlet weak var selectBtn: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
self.titleL.snp.remakeConstraints { make in
make.right.equalTo(selectBtn.snp.left).offset(-5)
make.top.bottom.equalToSuperview()
make.left.equalToSuperview().offset(16)
make.height.equalTo(50)
}
}
@IBAction func selectActions(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
callblock(sender.isSelected)
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
//
// EmailContentDelAlert.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import UIKit
class EmailContentDelAlert: UIViewController {
enum EmailStateAlert {
case group
case list
}
var callblock:((Int)->Void) = { idx in}
var state:EmailStateAlert = .group
@IBOutlet weak var EmailContentMessage: UILabel!
@IBOutlet weak var EmailContentAction1: UIButton!
@IBOutlet weak var EmailContentAction2: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = UIColor.colorWithHex(hexStr: "#000000", alpha: 0.5)
switch state {
case .group:
EmailContentMessage.text = "Do you want to apply filters\nfirst or delete mails\nimmediately?"
EmailContentAction1.setTitle("Open Filters", for: .normal)
EmailContentAction2.setTitle("Delete Mails", for: .normal)
break
case .list:
EmailContentMessage.text = "Are you sure you want to delete\nthe selected message?"
EmailContentAction1.setTitle("Delete", for: .normal)
EmailContentAction2.setTitle("Cancel", for: .normal)
break
}
}
func show() -> Void {
self.modalTransitionStyle = .crossDissolve
self.modalPresentationStyle = .overFullScreen
UIViewController.topMostViewController()?.present(self, animated: true)
}
@IBAction func openAction(_ sender: Any) {
callblock(1)
self.dismiss(animated: true)
}
@IBAction func delMails(_ sender: Any) {
callblock(2)
self.dismiss(animated: true)
}
init(state:EmailStateAlert) {
super.init(nibName: nil, bundle: nil)
self.state = state
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
<?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="EmailContentDelAlert" customModule="PhoneManager" customModuleProvider="target">
<connections>
<outlet property="EmailContentAction1" destination="H0G-H1-Hx9" id="UGo-uz-h5v"/>
<outlet property="EmailContentAction2" destination="jnJ-Cn-DN9" id="kvy-Tn-fkZ"/>
<outlet property="EmailContentMessage" destination="LvN-1W-NqV" id="Njf-Gw-nPY"/>
<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>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="pSS-8M-78U">
<rect key="frame" x="15" y="324" width="363" height="204"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Do you want to apply filters first or delete mails immediately?" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="LvN-1W-NqV">
<rect key="frame" x="30" y="28" width="303" height="48"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="H0G-H1-Hx9">
<rect key="frame" x="20" y="92" width="323" height="46"/>
<color key="backgroundColor" red="0.0" green="0.50980392156862742" blue="1" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="46" id="5di-G4-1L2"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Open Filters"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="Radius">
<real key="value" value="23"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<action selector="openAction:" destination="-1" eventType="touchUpInside" id="cXg-7i-361"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="jnJ-Cn-DN9">
<rect key="frame" x="20" y="142" width="323" height="46"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="46" id="nV9-Zl-cHG"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Delete Mails">
<color key="titleColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="calibratedRGB"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="Radius">
<real key="value" value="23"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<action selector="delMails:" destination="-1" eventType="touchUpInside" id="4eY-Ct-AUg"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="jnJ-Cn-DN9" firstAttribute="trailing" secondItem="H0G-H1-Hx9" secondAttribute="trailing" id="4ng-Lt-WbX"/>
<constraint firstAttribute="trailing" secondItem="H0G-H1-Hx9" secondAttribute="trailing" constant="20" id="905-Xu-9S0"/>
<constraint firstItem="jnJ-Cn-DN9" firstAttribute="leading" secondItem="H0G-H1-Hx9" secondAttribute="leading" id="LEk-uf-rgE"/>
<constraint firstAttribute="bottom" secondItem="jnJ-Cn-DN9" secondAttribute="bottom" constant="16" id="Md6-lU-fDx"/>
<constraint firstAttribute="trailing" secondItem="LvN-1W-NqV" secondAttribute="trailing" constant="30" id="NSl-d7-q7R"/>
<constraint firstItem="H0G-H1-Hx9" firstAttribute="leading" secondItem="pSS-8M-78U" secondAttribute="leading" constant="20" id="Ug2-zL-HbE"/>
<constraint firstItem="LvN-1W-NqV" firstAttribute="top" secondItem="pSS-8M-78U" secondAttribute="top" constant="28" id="WEG-CD-zit"/>
<constraint firstItem="H0G-H1-Hx9" firstAttribute="top" secondItem="LvN-1W-NqV" secondAttribute="bottom" constant="16" id="iri-xQ-fNU"/>
<constraint firstItem="jnJ-Cn-DN9" firstAttribute="top" secondItem="H0G-H1-Hx9" secondAttribute="bottom" constant="4" id="lRP-Ui-Mbq"/>
<constraint firstItem="LvN-1W-NqV" firstAttribute="leading" secondItem="pSS-8M-78U" secondAttribute="leading" constant="30" id="nXB-dD-AvZ"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="Radius">
<real key="value" value="20"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="pSS-8M-78U" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="15" id="HFc-06-2Br"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="pSS-8M-78U" secondAttribute="trailing" constant="15" id="gCg-jq-x1v"/>
<constraint firstItem="pSS-8M-78U" firstAttribute="centerY" secondItem="i5M-Pr-FkT" secondAttribute="centerY" id="j7D-f0-DPt"/>
</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>
//
// EmailCleanController.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import UIKit
class EmailCleanController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
setup()
}
private func setup() -> Void {
contentView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.top.equalTo(titleView.snp.bottom)
}
}
private lazy var contentView: EmailContentView = {
let content = EmailContentView(self)
view.addSubview(content)
return content
}()
}
//
// EmailCleanListController.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import UIKit
class EmailCleanListController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setup()
}
@objc func seletedAllBtnClick() {
DispatchQueue.main.async {[weak self] in
guard let self else {return}
seletedAllBtn.isSelected = !seletedAllBtn.isSelected
UIView.animate(withDuration: 0.1) {
self.seletedAllBtn.width = self.seletedAllBtn.isSelected ? 131 : 115
self.seletedAllBtn.x = self.titleView.width - marginLR - self.seletedAllBtn.width
}
tableView.changeSelectAll(seletedAllBtn.isSelected)
}
}
private func setup() -> Void {
titleLabel.snp.makeConstraints { make in
make.top.equalTo(titleView.snp.bottom).offset(20)
make.left.equalToSuperview().offset(marginLR)
}
tableView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.top.equalTo(titleLabel.snp.bottom).offset(10)
make.bottom.equalToSuperview()
}
titleView.addSubview(seletedAllBtn)
seletedAllBtn.centerY = navCenterY
seletedAllBtn.x = titleView.width - marginLR - seletedAllBtn.width
}
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.text = "Social Media"
label.font = UIFont.systemFont(ofSize: 20, weight: .bold)
label.textColor = .black
label.textAlignment = .left
view.addSubview(label)
return label
}()
private lazy var tableView: EmailCleanListView = {
let tab = EmailCleanListView()
view.addSubview(tab)
tab.callblock = { [weak self] select in
guard let self = self else { return }
self.seletedAllBtn.isSelected = select
}
return tab
}()
private lazy var seletedAllBtn:UIButton = {
let btn:UIButton = UIButton(frame: CGRect(x: 0, y: 0, width: 115, height: 32))
btn.addTarget(self, action: #selector(seletedAllBtnClick), for: .touchUpInside)
btn.backgroundColor = UIColor.colorWithHex(hexStr: "#F2F6FC")
btn.setImage(UIImage.init(named: "ic_check_similar"), for: .normal)
btn.setTitle("Select All", for: .normal)
btn.setImage(UIImage.init(named: "ic_close_similar"), for: .selected)
btn.setTitle("Deselect All", for: .selected)
btn.setTitleColor(UIColor.colorWithHex(hexStr: mColor), for: .normal)
btn.setTitleColor(UIColor.colorWithHex(hexStr: black3Color), for: .selected)
btn.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .bold)
btn.layer.cornerRadius = btn.height / 2
btn.layer.masksToBounds = true
btn.changBtnWithStytl(btnStyle: .defalut, margin: 8)
return btn
}()
}
//
// EmailFilterController.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import UIKit
class EmailFilterController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
setup()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.tableView.reloadData()
}
var datasource:[EmailFilterModel] = EmailFilterManager.filter()
private func setup() -> Void {
titleLabel.snp.makeConstraints({ make in
make.left.equalTo(titleView.backBtn.snp.right).offset(5)
make.centerY.equalTo(titleView.backBtn)
})
tableView.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(marginLR)
make.top.equalTo(titleView.snp.bottom).offset(10)
make.bottom.equalTo(ApplyBtn.snp.top)
}
ApplyBtn.snp.makeConstraints { make in
make.height.equalTo(46)
make.bottom.equalToSuperview().offset(-(cWindow?.safeAreaInsets.bottom ?? 0)-10)
make.left.right.equalToSuperview().inset(marginLR)
}
}
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.text = "Filters"
label.font = UIFont.systemFont(ofSize: 20, weight: .bold)
label.textColor = .black
label.textAlignment = .left
titleView.addSubview(label)
return label
}()
private lazy var tableView: UITableView = {
let tab = UITableView(frame: CGRectZero, style: .plain)
tab.delegate = self;
tab.dataSource = self
tab.separatorStyle = .none
tab.separatorInset = UIEdgeInsets()
tab.sectionHeaderHeight = 50
tab.register(UINib(nibName: EmailFilterSelectCell.id, bundle: nil), forCellReuseIdentifier: EmailFilterSelectCell.id)
if #available(iOS 15.0, *) {
tab.sectionHeaderTopPadding = 0
}
view.addSubview(tab)
return tab
}()
private lazy var ApplyBtn: UIButton = {
let emailLogin = UIButton(type: .custom)
emailLogin.backgroundColor = UIColor.colorWithHex(hexStr: "#0082FF")
emailLogin.setTitle("Apply Filters", for: .normal)
emailLogin.setTitleColor(.white, for: .normal)
emailLogin.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
emailLogin.layer.cornerRadius = 46/2.0
emailLogin.clipsToBounds = true
emailLogin.addTarget(self, action: #selector(ApplyAction), for: .touchUpInside)
view.addSubview(emailLogin)
return emailLogin
}()
}
extension EmailFilterController : UITableViewDelegate,UITableViewDataSource {
@objc func ApplyAction() -> Void {
guard var path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
path = path.appendingPathComponent("EmailFilter.json")
do{
let data = try JSONEncoder().encode(datasource)
try data.write(to: path)
}catch{
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return datasource.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return datasource[section].child?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: EmailFilterSelectCell.id, for: indexPath) as! EmailFilterSelectCell
let dataA = datasource[indexPath.section].child
let data = dataA?[indexPath.row]
cell.titleL.text = data?.title ?? ""
cell.selectBtn.isSelected = data?.isSelect ?? false
cell.top = (indexPath.row == 0)
cell.bot = (indexPath.row == (dataA?.count ?? 0 - 1))
cell.callblock = {[weak self] select in
guard let self = self else { return }
self.datasource[indexPath.section].child?[indexPath.row].isSelect = select
tableView.reloadData()
}
cell.reload()
return cell
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = UILabel()
header.font = UIFont.boldSystemFont(ofSize: 12)
header.text = datasource[section].header ?? ""
header.textColor = UIColor.colorWithHex(hexStr: "#B3B3B3")
return header
}
}
//
// EmailListDetailController.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import UIKit
class EmailListDetailController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
setup()
}
func setup() -> Void {
line.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.top.equalTo(titleView.snp.bottom).offset(20)
make.height.equalTo(1)
}
LT.snp.makeConstraints { make in
make.left.equalToSuperview().inset(15)
make.top.equalTo(line.snp.bottom).offset(15)
make.size.equalTo(CGSizeMake(40, 40))
}
SendL.snp.makeConstraints { make in
make.left.equalTo(LT.snp.right).offset(4)
make.right.equalTo(dateL.snp.left).inset(-5)
make.bottom.equalTo(LT.snp.centerY).offset(-2)
}
ToEmail.snp.makeConstraints { make in
make.left.equalTo(LT.snp.right).offset(4)
make.right.equalTo(dateL.snp.left).inset(-5)
make.top.equalTo(LT.snp.centerY).offset(2)
}
dateL.snp.makeConstraints { make in
make.right.equalToSuperview().inset(marginLR)
make.centerY.equalTo(LT.snp.centerY).offset(2)
make.width.equalTo(55)
}
line1.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.top.equalTo(LT.snp.bottom).offset(15)
make.height.equalTo(1)
}
titleL.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(marginLR)
make.top.equalTo(line1.snp.bottom).offset(20)
}
}
private lazy var LT: UILabel = {
let l = UILabel()
l.Radius = 20
l.text = "G"
l.font = UIFont.systemFont(ofSize: 20, weight: .heavy)
l.textAlignment = .center
l.textColor = .white
l.backgroundColor = UIColor.colorWithHex(hexStr: "#0082FF")
view.addSubview(l)
return l
}()
private lazy var SendL: UILabel = {
let l = UILabel()
l.text = "Google Play Support"
l.font = UIFont.systemFont(ofSize: 16, weight: .bold)
l.textColor = UIColor.colorWithHex(hexStr: "#333333")
view.addSubview(l)
return l
}()
private lazy var ToEmail: UILabel = {
let l = UILabel()
l.text = "To:zxcvbnm@gmail.com"
l.font = UIFont.systemFont(ofSize: 14, weight: .regular)
l.textColor = UIColor.colorWithHex(hexStr: "#666666")
view.addSubview(l)
return l
}()
private lazy var dateL: UILabel = {
let l = UILabel()
l.text = "20 Dec"
l.textAlignment = .right
l.font = UIFont.systemFont(ofSize: 12, weight: .regular)
l.textColor = UIColor.colorWithHex(hexStr: "#B3B3B3")
view.addSubview(l)
return l
}()
private lazy var titleL: UILabel = {
let l = UILabel()
l.text = "Notification from Google Play"
l.font = UIFont.systemFont(ofSize: 16, weight: .bold)
l.textColor = UIColor.colorWithHex(hexStr: "#333333")
view.addSubview(l)
return l
}()
private lazy var line: UIView = {
let l = UIView()
l.backgroundColor = UIColor.colorWithHex(hexStr: "#EBEFF5")
view.addSubview(l)
return l
}()
private lazy var line1: UIView = {
let l = UIView()
l.backgroundColor = UIColor.colorWithHex(hexStr: "#EBEFF5")
view.addSubview(l)
return l
}()
}
//
// EmailLoginController.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import UIKit
class EmailLoginController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
setup()
}
func setup() -> Void {
titleLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(marginLR)
make.top.equalTo(titleView.snp.bottom).offset(20)
}
EmptyView.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.top.equalTo(titleLabel.snp.bottom)
}
}
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.text = "Email Cleaner"
label.font = UIFont.systemFont(ofSize: 20, weight: .bold)
label.textColor = .black
label.textAlignment = .left
view.addSubview(label)
return label
}()
private lazy var EmptyView: EmailEmptyView = {
let empty = EmailEmptyView()
view.addSubview(empty)
empty.callblock = {[weak self] in
guard let self = self else { return }
let gourp = EmailCleanController()
var navigation = self.navigationController?.viewControllers
if navigation?.count ?? 0 > 1 {
navigation![navigation!.count-1] = gourp
self.navigationController?.setViewControllers(navigation ?? [], animated: true)
}
}
return empty
}()
}
//
// EmailFilterModel.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import UIKit
class EmailFilterManager: NSObject {
class func filter() -> [EmailFilterModel] {
let data = [ ["header":"TIME","child":[ ["title":"Delete all mails from selected categories",
"isSelect":false],
["title":"Delete 1 week and older mails",
"isSelect":false],
["title":"Delete 1 month and older mails",
"isSelect":false],
["title":"Delete 1 year and older mails",
"isSelect":false] ]
],
["header":"FAVORITE","child":[ ["title":"Delete stared mails",
"isSelect":false] ]
],
["header":"READ & UNREAD","child":[ ["title":"Delete read mails",
"isSelect":false],
["title":"Delete unread mails",
"isSelect":false]]
],
["header":"KEYWORDS","child":[ ["title":"Do not delete mails that contains the keywords below",
"isSelect":false,
"keyword":[] ] ]
]
]
guard var path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return [] }
path = path.appendingPathComponent("EmailFilter.json")
do {
let dataFile = try Data(contentsOf: path)
let decode = try JSONDecoder().decode([EmailFilterModel].self, from:dataFile)
return decode
}catch{
}
do{
let encode = try JSONSerialization.data(withJSONObject: data)
let decode = try JSONDecoder().decode([EmailFilterModel].self, from: encode)
return decode
}catch{
return []
}
}
}
struct EmailFilterModel: Codable {
var header:String?
var child:[EmailFilterChildModel]?
}
struct EmailFilterChildModel:Codable {
var title:String?
var isSelect:Bool = false
var keyword:[String]?
}
//
// EmailCleanListView.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import UIKit
class EmailCleanListView: UIView {
var callblock:((Bool)->Void) = { select in }
private func setup() -> Void {
tableView.snp.makeConstraints { make in
make.left.right.top.equalToSuperview()
make.bottom.equalTo(botAction.snp.top)
}
botAction.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.height.equalTo(52 + (cWindow?.safeAreaInsets.bottom ?? 0) + 24 )
}
}
var mailset = NSMutableSet()
var datasource:[String] = ["","","","","","","",""]
func changeSelectAll(_ select:Bool) -> Void {
if select {
for i in 0..<datasource.count {
self.mailset.add(i)
}
}else{
self.mailset.removeAllObjects()
}
botAction.numberMails = self.mailset.count
tableView.reloadData()
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
private lazy var tableView: UITableView = {
let tab = UITableView(frame: CGRectZero, style: .plain)
tab.delegate = self;
tab.dataSource = self
tab.separatorStyle = .none
tab.separatorInset = UIEdgeInsets()
tab.rowHeight = 101
tab.sectionHeaderHeight = 10
tab.register(UINib(nibName: EmailCleanListViewCell.id, bundle: nil), forCellReuseIdentifier: EmailCleanListViewCell.id)
if #available(iOS 15.0, *) {
tab.sectionHeaderTopPadding = 0
} else {
// Fallback on earlier versions
}
addSubview(tab)
return tab
}()
private lazy var botAction: EmailContentBottonAction = {
let bot = EmailContentBottonAction(state: .EmailList)
bot.clipsToBounds = false
addSubview(bot)
bot.numberMails = 0
bot.callblock = { [weak self] in
guard let self = self else { return }
let alert = EmailContentDelAlert(state: .list)
alert.callblock = { idx in
}
alert.show()
}
return bot
}()
}
extension EmailCleanListView : UITableViewDataSource,UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return datasource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: EmailCleanListViewCell.id, for: indexPath) as! EmailCleanListViewCell
cell.selectionStyle = .none
cell.selectBtn.isSelected = self.mailset.contains(indexPath.row)
cell.callblock = {[weak self] in
guard let self = self else { return }
if self.mailset.contains(indexPath.row) {
self.mailset.remove(indexPath.row)
}else{
self.mailset.add(indexPath.row)
}
self.botAction.numberMails = self.mailset.count
callblock(self.mailset.count == self.datasource.count)
tableView.reloadData()
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let detail = EmailListDetailController()
UIViewController.topMostViewController()?.navigationController?.pushViewController(detail, animated: true)
}
}
//
// EmailCleanTopView.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import UIKit
class EmailCleanTopView: UIView {
var callblock:(()->Void) = {}
private func setup() -> Void {
titleLabel.snp.makeConstraints { make in
make.left.equalToSuperview().offset(marginLR)
make.top.equalToSuperview().offset(20)
}
settingsButton.snp.makeConstraints { make in
make.right.equalToSuperview().inset(marginLR)
make.centerY.equalTo(titleLabel.snp.centerY)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.text = "Email Cleaner"
label.font = UIFont.systemFont(ofSize: 20, weight: .bold)
label.textColor = .black
label.textAlignment = .left
addSubview(label)
return label
}()
private lazy var settingsButton: UIButton = {
let button = UIButton(type: .custom)
button.clipsToBounds = true
button.setImage(UIImage(named: "ic_switch_email"), for: .normal)
button.addTarget(self, action: #selector(filter), for: .touchUpInside)
addSubview(button)
return button
}()
@objc private func filter() -> Void {
callblock()
}
}
//
// EmailContentBottonAction.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import UIKit
class EmailContentBottonAction: UIView {
enum ActionState:Int {
case EmailGroup = 0
case EmailList = 1
}
var callblock = {}
var state:ActionState = .EmailGroup
var numberMails:Int = 0 {
didSet {
DelEmailBtn.setTitle(btnTitle(), for: .normal)
DelEmailBtn.isEnabled = numberMails > 0
}
}
@objc private func delMails() -> Void {
callblock()
}
private func setup() -> Void {
DelEmailBtn.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(marginLR)
make.height.equalTo(46)
make.top.equalToSuperview().offset(12)
}
if state == .EmailGroup {
DelEmailBtn.setBackgroundImage(UIImage.Clear(UIColor(hex: "#7FC0FF") ?? .clear), for: .disabled)
DelEmailBtn.setBackgroundImage(UIImage.Clear(UIColor(hex: "#0082FF") ?? .clear), for: .normal)
}else{
DelEmailBtn.setBackgroundImage(UIImage.Clear(UIColor(hex: "#F5A2A2") ?? .clear), for: .disabled)
DelEmailBtn.setBackgroundImage(UIImage.Clear(UIColor(hex: "#EB4545") ?? .clear), for: .normal)
}
}
convenience init(state:ActionState) {
self.init(frame: CGRect())
self.state = state
setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
private lazy var DelEmailBtn: UIButton = {
let emailLogin = UIButton(type: .custom)
emailLogin.setImage(UIImage(named: "ic_delete_duplicates"), for: .normal)
emailLogin.setTitle(btnTitle(), for: .normal)
emailLogin.setTitleColor(.white, for: .normal)
emailLogin.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
emailLogin.layer.cornerRadius = 46/2.0
emailLogin.clipsToBounds = true
emailLogin.addTarget(self, action: #selector(delMails), for: .touchUpInside)
emailLogin.titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 0)
emailLogin.setBackgroundImage(UIImage.Clear(UIColor(hex: "#7FC0FF") ?? .clear), for: .disabled)
emailLogin.setBackgroundImage(UIImage.Clear(UIColor(hex: "#0082FF") ?? .clear), for: .normal)
addSubview(emailLogin)
return emailLogin
}()
private func btnTitle() -> String {
return "Delete \(numberMails) Mails"
}
}
//
// EmailContentView.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import UIKit
class EmailContentView: UIView {
var parent:UIViewController?
var mailset = NSMutableSet()
private func setup() -> Void {
topItem.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.top.equalTo(self.snp.top).offset(0)
make.height.equalTo(60)
}
tableView.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.bottom.equalTo(botAction.snp.top)
make.top.equalTo(topItem.snp.bottom)
}
botAction.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
make.height.equalTo(52 + (cWindow?.safeAreaInsets.bottom ?? 0) + 24 )
}
}
convenience init( _ parent:UIViewController) {
self.init(frame: CGRect())
self.parent = parent
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
private lazy var topItem: EmailCleanTopView = {
let item = EmailCleanTopView()
addSubview(item)
item.callblock = { [weak self] in
guard let self = self else { return }
let vc = EmailFilterController()
UIViewController.topMostViewController()?.navigationController?.pushViewController(vc, animated: true)
}
return item
}()
private lazy var tableView: UITableView = {
let tab = UITableView(frame: CGRectZero, style: .plain)
tab.delegate = self;
tab.dataSource = self
tab.separatorStyle = .none
tab.separatorInset = UIEdgeInsets()
tab.rowHeight = 74 + 12
tab.sectionHeaderHeight = 40 + 12
tab.register(UINib(nibName: EmailContentTabCell.id, bundle: nil), forCellReuseIdentifier: EmailContentTabCell.id)
if #available(iOS 15.0, *) {
tab.sectionHeaderTopPadding = 0
}
addSubview(tab)
return tab
}()
private lazy var botAction: EmailContentBottonAction = {
let bot = EmailContentBottonAction(state: .EmailGroup)
bot.clipsToBounds = false
addSubview(bot)
bot.numberMails = 0
bot.callblock = { [weak self] in
guard let self = self else { return }
let alert = EmailContentDelAlert(state: .group)
alert.callblock = { idx in
}
alert.show()
}
return bot
}()
}
extension EmailContentView :UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: EmailContentTabCell.id, for: indexPath) as! EmailContentTabCell
cell.selectionStyle = .none
cell.selectBtn.isSelected = self.mailset.contains(indexPath.row)
cell.callblock = {[weak self] in
guard let self = self else { return }
if self.mailset.contains(indexPath.row) {
self.mailset.remove(indexPath.row)
}else{
self.mailset.add(indexPath.row)
}
self.botAction.numberMails = self.mailset.count
tableView.reloadData()
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = EmailCleanListController()
parent?.navigationController?.pushViewController(vc, animated: true)
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = UIView()
header.backgroundColor = .white
let headerT = UILabel()
headerT.text = "Cleans the mails in the categories you choose,according to the filters you applied."
headerT.numberOfLines = 0
headerT.font = UIFont.systemFont(ofSize: 14)
headerT.textColor = UIColor(hex: "#333333")
headerT.numberOfLines = 0
header.addSubview(headerT)
headerT.snp.makeConstraints { make in
make.left.right.top.equalToSuperview().inset(UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15))
}
return header
}
}
//
// EmailEmptyView.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
//
import UIKit
class EmailEmptyView: UIView {
var callblock:(()->Void) = {}
@objc private func loginAction() -> Void {
callblock()
}
//FIXME: 差个链接
@objc private func PrivacyPolicy(_ ges:UIGestureRecognizer) -> Void {
let touch = ges.location(in: descpLabel)
let content = CGRectMake((descpLabel.width - 100) / 2.0, descpLabel.height - 25, 100, 25)
if CGRectContainsPoint(content, touch) {
let web = BaseWebViewController()
web.LoadWithUrl(url: "")
UIViewController.topMostViewController()?.navigationController?.pushViewController(web, animated: true)
}
}
private func setup() -> Void {
emptystack.addArrangedSubview(icon)
emptystack.addArrangedSubview(descpLabel)
emptystack.addArrangedSubview(signEmail)
emptystack.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(30)
make.centerY.equalToSuperview().offset(-30.RH())
}
signEmail.snp.makeConstraints { make in
make.height.equalTo(50)
make.width.equalToSuperview()
}
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
private lazy var emptystack: UIStackView = {
let stack = UIStackView()
stack.axis = .vertical
stack.spacing = 50
stack.alignment = .center
stack.distribution = .equalSpacing
addSubview(stack)
return stack
}()
private lazy var icon: UIImageView = {
let icon = UIImageView(image: UIImage(named: "img_email"))
icon.contentMode = .scaleAspectFill
return icon
}()
private lazy var descpLabel: UILabel = {
let l = UILabel()
l.textAlignment = .center
l.numberOfLines = 0
l.textColor = UIColor(hex: "#666666")
l.font = UIFont.systemFont(ofSize: 14)
let attrString = NSMutableAttributedString(string: "Cleans the mails in the categories you choose,according to the filters you apply. Your Gmail account and password is not stored in our app and Gmail secures the process.\nPrivacy Policy")
let strSubAttr2: [NSMutableAttributedString.Key: Any] = [.foregroundColor: UIColor(hex: "#0082FF") ?? .clear, .underlineStyle: NSUnderlineStyle.single.rawValue, .underlineColor: UIColor(hex: "#0082FF") ?? .clear]
attrString.addAttributes(strSubAttr2, range: NSRange(location: 170, length: 14))
l.attributedText = attrString
l.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(PrivacyPolicy(_:)))
l.addGestureRecognizer(tap)
return l
}()
private lazy var signEmail: UIButton = {
let emailLogin = UIButton(type: .custom)
emailLogin.setImage(UIImage(named: "emailSmall"), for: .normal)
emailLogin.setTitle("Sign in with Google", for: .normal)
emailLogin.setTitleColor(.white, for: .normal)
emailLogin.titleLabel?.font = UIFont.systemFont(ofSize: 16)
emailLogin.backgroundColor = UIColor(hex: "#0082FF")
emailLogin.layer.cornerRadius = 50/2.0
emailLogin.addTarget(self, action: #selector(loginAction), for: .touchUpInside)
emailLogin.titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 0)
return emailLogin
}()
}
//
// PMScaleImageView.swift
// PhoneManager
//
// Created by edy on 2025/5/7.
//
import UIKit
class PMScaleImageView: UIView , UIScrollViewDelegate {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setup()
}
var icon:UIImage? {
didSet {
showImg.image = icon
DispatchQueue.main.asyncAfter(deadline: .now()+0.1, execute: {
let size = self.icon?.size ?? CGSize()
// self.showImg.snp.remakeConstraints({ make in
// make.size.equalTo(size)
// })
// self.layoutIfNeeded()
// self.showImg.center = CGPoint(x: self.scroll.width/2.0, y: self.scroll.height/2.0)
})
}
}
private func setup() -> Void {
scroll.snp.makeConstraints { make in
make.left.right.bottom.top.equalToSuperview()
}
showImg.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.width.height.equalToSuperview()
}
}
private lazy var showImg: UIImageView = {
let iv = UIImageView()
iv.contentMode = .center
scroll.addSubview(iv)
return iv
}()
private lazy var scroll: UIScrollView = {
let scroll = UIScrollView()
scroll.delegate = self
scroll.showsVerticalScrollIndicator = false
scroll.showsHorizontalScrollIndicator = false
scroll.minimumZoomScale = 1.0
scroll.maximumZoomScale = 3.0
addSubview(scroll)
return scroll
}()
func scrollViewDidZoom(_ scrollView: UIScrollView) {
Print(scrollView.zoomScale)
if scrollView.zoomScale > 1.5 {
self.Radius = 16
}else{
self.Radius = 0
}
}
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return showImg
}
}
......@@ -30,7 +30,6 @@ extension UIView {
}
func cornerCut(radius:CGFloat,corner:UIRectCorner){
let maskPath = UIBezierPath.init(roundedRect: bounds, byRoundingCorners: corner, cornerRadii: CGSize.init(width: radius, height: radius))
let maskLayer = CAShapeLayer()
maskLayer.frame = bounds
......
......@@ -2,10 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSContactsUsageDescription</key>
<string>Phone Manager needs access to your contacts to find and merge duplicate contacts</string>
<key>NSUserTrackingUsageDescription</key>
<string>We need your permission to track your usage habits in order to provide a more personalized advertising experience</string>
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-3940256099942544~1458002511</string>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
......@@ -18,15 +16,10 @@
<string>ChargeShowIntent</string>
<string>LaunchAppIntent</string>
</array>
<key>NSWidgetUsageDescription</key>
<string>Need to access device data to provide real-time information</string>
<key>PHPhotoLibraryPreventAutomaticLimitedAccessAlert</key>
<true/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
</dict>
<key>GADApplicationIdentifier</key>
<string>ca-app-pub-3940256099942544~1458002511</string>
<key>SKAdNetworkItems</key>
<array>
<dict>
......@@ -226,6 +219,11 @@
<string>3qcr597p9d.skadnetwork</string>
</dict>
</array>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
</dict>
<key>UIBackgroundModes</key>
<array>
<string>processing</string>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment