mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-24 17:20:59 +00:00
Refactoring
This commit is contained in:
parent
2745f2470d
commit
ceff3fd4c9
8 changed files with 91 additions and 110 deletions
7
Extensions/URL+Extensions.swift
Normal file
7
Extensions/URL+Extensions.swift
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Copyright © 2020 Metabolist. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
extension URL: Identifiable {
|
||||
public var id: String { absoluteString }
|
||||
}
|
|
@ -13,7 +13,20 @@ public enum AccessTokenEndpoint {
|
|||
code: String?,
|
||||
redirectURI: String?
|
||||
)
|
||||
case accounts(username: String, email: String, password: String, reason: String?)
|
||||
case accounts(Registration)
|
||||
}
|
||||
|
||||
public extension AccessTokenEndpoint {
|
||||
struct Registration {
|
||||
public var username = ""
|
||||
public var email = ""
|
||||
public var password = ""
|
||||
public var locale = "en"
|
||||
public var reason = ""
|
||||
public var agreement = false
|
||||
|
||||
public init() {}
|
||||
}
|
||||
}
|
||||
|
||||
extension AccessTokenEndpoint: Endpoint {
|
||||
|
@ -56,15 +69,17 @@ extension AccessTokenEndpoint: Endpoint {
|
|||
params["redirect_uri"] = redirectURI
|
||||
|
||||
return params
|
||||
case let .accounts(username, email, password, reason):
|
||||
case let .accounts(registration):
|
||||
var params: [String: Any] = [
|
||||
"username": username,
|
||||
"email": email,
|
||||
"password": password,
|
||||
"locale": Locale.autoupdatingCurrent.languageCode ?? "en", // TODO: probably need to map
|
||||
"agreement": true]
|
||||
"username": registration.username,
|
||||
"email": registration.email,
|
||||
"password": registration.password,
|
||||
"locale": registration.locale,
|
||||
"agreement": registration.agreement]
|
||||
|
||||
params["reason"] = reason
|
||||
if !registration.reason.isEmpty {
|
||||
params["reason"] = registration.reason
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
D0030982250C6C8500EACB32 /* URL+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0030981250C6C8500EACB32 /* URL+Extensions.swift */; };
|
||||
D01F41D724F880C400D55A2D /* StatusTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D01F41D424F880C400D55A2D /* StatusTableViewCell.xib */; };
|
||||
D01F41D824F880C400D55A2D /* StatusTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41D524F880C400D55A2D /* StatusTableViewCell.swift */; };
|
||||
D01F41D924F880C400D55A2D /* TouchFallthroughTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01F41D624F880C400D55A2D /* TouchFallthroughTextView.swift */; };
|
||||
|
@ -80,6 +81,7 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
D0030981250C6C8500EACB32 /* URL+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Extensions.swift"; sourceTree = "<group>"; };
|
||||
D01F41D424F880C400D55A2D /* StatusTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = StatusTableViewCell.xib; sourceTree = "<group>"; };
|
||||
D01F41D524F880C400D55A2D /* StatusTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusTableViewCell.swift; sourceTree = "<group>"; };
|
||||
D01F41D624F880C400D55A2D /* TouchFallthroughTextView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TouchFallthroughTextView.swift; sourceTree = "<group>"; };
|
||||
|
@ -302,6 +304,7 @@
|
|||
D0C7D46A24F76169001EBDBB /* String+Extensions.swift */,
|
||||
D0C7D46C24F76169001EBDBB /* UIColor+Extensions.swift */,
|
||||
D0C7D46F24F76169001EBDBB /* View+Extensions.swift */,
|
||||
D0030981250C6C8500EACB32 /* URL+Extensions.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
|
@ -505,6 +508,7 @@
|
|||
D0C7D49824F7616A001EBDBB /* CustomEmojiText.swift in Sources */,
|
||||
D01F41E424F8889700D55A2D /* AttachmentsView.swift in Sources */,
|
||||
D0BEB21124FA2A91001B0F04 /* EditFilterView.swift in Sources */,
|
||||
D0030982250C6C8500EACB32 /* URL+Extensions.swift in Sources */,
|
||||
D0C7D4C424F7616A001EBDBB /* AppDelegate.swift in Sources */,
|
||||
D0C7D49924F7616A001EBDBB /* AddIdentityView.swift in Sources */,
|
||||
D0C7D4C324F7616A001EBDBB /* MetatextApp.swift in Sources */,
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
// Copyright © 2020 Metabolist. All rights reserved.
|
||||
|
||||
import MastodonAPI
|
||||
|
||||
public typealias Registration = AccessTokenEndpoint.Registration
|
|
@ -37,18 +37,12 @@ public extension AllIdentitiesService {
|
|||
: nil)
|
||||
}
|
||||
|
||||
func createIdentity(
|
||||
id: UUID,
|
||||
url: URL,
|
||||
username: String,
|
||||
email: String,
|
||||
password: String,
|
||||
reason: String?) -> AnyPublisher<Never, Error> {
|
||||
func createIdentity(id: UUID, url: URL, registration: Registration) -> AnyPublisher<Never, Error> {
|
||||
createIdentity(
|
||||
id: id,
|
||||
url: url,
|
||||
authenticationPublisher: AuthenticationService(url: url, environment: environment)
|
||||
.register(username: username, email: email, password: password, reason: reason))
|
||||
.register(registration))
|
||||
}
|
||||
|
||||
func deleteIdentity(id: UUID) -> AnyPublisher<Never, Error> {
|
||||
|
|
|
@ -29,10 +29,7 @@ extension AuthenticationService {
|
|||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func register(username: String,
|
||||
email: String,
|
||||
password: String,
|
||||
reason: String?) -> AnyPublisher<(AppAuthorization, AccessToken), Error> {
|
||||
func register(_ registration: Registration) -> AnyPublisher<(AppAuthorization, AccessToken), Error> {
|
||||
let authorization = appAuthorization()
|
||||
.share()
|
||||
|
||||
|
@ -49,12 +46,7 @@ extension AuthenticationService {
|
|||
.flatMap { accessToken -> AnyPublisher<AccessToken, Error> in
|
||||
mastodonAPIClient.accessToken = accessToken.accessToken
|
||||
|
||||
return mastodonAPIClient.request(
|
||||
AccessTokenEndpoint.accounts(
|
||||
username: username,
|
||||
email: email,
|
||||
password: password,
|
||||
reason: reason))
|
||||
return mastodonAPIClient.request(AccessTokenEndpoint.accounts(registration))
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
})
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
import Combine
|
||||
import Foundation
|
||||
import Mastodon
|
||||
import MastodonAPI
|
||||
import ServiceLayer
|
||||
|
||||
public enum RegistrationError: Error {
|
||||
|
@ -15,14 +14,9 @@ public final class RegistrationViewModel: ObservableObject {
|
|||
public let serverRulesURL: URL
|
||||
public let termsOfServiceURL: URL
|
||||
@Published public var alertItem: AlertItem?
|
||||
@Published public var username = ""
|
||||
@Published public var email = ""
|
||||
@Published public var password = ""
|
||||
@Published public var registration = Registration()
|
||||
@Published public var passwordConfirmation = ""
|
||||
@Published public var reason = ""
|
||||
@Published public var passwordsMatch = false
|
||||
@Published public var agreement = false
|
||||
@Published public private(set) var registerButtonEnabled = false
|
||||
@Published public private(set) var registerDisabled = true
|
||||
@Published public private(set) var registering = false
|
||||
|
||||
private let url: URL
|
||||
|
@ -36,34 +30,27 @@ public final class RegistrationViewModel: ObservableObject {
|
|||
self.termsOfServiceURL = url.appendingPathComponent("terms")
|
||||
self.allIdentitiesService = allIdentitiesService
|
||||
|
||||
Publishers.CombineLatest4($username, $email, $password, $reason)
|
||||
.map { username, email, password, reason in
|
||||
!username.isEmpty
|
||||
&& !email.isEmpty
|
||||
&& !password.isEmpty
|
||||
&& (!instance.approvalRequired || !reason.isEmpty)
|
||||
$registration
|
||||
.map {
|
||||
$0.username.isEmpty
|
||||
|| $0.email.isEmpty
|
||||
|| $0.password.isEmpty
|
||||
|| ($0.reason.isEmpty && instance.approvalRequired)
|
||||
|| !$0.agreement
|
||||
}
|
||||
.combineLatest($agreement)
|
||||
.map { $0 && $1 }
|
||||
.assign(to: &$registerButtonEnabled)
|
||||
.assign(to: &$registerDisabled)
|
||||
}
|
||||
}
|
||||
|
||||
public extension RegistrationViewModel {
|
||||
func registerTapped() {
|
||||
guard password == passwordConfirmation else {
|
||||
guard registration.password == passwordConfirmation else {
|
||||
alertItem = AlertItem(error: RegistrationError.passwordConfirmationMismatch)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
allIdentitiesService.createIdentity(
|
||||
id: UUID(),
|
||||
url: url,
|
||||
username: username,
|
||||
email: email,
|
||||
password: password,
|
||||
reason: reason)
|
||||
allIdentitiesService.createIdentity(id: UUID(), url: url, registration: registration)
|
||||
.handleEvents(receiveSubscription: { [weak self] _ in self?.registering = true })
|
||||
.mapError { error -> Error in
|
||||
if error is URLError {
|
||||
|
|
|
@ -6,75 +6,52 @@ import ViewModels
|
|||
struct RegistrationView: View {
|
||||
@StateObject var viewModel: RegistrationViewModel
|
||||
|
||||
@State private var presentWebView = false
|
||||
@State private var toReview = ToReview.serverRules
|
||||
@State private var presentURL: URL?
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section {
|
||||
HStack {
|
||||
TextField("registration.username", text: $viewModel.username)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
Text("@" + viewModel.instance.uri)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
TextField("registration.email", text: $viewModel.email)
|
||||
HStack {
|
||||
TextField("registration.username", text: $viewModel.registration.username)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.keyboardType(.emailAddress)
|
||||
SecureField("registration.password", text: $viewModel.password)
|
||||
SecureField("registration.password-confirmation", text: $viewModel.passwordConfirmation)
|
||||
if viewModel.instance.approvalRequired {
|
||||
VStack(alignment: .leading) {
|
||||
Text("registration.reason-\(viewModel.instance.uri)")
|
||||
TextEditor(text: $viewModel.reason)
|
||||
}
|
||||
}
|
||||
Button("registration.server-rules") {
|
||||
toReview = .serverRules
|
||||
presentWebView = true
|
||||
}
|
||||
Button("registration.terms-of-service") {
|
||||
toReview = .termsOfService
|
||||
presentWebView = true
|
||||
}
|
||||
Toggle("registration.agree-to-server-rules-and-terms-of-service",
|
||||
isOn: $viewModel.agreement)
|
||||
Text("@" + viewModel.instance.uri)
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
Section {
|
||||
Group {
|
||||
if viewModel.registering {
|
||||
ProgressView()
|
||||
} else {
|
||||
Button(viewModel.instance.approvalRequired
|
||||
? "add-identity.request-invite"
|
||||
: "add-identity.join",
|
||||
action: viewModel.registerTapped)
|
||||
.disabled(!viewModel.registerButtonEnabled)
|
||||
}
|
||||
TextField("registration.email", text: $viewModel.registration.email)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.keyboardType(.emailAddress)
|
||||
SecureField("registration.password", text: $viewModel.registration.password)
|
||||
SecureField("registration.password-confirmation", text: $viewModel.passwordConfirmation)
|
||||
if viewModel.instance.approvalRequired {
|
||||
VStack(alignment: .leading) {
|
||||
Text("registration.reason-\(viewModel.instance.uri)")
|
||||
TextEditor(text: $viewModel.registration.reason)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
}
|
||||
Button("registration.server-rules") {
|
||||
presentURL = viewModel.serverRulesURL
|
||||
}
|
||||
Button("registration.terms-of-service") {
|
||||
presentURL = viewModel.termsOfServiceURL
|
||||
}
|
||||
Toggle("registration.agree-to-server-rules-and-terms-of-service",
|
||||
isOn: $viewModel.registration.agreement)
|
||||
Group {
|
||||
if viewModel.registering {
|
||||
ProgressView()
|
||||
} else {
|
||||
Button(viewModel.instance.approvalRequired
|
||||
? "add-identity.request-invite"
|
||||
: "add-identity.join",
|
||||
action: viewModel.registerTapped)
|
||||
.disabled(viewModel.registerDisabled)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
}
|
||||
.alertItem($viewModel.alertItem)
|
||||
.sheet(isPresented: $presentWebView) { () -> SafariView in
|
||||
let url: URL
|
||||
|
||||
switch toReview {
|
||||
case .serverRules: url = viewModel.serverRulesURL
|
||||
case .termsOfService: url = viewModel.termsOfServiceURL
|
||||
}
|
||||
|
||||
return SafariView(url: url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension RegistrationView {
|
||||
enum ToReview {
|
||||
case serverRules
|
||||
case termsOfService
|
||||
.sheet(item: $presentURL) { SafariView(url: $0) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue