Impressia/Vernissage/Views/SignInView/SignInView.swift

121 lines
4.7 KiB
Swift

//
// https://mczachurski.dev
// Copyright © 2022 Marcin Czachurski and the repository contributors.
// Licensed under the Apache License 2.0.
//
import SwiftUI
import PixelfedKit
import AuthenticationServices
struct SignInView: View {
@Environment(\.managedObjectContext) private var viewContext
@Environment(\.dismiss) private var dismiss
@EnvironmentObject var applicationState: ApplicationState
@EnvironmentObject var client: Client
@State private var serverAddress = String.empty()
@State private var instructionsUrlString:String?
@State private var instances: [Instance] = []
var onSignedIn: ((_ accountData: AccountData) -> Void)?
var body: some View {
List {
Section {
VStack(alignment: .center) {
HStack(alignment: .center, spacing: 4) {
TextField("signin.title.serverAddress", text: $serverAddress)
.onSubmit {
let baseAddress = self.getServerAddress(uri: self.serverAddress)
self.signIn(baseAddress: baseAddress)
}
.textInputAutocapitalization(.never)
.keyboardType(.URL)
.disableAutocorrection(true)
.clearButton(text: $serverAddress)
Button(NSLocalizedString("signin.title.signIn", comment: "Sign in")) {
HapticService.shared.fireHaptic(of: .buttonPress)
let baseAddress = self.getServerAddress(uri: self.serverAddress)
self.signIn(baseAddress: baseAddress)
}
.buttonStyle(.borderedProminent)
.padding(.vertical, 4)
}
}
.buttonStyle(PlainButtonStyle())
} header: {
Text("signin.title.enterServerAddress", comment: "Enter server address")
} footer: {
if let instructionsUrlString = self.instructionsUrlString,
let instructionsUrl = URL(string: instructionsUrlString) {
HStack {
Spacer()
Link(NSLocalizedString("signin.title.howToJoinLink", comment: "How to join Pixelfed"), destination: instructionsUrl)
.font(.caption)
}
}
}
Section("signin.title.chooseServer") {
if self.instances.isEmpty {
HStack {
Spacer()
LoadingIndicator()
Spacer()
}
}
ForEach(self.instances, id: \.uri) { instance in
InstanceRowView(instance: instance) { uri in
let baseAddress = self.getServerAddress(uri: uri)
self.signIn(baseAddress: baseAddress)
}
}
}
}
.onFirstAppear {
let metadata = await AppMetadataService.shared.metadata()
self.instances = await self.client.instances.instances(instanceUrls: metadata.instances)
self.instructionsUrlString = metadata.instructionsUrl
}
.navigationTitle("signin.navigationBar.title")
.navigationBarTitleDisplayMode(.inline)
}
private func signIn(baseAddress: String) {
Task {
do {
let authorizationSession = AuthorizationSession()
try await AuthorizationService.shared.sign(in: baseAddress, session: authorizationSession) { accountData in
onSignedIn?(accountData)
DispatchQueue.main.sync {
dismiss()
}
}
} catch let error as AuthorisationError {
ErrorService.shared.handle(error, message: error.localizedDescription, showToastr: true)
}
catch {
ErrorService.shared.handle(error, message: "signin.error.communicationFailed", showToastr: true)
}
}
}
private func getServerAddress(uri: String) -> String {
var address = uri.trimmingCharacters(in: .whitespacesAndNewlines)
address = address.trimmingCharacters(in: CharacterSet.init(charactersIn: "/\\"))
if !address.starts(with: "https://") {
return "https://\(address)"
}
return address
}
}