Ferrite-backup/Ferrite/Views/MainView.swift
kingbri ff13884b2b Application: Use the plist minVersion to restrict updates
It's more reliable to use the plist which contains the min version
to determine if an update notification should be shown.

Signed-off-by: kingbri <bdashore3@proton.me>
2023-03-23 11:52:52 -04:00

245 lines
9.2 KiB
Swift

//
// MainView.swift
// Ferrite
//
// Created by Brian Dashore on 7/11/22.
//
import SwiftUI
import SwiftUIX
struct MainView: View {
@EnvironmentObject var navModel: NavigationViewModel
@EnvironmentObject var logManager: LoggingManager
@EnvironmentObject var debridManager: DebridManager
@EnvironmentObject var scrapingModel: ScrapingViewModel
@EnvironmentObject var backupManager: BackupManager
@EnvironmentObject var pluginManager: PluginManager
@AppStorage("Updates.AutomaticNotifs") var autoUpdateNotifs = true
@State private var showUpdateAlert = false
@State private var releaseVersionString: String = ""
@State private var releaseUrlString: String = ""
@State private var viewTask: Task<Void, Never>?
var body: some View {
TabView(selection: $navModel.selectedTab) {
ContentView()
.tabItem {
Label("Search", systemImage: "magnifyingglass")
}
.tag(NavigationViewModel.ViewTab.search)
LibraryView()
.tabItem {
Label("Library", systemImage: "book.closed")
}
.tag(NavigationViewModel.ViewTab.library)
PluginsView()
.tabItem {
Label("Plugins", systemImage: "doc.text")
}
.tag(NavigationViewModel.ViewTab.plugins)
SettingsView()
.tabItem {
Label("Settings", systemImage: "gear")
}
.tag(NavigationViewModel.ViewTab.settings)
}
.sheet(item: $navModel.currentChoiceSheet) { item in
switch item {
case .action:
ActionChoiceView()
.environmentObject(debridManager)
.environmentObject(scrapingModel)
.environmentObject(navModel)
.environmentObject(pluginManager)
.environment(\.managedObjectContext, PersistenceController.shared.container.viewContext)
case .batch:
BatchChoiceView()
.environmentObject(debridManager)
.environmentObject(scrapingModel)
.environmentObject(navModel)
case .activity:
if #available(iOS 16, *) {
AppActivityView(activityItems: navModel.activityItems)
.presentationDetents([.medium, .large])
} else {
AppActivityView(activityItems: navModel.activityItems)
}
}
}
.backport.onAppear {
if
autoUpdateNotifs,
Application.shared.osVersion.toString() >= Application.shared.minVersion
{
// MARK: If scope bar duplication happens, this may be the problem
logManager.info("Ferrite started")
viewTask = Task {
// Sleep for 2 seconds to allow for view layout and app init
try? await Task.sleep(seconds: 2)
do {
guard let latestRelease = try await Github().fetchLatestRelease() else {
logManager.error(
"Github: No releases found",
description: "Github error: No releases found"
)
return
}
let releaseVersion = String(latestRelease.tagName.dropFirst())
if releaseVersion > Application.shared.appVersion {
releaseVersionString = latestRelease.tagName
releaseUrlString = latestRelease.htmlUrl
logManager.info("Update available to \(releaseVersionString)")
showUpdateAlert.toggle()
}
} catch {
let error = error as NSError
if error.code == -1009 {
logManager.info(
"Github: The connection is offline",
description: "The connection is offline"
)
} else {
logManager.error(
"Github: \(error)",
description: "A Github error was logged"
)
}
}
logManager.info("Github release updates checked")
}
}
}
.onDisappear {
viewTask?.cancel()
}
.onOpenURL { url in
if url.scheme == "file" {
// Attempt to copy to backups directory if backup doesn't exist
backupManager.copyBackup(backupUrl: url)
backupManager.showRestoreAlert.toggle()
}
}
// Global alerts and dialogs for backups
.backport.confirmationDialog(
isPresented: $backupManager.showRestoreAlert,
title: "Restore backup?",
message:
"Merge (preferred): Will merge your current data with the backup \n\n" +
"Overwrite: Will delete and replace all your data \n\n" +
"If Merge causes app instability, uninstall Ferrite and use the Overwrite option.",
buttons: [
.init("Merge", role: .destructive) {
Task {
await backupManager.restoreBackup(pluginManager: pluginManager, doOverwrite: false)
}
},
.init("Overwrite", role: .destructive) {
Task {
await backupManager.restoreBackup(pluginManager: pluginManager, doOverwrite: true)
}
}
]
)
.backport.alert(
isPresented: $backupManager.showRestoreCompletedAlert,
title: "Backup restored",
message: backupManager.restoreCompletedMessage.joined(separator: " \n\n"),
buttons: [
.init("OK") {
backupManager.restoreCompletedMessage = []
}
]
)
// Updater alert
.backport.alert(
isPresented: $showUpdateAlert,
title: "Update available",
message:
"Ferrite \(releaseVersionString) can be downloaded. \n\n" +
"This alert can be disabled in Settings.",
buttons: [
.init("Download") {
guard let releaseUrl = URL(string: releaseUrlString) else {
return
}
UIApplication.shared.open(releaseUrl)
},
.init(role: .cancel)
]
)
.overlay {
VStack {
Spacer()
if logManager.showToast {
Group {
switch logManager.toastType {
case .info:
Text(logManager.toastDescription ?? "This shouldn't be showing up... Contact the dev!")
case .warn:
Text("Warn: \(logManager.toastDescription ?? "This shouldn't be showing up... Contact the dev!")")
case .error:
Text("Error: \(logManager.toastDescription ?? "This shouldn't be showing up... Contact the dev!")")
}
}
.padding(12)
.font(.caption)
.background {
VisualEffectBlurView(blurStyle: .systemThinMaterial)
}
.cornerRadius(10)
}
if logManager.showIndeterminateToast {
VStack {
Text(logManager.indeterminateToastDescription ?? "Loading...")
.lineLimit(1)
HStack {
IndeterminateProgressView()
if let cancelAction = logManager.indeterminateCancelAction {
Button("Cancel") {
cancelAction()
logManager.hideIndeterminateToast()
}
}
}
}
.padding(12)
.font(.caption)
.background {
VisualEffectBlurView(blurStyle: .systemThinMaterial)
}
.cornerRadius(10)
.frame(width: 200)
}
Rectangle()
.foregroundColor(.clear)
.frame(height: 60)
}
.animation(.easeInOut(duration: 0.3), value: logManager.showToast || logManager.showIndeterminateToast)
}
}
}
struct MainView_Previews: PreviewProvider {
static var previews: some View {
MainView()
}
}