mirror of
				https://github.com/yattee/yattee.git
				synced 2025-10-31 04:31:54 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			199 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Swift
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Swift
		
	
	
	
	
	
| import SwiftUI
 | |
| 
 | |
| struct ImportSettingsAccountRow: View {
 | |
|     var account: Account
 | |
|     var fileModel: ImportSettingsFileModel
 | |
| 
 | |
|     @State private var password = ""
 | |
| 
 | |
|     @State private var isValid = false
 | |
|     @State private var isValidated = false
 | |
|     @State private var isValidating = false
 | |
|     @State private var validationError: String?
 | |
|     @State private var validationDebounce = Debounce()
 | |
| 
 | |
|     @ObservedObject private var model = ImportSettingsSheetViewModel.shared
 | |
| 
 | |
|     func afterValidation() {
 | |
|         if isValid {
 | |
|             model.importableAccounts.insert(account.id)
 | |
|             model.selectedAccounts.insert(account.id)
 | |
|             model.importableAccountsPasswords[account.id] = password
 | |
|         } else {
 | |
|             model.selectedAccounts.remove(account.id)
 | |
|             model.importableAccounts.remove(account.id)
 | |
|             model.importableAccountsPasswords.removeValue(forKey: account.id)
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     var body: some View {
 | |
|         #if os(tvOS)
 | |
|             row
 | |
|         #else
 | |
|             Button(action: { model.toggleAccount(account, accounts: accounts) }) {
 | |
|                 row
 | |
|             }
 | |
|             .buttonStyle(.plain)
 | |
|         #endif
 | |
|     }
 | |
| 
 | |
|     var row: some View {
 | |
|         let accountExists = AccountsModel.shared.find(account.id) != nil
 | |
| 
 | |
|         return VStack(alignment: .leading) {
 | |
|             HStack {
 | |
|                 Text(account.username)
 | |
|                 Spacer()
 | |
|                 Image(systemName: "checkmark")
 | |
|                     .foregroundColor(.accentColor)
 | |
|                     .opacity(isChecked ? 1 : 0)
 | |
|             }
 | |
|             Text(account.instance?.description ?? "")
 | |
|                 .font(.caption)
 | |
|                 .foregroundColor(.secondary)
 | |
| 
 | |
|             Group {
 | |
|                 if let instanceID = account.instanceID {
 | |
|                     if accountExists {
 | |
|                         HStack {
 | |
|                             Image(systemName: "xmark.circle.fill")
 | |
|                                 .foregroundColor(Color("AppRedColor"))
 | |
|                             Text("Account already exists")
 | |
|                         }
 | |
|                     } else {
 | |
|                         Group {
 | |
|                             if InstancesModel.shared.find(instanceID) != nil || InstancesModel.shared.findByURLString(account.urlString) != nil {
 | |
|                                 HStack {
 | |
|                                     Image(systemName: "checkmark.circle.fill")
 | |
|                                         .foregroundColor(.green)
 | |
|                                     Text("Custom Location already exists")
 | |
|                                 }
 | |
|                             } else if model.selectedInstances.contains(instanceID) {
 | |
|                                 HStack {
 | |
|                                     Image(systemName: "checkmark.circle.fill")
 | |
|                                         .foregroundColor(.green)
 | |
|                                     Text("Custom Location selected for import")
 | |
|                                 }
 | |
|                             } else {
 | |
|                                 HStack {
 | |
|                                     Image(systemName: "xmark.circle.fill")
 | |
|                                         .foregroundColor(.red)
 | |
|                                     Text("Custom Location not selected for import")
 | |
|                                 }
 | |
|                                 .foregroundColor(Color("AppRedColor"))
 | |
|                             }
 | |
|                         }
 | |
|                         .frame(minHeight: 20)
 | |
| 
 | |
|                         if account.password.isNil || account.password!.isEmpty {
 | |
|                             Group {
 | |
|                                 if password.isEmpty {
 | |
|                                     HStack {
 | |
|                                         Image(systemName: "key")
 | |
|                                         Text("Password required to import")
 | |
|                                     }
 | |
|                                     .foregroundColor(Color("AppRedColor"))
 | |
|                                 } else {
 | |
|                                     AccountValidationStatus(
 | |
|                                         app: .constant(instance.app),
 | |
|                                         isValid: $isValid,
 | |
|                                         isValidated: $isValidated,
 | |
|                                         isValidating: $isValidating,
 | |
|                                         error: $validationError
 | |
|                                     )
 | |
|                                 }
 | |
|                             }
 | |
|                             .frame(minHeight: 20)
 | |
|                         } else {
 | |
|                             HStack {
 | |
|                                 Image(systemName: "checkmark.circle.fill")
 | |
|                                     .foregroundColor(.green)
 | |
| 
 | |
|                                 Text("Password saved in import file")
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             .foregroundColor(.primary)
 | |
|             .font(.caption)
 | |
|             .padding(.vertical, 2)
 | |
| 
 | |
|             if !accountExists && (account.password.isNil || account.password!.isEmpty) {
 | |
|                 SecureField("Password", text: $password)
 | |
|                     .onChange(of: password) { _ in validate() }
 | |
|                 #if !os(tvOS)
 | |
|                     .textFieldStyle(RoundedBorderTextFieldStyle())
 | |
|                 #endif
 | |
|             }
 | |
|         }
 | |
|         .frame(maxWidth: .infinity, alignment: .leading)
 | |
|         .contentShape(Rectangle())
 | |
|         .onChange(of: isValid) { _ in afterValidation() }
 | |
|         .animation(nil, value: isChecked)
 | |
|     }
 | |
| 
 | |
|     var isChecked: Bool {
 | |
|         model.isSelectedForImport(account)
 | |
|     }
 | |
| 
 | |
|     var locationsSettingsGroupImporter: LocationsSettingsGroupImporter? {
 | |
|         fileModel.locationsSettingsGroupImporter
 | |
|     }
 | |
| 
 | |
|     var accounts: [Account] {
 | |
|         fileModel.locationsSettingsGroupImporter?.accounts ?? []
 | |
|     }
 | |
| 
 | |
|     private var instance: Instance! {
 | |
|         (fileModel.locationsSettingsGroupImporter?.instances ?? []).first { $0.id == account.instanceID }
 | |
|     }
 | |
| 
 | |
|     private var validator: AccountValidator {
 | |
|         AccountValidator(
 | |
|             app: .constant(instance.app),
 | |
|             url: instance.apiURLString,
 | |
|             account: Account(instanceID: instance.id, urlString: instance.apiURLString, username: account.username, password: password),
 | |
|             id: .constant(account.username),
 | |
|             isValid: $isValid,
 | |
|             isValidated: $isValidated,
 | |
|             isValidating: $isValidating,
 | |
|             error: $validationError
 | |
|         )
 | |
|     }
 | |
| 
 | |
|     private func validate() {
 | |
|         isValid = false
 | |
|         validationDebounce.invalidate()
 | |
| 
 | |
|         guard !account.username.isEmpty, !password.isEmpty else {
 | |
|             validator.reset()
 | |
|             return
 | |
|         }
 | |
| 
 | |
|         isValidating = true
 | |
| 
 | |
|         validationDebounce.debouncing(1) {
 | |
|             validator.validateAccount()
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| struct ImportSettingsAccountRow_Previews: PreviewProvider {
 | |
|     static var previews: some View {
 | |
|         let fileModel = ImportSettingsFileModel()
 | |
|         fileModel.loadData(URL(string: "https://gist.githubusercontent.com/arekf/578668969c9fdef1b3828bea864c3956/raw/f794a95a20261bcb1145e656c8dda00bea339e2a/yattee-recents.yatteesettings")!)
 | |
| 
 | |
|         return List {
 | |
|             ImportSettingsAccountRow(
 | |
|                 account: .init(name: "arekf", urlString: "https://instance.com", username: "arekf"),
 | |
|                 fileModel: fileModel
 | |
|             )
 | |
|             ImportSettingsAccountRow(
 | |
|                 account: .init(name: "arekf", urlString: "https://instance.com", username: "arekf", password: "a"),
 | |
|                 fileModel: fileModel
 | |
|             )
 | |
|         }
 | |
|     }
 | |
| }
 | 
