Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reverse alias creation check #160

Merged
merged 3 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/simple-login/swift-package",
"state" : {
"revision" : "d7e1661c5ab4fba1a5be8b166fbf55911c5786e3",
"version" : "2.1.1"
"revision" : "b682be9c14af4b4b660ad2213b3601d899236977",
"version" : "2.1.2"
}
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
//

import AuthenticationServices
import BetterSafariView
import SimpleLoginPackage
import SwiftUI

Expand Down Expand Up @@ -48,7 +49,9 @@ struct LogInWithProtonButtonView: View {
.webAuthenticationSession(isPresented: isShowingSafariView) {
// swiftlint:disable:next force_unwrapping
let url = URL(string: selectedUrlString ?? "") ?? URL(string: "https://simplelogin.io")!
return .init(url: url, callbackURLScheme: "auth.simplelogin", onCompletion: handleResult)
return .init(url: url,
callbackURLScheme: "auth.simplelogin",
onCompletion: handleResult).prefersEphemeralWebBrowserSession(true)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ struct AccountView: View {
return .init(url: url,
callbackURLScheme: "auth.simplelogin",
onCompletion: viewModel.handleLinkingResult)
.prefersEphemeralWebBrowserSession(true)
}
// swiftlint:disable:next force_unwrapping
return .init(url: URL(string: "https://simplelogin.io")!,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,8 @@ extension UserInfo {
isPremium: false,
inTrial: false,
maxAliasFreePlan: 0,
connectedProtonAddress: nil)
connectedProtonAddress: nil,
canCreateReverseAlias: false)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ struct UpgradeView_Previews: PreviewProvider {
private let kFreeCapacities: [Capacity] = [
.fifteenAliases,
.unlimitedBandWidth,
.unlimitedReplySend,
.oneMailbox,
.browserExtensions,
.totp,
Expand All @@ -197,6 +196,7 @@ private let kFreeCapacities: [Capacity] = [
private let kPremiumCapacities: [Capacity] = [
.everythingInFreePlan,
.unlimitedAliases,
.unlimitedReplySend,
.unlimitedMailboxes,
.unlimitedDomains,
.catchAllDomain,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ struct AliasContactsView: View {
@State private var copiedText: String?
@State private var newContactEmail = ""
@State private var selectedUrlString: String?
private let onUpgrade: () -> Void

init(alias: Alias, session: Session) {
init(alias: Alias, session: Session, onUpgrade: @escaping () -> Void) {
_viewModel = StateObject(wrappedValue: .init(alias: alias, session: session))
self.onUpgrade = onUpgrade
}

var body: some View {
Expand Down Expand Up @@ -80,6 +82,12 @@ struct AliasContactsView: View {
newContactEmail = ""
}
}
.alert("Please upgrade to create contacts",
isPresented: $viewModel.shouldUpgrade,
actions: {
Button("Upgrade", role: nil, action: onUpgrade)
Button("Cancel", role: .cancel) {}
})
.betterSafariView(urlString: $selectedUrlString)
.alertToastCopyMessage(isPresenting: showingCopyAlert, message: copiedText)
.alertToastError($viewModel.error)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ final class AliasContactsViewModel: ObservableObject {
@Published private(set) var isFetchingContacts = false
@Published private(set) var contacts: [Contact] = []
@Published private(set) var createdContact: Contact?
@Published var shouldUpgrade = false
@Published var isLoading = false
@Published var error: Error?

Expand Down Expand Up @@ -122,19 +123,24 @@ final class AliasContactsViewModel: ObservableObject {

func createContact(contactEmail: String) {
guard !isLoading else { return }
Task { @MainActor in
Task { @MainActor [weak self] in
guard let self else { return }
defer { isLoading = false }
isLoading = true
do {
guard try await canCreateReverseAlias() else {
shouldUpgrade = true
return
}
let createContactEndpoint = CreateContactEndpoint(apiKey: session.apiKey.value,
aliasID: alias.id,
email: contactEmail)
let createdContact = try await session.execute(createContactEndpoint)
if createdContact.existed {
self.error = SLError.contactExists
error = SLError.contactExists
} else {
self.createdContact = createdContact
self.contacts.insert(createdContact, at: 0)
contacts.insert(createdContact, at: 0)
}
} catch {
self.error = error
Expand All @@ -146,3 +152,11 @@ final class AliasContactsViewModel: ObservableObject {
self.createdContact = nil
}
}

private extension AliasContactsViewModel {
func canCreateReverseAlias() async throws -> Bool {
let userInfoEndpoint = GetUserInfoEndpoint(apiKey: session.apiKey.value)
let userInfo = try await session.execute(userInfoEndpoint)
return userInfo.canCreateReverseAlias
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@ struct AliasDetailWrapperView: View {
private let session: Session
let onUpdateAlias: (Alias) -> Void
let onDeleteAlias: (Alias) -> Void
let onUpgrade: () -> Void

init(selectedAlias: Binding<Alias?>,
session: Session,
onUpdateAlias: @escaping (Alias) -> Void,
onDeleteAlias: @escaping (Alias) -> Void) {
onDeleteAlias: @escaping (Alias) -> Void,
onUpgrade: @escaping () -> Void) {
self._selectedAlias = selectedAlias
self.session = session
self.onUpdateAlias = onUpdateAlias
self.onDeleteAlias = onDeleteAlias
self.onUpgrade = onUpgrade
}

var body: some View {
Expand All @@ -42,7 +45,8 @@ struct AliasDetailWrapperView: View {
dismiss()
// Show placeholder view in master detail mode (iPad)
self.selectedAlias = nil
})
},
onUpgrade: onUpgrade)
} else {
DetailPlaceholderView.aliasDetails
}
Expand All @@ -56,22 +60,26 @@ struct AliasDetailView: View {
@State private var showingAliasEmailSheet = false
@State private var showingAliasFullScreen = false
@State private var copiedText: String?
let onUpgrade: () -> Void

init(alias: Alias,
session: Session,
onUpdateAlias: @escaping (Alias) -> Void,
onDeleteAlias: @escaping (Alias) -> Void) {
onDeleteAlias: @escaping (Alias) -> Void,
onUpgrade: @escaping () -> Void) {
_viewModel = StateObject(wrappedValue: .init(alias: alias,
session: session,
onUpdateAlias: onUpdateAlias,
onDeleteAlias: onDeleteAlias))
self.onUpgrade = onUpgrade
}

var body: some View {
List {
ActionsSection(viewModel: viewModel,
copiedText: $copiedText,
enterFullScreen: showAliasInFullScreen)
enterFullScreen: showAliasInFullScreen,
onUpgrade: onUpgrade)
NotesSection(viewModel: viewModel)
MailboxesSection(viewModel: viewModel)
NameSection(viewModel: viewModel)
Expand Down Expand Up @@ -132,6 +140,7 @@ private struct ActionsSection: View {
@ObservedObject var viewModel: AliasDetailViewModel
@Binding var copiedText: String?
var enterFullScreen: () -> Void
let onUpgrade: () -> Void

private var alias: Alias { viewModel.alias }

Expand Down Expand Up @@ -214,7 +223,7 @@ private struct ActionsSection: View {
NavigationLink(
isActive: $showingContacts,
destination: {
AliasContactsView(alias: alias, session: viewModel.session)
AliasContactsView(alias: alias, session: viewModel.session, onUpgrade: onUpgrade)
},
label: {
button(
Expand Down
15 changes: 11 additions & 4 deletions SimpleLogin/SimpleLogin/Modules/Main/Aliases/AliasesView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct AliasesView: View {
@State private var selectedAlias: Alias?
@State private var aliasToShowDetails: Alias?
@State private var selectedLink: Link?
private let onUpgrade: () -> Void

enum Modal {
case search, create
Expand All @@ -33,11 +34,13 @@ struct AliasesView: View {
init(session: Session,
reachabilityObserver: ReachabilityObserver,
managedObjectContext: NSManagedObjectContext,
createdAlias: Binding<Alias?>) {
createdAlias: Binding<Alias?>,
onUpgrade: @escaping () -> Void) {
_viewModel = StateObject(wrappedValue: .init(session: session,
reachabilityObserver: reachabilityObserver,
managedObjectContext: managedObjectContext))
_createdAlias = createdAlias
self.onUpgrade = onUpgrade
}

var body: some View {
Expand Down Expand Up @@ -69,7 +72,8 @@ struct AliasesView: View {
createdAlias = nil
}
viewModel.remove(alias: deletedAlias)
})
},
onUpgrade: onUpgrade)
.ignoresSafeArea(.keyboard)
.onAppear {
if UIDevice.current.userInterfaceIdiom != .phone {
Expand All @@ -86,7 +90,9 @@ struct AliasesView: View {
selection: $selectedLink,
destination: {
if let selectedAlias = selectedAlias {
AliasContactsView(alias: selectedAlias, session: viewModel.session)
AliasContactsView(alias: selectedAlias,
session: viewModel.session,
onUpgrade: onUpgrade)
.onAppear {
if UIDevice.current.userInterfaceIdiom != .phone {
selectedLink = nil
Expand Down Expand Up @@ -191,7 +197,8 @@ struct AliasesView: View {
createdAlias = nil
}
viewModel.remove(alias: deletedAlias)
})
},
onUpgrade: onUpgrade)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ struct SearchAliasesView: UIViewControllerRepresentable {
let session: Session
let onUpdateAlias: (Alias) -> Void
let onDeleteAlias: (Alias) -> Void
let onUpgrade: () -> Void

func makeUIViewController(context: Context) -> UINavigationController {
let viewController = SearchAliasesViewController(session: session,
reachabilityObserver: reachabilityObserver,
managedObjectContext: managedObjectContext,
onUpdateAlias: onUpdateAlias,
onDeleteAlias: onDeleteAlias)
onDeleteAlias: onDeleteAlias,
onUpgrade: onUpgrade)
let navigationController = UINavigationController(rootViewController: viewController)
navigationController.view.tintColor = .slPurple
return navigationController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,20 @@ final class SearchAliasesViewController: BaseViewController {
private let viewModel: SearchAliasesViewModel
let onUpdateAlias: (Alias) -> Void
let onDeleteAlias: (Alias) -> Void
let onUpgrade: () -> Void

init(session: Session,
reachabilityObserver: ReachabilityObserver,
managedObjectContext: NSManagedObjectContext,
onUpdateAlias: @escaping (Alias) -> Void,
onDeleteAlias: @escaping (Alias) -> Void) {
onDeleteAlias: @escaping (Alias) -> Void,
onUpgrade: @escaping () -> Void) {
self.viewModel = .init(session: session,
reachabilityObserver: reachabilityObserver,
managedObjectContext: managedObjectContext)
self.onUpdateAlias = onUpdateAlias
self.onDeleteAlias = onDeleteAlias
self.onUpgrade = onUpgrade
super.init(nibName: nil, bundle: nil)
}

Expand Down Expand Up @@ -80,7 +83,8 @@ final class SearchAliasesViewController: BaseViewController {
guard let self = self else { return }
self.onDeleteAlias(deletedAlias)
self.viewModel.remove(alias: alias)
})
},
onUpgrade: onUpgrade)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: dismissPresentedViewController) {
Expand All @@ -96,7 +100,8 @@ final class SearchAliasesViewController: BaseViewController {
private func showAliasContacts(_ alias: Alias) {
let aliasContactsView = AliasContactsView(
alias: alias,
session: viewModel.session)
session: viewModel.session,
onUpgrade: onUpgrade)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button(action: dismissPresentedViewController) {
Expand Down
13 changes: 8 additions & 5 deletions SimpleLogin/SimpleLogin/Modules/Main/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ struct MainView: View {
AliasesView(session: session,
reachabilityObserver: reachabilityObserver,
managedObjectContext: managedObjectContext,
createdAlias: $createdAlias)
createdAlias: $createdAlias,
onUpgrade: beginUpgradeFlow)
.tag(TabBarItem.aliases)

AdvancedView()
Expand Down Expand Up @@ -132,10 +133,7 @@ struct MainView: View {
self.selectedItem = .aliases
},
onCancel: nil,
onOpenMyAccount: {
upgradeNeeded = true
selectedItem = .myAccount
})
onOpenMyAccount: beginUpgradeFlow)
case .none:
EmptyView()
}
Expand All @@ -148,6 +146,11 @@ struct MainView: View {
primaryButton: .default(Text("Try again"), action: viewModel.biometricallyAuthenticate),
secondaryButton: .destructive(Text("Log out"), action: onLogOut))
}

private func beginUpgradeFlow() {
upgradeNeeded = true
selectedItem = .myAccount
}
}

final class MainViewModel: ObservableObject {
Expand Down
Loading