mirror of
https://github.com/exituser/Pearcleaner.git
synced 2026-09-17 07:19:04 +00:00
v3.7.1
This commit is contained in:
@@ -568,8 +568,8 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
APP_BUILD = 45;
|
APP_BUILD = 46;
|
||||||
APP_VERSION = 3.7.0;
|
APP_VERSION = 3.7.1;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
@@ -638,8 +638,8 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
APP_BUILD = 45;
|
APP_BUILD = 46;
|
||||||
APP_VERSION = 3.7.0;
|
APP_VERSION = 3.7.1;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
|||||||
@@ -29,9 +29,10 @@ extension Release {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --- Updater functionality
|
||||||
|
|
||||||
|
|
||||||
func loadGithubReleases(appState: AppState, manual: Bool = false) {
|
func loadGithubReleases(appState: AppState, manual: Bool = false, releaseOnly: Bool = false) {
|
||||||
let url = URL(string: "https://api.github.com/repos/alienator88/Pearcleaner/releases")!
|
let url = URL(string: "https://api.github.com/repos/alienator88/Pearcleaner/releases")!
|
||||||
let request = URLRequest(url: url)
|
let request = URLRequest(url: url)
|
||||||
URLSession.shared.dataTask(with: request) { data, response, error in
|
URLSession.shared.dataTask(with: request) { data, response, error in
|
||||||
@@ -40,7 +41,9 @@ func loadGithubReleases(appState: AppState, manual: Bool = false) {
|
|||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
let lastFewReleases = Array(decodedResponse.prefix(3)) // Get only the last 3 recent releases
|
let lastFewReleases = Array(decodedResponse.prefix(3)) // Get only the last 3 recent releases
|
||||||
appState.releases = lastFewReleases
|
appState.releases = lastFewReleases
|
||||||
checkForUpdate(appState: appState, manual: manual)
|
if !releaseOnly {
|
||||||
|
checkForUpdate(appState: appState, manual: manual)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -165,7 +168,58 @@ func UnzipAndReplace(DownloadedFileURL fileURL: String, appState: AppState) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// --- Updater check frequency
|
||||||
|
|
||||||
|
func updateNextUpdateDate() {
|
||||||
|
@AppStorage("settings.updater.updateTimeframe") var updateTimeframe: Int = 1
|
||||||
|
@AppStorage("settings.updater.nextUpdateDate") var nextUpdateDate = Date.now.timeIntervalSinceReferenceDate
|
||||||
|
let updateSeconds = updateTimeframe.daysToSeconds
|
||||||
|
let newUpdateDate = Calendar.current.startOfDay(for: Date().addingTimeInterval(updateSeconds))
|
||||||
|
nextUpdateDate = newUpdateDate.timeIntervalSinceReferenceDate
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkAndUpdateIfNeeded(appState: AppState) {
|
||||||
|
@AppStorage("settings.updater.updateTimeframe") var updateTimeframe: Int = 1
|
||||||
|
@AppStorage("settings.updater.nextUpdateDate") var nextUpdateDate = Date.now.timeIntervalSinceReferenceDate
|
||||||
|
|
||||||
|
let updateSeconds = updateTimeframe.daysToSeconds
|
||||||
|
let now = Date()
|
||||||
|
|
||||||
|
// Retrieve the next update date from UserDefaults
|
||||||
|
let nextUpdateDateLocal = Date(timeIntervalSinceReferenceDate: nextUpdateDate)
|
||||||
|
// let nextUpdateDate = UserDefaults.standard.object(forKey: "settings.updater.nextUpdateDate") as? Date
|
||||||
|
|
||||||
|
// If there's no stored next update date or it's in the past, update immediately
|
||||||
|
if !isSameDay(date1: nextUpdateDateLocal, date2: now) {
|
||||||
|
// Next update date is in the future, no need to update
|
||||||
|
printOS("Updater: next update date is in the future, skipping")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update immediately and set next update date
|
||||||
|
updateApp(appState: appState)
|
||||||
|
setNextUpdateDate(interval: updateSeconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateApp(appState: AppState) {
|
||||||
|
// Perform your update logic here
|
||||||
|
printOS("Updater: performing update")
|
||||||
|
loadGithubReleases(appState: appState)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setNextUpdateDate(interval: TimeInterval) {
|
||||||
|
let newUpdateDate = Calendar.current.startOfDay(for: Date().addingTimeInterval(interval))
|
||||||
|
UserDefaults.standard.set(newUpdateDate.timeIntervalSinceReferenceDate, forKey: "settings.updater.nextUpdateDate")
|
||||||
|
// UserDefaults.standard.set(newUpdateDate, forKey: "settings.updater.nextUpdateDate")
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSameDay(date1: Date, date2: Date) -> Bool {
|
||||||
|
return Calendar.current.isDate(date1, inSameDayAs: date2)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// --- Updater Badge View
|
||||||
|
|
||||||
|
|
||||||
struct UpdateNotificationView: View {
|
struct UpdateNotificationView: View {
|
||||||
|
|||||||
@@ -657,5 +657,13 @@ func getCurrentTimestamp() -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func formattedDate(_ date: Date?) -> String {
|
||||||
|
guard let date = date else { return "N/A" }
|
||||||
|
let formatter = DateFormatter()
|
||||||
|
formatter.dateStyle = .short
|
||||||
|
formatter.timeStyle = .none
|
||||||
|
return formatter.string(from: date)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ struct PearcleanerApp: App {
|
|||||||
@StateObject var locations = Locations()
|
@StateObject var locations = Locations()
|
||||||
@StateObject var fsm = FolderSettingsManager()
|
@StateObject var fsm = FolderSettingsManager()
|
||||||
@State private var windowSettings = WindowSettings()
|
@State private var windowSettings = WindowSettings()
|
||||||
@AppStorage("settings.updater.updateTimeframe") private var updateTimeframe: Int = 1
|
// @AppStorage("settings.updater.updateTimeframe") private var updateTimeframe: Int = 1
|
||||||
|
@AppStorage("settings.updater.enableUpdates") private var enableUpdates: Bool = true
|
||||||
@AppStorage("settings.permissions.hasLaunched") private var hasLaunched: Bool = false
|
@AppStorage("settings.permissions.hasLaunched") private var hasLaunched: Bool = false
|
||||||
@AppStorage("displayMode") var displayMode: DisplayMode = .system
|
@AppStorage("displayMode") var displayMode: DisplayMode = .system
|
||||||
@AppStorage("settings.general.mini") private var mini: Bool = false
|
@AppStorage("settings.general.mini") private var mini: Bool = false
|
||||||
@@ -110,31 +111,29 @@ struct PearcleanerApp: App {
|
|||||||
|
|
||||||
|
|
||||||
// Make sure App Support folder exists in the future if needed for storage
|
// Make sure App Support folder exists in the future if needed for storage
|
||||||
//MARK: This is not needed any longer as the update file is stored in /tmp directory
|
//MARK: This is not needed any longer as the update file is stored in /tmp directory. Use in the future for any local db functions the app might need
|
||||||
// ensureApplicationSupportFolderExists(appState: appState)
|
// ensureApplicationSupportFolderExists(appState: appState)
|
||||||
|
|
||||||
// Check for updates after app launch
|
// Check for updates after app launch
|
||||||
checkAllPermissions(appState: appState) { results in
|
checkAllPermissions(appState: appState) { results in
|
||||||
appState.permissionResults = results
|
appState.permissionResults = results
|
||||||
if results.allPermissionsGranted {
|
if results.allPermissionsGranted {
|
||||||
loadGithubReleases(appState: appState)
|
// Get GH releases
|
||||||
|
loadGithubReleases(appState: appState, releaseOnly: true)
|
||||||
|
|
||||||
|
if enableUpdates {
|
||||||
|
// Update checker
|
||||||
|
checkAndUpdateIfNeeded(appState: appState)
|
||||||
|
}
|
||||||
|
// Get new features
|
||||||
getFeatures(appState: appState, features: $features)
|
getFeatures(appState: appState, features: $features)
|
||||||
|
// Load extra conditions from GitHub
|
||||||
|
loadConditionsFromGitHub()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load extra conditions from GitHub
|
|
||||||
loadConditionsFromGitHub()
|
|
||||||
|
|
||||||
|
|
||||||
// TIMERS ////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Check for app updates every 8 hours or whatever user saved setting.
|
|
||||||
let updateSeconds = updateTimeframe.daysToSeconds
|
|
||||||
_ = Timer.scheduledTimer(withTimeInterval: updateSeconds, repeats: true) { _ in
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
loadGithubReleases(appState: appState)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -13,19 +13,61 @@ struct UpdateSettingsTab: View {
|
|||||||
@EnvironmentObject var appState: AppState
|
@EnvironmentObject var appState: AppState
|
||||||
@State private var showAlert = false
|
@State private var showAlert = false
|
||||||
@State private var showDone = false
|
@State private var showDone = false
|
||||||
|
@AppStorage("settings.updater.nextUpdateDate") private var nextUpdateDate = Date.now.timeIntervalSinceReferenceDate
|
||||||
@AppStorage("settings.updater.updateTimeframe") private var updateTimeframe: Int = 1
|
@AppStorage("settings.updater.updateTimeframe") private var updateTimeframe: Int = 1
|
||||||
|
@AppStorage("settings.updater.enableUpdates") private var enableUpdates: Bool = true
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
VStack {
|
||||||
|
|
||||||
HStack {
|
HStack(spacing: 0) {
|
||||||
Text("Check for updates every ") +
|
Image(systemName: "arrow.down.square")
|
||||||
Text("**\(updateTimeframe)**").foregroundColor(.red) +
|
.resizable()
|
||||||
Text(updateTimeframe == 1 ? " day" : " days")
|
.scaledToFit()
|
||||||
Stepper(value: $updateTimeframe, in: 1...7) {
|
.frame(width: 20, height: 20)
|
||||||
Text("")
|
.padding(.trailing)
|
||||||
|
.foregroundStyle(Color("mode").opacity(0.5))
|
||||||
|
|
||||||
|
VStack {
|
||||||
|
HStack(spacing: 0) {
|
||||||
|
Text("\(enableUpdates ? "Pearcleaner will check for updates every " : "Automatic updates are disabled")")
|
||||||
|
.font(.callout)
|
||||||
|
.foregroundStyle(Color("mode").opacity(0.5))
|
||||||
|
|
||||||
|
if enableUpdates {
|
||||||
|
Text("**\(updateTimeframe)**").font(.system(.callout, design: .monospaced)).monospacedDigit()
|
||||||
|
Text(updateTimeframe == 1 ? " day" : " days")
|
||||||
|
.font(.callout)
|
||||||
|
.foregroundStyle(Color("mode").opacity(0.5))
|
||||||
|
|
||||||
|
Stepper("", value: $updateTimeframe, in: 0...30)
|
||||||
|
.onChange(of: updateTimeframe, perform: { _ in
|
||||||
|
updateNextUpdateDate()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
|
||||||
|
if enableUpdates {
|
||||||
|
HStack {
|
||||||
|
Text("Next update check: \(formattedDate(Date(timeIntervalSinceReferenceDate: nextUpdateDate)))")
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundStyle(Color("mode").opacity(0.3))
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
Toggle(isOn: $enableUpdates, label: {
|
||||||
|
})
|
||||||
|
.toggleStyle(.switch)
|
||||||
}
|
}
|
||||||
|
.padding(5)
|
||||||
|
.padding(.leading)
|
||||||
|
|
||||||
ScrollView {
|
ScrollView {
|
||||||
VStack() {
|
VStack() {
|
||||||
@@ -87,6 +129,10 @@ struct UpdateSettingsTab: View {
|
|||||||
}
|
}
|
||||||
.padding(20)
|
.padding(20)
|
||||||
.frame(width: 500, height: 520)
|
.frame(width: 500, height: 520)
|
||||||
|
// .onAppear {
|
||||||
|
// // Convert TimeInterval to Date on appearance
|
||||||
|
// let _ = Date(timeIntervalSinceReferenceDate: nextUpdateDate)
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user