Refactor alerts to use latest API (#320)
This commit is contained in:
parent
de7e574fec
commit
7198150f00
|
@ -16,6 +16,8 @@ private struct ErrorAlert: Identifiable {
|
||||||
final class ErrorHandler: ObservableObject {
|
final class ErrorHandler: ObservableObject {
|
||||||
static let shared = ErrorHandler()
|
static let shared = ErrorHandler()
|
||||||
|
|
||||||
|
@Published fileprivate var isPresented = false
|
||||||
|
|
||||||
@Published fileprivate var currentAlert: ErrorAlert?
|
@Published fileprivate var currentAlert: ErrorAlert?
|
||||||
|
|
||||||
func handle(_ error: Error, title: String? = nil, onDismiss: (() -> Void)? = nil) {
|
func handle(_ error: Error, title: String? = nil, onDismiss: (() -> Void)? = nil) {
|
||||||
|
@ -24,6 +26,7 @@ final class ErrorHandler: ObservableObject {
|
||||||
message: AppError(error).localizedDescription,
|
message: AppError(error).localizedDescription,
|
||||||
dismissAction: onDismiss
|
dismissAction: onDismiss
|
||||||
)
|
)
|
||||||
|
isPresented = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func handle(title: String, message: String, onDismiss: (() -> Void)? = nil) {
|
func handle(title: String, message: String, onDismiss: (() -> Void)? = nil) {
|
||||||
|
@ -32,6 +35,7 @@ final class ErrorHandler: ObservableObject {
|
||||||
message: message,
|
message: message,
|
||||||
dismissAction: onDismiss
|
dismissAction: onDismiss
|
||||||
)
|
)
|
||||||
|
isPresented = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,14 +53,18 @@ struct HandleErrorsByShowingAlertViewModifier: ViewModifier {
|
||||||
// other .alert modifiers inside of content would not work anymore
|
// other .alert modifiers inside of content would not work anymore
|
||||||
.background(
|
.background(
|
||||||
EmptyView()
|
EmptyView()
|
||||||
.alert(item: $errorHandler.currentAlert) { currentAlert in
|
.alert(
|
||||||
Alert(
|
errorHandler.currentAlert?.title ?? Unlocalized.appName,
|
||||||
title: Text(currentAlert.title ?? Unlocalized.appName),
|
isPresented: $errorHandler.isPresented,
|
||||||
message: Text(currentAlert.message.withTrailingDot),
|
presenting: errorHandler.currentAlert
|
||||||
dismissButton: .cancel(Text(L10n.Global.Strings.ok)) {
|
) { alert in
|
||||||
currentAlert.dismissAction?()
|
Button(role: .cancel) {
|
||||||
|
alert.dismissAction?()
|
||||||
|
} label: {
|
||||||
|
Text(L10n.Global.Strings.ok)
|
||||||
}
|
}
|
||||||
)
|
} message: { alert in
|
||||||
|
Text(alert.message.withTrailingDot)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,8 +74,12 @@ extension AddHostView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.alert(isPresented: $viewModel.isAskingOverwrite, content: alertOverwriteExistingProfile)
|
}.alert(
|
||||||
.onAppear(perform: requestResourcePermissions)
|
L10n.AddProfile.Shared.title,
|
||||||
|
isPresented: $viewModel.isAskingOverwrite,
|
||||||
|
actions: alertOverwriteActions,
|
||||||
|
message: alertOverwriteMessage
|
||||||
|
).onAppear(perform: requestResourcePermissions)
|
||||||
.onDisappear(perform: dropResourcePermissions)
|
.onDisappear(perform: dropResourcePermissions)
|
||||||
.navigationTitle(L10n.AddProfile.Shared.title)
|
.navigationTitle(L10n.AddProfile.Shared.title)
|
||||||
.themeSecondaryView()
|
.themeSecondaryView()
|
||||||
|
@ -158,15 +162,21 @@ extension AddHostView {
|
||||||
url.stopAccessingSecurityScopedResource()
|
url.stopAccessingSecurityScopedResource()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func alertOverwriteExistingProfile() -> Alert {
|
@ViewBuilder
|
||||||
Alert(
|
private func alertOverwriteActions() -> some View {
|
||||||
title: Text(L10n.AddProfile.Shared.title),
|
Button(role: .destructive) {
|
||||||
message: Text(L10n.AddProfile.Shared.Alerts.Overwrite.message),
|
|
||||||
primaryButton: .destructive(Text(L10n.Global.Strings.ok)) {
|
|
||||||
processProfile(replacingExisting: true)
|
processProfile(replacingExisting: true)
|
||||||
},
|
} label: {
|
||||||
secondaryButton: .cancel(Text(L10n.Global.Strings.cancel))
|
Text(L10n.Global.Strings.ok)
|
||||||
)
|
}
|
||||||
|
Button(role: .cancel) {
|
||||||
|
} label: {
|
||||||
|
Text(L10n.Global.Strings.cancel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func alertOverwriteMessage() -> some View {
|
||||||
|
Text(L10n.AddProfile.Shared.Alerts.Overwrite.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func processProfile(replacingExisting: Bool) {
|
private func processProfile(replacingExisting: Bool) {
|
||||||
|
|
|
@ -77,8 +77,12 @@ extension AddProviderView {
|
||||||
} label: {
|
} label: {
|
||||||
themeSaveButtonLabel()
|
themeSaveButtonLabel()
|
||||||
}
|
}
|
||||||
}.alert(isPresented: $viewModel.isAskingOverwrite, content: alertOverwriteExistingProfile)
|
}.alert(
|
||||||
.navigationTitle(providerMetadata.fullName)
|
L10n.AddProfile.Shared.title,
|
||||||
|
isPresented: $viewModel.isAskingOverwrite,
|
||||||
|
actions: alertOverwriteActions,
|
||||||
|
message: alertOverwriteMessage
|
||||||
|
).navigationTitle(providerMetadata.fullName)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var hiddenAccountLink: some View {
|
private var hiddenAccountLink: some View {
|
||||||
|
@ -90,15 +94,21 @@ extension AddProviderView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func alertOverwriteExistingProfile() -> Alert {
|
@ViewBuilder
|
||||||
return Alert(
|
private func alertOverwriteActions() -> some View {
|
||||||
title: Text(L10n.AddProfile.Shared.title),
|
Button(role: .destructive) {
|
||||||
message: Text(L10n.AddProfile.Shared.Alerts.Overwrite.message),
|
|
||||||
primaryButton: .destructive(Text(L10n.Global.Strings.ok)) {
|
|
||||||
saveProfile(replacingExisting: true)
|
saveProfile(replacingExisting: true)
|
||||||
},
|
} label: {
|
||||||
secondaryButton: .cancel(Text(L10n.Global.Strings.cancel))
|
Text(L10n.Global.Strings.ok)
|
||||||
)
|
}
|
||||||
|
Button(role: .cancel) {
|
||||||
|
} label: {
|
||||||
|
Text(L10n.Global.Strings.cancel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func alertOverwriteMessage() -> some View {
|
||||||
|
Text(L10n.AddProfile.Shared.Alerts.Overwrite.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func saveProfile(replacingExisting: Bool) {
|
private func saveProfile(replacingExisting: Bool) {
|
||||||
|
|
|
@ -53,6 +53,8 @@ extension DiagnosticsView {
|
||||||
|
|
||||||
@State private var isReportingIssue = false
|
@State private var isReportingIssue = false
|
||||||
|
|
||||||
|
@State private var isAlertPresented = false
|
||||||
|
|
||||||
@State private var alertType: AlertType?
|
@State private var alertType: AlertType?
|
||||||
|
|
||||||
private let vpnProtocol: VPNProtocolType = .openVPN
|
private let vpnProtocol: VPNProtocolType = .openVPN
|
||||||
|
@ -75,17 +77,26 @@ extension DiagnosticsView {
|
||||||
issueReporterSection
|
issueReporterSection
|
||||||
}
|
}
|
||||||
}.sheet(isPresented: $isReportingIssue, content: reportIssueView)
|
}.sheet(isPresented: $isReportingIssue, content: reportIssueView)
|
||||||
.alert(item: $alertType, content: presentedAlert)
|
.alert(
|
||||||
|
L10n.ReportIssue.Alert.title,
|
||||||
|
isPresented: $isAlertPresented,
|
||||||
|
presenting: alertType,
|
||||||
|
actions: alertActions,
|
||||||
|
message: alertMessage
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func presentedAlert(_ alertType: AlertType) -> Alert {
|
private func alertActions(_ alertType: AlertType) -> some View {
|
||||||
|
Button(role: .cancel) {
|
||||||
|
} label: {
|
||||||
|
Text(L10n.Global.Strings.ok)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func alertMessage(_ alertType: AlertType) -> some View {
|
||||||
switch alertType {
|
switch alertType {
|
||||||
case .emailNotConfigured:
|
case .emailNotConfigured:
|
||||||
return Alert(
|
return Text(L10n.Global.Messages.emailNotConfigured)
|
||||||
title: Text(L10n.ReportIssue.Alert.title),
|
|
||||||
message: Text(L10n.Global.Messages.emailNotConfigured),
|
|
||||||
dismissButton: .cancel(Text(L10n.Global.Strings.ok))
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,6 +191,7 @@ extension DiagnosticsView.OpenVPNView {
|
||||||
}
|
}
|
||||||
guard URL.open(url) else {
|
guard URL.open(url) else {
|
||||||
alertType = .emailNotConfigured
|
alertType = .emailNotConfigured
|
||||||
|
isAlertPresented = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,8 @@ struct DonateView: View {
|
||||||
|
|
||||||
@ObservedObject private var productManager: ProductManager
|
@ObservedObject private var productManager: ProductManager
|
||||||
|
|
||||||
|
@State private var isAlertPresented = false
|
||||||
|
|
||||||
@State private var alertType: AlertType?
|
@State private var alertType: AlertType?
|
||||||
|
|
||||||
@State private var pendingDonationIdentifier: String?
|
@State private var pendingDonationIdentifier: String?
|
||||||
|
@ -57,7 +59,13 @@ struct DonateView: View {
|
||||||
.disabled(pendingDonationIdentifier != nil)
|
.disabled(pendingDonationIdentifier != nil)
|
||||||
}.themeSecondaryView()
|
}.themeSecondaryView()
|
||||||
.navigationTitle(L10n.Donate.title)
|
.navigationTitle(L10n.Donate.title)
|
||||||
.alert(item: $alertType, content: presentedAlert)
|
.alert(
|
||||||
|
L10n.Donate.title,
|
||||||
|
isPresented: $isAlertPresented,
|
||||||
|
presenting: alertType,
|
||||||
|
actions: alertActions,
|
||||||
|
message: alertMessage
|
||||||
|
)
|
||||||
|
|
||||||
// reloading
|
// reloading
|
||||||
.onAppear {
|
.onAppear {
|
||||||
|
@ -69,14 +77,20 @@ struct DonateView: View {
|
||||||
}.themeAnimation(on: productManager.isRefreshingProducts)
|
}.themeAnimation(on: productManager.isRefreshingProducts)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func presentedAlert(_ alertType: AlertType) -> Alert {
|
private func alertActions(_ alertType: AlertType) -> some View {
|
||||||
switch alertType {
|
switch alertType {
|
||||||
case .thankYou:
|
case .thankYou:
|
||||||
return Alert(
|
return Button(role: .cancel) {
|
||||||
title: Text(L10n.Donate.Alerts.Purchase.Success.title),
|
} label: {
|
||||||
message: Text(L10n.Donate.Alerts.Purchase.Success.message),
|
Text(L10n.Global.Strings.ok)
|
||||||
dismissButton: .cancel(Text(L10n.Global.Strings.ok))
|
}
|
||||||
)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func alertMessage(_ alertType: AlertType) -> some View {
|
||||||
|
switch alertType {
|
||||||
|
case .thankYou:
|
||||||
|
return Text(L10n.Donate.Alerts.Purchase.Success.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,6 +138,7 @@ extension DonateView {
|
||||||
case .success(let value):
|
case .success(let value):
|
||||||
if case .done = value {
|
if case .done = value {
|
||||||
alertType = .thankYou
|
alertType = .thankYou
|
||||||
|
isAlertPresented = true
|
||||||
} else {
|
} else {
|
||||||
// cancelled
|
// cancelled
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,13 +30,16 @@ extension OrganizerView {
|
||||||
struct SceneView: View {
|
struct SceneView: View {
|
||||||
@Environment(\.scenePhase) private var scenePhase
|
@Environment(\.scenePhase) private var scenePhase
|
||||||
|
|
||||||
|
@Binding private var isAlertPresented: Bool
|
||||||
|
|
||||||
@Binding private var alertType: AlertType?
|
@Binding private var alertType: AlertType?
|
||||||
|
|
||||||
@Binding private var didHandleSubreddit: Bool
|
@Binding private var didHandleSubreddit: Bool
|
||||||
|
|
||||||
@State private var isFirstLaunch = true
|
@State private var isFirstLaunch = true
|
||||||
|
|
||||||
init(alertType: Binding<AlertType?>, didHandleSubreddit: Binding<Bool>) {
|
init(isAlertPresented: Binding<Bool>, alertType: Binding<AlertType?>, didHandleSubreddit: Binding<Bool>) {
|
||||||
|
_isAlertPresented = isAlertPresented
|
||||||
_alertType = alertType
|
_alertType = alertType
|
||||||
_didHandleSubreddit = didHandleSubreddit
|
_didHandleSubreddit = didHandleSubreddit
|
||||||
}
|
}
|
||||||
|
@ -53,6 +56,7 @@ extension OrganizerView {
|
||||||
private func onAppear() {
|
private func onAppear() {
|
||||||
guard didHandleSubreddit else {
|
guard didHandleSubreddit else {
|
||||||
alertType = .subscribeReddit
|
alertType = .subscribeReddit
|
||||||
|
isAlertPresented = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,8 @@ struct OrganizerView: View {
|
||||||
|
|
||||||
@State private var modalType: ModalType?
|
@State private var modalType: ModalType?
|
||||||
|
|
||||||
|
@State private var isAlertPresented = false
|
||||||
|
|
||||||
@State private var alertType: AlertType?
|
@State private var alertType: AlertType?
|
||||||
|
|
||||||
@State private var isHostFileImporterPresented = false
|
@State private var isHostFileImporterPresented = false
|
||||||
|
@ -81,8 +83,13 @@ struct OrganizerView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.sheet(item: $modalType, content: presentedModal)
|
}.sheet(item: $modalType, content: presentedModal)
|
||||||
.alert(item: $alertType, content: presentedAlert)
|
.alert(
|
||||||
.fileImporter(
|
Unlocalized.appName,
|
||||||
|
isPresented: $isAlertPresented,
|
||||||
|
presenting: alertType,
|
||||||
|
actions: alertActions,
|
||||||
|
message: alertMessage
|
||||||
|
).fileImporter(
|
||||||
isPresented: $isHostFileImporterPresented,
|
isPresented: $isHostFileImporterPresented,
|
||||||
allowedContentTypes: hostFileTypes,
|
allowedContentTypes: hostFileTypes,
|
||||||
allowsMultipleSelection: false,
|
allowsMultipleSelection: false,
|
||||||
|
@ -93,6 +100,7 @@ struct OrganizerView: View {
|
||||||
|
|
||||||
private var hiddenSceneView: some View {
|
private var hiddenSceneView: some View {
|
||||||
SceneView(
|
SceneView(
|
||||||
|
isAlertPresented: $isAlertPresented,
|
||||||
alertType: $alertType,
|
alertType: $alertType,
|
||||||
didHandleSubreddit: $didHandleSubreddit
|
didHandleSubreddit: $didHandleSubreddit
|
||||||
)
|
)
|
||||||
|
@ -133,26 +141,27 @@ extension OrganizerView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func presentedAlert(_ alertType: AlertType) -> Alert {
|
private func alertActions(_ alertType: AlertType) -> some View {
|
||||||
switch alertType {
|
switch alertType {
|
||||||
case .subscribeReddit:
|
case .subscribeReddit:
|
||||||
return Alert(
|
return Group {
|
||||||
title: Text(Unlocalized.Social.reddit),
|
Button(L10n.Organizer.Alerts.Reddit.Buttons.subscribe) {
|
||||||
message: Text(L10n.Organizer.Alerts.Reddit.message),
|
|
||||||
primaryButton: .default(Text(L10n.Organizer.Alerts.Reddit.Buttons.subscribe)) {
|
|
||||||
didHandleSubreddit = true
|
didHandleSubreddit = true
|
||||||
URL.open(redditURL)
|
URL.open(redditURL)
|
||||||
},
|
}
|
||||||
secondaryButton: .cancel(Text(L10n.Global.Alerts.Buttons.never)) {
|
Button(role: .cancel) {
|
||||||
didHandleSubreddit = true
|
didHandleSubreddit = true
|
||||||
}
|
} label: {
|
||||||
)
|
Text(L10n.Global.Alerts.Buttons.never)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
extension OrganizerView {
|
private func alertMessage(_ alertType: AlertType) -> some View {
|
||||||
private func presentSubscribeReddit() {
|
switch alertType {
|
||||||
alertType = .subscribeReddit
|
case .subscribeReddit:
|
||||||
|
return Text(L10n.Organizer.Alerts.Reddit.message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ import SwiftUI
|
||||||
|
|
||||||
extension ProfileView {
|
extension ProfileView {
|
||||||
struct MainMenu: View {
|
struct MainMenu: View {
|
||||||
enum ActionSheetType: Int, Identifiable {
|
enum AlertType: Int, Identifiable {
|
||||||
case uninstallVPN
|
case uninstallVPN
|
||||||
|
|
||||||
case deleteProfile
|
case deleteProfile
|
||||||
|
@ -52,14 +52,14 @@ extension ProfileView {
|
||||||
|
|
||||||
@Binding private var modalType: ModalType?
|
@Binding private var modalType: ModalType?
|
||||||
|
|
||||||
@State private var actionSheetType: ActionSheetType?
|
@State private var isAlertPresented = false
|
||||||
|
|
||||||
|
@State private var alertType: AlertType?
|
||||||
|
|
||||||
private let uninstallVPNTitle = L10n.Global.Strings.uninstall
|
private let uninstallVPNTitle = L10n.Global.Strings.uninstall
|
||||||
|
|
||||||
private let deleteProfileTitle = L10n.Global.Strings.delete
|
private let deleteProfileTitle = L10n.Global.Strings.delete
|
||||||
|
|
||||||
private let cancelTitle = L10n.Global.Strings.cancel
|
|
||||||
|
|
||||||
init(currentProfile: ObservableProfile, modalType: Binding<ModalType?>) {
|
init(currentProfile: ObservableProfile, modalType: Binding<ModalType?>) {
|
||||||
profileManager = .shared
|
profileManager = .shared
|
||||||
vpnManager = .shared
|
vpnManager = .shared
|
||||||
|
@ -70,25 +70,13 @@ extension ProfileView {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
mainView
|
mainView
|
||||||
.alert(item: $actionSheetType) {
|
.alert(
|
||||||
switch $0 {
|
Text(Unlocalized.appName),
|
||||||
case .uninstallVPN:
|
isPresented: $isAlertPresented,
|
||||||
return Alert(
|
presenting: alertType,
|
||||||
title: Text(uninstallVPNTitle),
|
actions: alertActions,
|
||||||
message: Text(L10n.Profile.Alerts.UninstallVpn.message),
|
message: alertMessage
|
||||||
primaryButton: .destructive(Text(uninstallVPNTitle), action: uninstallVPN),
|
|
||||||
secondaryButton: .cancel(Text(cancelTitle))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
case .deleteProfile:
|
|
||||||
return Alert(
|
|
||||||
title: Text(deleteProfileTitle),
|
|
||||||
message: Text(L10n.Organizer.Alerts.RemoveProfile.message(header.name)),
|
|
||||||
primaryButton: .destructive(Text(deleteProfileTitle), action: removeProfile),
|
|
||||||
secondaryButton: .cancel(Text(cancelTitle))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var mainView: some View {
|
private var mainView: some View {
|
||||||
|
@ -113,9 +101,46 @@ extension ProfileView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func alertActions(_ alertType: AlertType) -> some View {
|
||||||
|
switch alertType {
|
||||||
|
case .uninstallVPN:
|
||||||
|
return Group {
|
||||||
|
Button(role: .destructive, action: uninstallVPN) {
|
||||||
|
Text(uninstallVPNTitle)
|
||||||
|
}
|
||||||
|
Button(role: .cancel) {
|
||||||
|
} label: {
|
||||||
|
Text(L10n.Global.Strings.cancel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case .deleteProfile:
|
||||||
|
return Group {
|
||||||
|
Button(role: .destructive, action: removeProfile) {
|
||||||
|
Text(deleteProfileTitle)
|
||||||
|
}
|
||||||
|
Button(role: .cancel) {
|
||||||
|
} label: {
|
||||||
|
Text(L10n.Global.Strings.cancel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func alertMessage(_ alertType: AlertType) -> some View {
|
||||||
|
switch alertType {
|
||||||
|
case .uninstallVPN:
|
||||||
|
return Text(L10n.Profile.Alerts.UninstallVpn.message)
|
||||||
|
|
||||||
|
case .deleteProfile:
|
||||||
|
return Text(L10n.Organizer.Alerts.RemoveProfile.message(header.name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var uninstallVPNButton: some View {
|
private var uninstallVPNButton: some View {
|
||||||
Button {
|
Button {
|
||||||
actionSheetType = .uninstallVPN
|
alertType = .uninstallVPN
|
||||||
|
isAlertPresented = true
|
||||||
} label: {
|
} label: {
|
||||||
Label(uninstallVPNTitle, systemImage: themeUninstallImage)
|
Label(uninstallVPNTitle, systemImage: themeUninstallImage)
|
||||||
}
|
}
|
||||||
|
@ -123,7 +148,8 @@ extension ProfileView {
|
||||||
|
|
||||||
private var deleteProfileButton: some View {
|
private var deleteProfileButton: some View {
|
||||||
DestructiveButton {
|
DestructiveButton {
|
||||||
actionSheetType = .deleteProfile
|
alertType = .deleteProfile
|
||||||
|
isAlertPresented = true
|
||||||
} label: {
|
} label: {
|
||||||
Label(deleteProfileTitle, systemImage: themeDeleteImage)
|
Label(deleteProfileTitle, systemImage: themeDeleteImage)
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,18 +59,29 @@ extension ProfileView {
|
||||||
ToolbarItem(placement: .primaryAction) {
|
ToolbarItem(placement: .primaryAction) {
|
||||||
Button(action: commitRenaming, label: themeSaveButtonLabel)
|
Button(action: commitRenaming, label: themeSaveButtonLabel)
|
||||||
}
|
}
|
||||||
}.alert(isPresented: $isOverwritingExistingProfile, content: alertOverwriteExistingProfile)
|
}.alert(
|
||||||
|
L10n.Profile.Alerts.Rename.title,
|
||||||
|
isPresented: $isOverwritingExistingProfile,
|
||||||
|
actions: alertOverwriteActions,
|
||||||
|
message: alertOverwriteMessage
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func alertOverwriteExistingProfile() -> Alert {
|
@ViewBuilder
|
||||||
Alert(
|
private func alertOverwriteActions() -> some View {
|
||||||
title: Text(L10n.Profile.Alerts.Rename.title),
|
Button(role: .destructive) {
|
||||||
message: Text(L10n.AddProfile.Shared.Alerts.Overwrite.message),
|
|
||||||
primaryButton: .destructive(Text(L10n.Global.Strings.ok)) {
|
|
||||||
commitRenaming(force: true)
|
commitRenaming(force: true)
|
||||||
},
|
} label: {
|
||||||
secondaryButton: .cancel(Text(L10n.Global.Strings.cancel))
|
Text(L10n.Global.Strings.ok)
|
||||||
)
|
}
|
||||||
|
Button(role: .cancel) {
|
||||||
|
} label: {
|
||||||
|
Text(L10n.Global.Strings.cancel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func alertOverwriteMessage() -> some View {
|
||||||
|
Text(L10n.AddProfile.Shared.Alerts.Overwrite.message)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func loadCurrentName() {
|
private func loadCurrentName() {
|
||||||
|
|
|
@ -314,7 +314,6 @@
|
||||||
"donate.sections.one_time.footer" = "Wenn du dich erkenntlich zeigen möchtest für meine Arbeit, gibt es hier ein paar Beträge die du direkt spenden kannst.\n\nDu bezahlst pro Spende nur einmal und kannst mehrmals spenden wenn du möchtest.";
|
"donate.sections.one_time.footer" = "Wenn du dich erkenntlich zeigen möchtest für meine Arbeit, gibt es hier ein paar Beträge die du direkt spenden kannst.\n\nDu bezahlst pro Spende nur einmal und kannst mehrmals spenden wenn du möchtest.";
|
||||||
"donate.items.loading.caption" = "Lade Spenden";
|
"donate.items.loading.caption" = "Lade Spenden";
|
||||||
"donate.items.purchasing.caption" = "Führe Spende durch";
|
"donate.items.purchasing.caption" = "Führe Spende durch";
|
||||||
"donate.alerts.purchase.success.title" = "Danke";
|
|
||||||
"donate.alerts.purchase.success.message" = "Das bedeutet mir viel und ich hoffe wirklich dass du die App weiterhin benutzt und unterstützt.";
|
"donate.alerts.purchase.success.message" = "Das bedeutet mir viel und ich hoffe wirklich dass du die App weiterhin benutzt und unterstützt.";
|
||||||
"donate.alerts.purchase.failure.message" = "Konnte Spende nicht durchführen. %@";
|
"donate.alerts.purchase.failure.message" = "Konnte Spende nicht durchführen. %@";
|
||||||
|
|
||||||
|
|
|
@ -314,7 +314,6 @@
|
||||||
"donate.sections.one_time.footer" = "Αν είστε χαρούμενη με τη δουλειά μου, εδώ είναι λίγα ποσά που μπορείτε να δώσετε αμέσως.\n\nΘα χρεωθείτε μόνο μία φορά και μπορείτε να δώσετε πολλές φορές.";
|
"donate.sections.one_time.footer" = "Αν είστε χαρούμενη με τη δουλειά μου, εδώ είναι λίγα ποσά που μπορείτε να δώσετε αμέσως.\n\nΘα χρεωθείτε μόνο μία φορά και μπορείτε να δώσετε πολλές φορές.";
|
||||||
"donate.items.loading.caption" = "Φόρτωση δωρεών";
|
"donate.items.loading.caption" = "Φόρτωση δωρεών";
|
||||||
"donate.items.purchasing.caption" = "Εκτέλεση δωρεάς";
|
"donate.items.purchasing.caption" = "Εκτέλεση δωρεάς";
|
||||||
"donate.alerts.purchase.success.title" = "Ευχαριστώ";
|
|
||||||
"donate.alerts.purchase.success.message" = "Αυτό σημαίνει πολλά για μένα και πραγματικά ελπίζω να συνεχίσετε να χρησιμοποιείτε και να προωθείτε αυτήν την εφαρμογή.";
|
"donate.alerts.purchase.success.message" = "Αυτό σημαίνει πολλά για μένα και πραγματικά ελπίζω να συνεχίσετε να χρησιμοποιείτε και να προωθείτε αυτήν την εφαρμογή.";
|
||||||
"donate.alerts.purchase.failure.message" = "Δεν είναι δυνατή η εκτέλεση της δωρεάς. %@";
|
"donate.alerts.purchase.failure.message" = "Δεν είναι δυνατή η εκτέλεση της δωρεάς. %@";
|
||||||
|
|
||||||
|
|
|
@ -314,7 +314,6 @@
|
||||||
"donate.sections.one_time.footer" = "If you want to display gratitude for my free work, here are a couple amounts you can donate instantly.\n\nYou will only be charged once per donation, and you can donate multiple times.";
|
"donate.sections.one_time.footer" = "If you want to display gratitude for my free work, here are a couple amounts you can donate instantly.\n\nYou will only be charged once per donation, and you can donate multiple times.";
|
||||||
"donate.items.loading.caption" = "Loading donations";
|
"donate.items.loading.caption" = "Loading donations";
|
||||||
"donate.items.purchasing.caption" = "Performing donation";
|
"donate.items.purchasing.caption" = "Performing donation";
|
||||||
"donate.alerts.purchase.success.title" = "Thank you";
|
|
||||||
"donate.alerts.purchase.success.message" = "This means a lot to me and I really hope you keep using and promoting this app.";
|
"donate.alerts.purchase.success.message" = "This means a lot to me and I really hope you keep using and promoting this app.";
|
||||||
"donate.alerts.purchase.failure.message" = "Unable to perform the donation. %@";
|
"donate.alerts.purchase.failure.message" = "Unable to perform the donation. %@";
|
||||||
|
|
||||||
|
|
|
@ -314,7 +314,6 @@
|
||||||
"donate.sections.one_time.footer" = "Si te gusta mi trabajo, aquí puedes colaborar con una donación.\n\nSólo se te cobrará una vez por donación, y puedes donar las veces que quieras.";
|
"donate.sections.one_time.footer" = "Si te gusta mi trabajo, aquí puedes colaborar con una donación.\n\nSólo se te cobrará una vez por donación, y puedes donar las veces que quieras.";
|
||||||
"donate.items.loading.caption" = "Cargando donaciones";
|
"donate.items.loading.caption" = "Cargando donaciones";
|
||||||
"donate.items.purchasing.caption" = "Efectuando donación";
|
"donate.items.purchasing.caption" = "Efectuando donación";
|
||||||
"donate.alerts.purchase.success.title" = "Muchas gracias";
|
|
||||||
"donate.alerts.purchase.success.message" = "Ésto significa mucho para mí y espero sinceramente que sigas usando y promoviendo esta aplicación.";
|
"donate.alerts.purchase.success.message" = "Ésto significa mucho para mí y espero sinceramente que sigas usando y promoviendo esta aplicación.";
|
||||||
"donate.alerts.purchase.failure.message" = "Imposible completar la donación, por favor vuelve a intentarlo. %@";
|
"donate.alerts.purchase.failure.message" = "Imposible completar la donación, por favor vuelve a intentarlo. %@";
|
||||||
|
|
||||||
|
|
|
@ -314,7 +314,6 @@
|
||||||
"donate.sections.one_time.footer" = "Si vous voulez manifester votre gratitude envers mon travail bénévole, voici certains montants pour faire un don instantanément.\n\n Vous n'allez être chargé qu'une seule fois par don et vous pouvez faire un don plus d'une fois.";
|
"donate.sections.one_time.footer" = "Si vous voulez manifester votre gratitude envers mon travail bénévole, voici certains montants pour faire un don instantanément.\n\n Vous n'allez être chargé qu'une seule fois par don et vous pouvez faire un don plus d'une fois.";
|
||||||
"donate.items.loading.caption" = "Chargement des dons";
|
"donate.items.loading.caption" = "Chargement des dons";
|
||||||
"donate.items.purchasing.caption" = "Don en cours";
|
"donate.items.purchasing.caption" = "Don en cours";
|
||||||
"donate.alerts.purchase.success.title" = "Merci";
|
|
||||||
"donate.alerts.purchase.success.message" = "Ceci signifie beaucoup pour moi et j'espère sincèrement que vous continuerez d'utiliser et de promouvoir cette app.";
|
"donate.alerts.purchase.success.message" = "Ceci signifie beaucoup pour moi et j'espère sincèrement que vous continuerez d'utiliser et de promouvoir cette app.";
|
||||||
"donate.alerts.purchase.failure.message" = "Impossible de faire le don. %@";
|
"donate.alerts.purchase.failure.message" = "Impossible de faire le don. %@";
|
||||||
|
|
||||||
|
|
|
@ -314,7 +314,6 @@
|
||||||
"donate.sections.one_time.footer" = "Se vuoi mostrare gratitudine per il mio lavoro a titolo gratuito, qui trovi varie somme da donare all'istante.\n\nLa donazione ti sarà addebitata solo una volta, e puoi effettuare più donazioni.";
|
"donate.sections.one_time.footer" = "Se vuoi mostrare gratitudine per il mio lavoro a titolo gratuito, qui trovi varie somme da donare all'istante.\n\nLa donazione ti sarà addebitata solo una volta, e puoi effettuare più donazioni.";
|
||||||
"donate.items.loading.caption" = "Caricando donazioni";
|
"donate.items.loading.caption" = "Caricando donazioni";
|
||||||
"donate.items.purchasing.caption" = "Effettuando donazione";
|
"donate.items.purchasing.caption" = "Effettuando donazione";
|
||||||
"donate.alerts.purchase.success.title" = "Grazie";
|
|
||||||
"donate.alerts.purchase.success.message" = "Questo significa molto per me e spero vivamente che tu continui ad usare e promuovere quest'applicazione.";
|
"donate.alerts.purchase.success.message" = "Questo significa molto per me e spero vivamente che tu continui ad usare e promuovere quest'applicazione.";
|
||||||
"donate.alerts.purchase.failure.message" = "Impossibile effettuare la donazione. %@";
|
"donate.alerts.purchase.failure.message" = "Impossibile effettuare la donazione. %@";
|
||||||
|
|
||||||
|
|
|
@ -314,7 +314,6 @@
|
||||||
"donate.sections.one_time.footer" = "Als je dankbaarheid wilt tonen voor mijn gratis werk, zijn hier een paar bedragen die je direct kunt doneren.\n\nHet bedrag wordt slechts één keer per donatie in rekening gebracht en u kunt meerdere keren doneren.";
|
"donate.sections.one_time.footer" = "Als je dankbaarheid wilt tonen voor mijn gratis werk, zijn hier een paar bedragen die je direct kunt doneren.\n\nHet bedrag wordt slechts één keer per donatie in rekening gebracht en u kunt meerdere keren doneren.";
|
||||||
"donate.items.loading.caption" = "Ophalen donaties";
|
"donate.items.loading.caption" = "Ophalen donaties";
|
||||||
"donate.items.purchasing.caption" = "Doneren";
|
"donate.items.purchasing.caption" = "Doneren";
|
||||||
"donate.alerts.purchase.success.title" = "Hartelijk dank";
|
|
||||||
"donate.alerts.purchase.success.message" = "Dit betekent veel voor mij en ik hoop echt dat je deze app blijft gebruiken en promoten.";
|
"donate.alerts.purchase.success.message" = "Dit betekent veel voor mij en ik hoop echt dat je deze app blijft gebruiken en promoten.";
|
||||||
"donate.alerts.purchase.failure.message" = "Donatie mislukt. %@";
|
"donate.alerts.purchase.failure.message" = "Donatie mislukt. %@";
|
||||||
|
|
||||||
|
|
|
@ -314,7 +314,6 @@
|
||||||
"donate.sections.one_time.footer" = "Jeśli chcesz docenić moją pracę, poniżej znajdziesz kilka kwot do wyboru dotacji.\n\nTwoje konto zostanie obciążone tylko raz na jedną dotację, możesz wysłać dotację kilka razy.";
|
"donate.sections.one_time.footer" = "Jeśli chcesz docenić moją pracę, poniżej znajdziesz kilka kwot do wyboru dotacji.\n\nTwoje konto zostanie obciążone tylko raz na jedną dotację, możesz wysłać dotację kilka razy.";
|
||||||
"donate.items.loading.caption" = "Ładowanie dotacji";
|
"donate.items.loading.caption" = "Ładowanie dotacji";
|
||||||
"donate.items.purchasing.caption" = "Wykonywanie dotacji";
|
"donate.items.purchasing.caption" = "Wykonywanie dotacji";
|
||||||
"donate.alerts.purchase.success.title" = "Dziękuję";
|
|
||||||
"donate.alerts.purchase.success.message" = "To dla mnie dużo znaczy, mam nadzięję że będziesz używać aplikacji i przyczynisz się do jej rozpowrzechnienia.";
|
"donate.alerts.purchase.success.message" = "To dla mnie dużo znaczy, mam nadzięję że będziesz używać aplikacji i przyczynisz się do jej rozpowrzechnienia.";
|
||||||
"donate.alerts.purchase.failure.message" = "Nie można dokonać dotacji. %@";
|
"donate.alerts.purchase.failure.message" = "Nie można dokonać dotacji. %@";
|
||||||
|
|
||||||
|
|
|
@ -314,7 +314,6 @@
|
||||||
"donate.sections.one_time.footer" = "Se você deseja mostrar gratidão pelo meu trabalho, aqui estão alguns valores do qual você pode contribuir.\n\nVocé só será cobrado uma única vez, ou doar mais vezes caso desejar.";
|
"donate.sections.one_time.footer" = "Se você deseja mostrar gratidão pelo meu trabalho, aqui estão alguns valores do qual você pode contribuir.\n\nVocé só será cobrado uma única vez, ou doar mais vezes caso desejar.";
|
||||||
"donate.items.loading.caption" = "Carregando doações";
|
"donate.items.loading.caption" = "Carregando doações";
|
||||||
"donate.items.purchasing.caption" = "Efetuando doação";
|
"donate.items.purchasing.caption" = "Efetuando doação";
|
||||||
"donate.alerts.purchase.success.title" = "Obrigado";
|
|
||||||
"donate.alerts.purchase.success.message" = "Isso significa muito para mim! Espero que você continue usando e promovendo esse aplicativo.";
|
"donate.alerts.purchase.success.message" = "Isso significa muito para mim! Espero que você continue usando e promovendo esse aplicativo.";
|
||||||
"donate.alerts.purchase.failure.message" = "Não foi possível realizar doação. %@";
|
"donate.alerts.purchase.failure.message" = "Não foi possível realizar doação. %@";
|
||||||
|
|
||||||
|
|
|
@ -314,7 +314,6 @@
|
||||||
"donate.sections.one_time.footer" = "Если Вы хотите поблагодарить мою бесплатную работу, здесь есть несколько сумм, которые Вы можете пожертвовать прямо сейчас.\n\nСумма будет списана только один раз, а Вы можете пожертвовать несколько раз.";
|
"donate.sections.one_time.footer" = "Если Вы хотите поблагодарить мою бесплатную работу, здесь есть несколько сумм, которые Вы можете пожертвовать прямо сейчас.\n\nСумма будет списана только один раз, а Вы можете пожертвовать несколько раз.";
|
||||||
"donate.items.loading.caption" = "Загружаем пожертвования";
|
"donate.items.loading.caption" = "Загружаем пожертвования";
|
||||||
"donate.items.purchasing.caption" = "Исполняется";
|
"donate.items.purchasing.caption" = "Исполняется";
|
||||||
"donate.alerts.purchase.success.title" = "Спасибо";
|
|
||||||
"donate.alerts.purchase.success.message" = "Это значит многое для меня, и, я надеюсь, Вы продолжить использовать и рассказывать об этом приложении.";
|
"donate.alerts.purchase.success.message" = "Это значит многое для меня, и, я надеюсь, Вы продолжить использовать и рассказывать об этом приложении.";
|
||||||
"donate.alerts.purchase.failure.message" = "Не получается совершить пожертвование. %@";
|
"donate.alerts.purchase.failure.message" = "Не получается совершить пожертвование. %@";
|
||||||
|
|
||||||
|
|
|
@ -314,7 +314,6 @@
|
||||||
"donate.sections.one_time.footer" = "Om du vill visa tacksamhet för mitt fria arbete, här är några belopp du kan donera direkt. \n\nDu betalas endast en gång per donation, och du kan donera flera gånger. ";
|
"donate.sections.one_time.footer" = "Om du vill visa tacksamhet för mitt fria arbete, här är några belopp du kan donera direkt. \n\nDu betalas endast en gång per donation, och du kan donera flera gånger. ";
|
||||||
"donate.items.loading.caption" = "Laddar donationer";
|
"donate.items.loading.caption" = "Laddar donationer";
|
||||||
"donate.items.purchasing.caption" = "Performing donation";
|
"donate.items.purchasing.caption" = "Performing donation";
|
||||||
"donate.alerts.purchase.success.title" = "Tack";
|
|
||||||
"donate.alerts.purchase.success.message" = "Detta betyder mycket för mig och jag hoppas verkligen att du fortsätter att använda och marknadsföra denna app.";
|
"donate.alerts.purchase.success.message" = "Detta betyder mycket för mig och jag hoppas verkligen att du fortsätter att använda och marknadsföra denna app.";
|
||||||
"donate.alerts.purchase.failure.message" = "Kan inte göra donationen. %@";
|
"donate.alerts.purchase.failure.message" = "Kan inte göra donationen. %@";
|
||||||
|
|
||||||
|
|
|
@ -314,7 +314,6 @@
|
||||||
"donate.sections.one_time.footer" = "Якщо ви бажаєте подякувати за мою безкоштовну роботу, тут є декілька сум, які ви можете пожертвувати прямо зараз.\n\nЗ вас буде стягнено плату лише один раз, але ви можете робити пожертви кілька разів.";
|
"donate.sections.one_time.footer" = "Якщо ви бажаєте подякувати за мою безкоштовну роботу, тут є декілька сум, які ви можете пожертвувати прямо зараз.\n\nЗ вас буде стягнено плату лише один раз, але ви можете робити пожертви кілька разів.";
|
||||||
"donate.items.loading.caption" = "Завантажуємо пожертвування";
|
"donate.items.loading.caption" = "Завантажуємо пожертвування";
|
||||||
"donate.items.purchasing.caption" = "Виконується";
|
"donate.items.purchasing.caption" = "Виконується";
|
||||||
"donate.alerts.purchase.success.title" = "Дякуємо";
|
|
||||||
"donate.alerts.purchase.success.message" = "Це дуже важливо для мене, і я сподіваюся, що ви й надалі будете користуватися цією програмою та рекламувати її.";
|
"donate.alerts.purchase.success.message" = "Це дуже важливо для мене, і я сподіваюся, що ви й надалі будете користуватися цією програмою та рекламувати її.";
|
||||||
"donate.alerts.purchase.failure.message" = "Не вдається здійснити пожертвування. %@";
|
"donate.alerts.purchase.failure.message" = "Не вдається здійснити пожертвування. %@";
|
||||||
|
|
||||||
|
|
|
@ -314,7 +314,6 @@
|
||||||
"donate.sections.one_time.footer" = "如果你想对我免费的工作表示感谢,这里是一些你可以捐助的数额。\n\n每次捐助只需要付款一次,你可以捐助多次。";
|
"donate.sections.one_time.footer" = "如果你想对我免费的工作表示感谢,这里是一些你可以捐助的数额。\n\n每次捐助只需要付款一次,你可以捐助多次。";
|
||||||
"donate.items.loading.caption" = "加载捐助中";
|
"donate.items.loading.caption" = "加载捐助中";
|
||||||
"donate.items.purchasing.caption" = "展示捐助页面中";
|
"donate.items.purchasing.caption" = "展示捐助页面中";
|
||||||
"donate.alerts.purchase.success.title" = "感谢";
|
|
||||||
"donate.alerts.purchase.success.message" = "这对于我意味着很多,希望你保持使用并使它更好。";
|
"donate.alerts.purchase.success.message" = "这对于我意味着很多,希望你保持使用并使它更好。";
|
||||||
"donate.alerts.purchase.failure.message" = "无法展现捐助内容。%@";
|
"donate.alerts.purchase.failure.message" = "无法展现捐助内容。%@";
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue