From a025923ba6d12e7a50e93d2d822e4e755d73abfc Mon Sep 17 00:00:00 2001 From: Vicnet <35202538+VincentMeilinger@users.noreply.github.com> Date: Tue, 17 Oct 2023 16:14:13 +0200 Subject: [PATCH] Updated duration pickers in Recipe Edit View --- .../project.pbxproj | 1 + .../Localizable.xcstrings | 526 ++++++++++++++++-- .../Views/RecipeEditView.swift | 125 +++-- .../Views/SettingsView.swift | 8 +- 4 files changed, 568 insertions(+), 92 deletions(-) diff --git a/Nextcloud Cookbook iOS Client.xcodeproj/project.pbxproj b/Nextcloud Cookbook iOS Client.xcodeproj/project.pbxproj index 77df786..6b6f354 100644 --- a/Nextcloud Cookbook iOS Client.xcodeproj/project.pbxproj +++ b/Nextcloud Cookbook iOS Client.xcodeproj/project.pbxproj @@ -319,6 +319,7 @@ en, Base, de, + es, ); mainGroup = A70171752AA8E71900064C43; productRefGroup = A701717F2AA8E71900064C43 /* Products */; diff --git a/Nextcloud Cookbook iOS Client/Localizable.xcstrings b/Nextcloud Cookbook iOS Client/Localizable.xcstrings index be88c1c..51be928 100644 --- a/Nextcloud Cookbook iOS Client/Localizable.xcstrings +++ b/Nextcloud Cookbook iOS Client/Localizable.xcstrings @@ -8,6 +8,28 @@ "state" : "translated", "value" : "" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "" + } + } + } + }, + ":" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : ":" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : ":" + } } } }, @@ -18,6 +40,12 @@ "state" : "translated", "value" : "%@" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } } } }, @@ -28,25 +56,11 @@ "state" : "translated", "value" : "%lld" } - } - } - }, - "%lld hours" : { - "localizations" : { - "de" : { + }, + "es" : { "stringUnit" : { "state" : "translated", - "value" : "%lld Std." - } - } - } - }, - "%lld min" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "%lld Min." + "value" : "%lld" } } } @@ -58,6 +72,12 @@ "state" : "translated", "value" : "%lld." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld." + } } } }, @@ -68,6 +88,28 @@ "state" : "translated", "value" : "•" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "•" + } + } + } + }, + "00" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "00" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "00" + } } } }, @@ -78,6 +120,12 @@ "state" : "translated", "value" : "Ein Rezept mit diesem Namen existiert bereits." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ya existe una receta con ese nombre." + } } } }, @@ -88,6 +136,12 @@ "state" : "translated", "value" : "Über uns" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Acerca de" + } } } }, @@ -98,6 +152,12 @@ "state" : "translated", "value" : "Hinzufügen" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Agregar" + } } } }, @@ -108,6 +168,12 @@ "state" : "translated", "value" : "Ein unbekannter Fehler ist aufgetreten." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ocurrió un error desconocido." + } } } }, @@ -118,6 +184,12 @@ "state" : "translated", "value" : "App Token Login" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "App Token Login" + } } } }, @@ -128,6 +200,12 @@ "state" : "translated", "value" : "Abbrechen" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cancelar" + } } } }, @@ -138,6 +216,12 @@ "state" : "translated", "value" : "Kategorie" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Categoría" + } } } }, @@ -148,6 +232,12 @@ "state" : "translated", "value" : "Kategorie: %@" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Categoría: %@" + } } } }, @@ -156,17 +246,13 @@ "de" : { "stringUnit" : { "state" : "translated", - "value" : "Kochzeit" + "value" : "Kochen" } - } - } - }, - "Cook time:" : { - "localizations" : { - "de" : { + }, + "es" : { "stringUnit" : { "state" : "translated", - "value" : "Kochdauer:" + "value" : "Duración de cocción" } } } @@ -178,6 +264,12 @@ "state" : "translated", "value" : "Cookbook Client" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cookbook Client" + } } } }, @@ -188,6 +280,28 @@ "state" : "translated", "value" : "Kochbücher" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Libros de cocina" + } + } + } + }, + "Cooking duration:" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kochen:" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Duración de cocción:" + } } } }, @@ -198,6 +312,12 @@ "state" : "translated", "value" : "Löschen" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Borrar" + } } } }, @@ -208,6 +328,12 @@ "state" : "translated", "value" : "Lokale Daten löschen" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eliminar datos locales" + } } } }, @@ -218,6 +344,12 @@ "state" : "translated", "value" : "Rezept Löschen" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eliminar receta" + } } } }, @@ -228,6 +360,12 @@ "state" : "translated", "value" : "Löschen bestätigen." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¿Eliminar receta?" + } } } }, @@ -238,6 +376,12 @@ "state" : "translated", "value" : "Das Löschen lokaler Daten hat keine Auswirkungen auf die Rezeptdaten, die auf Ihrem Server gespeichert sind." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Eliminar datos locales no afectará los datos de las recetas almacenados en su servidor." + } } } }, @@ -248,15 +392,11 @@ "state" : "translated", "value" : "Beschreibung" } - } - } - }, - "Discoverability" : { - "localizations" : { - "de" : { + }, + "es" : { "stringUnit" : { "state" : "translated", - "value" : "Kategorisierung" + "value" : "Descripción." } } } @@ -268,6 +408,12 @@ "state" : "translated", "value" : "Alle Rezepte herunterladen" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Descargar todas las recetas" + } } } }, @@ -278,6 +424,12 @@ "state" : "translated", "value" : "Rezepte herunterladen" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Descargar recetas" + } } } }, @@ -288,6 +440,12 @@ "state" : "translated", "value" : "Rezept bereits vorhanden." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Receta duplicada." + } } } }, @@ -298,6 +456,12 @@ "state" : "translated", "value" : "Bearbeiten" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Editar" + } } } }, @@ -308,6 +472,12 @@ "state" : "translated", "value" : "Das Eingeben der Serveradresse wird einen Webbrowser öffnen. Bitte folgen Sie dort den bereitgestellten Anmeldeanweisungen. Falls der Browser nicht geöffnet wird, klicken Sie auf den Link 'Im Browser öffnen'.\nNach erfolgreicher Anmeldung kehren Sie zu dieser Anwendung zurück und drücken Sie 'Überprüfen'." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingresar la dirección del servidor abrirá un navegador web. Por favor, siga las instrucciones de inicio de sesión proporcionadas allí. Si el navegador no se abre, haga clic en el enlace 'Abrir en el navegador'.\nDespués de iniciar sesión con éxito, regrese a esta aplicación y presione 'Validar'." + } } } }, @@ -318,6 +488,12 @@ "state" : "translated", "value" : "Fehler." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error." + } } } }, @@ -328,6 +504,12 @@ "state" : "translated", "value" : "Allgemein" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "General" + } } } }, @@ -338,6 +520,12 @@ "state" : "translated", "value" : "Kontakt-Seite öffnen" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Obtener soporte" + } } } }, @@ -348,6 +536,12 @@ "state" : "translated", "value" : "Wenn Sie Interesse daran haben, zu diesem Projekt beizutragen oder einfach den Quellcode überprüfen möchten, ermutigen wir Sie, das GitHub-Repository für diese Anwendung zu besuchen." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Si estás interesado en contribuir a este proyecto o simplemente deseas revisar su código fuente, te animamos a visitar el repositorio de GitHub de esta aplicación." + } } } }, @@ -358,6 +552,12 @@ "state" : "translated", "value" : "Wenn Sie Anfragen oder Rückmeldungen haben, oder Unterstützung benötigen, finden Sie unter diesem Link die Kontaktinformationen." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Si tienes alguna pregunta, comentarios o necesitas asistencia, por favor consulta la página de soporte para obtener información de contacto." + } } } }, @@ -368,6 +568,12 @@ "state" : "translated", "value" : "Zutaten" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingredientes" + } } } }, @@ -378,6 +584,12 @@ "state" : "translated", "value" : "Zutaten für %lld Portionen" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingredientes para %lld porciones." + } } } }, @@ -388,6 +600,12 @@ "state" : "translated", "value" : "Zutaten pro Portion" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ingredientes por porción" + } } } }, @@ -398,6 +616,12 @@ "state" : "translated", "value" : "Anleitung" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Instrucciones" + } } } }, @@ -408,6 +632,12 @@ "state" : "translated", "value" : "Schlagwörter" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Palabras clave" + } } } }, @@ -418,6 +648,12 @@ "state" : "translated", "value" : "Sprache" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Idioma" + } } } }, @@ -428,6 +664,12 @@ "state" : "translated", "value" : "Abmelden" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cerrar sesión" + } } } }, @@ -438,6 +680,12 @@ "state" : "translated", "value" : "Login-Methode" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Método de inicio de sesión" + } } } }, @@ -448,6 +696,12 @@ "state" : "translated", "value" : "Fehlender Rezeptname." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Falta el nombre de la receta." + } } } }, @@ -458,6 +712,12 @@ "state" : "translated", "value" : "Netzwerkfehler" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Error de red." + } } } }, @@ -468,6 +728,12 @@ "state" : "translated", "value" : "Neues Rezept" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nueva receta" + } } } }, @@ -478,6 +744,12 @@ "state" : "translated", "value" : "Nextcloud Login" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nextcloud Login" + } } } }, @@ -488,6 +760,12 @@ "state" : "translated", "value" : "Keines" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ninguno" + } } } }, @@ -498,6 +776,12 @@ "state" : "translated", "value" : "Ok" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ok" + } } } }, @@ -508,6 +792,12 @@ "state" : "translated", "value" : "Im Browser öffnen" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Abrir en el navegador." + } } } }, @@ -518,6 +808,12 @@ "state" : "translated", "value" : "Andere" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Otro" + } } } }, @@ -528,6 +824,12 @@ "state" : "translated", "value" : "Bitte tragen Sie einen Rezeptnamen ein." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Por favor, ingrese un nombre de receta." + } } } }, @@ -536,17 +838,29 @@ "de" : { "stringUnit" : { "state" : "translated", - "value" : "Vorbereitungsdauer" + "value" : "Vorbereitung" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Duración de preparación" } } } }, - "Prep time:" : { + "Preparation duration:" : { "localizations" : { "de" : { "stringUnit" : { "state" : "translated", - "value" : "Vorbereitungsdauer:" + "value" : "Vorbereitung:" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Duración de preparación:" } } } @@ -558,6 +872,12 @@ "state" : "translated", "value" : "Rezepte durchsuchen" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Buscar recetas" + } } } }, @@ -568,6 +888,12 @@ "state" : "translated", "value" : "Wählen Sie ein Standard-Kochbuch" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Seleccionar un libro de cocina predeterminado" + } } } }, @@ -578,6 +904,28 @@ "state" : "translated", "value" : "Ausgewählte Schlagwörter:" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Palabras clave seleccionadas:" + } + } + } + }, + "Servings:" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Portionen:" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Porciones:" + } } } }, @@ -588,6 +936,12 @@ "state" : "translated", "value" : "Einstellungen" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Configuración" + } } } }, @@ -598,6 +952,12 @@ "state" : "translated", "value" : "Eingeben" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enviar" + } } } }, @@ -608,6 +968,12 @@ "state" : "translated", "value" : "Kontakt" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ayuda" + } } } }, @@ -618,6 +984,12 @@ "state" : "translated", "value" : "Vielen Dank für's herunterladen!" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gracias por descargar" + } } } }, @@ -628,6 +1000,12 @@ "state" : "translated", "value" : "Das ausgewählte Kochbuch wird standardmäßig beim Start der App geöffnet." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "El libro de cocina seleccionado se abrirá por defecto al iniciar la aplicación." + } } } }, @@ -638,6 +1016,12 @@ "state" : "translated", "value" : "Diese Aktion lässt sich nicht Rückgängig machen!" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "¡Esta acción no es reversible!" + } } } }, @@ -648,6 +1032,12 @@ "state" : "translated", "value" : "Diese Anwendung ist ein Open-Source-Projekt. Wenn Sie daran interessiert sind, neue Funktionen vorzuschlagen oder beizutragen, oder wenn Sie auf Probleme stoßen, nutzen Sie bitte den Kontakt-Link oder besuchen Sie das GitHub-Repository in den App-Einstellungen." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Esta aplicación es un esfuerzo de código abierto. Si estás interesado en sugerir o contribuir con nuevas funciones o te encuentras con algún problema, por favor utiliza el enlace de soporte o visita el repositorio de GitHub en la configuración de la aplicación." + } } } }, @@ -658,6 +1048,12 @@ "state" : "translated", "value" : "Name" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Título" + } } } }, @@ -668,6 +1064,28 @@ "state" : "translated", "value" : "Küchenutensilien" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Utensilios de cocina." + } + } + } + }, + "Total duration:" : { + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gesamtdauer:" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Duración total:" + } } } }, @@ -678,15 +1096,11 @@ "state" : "translated", "value" : "Gesamtdauer" } - } - } - }, - "Total time:" : { - "localizations" : { - "de" : { + }, + "es" : { "stringUnit" : { "state" : "translated", - "value" : "Gesamtdauer:" + "value" : "Duración total" } } } @@ -698,6 +1112,12 @@ "state" : "translated", "value" : "Es ist nicht möglich, Ihr Rezept hochzuladen. Bitte überprüfen Sie Ihre Internetverbindung." } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "No es posible cargar tu receta. Por favor, verifica tu conexión a internet." + } } } }, @@ -708,6 +1128,12 @@ "state" : "translated", "value" : "Speichern" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cargar" + } } } }, @@ -718,6 +1144,12 @@ "state" : "translated", "value" : "Überprüfen" } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Validar" + } } } }, @@ -728,15 +1160,11 @@ "state" : "translated", "value" : "GitHub öffnen" } - } - } - }, - "Yield/Portions:" : { - "localizations" : { - "de" : { + }, + "es" : { "stringUnit" : { "state" : "translated", - "value" : "Portionen:" + "value" : "Visita la página de GitHub." } } } diff --git a/Nextcloud Cookbook iOS Client/Views/RecipeEditView.swift b/Nextcloud Cookbook iOS Client/Views/RecipeEditView.swift index 09c20f8..57e7c8e 100644 --- a/Nextcloud Cookbook iOS Client/Views/RecipeEditView.swift +++ b/Nextcloud Cookbook iOS Client/Views/RecipeEditView.swift @@ -62,7 +62,9 @@ struct RecipeEditView: View { @State var uploadNew: Bool = true @State private var image: PhotosPickerItem? = nil - @State private var times = [Date.zero, Date.zero, Date.zero] + @StateObject private var prepDuration: Duration = Duration() + @StateObject private var cookDuration: Duration = Duration() + @StateObject private var totalDuration: Duration = Duration() @State private var searchText: String = "" @State private var keywords: [String] = [] @State private var keywordSuggestions: [String] = [] @@ -112,7 +114,7 @@ struct RecipeEditView: View { } }.padding() HStack { - Text(recipe.name == "" ? String(localized: "New recipe") : recipe.name) + Text(recipe.name == "" ? LocalizedStringKey("New recipe") : LocalizedStringKey(recipe.name)) .font(.title) .bold() .padding() @@ -148,8 +150,6 @@ struct RecipeEditView: View { selection: $keywords ) } - } header: { - Text("Discoverability") } footer: { ScrollView(.horizontal, showsIndicators: false) { HStack { @@ -161,20 +161,20 @@ struct RecipeEditView: View { } Section() { - Picker("Yield/Portions:", selection: $recipe.recipeYield) { + Picker("Servings:", selection: $recipe.recipeYield) { ForEach(0..<99, id: \.self) { i in Text("\(i)").tag(i) } } .pickerStyle(.menu) - DatePicker("Prep time:", selection: $times[0], displayedComponents: .hourAndMinute) - DatePicker("Cook time:", selection: $times[1], displayedComponents: .hourAndMinute) - DatePicker("Total time:", selection: $times[2], displayedComponents: .hourAndMinute) + DurationPicker(title: LocalizedStringKey("Preparation duration:"), duration: prepDuration) + DurationPicker(title: LocalizedStringKey("Cooking duration:"), duration: cookDuration) + DurationPicker(title: LocalizedStringKey("Total duration:"), duration: totalDuration) } - EditableListSection(title: String(localized: "Ingredients"), items: $recipe.recipeIngredient) - EditableListSection(title: String(localized: "Tools"), items: $recipe.tool) - EditableListSection(title: String(localized: "Instructions"), items: $recipe.recipeInstructions) + EditableListSection(title: LocalizedStringKey("Ingredients"), items: $recipe.recipeIngredient) + EditableListSection(title: LocalizedStringKey("Tools"), items: $recipe.tool) + EditableListSection(title: LocalizedStringKey("Instructions"), items: $recipe.recipeInstructions) } } } @@ -184,16 +184,15 @@ struct RecipeEditView: View { .onAppear { if uploadNew { return } if let prepTime = recipe.prepTime { - self.times[0] = Date.fromPTRepresentation(prepTime) + prepDuration.initFromPT(prepTime) } if let cookTime = recipe.cookTime { - self.times[1] = Date.fromPTRepresentation(cookTime) + cookDuration.initFromPT(cookTime) } if let totalTime = recipe.totalTime { - self.times[2] = Date.fromPTRepresentation(totalTime) + totalDuration.initFromPT(totalTime) } - - for keyword in recipe.keywords.components(separatedBy: ",") { + for keyword in self.recipe.keywords.components(separatedBy: ",") { keywords.append(keyword) } } @@ -213,15 +212,10 @@ struct RecipeEditView: View { } func createRecipe() { - if let date = Date.toPTRepresentation(date: times[0]) { - self.recipe.prepTime = date - } - if let date = Date.toPTRepresentation(date: times[1]) { - self.recipe.cookTime = date - } - if let date = Date.toPTRepresentation(date: times[2]) { - self.recipe.totalTime = date - } + self.recipe.prepTime = prepDuration.format() + self.recipe.cookTime = cookDuration.format() + self.recipe.totalTime = totalDuration.format() + if !self.keywords.isEmpty { self.recipe.keywords = self.keywords.joined(separator: ",") } @@ -339,7 +333,7 @@ struct RecipeEditView: View { struct EditableListSection: View { - @State var title: String + @State var title: LocalizedStringKey @Binding var items: [String] var body: some View { @@ -383,24 +377,75 @@ struct EditableListSection: View { } -struct TimePicker: View { - @Binding var hours: Int - @Binding var minutes: Int +struct DurationPicker: View { + @State var title: LocalizedStringKey + @ObservedObject var duration: Duration var body: some View { HStack { - Picker("", selection: $hours) { - ForEach(0..<99, id: \.self) { i in - Text("\(i) hours").tag(i) - } - }.pickerStyle(.wheel) - Picker("", selection: $minutes) { - ForEach(0..<60, id: \.self) { i in - Text("\(i) min").tag(i) - } - }.pickerStyle(.wheel) + Text(title) + Spacer() + TextField("00", text: $duration.hourComponent) + .keyboardType(.decimalPad) + .textFieldStyle(.roundedBorder) + .multilineTextAlignment(.trailing) + .frame(maxWidth: 40) + Text(":") + TextField("00", text: $duration.minuteComponent) + .keyboardType(.decimalPad) + .textFieldStyle(.roundedBorder) + .frame(maxWidth: 40) } - .padding(.horizontal) + .frame(maxHeight: 40) + .clipped() } } +class Duration: ObservableObject { + @Published var minuteComponent: String = "00" { + didSet { + if minuteComponent.count > 2 { + minuteComponent = oldValue + } else if minuteComponent.count == 1 { + minuteComponent = "0\(minuteComponent)" + } else if minuteComponent.count == 0 { + minuteComponent = "00" + } + let filtered = minuteComponent.filter { $0.isNumber } + if minuteComponent != filtered { + minuteComponent = filtered + } + } + } + + @Published var hourComponent: String = "00" { + didSet { + if hourComponent.count > 2 { + hourComponent = oldValue + } else if hourComponent.count == 1 { + hourComponent = "0\(hourComponent)" + } else if hourComponent.count == 0 { + hourComponent = "00" + } + let filtered = hourComponent.filter { $0.isNumber } + if hourComponent != filtered { + hourComponent = filtered + } + } + } + + func initFromPT(_ PTRepresentation: String) { + let hourRegex = /([0-9]{1,2})H/ + let minuteRegex = /([0-9]{1,2})M/ + if let match = PTRepresentation.firstMatch(of: hourRegex) { + self.hourComponent = String(match.1) + } + if let match = PTRepresentation.firstMatch(of: minuteRegex) { + self.minuteComponent = String(match.1) + } + } + + func format() -> String { + return "PT\(hourComponent)H\(minuteComponent)M00S" + } +} diff --git a/Nextcloud Cookbook iOS Client/Views/SettingsView.swift b/Nextcloud Cookbook iOS Client/Views/SettingsView.swift index d7f7eb3..c5f4a8f 100644 --- a/Nextcloud Cookbook iOS Client/Views/SettingsView.swift +++ b/Nextcloud Cookbook iOS Client/Views/SettingsView.swift @@ -32,18 +32,20 @@ fileprivate enum SettingsAlert { enum SupportedLanguage: String, Codable { case EN = "en", - DE = "de" - + DE = "de", + ES = "es" func descriptor() -> String { switch self { case .EN: return "English" case .DE: return "Deutsch" + case .ES: + return "Español" } } - static let allValues = [EN, DE] + static let allValues = [EN, DE, ES] } struct SettingsView: View {