diff --git a/Config.xcconfig b/Config.xcconfig index b24f694e25..a5236f9f4f 100644 --- a/Config.xcconfig +++ b/Config.xcconfig @@ -1,5 +1,5 @@ APP_DISPLAY_NAME = iAPS -APP_VERSION = 5.6.0 +APP_VERSION = 5.8.0 APP_BUILD_NUMBER = 1 COPYRIGHT_NOTICE = DEVELOPER_TEAM = ##TEAM_ID## diff --git a/Core_Data.xcdatamodeld/Core_Data.xcdatamodel/contents b/Core_Data.xcdatamodeld/Core_Data.xcdatamodel/contents index 6a6c521bdd..09d7e0645e 100644 --- a/Core_Data.xcdatamodeld/Core_Data.xcdatamodel/contents +++ b/Core_Data.xcdatamodeld/Core_Data.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -116,7 +116,7 @@ - + diff --git a/FreeAPS/Resources/Assets.xcassets/Contents.json b/FreeAPS/Resources/Assets.xcassets/Contents.json index 73c00596a7..2aa0709eb6 100644 --- a/FreeAPS/Resources/Assets.xcassets/Contents.json +++ b/FreeAPS/Resources/Assets.xcassets/Contents.json @@ -2,5 +2,8 @@ "info" : { "author" : "xcode", "version" : 1 + }, + "properties" : { + "compression-type" : "lossless" } } diff --git a/FreeAPS/Resources/Assets.xcassets/artficialPancreasPurple.appiconset/Contents.json b/FreeAPS/Resources/Assets.xcassets/artficialPancreasPurple.appiconset/Contents.json new file mode 100644 index 0000000000..a10b833182 --- /dev/null +++ b/FreeAPS/Resources/Assets.xcassets/artficialPancreasPurple.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "artificialPancreas_purple_2.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FreeAPS/Resources/Assets.xcassets/artficialPancreasPurple.appiconset/artificialPancreas_purple_2.png b/FreeAPS/Resources/Assets.xcassets/artficialPancreasPurple.appiconset/artificialPancreas_purple_2.png new file mode 100644 index 0000000000..239ebb2927 Binary files /dev/null and b/FreeAPS/Resources/Assets.xcassets/artficialPancreasPurple.appiconset/artificialPancreas_purple_2.png differ diff --git a/FreeAPS/Resources/Assets.xcassets/pancreasVial.appiconset/Contents.json b/FreeAPS/Resources/Assets.xcassets/pancreasVial.appiconset/Contents.json new file mode 100644 index 0000000000..f67da1234a --- /dev/null +++ b/FreeAPS/Resources/Assets.xcassets/pancreasVial.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "iAPS_vial.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/FreeAPS/Resources/Assets.xcassets/pancreasVial.appiconset/iAPS_vial.png b/FreeAPS/Resources/Assets.xcassets/pancreasVial.appiconset/iAPS_vial.png new file mode 100644 index 0000000000..e22444e931 Binary files /dev/null and b/FreeAPS/Resources/Assets.xcassets/pancreasVial.appiconset/iAPS_vial.png differ diff --git a/FreeAPS/Sources/Localizations/Main/ar.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/ar.lproj/Localizable.strings index e06dea7c32..49d2306cf2 100644 --- a/FreeAPS/Sources/Localizations/Main/ar.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/ar.lproj/Localizable.strings @@ -1573,6 +1573,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Meal Presets"; +/* Back button */ +"Back" = "رجوع"; + +/* Search Saved Food presets */ +"Search" = "Search"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Empty"; diff --git a/FreeAPS/Sources/Localizations/Main/da.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/da.lproj/Localizable.strings index 69117c66de..603f816228 100644 --- a/FreeAPS/Sources/Localizations/Main/da.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/da.lproj/Localizable.strings @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Måltid Forudindstillinger"; +/* Back button */ +"Back" = "Tilbage"; + +/* Search Saved Food presets */ +"Search" = "Search"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Tom"; diff --git a/FreeAPS/Sources/Localizations/Main/de.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/de.lproj/Localizable.strings index c684fb4772..2e416dc649 100644 --- a/FreeAPS/Sources/Localizations/Main/de.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/de.lproj/Localizable.strings @@ -477,37 +477,37 @@ Enact a temp Basal or a temp target */ "Max Bolus" = "Maximaler Bolus"; /* Insulin alert message */ -"Please verify that you have selected the correct insulin concentration before saving your settings.\n\nThe insulin vial or pen should indicate the concentration in units per milliliter (e.g., U100 indicates 100 units per milliliter, which is the standard concentration).\n\nAccurate selection is critical for proper dosing." = "Please verify that you have selected the correct insulin concentration before saving your settings.\n\nThe insulin vial or pen should indicate the concentration in units per milliliter (e.g., U100 indicates 100 units per milliliter, which is the standard concentration).\n\nAccurate selection is critical for proper dosing."; +"Please verify that you have selected the correct insulin concentration before saving your settings.\n\nThe insulin vial or pen should indicate the concentration in units per milliliter (e.g., U100 indicates 100 units per milliliter, which is the standard concentration).\n\nAccurate selection is critical for proper dosing." = "Bitte vergewissern Sie sich, dass Sie die richtige Insulinkonzentration ausgewählt haben, bevor Sie Ihre Einstellungen speichern.\n\n Auf der Insulinampulle oder dem Pen sollte die Konzentration in Einheiten pro Milliliter angegeben sein (z. B. U100 steht für 100 Einheiten pro Milliliter, was der Standardkonzentration entspricht).\n\nEine genaue Auswahl ist für die richtige Dosierung entscheidend."; /* Insulin Concentration View */ -"Concentration" = "Concentration"; +"Concentration" = "Konzentration"; /* Insulin Concentration View */ -"Insulin Concentration" = "Insulin Concentration"; +"Insulin Concentration" = "Insulinkonzentration"; /* Insulin Concentration View */ -"Change Insulin" = "Change Insulin"; +"Change Insulin" = "Insulin ändern"; /* Insulin Concentration View */ -"Insulin diluted to" = "Insulin diluted to"; +"Insulin diluted to" = "Verdünntes Insulin auf"; /* Insulin Concentration View */ -"standard concentration:" = "standard concentration:"; +"standard concentration:" = "Standardkonzentration:"; /* Insulin Concentration View */ -"units per ml" = "units per ml"; +"units per ml" = "Einheiten pro ml"; /* Insulin Concentration View */ -"Standard concentration (U 100)" = "Standard concentration (U 100)"; +"Standard concentration (U 100)" = "Standardkonzentration (U 100)"; /* Insulin Concentration View */ -"Insulin concentration increased to" = "Insulin concentration increased to"; +"Insulin concentration increased to" = "Insulinkonzentration erhöht auf"; /* Insulin Concentration View */ -"Couldn't save to pump. Try again when pump isn't busy bolusing." = "Couldn't save to pump. Try again when pump isn't busy bolusing."; +"Couldn't save to pump. Try again when pump isn't busy bolusing." = "Konnte nicht auf der Pumpe speichern. Versuchen Sie es erneut, wenn die Pumpe nicht mit einem Bolus beschäftigt ist."; /* Insulin Concentration View */ -"Saved" = "Saved"; +"Saved" = "Gespeichert"; /* Label inusulin concentration, units per ml */ "U100" = "U100"; @@ -521,7 +521,7 @@ Enact a temp Basal or a temp target */ /* Label inusulin concentration, units per ml */ "U10" = "U10"; /* Debug option, allow U50 and U10 (diluted insulin) */ -"Allow diluted insulin concentration settings" = "Allow diluted insulin concentration settings"; +"Allow diluted insulin concentration settings" = "Verdünnte Insulinkonzentration erlauben"; /* Max setting */ "Max Carbs" = "Max Kohlenhydrate"; @@ -1301,7 +1301,7 @@ Enact a temp Basal or a temp target */ "Pump is Busy." = "Die Insulinpumpe ist beschäftigt."; /* Alert when bolus is already in progress (tapping the bolus button) */ -"Bolus already in Progress!" = "Bolus already in Progress!"; +"Bolus already in Progress!" = "Ein Bolus wird bereits abgegeben!"; /* -------------- Developer settings ---------------------- */ /* Debug options */ @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Mahlzeit Voreinstellungen"; +/* Back button */ +"Back" = "Zurück"; + +/* Search Saved Food presets */ +"Search" = "Suchen"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "Neu"; + /* */ "Empty" = "Leer"; @@ -1927,13 +1936,13 @@ Enact a temp Basal or a temp target */ "Errors" = "Fehler"; /* Loop Statistics pop-up description */ -"Success = Started / Completed (loops)" = "Success = Started / Completed (loops)"; +"Success = Started / Completed (loops)" = "Erfolgreich berechnete Loops"; /* Loop Statistics pop-up */ -"Most Frequent Error" = "Most Frequent Error"; +"Most Frequent Error" = "Häufigste Fehler"; /* Loop Statistics pop-up */ -"Non-completed Loops" = "Non-completed Loops"; +"Non-completed Loops" = "Nicht abgeschlossene Loops"; /* Average loop interval */ "Interval" = "Intervall"; @@ -1981,31 +1990,32 @@ Enact a temp Basal or a temp target */ "all" = "alle"; /* Active Insulin View */ -"Active Insulin" = "Active Insulin"; +"Active Insulin" = "Aktives Insulin"; /* Active Insulin View */ -"Time with negative insulin" = "Time with negative insulin"; +"Time with negative insulin" = "Zeit mit negativem Insulin"; /* Active Insulin View */ -"Insulin compared to yesterday" = "Insulin compared to yesterday"; +"Insulin compared to yesterday" = "Insulin im Vergleich zu gestern"; /* Active Insulin View */ -"Insulin compared to average" = "Insulin compared to average"; +"Insulin compared to average" = "Insulin im Vergleich zum Durchschnitt"; /* Active Insulin View */ -"Average Insulin 10 days" = "Average Insulin 10 days"; +"Average Insulin 10 days" = "Durchs. Insulinverbrauch (10 Tage) +"; /* Active Insulin View */ -"TDD yesterday" = "TDD yesterday"; +"TDD yesterday" = "TDD gestern"; /* Active Insulin View */ -"TDD 2 days ago" = "TDD 2 days ago"; +"TDD 2 days ago" = "TDD vor 2 Tagen"; /* Active Insulin View */ -"TDD 3 days ago" = "TDD 3 days ago"; +"TDD 3 days ago" = "TDD vor 3 Tagen"; /* Active Carbohydrates View */ -"Active Carbohydrates" = "Active Carbohydrates"; +"Active Carbohydrates" = "Aktive Kohlenhydrate"; /* -------------------------------------------------------- Dexcom G7 --------------------------------------*/ @@ -2065,7 +2075,7 @@ Enact a temp Basal or a temp target */ "Just iAPS version number" = "Nur iAPS Versionsnummer"; /* Share info text */ -"Every bit of information you choose to share is uploaded anonymously. To prevent duplicate uploads, the data is identified with a unique random string saved on your phone, the recovery token." = "Alle Informationen, die Sie freigeben möchten, werden anonym hochgeladen. Um doppelte Uploads zu vermeiden, werden die Daten mit einer eindeutigen, zufälligen Zeichenfolge identifiziert, die auf Ihrem Telefon gespeichert ist."; +"Every bit of information you choose to share is uploaded anonymously. To prevent duplicate uploads, the data is identified with a unique random string saved on your phone, the recovery token." = "Alle Informationen, die Sie teilen möchten, werden anonym hochgeladen. Um das Hochladen von Duplikaten zu verhindern, werden die Daten mit einer einzigartigen zufälligen Zeichenkette identifiziert, die auf Ihrem Telefon gespeichert wird, dem Wiederherstellungs-Token.Um doppelte Uploads zu verhindern, werden die Daten durch eine eindeutige, zufällige Zeichenfolge identifiziert, die auf deinem Telefon als Wiederherstellungs-Token gespeichert wird."; /* Token section title */ "Your recovery token" = "Ihr Wiederherstellungs-Token"; @@ -2545,19 +2555,19 @@ Enact a temp Basal or a temp target */ "Threshold" = "Grenzwert"; /* Dynamic settings View */ -"Averages" = "Averages"; +"Averages" = "Durchschnitsswerte"; /* Dynamic settings View */ -"Average ISF" = "Average ISF"; +"Average ISF" = "Durchschnittlicher ISF"; /* Dynamic settings View */ -"Average CR" = "Average CR"; +"Average CR" = "Durchschnittlicher CR"; /* Dynamic settings View */ -"Average CSF" = "Average CSF"; +"Average CSF" = "Durchschnittlicher CSF"; /* Dynamic settings View */ -"ISF: Insulin Sensitivity, CR: Carb Ratio,\nCSF: Carb Sensitivity = ISF/CR" = "ISF: Insulin Sensitivity, CR: Carb Ratio,\nCSF: Carb Sensitivity = ISF/CR"; +"ISF: Insulin Sensitivity, CR: Carb Ratio,\nCSF: Carb Sensitivity = ISF/CR" = "ISF: Insulinempfindlichkeit, CR: Kohlenhydratverhältnis,\nCSF: Kohlenhydrate Empfindlichkeit = ISF/CR"; /* Header */ "Calculator settings" = "Berechnungseinstellungen"; @@ -2631,13 +2641,13 @@ Enact a temp Basal or a temp target */ "Display Glucose Delta" = "Glukose-Delta anzeigen"; /* UI/UX option */ -"Hide Concentration Badge" = "Hide Concentration Badge"; +"Hide Concentration Badge" = "Insulinkonzentrations ausblenden"; /* UI/UX option */ -"Use insulin bars" = "Use insulin bars"; +"Use insulin bars" = "Insulinbalken verwenden"; /* UI/UX option */ -"Hide the bolus amount strings when amount is under" = "Hide the bolus amount strings when amount is under"; +"Hide the bolus amount strings when amount is under" = "Bolusmengen in der Grafik ausblenden wenn sie kleiner als"; /* Setting title */ "Bolus Calculator" = "Bolus-Rechner"; diff --git a/FreeAPS/Sources/Localizations/Main/en.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/en.lproj/Localizable.strings index faa10bd63e..082a8f02e1 100644 --- a/FreeAPS/Sources/Localizations/Main/en.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/en.lproj/Localizable.strings @@ -1587,6 +1587,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Meal Presets"; +/* Back button */ +"Back" = "Back"; + +/* Search Saved Food presets */ +"Search" = "Search"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Empty"; diff --git a/FreeAPS/Sources/Localizations/Main/es.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/es.lproj/Localizable.strings index 18c185f116..a605f842ac 100644 --- a/FreeAPS/Sources/Localizations/Main/es.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/es.lproj/Localizable.strings @@ -1583,6 +1583,15 @@ Ajustes predeterminados:\n /* */ "Meal Presets" = "Atajo de comida"; +/* Back button */ +"Back" = "Atrás"; + +/* Search Saved Food presets */ +"Search" = "Search"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Vacío"; diff --git a/FreeAPS/Sources/Localizations/Main/fi.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/fi.lproj/Localizable.strings index d4d3a28b80..96ab5bc37c 100644 --- a/FreeAPS/Sources/Localizations/Main/fi.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/fi.lproj/Localizable.strings @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Meal Presets"; +/* Back button */ +"Back" = "Takaisin"; + +/* Search Saved Food presets */ +"Search" = "Search"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Empty"; diff --git a/FreeAPS/Sources/Localizations/Main/fr.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/fr.lproj/Localizable.strings index bda8d17112..11e34202e1 100644 --- a/FreeAPS/Sources/Localizations/Main/fr.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/fr.lproj/Localizable.strings @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Préréglages des repas"; +/* Back button */ +"Back" = "Retour"; + +/* Search Saved Food presets */ +"Search" = "Recherche"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "Nouveau repas"; + /* */ "Empty" = "Vide"; diff --git a/FreeAPS/Sources/Localizations/Main/he.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/he.lproj/Localizable.strings index 4e4c041617..9e74428bce 100644 --- a/FreeAPS/Sources/Localizations/Main/he.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/he.lproj/Localizable.strings @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Meal Presets"; +/* Back button */ +"Back" = "Back"; + +/* Search Saved Food presets */ +"Search" = "Search"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Empty"; diff --git a/FreeAPS/Sources/Localizations/Main/hu.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/hu.lproj/Localizable.strings index b61f58f39d..848d846dc7 100644 --- a/FreeAPS/Sources/Localizations/Main/hu.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/hu.lproj/Localizable.strings @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Meal Presets"; +/* Back button */ +"Back" = "Back"; + +/* Search Saved Food presets */ +"Search" = "Search"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Empty"; diff --git a/FreeAPS/Sources/Localizations/Main/it.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/it.lproj/Localizable.strings index 48d12c960e..b291047ddb 100644 --- a/FreeAPS/Sources/Localizations/Main/it.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/it.lproj/Localizable.strings @@ -477,37 +477,37 @@ Enact a temp Basal or a temp target */ "Max Bolus" = "Bolo massimo"; /* Insulin alert message */ -"Please verify that you have selected the correct insulin concentration before saving your settings.\n\nThe insulin vial or pen should indicate the concentration in units per milliliter (e.g., U100 indicates 100 units per milliliter, which is the standard concentration).\n\nAccurate selection is critical for proper dosing." = "Please verify that you have selected the correct insulin concentration before saving your settings.\n\nThe insulin vial or pen should indicate the concentration in units per milliliter (e.g., U100 indicates 100 units per milliliter, which is the standard concentration).\n\nAccurate selection is critical for proper dosing."; +"Please verify that you have selected the correct insulin concentration before saving your settings.\n\nThe insulin vial or pen should indicate the concentration in units per milliliter (e.g., U100 indicates 100 units per milliliter, which is the standard concentration).\n\nAccurate selection is critical for proper dosing." = "Si prega di verificare di aver selezionato la concentrazione corretta di insulina prima di salvare le impostazioni.\n\nIl flaconcino o la penna di insulina devono indicare la concentrazione in unità per millilitro (e.., U100 indica 100 unità per millilitro, che è la concentrazione standard). Una selezione giusta\n\nè fondamentale per un dosaggio adeguato."; /* Insulin Concentration View */ -"Concentration" = "Concentration"; +"Concentration" = "Concentrazione"; /* Insulin Concentration View */ -"Insulin Concentration" = "Insulin Concentration"; +"Insulin Concentration" = "Concentrazione di insulina"; /* Insulin Concentration View */ -"Change Insulin" = "Change Insulin"; +"Change Insulin" = "Modifica insulina"; /* Insulin Concentration View */ -"Insulin diluted to" = "Insulin diluted to"; +"Insulin diluted to" = "Insulina diluita fino a"; /* Insulin Concentration View */ -"standard concentration:" = "standard concentration:"; +"standard concentration:" = "concentrazione standard:"; /* Insulin Concentration View */ -"units per ml" = "units per ml"; +"units per ml" = "unità per ml"; /* Insulin Concentration View */ -"Standard concentration (U 100)" = "Standard concentration (U 100)"; +"Standard concentration (U 100)" = "Concentrazione standard (U 100)"; /* Insulin Concentration View */ -"Insulin concentration increased to" = "Insulin concentration increased to"; +"Insulin concentration increased to" = "Concentrazione di insulina aumentata a"; /* Insulin Concentration View */ -"Couldn't save to pump. Try again when pump isn't busy bolusing." = "Couldn't save to pump. Try again when pump isn't busy bolusing."; +"Couldn't save to pump. Try again when pump isn't busy bolusing." = "Impossibile salvare sulla pompa. Riprova quando il microinfusore non è occupato in erogazione di bolo."; /* Insulin Concentration View */ -"Saved" = "Saved"; +"Saved" = "Salvato"; /* Label inusulin concentration, units per ml */ "U100" = "U100"; @@ -521,7 +521,7 @@ Enact a temp Basal or a temp target */ /* Label inusulin concentration, units per ml */ "U10" = "U10"; /* Debug option, allow U50 and U10 (diluted insulin) */ -"Allow diluted insulin concentration settings" = "Allow diluted insulin concentration settings"; +"Allow diluted insulin concentration settings" = "Consenti impostazioni di concentrazione di insulina diluita"; /* Max setting */ "Max Carbs" = "Carboidrati massimi"; @@ -1301,7 +1301,7 @@ Enact a temp Basal or a temp target */ "Pump is Busy." = "Il microinfusore sta già erogando."; /* Alert when bolus is already in progress (tapping the bolus button) */ -"Bolus already in Progress!" = "Bolus already in Progress!"; +"Bolus already in Progress!" = "Bolo già in corso!"; /* -------------- Developer settings ---------------------- */ /* Debug options */ @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Pasto Predefinito"; +/* Back button */ +"Back" = "Indietro"; + +/* Search Saved Food presets */ +"Search" = "Cerca"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Vuoto"; @@ -1981,31 +1990,31 @@ Enact a temp Basal or a temp target */ "all" = "tutti"; /* Active Insulin View */ -"Active Insulin" = "Active Insulin"; +"Active Insulin" = "Insulina attiva"; /* Active Insulin View */ -"Time with negative insulin" = "Time with negative insulin"; +"Time with negative insulin" = "Tempo con insulina negativa"; /* Active Insulin View */ -"Insulin compared to yesterday" = "Insulin compared to yesterday"; +"Insulin compared to yesterday" = "Insulina rispetto a ieri"; /* Active Insulin View */ -"Insulin compared to average" = "Insulin compared to average"; +"Insulin compared to average" = "Insulina rispetto alla media"; /* Active Insulin View */ -"Average Insulin 10 days" = "Average Insulin 10 days"; +"Average Insulin 10 days" = "Insulina media a 10 giorni"; /* Active Insulin View */ -"TDD yesterday" = "TDD yesterday"; +"TDD yesterday" = "TDD ieri"; /* Active Insulin View */ -"TDD 2 days ago" = "TDD 2 days ago"; +"TDD 2 days ago" = "TDD 2 giorni fa"; /* Active Insulin View */ -"TDD 3 days ago" = "TDD 3 days ago"; +"TDD 3 days ago" = "TDD 3 giorni fa"; /* Active Carbohydrates View */ -"Active Carbohydrates" = "Active Carbohydrates"; +"Active Carbohydrates" = "Carboidrati Attivi"; /* -------------------------------------------------------- Dexcom G7 --------------------------------------*/ @@ -2546,19 +2555,19 @@ Per gli utenti più giovani si consiglia di iniziare con un dosaggio ancora più "Threshold" = "Soglia"; /* Dynamic settings View */ -"Averages" = "Averages"; +"Averages" = "Medie"; /* Dynamic settings View */ -"Average ISF" = "Average ISF"; +"Average ISF" = "Media ISF"; /* Dynamic settings View */ -"Average CR" = "Average CR"; +"Average CR" = "Media CR"; /* Dynamic settings View */ -"Average CSF" = "Average CSF"; +"Average CSF" = "Media CSF"; /* Dynamic settings View */ -"ISF: Insulin Sensitivity, CR: Carb Ratio,\nCSF: Carb Sensitivity = ISF/CR" = "ISF: Insulin Sensitivity, CR: Carb Ratio,\nCSF: Carb Sensitivity = ISF/CR"; +"ISF: Insulin Sensitivity, CR: Carb Ratio,\nCSF: Carb Sensitivity = ISF/CR" = "ISF: Sensibilità Per L'Insulina, CR: Rapporto Carb,\nCSF: Sensibilità Carb = ISF/CR"; /* Header */ "Calculator settings" = "Impostazioni calcolatore"; @@ -2632,13 +2641,13 @@ Per gli utenti più giovani si consiglia di iniziare con un dosaggio ancora più "Display Glucose Delta" = "Mostra Delta Glicemia"; /* UI/UX option */ -"Hide Concentration Badge" = "Hide Concentration Badge"; +"Hide Concentration Badge" = "Nascondi Badge Concentrazione"; /* UI/UX option */ -"Use insulin bars" = "Use insulin bars"; +"Use insulin bars" = "Usa barre dell'insulina"; /* UI/UX option */ -"Hide the bolus amount strings when amount is under" = "Hide the bolus amount strings when amount is under"; +"Hide the bolus amount strings when amount is under" = "Nascondi le stringhe di quantità del bolo quando la quantità è inferiore"; /* Setting title */ "Bolus Calculator" = "Calcolatore Bolo"; diff --git a/FreeAPS/Sources/Localizations/Main/nb.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/nb.lproj/Localizable.strings index d33bdab1a4..1cad0491f1 100644 --- a/FreeAPS/Sources/Localizations/Main/nb.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/nb.lproj/Localizable.strings @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Forvalg av måltid"; +/* Back button */ +"Back" = "Tilbake"; + +/* Search Saved Food presets */ +"Search" = "Search"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Tom"; diff --git a/FreeAPS/Sources/Localizations/Main/nl.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/nl.lproj/Localizable.strings index 25f223cfc2..0bd41f1f88 100644 --- a/FreeAPS/Sources/Localizations/Main/nl.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/nl.lproj/Localizable.strings @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Maaltijd voorinstellingen"; +/* Back button */ +"Back" = "Terug"; + +/* Search Saved Food presets */ +"Search" = "Search"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Leeg"; diff --git a/FreeAPS/Sources/Localizations/Main/pl.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/pl.lproj/Localizable.strings index c9a1a29a00..c0a0d7dc27 100644 --- a/FreeAPS/Sources/Localizations/Main/pl.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/pl.lproj/Localizable.strings @@ -1574,6 +1574,15 @@ Połączono z Nightscout!"; /* */ "Meal Presets" = "Meal Presets"; +/* Back button */ +"Back" = "Powrót"; + +/* Search Saved Food presets */ +"Search" = "Search"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Empty"; diff --git a/FreeAPS/Sources/Localizations/Main/pt-BR.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/pt-BR.lproj/Localizable.strings index 24cbe83532..edd300bc58 100644 --- a/FreeAPS/Sources/Localizations/Main/pt-BR.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/pt-BR.lproj/Localizable.strings @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Meal Presets"; +/* Back button */ +"Back" = "Back"; + +/* Search Saved Food presets */ +"Search" = "Search"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Empty"; diff --git a/FreeAPS/Sources/Localizations/Main/pt-PT.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/pt-PT.lproj/Localizable.strings index d05c66592c..f957906988 100644 --- a/FreeAPS/Sources/Localizations/Main/pt-PT.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/pt-PT.lproj/Localizable.strings @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Meal Presets"; +/* Back button */ +"Back" = "Back"; + +/* Search Saved Food presets */ +"Search" = "Search"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Empty"; diff --git a/FreeAPS/Sources/Localizations/Main/ru.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/ru.lproj/Localizable.strings index b7aa7c566c..2eeb760d7d 100644 --- a/FreeAPS/Sources/Localizations/Main/ru.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/ru.lproj/Localizable.strings @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Шаблоны"; +/* Back button */ +"Back" = "Назад"; + +/* Search Saved Food presets */ +"Search" = "Поиск"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Пустой"; diff --git a/FreeAPS/Sources/Localizations/Main/sk.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/sk.lproj/Localizable.strings index a53de0a885..95f529c864 100644 --- a/FreeAPS/Sources/Localizations/Main/sk.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/sk.lproj/Localizable.strings @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Predvoľby jedál"; +/* Back button */ +"Back" = "Späť"; + +/* Search Saved Food presets */ +"Search" = "Search"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Prázdny"; diff --git a/FreeAPS/Sources/Localizations/Main/sv.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/sv.lproj/Localizable.strings index 9ce8ecfc22..070ecbec1a 100644 --- a/FreeAPS/Sources/Localizations/Main/sv.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/sv.lproj/Localizable.strings @@ -1584,6 +1584,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Förval"; +/* Back button */ +"Back" = "Tillbaka"; + +/* Search Saved Food presets */ +"Search" = "Sök"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "Ny"; + /* */ "Empty" = "Inget"; diff --git a/FreeAPS/Sources/Localizations/Main/tr.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/tr.lproj/Localizable.strings index ca499f6c85..db873bde38 100644 --- a/FreeAPS/Sources/Localizations/Main/tr.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/tr.lproj/Localizable.strings @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Meal Presets"; +/* Back button */ +"Back" = "Geri"; + +/* Search Saved Food presets */ +"Search" = "Search"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Empty"; diff --git a/FreeAPS/Sources/Localizations/Main/uk.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/uk.lproj/Localizable.strings index d441138853..a4a0cc9e91 100644 --- a/FreeAPS/Sources/Localizations/Main/uk.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/uk.lproj/Localizable.strings @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Попередні Налаштування Їжі"; +/* Back button */ +"Back" = "Тому"; + +/* Search Saved Food presets */ +"Search" = "Пошук"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "Новий"; + /* */ "Empty" = "Порожній"; diff --git a/FreeAPS/Sources/Localizations/Main/vi.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/vi.lproj/Localizable.strings index 2f9a83af23..6ffdba5dfa 100644 --- a/FreeAPS/Sources/Localizations/Main/vi.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/vi.lproj/Localizable.strings @@ -1301,7 +1301,7 @@ Enact a temp Basal or a temp target */ "Pump is Busy." = "Bơm đang bận."; /* Alert when bolus is already in progress (tapping the bolus button) */ -"Bolus already in Progress!" = "Bolus already in Progress!"; +"Bolus already in Progress!" = "Liều bolus đang được thực hiện!"; /* -------------- Developer settings ---------------------- */ /* Debug options */ @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Trước bữa ăn"; +/* Back button */ +"Back" = "Quay Lại"; + +/* Search Saved Food presets */ +"Search" = "Tìm kiếm"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Trống rỗng"; @@ -1981,31 +1990,31 @@ Enact a temp Basal or a temp target */ "all" = "Tất cả"; /* Active Insulin View */ -"Active Insulin" = "Active Insulin"; +"Active Insulin" = "Lượng Insulin còn hoạt động"; /* Active Insulin View */ -"Time with negative insulin" = "Time with negative insulin"; +"Time with negative insulin" = "Thời gian có Insulin âm tính"; /* Active Insulin View */ -"Insulin compared to yesterday" = "Insulin compared to yesterday"; +"Insulin compared to yesterday" = "Insulin so với ngày hôm qua"; /* Active Insulin View */ -"Insulin compared to average" = "Insulin compared to average"; +"Insulin compared to average" = "Insulin so với mức trung bình"; /* Active Insulin View */ -"Average Insulin 10 days" = "Average Insulin 10 days"; +"Average Insulin 10 days" = "Insulin trung bình 10 ngày"; /* Active Insulin View */ -"TDD yesterday" = "TDD yesterday"; +"TDD yesterday" = "Tổng liều ngày hôm qua"; /* Active Insulin View */ -"TDD 2 days ago" = "TDD 2 days ago"; +"TDD 2 days ago" = "Tổng liều 2 ngày trước"; /* Active Insulin View */ -"TDD 3 days ago" = "TDD 3 days ago"; +"TDD 3 days ago" = "Tổng liều 3 ngày trước"; /* Active Carbohydrates View */ -"Active Carbohydrates" = "Active Carbohydrates"; +"Active Carbohydrates" = "Lượng Carbohydrates còn hoạt động"; /* -------------------------------------------------------- Dexcom G7 --------------------------------------*/ @@ -2546,16 +2555,16 @@ Enact a temp Basal or a temp target */ "Threshold" = "Ngưỡng"; /* Dynamic settings View */ -"Averages" = "Averages"; +"Averages" = "Trung Bình"; /* Dynamic settings View */ -"Average ISF" = "Average ISF"; +"Average ISF" = "ISF trung bình"; /* Dynamic settings View */ -"Average CR" = "Average CR"; +"Average CR" = "CR trung bình"; /* Dynamic settings View */ -"Average CSF" = "Average CSF"; +"Average CSF" = "CSF trung bình"; /* Dynamic settings View */ "ISF: Insulin Sensitivity, CR: Carb Ratio,\nCSF: Carb Sensitivity = ISF/CR" = "ISF: Insulin Sensitivity, CR: Carb Ratio,\nCSF: Carb Sensitivity = ISF/CR"; @@ -2632,13 +2641,13 @@ Enact a temp Basal or a temp target */ "Display Glucose Delta" = "Hiển thị Glucose Delta"; /* UI/UX option */ -"Hide Concentration Badge" = "Hide Concentration Badge"; +"Hide Concentration Badge" = "Ẩn nhãn nồng độ Insulin"; /* UI/UX option */ -"Use insulin bars" = "Use insulin bars"; +"Use insulin bars" = "Sử dụng thanh Insulin"; /* UI/UX option */ -"Hide the bolus amount strings when amount is under" = "Hide the bolus amount strings when amount is under"; +"Hide the bolus amount strings when amount is under" = "Ẩn số lượng bolus khi số lượng dưới"; /* Setting title */ "Bolus Calculator" = "Tính toán Bolus"; diff --git a/FreeAPS/Sources/Localizations/Main/zh-Hans.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/zh-Hans.lproj/Localizable.strings index 5ace41422a..c958512d39 100644 --- a/FreeAPS/Sources/Localizations/Main/zh-Hans.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/zh-Hans.lproj/Localizable.strings @@ -1572,6 +1572,15 @@ Enact a temp Basal or a temp target */ /* */ "Meal Presets" = "Meal Presets"; +/* Back button */ +"Back" = "Back"; + +/* Search Saved Food presets */ +"Search" = "Search"; + +/* Placeholder for name of dish when adding a new food preset */ +"New" = "New"; + /* */ "Empty" = "Empty"; diff --git a/FreeAPS/Sources/Models/Icons.swift b/FreeAPS/Sources/Models/Icons.swift index 16056b66bb..9397d527ea 100644 --- a/FreeAPS/Sources/Models/Icons.swift +++ b/FreeAPS/Sources/Models/Icons.swift @@ -23,6 +23,8 @@ enum Icon_: String, CaseIterable, Identifiable { case purpleBG = "iAPS_Purple_BG" case whiteBG = "iAPS_White_BG" case loop = "iAPS_Loop" + case artficialPancreasPurple + case pancreasVial var id: String { rawValue } } diff --git a/FreeAPS/Sources/Modules/AddCarbs/AddCarbsStateModel.swift b/FreeAPS/Sources/Modules/AddCarbs/AddCarbsStateModel.swift index 8f4668a4cc..c01882e84d 100644 --- a/FreeAPS/Sources/Modules/AddCarbs/AddCarbsStateModel.swift +++ b/FreeAPS/Sources/Modules/AddCarbs/AddCarbsStateModel.swift @@ -17,7 +17,6 @@ extension AddCarbs { @Published var useFPUconversion: Bool = false @Published var dish: String = "" @Published var selection: Presets? - @Published var summation: [String] = [] @Published var maxCarbs: Decimal = 0 @Published var note: String = "" @Published var id_: String = "" @@ -25,6 +24,10 @@ extension AddCarbs { @Published var skipBolus: Bool = false @Published var id: String? @Published var hypoTreatment = false + @Published var presetToEdit: Presets? + @Published var edit = false + + @Published var combinedPresets: [(preset: Presets?, portions: Int)] = [] let now = Date.now @@ -75,108 +78,73 @@ extension AddCarbs { func deletePreset() { if selection != nil { + carbs -= ((selection?.carbs ?? 0) as NSDecimalNumber) as Decimal + fat -= ((selection?.fat ?? 0) as NSDecimalNumber) as Decimal + protein -= ((selection?.protein ?? 0) as NSDecimalNumber) as Decimal try? coredataContext.delete(selection!) try? coredataContext.save() - carbs = 0 - fat = 0 - protein = 0 } - selection = nil } func removePresetFromNewMeal() { - let a = summation.firstIndex(where: { $0 == selection?.dish! }) - if a != nil, summation[a ?? 0] != "" { - summation.remove(at: a!) + if let index = combinedPresets.firstIndex(where: { $0.preset == selection }) { + if combinedPresets[index].portions > 1 { + combinedPresets[index].portions -= 1 + } else if combinedPresets[index].portions == 1 { + combinedPresets.remove(at: index) + selection = nil + } } } func addPresetToNewMeal() { - let test: String = selection?.dish ?? "dontAdd" - if test != "dontAdd" { - summation.append(test) + if let index = combinedPresets.firstIndex(where: { $0.preset == selection }) { + combinedPresets[index].portions += 1 + } else { + combinedPresets.append((selection, 1)) } } - func addNewPresetToWaitersNotepad(_ dish: String) { - summation.append(dish) - } - - func addToSummation() { - summation.append(selection?.dish ?? "") - } - - func waitersNotepad() -> String { - var filteredArray = summation.filter { !$0.isEmpty } + func waitersNotepad() -> [String] { + guard combinedPresets.isNotEmpty else { return [] } if carbs == 0, protein == 0, fat == 0 { - filteredArray = [] + return [] } - guard filteredArray != [] else { - return "" - } - var carbs_: Decimal = 0.0 - var fat_: Decimal = 0.0 - var protein_: Decimal = 0.0 - var presetArray = [Presets]() - - coredataContext.performAndWait { - let requestPresets = Presets.fetchRequest() as NSFetchRequest - try? presetArray = coredataContext.fetch(requestPresets) - } - var waitersNotepad = [String]() - var stringValue = "" - - for each in filteredArray { - let countedSet = NSCountedSet(array: filteredArray) - let count = countedSet.count(for: each) - if each != stringValue { - waitersNotepad.append("\(count) \(each)") - } - stringValue = each - - for sel in presetArray { - if sel.dish == each { - carbs_ += (sel.carbs)! as Decimal - fat_ += (sel.fat)! as Decimal - protein_ += (sel.protein)! as Decimal - break - } - } + var presetsString: [String] = combinedPresets.map { item in + "\(item.portions) \(item.preset?.dish ?? "")" } - let extracarbs = carbs - carbs_ - let extraFat = fat - fat_ - let extraProtein = protein - protein_ - var addedString = "" - if extracarbs > 0, filteredArray.isNotEmpty { - addedString += "Additional carbs: \(extracarbs) ," - } else if extracarbs < 0 { addedString += "Removed carbs: \(extracarbs) " } + if presetsString.isNotEmpty { + let totCarbs = combinedPresets + .compactMap({ each in (each.preset?.carbs ?? 0) as Decimal * Decimal(each.portions) }) + .reduce(0, +) + let totFat = combinedPresets.compactMap({ each in (each.preset?.fat ?? 0) as Decimal * Decimal(each.portions) }) + .reduce(0, +) + let totProtein = combinedPresets + .compactMap({ each in (each.preset?.protein ?? 0) as Decimal * Decimal(each.portions) }).reduce(0, +) - if extraFat > 0, filteredArray.isNotEmpty { - addedString += "Additional fat: \(extraFat) ," - } else if extraFat < 0 { addedString += "Removed fat: \(extraFat) ," } + if carbs > totCarbs { + presetsString.append("+ \(carbs - totCarbs) carbs") + } else if carbs < totCarbs { + presetsString.append("- \(totCarbs - carbs) carbs") + } - if extraProtein > 0, filteredArray.isNotEmpty { - addedString += "Additional protein: \(extraProtein) ," - } else if extraProtein < 0 { addedString += "Removed protein: \(extraProtein) ," } + if fat > totFat { + presetsString.append("+ \(fat - totFat) fat") + } else if fat < totFat { + presetsString.append("- \(totFat - fat) fat") + } - if addedString != "" { - waitersNotepad.append(addedString) - } - var waitersNotepadString = "" - - if waitersNotepad.count == 1 { - waitersNotepadString = waitersNotepad[0] - } else if waitersNotepad.count > 1 { - for each in waitersNotepad { - if each != waitersNotepad.last { - waitersNotepadString += " " + each + "," - } else { waitersNotepadString += " " + each } + if protein > totProtein { + presetsString.append("+ \(protein - totProtein) protein") + } else if protein < totProtein { + presetsString.append("- \(totProtein - protein) protein") } } - return waitersNotepadString + + return presetsString.removeDublicates() } func loadEntries(_ editMode: Bool) { @@ -198,6 +166,39 @@ extension AddCarbs { } } + func subtract() { + let presetCarbs = ((selection?.carbs ?? 0) as NSDecimalNumber) as Decimal + if carbs != 0, carbs - presetCarbs >= 0 { + carbs -= presetCarbs + } else { carbs = 0 } + + let presetFat = ((selection?.fat ?? 0) as NSDecimalNumber) as Decimal + if fat != 0, presetFat >= 0 { + fat -= presetFat + } else { fat = 0 } + + let presetProtein = ((selection?.protein ?? 0) as NSDecimalNumber) as Decimal + if protein != 0, presetProtein >= 0 { + protein -= presetProtein + } else { protein = 0 } + + removePresetFromNewMeal() + } + + func plus() { + carbs += ((selection?.carbs ?? 0) as NSDecimalNumber) as Decimal + fat += ((selection?.fat ?? 0) as NSDecimalNumber) as Decimal + protein += ((selection?.protein ?? 0) as NSDecimalNumber) as Decimal + addPresetToNewMeal() + } + + func addU(_ selection: Presets?) { + carbs += ((selection?.carbs ?? 0) as NSDecimalNumber) as Decimal + fat += ((selection?.fat ?? 0) as NSDecimalNumber) as Decimal + protein += ((selection?.protein ?? 0) as NSDecimalNumber) as Decimal + addPresetToNewMeal() + } + func saveToCoreData(_ stored: [CarbsEntry]) { coredataContext.performAndWait { let save = Meals(context: coredataContext) diff --git a/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift b/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift index cac7e74aea..4349b22bec 100644 --- a/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift +++ b/FreeAPS/Sources/Modules/AddCarbs/View/AddCarbsRootView.swift @@ -14,14 +14,19 @@ extension AddCarbs { @State var pushed = false @State var button = false @State private var showAlert = false - @FocusState private var isFocused: Bool - + @State private var presentPresets = false + @State private var string = "" + @State private var newPreset: (dish: String, carbs: Decimal, fat: Decimal, protein: Decimal) = ("", 0, 0, 0) + @FetchRequest( entity: Presets.entity(), - sortDescriptors: [NSSortDescriptor(key: "dish", ascending: true)] + sortDescriptors: [NSSortDescriptor(key: "dish", ascending: true)], predicate: NSPredicate( + format: "dish != %@", " " as String + ) ) var carbPresets: FetchedResults @Environment(\.managedObjectContext) var moc + @Environment(\.colorScheme) var colorScheme private var formatter: NumberFormatter { let formatter = NumberFormatter() @@ -41,7 +46,11 @@ extension AddCarbs { } } } + Section { + // Saved Food presets + mealPresets.padding(.vertical, 9) + HStack { Text("Carbs").fontWeight(.semibold) Spacer() @@ -60,16 +69,18 @@ extension AddCarbs { } // Summary when combining presets - if state.waitersNotepad() != "" { - HStack { - Text("Total") - let test = state.waitersNotepad().components(separatedBy: ", ").removeDublicates() - HStack(spacing: 0) { - ForEach(test, id: \.self) { - Text($0).foregroundStyle(Color.randomGreen()).font(.footnote) - Text($0 == test[test.count - 1] ? "" : ", ") - } - }.frame(maxWidth: .infinity, alignment: .trailing) + if state.combinedPresets.isNotEmpty { + let summary = state.waitersNotepad() + if summary.isNotEmpty { + HStack { + Text("Total") + HStack(spacing: 0) { + ForEach(summary, id: \.self) { + Text($0).foregroundStyle(Color.randomGreen()).font(.footnote) + Text($0 == summary[summary.count - 1] ? "" : ", ") + } + }.frame(maxWidth: .infinity, alignment: .trailing) + } } } @@ -96,25 +107,20 @@ extension AddCarbs { label: { Image(systemName: "plus.circle") }.tint(.blue).buttonStyle(.borderless) } } - - // Optional meal note - HStack { - Text("Note").foregroundColor(.secondary) - TextField("", text: $state.note).multilineTextAlignment(.trailing) - if state.note != "", isFocused { - Button { isFocused = false } label: { Image(systemName: "keyboard.chevron.compact.down") } - .controlSize(.mini) + } + // Optional Hypo Treatment + if state.carbs > 0, let profile = state.id, profile != "None", state.carbsRequired != nil { + Section { + Button { + state.hypoTreatment = true + button.toggle() + if button { state.add(override, fetch: editMode) } } - } - .focused($isFocused) - .popover(isPresented: $isPromptPresented) { - presetPopover - } - - // Optional Hypo Treatment - if state.carbs > 0, let profile = state.id, profile != "None" { - Toggle("Hypo Treatment", isOn: $state.hypoTreatment) - } + label: { + Text("Hypo Treatment") + } + .frame(maxWidth: .infinity, alignment: .center) + }.listRowBackground(Color(.orange).opacity(0.9)).tint(.white) } Section { @@ -124,17 +130,13 @@ extension AddCarbs { } label: { Text( - ((state.skipBolus && !override && !editMode) || state.carbs <= 0 || state.hypoTreatment) ? "Save" : + ((state.skipBolus && !override && !editMode) || state.carbs <= 0) ? "Save" : "Continue" ) } .disabled(empty) .frame(maxWidth: .infinity, alignment: .center) }.listRowBackground(!empty ? Color(.systemBlue) : Color(.systemGray4)) .tint(.white) - - Section { - mealPresets - } } .compactSectionSpacing() .dynamicTypeSize(...DynamicTypeSize.xxLarge) @@ -146,155 +148,124 @@ extension AddCarbs { .navigationTitle("Add Meal") .navigationBarTitleDisplayMode(.inline) .navigationBarItems(trailing: Button("Cancel", action: state.hideModal)) - } - - private var presetPopover: some View { - Form { - Section { - TextField("Name Of Dish", text: $dish) - Button { - saved = true - if dish != "", saved { - let preset = Presets(context: moc) - preset.dish = dish - preset.fat = state.fat as NSDecimalNumber - preset.protein = state.protein as NSDecimalNumber - preset.carbs = state.carbs as NSDecimalNumber - try? moc.save() - state.addNewPresetToWaitersNotepad(dish) - saved = false - isPromptPresented = false - } - } - label: { Text("Save") } - Button { - dish = "" - saved = false - isPromptPresented = false } - label: { Text("Cancel") } - } header: { Text("Enter Meal Preset Name") } - }.dynamicTypeSize(...DynamicTypeSize.xxLarge) + .sheet(isPresented: $presentPresets, content: { presetView }) } private var empty: Bool { state.carbs <= 0 && state.fat <= 0 && state.protein <= 0 } - private var minusButton: some View { - Button { - if state.carbs != 0, - (state.carbs - (((state.selection?.carbs ?? 0) as NSDecimalNumber) as Decimal) as Decimal) >= 0 - { - state.carbs -= (((state.selection?.carbs ?? 0) as NSDecimalNumber) as Decimal) - } else { state.carbs = 0 } - - if state.fat != 0, - (state.fat - (((state.selection?.fat ?? 0) as NSDecimalNumber) as Decimal) as Decimal) >= 0 - { - state.fat -= (((state.selection?.fat ?? 0) as NSDecimalNumber) as Decimal) - } else { state.fat = 0 } - - if state.protein != 0, - (state.protein - (((state.selection?.protein ?? 0) as NSDecimalNumber) as Decimal) as Decimal) >= 0 - { - state.protein -= (((state.selection?.protein ?? 0) as NSDecimalNumber) as Decimal) - } else { state.protein = 0 } - - state.removePresetFromNewMeal() - if state.carbs == 0, state.fat == 0, state.protein == 0 { state.summation = [] } - } - label: { Image(systemName: "minus.circle") } - .disabled( - state - .selection == nil || - ( - !state.summation - .contains(state.selection?.dish ?? "") && (state.selection?.dish ?? "") != "" - ) - ) - .buttonStyle(.borderless) - .tint(.blue) - } - - private var plusButton: some View { - Button { - state.carbs += ((state.selection?.carbs ?? 0) as NSDecimalNumber) as Decimal - state.fat += ((state.selection?.fat ?? 0) as NSDecimalNumber) as Decimal - state.protein += ((state.selection?.protein ?? 0) as NSDecimalNumber) as Decimal - - state.addPresetToNewMeal() - } - label: { Image(systemName: "plus.circle") } - .disabled(state.selection == nil) - .buttonStyle(.borderless) - .tint(.blue) - } - private var mealPresets: some View { Section { HStack { - if state.selection != nil { + if state.selection == nil { + Button { presentPresets.toggle() } + label: { + HStack { + Text(state.selection?.dish ?? NSLocalizedString("Saved Food", comment: "")) + Text(">") + } + }.foregroundStyle(.secondary) + .frame(maxWidth: .infinity, alignment: .trailing) + } else { minusButton - } - Picker("Preset", selection: $state.selection) { - Text("Saved Food").tag(nil as Presets?) - ForEach(carbPresets, id: \.self) { (preset: Presets) in - Text(preset.dish ?? "").tag(preset as Presets?) - } - } - .labelsHidden() - .frame(maxWidth: .infinity, alignment: .center) - ._onBindingChange($state.selection) { _ in - state.carbs += ((state.selection?.carbs ?? 0) as NSDecimalNumber) as Decimal - state.fat += ((state.selection?.fat ?? 0) as NSDecimalNumber) as Decimal - state.protein += ((state.selection?.protein ?? 0) as NSDecimalNumber) as Decimal - state.addToSummation() - } - if state.selection != nil { + Spacer() + + Button { presentPresets.toggle() } + label: { + HStack { + Text(state.selection?.dish ?? NSLocalizedString("Saved Food", comment: "")) + Text(">") + } + }.foregroundStyle(.secondary) + Spacer() plusButton } - }.dynamicTypeSize(...DynamicTypeSize.xxLarge) + } + }.dynamicTypeSize(...DynamicTypeSize.xxLarge) + } - HStack { - Button("Delete Preset") { - showAlert.toggle() - } - .disabled(state.selection == nil) - .tint(.orange) - .buttonStyle(.borderless) - .alert( - "Delete preset '\(state.selection?.dish ?? "")'?", - isPresented: $showAlert, - actions: { - Button("No", role: .cancel) {} - Button("Yes", role: .destructive) { - state.deletePreset() - - state.carbs += ((state.selection?.carbs ?? 0) as NSDecimalNumber) as Decimal - state.fat += ((state.selection?.fat ?? 0) as NSDecimalNumber) as Decimal - state.protein += ((state.selection?.protein ?? 0) as NSDecimalNumber) as Decimal - - state.addPresetToNewMeal() - } + private var presetView: some View { + Form { + Section {} header: { + Text("Back").textCase(nil).foregroundStyle(.blue).font(.system(size: 16)) + .onTapGesture { reset() } } + + if !empty { + Section { + Button { + addfromCarbsView() } - ) + label: { + HStack { + Text("Save as Preset") + Spacer() + Text("[\(state.carbs), \(state.fat), \(state.protein)]") + } + }.frame(maxWidth: .infinity, alignment: .center) + .listRowBackground(Color(.systemBlue)).tint(.white) + } + header: { Text("Save") } + } - Spacer() + let filtered = carbPresets.filter { ($0.dish ?? "").count > 1 }.removeDublicates() + if filtered.count > 4 { + Section { + TextField("Search", text: $string) + } header: { Text("Search") } + } + let data = string.isEmpty ? filtered : carbPresets + .filter { ($0.dish ?? "").localizedCaseInsensitiveContains(string) } - Button { - isPromptPresented = true + Section { + ForEach(data, id: \.self) { preset in + presetsList(for: preset) + }.onDelete(perform: delete) + } header: { + HStack { + Text("Saved Food") + Button { + state.presetToEdit = Presets(context: moc) + newPreset = (NSLocalizedString("New", comment: ""), 0, 0, 0) + state.edit = true + } label: { Image(systemName: "plus").font(.system(size: 22)) } + .buttonStyle(.borderless).frame(maxWidth: .infinity, alignment: .trailing) } - label: { Text("Save as Preset") } - .buttonStyle(.borderless) - .disabled( - empty || - ( - (((state.selection?.carbs ?? 0) as NSDecimalNumber) as Decimal) == state - .carbs && (((state.selection?.fat ?? 0) as NSDecimalNumber) as Decimal) == state - .fat && (((state.selection?.protein ?? 0) as NSDecimalNumber) as Decimal) == state - .protein - ) - ) + } + } + .sheet(isPresented: $state.edit, content: { editView }) + } + + private var editView: some View { + Form { + Section { + HStack { + TextField("", text: $newPreset.dish) + } + HStack { + Text("Carbs").foregroundStyle(.secondary) + Spacer() + DecimalTextField("0", value: $newPreset.carbs, formatter: formatter) + } + HStack { + Text("Fat").foregroundStyle(.secondary) + Spacer() + DecimalTextField("0", value: $newPreset.fat, formatter: formatter) + } + HStack { + Text("Protein").foregroundStyle(.secondary) + Spacer() + DecimalTextField("0", value: $newPreset.protein, formatter: formatter) + } + } header: { Text(!addingNew ? NSLocalizedString("Edit", comment: "") : NSLocalizedString("Add", comment: "")) } + + Section { + Button { save() } + label: { Text("Save") } + .frame(maxWidth: .infinity, alignment: .center) + .listRowBackground(!disabled ? Color(.systemBlue) : Color(.systemGray4)) + .tint(.white) + .disabled(disabled) } } } @@ -326,6 +297,131 @@ extension AddCarbs { Text("grams").foregroundColor(.secondary) } } + + @ViewBuilder private func presetsList(for preset: Presets) -> some View { + let dish = preset.dish ?? "" + + // Only list saved entries + if !preset.hasChanges { + HStack { + VStack(alignment: .leading) { + Text(dish) + HStack { + Text("Carbs") + Text("\(preset.carbs ?? 0)") + Spacer() + Text("Fat") + Text("\(preset.fat ?? 0)") + Spacer() + Text("Protein") + Text("\(preset.protein ?? 0)") + }.foregroundStyle(.secondary).font(.caption).padding(.top, 2) + } + .contentShape(Rectangle()) + .onTapGesture { + state.selection = preset + state.addU(state.selection) + reset() + } + .swipeActions(edge: .leading) { + Button { + state.edit = true + state.presetToEdit = preset + update() + } label: { + Label("Edit", systemImage: "pencil.line") + } + } + } + } + } + + private var minusButton: some View { + Button { + state.subtract() + if empty { + state.selection = nil + state.combinedPresets = [] + } + } + label: { Image(systemName: "minus.circle.fill") + } + .buttonStyle(.borderless) + .disabled(state.selection == nil) + } + + private var plusButton: some View { + Button { + state.plus() + } + label: { Image(systemName: "plus.circle.fill") + } + .buttonStyle(.borderless) + .disabled(state.selection == nil) + } + + private func delete(at offsets: IndexSet) { + for index in offsets { + let preset = carbPresets[index] + moc.delete(preset) + } + do { + try moc.save() + } catch { + // To do: add error + } + } + + private func save() { + if let preset = state.presetToEdit { + preset.dish = newPreset.dish + preset.carbs = newPreset.carbs as NSDecimalNumber + preset.fat = newPreset.fat as NSDecimalNumber + preset.protein = newPreset.protein as NSDecimalNumber + } else if !disabled { + let preset = Presets(context: moc) + preset.carbs = newPreset.carbs as NSDecimalNumber + preset.fat = newPreset.fat as NSDecimalNumber + preset.protein = newPreset.protein as NSDecimalNumber + preset.dish = newPreset.dish + } + + if moc.hasChanges { + do { + try moc.save() + } catch { /* To do: add error */ } + } + + state.edit = false + } + + private func update() { + newPreset.dish = state.presetToEdit?.dish ?? "" + newPreset.carbs = (state.presetToEdit?.carbs ?? 0) as Decimal + newPreset.fat = (state.presetToEdit?.fat ?? 0) as Decimal + newPreset.protein = (state.presetToEdit?.protein ?? 0) as Decimal + } + + private func addfromCarbsView() { + newPreset = (NSLocalizedString("New", comment: ""), state.carbs, state.fat, state.protein) + state.edit = true + } + + private func reset() { + presentPresets = false + string = "" + state.presetToEdit = nil // Probably not needed + state.edit = false // Probably not needed + } + + private var disabled: Bool { + (newPreset == (NSLocalizedString("New", comment: ""), 0, 0, 0)) || (newPreset.dish == "") || + (newPreset.carbs + newPreset.fat + newPreset.protein <= 0) + } + + private var addingNew: Bool { + ((state.presetToEdit?.dish) == nil) + } } } diff --git a/FreeAPS/Sources/Modules/AutotuneConfig/AutotuneConfigStateModel.swift b/FreeAPS/Sources/Modules/AutotuneConfig/AutotuneConfigStateModel.swift index 1e41bc8716..23c8b40fb7 100644 --- a/FreeAPS/Sources/Modules/AutotuneConfig/AutotuneConfigStateModel.swift +++ b/FreeAPS/Sources/Modules/AutotuneConfig/AutotuneConfigStateModel.swift @@ -11,6 +11,7 @@ extension AutotuneConfig { @Published var autotune: Autotune? private(set) var units: GlucoseUnits = .mmolL @Published var publishedDate = Date() + @Published var increment: Double = 0.1 @Persisted(key: "lastAutotuneDate") private var lastAutotuneDate = Date() { didSet { DispatchQueue.main.async { @@ -24,6 +25,7 @@ extension AutotuneConfig { units = settingsManager.settings.units useAutotune = settingsManager.settings.useAutotune publishedDate = lastAutotuneDate + increment = Double(settingsManager.preferences.bolusIncrement) subscribeSetting(\.onlyAutotuneBasals, on: $onlyAutotuneBasals) { onlyAutotuneBasals = $0 } $useAutotune @@ -69,7 +71,7 @@ extension AutotuneConfig { BasalProfileEntry( start: String(basal.start.prefix(5)), minutes: basal.minutes, - rate: basal.rate + rate: basal.rate.roundBolus(increment: increment) ) } guard let pump = apsManager.pumpManager else { @@ -86,7 +88,7 @@ extension AutotuneConfig { self.storage.save(basals, as: OpenAPS.Settings.basalProfile) debug(.service, "Basals saved to pump!") case .failure: - debug(.service, "Basals couldn't be save to pump") + debug(.service, "Basals couldn't be saved to pump") } } } diff --git a/FreeAPS/Sources/Modules/Dynamic/View/DynamicRootView.swift b/FreeAPS/Sources/Modules/Dynamic/View/DynamicRootView.swift index a9cc4bac58..158f9d905b 100644 --- a/FreeAPS/Sources/Modules/Dynamic/View/DynamicRootView.swift +++ b/FreeAPS/Sources/Modules/Dynamic/View/DynamicRootView.swift @@ -172,7 +172,7 @@ extension Dynamic { Text("Average CR") Spacer() Text( - glucoseFormatter + daysFormatter .string(from: averages.cr as NSNumber) ?? "" ) Text("g/U").foregroundColor(.secondary) diff --git a/FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift b/FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift index 3a3e20c734..988c6139b3 100644 --- a/FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift +++ b/FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift @@ -91,7 +91,7 @@ struct CurrentGlucoseView: View { let minutesAgo = -1 * recent.dateString.timeIntervalSinceNow / 60 let text = timaAgoFormatter.string(for: Double(minutesAgo)) ?? "" Text( - minutesAgo <= 1 ? "Now" : + minutesAgo <= 1 ? NSLocalizedString("Now", comment: "") : (text + " " + NSLocalizedString("min", comment: "Short form for minutes") + " ") ) .font(.caption) diff --git a/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift b/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift index 882697f47c..ad548e99f7 100644 --- a/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift +++ b/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift @@ -834,7 +834,6 @@ extension Home { configureView() } - // .onAppear(perform: configureView) .navigationTitle("Home") .navigationBarHidden(true) .ignoresSafeArea(.keyboard) @@ -857,7 +856,6 @@ extension Home { } ) } - .onAppear(perform: configureView) } private var popup: some View {