Commit b3db5b71 authored by shenyong's avatar shenyong

Merge branch 'develop_0409' into Adv_NewClean

parents 3349dd14 7550e2e4
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "pm_battery_widgets_blue.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "pm_battery_widgets_blue@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "pm_battery_widgets_blue@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "pm_battery_widgets_small.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "pm_battery_widgets_small@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "pm_battery_widgets_small@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "pm_storage_widgets_blue.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "pm_storage_widgets_blue@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "pm_storage_widgets_blue@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "pm_storage_widgets_small.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "pm_storage_widgets_small@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "pm_storage_widgets_small@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
<?xml version="1.0" encoding="UTF-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>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.widgetkit-extension</string>
</dict>
</dict>
</plist>
//
// LockSreen.swift
// LockSreen
//
// Created by edy on 2025/5/12.
//
import WidgetKit
import SwiftUI
struct lockEmpty:View {
var body: some View {
ZStack(content: { })
}
}
// 正方形
struct LockSreenSquareView : View {
var entry:LockSreenProvider.Entry
var type:lockSreenType = lockSreenType()
var body: some View {
GeometryReader(content: { geometry in
let width = min(geometry.size.width, geometry.size.height)
ZStack {
let img = (type.isStorage ? "pm_storage_widgets_blue" : "pm_battery_widgets_blue")
let degree = (type.isStorage ? Double(entry.widgetUseSpace)/Double(entry.widgetAllSpace) * 360.0 : Double(entry.widgetBattery))
Image(img, bundle: nil).aspectRatio(contentMode: .fill)
lockArcShape(startAngle: .degrees(-90), endAngle:.degrees(degree-90)).stroke(style: StrokeStyle(lineWidth: 4, lineCap: .round))
}.frame(width: width, height: width)
})
}
}
// 长方形
struct LockSreenRectView : View {
var entry:LockSreenProvider.Entry
var type:lockSreenType = lockSreenType()
var body: some View {
let use = (Double(entry.widgetUseSpace)/Double(entry.widgetAllSpace))
HStack(content: {
VStack(spacing: 10, content: {
let name = type.isStorage ? "Storage" : "Battery"
let use = type.isStorage ? String("\(Int(use*100))%") : String("\(entry.widgetBattery)%")
let descp = type.isStorage ? String(" \(entry.widgetUseSpace)/\(entry.widgetAllSpace)GB") : entry.isCharging ? "Charging" : "No action"
VStack(spacing: 2, content: {
Text(name).font(.system(size: 12)).frame(maxWidth: .infinity,alignment:.leading)
Text(use).frame(maxWidth: .infinity, alignment: .leading).font(.system(size: 16,weight: .bold))
})
Text(descp).font(.system(size: 10)).frame(maxWidth: .infinity, alignment: .leading)
})
ZStack {
let img = (type.isStorage ? "pm_storage_widgets_blue" : "pm_battery_widgets_blue")
let degree = (type.isStorage ? Double(entry.widgetUseSpace)/Double(entry.widgetAllSpace) * 360 : Double(entry.widgetBattery))
Image(img, bundle: nil).aspectRatio(contentMode: .fill)
lockArcShape(startAngle: .degrees(-90), endAngle: .degrees( degree-90)).stroke(style: StrokeStyle(lineWidth: 4, lineCap: .round))
}
})
}
}
// 二者长方形
struct LockSreenBothView : View {
var entry:LockSreenProvider.Entry
var body: some View {
let use = (Double(entry.widgetUseSpace)/Double(entry.widgetAllSpace))
VStack(content: {
HStack(spacing: 5, content: {
Image("pm_battery_widgets_small")
Text("Battery").frame(maxWidth: .infinity, alignment: .leading).font(.system(size: 12,weight: .regular))
Text(String("\(entry.widgetBattery)%")).font(.system(size: 12,weight: .medium))
})
HStack(spacing: 3, content: {
Image("pm_storage_widgets_small")
Text("Storage").frame(maxWidth: .infinity, alignment: .leading).font(.system(size: 12,weight: .regular))
Text(String("\(Int(use*100))%")).font(.system(size: 12,weight: .medium))
})
})
.padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
}
}
struct LockSreenEntryView : View {
var type:lockSreenType = lockSreenType()
var entry: LockSreenProvider.Entry
@Environment(\.widgetFamily) var family
var body: some View {
switch family {
case .accessoryCircular:
LockSreenSquareView(entry: entry ,type: type)
case .accessoryRectangular:
LockSreenRectView(entry: entry ,type: type)
default:
lockEmpty()
}
}
}
// 圆孤
struct lockArcShape: Shape {
var startAngle: Angle
var endAngle: Angle
func path(in rect: CGRect) -> Path {
var path = Path()
let center = CGPoint(x: rect.midX, y: rect.midY)
let radius = min(rect.width, rect.height) / 2.0 - 2
path.addArc(
center: center,
radius: radius,
startAngle: startAngle,
endAngle: endAngle,
clockwise: false
)
return path
}
}
//
// LockSreenBundle.swift
// LockSreen
//
// Created by edy on 2025/5/12.
//
import WidgetKit
import SwiftUI
let kind: String = "LockSreen"
let kind1: String = "LockSreen1"
@main
struct LockSreenBundle: WidgetBundle {
var body: some Widget {
LockStorageSreen(type: lockSreenType(isStorage: true, kind: kind, displayName: "Storage", description: "Monitor your storage space"))
LockStorageSreen(type: lockSreenType(kind: kind1, displayName: "Battery", description: "Monitor your battery"))
LockBothSreen()
}
}
struct LockStorageSreen: Widget {
var type:lockSreenType = lockSreenType()
var body: some WidgetConfiguration {
StaticConfiguration(kind: type.kind, provider: LockSreenProvider()) { entry in
if #available(iOS 17.0, *) {
LockSreenEntryView(type: type, entry: entry)
.containerBackground(.fill.tertiary, for: .widget)
} else {
LockSreenEntryView(type: type, entry: entry)
.padding()
.background(Color.clear)
}
}
.configurationDisplayName(type.displayName)
.description(type.description)
.supportedFamilies([.accessoryCircular,.accessoryRectangular])
}
}
struct LockBothSreen: Widget {
let kind: String = "LockSreenBoth"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: LockSreenProvider()) { entry in
if #available(iOS 17.0, *) {
LockSreenBothView(entry: entry)
.containerBackground(.fill.tertiary, for: .widget)
} else {
LockSreenBothView(entry: entry)
.background(Color.clear)
}
}
.configurationDisplayName("Both")
.description("Monitor your battery and storage space")
.supportedFamilies([.accessoryRectangular])
}
}
//
// LockSreenModel.swift
// widget
//
// Created by Flower on 2025/5/10.
//
import WidgetKit
import SwiftUI
struct LockSreenProvider: TimelineProvider {
func placeholder(in context: Context) -> LockSreenEntry {
LockSreenEntry(date: .now, widgets: 0, widgetBattery: 0, widgetStorage: 0, widgetAllSpace: 0, widgetUseSpace: 0, batteryState: "Off", isCharging: false)
}
func getSnapshot(in context: Context, completion: @escaping (LockSreenEntry) -> ()) {
let entry = LockSreenEntry(date: .now, widgets: 0, widgetBattery: 0, widgetStorage: 0, widgetAllSpace: 0, widgetUseSpace: 0, batteryState: "Off", isCharging: false)
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<LockSreenEntry>) -> ()) {
let entry = loadSharedData()
let timeline = Timeline(entries: [entry], policy: .after(Date().addingTimeInterval(60)))
completion(timeline)
}
private func loadSharedData() -> LockSreenEntry {
guard let sharedDefaults = UserDefaults(suiteName: "group.com.app.phonemanager"),
let data:Data = sharedDefaults.object(forKey: "widgetSharedData") as? Data,
let decodedData = try? JSONDecoder().decode(WidgetData.self, from: data)
else {
return LockSreenEntry(date: Date(), widgets: 0, widgetBattery: 0, widgetStorage: 0 ,widgetAllSpace: 0 ,widgetUseSpace: 0 ,batteryState: "Off" , isCharging: false)
}
return LockSreenEntry(date: Date(), widgets: decodedData.widget, widgetBattery: decodedData.battery, widgetStorage: decodedData.widgetStorage,widgetAllSpace: decodedData.AllSpace,widgetUseSpace: decodedData.UseSpace ,batteryState: decodedData.batteryState ,isCharging: decodedData.isCharging)
}
}
struct WidgetData: Codable {
var userId: String
var widget: Int
var battery: Int
var widgetStorage: Int
var AllSpace: Int
var UseSpace: Int
let batteryState: String
let isCharging: Bool
}
struct LockSreenEntry: TimelineEntry {
let date: Date
var widgets:Int
let widgetBattery:Int
let widgetStorage:Int
let widgetAllSpace:Int
let widgetUseSpace:Int
let batteryState: String // 是否低电量模式
let isCharging: Bool // 是否在充电
}
// 单一
struct lockSreenType {
var type:Int = 0 // 正方形 长方形
var isStorage:Bool = false // 是否是存储
var kind:String = ""
var displayName:String = ""
var description:String = ""
}
<?xml version="1.0" encoding="UTF-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>com.apple.security.application-groups</key>
<array>
<string>group.com.app.phonemanager</string>
</array>
</dict>
</plist>
This diff is collapsed.
......@@ -10,6 +10,7 @@ import AppIntents
import Photos
import GoogleMobileAds
import UserMessagingPlatform
import GoogleSignIn
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
......@@ -45,6 +46,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// 初始化广告SDK
AdvManager.shared.initAdertisementSDK()
PMEmailManager.shareManager.restore()
PhotoManager.shared.config()
......@@ -337,7 +339,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}
func application(
_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
return GIDSignIn.sharedInstance.handle(url)
}
}
{
"images" : [
{
"filename" : "Group_1171275119.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Group_1171275119@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Group_1171275119@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Group_1171275120.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Group_1171275120@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Group_1171275120@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "image_76.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "image_76@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "image_76@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "img_phone_battery_02.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "img_phone_battery_02@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "img_phone_battery_02@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "ic_ok_duolicates.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "ic_ok_duolicates@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "ic_ok_duolicates@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "icon_close.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "icon_close@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "icon_close@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Frame.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Frame.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{
"images" : [
{
"filename" : "Frame_1171276289.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Frame_1171276289@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Frame_1171276289@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
......@@ -12,7 +12,7 @@ class ChargeGuideController : BaseViewController,UIScrollViewDelegate,UINavigati
let imageString : [String] = [
"img_phone_battery_02",
"img_phone_battery_02 1",
"img_phone_battery_03",
"img_phone_battery_04",
"img_phone_battery_05",
......
......@@ -13,7 +13,7 @@ class ChargeGuideStartController : BaseViewController {
lazy var backView : UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "img_bj_battery")
view.image = UIImage(named: "image_76")
return view
}()
......@@ -40,7 +40,7 @@ class ChargeGuideStartController : BaseViewController {
lazy var chargeView : UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "img_phone_battery_01")
view.image = UIImage(named: "Group_1171275119")
return view
}()
......@@ -96,15 +96,15 @@ class ChargeGuideStartController : BaseViewController {
self.startButton.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.right.equalToSuperview().offset(-15)
make.top.equalTo(self.chargeView.snp.bottom)
make.bottom.equalToSuperview().offset(-safeHeight-37)
make.height.equalTo(50)
}
self.chargeView.snp.makeConstraints { make in
make.top.equalTo(self.detailTipTitleLabel.snp.bottom).offset(42)
make.height.equalTo(476)
make.left.equalToSuperview().offset(27)
make.right.equalToSuperview().offset(-26)
make.top.equalTo(self.detailTipTitleLabel.snp.bottom).offset(32)
make.height.equalTo(453.5 * RScreenH())
make.width.equalTo(345 * RScreenH())
make.centerX.equalToSuperview()
}
self.closeButton.snp.makeConstraints { make in
......
......@@ -12,7 +12,7 @@ class ChargeGuideEndView : UIView{
lazy var backView : UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "img_bj_battery")
view.image = UIImage(named: "image_76")
return view
}()
......@@ -39,7 +39,7 @@ class ChargeGuideEndView : UIView{
lazy var chargeView : UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "img_phone_battery_08")
view.image = UIImage(named: "Group_1171275120")
return view
}()
......@@ -88,15 +88,15 @@ class ChargeGuideEndView : UIView{
self.startButton.snp.makeConstraints { make in
make.left.equalToSuperview().offset(15)
make.right.equalToSuperview().offset(-15)
make.top.equalTo(self.chargeView.snp.bottom).offset(66)
make.bottom.equalToSuperview().offset(-safeHeight-37)
make.height.equalTo(50)
}
self.chargeView.snp.makeConstraints { make in
make.top.equalTo(self.detailTipTitleLabel.snp.bottom).offset(42)
make.height.equalTo(352)
make.left.equalToSuperview().offset(27)
make.right.equalToSuperview().offset(-26)
make.height.equalTo(445 * RScreenH())
make.width.equalTo(338 * RScreenH())
make.centerX.equalToSuperview()
}
}
......
......@@ -15,7 +15,7 @@ class ChargeGuideNormalView : UIView{
lazy var backView : UIImageView = {
let view = UIImageView()
view.image = UIImage(named: "img_bj_battery")
view.image = UIImage(named: "image_76")
return view
}()
......
......@@ -62,8 +62,7 @@ class HomeViewController:BaseViewController {
case 3 :
DispatchQueue.main.async {[weak self] in
guard let self else {return}
//FIXME: 是否登录了谷歌邮箱
if false {
if PMEmailManager.shareManager.loginUser != nil {
let vc:EmailCleanController = EmailCleanController()
self.navigationController?.pushViewController(vc, animated: true)
}else{
......
//
// DateSelectButtonView.swift
// PhoneManager
//
// Created by edy on 2025/5/12.
//
import Foundation
class DateSelectButtonView : UIView {
var type : PikerDateType?
lazy var dateButton : UIButton = {
let button = UIButton(type: .custom)
button.setTitle("Start date", for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .semibold)
button.setTitleColor(UIColor(red: 0.07, green: 0.07, blue: 0.07, alpha: 1), for: .normal)
button.backgroundColor = UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 1)
button.layer.borderColor = UIColor(red: 0.96, green: 0.96, blue: 0.96, alpha: 1).cgColor
button.layer.borderWidth = 1.0
button.layer.cornerRadius = 21
button.clipsToBounds = true
return button
}()
lazy var closeButton : UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "ic_close_charging"), for: .normal)
button.addTarget(self, action: #selector(closeButtonAction), for: .touchUpInside)
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(dateButton)
self.addSubview(closeButton)
self.dateButton.snp.makeConstraints { make in
make.left.bottom.right.equalToSuperview()
make.top.equalToSuperview().offset(4)
}
self.closeButton.snp.makeConstraints { make in
make.width.height.equalTo(16)
make.top.equalToSuperview()
make.right.equalToSuperview().offset(-5)
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc func closeButtonAction(){
reSetButtonTitle()
}
func reSetButtonTitle() {
DispatchQueue.main.async {
let title = self.type == .start ? "Start date" : "Over date"
self.dateButton.setTitle(title, for: .normal)
self.closeButton.isHidden = true
}
}
}
......@@ -42,10 +42,19 @@ class HomeInfoView :UIView {
lazy var headerView:HomeInfoTitleView = {
let sview:HomeInfoTitleView = HomeInfoTitleView(frame: CGRect(x: 0, y: 0, width: width, height: 84))
sview.titleLabel.text = self.titleText
sview.filterButton.isHidden = self.type != .similar
tableView.addSubview(sview)
return sview
}()
lazy var nextRowButton : UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "Frame_1171276289"), for: .normal)
button.backgroundColor = .clear
button.addTarget(self, action: #selector(nextRowButtonAction), for: .touchUpInside)
return button
}()
lazy var deleteView:HomeInfoDeleteView = {
let cH:CGFloat = 48 + 2 * marginLR + safeHeight
......@@ -101,6 +110,38 @@ class HomeInfoView :UIView {
super.init(frame: frame)
setupUI()
self.headerView.sortViewSubmitCallBack = {[weak self]filterModel in
guard let self else {return}
// 从源头获取相似数据
PhotoDataManager.manager.loadFromFileSystem(resultModel: {[weak self] model in
guard let self else {return}
let tempData = self.filterDataByDate(orgModels: model.titleModelArray[1].assets, startDate: filterModel.startDate, endDate: filterModel.endDate)
// 重新更新下数据源
self.ids = self.sortData(source: tempData, type: filterModel.sortType)
var tempModels : [HomeInfoTableItem] = []
for array in self.ids ?? [] {
var smodels:[ImageSeletedCollectionItem] = []
for id in array {
let smodel = ImageSeletedCollectionItem()
smodel.id = id
smodel.isSeleted = false
smodels.append(smodel)
}
let smodel = HomeInfoTableItem()
smodel.type = type
smodel.smodels = smodels
smodel.titleText = titleText
tempModels.append(smodel)
}
models = tempModels
DispatchQueue.main.async {
// FIXME: 闪屏
self.tableView.reloadSections(IndexSet(integer: 0), with: .automatic)
}
})
}
}
required init?(coder: NSCoder) {
......@@ -116,6 +157,15 @@ class HomeInfoView :UIView {
self.addSubview(tableView)
self.addSubview(deleteView)
self.addSubview(self.nextRowButton)
self.nextRowButton.snp.makeConstraints { make in
make.bottom.equalToSuperview().offset(-safeHeight - 106)
make.right.equalToSuperview().offset(-16)
make.height.equalTo(38)
make.width.equalTo(24)
}
}
func changeValue() {
......@@ -253,6 +303,26 @@ class HomeInfoView :UIView {
extension HomeInfoView:UITableViewDataSource,UITableViewDelegate {
@objc func nextRowButtonAction(){
self.tableScrollToNextRow()
}
/// 让表格自动滚动一行
private func tableScrollToNextRow(){
if let indexPath = tableView.indexPathsForVisibleRows?.first {
// 计算下一行的索引
let nextRow = indexPath.row + 1
let nextSection = indexPath.section
// 检查下一行是否存在
if nextRow < tableView.numberOfRows(inSection: nextSection) {
let nextIndexPath = IndexPath(row: nextRow, section: nextSection)
// 滚动到下一行
tableView.scrollToRow(at: nextIndexPath, at: .top, animated: true)
}
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let OffsetY = scrollView.contentOffset.y
let top = CGRectGetMaxY(self.headerView.titleLabel.frame) + 8
......@@ -275,6 +345,7 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: HomeInfoTableViewCell.identifier, for: indexPath) as! HomeInfoTableViewCell
cell.type = self.type
cell.model = models[indexPath.row]
......@@ -303,10 +374,62 @@ extension HomeInfoView:UITableViewDataSource,UITableViewDelegate {
return UIView()
}
func filterDataByDate(orgModels : [[AssetModel]], startDate:Date? ,endDate : Date?)->[[AssetModel]]{
var tempArray : [[AssetModel]] = []
for item in orgModels {
var array = item
if startDate != nil {
array = array.filter({$0.createDate > startDate!})
}
if endDate != nil {
array = array.filter({$0.createDate < endDate!})
}
if array.count > 2 {
tempArray.append(item)
}
}
return tempArray
}
func sortData(source: [[AssetModel]], type: ResouceSortType) -> [[AssetModel]] {
switch type {
case .largest:
return source.sorted { subArray1, subArray2 in
let sum1 = subArray1.reduce(0) { $0 + $1.assetSize }
let sum2 = subArray2.reduce(0) { $0 + $1.assetSize }
return sum1 > sum2
}
case .smallest:
return source.sorted { subArray1, subArray2 in
let sum1 = subArray1.reduce(0) { $0 + $1.assetSize }
let sum2 = subArray2.reduce(0) { $0 + $1.assetSize }
return sum1 < sum2
}
case .latest:
return source.sorted { subArray1, subArray2 in
guard let max1 = subArray1.max(by: { $0.createDate < $1.createDate })?.createDate else { return false }
guard let max2 = subArray2.max(by: { $0.createDate < $1.createDate })?.createDate else { return true }
return max1 > max2
}
case .oldest:
return source.sorted { subArray1, subArray2 in
guard let min1 = subArray1.min(by: { $0.createDate < $1.createDate })?.createDate else { return false }
guard let min2 = subArray2.min(by: { $0.createDate < $1.createDate })?.createDate else { return true }
return min1 < min2
}
}
}
}
class HomeInfoTitleView:UIView {
var sortViewSubmitCallBack : (ResourceFilterBoxModel)->Void = {model in}
lazy var titleLabel:UILabel = {
let sview:UILabel = UILabel()
......@@ -333,6 +456,23 @@ class HomeInfoTitleView:UIView {
return sview
}()
// 筛选按钮
lazy var filterButton : UIButton = {
let button = UIButton(type: .custom)
button.setImage(UIImage(named: "Frame 1"), for: .normal)
button.setTitle("The largest", for: .normal)
button.layer.cornerRadius = 14
button.clipsToBounds = true
button.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 0.1000)
button.titleLabel?.font = UIFont.systemFont(ofSize: 12, weight: .semibold)
button.setTitleColor(UIColor(red: 0.07, green: 0.07, blue: 0.07, alpha: 1), for: .normal)
button.addTarget(self, action: #selector(filterButtonAction), for: .touchUpInside)
button.isHidden = true
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
......@@ -348,6 +488,15 @@ class HomeInfoTitleView:UIView {
backgroundColor = .white
addSubview(titleLabel)
addSubview(numberLabel)
addSubview(self.filterButton)
self.filterButton.snp.makeConstraints { make in
make.top.equalToSuperview().offset(35)
make.right.equalToSuperview().offset(-15)
make.height.equalTo(28)
make.width.equalTo(98)
}
}
func changeContent(title:String,allNumber:Int,seletedCount:Int) {
......@@ -381,6 +530,20 @@ class HomeInfoTitleView:UIView {
numberLabel.attributedText = attributedString2
numberLabel.y = height - numberLabel.height - 8
}
@objc func filterButtonAction(){
if let cWindow = cWindow {
let filterView : ResourceFilterBoxView = ResourceFilterBoxView.init(frame: cWindow.bounds)
cWindow.addSubview(filterView)
filterView.submitCallBack = {model in
DispatchQueue.main.async {
self.filterButton.setTitle(model.sortType.rawValue, for: .normal)
}
self.sortViewSubmitCallBack(model)
}
}
}
}
......@@ -437,5 +600,7 @@ class HomeInfoDeleteView:UIView {
callBack(OperStatus.delete)
}
}
This diff is collapsed.
//
// YearMonthPickerView.swift
// PhoneManager
//
// Created by edy on 2025/5/12.
//
import Foundation
enum PikerDateType {
case start
case end
}
class YearMonthPickerView: UIView {
var type : PikerDateType = .start
// MARK: - Properties
private var selectedYear: Int = 0
private var selectedMonth: Int = 0
var onCancel: (() -> Void)?
var onConfirm: ((_ type : PikerDateType,_ year: Int, _ month: Int) -> Void)?
private let pickerView: UIPickerView = {
let picker = UIPickerView()
picker.backgroundColor = .white
return picker
}()
private let years = Array(Array(Calendar.current.component(.year, from: Date())-30...Calendar.current.component(.year, from: Date())).reversed())
private lazy var months: [String] = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US")
return formatter.monthSymbols
}()
// MARK: - Initialization
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupView()
}
// MARK: - Setup
private func setupView() {
backgroundColor = .white
layer.cornerRadius = 12
layer.masksToBounds = true
// 按钮容器
let buttonContainer = UIView()
buttonContainer.backgroundColor = UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 1)
buttonContainer.translatesAutoresizingMaskIntoConstraints = false
// 取消按钮
let cancelButton = UIButton(type: .system)
cancelButton.setTitle("Cancel", for: .normal)
cancelButton.contentHorizontalAlignment = .left
cancelButton.addTarget(self, action: #selector(cancelAction), for: .touchUpInside)
cancelButton.translatesAutoresizingMaskIntoConstraints = false
cancelButton.setTitleColor(UIColor(red: 0.6, green: 0.6, blue: 0.6, alpha: 1), for: .normal)
cancelButton.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium)
// 确认按钮
let confirmButton = UIButton(type: .system)
confirmButton.setTitle("Completed", for: .normal)
confirmButton.contentHorizontalAlignment = .right
confirmButton.addTarget(self, action: #selector(confirmAction), for: .touchUpInside)
confirmButton.translatesAutoresizingMaskIntoConstraints = false
cancelButton.setTitleColor(UIColor(red: 0.07, green: 0.07, blue: 0.07, alpha: 1), for: .normal)
cancelButton.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .medium)
buttonContainer.addSubview(cancelButton)
buttonContainer.addSubview(confirmButton)
// 按钮容器约束
NSLayoutConstraint.activate([
buttonContainer.heightAnchor.constraint(equalToConstant: 42),
cancelButton.leadingAnchor.constraint(equalTo: buttonContainer.leadingAnchor, constant: 16),
cancelButton.centerYAnchor.constraint(equalTo: buttonContainer.centerYAnchor),
confirmButton.trailingAnchor.constraint(equalTo: buttonContainer.trailingAnchor, constant: -16),
confirmButton.centerYAnchor.constraint(equalTo: buttonContainer.centerYAnchor)
])
// 主布局
let stackView = UIStackView(arrangedSubviews: [buttonContainer, pickerView])
stackView.axis = .vertical
stackView.spacing = 0
stackView.translatesAutoresizingMaskIntoConstraints = false
addSubview(stackView)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: topAnchor),
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
stackView.bottomAnchor.constraint(equalTo: bottomAnchor)
])
pickerView.delegate = self
pickerView.dataSource = self
// 设置初始选择
let currentYear = Calendar.current.component(.year, from: Date())
let currentMonth = Calendar.current.component(.month, from: Date())
selectedYear = currentYear
selectedMonth = currentMonth - 1
if let yearIndex = years.firstIndex(of: currentYear) {
pickerView.selectRow(yearIndex, inComponent: 1, animated: false)
}
pickerView.tintColor = .red
pickerView.selectRow(currentMonth - 1, inComponent: 0, animated: false)
}
// MARK: - 按钮操作
@objc private func cancelAction() {
onCancel?()
}
@objc private func confirmAction() {
onConfirm?(self.type,selectedYear, selectedMonth + 1)
}
}
// MARK: - UIPickerView DataSource & Delegate
extension YearMonthPickerView: UIPickerViewDataSource, UIPickerViewDelegate {
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 2
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return component == 0 ? months.count : years.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return component == 0 ? months[row] : "\(years.reversed()[row])"
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if component == 0 {
selectedMonth = row
} else {
selectedYear = years.reversed()[row]
}
}
func pickerView(_ pickerView: UIPickerView, widthForComponent component: Int) -> CGFloat {
return component == 0 ? self.width/2 : self.width/2
}
}
......@@ -20,6 +20,8 @@ class HomeInfoTableViewCell:UITableViewCell {
private var seletedAllBtn:UIButton?
var type : PhotsFileType?
var callBack:callBack<Any> = {text in}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
......@@ -112,13 +114,30 @@ class HomeInfoTableViewCell:UITableViewCell {
collectionView?.x = (backView?.x ?? 0) + marginLR
collectionView?.y = (backView?.y ?? 0) + (backView?.height ?? 0) - (collectionView?.height ?? 0) - 16
UIView.transition(with: collectionView!, duration: 0.3, options: .transitionCrossDissolve, animations: {
self.collectionView?.reloadData()
// self.reloadCollectionView()
}, completion: nil)
}
}
// 重新刷新下集合
func reloadCollectionView(){
DispatchQueue.main.async {
if let collectionView = self.collectionView {
for section in 0..<collectionView.numberOfSections {
for item in 0..<collectionView.numberOfItems(inSection: section) {
UIView.transition(with:collectionView, duration: 0.3, options: .transitionCrossDissolve, animations: {
collectionView.reloadItems(at: [IndexPath(row: item, section: section)])
}, completion: nil)
}
}
}
}
}
@objc func seletedAllBtnClick() {
DispatchQueue.main.async {[weak self] in
......@@ -131,8 +150,8 @@ class HomeInfoTableViewCell:UITableViewCell {
seletedAllBtn?.centerY = numberLabel?.centerY ?? 0
seletedAllBtn?.x = (backView?.x ?? 0) + (backView?.width ?? 0) - 12 - (seletedAllBtn?.width ?? 0)
}
for (index,smodel) in (model?.smodels ?? []).enumerated() {
if index == 0 {
......@@ -195,6 +214,11 @@ extension HomeInfoTableViewCell:UICollectionViewDelegate,UICollectionViewDataSou
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ImageSeletedCollectionCell.identifiers, for: indexPath) as! ImageSeletedCollectionCell
// 显示保留按钮或者最佳匹配结果按钮
cell.allKeepButton.isHidden = indexPath.item != 0 || self.type == .duplicates
cell.bestResultButton.isHidden = indexPath.item != 0 || self.type == .duplicates
cell.model = model?.smodels?[indexPath.row]
cell.photsFileType = model?.type
......@@ -211,7 +235,7 @@ extension HomeInfoTableViewCell:UICollectionViewDelegate,UICollectionViewDataSou
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// 计算 cell 宽度
// 计算 cell 宽度
/*return CGSize(width:collectionView.height, height: collectionView.height) */ // 宽高相等,形成网格
return CGSize(width:collectionView.height, height: collectionView.height)
......
......@@ -19,6 +19,34 @@ class ImageSeletedCollectionCell:UICollectionViewCell {
var callBack:callBack<Any> = {text in}
lazy var allKeepButton : UIButton = {
let button = UIButton(type: .custom)
button.backgroundColor = UIColor(red: 0.33, green: 0.77, blue: 0.49, alpha: 1)
button.layer.cornerRadius = 7
button.clipsToBounds = true
button.setTitle( "All retained", for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 9, weight: .semibold)
button.addTarget(self, action: #selector(allKeepButtonAction), for: .touchUpInside)
button.isHidden = true
return button
}()
lazy var bestResultButton : UIButton = {
let button = UIButton(type: .custom)
button.layer.cornerRadius = 8
button.clipsToBounds = true
button.backgroundColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1)
button.setTitle( "Best result", for: .normal)
button.setImage(UIImage(named: "Frame"), for: .normal)
button.setTitleColor(.white, for: .normal)
button.isHidden = true
button.titleLabel?.font = UIFont.systemFont(ofSize: 10, weight: .semibold)
return button
}()
override init(frame: CGRect) {
super.init(frame: frame)
......@@ -132,9 +160,6 @@ class ImageSeletedCollectionCell:UICollectionViewCell {
self.backgroundColor = .clear
}
func addViews() {
......@@ -142,6 +167,22 @@ class ImageSeletedCollectionCell:UICollectionViewCell {
self.addSubview(backImageView!)
self.addSubview(seletedBtn!)
self.addSubview(self.extensionView)
self.addSubview(self.allKeepButton)
self.addSubview(self.bestResultButton)
self.allKeepButton.snp.makeConstraints { make in
make.top.left.equalToSuperview()
make.width.equalTo(58)
make.height.equalTo(14)
}
self.bestResultButton.snp.makeConstraints { make in
make.left.bottom.equalToSuperview()
make.width.equalTo(81)
make.height.equalTo(16)
}
}
@objc func seletedBtnClick() {
......@@ -178,3 +219,9 @@ class ImageSeletedCollectionCell:UICollectionViewCell {
}
extension ImageSeletedCollectionCell {
@objc func allKeepButtonAction(){
Print("点击了全部保留按钮")
}
}
//
// ResourceFilterBoxTableViewCell.swift
// PhoneManager
//
// Created by edy on 2025/5/12.
//
import Foundation
class ResourceFilterBoxTableViewCell : UITableViewCell {
var cellTag : Int = 0
var callBack : callBack<Any> = {cellTag in}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.selectionStyle = .none
self.contentView.addSubview(self.selectButton)
self.selectButton.snp.makeConstraints { make in
make.left.equalToSuperview().offset(0)
make.right.equalToSuperview().offset(0)
make.top.equalToSuperview().offset(7)
make.bottom.equalToSuperview().offset(-7)
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
lazy var selectButton : UIButton = {
let view = UIButton(type: UIButton.ButtonType.custom)
view.backgroundColor = UIColor(red: 0.95, green: 0.96, blue: 0.99, alpha: 1)
view.layer.cornerRadius = 12
view.clipsToBounds = true
view.setTitleColor(UIColor(red: 0.2, green: 0.2, blue: 0.2, alpha: 1), for: .normal)
view.addTarget(self, action: #selector(selectAction), for: .touchUpInside)
view.layer.borderColor = UIColor(red: 0, green: 0.51, blue: 1, alpha: 1).cgColor
return view
}()
@objc func selectAction(){
callBack(self.cellTag)
}
}
......@@ -17,30 +17,15 @@ class PMShowImgCell: UICollectionViewCell {
callblock()
}
var isCurrent:Bool = false {
didSet {
selectBtn.isSelected = isCurrent
}
}
var icon:UIImage = UIImage() {
didSet {
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)
// }
}
}
......@@ -54,8 +39,8 @@ class PMShowImgCell: UICollectionViewCell {
lazy var selectBtn: UIButton = {
let select = UIButton(type: .custom)
select.setImage(UIImage(named: ""), for: .normal)
select.setImage(UIImage(named: ""), for: .selected)
select.setImage(UIImage(named: "home_info_norl"), for: .normal)
select.setImage(UIImage(named: "home_info_seleted"), for: .selected)
select.addTarget(self, action: #selector(selectTap), for: .touchUpInside)
contentView.addSubview(select)
return select
......
......@@ -14,13 +14,7 @@ class PMShowItemCell: UICollectionViewCell {
var isCurrent:Bool = false {
didSet {
if isCurrent {
layer.borderColor = UIColor.colorWithHex(hexStr: "#0082FF").cgColor
layer.borderWidth = 4
}else{
layer.borderColor = UIColor.clear.cgColor
layer.borderWidth = 0
}
selectBtn.isSelected = isCurrent
}
}
......@@ -39,8 +33,8 @@ class PMShowItemCell: UICollectionViewCell {
private lazy var selectBtn: UIButton = {
let select = UIButton(type: .custom)
select.setImage(UIImage(named: ""), for: .normal)
select.setImage(UIImage(named: ""), for: .selected)
select.setImage(UIImage(named: "home_info_norl"), for: .normal)
select.setImage(UIImage(named: "home_info_seleted"), for: .selected)
contentView.addSubview(select)
select.isUserInteractionEnabled = false
return select
......
......@@ -137,11 +137,6 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
}
self.MaxCollection.reloadData()
collectionView.reloadData()
// if currentIdx != indexPath.row {
// currentIdx = indexPath.row
// MaxCollection.scrollToItem(at: indexPath, at: .left, animated: false)
// collectionView.reloadData()
// }
}
}
......@@ -177,6 +172,17 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
showName.loadPhotoOrVideo { durs, icon in
cell.icon = icon
}
cell.isCurrent = 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: PMShowVideoCellID, for: indexPath) as! PMShowVideoCell
......@@ -191,7 +197,7 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
cell.icon = icon
}
}
cell.isCurrent = (self.currentIdx == indexPath.row)
cell.isCurrent = selectSet.contains(indexPath.row)
return cell
}
}
......@@ -201,7 +207,7 @@ 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.isCurrent = selectSet.contains(indexPath.row)
cell.callblock = {[weak self] in
guard let self = self else { return }
if self.selectSet.contains(indexPath.row){
......@@ -246,7 +252,7 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
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)
cell.isCurrent = selectSet.contains(indexPath.row)
return cell
}
}
......@@ -259,10 +265,17 @@ extension PMShowImgVideoController : UICollectionViewDelegate,UICollectionViewDa
if collectionView == MaxCollection {
return collectionView.size
}
if indexPath.row < self.homeDataSource?.count ?? 0 {
return CGSize(width: 68, height: 68)
if state == .secret {
if indexPath.row < imageVideoPath.count {
return CGSize(width: 68, height: 68)
}
return CGSize(width: collectionView.width - 68, height: 68)
}else{
if indexPath.row < self.homeDataSource?.count ?? 0 {
return CGSize(width: 68, height: 68)
}
return CGSize(width: collectionView.width - 68, height: 68)
}
return CGSize(width: collectionView.width - 68, height: 68)
}
......
......@@ -60,10 +60,14 @@ func getSettingViewInfo() -> [SettingModel] {
[RowInfoModel(imageName: "ic_more_setting",title: "More Apps From Us")]),
SettingModel(sectionTitle: "UTILITIES",rowInfo:
[RowInfoModel(imageName: "ic_widgets_setting",title: "Widgets")]),
SettingModel(sectionTitle: "OTHERS",rowInfo:
[RowInfoModel(imageName: "ic_list_setting",title: "Keep List")]),
// SettingModel(sectionTitle: "SECRET SPACE",rowInfo: [
// RowInfoModel(imageName: "ic_pin_setting",title: "Use PIN")]),
SettingModel(sectionTitle: "STAY IN TOUCH",rowInfo:
[RowInfoModel(imageName: "ic_rate_setting",title: "Rate App"),
RowInfoModel(imageName: "ic_share_setting",title: "Share App"),
/*RowInfoModel(imageName: "ic_ins_setting",title: "Follow on Instagram")*/])]
/*RowInfoModel(imageName: "ic_ins_setting",title: "Follow on Instagram")*/]),
SettingModel(sectionTitle: "STAY IN TOUCH",rowInfo:
[RowInfoModel(imageName: "ic_email_setting",title: "Email support") ])]
}
......@@ -159,12 +159,35 @@ class SettingViewController : BaseViewController , UITableViewDelegate, UITableV
self.navigationController?.pushViewController(widget, animated: true)
break
case 3:
// 保留列表
break
case 4:
if indexPath.row == 0 { // 评分
self.review()
}else if indexPath.row == 1 { // 分享
self.PhoneShare()
}
break
case 5:
if indexPath.row == 0 { // 邮件登录和退出
if PMEmailManager.shareManager.loginUser != nil {
let alert = EmailContentDelAlert(state: .list)
alert.callblock = { idx in
if idx == 1 {
PMEmailManager.shareManager.signOut { success in
if success {
}
}
}
}
alert.show()
}else{
let vc:EmailLoginController = EmailLoginController()
vc.state = .set
self.navigationController?.pushViewController(vc, animated: true)
}
}
default:
break
}
......
//
// EmailFilterSelectCell.swift
// EmailFilterFAVORITECell.swift
// PhoneManager
//
// Created by edy on 2025/5/9.
// Created by edy on 2025/5/12.
//
import UIKit
class EmailFilterBaseCell: UITableViewCell {
class EmailFilterFAVORITECell: UITableViewCell {
static let id = "EmailFilterFAVORITECell"
@IBOutlet weak var titleL: UILabel!
var callblock:((Bool)->Void) = { select in}
@IBOutlet weak var emSwtich: UISwitch!
var top:Bool = false
var bot:Bool = false
......@@ -28,9 +34,10 @@ class EmailFilterBaseCell: UITableViewCell {
}
}
override func awakeFromNib() {
super.awakeFromNib()
@IBAction func selectActions(_ sender: UISwitch) {
// sender.isOn = !sender.isOn
callblock(sender.isOn)
}
@IBOutlet weak var titleL: UILabel!
}
......@@ -10,20 +10,20 @@
<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"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="KGk-i7-Jjw" customClass="EmailFilterFAVORITECell" customModule="PhoneManager" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="320" height="60"/>
<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"/>
<rect key="frame" x="0.0" y="0.0" width="320" height="60"/>
<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"/>
<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="Cz5-6m-Mah">
<rect key="frame" x="15" y="0.0" width="236" height="60"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="50" id="ByC-vP-p5G"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="60" id="q5h-W4-mcE"/>
</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"/>
<color key="textColor" red="0.20000001789999999" green="0.20000001789999999" blue="0.20000001789999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
......@@ -31,19 +31,33 @@
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="Z64-4z-Cnp">
<rect key="frame" x="256" y="14.666666666666664" width="51" height="31"/>
<constraints>
<constraint firstAttribute="height" constant="31" id="2yv-Iv-20a"/>
<constraint firstAttribute="width" constant="49" id="YS2-4n-lOj"/>
</constraints>
<connections>
<action selector="selectActions:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="nvW-EK-ui8"/>
</connections>
</switch>
</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"/>
<constraint firstItem="Cz5-6m-Mah" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="0Mq-J4-Xeq"/>
<constraint firstItem="Z64-4z-Cnp" firstAttribute="leading" secondItem="Cz5-6m-Mah" secondAttribute="trailing" constant="5" id="4nT-3I-qbv"/>
<constraint firstAttribute="bottom" secondItem="Cz5-6m-Mah" secondAttribute="bottom" id="M27-P5-Ro1"/>
<constraint firstItem="Cz5-6m-Mah" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" constant="15" id="NKG-qu-La9"/>
<constraint firstItem="Z64-4z-Cnp" firstAttribute="centerY" secondItem="H2p-sc-9uM" secondAttribute="centerY" id="tay-in-p1H"/>
<constraint firstAttribute="trailing" secondItem="Z64-4z-Cnp" secondAttribute="trailing" constant="15" id="ucO-vb-yyW"/>
</constraints>
</tableViewCellContentView>
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
<color key="backgroundColor" red="0.94901960784313721" green="0.96470588235294119" blue="0.9882352941176471" alpha="1" colorSpace="calibratedRGB"/>
<connections>
<outlet property="titleL" destination="bYm-Ap-ASH" id="mmr-1G-Kh5"/>
<outlet property="emSwtich" destination="Z64-4z-Cnp" id="Tqg-qK-SLh"/>
<outlet property="titleL" destination="Cz5-6m-Mah" id="tli-w9-h55"/>
</connections>
<point key="canvasLocation" x="104" y="-11"/>
<point key="canvasLocation" x="131" y="-12"/>
</tableViewCell>
</objects>
</document>
//
// EmailFilterKeywordCell.swift
// PhoneManager
//
// Created by edy on 2025/5/12.
//
import UIKit
class EmailFilterKeywordCell: UITableViewCell {
static let id = "EmailFilterKeywordCell"
@IBOutlet weak var kwTitleL: UILabel!
var callblock:((String,Bool)->Void) = { event, select in}
@IBOutlet weak var emSwitch: UISwitch!
override func awakeFromNib() {
super.awakeFromNib()
}
@IBAction func switchValueChange(_ sender: UISwitch) {
callblock("switch",sender.isOn)
}
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])
}
}
}
@IBAction func AddKeyWordActions(_ sender: Any) {
callblock("keyword",true)
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" rowHeight="144" id="KGk-i7-Jjw" customClass="EmailFilterKeywordCell" customModule="PhoneManager" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="456" height="144"/>
<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="456" height="144"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Hop-Ic-sfc">
<rect key="frame" x="0.0" y="0.0" width="456" height="84"/>
<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="AJp-c0-6Ib">
<rect key="frame" x="15" y="0.0" width="367" height="84"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="72" id="g5j-o3-20E"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="u6a-TR-UVD">
<rect key="frame" x="392" y="26.666666666666671" width="51" height="31"/>
<constraints>
<constraint firstAttribute="height" constant="31" id="55x-6W-qb7"/>
<constraint firstAttribute="width" constant="49" id="XoH-WD-4ln"/>
</constraints>
<connections>
<action selector="switchValueChange:" destination="KGk-i7-Jjw" eventType="valueChanged" id="EMy-ik-HnY"/>
</connections>
</switch>
</subviews>
<color key="backgroundColor" red="0.94901960784313721" green="0.96470588235294119" blue="0.9882352941176471" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="u6a-TR-UVD" firstAttribute="centerY" secondItem="Hop-Ic-sfc" secondAttribute="centerY" id="17f-0M-5Hj"/>
<constraint firstAttribute="trailing" secondItem="u6a-TR-UVD" secondAttribute="trailing" constant="15" id="2d2-f1-5AW"/>
<constraint firstItem="AJp-c0-6Ib" firstAttribute="leading" secondItem="Hop-Ic-sfc" secondAttribute="leading" constant="15" id="OUs-KH-rbZ"/>
<constraint firstAttribute="bottom" secondItem="AJp-c0-6Ib" secondAttribute="bottom" id="i5F-g5-TWS"/>
<constraint firstItem="u6a-TR-UVD" firstAttribute="leading" secondItem="AJp-c0-6Ib" secondAttribute="trailing" constant="10" id="i6F-Ji-r51"/>
<constraint firstItem="AJp-c0-6Ib" firstAttribute="top" secondItem="Hop-Ic-sfc" secondAttribute="top" id="l50-Us-I0B"/>
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="Radius">
<real key="value" value="12"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="AcA-F1-B4u">
<rect key="frame" x="0.0" y="99" width="136" height="45"/>
<color key="backgroundColor" red="0.94901960784313721" green="0.96470588235294119" blue="0.9882352941176471" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="height" constant="45" id="Xtx-DS-XGd"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<inset key="contentEdgeInsets" minX="10" minY="10" maxX="20" maxY="10"/>
<inset key="titleEdgeInsets" minX="5" minY="0.0" maxX="-5" maxY="0.0"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Add Keyword" image="icon_add">
<color key="titleColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="Radius">
<real key="value" value="8"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<action selector="AddKeyWordActions:" destination="KGk-i7-Jjw" eventType="touchUpInside" id="Y5I-Cr-UaT"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="Hop-Ic-sfc" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" id="8Bd-4Q-CmS"/>
<constraint firstAttribute="trailing" secondItem="Hop-Ic-sfc" secondAttribute="trailing" id="MvI-YU-exU"/>
<constraint firstAttribute="bottom" secondItem="AcA-F1-B4u" secondAttribute="bottom" id="cKw-Zm-qz0"/>
<constraint firstItem="AcA-F1-B4u" firstAttribute="top" secondItem="Hop-Ic-sfc" secondAttribute="bottom" constant="15" id="hCj-pu-5gm"/>
<constraint firstItem="AcA-F1-B4u" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" id="vUG-fw-GkT"/>
<constraint firstItem="Hop-Ic-sfc" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="vkW-OW-FZ3"/>
</constraints>
</tableViewCellContentView>
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
<connections>
<outlet property="emSwitch" destination="u6a-TR-UVD" id="GEj-db-Vul"/>
<outlet property="kwTitleL" destination="AJp-c0-6Ib" id="kqS-dt-JUz"/>
</connections>
<point key="canvasLocation" x="233.58778625954199" y="23.943661971830988"/>
</tableViewCell>
</objects>
<resources>
<image name="icon_add" width="20" height="20"/>
</resources>
</document>
......@@ -7,23 +7,37 @@
import UIKit
class EmailFilterSelectCell: EmailFilterBaseCell {
class EmailFilterSelectCell: UITableViewCell {
static let id = "EmailFilterSelectCell"
@IBOutlet weak var selectBtn: UIButton!
@IBOutlet weak var titleL: UILabel!
var callblock:((Bool)->Void) = { select in}
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)
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])
}
}
}
@IBAction func selectActions(_ sender: UIButton) {
sender.isSelected = !sender.isSelected
if sender.isSelected {
return
}
sender.isSelected = true
callblock(sender.isSelected)
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
//
// EmailKeyWordItemsCell.swift
// PhoneManager
//
// Created by edy on 2025/5/12.
//
import UIKit
class EmailKeyWordItemsCell: UITableViewCell {
static let id = "EmailKeyWordItemsCell"
@IBOutlet weak var EmailFilterKeywordCollection: UICollectionView!
@IBOutlet weak var collectionFlowLayout: EmailKeywordCollectionFlowLayout!
@IBOutlet weak var collectHeightConstraint: NSLayoutConstraint!
var callblock:(()->Void) = {}
var datasoure:[String] = []
override func awakeFromNib() {
super.awakeFromNib()
self.EmailFilterKeywordCollection.delegate = self
self.EmailFilterKeywordCollection.dataSource = self;
self.EmailFilterKeywordCollection.register(EmailKeywordCollectionCell.self, forCellWithReuseIdentifier: EmailKeywordCollectionCell.id)
self.collectionFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
}
func reload() -> Void {
self.layoutIfNeeded()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.reloadItems()
}
}
private func reloadItems() -> Void {
self.EmailFilterKeywordCollection.reloadData()
self.layoutIfNeeded()
DispatchQueue.main.asyncAfter(deadline: .now()+0.1, execute: {
Print("fefsfsfsf \(self.EmailFilterKeywordCollection.contentSize.height)")
let height = self.EmailFilterKeywordCollection.height
if self.datasoure.count > 0 {
self.collectHeightConstraint.constant = self.EmailFilterKeywordCollection.contentSize.height
}else{
self.collectHeightConstraint.constant = 0
}
if height != self.EmailFilterKeywordCollection.contentSize.height {
self.callblock()
}
})
}
}
extension EmailKeyWordItemsCell : UICollectionViewDataSource,UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return datasoure.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: EmailKeywordCollectionCell.id, for: indexPath) as! EmailKeywordCollectionCell
cell.titleL.text = datasoure[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
datasoure.remove(at: indexPath.row)
EmailFilterManager.share.keyword = datasoure
reloadItems()
self.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" rowHeight="96" id="KGk-i7-Jjw" customClass="EmailKeyWordItemsCell" customModule="PhoneManager" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="362" height="96"/>
<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="362" height="96"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<collectionView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" dataMode="none" translatesAutoresizingMaskIntoConstraints="NO" id="mE1-4I-UM9">
<rect key="frame" x="0.0" y="0.0" width="362" height="96"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" id="wh6-On-2nF"/>
</constraints>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="10" minimumInteritemSpacing="10" id="nsY-D4-rsQ" customClass="EmailKeywordCollectionFlowLayout" customModule="PhoneManager" customModuleProvider="target">
<size key="itemSize" width="128" height="128"/>
<size key="headerReferenceSize" width="0.0" height="0.0"/>
<size key="footerReferenceSize" width="0.0" height="0.0"/>
<inset key="sectionInset" minX="0.0" minY="0.0" maxX="0.0" maxY="0.0"/>
</collectionViewFlowLayout>
</collectionView>
</subviews>
<constraints>
<constraint firstItem="mE1-4I-UM9" firstAttribute="top" secondItem="H2p-sc-9uM" secondAttribute="top" id="67S-7k-7lw"/>
<constraint firstAttribute="trailing" secondItem="mE1-4I-UM9" secondAttribute="trailing" id="KsC-DY-CKi"/>
<constraint firstAttribute="bottom" secondItem="mE1-4I-UM9" secondAttribute="bottom" id="shZ-1J-L2E"/>
<constraint firstItem="mE1-4I-UM9" firstAttribute="leading" secondItem="H2p-sc-9uM" secondAttribute="leading" id="wM7-6Q-v1T"/>
</constraints>
</tableViewCellContentView>
<viewLayoutGuide key="safeArea" id="njF-e1-oar"/>
<connections>
<outlet property="EmailFilterKeywordCollection" destination="mE1-4I-UM9" id="gLL-fG-BEi"/>
<outlet property="collectHeightConstraint" destination="wh6-On-2nF" id="HHX-uQ-kyq"/>
<outlet property="collectionFlowLayout" destination="nsY-D4-rsQ" id="Mhl-0Z-vY8"/>
</connections>
<point key="canvasLocation" x="161.83206106870227" y="5.6338028169014089"/>
</tableViewCell>
</objects>
</document>
//
// EmailKeywordCollectionCell.swift
// PhoneManager
//
// Created by edy on 2025/5/12.
//
import UIKit
class EmailKeywordCollectionCell: UICollectionViewCell {
static let id = "EmailKeywordCollectionCell"
override init(frame: CGRect) {
super.init(frame: frame)
setuup()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setuup() -> Void {
content.snp.makeConstraints { make in
make.left.bottom.equalToSuperview()
make.top.equalToSuperview().offset(5)
make.right.equalTo(titleL.snp.right).offset(12)
}
titleL.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(12)
make.top.equalToSuperview().offset(17)
make.bottom.equalToSuperview().inset(10)
}
icon.snp.makeConstraints { make in
make.right.equalToSuperview().offset(3)
make.top.equalToSuperview()
}
DispatchQueue.main.async {
self.content.layer.borderColor = UIColor.colorWithHex(hexStr: "#B3B3B3").cgColor
self.content.layer.borderWidth = 0.5
self.content.layer.cornerRadius = 8
self.content.clipsToBounds = true
}
}
private lazy var content: UIView = {
let c = UIView()
c.backgroundColor = .clear
contentView.addSubview(c)
return c
}()
private lazy var icon: UIImageView = {
let v = UIImageView(image: UIImage(named: "icon_email_close"))
v.contentMode = .scaleAspectFill
contentView.addSubview(v)
return v
}()
lazy var titleL: UILabel = {
let l = UILabel()
contentView.addSubview(l)
l.font = UIFont.boldSystemFont(ofSize: 14)
l.textAlignment = .center
l.textColor = UIColor.colorWithHex(hexStr: "#333333")
return l
}()
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
let attributes = super.preferredLayoutAttributesFitting(layoutAttributes)
let strs:NSString = self.titleL.text as? NSString ?? ""
let frame = strs.boundingRect(with: CGSizeMake(ScreenW-15*2-29.0, .infinity), attributes: [NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 14)], context: nil)
let width = max(40, min(CGRectGetWidth(frame), ScreenW-15*2-29.0)) + 24.0
attributes.frame.size = contentView.systemLayoutSizeFitting(
CGSize(width: width, height: UIView.layoutFittingCompressedSize.height),
withHorizontalFittingPriority: .required,
verticalFittingPriority: .fittingSizeLevel
)
return attributes
}
}
//
// EmailKeywordCollectionFlowLayout.swift
// PhoneManager
//
// Created by edy on 2025/5/12.
//
import UIKit
class EmailKeywordCollectionFlowLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let attributes = super.layoutAttributesForElements(in: rect) else { return nil }
var leftMargin = sectionInset.left // 每行起始位置:ml-citation{ref="4,7" data="citationList"}
var currentY = CGFloat(-1)
return attributes.map { attr in
// 换行重置边距:ml-citation{ref="5" data="citationList"}
if attr.frame.origin.y != currentY {
leftMargin = sectionInset.left
currentY = attr.frame.origin.y
}
// 调整 X 坐标实现左对齐:ml-citation{ref="7" data="citationList"}
attr.frame.origin.x = leftMargin
leftMargin += attr.frame.width + minimumInteritemSpacing
return attr
}
}
}
......@@ -13,6 +13,7 @@ class EmailContentDelAlert: UIViewController {
enum EmailStateAlert {
case group
case list
case emailSignOut
}
var callblock:((Int)->Void) = { idx in}
......@@ -26,7 +27,6 @@ class EmailContentDelAlert: UIViewController {
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?"
......@@ -38,11 +38,19 @@ class EmailContentDelAlert: UIViewController {
EmailContentAction1.setTitle("Delete", for: .normal)
EmailContentAction2.setTitle("Cancel", for: .normal)
break
case .emailSignOut:
EmailContentMessage.text = "Are you sure you want to quit?"
EmailContentAction1.setTitle("Yes", for: .normal)
EmailContentAction2.setTitle("Cancel", for: .normal)
break
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
func show() -> Void {
self.modalTransitionStyle = .crossDissolve
self.modalPresentationStyle = .overFullScreen
UIViewController.topMostViewController()?.present(self, animated: true)
}
......
//
// EmailSaveController.swift
// PhoneManager
//
// Created by edy on 2025/5/12.
//
import UIKit
class EmailSaveController: UIViewController {
enum SuccessfromState {
case keyword
case signout
}
var state:SuccessfromState = .keyword
override func viewDidLoad() {
super.viewDidLoad()
}
@IBOutlet weak var messageBox: UILabel!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
switch state {
case .keyword:
messageBox.text = "Keyword saved"
messageBox.textColor = UIColor.colorWithHex(hexStr: "#666666")
case .signout:
messageBox.text = "Exit successfully"
messageBox.textColor = .black
}
}
}
<?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="EmailSaveController" customModule="PhoneManager" customModuleProvider="target">
<connections>
<outlet property="messageBox" destination="adM-fJ-AeE" id="CZa-Uh-JGc"/>
<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="zXo-fv-YGt">
<rect key="frame" x="109" y="378.66666666666669" width="175" height="95"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="lSd-TZ-jr6">
<rect key="frame" x="38.666666666666657" y="21.333333333333314" width="97.666666666666686" height="52"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_ok_duolicates" translatesAutoresizingMaskIntoConstraints="NO" id="Vuz-Sa-De6">
<rect key="frame" x="31.333333333333343" y="0.0" width="35" height="35"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Keyword saved" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="adM-fJ-AeE">
<rect key="frame" x="0.0" y="35" width="97.666666666666671" height="17"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<color key="textColor" red="0.40000000000000002" green="0.40000000000000002" blue="0.40000000000000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="lSd-TZ-jr6" firstAttribute="centerX" secondItem="zXo-fv-YGt" secondAttribute="centerX" id="asq-Oo-t1z"/>
<constraint firstItem="lSd-TZ-jr6" firstAttribute="centerY" secondItem="zXo-fv-YGt" secondAttribute="centerY" id="gi8-eX-JcK"/>
<constraint firstAttribute="width" constant="175" id="pee-w9-hhU"/>
<constraint firstAttribute="height" constant="95" id="xht-FO-Xc7"/>
</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="zXo-fv-YGt" firstAttribute="centerY" secondItem="i5M-Pr-FkT" secondAttribute="centerY" id="lHX-qV-grE"/>
<constraint firstItem="zXo-fv-YGt" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="rqA-77-psE"/>
</constraints>
<point key="canvasLocation" x="132" y="-11"/>
</view>
</objects>
<resources>
<image name="ic_ok_duolicates" width="35" height="35"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
......@@ -14,13 +14,16 @@ class EmailCleanController: BaseViewController {
setup()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
PMEmailManager.shareManager.fetchEmails()
}
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 = {
......
//
// EmailKeywordController.swift
// PhoneManager
//
// Created by edy on 2025/5/12.
//
import UIKit
class EmailKeywordController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .clear
self.view.addSubview(blur)
setup()
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardShow(_:)), name: UIApplication.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardHide(_:)), name: UIApplication.keyboardWillHideNotification, object: nil)
}
var callblock:((String)->Void) = { keyword in}
@objc func keyBoardShow(_ notication:Notification) -> Void {
guard let info = notication.userInfo,
let duration = info[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval,
let keyboardFrame = info[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else {
return
}
UIView.animate(withDuration: duration) {
self.content.snp.updateConstraints { make in
make.bottom.equalToSuperview().offset(-CGRectGetHeight(keyboardFrame))
}
self.view.layoutIfNeeded()
}
}
@objc func keyBoardHide(_ notication:Notification) -> Void {
guard let info = notication.userInfo,
let duration = info[UIResponder.keyboardAnimationDurationUserInfoKey] as? TimeInterval,
let keyboardFrame = info[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else {
return
}
UIView.animate(withDuration: duration) {
self.content.snp.updateConstraints { make in
make.bottom.equalToSuperview()
}
self.view.layoutIfNeeded()
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
DispatchQueue.main.async {
self.blur.frame = self.view.bounds
self.textInput.becomeFirstResponder()
self.content.cornerCut(radius: 16, corner: [.topLeft,.topRight])
}
}
private lazy var blur: UIVisualEffectView = {
let blurEffect = UIBlurEffect(style: .systemChromeMaterialDark)
let blurView = UIVisualEffectView(effect: blurEffect)
blurView.alpha = 0.8
return blurView
}()
private func setup() -> Void {
content.snp.makeConstraints { make in
make.left.right.bottom.equalToSuperview()
}
tl.snp.makeConstraints { make in
make.left.right.equalToSuperview()
make.top.equalToSuperview().offset(12)
make.height.equalTo(20)
}
textInput.snp.makeConstraints { make in
make.left.right.equalToSuperview().inset(10)
make.top.equalTo(tl.snp.bottom).offset(12)
make.height.equalTo(54)
}
saveBtn.snp.makeConstraints { make in
make.left.right.equalTo(textInput)
make.top.equalTo(textInput.snp.bottom).offset(12)
make.height.equalTo(54)
}
cancelBtn.snp.makeConstraints { make in
make.left.right.equalTo(textInput)
make.top.equalTo(saveBtn.snp.bottom).offset(12)
make.height.equalTo(54)
make.bottom.equalToSuperview().offset(-10)
}
self.view.layoutIfNeeded()
}
@objc func emActions(_ sender:UIButton) {
view.endEditing(true)
guard let text:String = self.textInput.text else { return }
if sender.tag == 10 {
let save = EmailSaveController()
save.modalTransitionStyle = .crossDissolve
save.modalPresentationStyle = .overFullScreen
self.present(save, animated: true)
DispatchQueue.main.asyncAfter(deadline: .now()+1.5) {
save.dismiss(animated: true) {
self.callblock(text)
self.dismiss(animated: true)
}
}
}else{
self.dismiss(animated: true)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
}
private lazy var tl: UILabel = {
let l = UILabel()
l.text = "Add Keyvrord"
l.font = UIFont.boldSystemFont(ofSize: 14)
l.textAlignment = .center
l.textColor = UIColor.colorWithHex(hexStr: "#B3B3B3")
content.addSubview(l)
return l
}()
private lazy var textInput: PMTextField = {
let t = PMTextField()
t.contentInsets = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15)
t.placeholder = "Keyvrord"
t.backgroundColor = .white
t.Radius = 8
content.addSubview(t)
return t
}()
private lazy var saveBtn: UIButton = {
let save = UIButton(type: .custom)
save.backgroundColor = UIColor.colorWithHex(hexStr: "#0082FF")
save.Radius = 8
save.setTitle("Save", for: .normal)
save.setTitleColor(.white, for: .normal)
save.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
save.tag = 10;
save.addTarget(self, action: #selector(emActions(_:)), for: .touchUpInside)
content.addSubview(save)
return save
}()
private lazy var cancelBtn: UIButton = {
let save = UIButton(type: .custom)
save.backgroundColor = .clear
save.Radius = 8
save.tag = 11;
save.setTitle("Cancel", for: .normal)
save.setTitleColor(UIColor.colorWithHex(hexStr: "#666666"), for: .normal)
save.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
save.addTarget(self, action: #selector(emActions(_:)), for: .touchUpInside)
content.addSubview(save)
return save
}()
private lazy var content: UIView = {
let c = UIView()
c.backgroundColor = UIColor.colorWithHex(hexStr: "#F2F6FC")
view.addSubview(c)
return c
}()
deinit {
NotificationCenter.default.removeObserver(self)
}
}
......@@ -9,6 +9,13 @@ import UIKit
class EmailLoginController: BaseViewController {
enum fromState {
case home
case set
}
var state:fromState = .home
override func viewDidLoad() {
super.viewDidLoad()
setup()
......@@ -40,11 +47,19 @@ class EmailLoginController: BaseViewController {
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)
PMEmailManager.shareManager.initOAuth(self) { success in
if success {
if self.state == .home {
let gourp = EmailCleanController()
var navigation = self.navigationController?.viewControllers
if navigation?.count ?? 0 > 1 {
navigation![navigation!.count-1] = gourp
self.navigationController?.setViewControllers(navigation ?? [], animated: true)
}
}else{
self.navigationController?.popViewController(animated: true)
}
}
}
}
return empty
......
......@@ -9,9 +9,33 @@ import UIKit
class EmailFilterManager: NSObject {
class func filter() -> [EmailFilterModel] {
static let share = EmailFilterManager()
var keyword:[String] {
set {
guard let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let path2 = path.appendingPathComponent("keyword.json")
do{
let data = try JSONEncoder().encode(newValue)
try data.write(to: path2)
}catch{}
}
get {
guard let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return [] }
let path2 = path.appendingPathComponent("keyword.json")
do {
let dataFile = try Data(contentsOf: path2)
let decode = try JSONDecoder().decode([String].self, from:dataFile)
return decode
}catch{
return []
}
}
}
func filter() -> [EmailFilterModel] {
let data = [ ["header":"TIME","child":[ ["title":"Delete all mails from selected categories",
"isSelect":false],
"isSelect":true],
["title":"Delete 1 week and older mails",
"isSelect":false],
["title":"Delete 1 month and older mails",
......@@ -23,7 +47,7 @@ class EmailFilterManager: NSObject {
"isSelect":false] ]
],
["header":"READ & UNREAD","child":[ ["title":"Delete read mails",
"isSelect":false],
"isSelect":true],
["title":"Delete unread mails",
"isSelect":false]]
],
......@@ -33,11 +57,10 @@ class EmailFilterManager: NSObject {
]
]
guard var path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return [] }
path = path.appendingPathComponent("EmailFilter.json")
guard let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return [] }
let path1 = path.appendingPathComponent("EmailFilter.json")
do {
let dataFile = try Data(contentsOf: path)
let dataFile = try Data(contentsOf: path1)
let decode = try JSONDecoder().decode([EmailFilterModel].self, from:dataFile)
return decode
}catch{
......@@ -63,5 +86,5 @@ struct EmailFilterModel: Codable {
struct EmailFilterChildModel:Codable {
var title:String?
var isSelect:Bool = false
var keyword:[String]?
}
//
// PMTextField.swift
// PhoneManager
//
// Created by edy on 2025/5/12.
//
import UIKit
class PMTextField: UITextField {
var contentInsets = UIEdgeInsets()
override func borderRect(forBounds bounds: CGRect) -> CGRect {
let rect = super.borderRect(forBounds: bounds)
return math(rect)
}
override func textRect(forBounds bounds: CGRect) -> CGRect {
let rect = super.textRect(forBounds: bounds)
return math(rect)
}
override func placeholderRect(forBounds bounds: CGRect) -> CGRect {
let rect = super.placeholderRect(forBounds: bounds)
return CGRect(
x: rect.origin.x,
y: (bounds.height - rect.height) / 2,
width: rect.width,
height: rect.height
)
}
override func editingRect(forBounds bounds: CGRect) -> CGRect {
let rect = super.editingRect(forBounds: bounds)
return math(rect)
}
private func math(_ bounds:CGRect) -> CGRect {
var rect = bounds
rect.origin.x = contentInsets.left
rect.origin.y = contentInsets.top
rect.size.width = rect.size.width - contentInsets.left - contentInsets.right
rect.size.height = rect.size.height - contentInsets.top - contentInsets.bottom
return rect
}
}
......@@ -23,12 +23,17 @@ class PMScaleImageView: UIView , UIScrollViewDelegate {
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)
self.layoutIfNeeded()
var size = self.icon?.size ?? CGSize()
if size.width > self.width {
size.width = self.width
size.height = size.height * (self.width / (self.icon?.size.width ?? 1))
}
self.showImg.snp.remakeConstraints({ make in
make.left.equalToSuperview().offset((self.width - size.width)/2.0 )
make.top.equalToSuperview().offset((self.height - size.height)/2.0 )
make.size.equalTo(size)
})
})
}
}
......@@ -37,15 +42,11 @@ class PMScaleImageView: UIView , UIScrollViewDelegate {
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
iv.contentMode = .scaleAspectFill
scroll.addSubview(iv)
return iv
}()
......@@ -56,7 +57,7 @@ class PMScaleImageView: UIView , UIScrollViewDelegate {
scroll.showsVerticalScrollIndicator = false
scroll.showsHorizontalScrollIndicator = false
scroll.minimumZoomScale = 1.0
scroll.maximumZoomScale = 3.0
scroll.maximumZoomScale = 4.0
addSubview(scroll)
return scroll
}()
......
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