From d6276df2576fac095b45f2c50b7197307c2d9dd3 Mon Sep 17 00:00:00 2001 From: Ivan Date: Tue, 28 Dec 2021 17:10:25 +0300 Subject: [PATCH] Release/0.2.5 (#163) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Bump dev version to 0.2.5 * Loop routine refactored * reportEnacted only in closed loop * Crowdin (#161) * Crowdin * Crowdin updates (#404) * Upload status in closed loop only * Decimal precision for sensitive values * Pause animated background when app is in background * Home view refactored * DecimalTextField fixes Co-authored-by: Jon B Mårtensson <53905247+Jon-b-m@users.noreply.github.com> --- Config.xcconfig | 2 +- .../LoopKit/tr.lproj/Localizable.strings | 4 +- .../LoopKitUI/tr.lproj/Localizable.strings | 2 +- .../tr.lproj/OmnipodPumpManager.strings | 46 +-- FreeAPS/Resources/fr.lproj/InfoPlist.strings | 14 +- FreeAPS/Sources/APS/APSManager.swift | 178 +++++---- .../AnimatedBackground/SnowScene.swift | 25 ++ .../Sources/Helpers/String+Extensions.swift | 10 + .../Main/ar.lproj/Localizable.strings | 3 + .../Main/ca.lproj/Localizable.strings | 3 + .../Main/da.lproj/Localizable.strings | 3 + .../Main/de.lproj/Localizable.strings | 3 + .../Main/es.lproj/Localizable.strings | 3 + .../Main/fi.lproj/Localizable.strings | 3 + .../Main/fr.lproj/Localizable.strings | 352 +++++++++--------- .../Main/he.lproj/Localizable.strings | 3 + .../Main/it.lproj/Localizable.strings | 3 + .../Main/nb.lproj/Localizable.strings | 13 +- .../Main/nl.lproj/Localizable.strings | 281 +++++++------- .../Main/pl.lproj/Localizable.strings | 3 + .../Main/pt-BR.lproj/Localizable.strings | 3 + .../Main/ru.lproj/Localizable.strings | 1 + .../Main/sk.lproj/Localizable.strings | 3 + .../Main/sv.lproj/Localizable.strings | 3 + .../Main/tr.lproj/Localizable.strings | 29 +- .../Main/uk.lproj/Localizable.strings | 3 + .../Main/zh-Hans.lproj/Localizable.strings | 3 + .../Sources/Models/BasalProfileEntry.swift | 17 + FreeAPS/Sources/Models/CarbRatios.swift | 17 + .../Sources/Models/InsulinSensitivities.swift | 17 + .../BasalProfileEditorStateModel.swift | 3 +- .../Modules/CREditor/CREditorStateModel.swift | 2 +- .../Modules/Home/View/HomeRootView.swift | 158 ++++---- .../ISFEditor/ISFEditorStateModel.swift | 2 +- FreeAPS/Sources/Views/DecimalTextField.swift | 19 +- 35 files changed, 722 insertions(+), 512 deletions(-) diff --git a/Config.xcconfig b/Config.xcconfig index bd921a83f..958f0f77a 100644 --- a/Config.xcconfig +++ b/Config.xcconfig @@ -1,5 +1,5 @@ APP_DISPLAY_NAME = FreeAPS X -BUILD_VERSION = 0.2.4 +BUILD_VERSION = 0.2.5 DEVELOPER_TEAM = ##TEAM_ID## BUNDLE_IDENTIFIER = ru.artpancreas.$(DEVELOPMENT_TEAM).FreeAPS APP_GROUP_ID = group.com.$(DEVELOPMENT_TEAM).loopkit.LoopGroup diff --git a/Dependencies/LoopKit/LoopKit/tr.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKit/tr.lproj/Localizable.strings index 88e3a515a..41b93e5e3 100644 --- a/Dependencies/LoopKit/LoopKit/tr.lproj/Localizable.strings +++ b/Dependencies/LoopKit/LoopKit/tr.lproj/Localizable.strings @@ -14,7 +14,7 @@ "com.loudnate.CarbKit.deleteCarbEntryUnownedErrorDescription" = "Yetkilendirme Reddedildi"; /* The error recovery suggestion when attempting to delete a sample not shared by the current app */ -"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Bu örnek Sağlık uygulamasından silinebilir"; +"com.loudnate.carbKit.sharingDeniedErrorRecoverySuggestion" = "Bu örnek Health uygulamasından silinebilir"; /* Generic pump error description */ "Communication Failure" = "İletişim Hatası"; @@ -68,7 +68,7 @@ "OK" = "Tamam"; /* The error recovery suggestion when Health sharing was denied */ -"Please re-enable sharing in Health" = "Lütfen Sağlık Uygulaması paylaşımını yeniden etkinleştirin"; +"Please re-enable sharing in Health" = "Lütfen Health paylaşımı yeniden etkinleştirin"; /* Glucose trend up */ "Rising" = "Yükselmekte"; diff --git a/Dependencies/LoopKit/LoopKitUI/tr.lproj/Localizable.strings b/Dependencies/LoopKit/LoopKitUI/tr.lproj/Localizable.strings index 4d0c508d8..9c80c567c 100644 --- a/Dependencies/LoopKit/LoopKitUI/tr.lproj/Localizable.strings +++ b/Dependencies/LoopKit/LoopKitUI/tr.lproj/Localizable.strings @@ -45,7 +45,7 @@ "Basal, bolus, and correction insulin dose amounts are unaffected." = "Bazal, bolus ve düzeltme insülin doz miktarları etkilenmez."; /* The title of the cancel action in an action sheet */ -"Cancel" = "İptal Et"; +"Cancel" = "Vazgeç"; /* The text for the override cancellation button */ "Cancel Override" = "Geçersiz kılmayı İptal et"; diff --git a/Dependencies/rileylink_ios/OmniKitUI/tr.lproj/OmnipodPumpManager.strings b/Dependencies/rileylink_ios/OmniKitUI/tr.lproj/OmnipodPumpManager.strings index b4012082a..c0d133abd 100644 --- a/Dependencies/rileylink_ios/OmniKitUI/tr.lproj/OmnipodPumpManager.strings +++ b/Dependencies/rileylink_ios/OmniKitUI/tr.lproj/OmnipodPumpManager.strings @@ -1,68 +1,68 @@ /* Class = "UITableViewSection"; headerTitle = "Remove POD"; ObjectID = "1LF-te-Bdd"; */ -"1LF-te-Bdd.headerTitle" = "Remove POD"; +"1LF-te-Bdd.headerTitle" = "POD'u kaldır"; /* Class = "UINavigationItem"; title = "RileyLink Setup"; ObjectID = "3HH-eJ-lRh"; */ -"3HH-eJ-lRh.title" = "RileyLink Setup"; +"3HH-eJ-lRh.title" = "RileyLink Kurulumu"; /* Class = "UITableViewController"; title = "Pod Settings"; ObjectID = "6vo-Ov-UpE"; */ -"6vo-Ov-UpE.title" = "Pod Settings"; +"6vo-Ov-UpE.title" = "Pod Ayarları"; /* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "91O-Un-vKc"; */ -"91O-Un-vKc.title" = "Pump Setup"; +"91O-Un-vKc.title" = "Pompa Kurulumu"; /* Class = "UITableViewSection"; footerTitle = "NOTE: Do not remove the pod's needle cap at this time."; ObjectID = "EUt-xk-Rmp"; */ -"EUt-xk-Rmp.footerTitle" = "NOTE: Do not remove the pod's needle cap at this time."; +"EUt-xk-Rmp.footerTitle" = "NOT: Şu anda pod'un plastik iğne kapağını çıkarmayın."; /* Class = "UITableViewSection"; headerTitle = "Prepare Pod"; ObjectID = "EUt-xk-Rmp"; */ -"EUt-xk-Rmp.headerTitle" = "Prepare Pod"; +"EUt-xk-Rmp.headerTitle" = "Pod'u Hazırla"; /* Class = "UILabel"; text = "Loop will remind you to change your pod before it expires. You can change this to a time convenient for you."; ObjectID = "Eng-IY-fQ7"; */ -"Eng-IY-fQ7.text" = "Loop will remind you to change your pod before it expires. You can change this to a time convenient for you."; +"Eng-IY-fQ7.text" = "Döngü, süresi dolmadan önce pod'u değiştirmenizi hatırlatacaktır. Bunun için değişimi size uygun olan bir zamanda yapabilirsiniz."; /* Class = "UILabel"; text = "Please deactivate the pod. When deactivation is complete, remove pod from body."; ObjectID = "GK7-jb-tyY"; */ -"GK7-jb-tyY.text" = "Please deactivate the pod. When deactivation is complete, remove pod from body."; +"GK7-jb-tyY.text" = "Lütfen pod'u devre dışı bırakın. Devre dışı bırakma tamamlandığında, pod'u vücudunuzdan çıkarın."; /* Class = "UINavigationItem"; title = "Insert Cannula"; ObjectID = "HwT-30-f0y"; */ -"HwT-30-f0y.title" = "Insert Cannula"; +"HwT-30-f0y.title" = "Kanül Yerleştir"; /* Class = "UILabel"; text = "Prepare site. Remove the pod's needle cap and adhesive backing. If pod is OK, apply to site."; ObjectID = "Iuv-5M-bDH"; */ -"Iuv-5M-bDH.text" = "Prepare site. Remove the pod's needle cap and adhesive backing. If pod is OK, apply to site."; +"Iuv-5M-bDH.text" = "İnfüzyon bölgesini hazırlayın. Pod'un plastik iğne kapağını ve yapışkan desteğini çıkarın. Herşey yolunda ise pod'u infüzyon bölgesine yapıştırın."; /* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "aNg-mm-Uuy"; */ -"aNg-mm-Uuy.title" = "Pump Setup"; +"aNg-mm-Uuy.title" = "Pompa Kurulumu"; /* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "ack-ra-XH6"; */ -"ack-ra-XH6.title" = "Pump Setup"; +"ack-ra-XH6.title" = "Pompa Kurulumu"; /* Class = "UILabel"; text = "Your Pod is ready for use."; ObjectID = "bJ5-iH-fnF"; */ -"bJ5-iH-fnF.text" = "Your Pod is ready for use."; +"bJ5-iH-fnF.text" = "Pod'unuz kullanıma hazır."; /* Class = "UILabel"; text = "Reminder"; ObjectID = "ePA-6p-q8C"; */ -"ePA-6p-q8C.text" = "Reminder"; +"ePA-6p-q8C.text" = "Hatırlatıcı"; /* Class = "UINavigationItem"; title = "Pod Pairing"; ObjectID = "jVO-Ut-MhL"; */ -"jVO-Ut-MhL.title" = "Pod Pairing"; +"jVO-Ut-MhL.title" = "Pod Eşleştiriliyor"; /* Class = "UITableViewController"; title = "Pump Setup"; ObjectID = "k1Y-x4-m0a"; */ -"k1Y-x4-m0a.title" = "Pump Setup"; +"k1Y-x4-m0a.title" = "Pompa Kurulumu"; /* Class = "UILabel"; text = "Review your settings below. They will be programmed into the pod during pairing. You can change these settings at any time in Loopʼs Settings screen."; ObjectID = "kLL-SQ-K0a"; */ -"kLL-SQ-K0a.text" = "Review your settings below. They will be programmed into the pod during pairing. You can change these settings at any time in Loopʼs Settings screen."; +"kLL-SQ-K0a.text" = "Aşağıdaki ayarlarınızı gözden geçirin. Pod eşleştirme sırasında bu ayarlar programlanacaktır. Bu ayarları istediğiniz zaman Loop'un Ayarlar ekranından değiştirebilirsiniz."; /* Class = "UINavigationItem"; title = "Setup Complete"; ObjectID = "nDb-R5-e02"; */ -"nDb-R5-e02.title" = "Setup Complete"; +"nDb-R5-e02.title" = "Kurulum tamamlandı"; /* Class = "UITableViewSection"; footerTitle = "NOTE: If cannula sticks out, press cancel."; ObjectID = "rcC-ke-lUP"; */ -"rcC-ke-lUP.footerTitle" = "NOTE: If cannula sticks out, press cancel."; +"rcC-ke-lUP.footerTitle" = "NOT: Kanül dışarı çıkarsa, iptal düğmesine basın."; /* Class = "UITableViewSection"; headerTitle = "Apply POD"; ObjectID = "rcC-ke-lUP"; */ -"rcC-ke-lUP.headerTitle" = "Apply POD"; +"rcC-ke-lUP.headerTitle" = "POD'u yerleştirin"; /* Class = "UILabel"; text = "Label"; ObjectID = "vEc-Km-ewe"; */ -"vEc-Km-ewe.text" = "Label"; +"vEc-Km-ewe.text" = "Etiket"; /* Class = "UILabel"; text = "Fill a new pod with insulin. Listen for 2 beeps from the pod during filling. Keep RileyLink adjacent to the pod during pairing."; ObjectID = "vmF-Dc-3DS"; */ -"vmF-Dc-3DS.text" = "Fill a new pod with insulin. Listen for 2 beeps from the pod during filling. Keep the RileyLink about 6 inches from the pod during pairing."; +"vmF-Dc-3DS.text" = "Yeni bir pod'u insülinle doldurun. Doldurma sırasında pod'tan gelen 2 bip sesini dinleyin. Eşleştirme sırasında RileyLink'i bölmeden yaklaşık 6 inç ( ≈ 15cm) uzakta tutun."; /* Class = "UINavigationItem"; title = "Replace Pod"; ObjectID = "yy1-xf-HdR"; */ -"yy1-xf-HdR.title" = "Replace Pod"; +"yy1-xf-HdR.title" = "Pod'u değiştir"; diff --git a/FreeAPS/Resources/fr.lproj/InfoPlist.strings b/FreeAPS/Resources/fr.lproj/InfoPlist.strings index d5f689540..1fd61cc46 100644 --- a/FreeAPS/Resources/fr.lproj/InfoPlist.strings +++ b/FreeAPS/Resources/fr.lproj/InfoPlist.strings @@ -1,20 +1,20 @@ /* Privacy - NFC Scan Usage Description */ -"NFCReaderUsageDescription" = "NFC is used to scan Libre sensors."; +"NFCReaderUsageDescription" = "NFC est utilisé pour scanner les capteurs Libre."; /* Privacy - Bluetooth Always Usage Description */ -"NSBluetoothAlwaysUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices"; +"NSBluetoothAlwaysUsageDescription" = "Bluetooth est utilisé pour communiquer avec la pompe à insuline et les dispositifs de surveillance continue du glucose"; /* Privacy - Bluetooth Peripheral Usage Description */ -"NSBluetoothPeripheralUsageDescription" = "Bluetooth is used to communicate with insulin pump and continuous glucose monitor devices"; +"NSBluetoothPeripheralUsageDescription" = "Bluetooth est utilisé pour communiquer avec la pompe à insuline et les dispositifs de surveillance continue du glucose"; /* Privacy - Face ID Usage Description */ -"NSFaceIDUsageDescription" = "For authorized acces to bolus"; +"NSFaceIDUsageDescription" = "Pour les accès autorisés au bolus"; /* Privacy - Calendars Usage Description */ -"NSCalendarsUsageDescription" = "Calendar is used to create a new glucose events."; +"NSCalendarsUsageDescription" = "Le calendrier est utilisé pour créer un nouvel événement de glycémie."; /* Privacy - Health Update Usage Description */ -"NSHealthUpdateUsageDescription" = "Health App is used to store blood glucose data"; +"NSHealthUpdateUsageDescription" = "L'application Santé est utilisée pour stocker les données de glycémie"; /* Privacy - Health Share Usage Description */ -"NSHealthShareUsageDescription" = "Health App is used to store blood glucose data"; +"NSHealthShareUsageDescription" = "L'application Santé est utilisée pour stocker les données de glycémie"; diff --git a/FreeAPS/Sources/APS/APSManager.swift b/FreeAPS/Sources/APS/APSManager.swift index e210af422..746d3b961 100644 --- a/FreeAPS/Sources/APS/APSManager.swift +++ b/FreeAPS/Sources/APS/APSManager.swift @@ -108,9 +108,7 @@ final class BaseAPSManager: APSManager, Injectable { lastLoopDateSubject.send(lastLoopDate) isLooping - .sink { value in - self.deviceDataManager.loopInProgress = value - } + .weakAssign(to: \.deviceDataManager.loopInProgress, on: self) .store(in: &lifetime) } @@ -147,6 +145,7 @@ final class BaseAPSManager: APSManager, Injectable { deviceDataManager.heartbeat(date: date) } + // Loop entry point private func loop() { guard !isLooping.value else { warning(.apsManager, "Already looping, skip") @@ -156,51 +155,71 @@ final class BaseAPSManager: APSManager, Injectable { debug(.apsManager, "Starting loop") isLooping.send(true) determineBasal() - .sink { [weak self] ok in - guard let self = self else { return } + .replaceEmpty(with: false) + .flatMap { [weak self] success -> AnyPublisher in + guard let self = self, success else { + return Fail(error: APSError.apsError(message: "Determine basal failed")).eraseToAnyPublisher() + } - if ok { - self.nightscout.uploadStatus() - if self.settings.closedLoop { - self.enactSuggested() - } else { - self.isLooping.send(false) - self.lastLoopDate = Date() - } + // Open loop completed + guard self.settings.closedLoop else { + return Just(()).setFailureType(to: Error.self).eraseToAnyPublisher() + } + + self.nightscout.uploadStatus() + + // Closed loop - enact suggested + return self.enactSuggested() + } + .sink { [weak self] completion in + guard let self = self else { return } + if case let .failure(error) = completion { + self.loopCompleted(error: error) } else { - self.isLooping.send(false) + self.loopCompleted() } - }.store(in: &lifetime) + } receiveValue: {} + .store(in: &lifetime) } - private func verifyStatus() -> Bool { + // Loop exit point + private func loopCompleted(error: Error? = nil) { + isLooping.send(false) + + if let error = error { + warning(.apsManager, "Loop failed with error: \(error.localizedDescription)") + processError(error) + } else { + debug(.apsManager, "Loop succeeded") + lastLoopDate = Date() + lastError.send(nil) + } + + if settings.closedLoop { + reportEnacted(received: error == nil) + } + } + + private func verifyStatus() -> Error? { guard let pump = pumpManager else { - debug(.apsManager, "Pump is not set") - processError(APSError.invalidPumpState(message: "Pump not set")) - return false + return APSError.invalidPumpState(message: "Pump not set") } let status = pump.status.pumpStatus guard !status.bolusing else { - debug(.apsManager, "Pump is bolusing") - processError(APSError.invalidPumpState(message: "Pump is bolusing")) - return false + return APSError.invalidPumpState(message: "Pump is bolusing") } guard !status.suspended else { - debug(.apsManager, "Pump suspended") - processError(APSError.invalidPumpState(message: "Pump suspended")) - return false + return APSError.invalidPumpState(message: "Pump suspended") } let reservoir = storage.retrieve(OpenAPS.Monitor.reservoir, as: Decimal.self) ?? 100 guard reservoir > 0 else { - debug(.apsManager, "Reservoir is empty") - processError(APSError.invalidPumpState(message: "Reservoir is empty")) - return false + return APSError.invalidPumpState(message: "Reservoir is empty") } - return true + return nil } private func autosens() -> AnyPublisher { @@ -301,7 +320,17 @@ final class BaseAPSManager: APSManager, Injectable { private var bolusReporter: DoseProgressReporter? func enactBolus(amount: Double, isSMB: Bool) { - guard let pump = pumpManager, verifyStatus() else { return } + if let error = verifyStatus() { + processError(error) + processQueue.async { + self.broadcaster.notify(BolusFailureObserver.self, on: self.processQueue) { + $0.bolusDidFail() + } + } + return + } + + guard let pump = pumpManager else { return } let roundedAmout = pump.roundToSupportedBolusVolume(units: amount) @@ -348,7 +377,12 @@ final class BaseAPSManager: APSManager, Injectable { } func enactTempBasal(rate: Double, duration: TimeInterval) { - guard let pump = pumpManager, verifyStatus() else { return } + if let error = verifyStatus() { + processError(error) + return + } + + guard let pump = pumpManager else { return } debug(.apsManager, "Enact temp basal \(rate) - \(duration)") let roundedAmout = pump.roundToSupportedBasalRate(unitsPerHour: rate) @@ -402,7 +436,8 @@ final class BaseAPSManager: APSManager, Injectable { switch action { case let .bolus(amount): - guard verifyStatus() else { + if let error = verifyStatus() { + processError(error) return } let roundedAmount = pump.roundToSupportedBolusVolume(units: Double(amount)) @@ -419,7 +454,8 @@ final class BaseAPSManager: APSManager, Injectable { case let .pump(pumpAction): switch pumpAction { case .suspend: - guard verifyStatus(), !pump.status.pumpStatus.suspended else { + if let error = verifyStatus() { + processError(error) return } pump.suspendDelivery { error in @@ -450,7 +486,11 @@ final class BaseAPSManager: APSManager, Injectable { debug(.apsManager, "Closed loop \(closedLoop) by Announcement") announcementsStorage.storeAnnouncements([announcement], enacted: true) case let .tempbasal(rate, duration): - guard verifyStatus(), !settings.closedLoop else { + if let error = verifyStatus() { + processError(error) + return + } + guard !settings.closedLoop else { return } let roundedRate = pump.roundToSupportedBasalRate(unitsPerHour: Double(rate)) @@ -489,30 +529,27 @@ final class BaseAPSManager: APSManager, Injectable { } } - private func enactSuggested() { + private func enactSuggested() -> AnyPublisher { guard let suggested = storage.retrieve(OpenAPS.Enact.suggested, as: Suggestion.self) else { - isLooping.send(false) - warning(.apsManager, "Suggestion not found") - processError(APSError.apsError(message: "Suggestion not found")) - return + return Fail(error: APSError.apsError(message: "Suggestion not found")).eraseToAnyPublisher() } guard Date().timeIntervalSince(suggested.deliverAt ?? .distantPast) < Config.eхpirationInterval else { - isLooping.send(false) - warning(.apsManager, "Suggestion expired") - processError(APSError.apsError(message: "Suggestion expired")) - return + return Fail(error: APSError.apsError(message: "Suggestion expired")).eraseToAnyPublisher() } guard let pump = pumpManager else { - isLooping.send(false) - warning(.apsManager, "Pump not set") - processError(APSError.invalidPumpState(message: "Pump not set")) - return + return Fail(error: APSError.apsError(message: "Pump not set")).eraseToAnyPublisher() } let basalPublisher: AnyPublisher = Deferred { () -> AnyPublisher in - guard let rate = suggested.rate, let duration = suggested.duration, self.verifyStatus() else { + if let error = self.verifyStatus() { + return Fail(error: error).eraseToAnyPublisher() + } + + guard let rate = suggested.rate, let duration = suggested.duration else { + // It is OK, no temp required + debug(.apsManager, "No temp required") return Just(()).setFailureType(to: Error.self) .eraseToAnyPublisher() } @@ -525,7 +562,12 @@ final class BaseAPSManager: APSManager, Injectable { }.eraseToAnyPublisher() let bolusPublisher: AnyPublisher = Deferred { () -> AnyPublisher in - guard let units = suggested.units, self.verifyStatus() else { + if let error = self.verifyStatus() { + return Fail(error: error).eraseToAnyPublisher() + } + guard let units = suggested.units else { + // It is OK, no bolus required + debug(.apsManager, "No bolus required") return Just(()).setFailureType(to: Error.self) .eraseToAnyPublisher() } @@ -536,26 +578,11 @@ final class BaseAPSManager: APSManager, Injectable { .eraseToAnyPublisher() }.eraseToAnyPublisher() - basalPublisher - .flatMap { bolusPublisher } - .sink { [weak self] completion in - if case let .failure(error) = completion { - warning(.apsManager, "Loop failed with error: \(error.localizedDescription)") - self?.reportEnacted(suggestion: suggested, received: false) - self?.processError(APSError.pumpError(error)) - } else { - self?.reportEnacted(suggestion: suggested, received: true) - } - self?.isLooping.send(false) - } receiveValue: { - debug(.apsManager, "Loop succeeded") - self.lastError.send(nil) - self.lastLoopDate = Date() - }.store(in: &lifetime) + return basalPublisher.flatMap { bolusPublisher }.eraseToAnyPublisher() } - private func reportEnacted(suggestion: Suggestion, received: Bool) { - if suggestion.deliverAt != nil { + private func reportEnacted(received: Bool) { + if let suggestion = storage.retrieve(OpenAPS.Enact.suggested, as: Suggestion.self), suggestion.deliverAt != nil { var enacted = suggestion enacted.timestamp = Date() enacted.recieved = received @@ -602,7 +629,9 @@ private extension PumpManager { promise(.failure(error)) } } - }.eraseToAnyPublisher() + } + .mapError { APSError.pumpError($0) } + .eraseToAnyPublisher() } func enactBolus(units: Double, automatic: Bool) -> AnyPublisher { @@ -617,7 +646,9 @@ private extension PumpManager { promise(.failure(error)) } } - }.eraseToAnyPublisher() + } + .mapError { APSError.pumpError($0) } + .eraseToAnyPublisher() } func cancelBolus() -> AnyPublisher { @@ -633,6 +664,7 @@ private extension PumpManager { } } } + .mapError { APSError.pumpError($0) } .eraseToAnyPublisher() } @@ -645,7 +677,9 @@ private extension PumpManager { promise(.success(())) } } - }.eraseToAnyPublisher() + } + .mapError { APSError.pumpError($0) } + .eraseToAnyPublisher() } func resumeDelivery() -> AnyPublisher { @@ -657,7 +691,9 @@ private extension PumpManager { promise(.success(())) } } - }.eraseToAnyPublisher() + } + .mapError { APSError.pumpError($0) } + .eraseToAnyPublisher() } } diff --git a/FreeAPS/Sources/AnimatedBackground/SnowScene.swift b/FreeAPS/Sources/AnimatedBackground/SnowScene.swift index ca5118200..b6e5336e5 100644 --- a/FreeAPS/Sources/AnimatedBackground/SnowScene.swift +++ b/FreeAPS/Sources/AnimatedBackground/SnowScene.swift @@ -1,3 +1,4 @@ +import Foundation import SpriteKit class SnowScene: SKScene { @@ -9,6 +10,22 @@ class SnowScene: SKScene { snowEmitterNode.particleLifetime = 2 snowEmitterNode.particleLifetimeRange = 6 addChild(snowEmitterNode) + subscribe() + } + + private func subscribe() { + Foundation.NotificationCenter.default.addObserver( + self, + selector: #selector(didEnterBackground), + name: UIApplication.didEnterBackgroundNotification, + object: nil + ) + Foundation.NotificationCenter.default.addObserver( + self, + selector: #selector(willEnterForeground), + name: UIApplication.willEnterForegroundNotification, + object: nil + ) } override func didChangeSize(_: CGSize) { @@ -16,4 +33,12 @@ class SnowScene: SKScene { snowEmitterNode.particlePosition = CGPoint(x: size.width / 2, y: size.height) snowEmitterNode.particlePositionRange = CGVector(dx: size.width, dy: size.height) } + + @objc private func didEnterBackground() { + isPaused = true + } + + @objc private func willEnterForeground() { + isPaused = false + } } diff --git a/FreeAPS/Sources/Helpers/String+Extensions.swift b/FreeAPS/Sources/Helpers/String+Extensions.swift index dd64b889b..8893a6ed6 100644 --- a/FreeAPS/Sources/Helpers/String+Extensions.swift +++ b/FreeAPS/Sources/Helpers/String+Extensions.swift @@ -1,3 +1,5 @@ +import Foundation + extension String { func capitalizingFirstLetter() -> String { prefix(1).capitalized + dropFirst() @@ -7,3 +9,11 @@ extension String { self = capitalizingFirstLetter() } } + +extension LosslessStringConvertible { + var string: String { .init(self) } +} + +extension FloatingPoint where Self: LosslessStringConvertible { + var decimal: Decimal? { Decimal(string: string) } +} diff --git a/FreeAPS/Sources/Localizations/Main/ar.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/ar.lproj/Localizable.strings index 505835ccb..c4f7db849 100644 --- a/FreeAPS/Sources/Localizations/Main/ar.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/ar.lproj/Localizable.strings @@ -893,6 +893,9 @@ Enact a temp Basal or a temp target */ /* */ "Suspend" = "Suspend"; +/* */ +"Animated Background" = "Animated Background"; + /* Headers for settings ----------------------- */ "OpenAPS main settings" = "OpenAPS main settings"; diff --git a/FreeAPS/Sources/Localizations/Main/ca.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/ca.lproj/Localizable.strings index 30a5ba2f3..f84f43203 100644 --- a/FreeAPS/Sources/Localizations/Main/ca.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/ca.lproj/Localizable.strings @@ -893,6 +893,9 @@ Enact a temp Basal or a temp target */ /* */ "Suspend" = "Suspend"; +/* */ +"Animated Background" = "Animated Background"; + /* Headers for settings ----------------------- */ "OpenAPS main settings" = "OpenAPS main settings"; diff --git a/FreeAPS/Sources/Localizations/Main/da.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/da.lproj/Localizable.strings index 889f89b62..8770a7c4b 100644 --- a/FreeAPS/Sources/Localizations/Main/da.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/da.lproj/Localizable.strings @@ -893,6 +893,9 @@ Enact a temp Basal or a temp target */ /* */ "Suspend" = "Suspend"; +/* */ +"Animated Background" = "Animated Background"; + /* Headers for settings ----------------------- */ "OpenAPS main settings" = "OpenAPS main settings"; diff --git a/FreeAPS/Sources/Localizations/Main/de.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/de.lproj/Localizable.strings index ea25a2b15..c71326a0a 100644 --- a/FreeAPS/Sources/Localizations/Main/de.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/de.lproj/Localizable.strings @@ -893,6 +893,9 @@ Enact a temp Basal or a temp target */ /* */ "Suspend" = "Suspend"; +/* */ +"Animated Background" = "Animated Background"; + /* Headers for settings ----------------------- */ "OpenAPS main settings" = "OpenAPS Haupteinstellungen"; diff --git a/FreeAPS/Sources/Localizations/Main/es.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/es.lproj/Localizable.strings index bf08e19f9..a7cf83f25 100644 --- a/FreeAPS/Sources/Localizations/Main/es.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/es.lproj/Localizable.strings @@ -893,6 +893,9 @@ Enact a temp Basal or a temp target */ /* */ "Suspend" = "Suspend"; +/* */ +"Animated Background" = "Animated Background"; + /* Headers for settings ----------------------- */ "OpenAPS main settings" = "OpenAPS main settings"; diff --git a/FreeAPS/Sources/Localizations/Main/fi.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/fi.lproj/Localizable.strings index 505835ccb..c4f7db849 100644 --- a/FreeAPS/Sources/Localizations/Main/fi.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/fi.lproj/Localizable.strings @@ -893,6 +893,9 @@ Enact a temp Basal or a temp target */ /* */ "Suspend" = "Suspend"; +/* */ +"Animated Background" = "Animated Background"; + /* Headers for settings ----------------------- */ "OpenAPS main settings" = "OpenAPS main settings"; diff --git a/FreeAPS/Sources/Localizations/Main/fr.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/fr.lproj/Localizable.strings index 965940948..2c306fbd6 100644 --- a/FreeAPS/Sources/Localizations/Main/fr.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/fr.lproj/Localizable.strings @@ -68,7 +68,7 @@ "Add Carbs" = "Ajouter des glucides"; /* Add carbs header and button in Watch app. You can skip the last " " space. It's just for differentiation */ -"Add Carbs " = "Add Carbs "; +"Add Carbs " = "Ajouter des glucides "; /* */ "Amount Carbs" = "Quantité de Glucides"; @@ -131,7 +131,7 @@ "Top target" = "Cible haute"; /* Temp target set for ... minutes */ -"for" = "for"; +"for" = "pour"; /* Temp target set for ... minutes */ "min" = "min"; @@ -228,7 +228,7 @@ Enact a temp Basal or a temp target */ "Allow uploads" = "Autoriser les uploads"; /* API secret in NS */ -"API secret" = "API secret"; +"API secret" = "Clé secrète API"; /* Connect to NS */ "Connect" = "Se connecter"; @@ -408,19 +408,19 @@ Enact a temp Basal or a temp target */ "Other" = "Autre"; /* Whatch app alert */ -"Set temp targets presets on iPhone first" = "Set temp targets presets on iPhone first"; +"Set temp targets presets on iPhone first" = "Définir les préréglages pour les cibles temporaires sur l'iPhone d'abord"; /* Updating Watch app */ -"Updating..." = "Updating..."; +"Updating..." = "Mise à jour..."; /* Header for Temp targets in Watch app */ -"Temp Targets" = "Temp Targets"; +"Temp Targets" = "Cibles temporaires"; /* Delete carbs from Treatments list*/ -"Delete carbs?" = "Delete carbs?"; +"Delete carbs?" = "Supprimer les glucides ?"; /* Treatments list */ -"Treatments" = "Treatments"; +"Treatments" = "Traitements"; /* " min" in Treatments list */ " min" = " min"; @@ -429,28 +429,28 @@ Enact a temp Basal or a temp target */ /* Calendar and Libre transmitter settings --------------- */ /* */ -"Configure Libre Transmitter" = "Configure Libre Transmitter"; +"Configure Libre Transmitter" = "Configurer le Transmetteur Libre"; /* */ -"Calibrations" = "Calibrations"; +"Calibrations" = "Étalonnages"; /* */ -"Create events in calendar" = "Create events in calendar"; +"Create events in calendar" = "Créer des événements dans le calendrier"; /* */ -"Calendar" = "Calendar"; +"Calendar" = "Calendrier"; /* */ -"Other" = "Other"; +"Other" = "Autre"; /* */ -"Libre Transmitter" = "Libre Transmitter"; +"Libre Transmitter" = "Transmetteur Libre"; /* */ -"Libre Transmitters" = "Libre Transmitters"; +"Libre Transmitters" = "Transmetteurs Libre"; /* */ -"Bluetooth Transmitters" = "Bluetooth Transmitters"; +"Bluetooth Transmitters" = "Transmetteurs Bluetooth"; /* */ "Modes" = "Modes"; @@ -459,10 +459,10 @@ Enact a temp Basal or a temp target */ "Libre 2 Direct" = "Libre 2 Direct"; /* */ -"Select the third party transmitter you want to connect to" = "Select the third party transmitter you want to connect to"; +"Select the third party transmitter you want to connect to" = "Sélectionnez l'émetteur tiers auquel vous souhaitez vous connecter"; /* State was restored */ -"State was restored" = "State was restored"; +"State was restored" = "L'état a été restauré"; /* The short unit display string for millimoles of glucose per liter */ "mmol/L" = "mmol/L"; @@ -471,477 +471,483 @@ Enact a temp Basal or a temp target */ "mg/dL" = "mg/dL"; /* */ -"Add calibration" = "Add calibration"; +"Add calibration" = "Ajouter un calibrage"; /* When adding capillary glucose meater reading */ -"Meter glucose" = "Meter glucose"; +"Meter glucose" = "Saisir Glycémie"; /* */ "Info" = "Info"; /*v*/ -"Slope" = "Slope"; +"Slope" = "Pente"; /* */ -"Intercept" = "Intercept"; +"Intercept" = "Intercepter"; /* */ -"Chart" = "Chart"; +"Chart" = "Graphique"; /* */ -"Remove" = "Remove"; +"Remove" = "Retirer"; /* */ -"Remove Last" = "Remove Last"; +"Remove Last" = "Supprimer la dernière"; /* */ -"Remove All" = "Remove All"; +"Remove All" = "Tout supprimer"; /* */ -"About the Process" = "About the Process"; +"About the Process" = "À propos du processus"; /* */ -"Please make sure that your Libre 2 sensor is already activated and finished warming up. If you have other apps connecting to the sensor via bluetooth, these need to be shut down or uninstalled. \n\n You can only have one app communicating with the sensor via bluetooth. Then press the \"pariring and connection\" button below to start the process. Please note that the bluetooth connection might take up to a couple of minutes before it starts working." = "Please make sure that your Libre 2 sensor is already activated and finished warming up. If you have other apps connecting to the sensor via bluetooth, these need to be shut down or uninstalled. \n\n You can only have one app communicating with the sensor via bluetooth. Then press the \"pariring and connection\" button below to start the process. Please note that the bluetooth connection might take up to a couple of minutes before it starts working."; +"Please make sure that your Libre 2 sensor is already activated and finished warming up. If you have other apps connecting to the sensor via bluetooth, these need to be shut down or uninstalled. \n\n You can only have one app communicating with the sensor via bluetooth. Then press the \"pariring and connection\" button below to start the process. Please note that the bluetooth connection might take up to a couple of minutes before it starts working." = "Veuillez vous assurer que votre capteur Libre 2 est déjà activé et initialisé. Si vous avez d'autres applications qui se connectent au capteur via Bluetooth, celles-ci doivent être arrêtées ou désinstallées. \n\n Vous ne pouvez avoir qu'une seule application qui communique avec le capteur via Bluetooth. Appuyez ensuite sur le bouton \"Appareiller\" ci-dessous pour démarrer le processus. Veuillez noter que la connexion Bluetooth peut prendre jusqu'à quelques minutes avant de commencer à fonctionner."; /* */ -"Pairinginfo" = "Pairinginfo"; +"Pairinginfo" = "Infos appareillage"; /* */ -"PatchInfo" = "PatchInfo"; +"PatchInfo" = "Infos sur le patch"; /* */ -"Calibrationinfo" = "Calibrationinfo"; +"Calibrationinfo" = "Infos de calibrage"; /* */ -"Unknown" = "Unknown"; +"Unknown" = "Inconnu"; /* */ -"Not paired yet" = "Not paired yet"; +"Not paired yet" = "Pas encore appairé"; /* */ -"Pair Sensor & connect" = "Pair Sensor & connect"; +"Pair Sensor & connect" = "Appareiller"; /* */ -"Phone NFC required!" = "Phone NFC required!"; +"Phone NFC required!" = "Téléphone NFC requis !"; /* */ -"Your phone or app is not enabled for NFC communications, which is needed to pair to libre2 sensors" = "Your phone or app is not enabled for NFC communications, which is needed to pair to libre2 sensors"; +"Your phone or app is not enabled for NFC communications, which is needed to pair to libre2 sensors" = "Votre téléphone ou application n'est pas activé pour les communications NFC, ce qui est nécessaire pour appairer avec les capteurs libre2"; /* Bluetooth Power Off */ -"Bluetooth Power Off" = "Bluetooth Power Off"; +"Bluetooth Power Off" = "Bluetooth non actif"; /* Please turn on Bluetooth */ -"Please turn on Bluetooth" = "Please turn on Bluetooth"; +"Please turn on Bluetooth" = "Veuillez activer le Bluetooth"; /* No Libre Transmitter Selected */ -"No Libre Transmitter Selected" = "No Libre Transmitter Selected"; +"No Libre Transmitter Selected" = "Aucun Transmetteur Libre sélectionné"; /* Delete Transmitter and start anew. */ -"Delete CGMManager and start anew. Your libreoopweb credentials will be preserved" = "Delete CGMManager and start anew. Your libreoopweb credentials will be preserved"; +"Delete CGMManager and start anew. Your libreoopweb credentials will be preserved" = "Supprimez CGMManager et recommencez à nouveau. Vos identifiants pour libreoopweb seront conservés"; /* Invalid libre checksum */ -"Invalid libre checksum" = "Invalid libre checksum"; +"Invalid libre checksum" = "Somme de contrôle invalide"; /* Libre sensor was incorrectly read, CRCs were not valid */ -"Libre sensor was incorrectly read, CRCs were not valid" = "Libre sensor was incorrectly read, CRCs were not valid"; +"Libre sensor was incorrectly read, CRCs were not valid" = "Le capteur de libre a été mal lu, les CRC n'étaient pas valides"; /* Glucose */ -"Glucose" = "Glucose"; +"Glucose" = "Glycémie"; /* LOWALERT! */ -"LOWALERT!" = "LOWALERT!"; +"LOWALERT!" = "FAIBLE!"; /* HIGHALERT! */ -"HIGHALERT!" = "HIGHALERT!"; +"HIGHALERT!" = "HAUT !"; /* (Snoozed)*/ -"(Snoozed)" = "(Snoozed)"; +"(Snoozed)" = "(Reporté)"; /* Glucose: %@ */ -"Glucose: %@" = "Glucose: %@"; +"Glucose: %@" = "Glycémie: %@"; /* Transmitter: %@%% */ -"Transmitter: %@%%" = "Transmitter: %@%%"; +"Transmitter: %@%%" = "Transmetteur: %@%%"; /* No Sensor Detected */ -"No Sensor Detected" = "No Sensor Detected"; +"No Sensor Detected" = "Aucun capteur détecté"; /* This might be an intermittent problem, but please check that your transmitter is tightly secured over your sensor */ -"This might be an intermittent problem, but please check that your transmitter is tightly secured over your sensor" = "This might be an intermittent problem, but please check that your transmitter is tightly secured over your sensor"; +"This might be an intermittent problem, but please check that your transmitter is tightly secured over your sensor" = "Ceci peut être un problème intermittent, mais veuillez vérifier que votre transmetteur est bien positionné sur votre capteur"; /* New Sensor Detected */ -"New Sensor Detected" = "New Sensor Detected"; +"New Sensor Detected" = "Nouveau capteur détecté"; /* Please wait up to 30 minutes before glucose readings are available! */ -"Please wait up to 30 minutes before glucose readings are available!" = "Please wait up to 30 minutes before glucose readings are available!"; +"Please wait up to 30 minutes before glucose readings are available!" = "Veuillez attendre jusqu'à 30 minutes avant que les lectures de glycémie soient disponibles!"; /* Invalid Glucose sample detected, try again later */ -"Invalid Glucose sample detected, try again later" = "Invalid Glucose sample detected, try again later"; +"Invalid Glucose sample detected, try again later" = "Échantillon de glycémie non valide détecté, réessayez plus tard"; /* ensor might have temporarily stopped, fallen off or is too cold or too warm */ -"Sensor might have temporarily stopped, fallen off or is too cold or too warm" = "Sensor might have temporarily stopped, fallen off or is too cold or too warm"; +"Sensor might have temporarily stopped, fallen off or is too cold or too warm" = "Le capteur peut avoir été temporairement arrêté, tombé ou trop froid ou trop chaud"; /* Invalid Sensor Detected */ -"Invalid Sensor Detected" = "Invalid Sensor Detected"; +"Invalid Sensor Detected" = "Capteur non valide détecté"; /* Detected sensor seems not to be a libre 1 sensor! */ -"Detected sensor seems not to be a libre 1 sensor!" = "Detected sensor seems not to be a libre 1 sensor!"; +"Detected sensor seems not to be a libre 1 sensor!" = "Le capteur détecté ne semble pas être un capteur libre 1 !"; /* Detected sensor is invalid: %@ */ -"Detected sensor is invalid: %@" = "Detected sensor is invalid: %@"; +"Detected sensor is invalid: %@" = "Le capteur détecté est invalide : %@"; /* Low Battery */ -"Low battery" = "Low battery"; +"Low battery" = "Batterie faible"; /* */ -"Invalid sensor" = "Invalid sensor"; +"Invalid sensor" = "Capteur invalide"; /* */ -"Sensor change" = "Sensor change"; +"Sensor change" = "Changement de capteur"; /* */ -"Sensor expires soon" = "Sensor expires soon"; +"Sensor expires soon" = "Le capteur expire bientôt"; /* Battery is running low %@, consider charging your %@ device as soon as possible */ -"Battery is running low %@, consider charging your %@ device as soon as possible" = "Battery is running low %@, consider charging your %@ device as soon as possible"; +"Battery is running low %@, consider charging your %@ device as soon as possible" = "La batterie est faible %@, pensez à charger votre appareil %@ dès que possible"; /* Extracting calibrationdata from sensor */ -"Extracting calibrationdata from sensor" = "Extracting calibrationdata from sensor"; +"Extracting calibrationdata from sensor" = "Extraction des données de calibration depuis le capteur"; /* Sensor Ending Soon */ -"Sensor Ending Soon" = "Sensor Ending Soon"; +"Sensor Ending Soon" = "Capteur se terminant bientôt"; /* Current Sensor is Ending soon! Sensor Life left in %@ */ -"Current Sensor is Ending soon! Sensor Life left in %@" = "Current Sensor is Ending soon! Sensor Life left in %@"; +"Current Sensor is Ending soon! Sensor Life left in %@" = "Capteur actuel se termine bientôt ! Fin de vie dans %@"; /* */ -"Libre Bluetooth" = "Libre Bluetooth"; +"Libre Bluetooth" = "Bluetooth libre"; /* */ -"Snooze Alerts" = "Snooze Alerts"; +"Snooze Alerts" = "Mise en veille Alertes"; /* */ -"Last measurement" = "Last measurement"; +"Last measurement" = "Dernière mesure"; /* */ -"Sensor Footer checksum" = "Sensor Footer checksum"; +"Sensor Footer checksum" = "Somme de contrôle du capteur de pied de page"; /* */ -"Last Blood Sugar prediction" = "Last Blood Sugar prediction"; +"Last Blood Sugar prediction" = "Dernière prédiction de glycémie"; /* */ -"CurrentBG" = "CurrentBG"; +"CurrentBG" = "Glycémie actuelle"; /* */ -"Sensor Info" = "Sensor Info"; +"Sensor Info" = "Infos capteur"; /* */ -"Sensor Age" = "Sensor Age"; +"Sensor Age" = "Âge capteur"; /* */ -"Sensor Age Left" = "Sensor Age Left"; +"Sensor Age Left" = "Âge restant capteur"; /* */ -"Sensor Endtime" = "Sensor Endtime"; +"Sensor Endtime" = "Date de fin capteur"; /* */ -"Sensor State" = "Sensor State"; +"Sensor State" = "État du capteur"; /* */ -"Sensor Serial" = "Sensor Serial"; +"Sensor Serial" = "Numéro série capteur"; /* */ -"Transmitter Info" = "Transmitter Info"; +"Transmitter Info" = "Infos transmetteur"; /* */ -"Hardware" = "Hardware"; +"Hardware" = "Matériel"; /* */ -"Firmware" = "Firmware"; +"Firmware" = "Microprogramme"; /* */ -"Connection State" = "Connection State"; +"Connection State" = "État de la connexion"; /* */ -"Transmitter Type" = "Transmitter Type"; +"Transmitter Type" = "Type de Transmetteur"; /* */ -"Sensor Type" = "Sensor Type"; +"Sensor Type" = "Type de capteur"; /* */ -"Factory Calibration Parameters" = "Factory Calibration Parameters"; +"Factory Calibration Parameters" = "Paramètres d'étalonnage"; /* */ -"Valid for footer" = "Valid for footer"; +"Valid for footer" = "Valide pour pied de page"; /* */ -"Edit calibrations" = "Edit calibrations"; +"Edit calibrations" = "Modifier le calibrage"; /* */ -"edit calibration clicked" = "edit calibration clicked"; +"edit calibration clicked" = "éditer l'étalonnage selectionné"; /* */ -"Delete CGM" = "Delete CGM"; +"Delete CGM" = "Supprimer CGM"; /* */ -"Are you sure you want to remove this cgm from loop?" = "Are you sure you want to remove this cgm from loop?"; +"Are you sure you want to remove this cgm from loop?" = "Êtes-vous sûr de vouloir supprimer ce cgm de la boucle ?"; /* */ -"There is no undo" = "There is no undo"; +"There is no undo" = "Cette opération est irréversible"; /* */ -"Advanced" = "Advanced"; +"Advanced" = "Options avancées"; /* */ -"Alarms" = "Alarms"; +"Alarms" = "Alarmes"; /* */ -"Glucose Settings" = "Glucose Settings"; +"Glucose Settings" = "Paramètres Glycémiques"; /* */ "Notifications" = "Notifications"; /* */ -"Export logs" = "Export logs"; +"Export logs" = "Exporter les logs"; /* */ -"Export not available" = "Export not available"; +"Export not available" = "Exportation non disponible"; /* */ -"Log export requires ios 15" = "Log export requires ios 15"; +"Log export requires ios 15" = "Exportation du journal nécessite ios 15"; /* */ -"Got it!" = "Got it!"; +"Got it!" = "Ok!"; /* */ -"Saved to %@" = "Saved to %@"; +"Saved to %@" = "Enregistrer sur %@"; /* */ -"No logs available" = "No logs available"; +"No logs available" = "Pas de journaux disponibles"; /* */ -"Glucose Notification visibility" = "Glucose Notification visibility"; +"Glucose Notification visibility" = "Affichage des notifications de glycémie"; /* */ -"Always Notify Glucose" = "Always Notify Glucose"; +"Always Notify Glucose" = "Toujours notifier Glycémie"; /* */ -"Notify per reading" = "Notify per reading"; +"Notify per reading" = "Notifier à chaque lecture"; /* */ -"Value" = "Value"; +"Value" = "Valeur"; /* */ -"Adds Phone Battery" = "Adds Phone Battery"; +"Adds Phone Battery" = "Ajouter niveau batterie tel"; /* */ -"Adds Transmitter Battery" = "Adds Transmitter Battery"; +"Adds Transmitter Battery" = "Ajouter niveau batterie transmetteur"; /* */ -"Also vibrate" = "Also vibrate"; +"Also vibrate" = "Vibrer aussi"; /* */ -"Additional notification types" = "Additional notification types"; +"Additional notification types" = "Notifications Supplémentaires"; /* */ -"Misc" = "Misc"; +"Misc" = "Autres"; /* */ -"Unit override" = "Unit override"; +"Unit override" = "Substitution d’unité"; /* */ -"Low" = "Low"; +"Low" = "Faible"; /* */ -"High" = "High"; +"High" = "Élevée"; /* */ -"glucose" = "glucose"; +"glucose" = "glycémie"; /* */ -"Schedule " = "Schedule "; +"Schedule " = "Horaires "; /* */ -"tapped save schedules" = "tapped save schedules"; +"tapped save schedules" = "horaires de sauvegarde cliqués"; /* */ -"Error" = "Error"; +"Error" = "Erreur"; /* */ -"Some ui element was incorrectly specified" = "Some ui element was incorrectly specified"; +"Some ui element was incorrectly specified" = "Certains éléments ui ont été mal spécifiés"; /* */ -"Success" = "Success"; +"Success" = "Succès"; /* */ -"Schedules were saved successfully!" = "Schedules were saved successfully!"; +"Schedules were saved successfully!" = "Calendrier enregistré avec succès!"; /* */ -"High Glucose Alarm active" = "High Glucose Alarm active"; +"High Glucose Alarm active" = "Alarme Glycémie haute active"; /* */ -"Low Glucose Alarm active" = "Low Glucose Alarm active"; +"Low Glucose Alarm active" = "Alarme Glycémie Faible activée"; /* */ -"No Glucose Alarm active" = "No Glucose Alarm active"; +"No Glucose Alarm active" = "Aucune alarme de glucose active"; /* */ -"snoozing until %@" = "snoozing until %@"; +"snoozing until %@" = "reporter jusqu'à %@"; /* */ -"not snoozing" = "not snoozing"; +"not snoozing" = "ne pas mettre en veille"; /* */ -"nothing to see here" = "nothing to see here"; +"nothing to see here" = "rien à voir ici"; /* */ -"snooze from testview clicked" = "snooze from testview clicked"; +"snooze from testview clicked" = "mise en veille depuis la vue de test cliqué"; /* */ -"will snooze for %@ until %@" = "will snooze for %@ until %@"; +"will snooze for %@ until %@" = "mettra en veille pendant %@ jusqu'à %@"; /* */ -"Click to Snooze Alerts" = "Click to Snooze Alerts"; +"Click to Snooze Alerts" = "Cliquez pour mettre en veille les alertes"; /* */ -"Strength" = "Strength"; +"Strength" = "Intensité"; /* */ -"Hold the top of your iPhone near the sensor to pair" = "Hold the top of your iPhone near the sensor to pair"; +"Hold the top of your iPhone near the sensor to pair" = "Positionner le haut de votre iPhone près du capteur à scanner"; /* */ -"Sensor not found" = "Sensor not found"; +"Sensor not found" = "Capteur non trouvé "; /* */ -"Also play alert sound" = "Also play alert sound"; +"Also play alert sound" = "Jouer également un son d'alerte"; /* */ -"Notification Settings" = "Notification Settings"; +"Notification Settings" = "Paramètres des notifications"; /* */ -"Found devices: %d" = "Found devices: %d"; +"Found devices: %d" = "Dispositifs détectés: %d"; /* */ -"Backfill options" = "Backfill options"; +"Backfill options" = "Options rétroactif"; /* */ -"Backfilling from trend is currently not well supported by Loop" = "Backfilling from trend is currently not well supported by Loop"; +"Backfilling from trend is currently not well supported by Loop" = "La gestion des tendances rétroactives n'est actuellement pas bien pris en charge"; /* */ -"Backfill from history" = "Backfill from history"; +"Backfill from history" = "Rétroactif de l'historique"; /* */ -"Backfill from trend" = "Backfill from trend"; +"Backfill from trend" = "Remplissage depuis la tendance"; /* */ -"Debug options" = "Debug options"; +"Debug options" = "Options de débogage"; /* */ -"Adds a lot of data to the Issue Report " = "Adds a lot of data to the Issue Report "; +"Adds a lot of data to the Issue Report " = "Ajoute beaucoup de données au rapport d'anomalie "; /* */ -"Persist sensordata" = "Persist sensordata"; +"Persist sensordata" = "Conserver les données de capteur"; /* */ -"Battery" = "Battery"; +"Battery" = "Batterie"; /* */ -"Also add source info" = "Also add source info"; +"Also add source info" = "Ajouter l'info de la source"; /* */ -"Carbs Required Threshold" = "Carbs Required Threshold"; +"Carbs Required Threshold" = "Seuil de glucides requis"; /* */ -"Carbs required: %d g" = "Carbs required: %d g"; +"Carbs required: %d g" = "Glucides requis :%d g"; /* */ -"To prevent LOW required %d g of carbs" = "To prevent LOW required %d g of carbs"; +"To prevent LOW required %d g of carbs" = "Pour éviter BAS %d g de glucides requis"; /* */ -"FreeAPS X not active" = "FreeAPS X not active"; +"FreeAPS X not active" = "FreeAPS X pas actif"; /* */ -"Last loop was more then %d min ago" = "Last loop was more then %d min ago"; +"Last loop was more then %d min ago" = "Dernier bouclage depuis plus de %d min"; /* Glucose badge */ -"Show glucose on the app badge" = "Show glucose on the app badge"; +"Show glucose on the app badge" = "Afficher glycémie en tant que badge"; /* */ "Backfill glucose" = "Backfill glucose"; /* About this source */ -"About this source" = "About this source"; +"About this source" = "A propos de ce module"; + +/* */ +"Bolus failed" = "Échec du Bolus"; + +/* */ +"Bolus failed or inaccurate. Check pump history before repeating." = "Bolus échoué ou imprécis. Vérifier l’historique de la pompe avant recommencer."; /* */ -"Bolus failed" = "Bolus failed"; +"Carbs" = "Glucides"; /* */ -"Bolus failed or inaccurate. Check pump history before repeating." = "Bolus failed or inaccurate. Check pump history before repeating."; +"Temp Basal" = "Basal Temp."; /* */ -"Carbs" = "Carbs"; +"Temp Target" = "Cibles temporaires"; /* */ -"Temp Basal" = "Temp Basal"; +"Resume" = "Reprendre"; /* */ -"Temp Target" = "Temp Target"; +"Suspend" = "Suspendre"; /* */ -"Resume" = "Resume"; +"Animated Background" = "Arrière-plan dynamique"; /* */ -"Suspend" = "Suspend"; +"Animated Background" = "Animated Background"; /* Headers for settings ----------------------- */ -"OpenAPS main settings" = "OpenAPS main settings"; +"OpenAPS main settings" = "Paramètres OpenAPS"; -"OpenAPS SMB settings" = "OpenAPS SMB settings"; +"OpenAPS SMB settings" = "Paramètres OpenAPS SMB"; -"OpenAPS targets settings" = "OpenAPS targets settings"; +"OpenAPS targets settings" = "Paramètres OpenAPS Cibles"; -"OpenAPS other settings" = "OpenAPS other settings"; +"OpenAPS other settings" = "Paramètres OpenAPS Autres"; /* Glucose Simulator CGM */ -"Glucose Simulator" = "Glucose Simulator"; +"Glucose Simulator" = "Simulateur de glycémie"; /* Restored state message */ -"Bluetooth State restored (APS restarted?). Found %d peripherals, and connected to %@ with identifier %@" = "Bluetooth State restored (APS restarted?). Found %d peripherals, and connected to %@ with identifier %@"; +"Bluetooth State restored (APS restarted?). Found %d peripherals, and connected to %@ with identifier %@" = "Etat Bluetooth restoré (APS relancé ?). Trouvé %d périphériques, et connectés à %@ avec ID %@"; /* Shared app group */ -"Shared app group" = "Shared app group"; +"Shared app group" = "Groupe partagé"; /* Native G6 app */ -"Native G6 app" = "Native G6 app"; +"Native G6 app" = "App G6 native"; /* Native G5 app */ -"Native G5 app" = "Native G5 app"; +"Native G5 app" = "App G5 native"; /* Minilink transmitter */ -"Minilink transmitter" = "Minilink transmitter"; +"Minilink transmitter" = "Minilink transmetteur"; /* Simple simulator */ -"Simple simulator" = "Simple simulator"; +"Simple simulator" = "Simple simulateur"; /* Direct connection with Libre 1 transmitters or Libre 2 */ -"Direct connection with Libre 1 transmitters or Libre 2" = "Direct connection with Libre 1 transmitters or Libre 2"; +"Direct connection with Libre 1 transmitters or Libre 2" = "Directe connexion avec Libre 1 transmetteur ou Libre 2"; /* Online or internal server */ -"Online or internal server" = "Online or internal server"; +"Online or internal server" = "Serveur en ligne ou interne"; /* HealthKit intergration --------------------*/ /* */ -"Apple Health" = "Apple Health"; +"Apple Health" = "Apple Santé"; /* */ -"Connect to Apple Health" = "Connect to Apple Health"; +"Connect to Apple Health" = "Connectez Apple Santé"; /* Show when have not permissions for writing to Health */ -"For write data to Apple Health you must give permissions in Settings > Health > Data Access" = "For write data to Apple Health you must give permissions in Settings > Health > Data Access"; +"For write data to Apple Health you must give permissions in Settings > Health > Data Access" = "Pour écrire des données sur Apple Santé, vous devez donner les autorisations dans Paramètres > Santé > Accès aux données"; /* */ -"After you create glucose records in the Health app, please open FreeAPS X to help us guaranteed transfer changed data" = "After you create glucose records in the Health app, please open FreeAPS X to help us guaranteed transfer changed data"; +"After you create glucose records in the Health app, please open FreeAPS X to help us guaranteed transfer changed data" = "Une fois que vous avez créé des enregistrements de glucose dans l'application Santé, veuillez ouvrir FreeAPS X pour nous aider à garantir le transfert des données"; /* -------------------------------------------- diff --git a/FreeAPS/Sources/Localizations/Main/he.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/he.lproj/Localizable.strings index 505835ccb..c4f7db849 100644 --- a/FreeAPS/Sources/Localizations/Main/he.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/he.lproj/Localizable.strings @@ -893,6 +893,9 @@ Enact a temp Basal or a temp target */ /* */ "Suspend" = "Suspend"; +/* */ +"Animated Background" = "Animated Background"; + /* Headers for settings ----------------------- */ "OpenAPS main settings" = "OpenAPS main settings"; diff --git a/FreeAPS/Sources/Localizations/Main/it.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/it.lproj/Localizable.strings index 57711e375..bbac28976 100644 --- a/FreeAPS/Sources/Localizations/Main/it.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/it.lproj/Localizable.strings @@ -893,6 +893,9 @@ Enact a temp Basal or a temp target */ /* */ "Suspend" = "Suspend"; +/* */ +"Animated Background" = "Animated Background"; + /* Headers for settings ----------------------- */ "OpenAPS main settings" = "Impostazioni principali di OpenAPS"; diff --git a/FreeAPS/Sources/Localizations/Main/nb.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/nb.lproj/Localizable.strings index 1c75d74b3..7794398b9 100644 --- a/FreeAPS/Sources/Localizations/Main/nb.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/nb.lproj/Localizable.strings @@ -879,19 +879,22 @@ Enact a temp Basal or a temp target */ "Bolus failed or inaccurate. Check pump history before repeating." = "Bolus mislyktes eller var upresis. Kontroller bolus-historikken før du gjentar."; /* */ -"Carbs" = "Carbs"; +"Carbs" = "Karbo"; /* */ -"Temp Basal" = "Temp Basal"; +"Temp Basal" = "Midlertidig basal"; /* */ -"Temp Target" = "Temp Target"; +"Temp Target" = "Midlertidig mål"; /* */ -"Resume" = "Resume"; +"Resume" = "Gjenoppta leveranse"; /* */ -"Suspend" = "Suspend"; +"Suspend" = "Pause leveranse"; + +/* */ +"Animated Background" = "Animert bakgrunn"; /* Headers for settings ----------------------- */ diff --git a/FreeAPS/Sources/Localizations/Main/nl.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/nl.lproj/Localizable.strings index 5f219558b..ef8e1331e 100644 --- a/FreeAPS/Sources/Localizations/Main/nl.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/nl.lproj/Localizable.strings @@ -462,7 +462,7 @@ Enact a temp Basal or a temp target */ "Select the third party transmitter you want to connect to" = "Selecteer de zender van de derde partij waarmee u wilt verbinden"; /* State was restored */ -"State was restored" = "Staat is hersteld"; +"State was restored" = "Staat is teruggezet"; /* The short unit display string for millimoles of glucose per liter */ "mmol/L" = "mmol/l"; @@ -480,10 +480,10 @@ Enact a temp Basal or a temp target */ "Info" = "Info"; /*v*/ -"Slope" = "Slope"; +"Slope" = "Toename"; /* */ -"Intercept" = "Intercept"; +"Intercept" = "Onderschep"; /* */ "Chart" = "Grafiek"; @@ -531,106 +531,106 @@ Enact a temp Basal or a temp target */ "Bluetooth Power Off" = "Bluetooth uitschakelen"; /* Please turn on Bluetooth */ -"Please turn on Bluetooth" = "Please turn on Bluetooth"; +"Please turn on Bluetooth" = "Activeer Bluetooth a.u.b."; /* No Libre Transmitter Selected */ -"No Libre Transmitter Selected" = "No Libre Transmitter Selected"; +"No Libre Transmitter Selected" = "Geen Libre zender geselecteerd"; /* Delete Transmitter and start anew. */ -"Delete CGMManager and start anew. Your libreoopweb credentials will be preserved" = "Delete CGMManager and start anew. Your libreoopweb credentials will be preserved"; +"Delete CGMManager and start anew. Your libreoopweb credentials will be preserved" = "Verwijder CGMManager en start opnieuw. De libreoopweb gegevens blijven bewaard"; /* Invalid libre checksum */ -"Invalid libre checksum" = "Invalid libre checksum"; +"Invalid libre checksum" = "Ongeldige libre controlesom"; /* Libre sensor was incorrectly read, CRCs were not valid */ -"Libre sensor was incorrectly read, CRCs were not valid" = "Libre sensor was incorrectly read, CRCs were not valid"; +"Libre sensor was incorrectly read, CRCs were not valid" = "Libre sensor is onjuist gelezen, CRC's waren niet geldig"; /* Glucose */ -"Glucose" = "Glucose"; +"Glucose" = "Glucosewaarde"; /* LOWALERT! */ -"LOWALERT!" = "LOWALERT!"; +"LOWALERT!" = "Waarschuwing Laag!"; /* HIGHALERT! */ -"HIGHALERT!" = "HIGHALERT!"; +"HIGHALERT!" = "Waarschuwing Hoog!"; /* (Snoozed)*/ -"(Snoozed)" = "(Snoozed)"; +"(Snoozed)" = "(Uitstellen)"; /* Glucose: %@ */ -"Glucose: %@" = "Glucose: %@"; +"Glucose: %@" = "Bloedsuiker: %@"; /* Transmitter: %@%% */ -"Transmitter: %@%%" = "Transmitter: %@%%"; +"Transmitter: %@%%" = "Zender: %@%%"; /* No Sensor Detected */ -"No Sensor Detected" = "No Sensor Detected"; +"No Sensor Detected" = "Geen Sensor Gevonden"; /* This might be an intermittent problem, but please check that your transmitter is tightly secured over your sensor */ -"This might be an intermittent problem, but please check that your transmitter is tightly secured over your sensor" = "This might be an intermittent problem, but please check that your transmitter is tightly secured over your sensor"; +"This might be an intermittent problem, but please check that your transmitter is tightly secured over your sensor" = "Dit kan een tijdelijk probleem zijn, maar controleer of uw zender stevig vastzit op uw sensor"; /* New Sensor Detected */ -"New Sensor Detected" = "New Sensor Detected"; +"New Sensor Detected" = "Nieuwe Sensor Gevonden"; /* Please wait up to 30 minutes before glucose readings are available! */ -"Please wait up to 30 minutes before glucose readings are available!" = "Please wait up to 30 minutes before glucose readings are available!"; +"Please wait up to 30 minutes before glucose readings are available!" = "Gelieve tot 30 minuten te wachten voordat glucosewaardes beschikbaar zijn!"; /* Invalid Glucose sample detected, try again later */ -"Invalid Glucose sample detected, try again later" = "Invalid Glucose sample detected, try again later"; +"Invalid Glucose sample detected, try again later" = "Ongeldige glucosewaarde ontdekt, probeer het later opnieuw"; /* ensor might have temporarily stopped, fallen off or is too cold or too warm */ -"Sensor might have temporarily stopped, fallen off or is too cold or too warm" = "Sensor might have temporarily stopped, fallen off or is too cold or too warm"; +"Sensor might have temporarily stopped, fallen off or is too cold or too warm" = "Mogelijk is de sensor tijdelijk gestopt, losgeraakt of te koud of te warm"; /* Invalid Sensor Detected */ -"Invalid Sensor Detected" = "Invalid Sensor Detected"; +"Invalid Sensor Detected" = "Ongeldige Sensor Gevonden"; /* Detected sensor seems not to be a libre 1 sensor! */ -"Detected sensor seems not to be a libre 1 sensor!" = "Detected sensor seems not to be a libre 1 sensor!"; +"Detected sensor seems not to be a libre 1 sensor!" = "Gevonden sensor lijkt geen Libre 1 sensor te zijn!"; /* Detected sensor is invalid: %@ */ -"Detected sensor is invalid: %@" = "Detected sensor is invalid: %@"; +"Detected sensor is invalid: %@" = "Gevonden sensor is ongeldig: %@"; /* Low Battery */ -"Low battery" = "Low battery"; +"Low battery" = "Batterij bijna leeg"; /* */ -"Invalid sensor" = "Invalid sensor"; +"Invalid sensor" = "Ongeldige sensor"; /* */ -"Sensor change" = "Sensor change"; +"Sensor change" = "Sensor wisselen"; /* */ -"Sensor expires soon" = "Sensor expires soon"; +"Sensor expires soon" = "Sensor verloopt binnenkort"; /* Battery is running low %@, consider charging your %@ device as soon as possible */ -"Battery is running low %@, consider charging your %@ device as soon as possible" = "Battery is running low %@, consider charging your %@ device as soon as possible"; +"Battery is running low %@, consider charging your %@ device as soon as possible" = "Batterijniveau is laag %@, laad uw %@ apparaat zo snel mogelijk op"; /* Extracting calibrationdata from sensor */ -"Extracting calibrationdata from sensor" = "Extracting calibrationdata from sensor"; +"Extracting calibrationdata from sensor" = "Kalibratiegegevens uit de sensor halen"; /* Sensor Ending Soon */ -"Sensor Ending Soon" = "Sensor Ending Soon"; +"Sensor Ending Soon" = "Sensor verloopt binnenkort"; /* Current Sensor is Ending soon! Sensor Life left in %@ */ -"Current Sensor is Ending soon! Sensor Life left in %@" = "Current Sensor is Ending soon! Sensor Life left in %@"; +"Current Sensor is Ending soon! Sensor Life left in %@" = "Sensor verloopt binnenkort! Sensor verloopt in %@"; /* */ "Libre Bluetooth" = "Libre Bluetooth"; /* */ -"Snooze Alerts" = "Snooze Alerts"; +"Snooze Alerts" = "Alarmen tijdelijk uitschakelen"; /* */ -"Last measurement" = "Last measurement"; +"Last measurement" = "Laatste meting"; /* */ -"Sensor Footer checksum" = "Sensor Footer checksum"; +"Sensor Footer checksum" = "Sensor voettekst controlesom"; /* */ -"Last Blood Sugar prediction" = "Last Blood Sugar prediction"; +"Last Blood Sugar prediction" = "Laatste Bloedsuikervoorspelling"; /* */ -"CurrentBG" = "CurrentBG"; +"CurrentBG" = "HuidigeBG"; /* */ "Sensor Info" = "Sensor Info"; @@ -645,13 +645,13 @@ Enact a temp Basal or a temp target */ "Sensor Endtime" = "Sensor verloopt"; /* */ -"Sensor State" = "Sensor State"; +"Sensor State" = "Sensor status"; /* */ -"Sensor Serial" = "Sensor Serial"; +"Sensor Serial" = "Sensor serienummer"; /* */ -"Transmitter Info" = "Transmitter Info"; +"Transmitter Info" = "Zender Informatie"; /* */ "Hardware" = "Hardware"; @@ -660,288 +660,291 @@ Enact a temp Basal or a temp target */ "Firmware" = "Firmware"; /* */ -"Connection State" = "Connection State"; +"Connection State" = "Verbindingsstatus"; /* */ -"Transmitter Type" = "Transmitter Type"; +"Transmitter Type" = "Type zender"; /* */ -"Sensor Type" = "Sensor Type"; +"Sensor Type" = "Type Sensor"; /* */ -"Factory Calibration Parameters" = "Factory Calibration Parameters"; +"Factory Calibration Parameters" = "Fabriekskalibratie voor Parameters"; /* */ -"Valid for footer" = "Valid for footer"; +"Valid for footer" = "Geldig voor voettekst"; /* */ -"Edit calibrations" = "Edit calibrations"; +"Edit calibrations" = "Kalibraties bewerken"; /* */ -"edit calibration clicked" = "edit calibration clicked"; +"edit calibration clicked" = "bewerken geselecteerde kalibratie"; /* */ -"Delete CGM" = "Delete CGM"; +"Delete CGM" = "Verwijder CGM"; /* */ -"Are you sure you want to remove this cgm from loop?" = "Are you sure you want to remove this cgm from loop?"; +"Are you sure you want to remove this cgm from loop?" = "Weet je zeker dat je deze CGM uit de lijst wilt verwijderen?"; /* */ -"There is no undo" = "There is no undo"; +"There is no undo" = "Ongedaan maken is niet mogelijk"; /* */ -"Advanced" = "Advanced"; +"Advanced" = "Geavanceerd"; /* */ -"Alarms" = "Alarms"; +"Alarms" = "Alarmen"; /* */ -"Glucose Settings" = "Glucose Settings"; +"Glucose Settings" = "Glucose instellingen"; /* */ -"Notifications" = "Notifications"; +"Notifications" = "Meldingen"; /* */ -"Export logs" = "Export logs"; +"Export logs" = "Logboek exporteren"; /* */ -"Export not available" = "Export not available"; +"Export not available" = "Exporteren niet beschikbaar"; /* */ -"Log export requires ios 15" = "Log export requires ios 15"; +"Log export requires ios 15" = "Log export vereist ios 15"; /* */ -"Got it!" = "Got it!"; +"Got it!" = "Begrepen!"; /* */ -"Saved to %@" = "Saved to %@"; +"Saved to %@" = "Opgeslagen in %@"; /* */ -"No logs available" = "No logs available"; +"No logs available" = "Geen logboeken beschikbaar"; /* */ -"Glucose Notification visibility" = "Glucose Notification visibility"; +"Glucose Notification visibility" = "Zichtbaarheid Glucose melding"; /* */ -"Always Notify Glucose" = "Always Notify Glucose"; +"Always Notify Glucose" = "Altijd Glucose Melden"; /* */ -"Notify per reading" = "Notify per reading"; +"Notify per reading" = "Melding bij elke meting"; /* */ -"Value" = "Value"; +"Value" = "Waarde"; /* */ -"Adds Phone Battery" = "Adds Phone Battery"; +"Adds Phone Battery" = "Telefoonbatterij Toevoegen"; /* */ -"Adds Transmitter Battery" = "Adds Transmitter Battery"; +"Adds Transmitter Battery" = "Zender Batterij Toevoegen"; /* */ -"Also vibrate" = "Also vibrate"; +"Also vibrate" = "Ook trillen"; /* */ -"Additional notification types" = "Additional notification types"; +"Additional notification types" = "Andere meldingsinstellingen"; /* */ -"Misc" = "Misc"; +"Misc" = "Overige"; /* */ -"Unit override" = "Unit override"; +"Unit override" = "Eenheid aanpassen"; /* */ -"Low" = "Low"; +"Low" = "Laag"; /* */ -"High" = "High"; +"High" = "Hoog"; /* */ "glucose" = "glucose"; /* */ -"Schedule " = "Schedule "; +"Schedule " = "Schema "; /* */ -"tapped save schedules" = "tapped save schedules"; +"tapped save schedules" = "geselecteerde schema's opslaan"; /* */ -"Error" = "Error"; +"Error" = "Fout"; /* */ -"Some ui element was incorrectly specified" = "Some ui element was incorrectly specified"; +"Some ui element was incorrectly specified" = "Sommige ui-elementen zijn onjuist opgegeven"; /* */ -"Success" = "Success"; +"Success" = "Geslaagd"; /* */ -"Schedules were saved successfully!" = "Schedules were saved successfully!"; +"Schedules were saved successfully!" = "Schema's zijn succesvol opgeslagen!"; /* */ -"High Glucose Alarm active" = "High Glucose Alarm active"; +"High Glucose Alarm active" = "Hoge Glucose Alarm actief"; /* */ -"Low Glucose Alarm active" = "Low Glucose Alarm active"; +"Low Glucose Alarm active" = "Laag Glucose Alarm actief"; /* */ -"No Glucose Alarm active" = "No Glucose Alarm active"; +"No Glucose Alarm active" = "Geen Glucose Alarm actief"; /* */ -"snoozing until %@" = "snoozing until %@"; +"snoozing until %@" = "sluimeren tot %@"; /* */ -"not snoozing" = "not snoozing"; +"not snoozing" = "niet gesluimerd"; /* */ -"nothing to see here" = "nothing to see here"; +"nothing to see here" = "er is hier niets te zien"; /* */ -"snooze from testview clicked" = "snooze from testview clicked"; +"snooze from testview clicked" = "sluimeren geklikt in de testweergave"; /* */ -"will snooze for %@ until %@" = "will snooze for %@ until %@"; +"will snooze for %@ until %@" = "zal sluimeren voor %@ tot %@"; /* */ -"Click to Snooze Alerts" = "Click to Snooze Alerts"; +"Click to Snooze Alerts" = "Klik om waarschuwingen tijdelijk uit te schakelen"; /* */ -"Strength" = "Strength"; +"Strength" = "Intensiteit"; /* */ -"Hold the top of your iPhone near the sensor to pair" = "Hold the top of your iPhone near the sensor to pair"; +"Hold the top of your iPhone near the sensor to pair" = "Houd de bovenkant van je iPhone dicht bij de sensor om te koppelen"; /* */ -"Sensor not found" = "Sensor not found"; +"Sensor not found" = "Sensor niet gevonden"; /* */ -"Also play alert sound" = "Also play alert sound"; +"Also play alert sound" = "Ook alarmgeluid afspelen"; /* */ -"Notification Settings" = "Notification Settings"; +"Notification Settings" = "Instellingen voor meldingen"; /* */ -"Found devices: %d" = "Found devices: %d"; +"Found devices: %d" = "Gevonden apparaten: %d"; /* */ -"Backfill options" = "Backfill options"; +"Backfill options" = "Terugzet opties"; /* */ -"Backfilling from trend is currently not well supported by Loop" = "Backfilling from trend is currently not well supported by Loop"; +"Backfilling from trend is currently not well supported by Loop" = "Terugzetten van trend wordt momenteel niet goed ondersteund door Loop"; /* */ -"Backfill from history" = "Backfill from history"; +"Backfill from history" = "Terugzetten van geschiedenis"; /* */ -"Backfill from trend" = "Backfill from trend"; +"Backfill from trend" = "Terugzetten van trend"; /* */ -"Debug options" = "Debug options"; +"Debug options" = "Foutopsporing opties"; /* */ -"Adds a lot of data to the Issue Report " = "Adds a lot of data to the Issue Report "; +"Adds a lot of data to the Issue Report " = "Voegt veel data toe aan het probleemrapport "; /* */ -"Persist sensordata" = "Persist sensordata"; +"Persist sensordata" = "Sensorgegevens bewaren"; /* */ -"Battery" = "Battery"; +"Battery" = "Batterij"; /* */ -"Also add source info" = "Also add source info"; +"Also add source info" = "Voeg ook bron info toe"; /* */ -"Carbs Required Threshold" = "Carbs Required Threshold"; +"Carbs Required Threshold" = "Koolhydraten vereist drempelwaarde"; /* */ -"Carbs required: %d g" = "Carbs required: %d g"; +"Carbs required: %d g" = "Koolhydraten vereist: %d g"; /* */ -"To prevent LOW required %d g of carbs" = "To prevent LOW required %d g of carbs"; +"To prevent LOW required %d g of carbs" = "Om LAAG te voorkomen zijn %d g koolhydraten nodig"; /* */ -"FreeAPS X not active" = "FreeAPS X not active"; +"FreeAPS X not active" = "FreeAPS X niet actief"; /* */ -"Last loop was more then %d min ago" = "Last loop was more then %d min ago"; +"Last loop was more then %d min ago" = "Laatste loop was meer dan %d min geleden"; /* Glucose badge */ -"Show glucose on the app badge" = "Show glucose on the app badge"; +"Show glucose on the app badge" = "Toon glucose op de app icoon"; /* */ -"Backfill glucose" = "Backfill glucose"; +"Backfill glucose" = "Terugzetten glucose"; /* About this source */ -"About this source" = "About this source"; +"About this source" = "Over deze bron"; /* */ -"Bolus failed" = "Bolus failed"; +"Bolus failed" = "Bolus mislukt"; /* */ -"Bolus failed or inaccurate. Check pump history before repeating." = "Bolus failed or inaccurate. Check pump history before repeating."; +"Bolus failed or inaccurate. Check pump history before repeating." = "Bolus mislukt of onjuist. Controleer de pompgeschiedenis voordat je herhaalt."; /* */ -"Carbs" = "Carbs"; +"Carbs" = "Koolhydraten"; /* */ -"Temp Basal" = "Temp Basal"; +"Temp Basal" = "Tijdelijk basaal"; /* */ -"Temp Target" = "Temp Target"; +"Temp Target" = "Tijdelijk streefdoel"; /* */ -"Resume" = "Resume"; +"Resume" = "Hervat"; /* */ -"Suspend" = "Suspend"; +"Suspend" = "Onderbreek"; + +/* */ +"Animated Background" = "Bewegende achtergrond"; /* Headers for settings ----------------------- */ -"OpenAPS main settings" = "OpenAPS main settings"; +"OpenAPS main settings" = "OpenAPS hoofdinstellingen"; -"OpenAPS SMB settings" = "OpenAPS SMB settings"; +"OpenAPS SMB settings" = "OpenAPS SMB instellingen"; -"OpenAPS targets settings" = "OpenAPS targets settings"; +"OpenAPS targets settings" = "OpenAPS doel instellingen"; -"OpenAPS other settings" = "OpenAPS other settings"; +"OpenAPS other settings" = "OpenAPS overige instellingen"; /* Glucose Simulator CGM */ "Glucose Simulator" = "Glucose Simulator"; /* Restored state message */ -"Bluetooth State restored (APS restarted?). Found %d peripherals, and connected to %@ with identifier %@" = "Bluetooth State restored (APS restarted?). Found %d peripherals, and connected to %@ with identifier %@"; +"Bluetooth State restored (APS restarted?). Found %d peripherals, and connected to %@ with identifier %@" = "Herstelde Bluetooth-status (APS opnieuw opgestart?). %d randapparatuur gevonden en verbonden met %@ met de identificatie %@"; /* Shared app group */ -"Shared app group" = "Shared app group"; +"Shared app group" = "Gedeelde app groep"; /* Native G6 app */ -"Native G6 app" = "Native G6 app"; +"Native G6 app" = "Oorspronkelijke G6 app"; /* Native G5 app */ -"Native G5 app" = "Native G5 app"; +"Native G5 app" = "Oorspronkelijke G5 app"; /* Minilink transmitter */ -"Minilink transmitter" = "Minilink transmitter"; +"Minilink transmitter" = "Minilink zender"; /* Simple simulator */ -"Simple simulator" = "Simple simulator"; +"Simple simulator" = "Eenvoudige simulator"; /* Direct connection with Libre 1 transmitters or Libre 2 */ -"Direct connection with Libre 1 transmitters or Libre 2" = "Direct connection with Libre 1 transmitters or Libre 2"; +"Direct connection with Libre 1 transmitters or Libre 2" = "Directe verbinding met Libre 1 of Libre 2 zender"; /* Online or internal server */ -"Online or internal server" = "Online or internal server"; +"Online or internal server" = "Online of interne server"; /* HealthKit intergration --------------------*/ /* */ -"Apple Health" = "Apple Health"; +"Apple Health" = "Apple Gezondheid"; /* */ -"Connect to Apple Health" = "Connect to Apple Health"; +"Connect to Apple Health" = "Verbinden met Apple Gezondheid"; /* Show when have not permissions for writing to Health */ -"For write data to Apple Health you must give permissions in Settings > Health > Data Access" = "For write data to Apple Health you must give permissions in Settings > Health > Data Access"; +"For write data to Apple Health you must give permissions in Settings > Health > Data Access" = "Als u gegevens wilt opslaan met Apple Gezondheid, moet u de juiste machtigingen verlenen in Instellingen > Gezondheid > Gegevenstoegang en apparaten"; /* */ -"After you create glucose records in the Health app, please open FreeAPS X to help us guaranteed transfer changed data" = "After you create glucose records in the Health app, please open FreeAPS X to help us guaranteed transfer changed data"; +"After you create glucose records in the Health app, please open FreeAPS X to help us guaranteed transfer changed data" = "Na het maken van glucoserecords in de Gezondheid-app, opent u FreeAPS X om ervoor te zorgen dat de gewijzigde gegevens veilig worden overgedragen"; /* -------------------------------------------- @@ -950,13 +953,13 @@ Enact a temp Basal or a temp target */ */ /* ”Rewind Resets Autosens” */ -"This feature, enabled by default, resets the autosens ratio to neutral when you rewind your pump, on the assumption that this corresponds to a probable site change. Autosens will begin learning sensitivity anew from the time of the rewind, which may take up to 6 hours. If you usually rewind your pump independently of site changes, you may want to consider disabling this feature." = "This feature, enabled by default, resets the autosens ratio to neutral when you rewind your pump, on the assumption that this corresponds to a probable site change. Autosens will begin learning sensitivity anew from the time of the rewind, which may take up to 6 hours. If you usually rewind your pump independently of site changes, you may want to consider disabling this feature."; +"This feature, enabled by default, resets the autosens ratio to neutral when you rewind your pump, on the assumption that this corresponds to a probable site change. Autosens will begin learning sensitivity anew from the time of the rewind, which may take up to 6 hours. If you usually rewind your pump independently of site changes, you may want to consider disabling this feature." = "Deze functie, die standaard is ingeschakeld, zet Autosense de ratio terug op neutraal wanneer je pomp terugdraait, ervan uitgaande dat dit een katheter- en reservoirwissel betekent. Autosens start opnieuw op vanaf het moment van terugkeer en het kan tot 6 uur duren om de gevoeligheid opnieuw te beoordelen. Als u uw pomp normaal gesproken onafhankelijk van de resevoir- en katheterwissel terugdraait, kunt u overwegen om deze functie uit te schakelen."; /* ”High Temptarget Raises Sensitivity" */ -"Defaults to false. When set to true, raises sensitivity (lower sensitivity ratio) for temp targets set to >= 111. Synonym for exercise_mode. The higher your temp target above 110 will result in more sensitive (lower) ratios, e.g., temp target of 120 results in sensitivity ratio of 0.75, while 140 results in 0.6 (with default halfBasalTarget of 160)." = "Defaults to false. When set to true, raises sensitivity (lower sensitivity ratio) for temp targets set to >= 111. Synonym for exercise_mode. The higher your temp target above 110 will result in more sensitive (lower) ratios, e.g., temp target of 120 results in sensitivity ratio of 0.75, while 140 results in 0.6 (with default halfBasalTarget of 160)."; +"Defaults to false. When set to true, raises sensitivity (lower sensitivity ratio) for temp targets set to >= 111. Synonym for exercise_mode. The higher your temp target above 110 will result in more sensitive (lower) ratios, e.g., temp target of 120 results in sensitivity ratio of 0.75, while 140 results in 0.6 (with default halfBasalTarget of 160)." = "Is standaard uitgeschakeld. Wanneer ingeschakeld, verhoogt dit de gevoeligheid (lagere gevoeligheidsratio) voor tijdelijk doel tot >= 111 exercise_mode. Hoe hoger je doel boven de 110 ligt, hoe gevoeliger (lagere) ratio's, bijvoorbeeld tijdelijk streefdoel van 120 resulteert in de sensitiviteitsratio van 0,75, terwijl 140 resulteert in 0,6 (met standaard half-basaal doel van 160)."; /* ”Low Temptarget Lowers Sensitivity" */ -"Defaults to false. When set to true, can lower sensitivity (higher sensitivity ratio) for temptargets <= 99. The lower your temp target below 100 will result in less sensitive (higher) ratios, e.g., temp target of 95 results in sensitivity ratio of 1.09, while 85 results in 1.33 (with default halfBasalTarget of 160)." = "Defaults to false. When set to true, can lower sensitivity (higher sensitivity ratio) for temptargets <= 99. The lower your temp target below 100 will result in less sensitive (higher) ratios, e.g., temp target of 95 results in sensitivity ratio of 1.09, while 85 results in 1.33 (with default halfBasalTarget of 160)."; +"Defaults to false. When set to true, can lower sensitivity (higher sensitivity ratio) for temptargets <= 99. The lower your temp target below 100 will result in less sensitive (higher) ratios, e.g., temp target of 95 results in sensitivity ratio of 1.09, while 85 results in 1.33 (with default halfBasalTarget of 160)." = "Is standaard uitgeschakeld. Indien ingeschakeld, kan de gevoeligheid (hogere gevoeligheidsratio) voor tijdelijke doelen worden verlaagd < = 99. Hoe lager je tijdelijke doel onder de 100 ligt, hoe hoger de gevoeligheid zal zijn. Zo levert een tijdelijk koersdoel van 95 een gevoeligheidsratio van 1,09 op, terwijl 85 een waarde van 1,33 geeft."; /* ”Sensitivity Raises Target" */ "When true, raises BG target when autosens detects sensitivity" = "Wanneer waar, verhoogt het BG streefdoel als autosens gevoeligheid detecteert"; @@ -965,13 +968,13 @@ Enact a temp Basal or a temp target */ "Defaults to false. When true, will lower BG target when autosens detects resistance" = "Standaard op onwaar. Wanneer waar, zal het BG doel verlagen als autosens minder gevoeligheid detecteert"; /* ”Advanced Target Adjustments" */ -"This feature was previously enabled by default but will now default to false (will NOT be enabled automatically) in oref0 0.6.0 and beyond. (There is no need for this with 0.6.0). This feature lowers oref0’s target BG automatically when current BG and eventualBG are high. This helps prevent and mitigate high BG, but automatically switches to low-temping to ensure that BG comes down smoothly toward your actual target. If you find this behavior too aggressive, you can disable this feature. If you do so, please let us know so we can better understand what settings work best for everyone." = "This feature was previously enabled by default but will now default to false (will NOT be enabled automatically) in oref0 0.6.0 and beyond. (There is no need for this with 0.6.0). This feature lowers oref0’s target BG automatically when current BG and eventualBG are high. This helps prevent and mitigate high BG, but automatically switches to low-temping to ensure that BG comes down smoothly toward your actual target. If you find this behavior too aggressive, you can disable this feature. If you do so, please let us know so we can better understand what settings work best for everyone."; +"This feature was previously enabled by default but will now default to false (will NOT be enabled automatically) in oref0 0.6.0 and beyond. (There is no need for this with 0.6.0). This feature lowers oref0’s target BG automatically when current BG and eventualBG are high. This helps prevent and mitigate high BG, but automatically switches to low-temping to ensure that BG comes down smoothly toward your actual target. If you find this behavior too aggressive, you can disable this feature. If you do so, please let us know so we can better understand what settings work best for everyone." = "Deze functie was in het verleden altijd geactiveerd, maar is nu standaard ingesteld op \"Uit\". Dit is niet langer nodig met oref 0.6.0. Deze functie verlaagt automatisch de bloedglucosedoelstelling van oref0 als de huidige BG of de verwachte BG hoog zijn. Dit helpt hoge BG te voorkomen en te beperken, maar schakelt automatisch over op lage gevoeligheid om ervoor te zorgen dat de BG zich soepel naar uw eigenlijke doel beweegt. Als u dit gedrag te agressief vindt, kunt u deze functie uitschakelen. Als u dat doet, laat het ons dan weten, zodat we beter kunnen begrijpen welke instellingen voor iedereen het beste werken."; /* "Exercise Mode" */ -"Defaults to false. When true, > 105 mg/dL high temp target adjusts sensitivityRatio for exercise_mode. Synonym for high_temptarget_raises_sensitivity" = "Defaults to false. When true, > 105 mg/dL high temp target adjusts sensitivityRatio for exercise_mode. Synonym for high_temptarget_raises_sensitivity"; +"Defaults to false. When true, > 105 mg/dL high temp target adjusts sensitivityRatio for exercise_mode. Synonym for high_temptarget_raises_sensitivity" = "Standaard uit. Indien aan, > 105 mg/dL hoge tijdelijke doelstelling past gevoeligheid voor Oefening_Modus aan. Synoniem voor hoge tijdelijk doel verhoging gevoeligheid"; /* "Wide BG Target Range" */ -"Defaults to false, which means by default only the low end of the pump’s BG target range is used as OpenAPS target. This is a safety feature to prevent too-wide targets and less-optimal outcomes. Therefore the higher end of the target range is used only for avoiding bolus wizard overcorrections. Use wide_bg_target_range: true to force neutral temps over a wider range of eventualBGs." = "Defaults to false, which means by default only the low end of the pump’s BG target range is used as OpenAPS target. This is a safety feature to prevent too-wide targets and less-optimal outcomes. Therefore the higher end of the target range is used only for avoiding bolus wizard overcorrections. Use wide_bg_target_range: true to force neutral temps over a wider range of eventualBGs."; +"Defaults to false, which means by default only the low end of the pump’s BG target range is used as OpenAPS target. This is a safety feature to prevent too-wide targets and less-optimal outcomes. Therefore the higher end of the target range is used only for avoiding bolus wizard overcorrections. Use wide_bg_target_range: true to force neutral temps over a wider range of eventualBGs." = "Standaard uit betekent dat standaard alleen de laagste BG van de pomp wordt gebruikt als OpenAPS doel. Dit is een veiligheidsvoorziening om al te brede doelen en minder optimale resultaten te voorkomen. Daarom wordt het hoogste eind van het streefbereik alleen gebruikt om teveel compenseren van de bolus assistent te voorkomen. Gebruik wide_bg_target_range: true om neutrale temps af te dwingen over een breder bereik van de uiteindelijke BG."; /* "Skip Neutral Temps" */ "Defaults to false, so that FreeAPS X will set temps whenever it can, so it will be easier to see if the system is working, even when you are offline. This means FreeAPS X will set a “neutral” temp (same as your default basal) if no adjustments are needed. This is an old setting for OpenAPS to have the options to minimise sounds and notifications from the 'rig', that may wake you up during the night." = "Defaults to false, so that FreeAPS X will set temps whenever it can, so it will be easier to see if the system is working, even when you are offline. This means OpenAPS will set a “neutral” temp (same as your default basal) if no adjustments are needed. This is an old setting for OpenAPS to have the options to minimise sounds and notifications form the 'rig', that may wake you up during the night. "; @@ -999,7 +1002,7 @@ Enact a temp Basal or a temp target */ "Defaults to false. When true, allows supermicrobolus (if otherwise enabled) even with high temp targets." = "Defaults to false. When true, allows supermicrobolus (if otherwise enabled) even with high temp targets."; /* "Use Custom Peak Time” */ -"Defaults to false. Setting to true allows changing insulinPeakTime" = "Defaults to false. Setting to true allows changing insulinPeakTime"; +"Defaults to false. Setting to true allows changing insulinPeakTime" = "Is standaard ingesteld op uit. Indien ingeschakeld, kunt u de insuline piektijd veranderen"; /* "Suspend Zeros IOB” */ "Default is false. Any existing temp basals during times the pump was suspended will be deleted and 0 temp basals to negate the profile basal rates during times pump is suspended will be added." = "Default is false. Any existing temp basals during times the pump was suspended will be deleted and 0 temp basals to negate the profile basal rates during times pump is suspended will be added."; diff --git a/FreeAPS/Sources/Localizations/Main/pl.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/pl.lproj/Localizable.strings index 0f0742c6b..8a34b4b07 100644 --- a/FreeAPS/Sources/Localizations/Main/pl.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/pl.lproj/Localizable.strings @@ -895,6 +895,9 @@ Połączono z Nightscout!"; /* */ "Suspend" = "Suspend"; +/* */ +"Animated Background" = "Animated Background"; + /* Headers for settings ----------------------- */ "OpenAPS main settings" = "OpenAPS main settings"; diff --git a/FreeAPS/Sources/Localizations/Main/pt-BR.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/pt-BR.lproj/Localizable.strings index d8e8675eb..ac9d66929 100644 --- a/FreeAPS/Sources/Localizations/Main/pt-BR.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/pt-BR.lproj/Localizable.strings @@ -893,6 +893,9 @@ Enact a temp Basal or a temp target */ /* */ "Suspend" = "Suspend"; +/* */ +"Animated Background" = "Animated Background"; + /* Headers for settings ----------------------- */ "OpenAPS main settings" = "OpenAPS main settings"; diff --git a/FreeAPS/Sources/Localizations/Main/ru.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/ru.lproj/Localizable.strings index 12c5577e8..cf0f4c572 100644 --- a/FreeAPS/Sources/Localizations/Main/ru.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/ru.lproj/Localizable.strings @@ -896,6 +896,7 @@ Enact a temp Basal or a temp target */ /* */ "Animated Background" = "Анимированный фон"; + /* Headers for settings ----------------------- */ "OpenAPS main settings" = "Основные настройки OpenAPS"; diff --git a/FreeAPS/Sources/Localizations/Main/sk.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/sk.lproj/Localizable.strings index 7052fd546..2e3295c88 100644 --- a/FreeAPS/Sources/Localizations/Main/sk.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/sk.lproj/Localizable.strings @@ -893,6 +893,9 @@ Enact a temp Basal or a temp target */ /* */ "Suspend" = "Suspend"; +/* */ +"Animated Background" = "Animated Background"; + /* Headers for settings ----------------------- */ "OpenAPS main settings" = "OpenAPS main settings"; diff --git a/FreeAPS/Sources/Localizations/Main/sv.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/sv.lproj/Localizable.strings index 071f3629e..674c79deb 100644 --- a/FreeAPS/Sources/Localizations/Main/sv.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/sv.lproj/Localizable.strings @@ -893,6 +893,9 @@ Enact a temp Basal or a temp target */ /* */ "Suspend" = "Pausa"; +/* */ +"Animated Background" = "Animerad Bakgrund"; + /* Headers for settings ----------------------- */ "OpenAPS main settings" = "OpenAPS huvudsakliga inställningar"; diff --git a/FreeAPS/Sources/Localizations/Main/tr.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/tr.lproj/Localizable.strings index 8d4772d2b..7ac172e8c 100644 --- a/FreeAPS/Sources/Localizations/Main/tr.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/tr.lproj/Localizable.strings @@ -522,7 +522,7 @@ Enact a temp Basal or a temp target */ "Pair Sensor & connect" = "Sensör eşleştir ve bağlan"; /* */ -"Phone NFC required!" = "Telefon NFC gerekli!"; +"Phone NFC required!" = "NFC özellikli telefon gerekli!"; /* */ "Your phone or app is not enabled for NFC communications, which is needed to pair to libre2 sensors" = "Telefonunuz veya uygulamanız, libre2 sensörleriyle eşleştirmek için gerekli olan NFC iletişimleri için etkin değil"; @@ -540,7 +540,7 @@ Enact a temp Basal or a temp target */ "Delete CGMManager and start anew. Your libreoopweb credentials will be preserved" = "CGMManager'ı silin ve yeniden başlayın. libreoopweb kimlik bilgileriniz korunacaktır"; /* Invalid libre checksum */ -"Invalid libre checksum" = "Geçersiz libre sağlama toplamı"; +"Invalid libre checksum" = "Libre sağlaması geçersiz"; /* Libre sensor was incorrectly read, CRCs were not valid */ "Libre sensor was incorrectly read, CRCs were not valid" = "Libre sensörü hatalı okundu, CRC'ler geçersizdi"; @@ -570,10 +570,10 @@ Enact a temp Basal or a temp target */ "This might be an intermittent problem, but please check that your transmitter is tightly secured over your sensor" = "Bu aralıklı bir sorun olabilir ancak lütfen vericinizin sensörünüze sıkıca sabitlendiğini kontrol edin"; /* New Sensor Detected */ -"New Sensor Detected" = "Yemi Sensör Tespit Edildi"; +"New Sensor Detected" = "Yeni Sensör Algılandı"; /* Please wait up to 30 minutes before glucose readings are available! */ -"Please wait up to 30 minutes before glucose readings are available!" = "Lütfen glikoz ölçümleri mevcut olana kadar 30 dakikaya kadar bekleyin!"; +"Please wait up to 30 minutes before glucose readings are available!" = "Lütfen glikoz ölçümleri mevcut olana kadar 30 dakika bekleyin!"; /* Invalid Glucose sample detected, try again later */ "Invalid Glucose sample detected, try again later" = "Geçersiz Glikoz örneği tespit edildi, daha sonra tekrar deneyin"; @@ -624,7 +624,7 @@ Enact a temp Basal or a temp target */ "Last measurement" = "Son ölçüm"; /* */ -"Sensor Footer checksum" = "Sensör Altbilgi sağlama toplamı"; +"Sensor Footer checksum" = "Sensör Altbilgi sağlaması"; /* */ "Last Blood Sugar prediction" = "Son KŞ'i tahmini"; @@ -642,7 +642,7 @@ Enact a temp Basal or a temp target */ "Sensor Age Left" = "Kalan Sensör Yaşı"; /* */ -"Sensor Endtime" = "Sensör Bitim zamanı"; +"Sensor Endtime" = "Sensör Bitiş zamanı"; /* */ "Sensor State" = "Sensör Durumu"; @@ -780,10 +780,10 @@ Enact a temp Basal or a temp target */ "High Glucose Alarm active" = "Yüksek Glikoz Uyarılarımı aktif"; /* */ -"Low Glucose Alarm active" = "Düşük Glikoz Uyarılarımı aktif"; +"Low Glucose Alarm active" = "Düşük Glikoz Alarmı aktif"; /* */ -"No Glucose Alarm active" = "Glikoz Uyarılarımı aktif değil"; +"No Glucose Alarm active" = "Glikoz Alarmı aktif değil"; /* */ "snoozing until %@" = "%@'e kadar erteleniyor"; @@ -879,19 +879,22 @@ Enact a temp Basal or a temp target */ "Bolus failed or inaccurate. Check pump history before repeating." = "Bolus başarısız veya hatalı. Tekrarlamadan önce pompa geçmişini kontrol edin."; /* */ -"Carbs" = "Carbs"; +"Carbs" = "Karbonhidrat"; /* */ -"Temp Basal" = "Temp Basal"; +"Temp Basal" = "Geçici Bazal Oranı"; /* */ -"Temp Target" = "Temp Target"; +"Temp Target" = "Geçici Hedef"; /* */ -"Resume" = "Resume"; +"Resume" = "Devam et"; /* */ -"Suspend" = "Suspend"; +"Suspend" = "Askıya al"; + +/* */ +"Animated Background" = "Animasyonlu Arka Plan"; /* Headers for settings ----------------------- */ diff --git a/FreeAPS/Sources/Localizations/Main/uk.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/uk.lproj/Localizable.strings index fc1cc1d2f..9abcbc81b 100644 --- a/FreeAPS/Sources/Localizations/Main/uk.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/uk.lproj/Localizable.strings @@ -893,6 +893,9 @@ Enact a temp Basal or a temp target */ /* */ "Suspend" = "Suspend"; +/* */ +"Animated Background" = "Animated Background"; + /* Headers for settings ----------------------- */ "OpenAPS main settings" = "OpenAPS main settings"; diff --git a/FreeAPS/Sources/Localizations/Main/zh-Hans.lproj/Localizable.strings b/FreeAPS/Sources/Localizations/Main/zh-Hans.lproj/Localizable.strings index e766e8bc6..869d80501 100644 --- a/FreeAPS/Sources/Localizations/Main/zh-Hans.lproj/Localizable.strings +++ b/FreeAPS/Sources/Localizations/Main/zh-Hans.lproj/Localizable.strings @@ -893,6 +893,9 @@ Enact a temp Basal or a temp target */ /* */ "Suspend" = "Suspend"; +/* */ +"Animated Background" = "Animated Background"; + /* Headers for settings ----------------------- */ "OpenAPS main settings" = "OpenAPS 主要设置"; diff --git a/FreeAPS/Sources/Models/BasalProfileEntry.swift b/FreeAPS/Sources/Models/BasalProfileEntry.swift index d81bb8e8e..2ce1918f2 100644 --- a/FreeAPS/Sources/Models/BasalProfileEntry.swift +++ b/FreeAPS/Sources/Models/BasalProfileEntry.swift @@ -9,3 +9,20 @@ struct BasalProfileEntry: JSON, Equatable { protocol BasalProfileObserver { func basalProfileDidChange(_ basalProfile: [BasalProfileEntry]) } + +extension BasalProfileEntry { + private enum CodingKeys: String, CodingKey { + case start + case minutes + case rate + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + let start = try container.decode(String.self, forKey: .start) + let minutes = try container.decode(Int.self, forKey: .minutes) + let rate = try container.decode(Double.self, forKey: .rate).decimal ?? .zero + + self = BasalProfileEntry(start: start, minutes: minutes, rate: rate) + } +} diff --git a/FreeAPS/Sources/Models/CarbRatios.swift b/FreeAPS/Sources/Models/CarbRatios.swift index 3dd48a6fe..16fd0f673 100644 --- a/FreeAPS/Sources/Models/CarbRatios.swift +++ b/FreeAPS/Sources/Models/CarbRatios.swift @@ -15,3 +15,20 @@ enum CarbUnit: String, JSON { case grams case exchanges } + +extension CarbRatioEntry { + private enum CodingKeys: String, CodingKey { + case start + case offset + case ratio + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + let start = try container.decode(String.self, forKey: .start) + let offset = try container.decode(Int.self, forKey: .offset) + let ratio = try container.decode(Double.self, forKey: .ratio).decimal ?? .zero + + self = CarbRatioEntry(start: start, offset: offset, ratio: ratio) + } +} diff --git a/FreeAPS/Sources/Models/InsulinSensitivities.swift b/FreeAPS/Sources/Models/InsulinSensitivities.swift index 2c780b65d..94f053e31 100644 --- a/FreeAPS/Sources/Models/InsulinSensitivities.swift +++ b/FreeAPS/Sources/Models/InsulinSensitivities.swift @@ -19,3 +19,20 @@ struct InsulinSensitivityEntry: JSON { let offset: Int let start: String } + +extension InsulinSensitivityEntry { + private enum CodingKeys: String, CodingKey { + case sensitivity + case offset + case start + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + let sensitivity = try container.decode(Double.self, forKey: .sensitivity).decimal ?? .zero + let start = try container.decode(String.self, forKey: .start) + let offset = try container.decode(Int.self, forKey: .offset) + + self = InsulinSensitivityEntry(sensitivity: sensitivity, offset: offset, start: start) + } +} diff --git a/FreeAPS/Sources/Modules/BasalProfileEditor/BasalProfileEditorStateModel.swift b/FreeAPS/Sources/Modules/BasalProfileEditor/BasalProfileEditorStateModel.swift index 04797a815..4a13fb3f2 100644 --- a/FreeAPS/Sources/Modules/BasalProfileEditor/BasalProfileEditorStateModel.swift +++ b/FreeAPS/Sources/Modules/BasalProfileEditor/BasalProfileEditorStateModel.swift @@ -15,7 +15,8 @@ extension BasalProfileEditor { } override func subscribe() { - rateValues = provider.supportedBasalRates ?? stride(from: Decimal(0.05), to: 10.01, by: 0.05).map { $0 } + rateValues = provider.supportedBasalRates ?? stride(from: 5.0, to: 1001.0, by: 5.0) + .map { ($0.decimal ?? .zero) / 100 } items = provider.profile.map { value in let timeIndex = timeValues.firstIndex(of: Double(value.minutes * 60)) ?? 0 let rateIndex = rateValues.firstIndex(of: value.rate) ?? 0 diff --git a/FreeAPS/Sources/Modules/CREditor/CREditorStateModel.swift b/FreeAPS/Sources/Modules/CREditor/CREditorStateModel.swift index dd42eb8aa..97c6daaa2 100644 --- a/FreeAPS/Sources/Modules/CREditor/CREditorStateModel.swift +++ b/FreeAPS/Sources/Modules/CREditor/CREditorStateModel.swift @@ -7,7 +7,7 @@ extension CREditor { let timeValues = stride(from: 0.0, to: 1.days.timeInterval, by: 30.minutes.timeInterval).map { $0 } - let rateValues = stride(from: 3, to: 50.01, by: 0.1).map { Decimal($0) } + let rateValues = stride(from: 30.0, to: 501.0, by: 1.0).map { ($0.decimal ?? .zero) / 10 } var canAdd: Bool { guard let lastItem = items.last else { return true } diff --git a/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift b/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift index 780da7570..b6e6e2216 100644 --- a/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift +++ b/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift @@ -37,82 +37,100 @@ extension Home { return scene } - var header: some View { + @ViewBuilder func header(_ geo: GeometryProxy) -> some View { HStack(alignment: .bottom) { Spacer() - VStack(alignment: .leading, spacing: 12) { - HStack { - Text("IOB").font(.caption2).foregroundColor(.secondary) - Text( - (numberFormatter.string(from: (state.suggestion?.iob ?? 0) as NSNumber) ?? "0") + - NSLocalizedString(" U", comment: "Insulin unit") - ) - .font(.system(size: 12, weight: .bold)) - } - HStack { - Text("COB").font(.caption2).foregroundColor(.secondary) - Text( - (numberFormatter.string(from: (state.suggestion?.cob ?? 0) as NSNumber) ?? "0") + - NSLocalizedString(" g", comment: "gram of carbs") - ) - .font(.system(size: 12, weight: .bold)) - } - } + cobIobView + Spacer() + glucoseView + Spacer() + pumpView Spacer() + loopView + Spacer() + } + .frame(maxWidth: .infinity) + .frame(maxHeight: 70) + .padding(.top, geo.safeAreaInsets.top) + .background(Color.gray.opacity(0.2)) + } - CurrentGlucoseView( - recentGlucose: $state.recentGlucose, - delta: $state.glucoseDelta, - units: $state.units, - alarm: $state.alarm - ) - .onTapGesture { - if state.alarm == nil { - state.openCGM() - } else { - state.showModal(for: .snooze) - } + var cobIobView: some View { + VStack(alignment: .leading, spacing: 12) { + HStack { + Text("IOB").font(.caption2).foregroundColor(.secondary) + Text( + (numberFormatter.string(from: (state.suggestion?.iob ?? 0) as NSNumber) ?? "0") + + NSLocalizedString(" U", comment: "Insulin unit") + ) + .font(.system(size: 12, weight: .bold)) } - .onLongPressGesture { - let impactHeavy = UIImpactFeedbackGenerator(style: .heavy) - impactHeavy.impactOccurred() - if state.alarm == nil { - state.showModal(for: .snooze) - } else { - state.openCGM() - } + HStack { + Text("COB").font(.caption2).foregroundColor(.secondary) + Text( + (numberFormatter.string(from: (state.suggestion?.cob ?? 0) as NSNumber) ?? "0") + + NSLocalizedString(" g", comment: "gram of carbs") + ) + .font(.system(size: 12, weight: .bold)) } + } + } - Spacer() - PumpView( - reservoir: $state.reservoir, - battery: $state.battery, - name: $state.pumpName, - expiresAtDate: $state.pumpExpiresAtDate, - timerDate: $state.timerDate - ) - .onTapGesture { - if state.pumpDisplayState != nil { - state.setupPump = true - } + var glucoseView: some View { + CurrentGlucoseView( + recentGlucose: $state.recentGlucose, + delta: $state.glucoseDelta, + units: $state.units, + alarm: $state.alarm + ) + .onTapGesture { + if state.alarm == nil { + state.openCGM() + } else { + state.showModal(for: .snooze) } - Spacer() - LoopView( - suggestion: $state.suggestion, - enactedSuggestion: $state.enactedSuggestion, - closedLoop: $state.closedLoop, - timerDate: $state.timerDate, - isLooping: $state.isLooping, - lastLoopDate: $state.lastLoopDate - ).onTapGesture { - isStatusPopupPresented = true - }.onLongPressGesture { - let impactHeavy = UIImpactFeedbackGenerator(style: .heavy) - impactHeavy.impactOccurred() - state.runLoop() + } + .onLongPressGesture { + let impactHeavy = UIImpactFeedbackGenerator(style: .heavy) + impactHeavy.impactOccurred() + if state.alarm == nil { + state.showModal(for: .snooze) + } else { + state.openCGM() } - Spacer() - }.frame(maxWidth: .infinity) + } + } + + var pumpView: some View { + PumpView( + reservoir: $state.reservoir, + battery: $state.battery, + name: $state.pumpName, + expiresAtDate: $state.pumpExpiresAtDate, + timerDate: $state.timerDate + ) + .onTapGesture { + if state.pumpDisplayState != nil { + state.setupPump = true + } + } + } + + var loopView: some View { + LoopView( + suggestion: $state.suggestion, + enactedSuggestion: $state.enactedSuggestion, + closedLoop: $state.closedLoop, + timerDate: $state.timerDate, + isLooping: $state.isLooping, + lastLoopDate: $state.lastLoopDate + ).onTapGesture { + isStatusPopupPresented = true + }.onLongPressGesture { + let impactHeavy = UIImpactFeedbackGenerator(style: .heavy) + impactHeavy.impactOccurred() + state.runLoop() + } } var infoPanal: some View { @@ -330,11 +348,7 @@ extension Home { var body: some View { GeometryReader { geo in VStack(spacing: 0) { - header - .frame(maxHeight: 70) - .padding(.top, geo.safeAreaInsets.top) - .background(Color.gray.opacity(0.2)) - + header(geo) infoPanal mainChart legendPanal diff --git a/FreeAPS/Sources/Modules/ISFEditor/ISFEditorStateModel.swift b/FreeAPS/Sources/Modules/ISFEditor/ISFEditorStateModel.swift index 70c147eb5..e54dc121f 100644 --- a/FreeAPS/Sources/Modules/ISFEditor/ISFEditorStateModel.swift +++ b/FreeAPS/Sources/Modules/ISFEditor/ISFEditorStateModel.swift @@ -14,7 +14,7 @@ extension ISFEditor { case .mgdL: return stride(from: 9, to: 540.01, by: 1.0).map { Decimal($0) } case .mmolL: - return stride(from: 0.1, to: 30.01, by: 0.1).map { Decimal($0) } + return stride(from: 1.0, to: 301.0, by: 1.0).map { ($0.decimal ?? .zero) / 10 } } } diff --git a/FreeAPS/Sources/Views/DecimalTextField.swift b/FreeAPS/Sources/Views/DecimalTextField.swift index 41e65fbe8..850ad5bc9 100644 --- a/FreeAPS/Sources/Views/DecimalTextField.swift +++ b/FreeAPS/Sources/Views/DecimalTextField.swift @@ -1,3 +1,4 @@ +import Combine import SwiftUI struct DecimalTextField: UIViewRepresentable { @@ -62,8 +63,11 @@ struct DecimalTextField: UIViewRepresentable { return textfield } - func updateUIView(_ textField: UITextField, context _: Context) { - if value != 0 { + func updateUIView(_ textField: UITextField, context: Context) { + let coordinator = context.coordinator + if coordinator.isEditing { + coordinator.resetEditing() + } else if value != 0 { textField.text = formatter.string(for: value) } } @@ -79,6 +83,15 @@ struct DecimalTextField: UIViewRepresentable { parent = textField } + private(set) var isEditing = false + private var editingCancellable: AnyCancellable? + + func resetEditing() { + editingCancellable = Just(false) + .delay(for: 0.5, scheduler: DispatchQueue.main) + .weakAssign(to: \.isEditing, on: self) + } + func textField( _ textField: UITextField, shouldChangeCharactersIn range: NSRange, @@ -106,6 +119,7 @@ struct DecimalTextField: UIViewRepresentable { // Set Value let double = number.doubleValue + isEditing = true parent.value = Decimal(double) } @@ -118,6 +132,7 @@ struct DecimalTextField: UIViewRepresentable { ) { // Format value with formatter at End Editing textField.text = parent.formatter.string(for: parent.value) + isEditing = false } } }