mirror of
https://github.com/yattee/yattee.git
synced 2024-12-15 14:50:32 +05:30
261 lines
8.2 KiB
Swift
261 lines
8.2 KiB
Swift
|
import SwiftUI
|
||
|
|
||
|
struct ImportSettingsSheetView: View {
|
||
|
@Binding var settingsFile: URL?
|
||
|
@StateObject private var model = ImportSettingsSheetViewModel.shared
|
||
|
@StateObject private var importExportModel = ImportExportSettingsModel.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 fileModel else { return }
|
||
|
model.reset(fileModel.locationsSettingsGroupImporter)
|
||
|
importExportModel.reset(fileModel)
|
||
|
}
|
||
|
.onChange(of: settingsFile) { _ in
|
||
|
importExportModel.reset(fileModel)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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 fileModel: ImportSettingsFileModel? {
|
||
|
guard let settingsFile else { return nil }
|
||
|
|
||
|
return ImportSettingsFileModel(url: settingsFile)
|
||
|
}
|
||
|
|
||
|
var locationsSettingsGroupImporter: LocationsSettingsGroupImporter? {
|
||
|
guard let fileModel else { return nil }
|
||
|
|
||
|
return 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)
|
||
|
Spacer()
|
||
|
Image(systemName: "checkmark")
|
||
|
.foregroundColor(.accent)
|
||
|
.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 fileModel {
|
||
|
Section(header: Text("File information")) {
|
||
|
MetadataRow(name: Text("Name"), value: Text(fileModel.filename))
|
||
|
|
||
|
if let date = fileModel.metadataDate {
|
||
|
MetadataRow(name: Text("Date"), value: Text(date))
|
||
|
}
|
||
|
|
||
|
if let build = fileModel.metadataBuild {
|
||
|
MetadataRow(name: Text("Build"), value: Text(build))
|
||
|
}
|
||
|
|
||
|
if let platform = fileModel.metadataPlatform {
|
||
|
MetadataRow(name: Text("Platform"), value: Text(platform))
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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 let fileModel {
|
||
|
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)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#Preview {
|
||
|
ImportSettingsSheetView(settingsFile: .constant(URL(string: "https://gist.githubusercontent.com/arekf/578668969c9fdef1b3828bea864c3956/raw/f794a95a20261bcb1145e656c8dda00bea339e2a/yattee-recents.yatteesettings")!))
|
||
|
}
|