mirror of
				https://github.com/yattee/yattee.git
				synced 2025-11-04 06:32:03 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			263 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Swift
		
	
	
	
	
	
			
		
		
	
	
			263 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Swift
		
	
	
	
	
	
import SwiftUI
 | 
						|
 | 
						|
struct ImportSettingsSheetView: View {
 | 
						|
    @Binding var settingsFile: URL?
 | 
						|
    @StateObject private var model = ImportSettingsSheetViewModel.shared
 | 
						|
    @StateObject private var importExportModel = ImportExportSettingsModel.shared
 | 
						|
    @StateObject private var fileModel = ImportSettingsFileModel.shared
 | 
						|
 | 
						|
    @Environment(\.presentationMode) private var presentationMode
 | 
						|
 | 
						|
    @State private var presentingCompletedAlert = false
 | 
						|
 | 
						|
    private let accountsModel = AccountsModel.shared
 | 
						|
 | 
						|
    var body: some View {
 | 
						|
        Group {
 | 
						|
            #if os(macOS)
 | 
						|
                list
 | 
						|
                    .frame(width: 700, height: 800)
 | 
						|
            #else
 | 
						|
                NavigationView {
 | 
						|
                    list
 | 
						|
                }
 | 
						|
            #endif
 | 
						|
        }
 | 
						|
        .onAppear {
 | 
						|
            guard let settingsFile else { return }
 | 
						|
            fileModel.loadData(settingsFile)
 | 
						|
        }
 | 
						|
        .onChange(of: settingsFile) { _ in
 | 
						|
            guard let settingsFile else { return }
 | 
						|
            fileModel.loadData(settingsFile)
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    var list: some View {
 | 
						|
        List {
 | 
						|
            importGroupView
 | 
						|
 | 
						|
            importOptions
 | 
						|
 | 
						|
            metadata
 | 
						|
        }
 | 
						|
        .alert(isPresented: $presentingCompletedAlert) {
 | 
						|
            completedAlert
 | 
						|
        }
 | 
						|
        #if os(iOS)
 | 
						|
        .backport
 | 
						|
        .scrollDismissesKeyboardInteractively()
 | 
						|
        #endif
 | 
						|
        .navigationTitle("Import Settings")
 | 
						|
        .toolbar {
 | 
						|
            ToolbarItem(placement: .cancellationAction) {
 | 
						|
                Button(action: { presentationMode.wrappedValue.dismiss() }) {
 | 
						|
                    Text("Cancel")
 | 
						|
                }
 | 
						|
            }
 | 
						|
            ToolbarItem(placement: .confirmationAction) {
 | 
						|
                Button(action: {
 | 
						|
                    fileModel.performImport()
 | 
						|
                    presentingCompletedAlert = true
 | 
						|
                    ImportExportSettingsModel.shared.reset()
 | 
						|
                }) {
 | 
						|
                    Text("Import")
 | 
						|
                }
 | 
						|
                .disabled(!canImport)
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    var completedAlert: Alert {
 | 
						|
        Alert(
 | 
						|
            title: Text("Import Completed"),
 | 
						|
            dismissButton: .default(Text("Close")) {
 | 
						|
                if accountsModel.isEmpty,
 | 
						|
                   let account = InstancesModel.shared.all.first?.anonymousAccount
 | 
						|
                {
 | 
						|
                    accountsModel.setCurrent(account)
 | 
						|
                }
 | 
						|
                presentationMode.wrappedValue.dismiss()
 | 
						|
            }
 | 
						|
        )
 | 
						|
    }
 | 
						|
 | 
						|
    var canImport: Bool {
 | 
						|
        return !model.selectedAccounts.isEmpty || !model.selectedInstances.isEmpty || !importExportModel.selectedExportGroups.isEmpty
 | 
						|
    }
 | 
						|
 | 
						|
    var locationsSettingsGroupImporter: LocationsSettingsGroupImporter? {
 | 
						|
        fileModel.locationsSettingsGroupImporter
 | 
						|
    }
 | 
						|
 | 
						|
    struct ExportGroupRow: View {
 | 
						|
        let group: ImportExportSettingsModel.ExportGroup
 | 
						|
 | 
						|
        @ObservedObject private var model = ImportExportSettingsModel.shared
 | 
						|
 | 
						|
        var body: some View {
 | 
						|
            Button(action: { model.toggleExportGroupSelection(group) }) {
 | 
						|
                HStack {
 | 
						|
                    Text(group.label.localized())
 | 
						|
                    Spacer()
 | 
						|
                    Image(systemName: "checkmark")
 | 
						|
                        .foregroundColor(.accentColor)
 | 
						|
                        .opacity(isChecked ? 1 : 0)
 | 
						|
                }
 | 
						|
                .contentShape(Rectangle())
 | 
						|
                .foregroundColor(.primary)
 | 
						|
                .animation(nil, value: isChecked)
 | 
						|
            }
 | 
						|
            .buttonStyle(.plain)
 | 
						|
        }
 | 
						|
 | 
						|
        var isChecked: Bool {
 | 
						|
            model.selectedExportGroups.contains(group)
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    var importGroupView: some View {
 | 
						|
        Group {
 | 
						|
            Section(header: Text("Settings")) {
 | 
						|
                ForEach(ImportExportSettingsModel.ExportGroup.settingsGroups) { group in
 | 
						|
                    ExportGroupRow(group: group)
 | 
						|
                        .disabled(!fileModel.isGroupIncludedInFile(group))
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            Section(header: Text("Other")) {
 | 
						|
                ForEach(ImportExportSettingsModel.ExportGroup.otherGroups) { group in
 | 
						|
                    ExportGroupRow(group: group)
 | 
						|
                        .disabled(!fileModel.isGroupIncludedInFile(group))
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    @ViewBuilder var metadata: some View {
 | 
						|
        if let settingsFile {
 | 
						|
            Section(header: Text("File information")) {
 | 
						|
                MetadataRow(name: Text("Name"), value: Text(fileModel.filename(settingsFile)))
 | 
						|
 | 
						|
                if let date = fileModel.metadataDate {
 | 
						|
                    MetadataRow(name: Text("Date"), value: Text(date))
 | 
						|
                    #if os(tvOS)
 | 
						|
                        .focusable()
 | 
						|
                    #endif
 | 
						|
                }
 | 
						|
 | 
						|
                if let build = fileModel.metadataBuild {
 | 
						|
                    MetadataRow(name: Text("Build"), value: Text(build))
 | 
						|
                    #if os(tvOS)
 | 
						|
                        .focusable()
 | 
						|
                    #endif
 | 
						|
                }
 | 
						|
 | 
						|
                if let platform = fileModel.metadataPlatform {
 | 
						|
                    MetadataRow(name: Text("Platform"), value: Text(platform))
 | 
						|
                    #if os(tvOS)
 | 
						|
                        .focusable()
 | 
						|
                    #endif
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    struct MetadataRow: View {
 | 
						|
        let name: Text
 | 
						|
        let value: Text
 | 
						|
 | 
						|
        var body: some View {
 | 
						|
            HStack {
 | 
						|
                name
 | 
						|
                    .layoutPriority(2)
 | 
						|
 | 
						|
                Spacer()
 | 
						|
 | 
						|
                value
 | 
						|
                    .layoutPriority(1)
 | 
						|
                    .lineLimit(2)
 | 
						|
                    .foregroundColor(.secondary)
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    var instances: [Instance] {
 | 
						|
        locationsSettingsGroupImporter?.instances ?? []
 | 
						|
    }
 | 
						|
 | 
						|
    var accounts: [Account] {
 | 
						|
        locationsSettingsGroupImporter?.accounts ?? []
 | 
						|
    }
 | 
						|
 | 
						|
    struct ImportInstanceRow: View {
 | 
						|
        var instance: Instance
 | 
						|
        var accounts: [Account]
 | 
						|
 | 
						|
        @ObservedObject private var model = ImportSettingsSheetViewModel.shared
 | 
						|
 | 
						|
        var body: some View {
 | 
						|
            Button(action: { model.toggleInstance(instance, accounts: accounts) }) {
 | 
						|
                VStack {
 | 
						|
                    Group {
 | 
						|
                        HStack {
 | 
						|
                            Text(instance.description)
 | 
						|
                            Spacer()
 | 
						|
                            Image(systemName: "checkmark")
 | 
						|
                                .opacity(isChecked ? 1 : 0)
 | 
						|
                                .foregroundColor(.accentColor)
 | 
						|
                        }
 | 
						|
 | 
						|
                        if model.isInstanceAlreadyAdded(instance) {
 | 
						|
                            HStack {
 | 
						|
                                Image(systemName: "xmark.circle.fill")
 | 
						|
                                    .foregroundColor(.red)
 | 
						|
                                Text("Custom Location already exists")
 | 
						|
                            }
 | 
						|
                            .font(.caption)
 | 
						|
                            .padding(.vertical, 2)
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    .frame(maxWidth: .infinity, alignment: .leading)
 | 
						|
                }
 | 
						|
                .contentShape(Rectangle())
 | 
						|
                .foregroundColor(.primary)
 | 
						|
                .transaction { t in t.animation = nil }
 | 
						|
            }
 | 
						|
            .buttonStyle(.plain)
 | 
						|
        }
 | 
						|
 | 
						|
        var isChecked: Bool {
 | 
						|
            model.isImportable(instance) && model.selectedInstances.contains(instance.id)
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    @ViewBuilder var importOptions: some View {
 | 
						|
        if fileModel.isPublicInstancesSettingsGroupInFile || !instances.isEmpty {
 | 
						|
            Section(header: Text("Locations")) {
 | 
						|
                if fileModel.isPublicInstancesSettingsGroupInFile {
 | 
						|
                    ExportGroupRow(group: .locationsSettings)
 | 
						|
                }
 | 
						|
 | 
						|
                ForEach(instances) { instance in
 | 
						|
                    ImportInstanceRow(instance: instance, accounts: accounts)
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if !accounts.isEmpty {
 | 
						|
            Section(header: Text("Accounts")) {
 | 
						|
                ForEach(accounts) { account in
 | 
						|
                    ImportSettingsAccountRow(account: account, fileModel: fileModel)
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
struct ImportSettingsSheetView_Previews: PreviewProvider {
 | 
						|
    static var previews: some View {
 | 
						|
        ImportSettingsSheetView(settingsFile: .constant(URL(string: "https://gist.githubusercontent.com/arekf/578668969c9fdef1b3828bea864c3956/raw/f794a95a20261bcb1145e656c8dda00bea339e2a/yattee-recents.yatteesettings")!))
 | 
						|
    }
 | 
						|
}
 |