Refactor alerts to use latest API (#320)

This commit is contained in:
Davide De Rosa 2023-07-03 16:41:49 +02:00 committed by GitHub
parent de7e574fec
commit 7198150f00
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 203 additions and 111 deletions

View File

@ -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,15 +53,19 @@ 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)
}
) )
} }
} }

View File

@ -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), processProfile(replacingExisting: true)
primaryButton: .destructive(Text(L10n.Global.Strings.ok)) { } label: {
processProfile(replacingExisting: true) Text(L10n.Global.Strings.ok)
}, }
secondaryButton: .cancel(Text(L10n.Global.Strings.cancel)) 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) {

View File

@ -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), saveProfile(replacingExisting: true)
primaryButton: .destructive(Text(L10n.Global.Strings.ok)) { } label: {
saveProfile(replacingExisting: true) Text(L10n.Global.Strings.ok)
}, }
secondaryButton: .cancel(Text(L10n.Global.Strings.cancel)) 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) {

View File

@ -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
} }
} }

View File

@ -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
} }

View File

@ -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
} }

View File

@ -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)) {
didHandleSubreddit = true
} }
) Button(role: .cancel) {
didHandleSubreddit = true
} label: {
Text(L10n.Global.Alerts.Buttons.never)
}
}
}
}
private func alertMessage(_ alertType: AlertType) -> some View {
switch alertType {
case .subscribeReddit:
return Text(L10n.Organizer.Alerts.Reddit.message)
} }
} }
} }
extension OrganizerView {
private func presentSubscribeReddit() {
alertType = .subscribeReddit
}
}

View File

@ -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)
} }

View File

@ -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), commitRenaming(force: true)
primaryButton: .destructive(Text(L10n.Global.Strings.ok)) { } label: {
commitRenaming(force: true) Text(L10n.Global.Strings.ok)
}, }
secondaryButton: .cancel(Text(L10n.Global.Strings.cancel)) 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() {

View File

@ -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. %@";

View File

@ -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" = "Δεν είναι δυνατή η εκτέλεση της δωρεάς. %@";

View File

@ -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. %@";

View File

@ -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. %@";

View File

@ -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. %@";

View File

@ -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. %@";

View File

@ -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. %@";

View File

@ -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. %@";

View File

@ -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. %@";

View File

@ -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" = "Не получается совершить пожертвование. %@";

View File

@ -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. %@";

View File

@ -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" = "Не вдається здійснити пожертвування. %@";

View File

@ -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" = "无法展现捐助内容。%@";