From 4f7d7751d090c081abae29a1b40ca9096031fcee Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Sun, 12 Nov 2023 17:50:34 +0100 Subject: [PATCH 01/84] fix: Compile station target on Xcode 15 --- station.xcodeproj/project.pbxproj | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/station.xcodeproj/project.pbxproj b/station.xcodeproj/project.pbxproj index 7eac17788..f04ee2940 100644 --- a/station.xcodeproj/project.pbxproj +++ b/station.xcodeproj/project.pbxproj @@ -1163,6 +1163,13 @@ remoteGlobalIDString = E17C469829956732008CFDD7; remoteInfo = pnservice; }; + E196D5B02B0137A100B60A90 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 64333D1D20B0C45900CDF4B6 /* Project object */; + proxyType = 1; + remoteGlobalIDString = E17C469829956732008CFDD7; + remoteInfo = pnservice; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -4758,16 +4765,17 @@ 64333D2120B0C45900CDF4B6 /* Sources */, 64333D2220B0C45900CDF4B6 /* Frameworks */, 64333D2320B0C45900CDF4B6 /* Resources */, - A9AB57592413CCAB006FD3D2 /* Fetch secrets */, 60666212F80D3A3EAC265637 /* [CP] Embed Pods Frameworks */, - A986147C248CD47A0030F197 /* Crashlytics */, 34D458E82821A06E00EA9F93 /* Embed Foundation Extensions */, + A986147C248CD47A0030F197 /* Crashlytics */, + A9AB57592413CCAB006FD3D2 /* Fetch secrets */, ); buildRules = ( ); dependencies = ( - 34D458E72821A06E00EA9F93 /* PBXTargetDependency */, 34D458EB2821A07600EA9F93 /* PBXTargetDependency */, + 34D458E72821A06E00EA9F93 /* PBXTargetDependency */, + E196D5B12B0137A100B60A90 /* PBXTargetDependency */, ); name = station; packageProductDependencies = ( @@ -6405,6 +6413,11 @@ target = E17C469829956732008CFDD7 /* pnservice */; targetProxy = E17C469E29956732008CFDD7 /* PBXContainerItemProxy */; }; + E196D5B12B0137A100B60A90 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = E17C469829956732008CFDD7 /* pnservice */; + targetProxy = E196D5B02B0137A100B60A90 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ From caa7cd8cdac09bff9a3838ecdc32659fb02fd0fb Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Sun, 12 Nov 2023 20:49:13 +0100 Subject: [PATCH 02/84] task: Adopt new widgets API of Xcode 15 #1714 --- ruuvi-widgets/RuuviWidgets.swift | 42 +++++++++++++++++++---- ruuvi-widgets/View/SimpleWidgetView.swift | 30 ++++++++++++---- 2 files changed, 58 insertions(+), 14 deletions(-) diff --git a/ruuvi-widgets/RuuviWidgets.swift b/ruuvi-widgets/RuuviWidgets.swift index fba90b869..703b0cf4a 100644 --- a/ruuvi-widgets/RuuviWidgets.swift +++ b/ruuvi-widgets/RuuviWidgets.swift @@ -27,7 +27,7 @@ struct RuuviWidgetEntryView: View { } else { UnauthorizedView() } - } + }.containerBackground() } } @@ -51,15 +51,40 @@ struct RuuviWidgets: Widget { } var body: some WidgetConfiguration { - IntentConfiguration(kind: kind, - intent: RuuviTagSelectionIntent.self, - provider: WidgetProvider()) { entry in + IntentConfiguration( + kind: kind, + intent: RuuviTagSelectionIntent.self, + provider: WidgetProvider() + ) { entry in RuuviWidgetEntryView(entry: entry) .environment(\.locale, viewModel.locale()) + }.configurationDisplayName(Constants.simpleWidgetDisplayName.rawValue) + .description(LocalizedStringKey("Widgets.Description.message")) + .supportedFamilies(supportedFamilies) + .contentMarginsDisabledIfAvailable() + } +} + +extension WidgetConfiguration { + func contentMarginsDisabledIfAvailable() -> some WidgetConfiguration { + if #available(iOSApplicationExtension 17.0, *) { + return self.contentMarginsDisabled() + } else { + return self + } + } +} + +extension View { + @ViewBuilder + func containerBackground() -> some View { + if #available(iOSApplicationExtension 17.0, *) { + self.containerBackground(for: .widget) { + Color.backgroundColor + } + } else { + self } - .configurationDisplayName(Constants.simpleWidgetDisplayName.rawValue) - .description(LocalizedStringKey("Widgets.Description.message")) - .supportedFamilies(supportedFamilies) } } @@ -68,6 +93,9 @@ struct RuuviWidgets_Previews: PreviewProvider { if #available(iOSApplicationExtension 16.0, *) { RuuviWidgetEntryView(entry: .placeholder()) .previewContext(WidgetPreviewContext(family: .accessoryCircular)) + } else if #available(iOSApplicationExtension 17.0, *) { + RuuviWidgetEntryView(entry: .placeholder()) + .previewContext(WidgetPreviewContext(family: .systemSmall)) } else { RuuviWidgetEntryView(entry: .placeholder()) .previewContext(WidgetPreviewContext(family: .systemSmall)) diff --git a/ruuvi-widgets/View/SimpleWidgetView.swift b/ruuvi-widgets/View/SimpleWidgetView.swift index edf54061c..ab9b1605a 100644 --- a/ruuvi-widgets/View/SimpleWidgetView.swift +++ b/ruuvi-widgets/View/SimpleWidgetView.swift @@ -1,12 +1,10 @@ import SwiftUI struct SimpleWidgetView: View { + @Environment(\.canShowWidgetContainerBackground) private var canShowBackground private let viewModel = WidgetViewModel() var entry: WidgetProvider.Entry var body: some View { - ZStack { - Color.backgroundColor.edgesIgnoringSafeArea(.all) - } GeometryReader { geometry in VStack { HStack { @@ -19,7 +17,11 @@ struct SimpleWidgetView: View { Spacer() Text(viewModel.measurementTime(from: entry)) .foregroundColor(Color.sensorNameColor1) - .font(.custom(Constants.muliRegular.rawValue, size: 10, relativeTo: .body)) + .font(.custom( + Constants.muliRegular.rawValue, + size: canShowBackground ? 10 : 14, + relativeTo: .body + )) .minimumScaleFactor(0.5) }.padding(EdgeInsets(top: 12, leading: 12, bottom: 0, trailing: 12)) @@ -29,7 +31,11 @@ struct SimpleWidgetView: View { HStack { Text(entry.tag.displayString) .foregroundColor(Color.sensorNameColor1) - .font(.custom(Constants.muliBold.rawValue, size: 16, relativeTo: .headline)) + .font(.custom( + Constants.muliBold.rawValue, + size: canShowBackground ? 16 : 22, + relativeTo: .headline) + ) .frame(maxWidth: .infinity, alignment: .leading) .fixedSize(horizontal: false, vertical: true) .minimumScaleFactor(0.5) @@ -42,13 +48,13 @@ struct SimpleWidgetView: View { .environment(\.locale, viewModel.locale()) .foregroundColor(.bodyTextColor) .font(.custom(Constants.oswaldBold.rawValue, - size: 36, + size: canShowBackground ? 36 : 66, relativeTo: .largeTitle)) .minimumScaleFactor(0.5) Text(viewModel.getUnit(for: WidgetSensorEnum(rawValue: entry.config.sensor.rawValue))) .foregroundColor(Color.unitTextColor) .font(.custom(Constants.oswaldExtraLight.rawValue, - size: 16, + size: canShowBackground ? 16 : 24, relativeTo: .title3)) .baselineOffset(14) .minimumScaleFactor(0.5) @@ -59,3 +65,13 @@ struct SimpleWidgetView: View { } } } + +extension EnvironmentValues { + var canShowWidgetContainerBackground: Bool { + if #available(iOSApplicationExtension 15.0, *) { + return self.showsWidgetContainerBackground + } else { + return false + } + } +} From 6cc7f561bbb02ba19a34bffb7c5ef7f78bac6973 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 18 Nov 2023 10:38:22 +0200 Subject: [PATCH 03/84] Add project.yml for xcodegened project with SPM (#1713) * Add project.yml for xcodegened project with SPM Motivation: migrate from development pods. What: created project.yml and refactored code to enable SPM based build. Steps: > brew install xcodegen > xcodegen > xed Ruuvi\ Station.xcodeproj/ Build and Run * fix imports --- .gitignore | 3 + Common/RuuviBundleUtils/.gitignore | 7 - Common/RuuviBundleUtils/Package.swift | 28 -- Common/RuuviBundleUtils/README.md | 3 - .../RuuviBundleUtils/RuuviBundleUtils.podspec | 31 --- .../RuuviBundleUtilsTests.swift | 11 - Common/RuuviLocalization/Package.swift | 3 +- Common/RuuviPresenters/Package.swift | 20 +- .../RuuviPresenters/RuuviPresenters.podspec | 2 - .../ActivityPresenterRuuviLogo.swift | 1 - .../Error/Alert/ErrorPresenterAlert.swift | 1 - .../Alert/PermissionPresenterAlert.swift | 1 - .../Resources/ActivityRuuviLogo.storyboard | 6 +- .../Util}/RuuviBundleUtils.swift | 0 .../RuuviPresentersTests.swift | 12 +- Modules/RuuviDiscover/Package.swift | 35 ++- .../RuuviDiscover/Util/RuuviBundleUtils.swift | 83 ++++++ .../Table/DiscoverTableViewController.swift | 1 - .../RuuviDiscoverTests.swift | 1 - Modules/RuuviLocationPicker/Package.swift | 20 +- .../Util/RuuviBundleUtils.swift | 83 ++++++ .../Presenter/LocationPickerPresenter.swift | 1 + Modules/RuuviOnboard/Package.swift | 7 +- Modules/RuuviOnboard/RuuviOnboard.podspec | 1 - .../Pages/RuuviOnboardViewController.swift | 1 - .../Pages/Util/RuuviBundleUtils.swift | 83 ++++++ Packages/RuuviAnalytics/Package.swift | 8 +- Packages/RuuviCloud/Package.swift | 10 +- .../Sources/RuuviCloud/RuuviCloud.swift | 2 +- .../RuuviCloud/RuuviCloudApiError.swift | 4 + .../RuuviCloudPNTokenListRequest.swift | 2 +- .../RuuviCloudPNTokenUnregisterRequest.swift | 5 + .../RuuviCloudApiAccountDeleteResponse.swift | 2 +- .../Response/RuuviCloudApiBaseResponse.swift | 2 +- .../Response/RuuviCloudApiClaimResponse.swift | 3 - .../RuuviCloudPure/RuuviCloudPure.swift | 2 +- Packages/RuuviContext/Package.swift | 4 +- Packages/RuuviCore/Package.swift | 7 +- Packages/RuuviDFU/Package.swift | 2 +- Packages/RuuviDaemon/Package.swift | 4 +- Packages/RuuviLocal/Package.swift | 4 +- Packages/RuuviLocation/Package.swift | 4 +- Packages/RuuviMigration/Package.swift | 2 +- Packages/RuuviNotification/Package.swift | 2 +- Packages/RuuviNotifier/Package.swift | 2 +- Packages/RuuviOntology/Package.swift | 6 +- Packages/RuuviPersistence/Package.swift | 4 +- Packages/RuuviPool/Package.swift | 4 +- Packages/RuuviReactor/Package.swift | 2 +- Packages/RuuviRepository/Package.swift | 4 +- Packages/RuuviService/Package.swift | 28 +- .../RuuviServiceAuthImpl.swift | 1 + .../RuuviServiceCloudNotificationImpl.swift | 3 + .../RuuviServiceFactory.swift | 6 + Packages/RuuviStorage/Package.swift | 4 +- Packages/RuuviUser/Package.swift | 4 +- Packages/RuuviVirtual/Package.swift | 2 +- Podfile | 3 +- Podfile.lock | 20 +- project.yml | 240 ++++++++++++++++++ station.xcodeproj/project.pbxproj | 8 +- station/Classes/Application/AppDelegate.swift | 3 +- .../About/Presenter/AboutPresenter.swift | 1 + .../Modules/About/Router/AboutRouter.swift | 2 + .../Cards/Presenter/CardsPresenter.swift | 1 + .../Dashboard/Cards/View/CardsViewInput.swift | 1 + .../Home/Interactor/DashboardInteractor.swift | 3 + .../Home/Presenter/DashboardPresenter.swift | 1 + .../Table/KaltiotTableInitializer.swift | 10 - .../Presenter/MyRuuviAccountPresenter.swift | 1 + .../Router/AppearanceSettingsRouter.swift | 1 + .../Router/NotificationsSettingsRouter.swift | 1 + .../SignIn/Presenter/SignInPresenter.swift | 1 + .../Presenter/TagSettingsPresenter.swift | 3 + .../Router/SensorForceClaimRouter.swift | 1 + .../OffsetCorrectionAppleViewController.swift | 3 + .../Submodules/Owner/Router/OwnerRouter.swift | 1 + .../Removal/Router/SensorRemovalRouter.swift | 1 + .../Router/UserApiConfigRouter.swift | 19 -- station/Classes/Routers/DiscoverRouter.swift | 1 + station/Resources/Plists/Info.plist | 4 +- station/Resources/Plists/Networking.plist | 2 + 82 files changed, 684 insertions(+), 232 deletions(-) delete mode 100644 Common/RuuviBundleUtils/.gitignore delete mode 100644 Common/RuuviBundleUtils/Package.swift delete mode 100644 Common/RuuviBundleUtils/README.md delete mode 100644 Common/RuuviBundleUtils/RuuviBundleUtils.podspec delete mode 100644 Common/RuuviBundleUtils/Tests/RuuviBundleUtilsTests/RuuviBundleUtilsTests.swift rename Common/{RuuviBundleUtils/Sources/RuuviBundleUtils => RuuviPresenters/Sources/RuuviPresenters/Util}/RuuviBundleUtils.swift (100%) create mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift create mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Util/RuuviBundleUtils.swift create mode 100644 Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift create mode 100644 project.yml delete mode 100644 station/Classes/Presentation/Modules/Kaltiot/Assembly/Table/KaltiotTableInitializer.swift delete mode 100644 station/Classes/Presentation/Modules/TagsManager/Router/UserApiConfigRouter.swift diff --git a/.gitignore b/.gitignore index 6fd0b0c71..a7fe67fd9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Generated +Ruuvi Station.xcodeproj + # Private station/Resources/Plists/GoogleService-Info.plist station/Classes/Networking/Assembly/Networking.plist diff --git a/Common/RuuviBundleUtils/.gitignore b/Common/RuuviBundleUtils/.gitignore deleted file mode 100644 index bb460e7be..000000000 --- a/Common/RuuviBundleUtils/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.DS_Store -/.build -/Packages -/*.xcodeproj -xcuserdata/ -DerivedData/ -.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata diff --git a/Common/RuuviBundleUtils/Package.swift b/Common/RuuviBundleUtils/Package.swift deleted file mode 100644 index 123d52762..000000000 --- a/Common/RuuviBundleUtils/Package.swift +++ /dev/null @@ -1,28 +0,0 @@ -// swift-tools-version:5.3 -// The swift-tools-version declares the minimum version of Swift required to build this package. - -import PackageDescription - -let package = Package( - name: "RuuviBundleUtils", - products: [ - // Products define the executables and libraries a package produces, and make them visible to other packages. - .library( - name: "RuuviBundleUtils", - targets: ["RuuviBundleUtils"]) - ], - dependencies: [ - // Dependencies declare other packages that this package depends on. - // .package(url: /* package url */, from: "1.0.0"), - ], - targets: [ - // Targets are the basic building blocks of a package. A target can define a module or a test suite. - // Targets can depend on other targets in this package, and on products in packages this package depends on. - .target( - name: "RuuviBundleUtils", - dependencies: []), - .testTarget( - name: "RuuviBundleUtilsTests", - dependencies: ["RuuviBundleUtils"]) - ] -) diff --git a/Common/RuuviBundleUtils/README.md b/Common/RuuviBundleUtils/README.md deleted file mode 100644 index 9517feee4..000000000 --- a/Common/RuuviBundleUtils/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# RuuviBundleUtils - -A description of this package. diff --git a/Common/RuuviBundleUtils/RuuviBundleUtils.podspec b/Common/RuuviBundleUtils/RuuviBundleUtils.podspec deleted file mode 100644 index deaab22b1..000000000 --- a/Common/RuuviBundleUtils/RuuviBundleUtils.podspec +++ /dev/null @@ -1,31 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviBundleUtils' - s.version = '0.0.1' - s.summary = 'Ruuvi BundleUtils' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'RuuviBundleUtils' - - s.subspec 'RuuviBundleUtils' do |ss| - ss.source_files = 'Sources/RuuviBundleUtils/**/*.{h,m,swift}', 'Sources/RuuviBundleUtils/*.{h,m,swift}' - ss.resource_bundles = { - 'RuuviBundleUtils' => ['Sources/**/Resources/**/*'] - } - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end - - - - diff --git a/Common/RuuviBundleUtils/Tests/RuuviBundleUtilsTests/RuuviBundleUtilsTests.swift b/Common/RuuviBundleUtils/Tests/RuuviBundleUtilsTests/RuuviBundleUtilsTests.swift deleted file mode 100644 index 33386d926..000000000 --- a/Common/RuuviBundleUtils/Tests/RuuviBundleUtilsTests/RuuviBundleUtilsTests.swift +++ /dev/null @@ -1,11 +0,0 @@ -import XCTest - @testable import RuuviBundleUtils - - final class RuuviBundleUtilsTests: XCTestCase { - func testExample() { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct - // results. - XCTAssertEqual(RuuviBundleUtils().text, "Hello, World!") - } - } diff --git a/Common/RuuviLocalization/Package.swift b/Common/RuuviLocalization/Package.swift index 3b58ba686..7ce392528 100644 --- a/Common/RuuviLocalization/Package.swift +++ b/Common/RuuviLocalization/Package.swift @@ -1,10 +1,11 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "RuuviLocalization", + platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( diff --git a/Common/RuuviPresenters/Package.swift b/Common/RuuviPresenters/Package.swift index 8c20dccf0..e8997bec6 100644 --- a/Common/RuuviPresenters/Package.swift +++ b/Common/RuuviPresenters/Package.swift @@ -1,28 +1,26 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "RuuviPresenters", + defaultLocalization: "en", + platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ - // Products define the executables and libraries a package produces, and make them visible to other packages. .library( name: "RuuviPresenters", - targets: ["RuuviPresenters"]) - ], - dependencies: [ - // Dependencies declare other packages that this package depends on. - // .package(url: /* package url */, from: "1.0.0"), + targets: ["RuuviPresenters"] + ) ], targets: [ - // Targets are the basic building blocks of a package. A target can define a module or a test suite. - // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "RuuviPresenters", - dependencies: []), + resources: [.process("Resources")] + ), .testTarget( name: "RuuviPresentersTests", - dependencies: ["RuuviPresenters"]) + dependencies: ["RuuviPresenters"] + ) ] ) diff --git a/Common/RuuviPresenters/RuuviPresenters.podspec b/Common/RuuviPresenters/RuuviPresenters.podspec index a70b2c733..ac4d34817 100644 --- a/Common/RuuviPresenters/RuuviPresenters.podspec +++ b/Common/RuuviPresenters/RuuviPresenters.podspec @@ -19,8 +19,6 @@ Pod::Spec.new do |s| ss.resource_bundles = { 'RuuviPresenters' => ['Sources/**/Resources/**/*'] } - - ss.dependency 'RuuviBundleUtils' end s.test_spec 'Tests' do |test_spec| diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift index 4b181bdf6..a22c198e4 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift @@ -1,5 +1,4 @@ import UIKit -import RuuviBundleUtils public final class ActivityPresenterRuuviLogo: ActivityPresenter { var counter = 0 { diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Error/Alert/ErrorPresenterAlert.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Error/Alert/ErrorPresenterAlert.swift index 329ea2345..3c6f5bd9c 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Error/Alert/ErrorPresenterAlert.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Error/Alert/ErrorPresenterAlert.swift @@ -1,5 +1,4 @@ import UIKit -import RuuviBundleUtils public final class ErrorPresenterAlert: ErrorPresenter { public init() {} diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Permission/Alert/PermissionPresenterAlert.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Permission/Alert/PermissionPresenterAlert.swift index a162e2134..866dd72f1 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Permission/Alert/PermissionPresenterAlert.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Permission/Alert/PermissionPresenterAlert.swift @@ -1,5 +1,4 @@ import UIKit -import RuuviBundleUtils public final class PermissionPresenterAlert: PermissionPresenter { public init() {} diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/ActivityRuuviLogo.storyboard b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/ActivityRuuviLogo.storyboard index 3a187ac25..f88418340 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/ActivityRuuviLogo.storyboard +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/ActivityRuuviLogo.storyboard @@ -1,9 +1,9 @@ - + - + @@ -11,7 +11,7 @@ - + diff --git a/Common/RuuviBundleUtils/Sources/RuuviBundleUtils/RuuviBundleUtils.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift similarity index 100% rename from Common/RuuviBundleUtils/Sources/RuuviBundleUtils/RuuviBundleUtils.swift rename to Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift diff --git a/Common/RuuviPresenters/Tests/RuuviPresentersTests/RuuviPresentersTests.swift b/Common/RuuviPresenters/Tests/RuuviPresentersTests/RuuviPresentersTests.swift index 0396cf18a..81d4e300e 100644 --- a/Common/RuuviPresenters/Tests/RuuviPresentersTests/RuuviPresentersTests.swift +++ b/Common/RuuviPresenters/Tests/RuuviPresentersTests/RuuviPresentersTests.swift @@ -1,11 +1,7 @@ import XCTest - @testable import RuuviPresenters +@testable import RuuviPresenters - final class RuuviPresentersTests: XCTestCase { - func testExample() { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct - // results. - XCTAssertEqual(RuuviPresenters().text, "Hello, World!") - } +final class RuuviPresentersTests: XCTestCase { + func testExample() { } +} diff --git a/Modules/RuuviDiscover/Package.swift b/Modules/RuuviDiscover/Package.swift index e1ec72b9c..2ef691a3a 100644 --- a/Modules/RuuviDiscover/Package.swift +++ b/Modules/RuuviDiscover/Package.swift @@ -1,28 +1,45 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "RuuviDiscover", + defaultLocalization: "en", + platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ - // Products define the executables and libraries a package produces, and make them visible to other packages. .library( name: "RuuviDiscover", targets: ["RuuviDiscover"]) ], dependencies: [ - // Dependencies declare other packages that this package depends on. - // .package(url: /* package url */, from: "1.0.0"), + .package(path: "../../Packages/RuuviOntology"), + .package(path: "../../Packages/RuuviContext"), + .package(path: "../../Packages/RuuviReactor"), + .package(path: "../../Packages/RuuviLocal"), + .package(path: "../../Packages/RuuviService"), + .package(path: "../../Packages/RuuviVirtual"), + .package(path: "../../Common/RuuviPresenters"), + .package(path: "../../Common/RuuviLocalization"), + .package(url: "https://github.com/ruuvi/BTKit", .upToNextMinor(from: "0.4.3")), ], targets: [ - // Targets are the basic building blocks of a package. A target can define a module or a test suite. - // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "RuuviDiscover", - dependencies: []), + dependencies: [ + "RuuviOntology", + "RuuviContext", + "RuuviReactor", + "RuuviLocal", + "RuuviService", + "RuuviVirtual", + "RuuviPresenters", + "BTKit", + "RuuviLocalization" + ] + ), .testTarget( - name: "RuuviDiscoverTests", - dependencies: ["RuuviDiscover"]) + name: "RuuviDiscoverTests" + ) ] ) diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift new file mode 100644 index 000000000..3f6f7e798 --- /dev/null +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift @@ -0,0 +1,83 @@ +import Foundation +import UIKit + +extension Bundle { + public static func pod(_ clazz: AnyClass) -> Bundle { + if let module = NSStringFromClass(clazz).components(separatedBy: ".").first, + let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), + let bundle = Bundle(url: bundleURL) { + return bundle + } else { + assertionFailure() + return Bundle.main + } + } +} + +extension UIImage { + public static func named(_ name: String, for clazz: AnyClass) -> UIImage? { + #if SWIFT_PACKAGE + return UIImage(named: name, in: Bundle.module, compatibleWith: nil) + #else + return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) + #endif + } +} + +extension String { + public func localized(for clazz: AnyClass) -> String { + let bundle: Bundle + #if SWIFT_PACKAGE + bundle = Bundle.module + #else + bundle = Bundle.pod(clazz) + #endif + if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { + if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), + let bundle = Bundle(path: path) { + return bundle.localizedString(forKey: self, value: nil, table: module) + } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), + let bundle = Bundle(path: path) { + return bundle.localizedString(forKey: self, value: nil, table: module) + } else { + assertionFailure() + return self + } + } else { + assertionFailure() + return self + } + } + + private func currentLanguage() -> String { + if let preferred = Bundle.main.preferredLocalizations.first { + return preferred + } else { + return "Base" + } + } +} + +extension UIStoryboard { + public static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { + let bundle: Bundle + #if SWIFT_PACKAGE + bundle = Bundle.module + #else + bundle = Bundle.pod(clazz) + #endif + return UIStoryboard(name: name, bundle: bundle) + } +} + +extension UINib { + public static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { + let bundle: Bundle + #if SWIFT_PACKAGE + bundle = Bundle.module + #else + bundle = Bundle.pod(clazz) + #endif + return UINib(nibName: nibName, bundle: bundle) + } +} diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift index 9bc3248ff..68d4f0964 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift @@ -3,7 +3,6 @@ import BTKit import RuuviOntology import RuuviVirtual import RuuviLocalization -import RuuviBundleUtils import CoreNFC enum DiscoverTableSection { diff --git a/Modules/RuuviDiscover/Tests/RuuviDiscoverTests/RuuviDiscoverTests.swift b/Modules/RuuviDiscover/Tests/RuuviDiscoverTests/RuuviDiscoverTests.swift index 58644a282..5bbd240b7 100644 --- a/Modules/RuuviDiscover/Tests/RuuviDiscoverTests/RuuviDiscoverTests.swift +++ b/Modules/RuuviDiscover/Tests/RuuviDiscoverTests/RuuviDiscoverTests.swift @@ -1,5 +1,4 @@ import XCTest -@testable import RuuviDiscover final class RuuviDiscoverTests: XCTestCase { func testExample() { diff --git a/Modules/RuuviLocationPicker/Package.swift b/Modules/RuuviLocationPicker/Package.swift index 69456016e..1568ed6d5 100644 --- a/Modules/RuuviLocationPicker/Package.swift +++ b/Modules/RuuviLocationPicker/Package.swift @@ -1,10 +1,12 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "RuuviLocationPicker", + defaultLocalization: "en", + platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( @@ -12,15 +14,25 @@ let package = Package( targets: ["RuuviLocationPicker"]) ], dependencies: [ - // Dependencies declare other packages that this package depends on. - // .package(url: /* package url */, from: "1.0.0"), + .package(path: "../../Packages/RuuviOntology"), + .package(path: "../../Common/RuuviPresenters"), + .package(path: "../../Common/RuuviLocalization"), + .package(path: "../../Packages/RuuviCore"), + .package(path: "../../Packages/RuuviLocation"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "RuuviLocationPicker", - dependencies: []), + dependencies: [ + "RuuviOntology", + "RuuviPresenters", + "RuuviCore", + "RuuviLocation", + "RuuviLocalization" + ] + ), .testTarget( name: "RuuviLocationPickerTests", dependencies: ["RuuviLocationPicker"]) diff --git a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Util/RuuviBundleUtils.swift b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Util/RuuviBundleUtils.swift new file mode 100644 index 000000000..3f6f7e798 --- /dev/null +++ b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Util/RuuviBundleUtils.swift @@ -0,0 +1,83 @@ +import Foundation +import UIKit + +extension Bundle { + public static func pod(_ clazz: AnyClass) -> Bundle { + if let module = NSStringFromClass(clazz).components(separatedBy: ".").first, + let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), + let bundle = Bundle(url: bundleURL) { + return bundle + } else { + assertionFailure() + return Bundle.main + } + } +} + +extension UIImage { + public static func named(_ name: String, for clazz: AnyClass) -> UIImage? { + #if SWIFT_PACKAGE + return UIImage(named: name, in: Bundle.module, compatibleWith: nil) + #else + return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) + #endif + } +} + +extension String { + public func localized(for clazz: AnyClass) -> String { + let bundle: Bundle + #if SWIFT_PACKAGE + bundle = Bundle.module + #else + bundle = Bundle.pod(clazz) + #endif + if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { + if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), + let bundle = Bundle(path: path) { + return bundle.localizedString(forKey: self, value: nil, table: module) + } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), + let bundle = Bundle(path: path) { + return bundle.localizedString(forKey: self, value: nil, table: module) + } else { + assertionFailure() + return self + } + } else { + assertionFailure() + return self + } + } + + private func currentLanguage() -> String { + if let preferred = Bundle.main.preferredLocalizations.first { + return preferred + } else { + return "Base" + } + } +} + +extension UIStoryboard { + public static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { + let bundle: Bundle + #if SWIFT_PACKAGE + bundle = Bundle.module + #else + bundle = Bundle.pod(clazz) + #endif + return UIStoryboard(name: name, bundle: bundle) + } +} + +extension UINib { + public static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { + let bundle: Bundle + #if SWIFT_PACKAGE + bundle = Bundle.module + #else + bundle = Bundle.pod(clazz) + #endif + return UINib(nibName: nibName, bundle: bundle) + } +} diff --git a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/Presenter/LocationPickerPresenter.swift b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/Presenter/LocationPickerPresenter.swift index b2adf2a27..6cdd21793 100644 --- a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/Presenter/LocationPickerPresenter.swift +++ b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/Presenter/LocationPickerPresenter.swift @@ -3,6 +3,7 @@ import CoreLocation import RuuviLocation import RuuviCore import RuuviPresenters +import UIKit class LocationPickerPresenter: RuuviLocationPicker { var viewController: UIViewController { diff --git a/Modules/RuuviOnboard/Package.swift b/Modules/RuuviOnboard/Package.swift index 194fbc903..f21a142b7 100644 --- a/Modules/RuuviOnboard/Package.swift +++ b/Modules/RuuviOnboard/Package.swift @@ -6,20 +6,19 @@ import PackageDescription let package = Package( name: "RuuviOnboard", defaultLocalization: "en", - platforms: [.iOS(.v11), .macOS(.v10_15)], + platforms: [.iOS(.v13), .macOS(.v10_15)], products: [ .library( name: "RuuviOnboard", targets: ["RuuviOnboard"]) ], dependencies: [ - // Dependencies declare other packages that this package depends on. - // .package(url: /* package url */, from: "1.0.0"), + .package(path: "../../Packages/RuuviUser") ], targets: [ .target( name: "RuuviOnboard", - dependencies: []), + dependencies: ["RuuviUser"]), .testTarget( name: "RuuviOnboardTests", dependencies: ["RuuviOnboard"]) diff --git a/Modules/RuuviOnboard/RuuviOnboard.podspec b/Modules/RuuviOnboard/RuuviOnboard.podspec index f1720b9d0..e368acbb4 100644 --- a/Modules/RuuviOnboard/RuuviOnboard.podspec +++ b/Modules/RuuviOnboard/RuuviOnboard.podspec @@ -19,7 +19,6 @@ Pod::Spec.new do |s| ss.resource_bundles = { 'RuuviOnboard' => ['Sources/**/Resources/**/*'] } - ss.dependency 'RuuviBundleUtils' ss.dependency 'RuuviUser' end diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift index 409cf0c3f..4740e9823 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift @@ -1,6 +1,5 @@ import UIKit import RuuviUser -import RuuviBundleUtils // swiftlint:disable file_length diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift new file mode 100644 index 000000000..3f6f7e798 --- /dev/null +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift @@ -0,0 +1,83 @@ +import Foundation +import UIKit + +extension Bundle { + public static func pod(_ clazz: AnyClass) -> Bundle { + if let module = NSStringFromClass(clazz).components(separatedBy: ".").first, + let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), + let bundle = Bundle(url: bundleURL) { + return bundle + } else { + assertionFailure() + return Bundle.main + } + } +} + +extension UIImage { + public static func named(_ name: String, for clazz: AnyClass) -> UIImage? { + #if SWIFT_PACKAGE + return UIImage(named: name, in: Bundle.module, compatibleWith: nil) + #else + return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) + #endif + } +} + +extension String { + public func localized(for clazz: AnyClass) -> String { + let bundle: Bundle + #if SWIFT_PACKAGE + bundle = Bundle.module + #else + bundle = Bundle.pod(clazz) + #endif + if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { + if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), + let bundle = Bundle(path: path) { + return bundle.localizedString(forKey: self, value: nil, table: module) + } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), + let bundle = Bundle(path: path) { + return bundle.localizedString(forKey: self, value: nil, table: module) + } else { + assertionFailure() + return self + } + } else { + assertionFailure() + return self + } + } + + private func currentLanguage() -> String { + if let preferred = Bundle.main.preferredLocalizations.first { + return preferred + } else { + return "Base" + } + } +} + +extension UIStoryboard { + public static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { + let bundle: Bundle + #if SWIFT_PACKAGE + bundle = Bundle.module + #else + bundle = Bundle.pod(clazz) + #endif + return UIStoryboard(name: name, bundle: bundle) + } +} + +extension UINib { + public static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { + let bundle: Bundle + #if SWIFT_PACKAGE + bundle = Bundle.module + #else + bundle = Bundle.pod(clazz) + #endif + return UINib(nibName: nibName, bundle: bundle) + } +} diff --git a/Packages/RuuviAnalytics/Package.swift b/Packages/RuuviAnalytics/Package.swift index b8fb6a138..e64cd5710 100644 --- a/Packages/RuuviAnalytics/Package.swift +++ b/Packages/RuuviAnalytics/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -15,13 +15,13 @@ let package = Package( targets: ["RuuviAnalyticsImpl"]) ], dependencies: [ - .package(name: "Firebase", url: "https://github.com/firebase/firebase-ios-sdk", .upToNextMajor(from: "9.0.0")), + .package(name: "Firebase", url: "https://github.com/firebase/firebase-ios-sdk", .upToNextMajor(from: "10.0.0")), .package(path: "../RuuviStorage"), .package(path: "../RuuviLocal"), .package(path: "../RuuviOntology"), .package(path: "../RuuviVirtual"), .package(path: "../RuuviUser"), - .package(path: "../RuuviService/Alert") + .package(path: "../RuuviService") ], targets: [ .target( @@ -37,7 +37,7 @@ let package = Package( "RuuviOntology", "RuuviVirtual", "RuuviUser", - "RuuviService/Alert" + "RuuviService" ]), .testTarget( name: "RuuviAnalyticsTests", diff --git a/Packages/RuuviCloud/Package.swift b/Packages/RuuviCloud/Package.swift index 7027f00f9..37789cee2 100644 --- a/Packages/RuuviCloud/Package.swift +++ b/Packages/RuuviCloud/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "RuuviCloud", - platforms: [.macOS(.v10_15), .iOS(.v11)], + platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ .library( name: "RuuviCloud", @@ -19,9 +19,10 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/kean/Future", .exact("1.3.0")), - .package(url: "https://github.com/rinat-enikeev/BTKit", .upToNextMinor(from: "0.3.0")), + .package(url: "https://github.com/ruuvi/BTKit", .upToNextMinor(from: "0.4.3")), .package(path: "../RuuviOntology"), - .package(path: "../RuuviUser") + .package(path: "../RuuviUser"), + .package(path: "../RuuviPool") ], targets: [ .target( @@ -29,6 +30,7 @@ let package = Package( dependencies: [ "Future", "RuuviOntology", + "RuuviPool", "RuuviUser" ] ), diff --git a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift index 46fc4bd5e..2a67edc6c 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift @@ -18,7 +18,7 @@ public struct ShareSensorResponse { public var macId: MACIdentifier? public var invited: Bool? - init(macId: MACIdentifier? = nil, invited: Bool? = nil) { + public init(macId: MACIdentifier? = nil, invited: Bool? = nil) { self.macId = macId self.invited = invited } diff --git a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloudApiError.swift b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloudApiError.swift index 0174cddee..3fbc6bd3c 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloudApiError.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloudApiError.swift @@ -11,3 +11,7 @@ public enum RuuviCloudApiError: Error { case failedToGetDataFromResponse case unauthorized } + +public struct RuuviCloudApiClaimError: Decodable { + public let error, code: String? +} diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenListRequest.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenListRequest.swift index 1da0e8db3..0bf6c659f 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenListRequest.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenListRequest.swift @@ -1,5 +1,5 @@ import Foundation public struct RuuviCloudPNTokenListRequest: Encodable { - + public init() {} } diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenUnregisterRequest.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenUnregisterRequest.swift index 0089cfb57..e0fa273c4 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenUnregisterRequest.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenUnregisterRequest.swift @@ -3,4 +3,9 @@ import Foundation public struct RuuviCloudPNTokenUnregisterRequest: Encodable { let token: String? let id: Int? + + public init(token: String?, id: Int?) { + self.token = token + self.id = id + } } diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiAccountDeleteResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiAccountDeleteResponse.swift index 8c73b899a..fd02ba625 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiAccountDeleteResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiAccountDeleteResponse.swift @@ -1,5 +1,5 @@ import Foundation public struct RuuviCloudApiAccountDeleteResponse: Codable { - let email: String? + public let email: String? } diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiBaseResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiBaseResponse.swift index cdcba9c0e..5ce820977 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiBaseResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiBaseResponse.swift @@ -35,7 +35,7 @@ extension RuuviCloudApiBaseResponse { return .success(data) case .error: guard let code = code else { - if let description = errorDescription { + if errorDescription != nil { return .failure(.api(.erInternal)) } else { return .failure(.emptyResponse) diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiClaimResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiClaimResponse.swift index 2b53de7e8..e3c609963 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiClaimResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiClaimResponse.swift @@ -3,8 +3,5 @@ import Foundation public struct RuuviCloudApiClaimResponse: Decodable { public let sensor: String? } -public struct RuuviCloudApiClaimError: Decodable { - public let error, code: String? -} public struct RuuviCloudApiUnclaimResponse: Decodable { } diff --git a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift index fd98d63b7..046e87bdc 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift @@ -752,7 +752,7 @@ public final class RuuviCloudPure: RuuviCloud { offsetHumidity: sensor.offsetHumidity, offsetPressure: sensor.offsetPressure, isCloudSensor: true, - canShare: sensor.canShare ?? false, + canShare: sensor.canShare, sharedTo: sensor.sharedTo ?? [] ), record: self?.decodeSensorRecord( diff --git a/Packages/RuuviContext/Package.swift b/Packages/RuuviContext/Package.swift index 18e746d28..589a9745f 100644 --- a/Packages/RuuviContext/Package.swift +++ b/Packages/RuuviContext/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "RuuviContext", - platforms: [.macOS(.v10_15), .iOS(.v11)], + platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ .library( name: "RuuviContext", diff --git a/Packages/RuuviCore/Package.swift b/Packages/RuuviCore/Package.swift index e4acc05e3..7db1f8f8e 100644 --- a/Packages/RuuviCore/Package.swift +++ b/Packages/RuuviCore/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "RuuviCore", - platforms: [.macOS(.v10_15), .iOS(.v11)], + platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ .library( name: "RuuviCore", @@ -32,7 +32,8 @@ let package = Package( targets: [ .target( name: "RuuviCore", - dependencies: []), + dependencies: ["Future"] + ), .target( name: "RuuviCoreImage", dependencies: ["RuuviCore"] diff --git a/Packages/RuuviDFU/Package.swift b/Packages/RuuviDFU/Package.swift index 4cd43d475..ba3c61b60 100644 --- a/Packages/RuuviDFU/Package.swift +++ b/Packages/RuuviDFU/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription diff --git a/Packages/RuuviDaemon/Package.swift b/Packages/RuuviDaemon/Package.swift index 35c16729a..0a82c26d4 100644 --- a/Packages/RuuviDaemon/Package.swift +++ b/Packages/RuuviDaemon/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -37,7 +37,7 @@ let package = Package( .package(path: "../RuuviPersistence"), .package(path: "../RuuviNotifier"), .package(path: "../RuuviNotification"), - .package(url: "https://github.com/rinat-enikeev/BTKit", .upToNextMinor(from: "0.3.0")) + .package(url: "https://github.com/ruuvi/BTKit", .upToNextMinor(from: "0.4.3")) ], targets: [ .target( diff --git a/Packages/RuuviLocal/Package.swift b/Packages/RuuviLocal/Package.swift index dc5239387..2fe57a942 100644 --- a/Packages/RuuviLocal/Package.swift +++ b/Packages/RuuviLocal/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "RuuviLocal", - platforms: [.macOS(.v10_15), .iOS(.v11)], + platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ .library( name: "RuuviLocal", diff --git a/Packages/RuuviLocation/Package.swift b/Packages/RuuviLocation/Package.swift index 78ed4d0f7..1247afef7 100644 --- a/Packages/RuuviLocation/Package.swift +++ b/Packages/RuuviLocation/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "RuuviLocation", - platforms: [.macOS(.v10_15), .iOS(.v11)], + platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ .library( name: "RuuviLocation", diff --git a/Packages/RuuviMigration/Package.swift b/Packages/RuuviMigration/Package.swift index 3d762a217..ee361f28f 100644 --- a/Packages/RuuviMigration/Package.swift +++ b/Packages/RuuviMigration/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription diff --git a/Packages/RuuviNotification/Package.swift b/Packages/RuuviNotification/Package.swift index a34cd8ebd..43240e514 100644 --- a/Packages/RuuviNotification/Package.swift +++ b/Packages/RuuviNotification/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription diff --git a/Packages/RuuviNotifier/Package.swift b/Packages/RuuviNotifier/Package.swift index f5357a7d1..ccfa633a0 100644 --- a/Packages/RuuviNotifier/Package.swift +++ b/Packages/RuuviNotifier/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription diff --git a/Packages/RuuviOntology/Package.swift b/Packages/RuuviOntology/Package.swift index be689831d..81c037975 100644 --- a/Packages/RuuviOntology/Package.swift +++ b/Packages/RuuviOntology/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "RuuviOntology", - platforms: [.macOS(.v10_15), .iOS(.v11)], + platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ .library( name: "RuuviOntology", @@ -22,7 +22,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/rinat-enikeev/Humidity", from: "0.1.5"), - .package(url: "https://github.com/rinat-enikeev/BTKit", .upToNextMinor(from: "0.3.0")), + .package(url: "https://github.com/ruuvi/BTKit", .upToNextMinor(from: "0.4.3")), .package(name: "Realm", url: "https://github.com/realm/realm-cocoa", .upToNextMajor(from: "10.8.0")), .package(name: "GRDB", url: "https://github.com/groue/GRDB.swift", .upToNextMajor(from: "4.14.0")) ], diff --git a/Packages/RuuviPersistence/Package.swift b/Packages/RuuviPersistence/Package.swift index 5a09c6188..c311e1131 100644 --- a/Packages/RuuviPersistence/Package.swift +++ b/Packages/RuuviPersistence/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "RuuviPersistence", - platforms: [.macOS(.v10_15), .iOS(.v11)], + platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ .library( name: "RuuviPersistence", diff --git a/Packages/RuuviPool/Package.swift b/Packages/RuuviPool/Package.swift index 073e80e75..ceee1a7e7 100644 --- a/Packages/RuuviPool/Package.swift +++ b/Packages/RuuviPool/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "RuuviPool", - platforms: [.macOS(.v10_15), .iOS(.v11)], + platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ .library( name: "RuuviPool", diff --git a/Packages/RuuviReactor/Package.swift b/Packages/RuuviReactor/Package.swift index 29ab5a21c..56849b046 100644 --- a/Packages/RuuviReactor/Package.swift +++ b/Packages/RuuviReactor/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription diff --git a/Packages/RuuviRepository/Package.swift b/Packages/RuuviRepository/Package.swift index 4f5fc3ec8..df13b9326 100644 --- a/Packages/RuuviRepository/Package.swift +++ b/Packages/RuuviRepository/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "RuuviRepository", - platforms: [.macOS(.v10_15), .iOS(.v11)], + platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ .library( name: "RuuviRepository", diff --git a/Packages/RuuviService/Package.swift b/Packages/RuuviService/Package.swift index 179e2ecbb..c6639cd50 100644 --- a/Packages/RuuviService/Package.swift +++ b/Packages/RuuviService/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "RuuviService", - platforms: [.macOS(.v10_15), .iOS(.v11)], + platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ .library( name: "RuuviService", @@ -13,6 +13,12 @@ let package = Package( .library( name: "RuuviServiceAlert", targets: ["RuuviServiceAlert"]), + .library( + name: "RuuviServiceAuth", + targets: ["RuuviServiceAuth"]), + .library( + name: "RuuviServiceCloudNotification", + targets: ["RuuviServiceCloudNotification"]), .library( name: "RuuviServiceAppSettings", targets: ["RuuviServiceAppSettings"]), @@ -48,7 +54,7 @@ let package = Package( dependencies: [ .package(url: "https://github.com/kean/Future", .exact("1.3.0")), .package(url: "https://github.com/rinat-enikeev/Humidity", from: "0.1.5"), - .package(url: "https://github.com/rinat-enikeev/BTKit", .upToNextMinor(from: "0.3.0")), + .package(url: "https://github.com/ruuvi/BTKit", .upToNextMinor(from: "0.4.3")), .package(path: "../RuuviOntology"), .package(path: "../RuuviStorage"), .package(path: "../RuuviCloud"), @@ -77,6 +83,18 @@ let package = Package( "RuuviService" ] ), + .target( + name: "RuuviServiceAuth", + dependencies: [ + "RuuviService" + ] + ), + .target( + name: "RuuviServiceCloudNotification", + dependencies: [ + "RuuviService" + ] + ), .target( name: "RuuviServiceAppSettings", dependencies: [ @@ -139,13 +157,15 @@ let package = Package( name: "RuuviServiceFactory", dependencies: [ "RuuviService", + "RuuviServiceAuth", "RuuviServiceAlert", "RuuviServiceAppSettings", "RuuviServiceCloudSync", "RuuviServiceOffsetCalibration", "RuuviServiceOwnership", "RuuviServiceSensorProperties", - "RuuviServiceSensorRecords" + "RuuviServiceSensorRecords", + "RuuviServiceCloudNotification" ] ), .testTarget( diff --git a/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift b/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift index 2253f4553..f0b7d5a86 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift @@ -5,6 +5,7 @@ import RuuviStorage import RuuviPool import RuuviLocal import RuuviOntology +import RuuviService public final class RuuviServiceAuthImpl: RuuviServiceAuth { private let ruuviUser: RuuviUser diff --git a/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift b/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift index dd91d4b90..5bba0fcb4 100644 --- a/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift @@ -3,6 +3,9 @@ import Future import RuuviOntology import RuuviStorage import RuuviCloud +#if canImport(RuuviCloudApi) +import RuuviCloudApi +#endif import RuuviPool import RuuviLocal import RuuviService diff --git a/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift b/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift index 811c84fdb..0a668f620 100644 --- a/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift +++ b/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift @@ -7,6 +7,12 @@ import RuuviCore import RuuviRepository import RuuviService import RuuviUser +#if canImport(RuuviServiceAuth) +import RuuviServiceAuth +#endif +#if canImport(RuuviServiceCloudNotification) +import RuuviServiceCloudNotification +#endif #if canImport(RuuviServiceAlert) import RuuviServiceAlert #endif diff --git a/Packages/RuuviStorage/Package.swift b/Packages/RuuviStorage/Package.swift index 01f76fed1..01d7a9fc0 100644 --- a/Packages/RuuviStorage/Package.swift +++ b/Packages/RuuviStorage/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "RuuviStorage", - platforms: [.macOS(.v10_15), .iOS(.v11)], + platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ .library( name: "RuuviStorage", diff --git a/Packages/RuuviUser/Package.swift b/Packages/RuuviUser/Package.swift index 494a294bb..dce01ebd6 100644 --- a/Packages/RuuviUser/Package.swift +++ b/Packages/RuuviUser/Package.swift @@ -1,11 +1,11 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "RuuviUser", - platforms: [.macOS(.v10_15), .iOS(.v11)], + platforms: [.macOS(.v10_15), .iOS(.v13)], products: [ .library( name: "RuuviUser", diff --git a/Packages/RuuviVirtual/Package.swift b/Packages/RuuviVirtual/Package.swift index db91d07ee..22e43eeed 100644 --- a/Packages/RuuviVirtual/Package.swift +++ b/Packages/RuuviVirtual/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.9 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription diff --git a/Podfile b/Podfile index 35c941a30..66d6016f0 100644 --- a/Podfile +++ b/Podfile @@ -31,7 +31,6 @@ def shared_pods pod 'RealmSwift', '~> 10.33.0' # common pod 'RuuviPresenters', :path => 'Common/RuuviPresenters/RuuviPresenters.podspec', :testspecs => ['Tests'] - pod 'RuuviBundleUtils', :path => 'Common/RuuviBundleUtils/RuuviBundleUtils.podspec', :testspecs => ['Tests'] pod 'RuuviLocalization', :path => 'Common/RuuviLocalization/RuuviLocalization.podspec', :testspecs => ['Tests'] # modules pod 'RuuviDiscover', :path => 'Modules/RuuviDiscover/RuuviDiscover.podspec', :testspecs => ['Tests'] @@ -49,6 +48,7 @@ def shared_pods pod 'RuuviCore/Permission', :path => 'Packages/RuuviCore/RuuviCore.podspec' pod 'RuuviCloud', :path => 'Packages/RuuviCloud/RuuviCloud.podspec', :testspecs => ['Tests'] pod 'RuuviCloud/Pure', :path => 'Packages/RuuviCloud/RuuviCloud.podspec' + pod 'RuuviCloud/Api', :path => 'Packages/RuuviCloud/RuuviCloud.podspec' pod 'RuuviDFU', :path => 'Packages/RuuviDFU/RuuviDFU.podspec', :testspecs => ['Tests'] pod 'RuuviDFU/Impl', :path => 'Packages/RuuviDFU/RuuviDFU.podspec' pod 'RuuviDaemon', :path => 'Packages/RuuviDaemon/RuuviDaemon.podspec', :testspecs => ['Tests'] @@ -118,7 +118,6 @@ def widget_pods pod 'RuuviCloud', :path => 'Packages/RuuviCloud/RuuviCloud.podspec', :testspecs => ['Tests'] pod 'RuuviCloud/Pure', :path => 'Packages/RuuviCloud/RuuviCloud.podspec' pod 'KeychainAccess' - pod 'RuuviBundleUtils', :path => 'Common/RuuviBundleUtils/RuuviBundleUtils.podspec', :testspecs => ['Tests'] pod 'RuuviPool', :path => 'Packages/RuuviPool/RuuviPool.podspec', :testspecs => ['Tests'] pod 'RuuviPool/Coordinator', :path => 'Packages/RuuviPool/RuuviPool.podspec' pod 'RuuviLocal/UserDefaults', :path => 'Packages/RuuviLocal/RuuviLocal.podspec' diff --git a/Podfile.lock b/Podfile.lock index 88b6a14f4..4d5399629 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -174,10 +174,6 @@ PODS: - RuuviUser - RuuviVirtual - RuuviAnalytics/Tests (0.0.3) - - RuuviBundleUtils (0.0.1): - - RuuviBundleUtils/RuuviBundleUtils (= 0.0.1) - - RuuviBundleUtils/RuuviBundleUtils (0.0.1) - - RuuviBundleUtils/Tests (0.0.1) - RuuviCloud (0.1.0): - RuuviCloud/Contract (= 0.1.0) - RuuviCloud/Api (0.1.0): @@ -353,7 +349,6 @@ PODS: - RuuviOnboard (0.0.4): - RuuviOnboard/RuuviOnboard (= 0.0.4) - RuuviOnboard/RuuviOnboard (0.0.4): - - RuuviBundleUtils - RuuviUser - RuuviOnboard/Tests (0.0.4) - RuuviOntology (0.0.6): @@ -412,8 +407,7 @@ PODS: - RuuviPool/Tests (0.0.1) - RuuviPresenters (0.0.1): - RuuviPresenters/RuuviPresenters (= 0.0.1) - - RuuviPresenters/RuuviPresenters (0.0.1): - - RuuviBundleUtils + - RuuviPresenters/RuuviPresenters (0.0.1) - RuuviPresenters/Tests (0.0.1) - RuuviReactor (0.0.1): - RuuviReactor/Contract (= 0.0.1) @@ -615,9 +609,8 @@ DEPENDENCIES: - RuuviAnalytics (from `Packages/RuuviAnalytics/RuuviAnalytics.podspec`) - RuuviAnalytics/Impl (from `Packages/RuuviAnalytics/RuuviAnalytics.podspec`) - RuuviAnalytics/Tests (from `Packages/RuuviAnalytics/RuuviAnalytics.podspec`) - - RuuviBundleUtils (from `Common/RuuviBundleUtils/RuuviBundleUtils.podspec`) - - RuuviBundleUtils/Tests (from `Common/RuuviBundleUtils/RuuviBundleUtils.podspec`) - RuuviCloud (from `Packages/RuuviCloud/RuuviCloud.podspec`) + - RuuviCloud/Api (from `Packages/RuuviCloud/RuuviCloud.podspec`) - RuuviCloud/Pure (from `Packages/RuuviCloud/RuuviCloud.podspec`) - RuuviCloud/Tests (from `Packages/RuuviCloud/RuuviCloud.podspec`) - RuuviContext (from `Packages/RuuviContext/RuuviContext.podspec`) @@ -755,8 +748,6 @@ EXTERNAL SOURCES: :git: https://github.com/rinat-enikeev/RangeSeekSlider RuuviAnalytics: :path: Packages/RuuviAnalytics/RuuviAnalytics.podspec - RuuviBundleUtils: - :path: Common/RuuviBundleUtils/RuuviBundleUtils.podspec RuuviCloud: :path: Packages/RuuviCloud/RuuviCloud.podspec RuuviContext: @@ -855,7 +846,6 @@ SPEC CHECKSUMS: Realm: d4f810e161fa2c2c589b9860b6eb09238deacd73 RealmSwift: cef9946f09f2333a8f2ac8bac4f8de52fb9f5ac3 RuuviAnalytics: 1442f702d42ca8a7c4000394a534cd54bf5fd67a - RuuviBundleUtils: b143f4bb7bbb9b173527bec8836b3a507b6ca8f2 RuuviCloud: f488ad2791dea1cee92b648e96e3eca20f5465b6 RuuviContext: 3c3a03e1791189e57d35252cac2448b30cb5c8c4 RuuviCore: c42d46fd24adec33663aa61a7b73430b448a56e4 @@ -869,11 +859,11 @@ SPEC CHECKSUMS: RuuviMigration: e2d397eba79436eef6e8b982b1e188a5f6426a2e RuuviNotification: 4907402a0962abd2513dc511ade32ee6a05da6a1 RuuviNotifier: 2fdb2579b48c2ff5ad28ae5d651b01831e8b1b90 - RuuviOnboard: a17e7b9ded33af7c7f3c622444fcf3d5b8770ad1 + RuuviOnboard: c9c5556007c56b4491df3ad8e1ef9c3c57ebbd34 RuuviOntology: 174c688dc2083e7afe1d98d941c9db0fd6c7a063 RuuviPersistence: 0be00598293866c79a94636247e9365b2a2e3da5 RuuviPool: 663c3b125b2f865b0e5174abcd88c148c4c7ed6b - RuuviPresenters: 9e7ab27726604db02b29bf8c8a8289bbc624e303 + RuuviPresenters: b883212d32138c00dd61680547ce33dcac922b37 RuuviReactor: 5fd4dcff29ba553c36e26b0a0334dc5007d26fcd RuuviRepository: 2a98401ff527bc19ec488281e5bbe5a820c405ca RuuviService: 87d15c3b9758850079b91a7823f4de41e7b90cac @@ -884,6 +874,6 @@ SPEC CHECKSUMS: Swinject: 893c9a543000ac2f10ee4cbaf0933c6992c935d5 ZIPFoundation: b1f0de4eed33e74a676f76e12559ab6b75990197 -PODFILE CHECKSUM: 217f39abb07c737f33db5c642a3168eeeaee16d7 +PODFILE CHECKSUM: 678248a5443826612f8c9f943ea15daf54e24fe5 COCOAPODS: 1.12.1 diff --git a/project.yml b/project.yml new file mode 100644 index 000000000..e62d23a76 --- /dev/null +++ b/project.yml @@ -0,0 +1,240 @@ +APP_NAME: &APP_NAME Ruuvi Station +DEVELOPMENT_TEAM: &DEVELOPMENT_TEAM 4MUYJ4YYH4 +BUNDLE_ID_PREFIX: &BUNDLE_ID_PREFIX com.ruuvi + +attributes: + ORGANIZATIONNAME: Ruuvi Innovations Oy + +settings: + base: + CURRENT_PROJECT_VERSION: 420 + MARKETING_VERSION: "2.5.0" + DEVELOPMENT_TEAM: *DEVELOPMENT_TEAM + +name: *APP_NAME + +options: + bundleIdPrefix: *BUNDLE_ID_PREFIX + developmentLanguage: en + deploymentTarget: + iOS: 14.0 + +packages: + BTKit: + url: https://github.com/ruuvi/BTKit + from: 0.4.3 + Charts: + url: https://github.com/danielgindi/Charts + from: 4.1.0 + LightRoute: + url: https://github.com/rinat-enikeev/LightRoute + from: 2.2.2 + Swinject: + url: https://github.com/Swinject/Swinject + from: 2.8.3 + Firebase: + url: https://github.com/firebase/firebase-ios-sdk + from: 10.7.0 + RangeSeekSlider: + url: https://github.com/rinat-enikeev/RangeSeekSlider + from: 1.8.2 + GestureInstructions: + url: https://github.com/rinat-enikeev/GestureInstructions + from: 0.0.2 + RuuviAnalytics: + path: Packages/RuuviAnalytics + RuuviCloud: + path: Packages/RuuviCloud + RuuviContext: + path: Packages/RuuviContext + RuuviCore: + path: Packages/RuuviCore + RuuviDaemon: + path: Packages/RuuviDaemon + RuuviDFU: + path: Packages/RuuviDFU + RuuviLocation: + path: Packages/RuuviLocation + RuuviLocal: + path: Packages/RuuviLocal + RuuviMigration: + path: Packages/RuuviMigration + RuuviNotification: + path: Packages/RuuviNotification + RuuviNotifier: + path: Packages/RuuviNotifier + RuuviOntology: + path: Packages/RuuviOntology + RuuviPersistence: + path: Packages/RuuviPersistence + RuuviPool: + path: Packages/RuuviPool + RuuviReactor: + path: Packages/RuuviReactor + RuuviRepository: + path: Packages/RuuviRepository + RuuviService: + path: Packages/RuuviService + RuuviStorage: + path: Packages/RuuviStorage + RuuviUser: + path: Packages/RuuviUser + RuuviVirtual: + path: Packages/RuuviVirtual + RuuviPresenters: + path: Common/RuuviPresenters + RuuviDiscover: + path: Modules/RuuviDiscover + RuuviLocationPicker: + path: Modules/RuuviLocationPicker + RuuviOnboard: + path: Modules/RuuviOnboard + +targets: + station: + type: application + platform: iOS + sources: + - path: station + dependencies: + - package: BTKit + - package: Charts + - package: LightRoute + - package: Swinject + - package: RangeSeekSlider + - package: GestureInstructions + - package: Firebase + product: FirebaseMessaging + - package: Firebase + product: FirebaseRemoteConfig + - package: RuuviAnalytics + - package: RuuviAnalytics + product: RuuviAnalyticsImpl + - package: RuuviCloud + - package: RuuviCloud + product: RuuviCloudPure + - package: RuuviContext + - package: RuuviContext + product: RuuviContextRealm + - package: RuuviContext + product: RuuviContextSQLite + - package: RuuviCore + - package: RuuviCore + product: RuuviCoreImage + - package: RuuviCore + product: RuuviCorePN + - package: RuuviCore + product: RuuviCorePermission + - package: RuuviCore + product: RuuviCoreLocation + - package: RuuviDaemon + - package: RuuviDaemon + product: RuuviDaemonBackground + - package: RuuviDaemon + product: RuuviDaemonVirtualTag + - package: RuuviDaemon + product: RuuviDaemonRuuviTag + - package: RuuviDaemon + product: RuuviDaemonCloudSync + - package: RuuviDFU + - package: RuuviDFU + product: RuuviDFUImpl + - package: RuuviLocation + - package: RuuviLocation + product: RuuviLocationService + - package: RuuviLocal + - package: RuuviLocal + product: RuuviLocalUserDefaults + - package: RuuviMigration + - package: RuuviMigration + product: RuuviMigrationImpl + - package: RuuviNotification + - package: RuuviNotification + product: RuuviNotificationLocal + - package: RuuviNotifier + - package: RuuviNotifier + product: RuuviNotifierImpl + - package: RuuviOntology + - package: RuuviPersistence + - package: RuuviPersistence + product: RuuviPersistenceRealm + - package: RuuviPersistence + product: RuuviPersistenceSQLite + - package: RuuviPool + - package: RuuviPool + product: RuuviPoolCoordinator + - package: RuuviReactor + - package: RuuviReactor + product: RuuviReactorImpl + - package: RuuviRepository + - package: RuuviRepository + product: RuuviRepositoryCoordinator + - package: RuuviService + - package: RuuviService + product: RuuviServiceFactory + - package: RuuviService + product: RuuviServiceMeasurement + - package: RuuviService + product: RuuviServiceOwnership + - package: RuuviService + product: RuuviServiceExport + - package: RuuviService + product: RuuviServiceGATT + - package: RuuviStorage + - package: RuuviStorage + product: RuuviStorageCoordinator + - package: RuuviUser + - package: RuuviUser + product: RuuviUserCoordinator + - package: RuuviVirtual + - package: RuuviVirtual + product: RuuviVirtualOWM + - package: RuuviVirtual + product: RuuviVirtualPersistence + - package: RuuviVirtual + product: RuuviVirtualReactor + - package: RuuviVirtual + product: RuuviVirtualRepository + - package: RuuviVirtual + product: RuuviVirtualStorage + - package: RuuviVirtual + product: RuuviVirtualService + - package: RuuviPresenters + - package: RuuviDiscover + - package: RuuviLocationPicker + - package: RuuviOnboard + info: + path: station/Resources/Plists/Info.plist + properties: + CFBundleDisplayName: Ruuvi Station + CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString: "$(MARKETING_VERSION)" + CFBundleVersion: $(CURRENT_PROJECT_VERSION) + UISupportedInterfaceOrientations: [UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight, UIInterfaceOrientationPortrait] + UILaunchStoryboardName: LaunchScreen + BGTaskSchedulerPermittedIdentifiers: [com.ruuvi.station.BackgroundTaskServiceiOS13.webTagRefresh, com.ruuvi.station.BackgroundProcessServiceiOS13.dataPruning] + FirebaseMessagingAutoInitEnabled: false + LSApplicationQueriesSchemes: [https, http, mailto] + LSRequiresIPhoneOS: true + NFCReaderUsageDescription: Allows user to claim a RuuviTag using NFC when the user has physical access to the sensor + NSBluetoothAlwaysUsageDescription: The app uses Bluetooth LE to read data from Ruuvi Sensors + NSBluetoothPeripheralUsageDescription: The app uses Bluetooth LE to read data from RuuviTag sensors. + NSCameraUsageDescription: Ruuvi Station needs to access your camera in order to be able to capture photos and use them as sensor background. + NSLocationAlwaysAndWhenInUseUsageDescription: Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. + NSLocationAlwaysUsageDescription: Ruuvi Station needs to access your location while being in background in order to pull data for Virtual Sensors for your current location and display alerts. + NSLocationUsageDescription: Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. + NSLocationWhenInUseUsageDescription: Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. + NSPhotoLibraryUsageDescription: Ruuvi Station needs to access your camera roll to enable selecting the background for the sensor. + NSUserActivityTypes: [RuuviTagSelectionIntent] + UIAppFonts: [Oswald-Bold.ttf,Oswald-ExtraLight.ttf,Muli-Regular.ttf,Muli-Bold.ttf,Muli-SemiBoldItalic.ttf,Muli-ExtraBold.ttf,Montserrat-Bold.ttf,Montserrat-Regular.ttf,Montserrat-ExtraBold.ttf] + UIBackgroundModes: [bluetooth-central, processing, remote-notification] + UIRequiredDeviceCapabilities: [armv7] + UIRequiresFullScreen: true + UIStatusBarStyle: UIStatusBarStyleLightContent + UISupportedInterfaceOrientations~ipad: [UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight,UIInterfaceOrientationPortrait, UIInterfaceOrientationPortraitUpsideDown] + UIViewControllerBasedStatusBarAppearance: true + settings: + base: + TARGETED_DEVICE_FAMILY: 1,2 + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true + CODE_SIGN_ENTITLEMENTS: station/station.entitlements \ No newline at end of file diff --git a/station.xcodeproj/project.pbxproj b/station.xcodeproj/project.pbxproj index f04ee2940..cf07bfbff 100644 --- a/station.xcodeproj/project.pbxproj +++ b/station.xcodeproj/project.pbxproj @@ -4895,7 +4895,7 @@ mainGroup = 64333D1C20B0C45900CDF4B6; packageReferences = ( 0EE36EAD269DC70E0021B746 /* XCRemoteSwiftPackageReference "swift-algorithms" */, - 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts" */, + 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts.git" */, ); productRefGroup = 64333D2620B0C45900CDF4B6 /* Products */; projectDirPath = ""; @@ -7130,7 +7130,7 @@ minimumVersion = 1.0.0; }; }; - 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts" */ = { + 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts.git" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/danielgindi/Charts.git"; requirement = { @@ -7153,12 +7153,12 @@ }; 0EE36EB3269DC7D90021B746 /* Charts */ = { isa = XCSwiftPackageProductDependency; - package = 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts" */; + package = 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts.git" */; productName = Charts; }; 0EE36EB5269DC7E40021B746 /* Charts */ = { isa = XCSwiftPackageProductDependency; - package = 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts" */; + package = 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts.git" */; productName = Charts; }; /* End XCSwiftPackageProductDependency section */ diff --git a/station/Classes/Application/AppDelegate.swift b/station/Classes/Application/AppDelegate.swift index 5cdaff68b..c5254467c 100644 --- a/station/Classes/Application/AppDelegate.swift +++ b/station/Classes/Application/AppDelegate.swift @@ -1,5 +1,6 @@ import UIKit -import Firebase +import FirebaseCore +import FirebaseMessaging #if canImport(FLEX) import FLEX #endif diff --git a/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift b/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift index 231c51efc..c55c82521 100644 --- a/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift +++ b/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift @@ -1,6 +1,7 @@ import Foundation import RuuviContext import RuuviStorage +import UIKit final class AboutPresenter: AboutModuleInput { weak var view: AboutViewInput! diff --git a/station/Classes/Presentation/Modules/About/Router/AboutRouter.swift b/station/Classes/Presentation/Modules/About/Router/AboutRouter.swift index f455a5cfd..c1b0038e3 100644 --- a/station/Classes/Presentation/Modules/About/Router/AboutRouter.swift +++ b/station/Classes/Presentation/Modules/About/Router/AboutRouter.swift @@ -1,4 +1,6 @@ +import Foundation import LightRoute +import UIKit class AboutRouter: AboutRouterInput { weak var transitionHandler: TransitionHandler! diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift index 817de5302..02f83e92c 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift @@ -13,6 +13,7 @@ import RuuviNotifier import RuuviPresenters import RuuviDaemon import RuuviCore +import UIKit class CardsPresenter { weak var view: CardsViewInput? diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift index 54738d57f..1e3660fd4 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift @@ -1,6 +1,7 @@ import Foundation import BTKit import RuuviOntology +import UIKit protocol CardsViewInput: ViewInput { var viewModels: [CardsViewModel] { get set } diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift index c849207dd..44b276435 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift @@ -5,6 +5,9 @@ import Future import BTKit import RuuviPool import RuuviService +#if canImport(RuuviServiceOwnership) +import RuuviServiceOwnership +#endif import RuuviUser class DashboardInteractor { diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift index ad626c0a1..8af7da595 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift @@ -18,6 +18,7 @@ import RuuviUser import WidgetKit import CoreBluetooth import Future +import UIKit class DashboardPresenter: DashboardModuleInput { weak var view: DashboardViewInput? diff --git a/station/Classes/Presentation/Modules/Kaltiot/Assembly/Table/KaltiotTableInitializer.swift b/station/Classes/Presentation/Modules/Kaltiot/Assembly/Table/KaltiotTableInitializer.swift deleted file mode 100644 index caef6187c..000000000 --- a/station/Classes/Presentation/Modules/Kaltiot/Assembly/Table/KaltiotTableInitializer.swift +++ /dev/null @@ -1,10 +0,0 @@ -import UIKit - -class KaltiotPickerTableInitializer: NSObject { - @IBOutlet weak var viewController: KaltiotPickerTableViewController! - - override func awakeFromNib() { - super.awakeFromNib() - KaltiotPickerTableConfigurator().configure(view: viewController) - } -} diff --git a/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift b/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift index f190968a3..791619ffe 100644 --- a/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift +++ b/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift @@ -6,6 +6,7 @@ import RuuviCloud import RuuviCore import Future import RuuviLocal +import UIKit #if canImport(WidgetKit) import WidgetKit diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouter.swift index 688c29c29..f558deb24 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouter.swift @@ -1,4 +1,5 @@ import LightRoute +import UIKit class AppearanceSettingsRouter: AppearanceSettingsRouterInput { weak var transitionHandler: UIViewController? diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouter.swift index 7676cfb00..93a69341a 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouter.swift @@ -1,4 +1,5 @@ import LightRoute +import UIKit class NotificationsSettingsRouter: NotificationsSettingsRouterInput { weak var transitionHandler: UIViewController? diff --git a/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift b/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift index 822076236..94d96a99e 100644 --- a/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift +++ b/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift @@ -8,6 +8,7 @@ import RuuviDaemon import FirebaseMessaging import RuuviLocal import WidgetKit +import UIKit class SignInPresenter: NSObject { enum State { diff --git a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift index df4daffcc..9ce720982 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift @@ -8,6 +8,9 @@ import RuuviStorage import RuuviReactor import RuuviLocal import RuuviService +#if canImport(RuuviServiceOwnership) +import RuuviServiceOwnership +#endif import RuuviUser import RuuviCore import RuuviPresenters diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Router/SensorForceClaimRouter.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Router/SensorForceClaimRouter.swift index 6e71ebc32..97e23fc30 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Router/SensorForceClaimRouter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Router/SensorForceClaimRouter.swift @@ -1,4 +1,5 @@ import LightRoute +import UIKit class SensorForceClaimRouter: SensorForceClaimRouterInput { weak var transitionHandler: UIViewController? diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift index 2172cfd55..7587af092 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift @@ -1,6 +1,9 @@ import UIKit import RuuviOntology import RuuviService +#if canImport(RuuviServiceMeasurement) +import RuuviServiceMeasurement +#endif class OffsetCorrectionAppleViewController: UIViewController { var output: OffsetCorrectionViewOutput! diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift index e95d93098..b32b129fc 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift @@ -1,5 +1,6 @@ import LightRoute import RuuviOntology +import UIKit final class OwnerRouter: OwnerRouterInput { weak var transitionHandler: UIViewController! diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Router/SensorRemovalRouter.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Router/SensorRemovalRouter.swift index fde9e99b2..fe5af014f 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Router/SensorRemovalRouter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Router/SensorRemovalRouter.swift @@ -1,4 +1,5 @@ import LightRoute +import UIKit class SensorRemovalRouter: SensorRemovalRouterInput { weak var transitionHandler: UIViewController? diff --git a/station/Classes/Presentation/Modules/TagsManager/Router/UserApiConfigRouter.swift b/station/Classes/Presentation/Modules/TagsManager/Router/UserApiConfigRouter.swift deleted file mode 100644 index c6b24efb8..000000000 --- a/station/Classes/Presentation/Modules/TagsManager/Router/UserApiConfigRouter.swift +++ /dev/null @@ -1,19 +0,0 @@ -import UIKit - -class TagsManagerRouter: TagsManagerRouterInput { - weak var transitionHandler: UIViewController! - - func dismiss(completion: (() -> Void)?) { - transitionHandler.dismiss(animated: true, completion: completion) - } - - func showAlert(_ viewModel: UserApiConfigAlertViewModel) { - let alertController = UIAlertController(title: viewModel.title, - message: viewModel.message, - preferredStyle: viewModel.style) - viewModel.actions.forEach({ alertController.addAction($0) }) - transitionHandler.present(alertController, - animated: true, - completion: nil) - } -} diff --git a/station/Classes/Routers/DiscoverRouter.swift b/station/Classes/Routers/DiscoverRouter.swift index 6cb5ba781..609206040 100644 --- a/station/Classes/Routers/DiscoverRouter.swift +++ b/station/Classes/Routers/DiscoverRouter.swift @@ -3,6 +3,7 @@ import RuuviDiscover import RuuviOntology import BTKit import RuuviLocationPicker +import UIKit protocol DiscoverRouterDelegate: AnyObject { func discoverRouterWantsClose(_ router: DiscoverRouter) diff --git a/station/Resources/Plists/Info.plist b/station/Resources/Plists/Info.plist index 14b727e4b..46055a497 100644 --- a/station/Resources/Plists/Info.plist +++ b/station/Resources/Plists/Info.plist @@ -20,11 +20,11 @@ CFBundleName $(PRODUCT_NAME) CFBundlePackageType - APPL + $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - 420 + $(CURRENT_PROJECT_VERSION) FirebaseMessagingAutoInitEnabled LSApplicationQueriesSchemes diff --git a/station/Resources/Plists/Networking.plist b/station/Resources/Plists/Networking.plist index 6f70aedf4..42fcbc762 100644 --- a/station/Resources/Plists/Networking.plist +++ b/station/Resources/Plists/Networking.plist @@ -6,5 +6,7 @@ { set your API key here } RuuviCloudURL https://network.ruuvi.com + RuuviCloudURLDev + https://testnet.ruuvi.com From fa5c4529a56e4181b25f2f69f1cb93453c6c8590 Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Tue, 21 Nov 2023 22:30:57 +0100 Subject: [PATCH 04/84] fix: Trigger sync call when app is launched from killed state #1718 --- .../RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift index fce592499..f4a528451 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift @@ -23,6 +23,9 @@ class RuuviDaemonCloudSyncWorker: RuuviDaemonWorker, RuuviDaemonCloudSync { start { [weak self] in guard let sSelf = self else { return } sSelf.pullTimer?.invalidate() + // Call the refreshImmediately method to execute it right away when + // thread is started. + sSelf.refreshImmediately() let timer = Timer.scheduledTimer( timeInterval: TimeInterval(sSelf.localSettings.networkPullIntervalSeconds), target: sSelf, From 236213d1bca93c942f7cd2fdd857a2eb8e4f10b8 Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Wed, 22 Nov 2023 19:05:42 +0100 Subject: [PATCH 05/84] fix: Remove extra call when app moves to foreground #1718 --- .../Classes/Application/AppState/Impl/AppStateServiceImpl.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift b/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift index bde2985df..e9537f0c3 100644 --- a/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift +++ b/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift @@ -93,7 +93,6 @@ class AppStateServiceImpl: AppStateService { } if ruuviUser.isAuthorized { cloudSyncDaemon.start() - cloudSyncDaemon.refreshImmediately() } propertiesDaemon.start() pullWebDaemon.start() From 93203fdc2d0d3213ac16444a68eea74dff416408 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Thu, 23 Nov 2023 22:34:27 +0200 Subject: [PATCH 06/84] Modify project.yml for xcodegened project with Frameworks (#1717) Migration: migrate from cocoapods. What: created project.yml and refactored code to be able to build from frameworks Steps: > brew upgrade xcodegen > xcodegen > xed Ruuvi\ Station.xcodeproj/ > Build and Run --- Common/RuuviLocalization/Info.plist | 22 ++ Common/RuuviLocalization/target.yml | 5 + Common/RuuviPresenters/Info.plist | 22 ++ .../Util/RuuviBundleUtils.swift | 13 +- Common/RuuviPresenters/target.yml | 5 + Modules/RuuviDiscover/Info.plist | 22 ++ .../RuuviDiscover/Util/RuuviBundleUtils.swift | 13 +- Modules/RuuviDiscover/target.yml | 16 + Modules/RuuviLocationPicker/Info.plist | 22 ++ .../Util/RuuviBundleUtils.swift | 13 +- Modules/RuuviLocationPicker/target.yml | 12 + Modules/RuuviOnboard/Helpers/Extension.swift | 19 -- Modules/RuuviOnboard/Info.plist | 22 ++ .../Pages/Util/RuuviBundleUtils.swift | 13 +- Modules/RuuviOnboard/target.yml | 7 + Packages/RuuviAnalytics/Info.plist | 22 ++ Packages/RuuviAnalytics/target.yml | 17 + Packages/RuuviCloud/Info.plist | 22 ++ .../RuuviCloudFactoryPure.swift | 3 - .../RuuviCloudPure/RuuviCloudPure.swift | 3 - Packages/RuuviCloud/target.yml | 12 + Packages/RuuviContext/Info.plist | 22 ++ Packages/RuuviContext/target.yml | 11 + Packages/RuuviCore/Info.plist | 22 ++ Packages/RuuviCore/target.yml | 7 + Packages/RuuviDFU/Info.plist | 22 ++ Packages/RuuviDFU/target.yml | 7 + Packages/RuuviDaemon/Info.plist | 22 ++ .../BackgroundProcessServiceiOS13.swift | 3 - .../BackgroundTaskServiceiOS13.swift | 3 - .../PullWeb/PullWebDaemonOperations.swift | 3 - .../WebTag/VirtualTagDaemonImpl.swift | 3 - Packages/RuuviDaemon/target.yml | 19 ++ Packages/RuuviLocal/Info.plist | 22 ++ Packages/RuuviLocal/target.yml | 8 + Packages/RuuviLocation/Info.plist | 22 ++ Packages/RuuviLocation/target.yml | 8 + Packages/RuuviMigration/Info.plist | 22 ++ Packages/RuuviMigration/target.yml | 18 + Packages/RuuviNotification/Info.plist | 22 ++ Packages/RuuviNotification/target.yml | 13 + Packages/RuuviNotifier/Info.plist | 22 ++ Packages/RuuviNotifier/target.yml | 11 + Packages/RuuviOntology/Info.plist | 22 ++ Packages/RuuviOntology/target.yml | 12 + Packages/RuuviPersistence/Info.plist | 22 ++ Packages/RuuviPersistence/target.yml | 14 + Packages/RuuviPool/Info.plist | 22 ++ Packages/RuuviPool/target.yml | 10 + Packages/RuuviReactor/Info.plist | 22 ++ Packages/RuuviReactor/target.yml | 15 + Packages/RuuviRepository/Info.plist | 22 ++ Packages/RuuviRepository/target.yml | 10 + Packages/RuuviService/Info.plist | 22 ++ .../RuuviServiceFactory.swift | 30 -- Packages/RuuviService/target.yml | 16 + Packages/RuuviStorage/Info.plist | 22 ++ Packages/RuuviStorage/target.yml | 9 + Packages/RuuviUser/Info.plist | 22 ++ Packages/RuuviUser/target.yml | 7 + Packages/RuuviVirtual/Info.plist | 22 ++ .../VirtualPersistenceRealm.swift | 3 - .../VirtualTagLastRecordSubjectCombine.swift | 3 - .../Combine/VirtualTagSubjectCombine.swift | 3 - .../VirtualProviderServiceImpl.swift | 3 - Packages/RuuviVirtual/target.yml | 16 + macOS.xcodeproj/project.pbxproj | 4 +- project.yml | 314 ++++++++++-------- project_spm.yml | 240 +++++++++++++ 69 files changed, 1282 insertions(+), 242 deletions(-) create mode 100644 Common/RuuviLocalization/Info.plist create mode 100644 Common/RuuviLocalization/target.yml create mode 100644 Common/RuuviPresenters/Info.plist create mode 100644 Common/RuuviPresenters/target.yml create mode 100644 Modules/RuuviDiscover/Info.plist create mode 100644 Modules/RuuviDiscover/target.yml create mode 100644 Modules/RuuviLocationPicker/Info.plist create mode 100644 Modules/RuuviLocationPicker/target.yml delete mode 100644 Modules/RuuviOnboard/Helpers/Extension.swift create mode 100644 Modules/RuuviOnboard/Info.plist create mode 100644 Modules/RuuviOnboard/target.yml create mode 100644 Packages/RuuviAnalytics/Info.plist create mode 100644 Packages/RuuviAnalytics/target.yml create mode 100644 Packages/RuuviCloud/Info.plist create mode 100644 Packages/RuuviCloud/target.yml create mode 100644 Packages/RuuviContext/Info.plist create mode 100644 Packages/RuuviContext/target.yml create mode 100644 Packages/RuuviCore/Info.plist create mode 100644 Packages/RuuviCore/target.yml create mode 100644 Packages/RuuviDFU/Info.plist create mode 100644 Packages/RuuviDFU/target.yml create mode 100644 Packages/RuuviDaemon/Info.plist create mode 100644 Packages/RuuviDaemon/target.yml create mode 100644 Packages/RuuviLocal/Info.plist create mode 100644 Packages/RuuviLocal/target.yml create mode 100644 Packages/RuuviLocation/Info.plist create mode 100644 Packages/RuuviLocation/target.yml create mode 100644 Packages/RuuviMigration/Info.plist create mode 100644 Packages/RuuviMigration/target.yml create mode 100644 Packages/RuuviNotification/Info.plist create mode 100644 Packages/RuuviNotification/target.yml create mode 100644 Packages/RuuviNotifier/Info.plist create mode 100644 Packages/RuuviNotifier/target.yml create mode 100644 Packages/RuuviOntology/Info.plist create mode 100644 Packages/RuuviOntology/target.yml create mode 100644 Packages/RuuviPersistence/Info.plist create mode 100644 Packages/RuuviPersistence/target.yml create mode 100644 Packages/RuuviPool/Info.plist create mode 100644 Packages/RuuviPool/target.yml create mode 100644 Packages/RuuviReactor/Info.plist create mode 100644 Packages/RuuviReactor/target.yml create mode 100644 Packages/RuuviRepository/Info.plist create mode 100644 Packages/RuuviRepository/target.yml create mode 100644 Packages/RuuviService/Info.plist create mode 100644 Packages/RuuviService/target.yml create mode 100644 Packages/RuuviStorage/Info.plist create mode 100644 Packages/RuuviStorage/target.yml create mode 100644 Packages/RuuviUser/Info.plist create mode 100644 Packages/RuuviUser/target.yml create mode 100644 Packages/RuuviVirtual/Info.plist create mode 100644 Packages/RuuviVirtual/target.yml create mode 100644 project_spm.yml diff --git a/Common/RuuviLocalization/Info.plist b/Common/RuuviLocalization/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Common/RuuviLocalization/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Common/RuuviLocalization/target.yml b/Common/RuuviLocalization/target.yml new file mode 100644 index 000000000..4ca8e70b3 --- /dev/null +++ b/Common/RuuviLocalization/target.yml @@ -0,0 +1,5 @@ +--- +targets: + RuuviLocalization: + templates: + - CommonFramework diff --git a/Common/RuuviPresenters/Info.plist b/Common/RuuviPresenters/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Common/RuuviPresenters/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift index 3f6f7e798..be1ad1013 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift @@ -3,10 +3,15 @@ import UIKit extension Bundle { public static func pod(_ clazz: AnyClass) -> Bundle { - if let module = NSStringFromClass(clazz).components(separatedBy: ".").first, - let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), - let bundle = Bundle(url: bundleURL) { - return bundle + if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { + if let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), let bundle = Bundle(url: bundleURL) { + return bundle + } else if let bundleURL = Bundle(for: clazz).resourceURL, let bundle = Bundle(url: bundleURL) { + return bundle + } else { + assertionFailure() + return Bundle.main + } } else { assertionFailure() return Bundle.main diff --git a/Common/RuuviPresenters/target.yml b/Common/RuuviPresenters/target.yml new file mode 100644 index 000000000..c4afef536 --- /dev/null +++ b/Common/RuuviPresenters/target.yml @@ -0,0 +1,5 @@ +--- +targets: + RuuviPresenters: + templates: + - CommonFramework diff --git a/Modules/RuuviDiscover/Info.plist b/Modules/RuuviDiscover/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Modules/RuuviDiscover/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift index 3f6f7e798..be1ad1013 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift @@ -3,10 +3,15 @@ import UIKit extension Bundle { public static func pod(_ clazz: AnyClass) -> Bundle { - if let module = NSStringFromClass(clazz).components(separatedBy: ".").first, - let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), - let bundle = Bundle(url: bundleURL) { - return bundle + if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { + if let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), let bundle = Bundle(url: bundleURL) { + return bundle + } else if let bundleURL = Bundle(for: clazz).resourceURL, let bundle = Bundle(url: bundleURL) { + return bundle + } else { + assertionFailure() + return Bundle.main + } } else { assertionFailure() return Bundle.main diff --git a/Modules/RuuviDiscover/target.yml b/Modules/RuuviDiscover/target.yml new file mode 100644 index 000000000..f27df5352 --- /dev/null +++ b/Modules/RuuviDiscover/target.yml @@ -0,0 +1,16 @@ +--- +targets: + RuuviDiscover: + templates: + - Module + dependencies: + - package: BTKit + - package: Future + - target: RuuviOntology + - target: RuuviContext + - target: RuuviReactor + - target: RuuviLocal + - target: RuuviService + - target: RuuviVirtual + - target: RuuviPresenters + - target: RuuviLocalization diff --git a/Modules/RuuviLocationPicker/Info.plist b/Modules/RuuviLocationPicker/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Modules/RuuviLocationPicker/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Util/RuuviBundleUtils.swift b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Util/RuuviBundleUtils.swift index 3f6f7e798..be1ad1013 100644 --- a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Util/RuuviBundleUtils.swift +++ b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Util/RuuviBundleUtils.swift @@ -3,10 +3,15 @@ import UIKit extension Bundle { public static func pod(_ clazz: AnyClass) -> Bundle { - if let module = NSStringFromClass(clazz).components(separatedBy: ".").first, - let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), - let bundle = Bundle(url: bundleURL) { - return bundle + if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { + if let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), let bundle = Bundle(url: bundleURL) { + return bundle + } else if let bundleURL = Bundle(for: clazz).resourceURL, let bundle = Bundle(url: bundleURL) { + return bundle + } else { + assertionFailure() + return Bundle.main + } } else { assertionFailure() return Bundle.main diff --git a/Modules/RuuviLocationPicker/target.yml b/Modules/RuuviLocationPicker/target.yml new file mode 100644 index 000000000..7b7afe921 --- /dev/null +++ b/Modules/RuuviLocationPicker/target.yml @@ -0,0 +1,12 @@ +--- +targets: + RuuviLocationPicker: + templates: + - Module + dependencies: + - package: Future + - target: RuuviOntology + - target: RuuviPresenters + - target: RuuviLocalization + - target: RuuviCore + - target: RuuviLocation diff --git a/Modules/RuuviOnboard/Helpers/Extension.swift b/Modules/RuuviOnboard/Helpers/Extension.swift deleted file mode 100644 index a084387b7..000000000 --- a/Modules/RuuviOnboard/Helpers/Extension.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Foundation -import UIKit - -public extension UIAlertController { - func setMessageAlignment(_ alignment: NSTextAlignment) { - let paragraphStyle = NSParagraphStyle.default.mutableCopy() as? NSMutableParagraphStyle - paragraphStyle?.alignment = alignment - - let messageText = NSMutableAttributedString( - string: self.message ?? "", - attributes: [ - NSAttributedString.Key.paragraphStyle: paragraphStyle, - NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13), - NSAttributedString.Key.foregroundColor: UIColor.label - ] - ) - self.setValue(messageText, forKey: "attributedMessage") - } -} diff --git a/Modules/RuuviOnboard/Info.plist b/Modules/RuuviOnboard/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Modules/RuuviOnboard/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift index 3f6f7e798..be1ad1013 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift @@ -3,10 +3,15 @@ import UIKit extension Bundle { public static func pod(_ clazz: AnyClass) -> Bundle { - if let module = NSStringFromClass(clazz).components(separatedBy: ".").first, - let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), - let bundle = Bundle(url: bundleURL) { - return bundle + if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { + if let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), let bundle = Bundle(url: bundleURL) { + return bundle + } else if let bundleURL = Bundle(for: clazz).resourceURL, let bundle = Bundle(url: bundleURL) { + return bundle + } else { + assertionFailure() + return Bundle.main + } } else { assertionFailure() return Bundle.main diff --git a/Modules/RuuviOnboard/target.yml b/Modules/RuuviOnboard/target.yml new file mode 100644 index 000000000..c5f993e98 --- /dev/null +++ b/Modules/RuuviOnboard/target.yml @@ -0,0 +1,7 @@ +--- +targets: + RuuviOnboard: + templates: + - Module + dependencies: + - target: RuuviUser diff --git a/Packages/RuuviAnalytics/Info.plist b/Packages/RuuviAnalytics/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviAnalytics/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviAnalytics/target.yml b/Packages/RuuviAnalytics/target.yml new file mode 100644 index 000000000..a9773bfb5 --- /dev/null +++ b/Packages/RuuviAnalytics/target.yml @@ -0,0 +1,17 @@ +--- +targets: + RuuviAnalytics: + name: RuuviAnalytics + templates: + - Framework + dependencies: + - package: Humidity + - package: Future + - package: Firebase + product: FirebaseAnalytics + - target: RuuviStorage + - target: RuuviLocal + - target: RuuviOntology + - target: RuuviVirtual + - target: RuuviUser + - target: RuuviService diff --git a/Packages/RuuviCloud/Info.plist b/Packages/RuuviCloud/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviCloud/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift index b2076ab51..81d876f6d 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift @@ -2,9 +2,6 @@ import Foundation import RuuviPool import RuuviUser import RuuviCloud -#if canImport(RuuviCloudApi) -import RuuviCloudApi -#endif public final class RuuviCloudFactoryPure: RuuviCloudFactory { public init() {} diff --git a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift index 046e87bdc..8ca9ca436 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift @@ -6,9 +6,6 @@ import BTKit import RuuviUser import RuuviCloud import RuuviPool -#if canImport(RuuviCloudApi) -import RuuviCloudApi -#endif // swiftlint:disable:next type_body_length public final class RuuviCloudPure: RuuviCloud { diff --git a/Packages/RuuviCloud/target.yml b/Packages/RuuviCloud/target.yml new file mode 100644 index 000000000..6222401c9 --- /dev/null +++ b/Packages/RuuviCloud/target.yml @@ -0,0 +1,12 @@ +--- +targets: + RuuviCloud: + templates: + - Framework + dependencies: + - package: Humidity + - package: BTKit + - package: Future + - target: RuuviOntology + - target: RuuviUser + - target: RuuviPool diff --git a/Packages/RuuviContext/Info.plist b/Packages/RuuviContext/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviContext/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviContext/target.yml b/Packages/RuuviContext/target.yml new file mode 100644 index 000000000..88120dd40 --- /dev/null +++ b/Packages/RuuviContext/target.yml @@ -0,0 +1,11 @@ +--- +targets: + RuuviContext: + templates: + - Framework + dependencies: + - package: Realm + - package: Realm + product: RealmSwift + - package: GRDB + - target: RuuviOntology diff --git a/Packages/RuuviCore/Info.plist b/Packages/RuuviCore/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviCore/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviCore/target.yml b/Packages/RuuviCore/target.yml new file mode 100644 index 000000000..d8c385aea --- /dev/null +++ b/Packages/RuuviCore/target.yml @@ -0,0 +1,7 @@ +--- +targets: + RuuviCore: + templates: + - Framework + dependencies: + - package: Future diff --git a/Packages/RuuviDFU/Info.plist b/Packages/RuuviDFU/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviDFU/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviDFU/target.yml b/Packages/RuuviDFU/target.yml new file mode 100644 index 000000000..6398a54b6 --- /dev/null +++ b/Packages/RuuviDFU/target.yml @@ -0,0 +1,7 @@ +--- +targets: + RuuviDFU: + templates: + - Framework + dependencies: + - package: NordicDFU diff --git a/Packages/RuuviDaemon/Info.plist b/Packages/RuuviDaemon/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviDaemon/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift index 83d6e204e..36dfcb018 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift @@ -2,9 +2,6 @@ import Foundation import BackgroundTasks import Future import RuuviDaemon -#if canImport(RuuviDaemonOperation) -import RuuviDaemonOperation -#endif @available(iOS 13, *) public final class BackgroundProcessServiceiOS13: BackgroundProcessService { diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundTaskServiceiOS13.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundTaskServiceiOS13.swift index b2c54de33..6c98eb9c4 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundTaskServiceiOS13.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundTaskServiceiOS13.swift @@ -1,9 +1,6 @@ import Foundation import BackgroundTasks import RuuviDaemon -#if canImport(RuuviDaemonOperation) -import RuuviDaemonOperation -#endif @available(iOS 13, *) public final class BackgroundTaskServiceiOS13: BackgroundTaskService { diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/PullWeb/PullWebDaemonOperations.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/PullWeb/PullWebDaemonOperations.swift index b1a54e875..b880c460c 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/PullWeb/PullWebDaemonOperations.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/PullWeb/PullWebDaemonOperations.swift @@ -1,9 +1,6 @@ import Foundation import RuuviLocal import RuuviDaemon -#if canImport(RuuviDaemonOperation) -import RuuviDaemonOperation -#endif public final class PullWebDaemonOperations: RuuviDaemonWorker, PullWebDaemon { private let settings: RuuviLocalSettings diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/WebTag/VirtualTagDaemonImpl.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/WebTag/VirtualTagDaemonImpl.swift index ac1a35402..a9cd59c15 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/WebTag/VirtualTagDaemonImpl.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/WebTag/VirtualTagDaemonImpl.swift @@ -5,9 +5,6 @@ import RuuviOntology import RuuviVirtual import RuuviNotifier import RuuviDaemon -#if canImport(RuuviDaemonOperation) -import RuuviDaemonOperation -#endif public final class VirtualTagDaemonImpl: RuuviDaemonWorker, VirtualTagDaemon { private let virtualService: VirtualService diff --git a/Packages/RuuviDaemon/target.yml b/Packages/RuuviDaemon/target.yml new file mode 100644 index 000000000..9eef05048 --- /dev/null +++ b/Packages/RuuviDaemon/target.yml @@ -0,0 +1,19 @@ +--- +targets: + RuuviDaemon: + templates: + - Framework + dependencies: + - package: BTKit + - package: Future + - package: Humidity + - target: RuuviOntology + - target: RuuviLocal + - target: RuuviService + - target: RuuviVirtual + - target: RuuviStorage + - target: RuuviReactor + - target: RuuviPool + - target: RuuviPersistence + - target: RuuviNotifier + - target: RuuviNotification diff --git a/Packages/RuuviLocal/Info.plist b/Packages/RuuviLocal/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviLocal/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviLocal/target.yml b/Packages/RuuviLocal/target.yml new file mode 100644 index 000000000..e6b4115be --- /dev/null +++ b/Packages/RuuviLocal/target.yml @@ -0,0 +1,8 @@ +--- +targets: + RuuviLocal: + templates: + - Framework + dependencies: + - package: Future + - target: RuuviOntology diff --git a/Packages/RuuviLocation/Info.plist b/Packages/RuuviLocation/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviLocation/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviLocation/target.yml b/Packages/RuuviLocation/target.yml new file mode 100644 index 000000000..ffe473a34 --- /dev/null +++ b/Packages/RuuviLocation/target.yml @@ -0,0 +1,8 @@ +--- +targets: + RuuviLocation: + templates: + - Framework + dependencies: + - package: Future + - target: RuuviOntology diff --git a/Packages/RuuviMigration/Info.plist b/Packages/RuuviMigration/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviMigration/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviMigration/target.yml b/Packages/RuuviMigration/target.yml new file mode 100644 index 000000000..73dc72843 --- /dev/null +++ b/Packages/RuuviMigration/target.yml @@ -0,0 +1,18 @@ +--- +targets: + RuuviMigration: + templates: + - Framework + dependencies: + - package: Humidity + - package: Future + - package: Realm + - package: Realm + product: RealmSwift + - target: RuuviOntology + - target: RuuviLocal + - target: RuuviPool + - target: RuuviContext + - target: RuuviVirtual + - target: RuuviStorage + - target: RuuviService diff --git a/Packages/RuuviNotification/Info.plist b/Packages/RuuviNotification/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviNotification/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviNotification/target.yml b/Packages/RuuviNotification/target.yml new file mode 100644 index 000000000..22122bfea --- /dev/null +++ b/Packages/RuuviNotification/target.yml @@ -0,0 +1,13 @@ +--- +targets: + RuuviNotification: + templates: + - Framework + dependencies: + - package: Future + - package: Humidity + - target: RuuviOntology + - target: RuuviLocal + - target: RuuviVirtual + - target: RuuviStorage + - target: RuuviService diff --git a/Packages/RuuviNotifier/Info.plist b/Packages/RuuviNotifier/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviNotifier/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviNotifier/target.yml b/Packages/RuuviNotifier/target.yml new file mode 100644 index 000000000..9ce902537 --- /dev/null +++ b/Packages/RuuviNotifier/target.yml @@ -0,0 +1,11 @@ +--- +targets: + RuuviNotifier: + templates: + - Framework + dependencies: + - package: Humidity + - target: RuuviOntology + - target: RuuviNotification + - target: RuuviVirtual + - target: RuuviService diff --git a/Packages/RuuviOntology/Info.plist b/Packages/RuuviOntology/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviOntology/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviOntology/target.yml b/Packages/RuuviOntology/target.yml new file mode 100644 index 000000000..889ee6667 --- /dev/null +++ b/Packages/RuuviOntology/target.yml @@ -0,0 +1,12 @@ +--- +targets: + RuuviOntology: + templates: + - Framework + dependencies: + - package: Humidity + - package: BTKit + - package: Realm + - package: Realm + product: RealmSwift + - package: GRDB diff --git a/Packages/RuuviPersistence/Info.plist b/Packages/RuuviPersistence/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviPersistence/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviPersistence/target.yml b/Packages/RuuviPersistence/target.yml new file mode 100644 index 000000000..4ad07b62f --- /dev/null +++ b/Packages/RuuviPersistence/target.yml @@ -0,0 +1,14 @@ +--- +targets: + RuuviPersistence: + templates: + - Framework + dependencies: + - package: Humidity + - package: Future + - package: Realm + - package: Realm + product: RealmSwift + - package: GRDB + - target: RuuviOntology + - target: RuuviContext diff --git a/Packages/RuuviPool/Info.plist b/Packages/RuuviPool/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviPool/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviPool/target.yml b/Packages/RuuviPool/target.yml new file mode 100644 index 000000000..7c4cac248 --- /dev/null +++ b/Packages/RuuviPool/target.yml @@ -0,0 +1,10 @@ +--- +targets: + RuuviPool: + templates: + - Framework + dependencies: + - package: Future + - target: RuuviOntology + - target: RuuviPersistence + - target: RuuviLocal diff --git a/Packages/RuuviReactor/Info.plist b/Packages/RuuviReactor/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviReactor/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviReactor/target.yml b/Packages/RuuviReactor/target.yml new file mode 100644 index 000000000..6474428b9 --- /dev/null +++ b/Packages/RuuviReactor/target.yml @@ -0,0 +1,15 @@ +--- +targets: + RuuviReactor: + templates: + - Framework + dependencies: + - package: Humidity + - package: Future + - package: GRDB + - package: Realm + - package: Realm + product: RealmSwift + - target: RuuviOntology + - target: RuuviPersistence + - target: RuuviContext diff --git a/Packages/RuuviRepository/Info.plist b/Packages/RuuviRepository/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviRepository/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviRepository/target.yml b/Packages/RuuviRepository/target.yml new file mode 100644 index 000000000..748bef85e --- /dev/null +++ b/Packages/RuuviRepository/target.yml @@ -0,0 +1,10 @@ +--- +targets: + RuuviRepository: + templates: + - Framework + dependencies: + - package: Future + - target: RuuviOntology + - target: RuuviPool + - target: RuuviStorage diff --git a/Packages/RuuviService/Info.plist b/Packages/RuuviService/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviService/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift b/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift index 0a668f620..dd00ae027 100644 --- a/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift +++ b/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift @@ -7,36 +7,6 @@ import RuuviCore import RuuviRepository import RuuviService import RuuviUser -#if canImport(RuuviServiceAuth) -import RuuviServiceAuth -#endif -#if canImport(RuuviServiceCloudNotification) -import RuuviServiceCloudNotification -#endif -#if canImport(RuuviServiceAlert) -import RuuviServiceAlert -#endif -#if canImport(RuuviServiceCloudSync) -import RuuviServiceCloudSync -#endif -#if canImport(RuuviServiceOwnership) -import RuuviServiceOwnership -#endif -#if canImport(RuuviServiceAppSettings) -import RuuviServiceAppSettings -#endif -#if canImport(RuuviServiceSensorRecords) -import RuuviServiceSensorRecords -#endif -#if canImport(RuuviServiceSensorProperties) -import RuuviServiceSensorProperties -#endif -#if canImport(RuuviServiceOffsetCalibration) -import RuuviServiceOffsetCalibration -#endif -#if canImport(RuuviServiceCloudNotification) -import RuuviServiceCloudNotification -#endif public protocol RuuviServiceFactory { // swiftlint:disable:next function_parameter_count diff --git a/Packages/RuuviService/target.yml b/Packages/RuuviService/target.yml new file mode 100644 index 000000000..115a14c07 --- /dev/null +++ b/Packages/RuuviService/target.yml @@ -0,0 +1,16 @@ +--- +targets: + RuuviService: + templates: + - Framework + dependencies: + - package: Future + - package: Humidity + - package: BTKit + - target: RuuviOntology + - target: RuuviStorage + - target: RuuviCloud + - target: RuuviPool + - target: RuuviLocal + - target: RuuviRepository + - target: RuuviCore diff --git a/Packages/RuuviStorage/Info.plist b/Packages/RuuviStorage/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviStorage/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviStorage/target.yml b/Packages/RuuviStorage/target.yml new file mode 100644 index 000000000..c071f6683 --- /dev/null +++ b/Packages/RuuviStorage/target.yml @@ -0,0 +1,9 @@ +--- +targets: + RuuviStorage: + templates: + - Framework + dependencies: + - package: Future + - target: RuuviOntology + - target: RuuviPersistence diff --git a/Packages/RuuviUser/Info.plist b/Packages/RuuviUser/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviUser/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviUser/target.yml b/Packages/RuuviUser/target.yml new file mode 100644 index 000000000..bec36bf60 --- /dev/null +++ b/Packages/RuuviUser/target.yml @@ -0,0 +1,7 @@ +--- +targets: + RuuviUser: + templates: + - Framework + dependencies: + - package: KeychainAccess diff --git a/Packages/RuuviVirtual/Info.plist b/Packages/RuuviVirtual/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Packages/RuuviVirtual/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualPersistence/VirtualPersistenceRealm.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualPersistence/VirtualPersistenceRealm.swift index dbee56a90..12b658bfa 100644 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualPersistence/VirtualPersistenceRealm.swift +++ b/Packages/RuuviVirtual/Sources/RuuviVirtualPersistence/VirtualPersistenceRealm.swift @@ -5,9 +5,6 @@ import RuuviOntology import RuuviContext import RuuviLocal import RuuviVirtual -#if canImport(RuuviVirtualModel) -import RuuviVirtualModel -#endif // swiftlint:disable:next type_body_length public final class VirtualPersistenceRealm: VirtualPersistence { diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagLastRecordSubjectCombine.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagLastRecordSubjectCombine.swift index 3759a8a52..319431eba 100644 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagLastRecordSubjectCombine.swift +++ b/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagLastRecordSubjectCombine.swift @@ -3,9 +3,6 @@ import Combine import RuuviContext import RuuviOntology import RealmSwift -#if canImport(RuuviVirtualModel) -import RuuviVirtualModel -#endif final class VirtualTagLastRecordSubjectCombine { var isServing: Bool = false diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagSubjectCombine.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagSubjectCombine.swift index 43389f047..5c6834d45 100644 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagSubjectCombine.swift +++ b/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagSubjectCombine.swift @@ -3,9 +3,6 @@ import Combine import RealmSwift import RuuviOntology import RuuviContext -#if canImport(RuuviVirtualModel) -import RuuviVirtualModel -#endif class VirtualTagSubjectCombine { var realm: RealmContext diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualService/VirtualProviderServiceImpl.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualService/VirtualProviderServiceImpl.swift index f0fce8c50..c194c1e7e 100644 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualService/VirtualProviderServiceImpl.swift +++ b/Packages/RuuviVirtual/Sources/RuuviVirtualService/VirtualProviderServiceImpl.swift @@ -5,9 +5,6 @@ import RuuviVirtual import RuuviOntology import RuuviLocation import RuuviCore -#if canImport(RuuviVirtualOWM) -import RuuviVirtualOWM -#endif public final class VirtualProviderServiceImpl: VirtualProviderService { private let owmApi: OpenWeatherMapAPI diff --git a/Packages/RuuviVirtual/target.yml b/Packages/RuuviVirtual/target.yml new file mode 100644 index 000000000..4fcc035a4 --- /dev/null +++ b/Packages/RuuviVirtual/target.yml @@ -0,0 +1,16 @@ +--- +targets: + RuuviVirtual: + templates: + - Framework + dependencies: + - package: Humidity + - package: Future + - package: Realm + - package: Realm + product: RealmSwift + - target: RuuviOntology + - target: RuuviCore + - target: RuuviLocation + - target: RuuviContext + - target: RuuviLocal diff --git a/macOS.xcodeproj/project.pbxproj b/macOS.xcodeproj/project.pbxproj index 6d0152c68..5510adc5d 100755 --- a/macOS.xcodeproj/project.pbxproj +++ b/macOS.xcodeproj/project.pbxproj @@ -4536,10 +4536,10 @@ }; 0EBE42D2267CA889002888EC /* XCRemoteSwiftPackageReference "BTKit" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/rinat-enikeev/BTKit"; + repositoryURL = "https://github.com/ruuvi/BTKit"; requirement = { kind = upToNextMinorVersion; - minimumVersion = 0.3.0; + minimumVersion = 0.4.3; }; }; 0EE1125A267BC327008DA8D9 /* XCRemoteSwiftPackageReference "LightRoute" */ = { diff --git a/project.yml b/project.yml index e62d23a76..347bbb5f1 100644 --- a/project.yml +++ b/project.yml @@ -19,6 +19,98 @@ options: deploymentTarget: iOS: 14.0 +targetTemplates: + Framework: + name: "${target_name}" + type: framework + platform: iOS + info: + path: Packages/${target_name}/Info.plist + properties: + CFBundleShortVersionString: "$(MARKETING_VERSION)" + sources: + - path: Packages/${target_name} + excludes: + - target.yml + - Info.plist + - .swiftpm + - Package.swift + - Package.resolved + - .gitignore + - README.md + - "*.podspec" + - Tests + settings: + base: + DEVELOPMENT_TEAM: *DEVELOPMENT_TEAM + TARGETED_DEVICE_FAMILY: 1,2 + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true + PRODUCT_BUNDLE_IDENTIFIER: com.ruuvi.station.${target_name} + PRODUCT_NAME: "${target_name}" + CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString: "$(MARKETING_VERSION)" + CFBundleVersion: $(CURRENT_PROJECT_VERSION) + Module: + name: "${target_name}" + type: framework + platform: iOS + info: + path: Modules/${target_name}/Info.plist + properties: + CFBundleShortVersionString: "$(MARKETING_VERSION)" + sources: + - path: Modules/${target_name} + excludes: + - target.yml + - Info.plist + - .swiftpm + - Package.swift + - Package.resolved + - .gitignore + - README.md + - "*.podspec" + - Tests + settings: + base: + DEVELOPMENT_TEAM: *DEVELOPMENT_TEAM + TARGETED_DEVICE_FAMILY: 1,2 + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true + PRODUCT_BUNDLE_IDENTIFIER: com.ruuvi.station.${target_name} + PRODUCT_NAME: "${target_name}" + CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString: "$(MARKETING_VERSION)" + CFBundleVersion: $(CURRENT_PROJECT_VERSION) + CommonFramework: + name: "${target_name}" + type: framework + platform: iOS + info: + path: Common/${target_name}/Info.plist + properties: + CFBundleShortVersionString: "$(MARKETING_VERSION)" + sources: + - path: Common/${target_name} + excludes: + - target.yml + - Info.plist + - .swiftpm + - Package.swift + - Package.resolved + - .gitignore + - README.md + - "*.podspec" + - Tests + settings: + base: + DEVELOPMENT_TEAM: *DEVELOPMENT_TEAM + TARGETED_DEVICE_FAMILY: 1,2 + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true + PRODUCT_BUNDLE_IDENTIFIER: com.ruuvi.station.${target_name} + PRODUCT_NAME: "${target_name}" + CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString: "$(MARKETING_VERSION)" + CFBundleVersion: $(CURRENT_PROJECT_VERSION) + packages: BTKit: url: https://github.com/ruuvi/BTKit @@ -34,61 +126,58 @@ packages: from: 2.8.3 Firebase: url: https://github.com/firebase/firebase-ios-sdk - from: 10.7.0 + from: 10.18.0 RangeSeekSlider: url: https://github.com/rinat-enikeev/RangeSeekSlider from: 1.8.2 GestureInstructions: url: https://github.com/rinat-enikeev/GestureInstructions from: 0.0.2 - RuuviAnalytics: - path: Packages/RuuviAnalytics - RuuviCloud: - path: Packages/RuuviCloud - RuuviContext: - path: Packages/RuuviContext - RuuviCore: - path: Packages/RuuviCore - RuuviDaemon: - path: Packages/RuuviDaemon - RuuviDFU: - path: Packages/RuuviDFU - RuuviLocation: - path: Packages/RuuviLocation - RuuviLocal: - path: Packages/RuuviLocal - RuuviMigration: - path: Packages/RuuviMigration - RuuviNotification: - path: Packages/RuuviNotification - RuuviNotifier: - path: Packages/RuuviNotifier - RuuviOntology: - path: Packages/RuuviOntology - RuuviPersistence: - path: Packages/RuuviPersistence - RuuviPool: - path: Packages/RuuviPool - RuuviReactor: - path: Packages/RuuviReactor - RuuviRepository: - path: Packages/RuuviRepository - RuuviService: - path: Packages/RuuviService - RuuviStorage: - path: Packages/RuuviStorage - RuuviUser: - path: Packages/RuuviUser - RuuviVirtual: - path: Packages/RuuviVirtual - RuuviPresenters: - path: Common/RuuviPresenters - RuuviDiscover: - path: Modules/RuuviDiscover - RuuviLocationPicker: - path: Modules/RuuviLocationPicker - RuuviOnboard: - path: Modules/RuuviOnboard + Humidity: + url: https://github.com/rinat-enikeev/Humidity + from: 0.1.5 + Future: + url: https://github.com/kean/Future + from: 1.3.0 + NordicDFU: + url: https://github.com/NordicSemiconductor/IOS-Pods-DFU-Library + from: 4.10.3 + KeychainAccess: + url: https://github.com/kishikawakatsumi/KeychainAccess + from: 4.2.1 + Realm: + url: https://github.com/realm/realm-cocoa + from: 10.8.0 + GRDB: + url: https://github.com/groue/GRDB.swift + from: 4.14.0 + +include: +- Packages/RuuviAnalytics/target.yml +- Packages/RuuviCloud/target.yml +- Packages/RuuviContext/target.yml +- Packages/RuuviCore/target.yml +- Packages/RuuviDaemon/target.yml +- Packages/RuuviDFU/target.yml +- Packages/RuuviLocation/target.yml +- Packages/RuuviLocal/target.yml +- Packages/RuuviMigration/target.yml +- Packages/RuuviNotification/target.yml +- Packages/RuuviNotifier/target.yml +- Packages/RuuviOntology/target.yml +- Packages/RuuviPersistence/target.yml +- Packages/RuuviPool/target.yml +- Packages/RuuviReactor/target.yml +- Packages/RuuviRepository/target.yml +- Packages/RuuviService/target.yml +- Packages/RuuviStorage/target.yml +- Packages/RuuviUser/target.yml +- Packages/RuuviVirtual/target.yml +- Common/RuuviPresenters/target.yml +- Common/RuuviLocalization/target.yml +- Modules/RuuviDiscover/target.yml +- Modules/RuuviLocationPicker/target.yml +- Modules/RuuviOnboard/target.yml targets: station: @@ -99,6 +188,7 @@ targets: dependencies: - package: BTKit - package: Charts + - package: GRDB - package: LightRoute - package: Swinject - package: RangeSeekSlider @@ -107,102 +197,36 @@ targets: product: FirebaseMessaging - package: Firebase product: FirebaseRemoteConfig - - package: RuuviAnalytics - - package: RuuviAnalytics - product: RuuviAnalyticsImpl - - package: RuuviCloud - - package: RuuviCloud - product: RuuviCloudPure - - package: RuuviContext - - package: RuuviContext - product: RuuviContextRealm - - package: RuuviContext - product: RuuviContextSQLite - - package: RuuviCore - - package: RuuviCore - product: RuuviCoreImage - - package: RuuviCore - product: RuuviCorePN - - package: RuuviCore - product: RuuviCorePermission - - package: RuuviCore - product: RuuviCoreLocation - - package: RuuviDaemon - - package: RuuviDaemon - product: RuuviDaemonBackground - - package: RuuviDaemon - product: RuuviDaemonVirtualTag - - package: RuuviDaemon - product: RuuviDaemonRuuviTag - - package: RuuviDaemon - product: RuuviDaemonCloudSync - - package: RuuviDFU - - package: RuuviDFU - product: RuuviDFUImpl - - package: RuuviLocation - - package: RuuviLocation - product: RuuviLocationService - - package: RuuviLocal - - package: RuuviLocal - product: RuuviLocalUserDefaults - - package: RuuviMigration - - package: RuuviMigration - product: RuuviMigrationImpl - - package: RuuviNotification - - package: RuuviNotification - product: RuuviNotificationLocal - - package: RuuviNotifier - - package: RuuviNotifier - product: RuuviNotifierImpl - - package: RuuviOntology - - package: RuuviPersistence - - package: RuuviPersistence - product: RuuviPersistenceRealm - - package: RuuviPersistence - product: RuuviPersistenceSQLite - - package: RuuviPool - - package: RuuviPool - product: RuuviPoolCoordinator - - package: RuuviReactor - - package: RuuviReactor - product: RuuviReactorImpl - - package: RuuviRepository - - package: RuuviRepository - product: RuuviRepositoryCoordinator - - package: RuuviService - - package: RuuviService - product: RuuviServiceFactory - - package: RuuviService - product: RuuviServiceMeasurement - - package: RuuviService - product: RuuviServiceOwnership - - package: RuuviService - product: RuuviServiceExport - - package: RuuviService - product: RuuviServiceGATT - - package: RuuviStorage - - package: RuuviStorage - product: RuuviStorageCoordinator - - package: RuuviUser - - package: RuuviUser - product: RuuviUserCoordinator - - package: RuuviVirtual - - package: RuuviVirtual - product: RuuviVirtualOWM - - package: RuuviVirtual - product: RuuviVirtualPersistence - - package: RuuviVirtual - product: RuuviVirtualReactor - - package: RuuviVirtual - product: RuuviVirtualRepository - - package: RuuviVirtual - product: RuuviVirtualStorage - - package: RuuviVirtual - product: RuuviVirtualService - - package: RuuviPresenters - - package: RuuviDiscover - - package: RuuviLocationPicker - - package: RuuviOnboard + - package: Humidity + - package: Future + - package: Realm + - package: Realm + product: RealmSwift + - target: RuuviAnalytics + - target: RuuviCloud + - target: RuuviContext + - target: RuuviCore + - target: RuuviDaemon + - target: RuuviDFU + - target: RuuviLocation + - target: RuuviLocal + - target: RuuviMigration + - target: RuuviNotification + - target: RuuviNotifier + - target: RuuviOntology + - target: RuuviPersistence + - target: RuuviPool + - target: RuuviReactor + - target: RuuviRepository + - target: RuuviService + - target: RuuviStorage + - target: RuuviUser + - target: RuuviVirtual + - target: RuuviPresenters + - target: RuuviDiscover + - target: RuuviLocationPicker + - target: RuuviOnboard + - target: RuuviLocalization info: path: station/Resources/Plists/Info.plist properties: diff --git a/project_spm.yml b/project_spm.yml new file mode 100644 index 000000000..5bff5fd8b --- /dev/null +++ b/project_spm.yml @@ -0,0 +1,240 @@ +APP_NAME: &APP_NAME Ruuvi Station SPM +DEVELOPMENT_TEAM: &DEVELOPMENT_TEAM 4MUYJ4YYH4 +BUNDLE_ID_PREFIX: &BUNDLE_ID_PREFIX com.ruuvi + +attributes: + ORGANIZATIONNAME: Ruuvi Innovations Oy + +settings: + base: + CURRENT_PROJECT_VERSION: 420 + MARKETING_VERSION: "2.5.0" + DEVELOPMENT_TEAM: *DEVELOPMENT_TEAM + +name: *APP_NAME + +options: + bundleIdPrefix: *BUNDLE_ID_PREFIX + developmentLanguage: en + deploymentTarget: + iOS: 14.0 + +packages: + BTKit: + url: https://github.com/ruuvi/BTKit + from: 0.4.3 + Charts: + url: https://github.com/danielgindi/Charts + from: 4.1.0 + LightRoute: + url: https://github.com/rinat-enikeev/LightRoute + from: 2.2.2 + Swinject: + url: https://github.com/Swinject/Swinject + from: 2.8.3 + Firebase: + url: https://github.com/firebase/firebase-ios-sdk + from: 10.7.0 + RangeSeekSlider: + url: https://github.com/rinat-enikeev/RangeSeekSlider + from: 1.8.2 + GestureInstructions: + url: https://github.com/rinat-enikeev/GestureInstructions + from: 0.0.2 + RuuviAnalytics: + path: Packages/RuuviAnalytics + RuuviCloud: + path: Packages/RuuviCloud + RuuviContext: + path: Packages/RuuviContext + RuuviCore: + path: Packages/RuuviCore + RuuviDaemon: + path: Packages/RuuviDaemon + RuuviDFU: + path: Packages/RuuviDFU + RuuviLocation: + path: Packages/RuuviLocation + RuuviLocal: + path: Packages/RuuviLocal + RuuviMigration: + path: Packages/RuuviMigration + RuuviNotification: + path: Packages/RuuviNotification + RuuviNotifier: + path: Packages/RuuviNotifier + RuuviOntology: + path: Packages/RuuviOntology + RuuviPersistence: + path: Packages/RuuviPersistence + RuuviPool: + path: Packages/RuuviPool + RuuviReactor: + path: Packages/RuuviReactor + RuuviRepository: + path: Packages/RuuviRepository + RuuviService: + path: Packages/RuuviService + RuuviStorage: + path: Packages/RuuviStorage + RuuviUser: + path: Packages/RuuviUser + RuuviVirtual: + path: Packages/RuuviVirtual + RuuviPresenters: + path: Common/RuuviPresenters + RuuviDiscover: + path: Modules/RuuviDiscover + RuuviLocationPicker: + path: Modules/RuuviLocationPicker + RuuviOnboard: + path: Modules/RuuviOnboard + +targets: + station: + type: application + platform: iOS + sources: + - path: station + dependencies: + - package: BTKit + - package: Charts + - package: LightRoute + - package: Swinject + - package: RangeSeekSlider + - package: GestureInstructions + - package: Firebase + product: FirebaseMessaging + - package: Firebase + product: FirebaseRemoteConfig + - package: RuuviAnalytics + - package: RuuviAnalytics + product: RuuviAnalyticsImpl + - package: RuuviCloud + - package: RuuviCloud + product: RuuviCloudPure + - package: RuuviContext + - package: RuuviContext + product: RuuviContextRealm + - package: RuuviContext + product: RuuviContextSQLite + - package: RuuviCore + - package: RuuviCore + product: RuuviCoreImage + - package: RuuviCore + product: RuuviCorePN + - package: RuuviCore + product: RuuviCorePermission + - package: RuuviCore + product: RuuviCoreLocation + - package: RuuviDaemon + - package: RuuviDaemon + product: RuuviDaemonBackground + - package: RuuviDaemon + product: RuuviDaemonVirtualTag + - package: RuuviDaemon + product: RuuviDaemonRuuviTag + - package: RuuviDaemon + product: RuuviDaemonCloudSync + - package: RuuviDFU + - package: RuuviDFU + product: RuuviDFUImpl + - package: RuuviLocation + - package: RuuviLocation + product: RuuviLocationService + - package: RuuviLocal + - package: RuuviLocal + product: RuuviLocalUserDefaults + - package: RuuviMigration + - package: RuuviMigration + product: RuuviMigrationImpl + - package: RuuviNotification + - package: RuuviNotification + product: RuuviNotificationLocal + - package: RuuviNotifier + - package: RuuviNotifier + product: RuuviNotifierImpl + - package: RuuviOntology + - package: RuuviPersistence + - package: RuuviPersistence + product: RuuviPersistenceRealm + - package: RuuviPersistence + product: RuuviPersistenceSQLite + - package: RuuviPool + - package: RuuviPool + product: RuuviPoolCoordinator + - package: RuuviReactor + - package: RuuviReactor + product: RuuviReactorImpl + - package: RuuviRepository + - package: RuuviRepository + product: RuuviRepositoryCoordinator + - package: RuuviService + - package: RuuviService + product: RuuviServiceFactory + - package: RuuviService + product: RuuviServiceMeasurement + - package: RuuviService + product: RuuviServiceOwnership + - package: RuuviService + product: RuuviServiceExport + - package: RuuviService + product: RuuviServiceGATT + - package: RuuviStorage + - package: RuuviStorage + product: RuuviStorageCoordinator + - package: RuuviUser + - package: RuuviUser + product: RuuviUserCoordinator + - package: RuuviVirtual + - package: RuuviVirtual + product: RuuviVirtualOWM + - package: RuuviVirtual + product: RuuviVirtualPersistence + - package: RuuviVirtual + product: RuuviVirtualReactor + - package: RuuviVirtual + product: RuuviVirtualRepository + - package: RuuviVirtual + product: RuuviVirtualStorage + - package: RuuviVirtual + product: RuuviVirtualService + - package: RuuviPresenters + - package: RuuviDiscover + - package: RuuviLocationPicker + - package: RuuviOnboard + info: + path: station/Resources/Plists/Info.plist + properties: + CFBundleDisplayName: Ruuvi Station + CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString: "$(MARKETING_VERSION)" + CFBundleVersion: $(CURRENT_PROJECT_VERSION) + UISupportedInterfaceOrientations: [UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight, UIInterfaceOrientationPortrait] + UILaunchStoryboardName: LaunchScreen + BGTaskSchedulerPermittedIdentifiers: [com.ruuvi.station.BackgroundTaskServiceiOS13.webTagRefresh, com.ruuvi.station.BackgroundProcessServiceiOS13.dataPruning] + FirebaseMessagingAutoInitEnabled: false + LSApplicationQueriesSchemes: [https, http, mailto] + LSRequiresIPhoneOS: true + NFCReaderUsageDescription: Allows user to claim a RuuviTag using NFC when the user has physical access to the sensor + NSBluetoothAlwaysUsageDescription: The app uses Bluetooth LE to read data from Ruuvi Sensors + NSBluetoothPeripheralUsageDescription: The app uses Bluetooth LE to read data from RuuviTag sensors. + NSCameraUsageDescription: Ruuvi Station needs to access your camera in order to be able to capture photos and use them as sensor background. + NSLocationAlwaysAndWhenInUseUsageDescription: Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. + NSLocationAlwaysUsageDescription: Ruuvi Station needs to access your location while being in background in order to pull data for Virtual Sensors for your current location and display alerts. + NSLocationUsageDescription: Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. + NSLocationWhenInUseUsageDescription: Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. + NSPhotoLibraryUsageDescription: Ruuvi Station needs to access your camera roll to enable selecting the background for the sensor. + NSUserActivityTypes: [RuuviTagSelectionIntent] + UIAppFonts: [Oswald-Bold.ttf,Oswald-ExtraLight.ttf,Muli-Regular.ttf,Muli-Bold.ttf,Muli-SemiBoldItalic.ttf,Muli-ExtraBold.ttf,Montserrat-Bold.ttf,Montserrat-Regular.ttf,Montserrat-ExtraBold.ttf] + UIBackgroundModes: [bluetooth-central, processing, remote-notification] + UIRequiredDeviceCapabilities: [armv7] + UIRequiresFullScreen: true + UIStatusBarStyle: UIStatusBarStyleLightContent + UISupportedInterfaceOrientations~ipad: [UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight,UIInterfaceOrientationPortrait, UIInterfaceOrientationPortraitUpsideDown] + UIViewControllerBasedStatusBarAppearance: true + settings: + base: + TARGETED_DEVICE_FAMILY: 1,2 + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true + CODE_SIGN_ENTITLEMENTS: station/station.entitlements \ No newline at end of file From 77baf7fe7878ddaebb8b52e3179ff29c346b50b9 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Fri, 24 Nov 2023 23:13:14 +0200 Subject: [PATCH 07/84] Make commands for project gen and CLI build (#1723) Implements Makefile for project generation with SPM and Frameworks --- .gitignore | 3 ++- Makefile | 25 +++++++++++++++++ .../RuuviCloudFactoryPure.swift | 4 ++- .../RuuviCloudPure/RuuviCloudPure.swift | 3 +++ .../BackgroundProcessServiceiOS13.swift | 3 +++ .../BackgroundTaskServiceiOS13.swift | 4 +++ .../PullWeb/PullWebDaemonOperations.swift | 3 +++ Packages/RuuviService/Package.swift | 6 ++++- .../RuuviServiceCloudNotificationImpl.swift | 6 ++--- .../RuuviServiceFactory.swift | 27 +++++++++++++++++++ .../VirtualPersistenceRealm.swift | 3 +++ .../VirtualTagLastRecordSubjectCombine.swift | 3 +++ .../Combine/VirtualTagSubjectCombine.swift | 3 +++ .../VirtualProviderServiceImpl.swift | 3 +++ project.yml => project_frameworks.yml | 4 +-- project_spm.yml | 2 +- 16 files changed, 93 insertions(+), 9 deletions(-) create mode 100644 Makefile rename project.yml => project_frameworks.yml (99%) diff --git a/.gitignore b/.gitignore index a7fe67fd9..f39b6266c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Generated -Ruuvi Station.xcodeproj +spm.xcodeproj +frameworks.xcodeproj # Private station/Resources/Plists/GoogleService-Info.plist diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..4cb8c6ce5 --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +# generates xcodeproj for frameworks build configuration +xcodeproj_with_frameworks: + xcodegen -s project_frameworks.yml + +# generates xcodeproj for swift package manager build configuration +xcodeproj_with_spm: + xcodegen -s project_spm.yml + +# builds station target with frameworks build configuration for iOS +build_with_frameworks: + d=$$(date +%s)\ + ; xcodebuild -project frameworks.xcodeproj -scheme station -configuration Release -sdk iphoneos17.0 build\ + && echo "Build took $$(($$(date +%s)-d)) seconds" + +# builds station target with swift package manager build configuration for iOS +build_with_spm: + d=$$(date +%s)\ + ; xcodebuild -project spm.xcodeproj -scheme station -configuration Release -sdk iphoneos17.0 build\ + && echo "Build took $$(($$(date +%s)-d)) seconds" + +# builds station target with development pods build configuration for iOS +build_with_pods: + d=$$(date +%s)\ + ; xcodebuild -workspace station.xcworkspace -scheme station -configuration Release -sdk iphoneos17.0 build\ + && echo "Build took $$(($$(date +%s)-d)) seconds" diff --git a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift index 81d876f6d..8b43202d4 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift @@ -2,7 +2,9 @@ import Foundation import RuuviPool import RuuviUser import RuuviCloud - +#if canImport(RuuviCloudApi) +import RuuviCloudApi +#endif public final class RuuviCloudFactoryPure: RuuviCloudFactory { public init() {} diff --git a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift index 8ca9ca436..046e87bdc 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift @@ -6,6 +6,9 @@ import BTKit import RuuviUser import RuuviCloud import RuuviPool +#if canImport(RuuviCloudApi) +import RuuviCloudApi +#endif // swiftlint:disable:next type_body_length public final class RuuviCloudPure: RuuviCloud { diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift index 36dfcb018..83d6e204e 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift @@ -2,6 +2,9 @@ import Foundation import BackgroundTasks import Future import RuuviDaemon +#if canImport(RuuviDaemonOperation) +import RuuviDaemonOperation +#endif @available(iOS 13, *) public final class BackgroundProcessServiceiOS13: BackgroundProcessService { diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundTaskServiceiOS13.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundTaskServiceiOS13.swift index 6c98eb9c4..05ed831ac 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundTaskServiceiOS13.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundTaskServiceiOS13.swift @@ -1,6 +1,10 @@ import Foundation import BackgroundTasks import RuuviDaemon +#if canImport(RuuviDaemonOperation) +import RuuviDaemonOperation +#endif + @available(iOS 13, *) public final class BackgroundTaskServiceiOS13: BackgroundTaskService { diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/PullWeb/PullWebDaemonOperations.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/PullWeb/PullWebDaemonOperations.swift index b880c460c..b1a54e875 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/PullWeb/PullWebDaemonOperations.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/PullWeb/PullWebDaemonOperations.swift @@ -1,6 +1,9 @@ import Foundation import RuuviLocal import RuuviDaemon +#if canImport(RuuviDaemonOperation) +import RuuviDaemonOperation +#endif public final class PullWebDaemonOperations: RuuviDaemonWorker, PullWebDaemon { private let settings: RuuviLocalSettings diff --git a/Packages/RuuviService/Package.swift b/Packages/RuuviService/Package.swift index c6639cd50..9a617e608 100644 --- a/Packages/RuuviService/Package.swift +++ b/Packages/RuuviService/Package.swift @@ -92,7 +92,11 @@ let package = Package( .target( name: "RuuviServiceCloudNotification", dependencies: [ - "RuuviService" + "RuuviService", + .product( + name: "RuuviCloudApi", + package: "RuuviCloud" + ) ] ), .target( diff --git a/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift b/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift index 5bba0fcb4..41b2d8a6f 100644 --- a/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift @@ -3,14 +3,14 @@ import Future import RuuviOntology import RuuviStorage import RuuviCloud -#if canImport(RuuviCloudApi) -import RuuviCloudApi -#endif import RuuviPool import RuuviLocal import RuuviService import RuuviUser import RuuviCore +#if canImport(RuuviCloudApi) +import RuuviCloudApi +#endif public final class RuuviServiceCloudNotificationImpl: RuuviServiceCloudNotification { diff --git a/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift b/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift index dd00ae027..3b64feb21 100644 --- a/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift +++ b/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift @@ -7,6 +7,33 @@ import RuuviCore import RuuviRepository import RuuviService import RuuviUser +#if canImport(RuuviServiceCloudSync) +import RuuviServiceCloudSync +#endif +#if canImport(RuuviServiceOwnership) +import RuuviServiceOwnership +#endif +#if canImport(RuuviServiceSensorProperties) +import RuuviServiceSensorProperties +#endif +#if canImport(RuuviServiceSensorRecords) +import RuuviServiceSensorRecords +#endif +#if canImport(RuuviServiceAppSettings) +import RuuviServiceAppSettings +#endif +#if canImport(RuuviServiceOffsetCalibration) +import RuuviServiceOffsetCalibration +#endif +#if canImport(RuuviServiceAlert) +import RuuviServiceAlert +#endif +#if canImport(RuuviServiceAuth) +import RuuviServiceAuth +#endif +#if canImport(RuuviServiceCloudNotification) +import RuuviServiceCloudNotification +#endif public protocol RuuviServiceFactory { // swiftlint:disable:next function_parameter_count diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualPersistence/VirtualPersistenceRealm.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualPersistence/VirtualPersistenceRealm.swift index 12b658bfa..dbee56a90 100644 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualPersistence/VirtualPersistenceRealm.swift +++ b/Packages/RuuviVirtual/Sources/RuuviVirtualPersistence/VirtualPersistenceRealm.swift @@ -5,6 +5,9 @@ import RuuviOntology import RuuviContext import RuuviLocal import RuuviVirtual +#if canImport(RuuviVirtualModel) +import RuuviVirtualModel +#endif // swiftlint:disable:next type_body_length public final class VirtualPersistenceRealm: VirtualPersistence { diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagLastRecordSubjectCombine.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagLastRecordSubjectCombine.swift index 319431eba..3759a8a52 100644 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagLastRecordSubjectCombine.swift +++ b/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagLastRecordSubjectCombine.swift @@ -3,6 +3,9 @@ import Combine import RuuviContext import RuuviOntology import RealmSwift +#if canImport(RuuviVirtualModel) +import RuuviVirtualModel +#endif final class VirtualTagLastRecordSubjectCombine { var isServing: Bool = false diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagSubjectCombine.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagSubjectCombine.swift index 5c6834d45..43389f047 100644 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagSubjectCombine.swift +++ b/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagSubjectCombine.swift @@ -3,6 +3,9 @@ import Combine import RealmSwift import RuuviOntology import RuuviContext +#if canImport(RuuviVirtualModel) +import RuuviVirtualModel +#endif class VirtualTagSubjectCombine { var realm: RealmContext diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualService/VirtualProviderServiceImpl.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualService/VirtualProviderServiceImpl.swift index c194c1e7e..f0fce8c50 100644 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualService/VirtualProviderServiceImpl.swift +++ b/Packages/RuuviVirtual/Sources/RuuviVirtualService/VirtualProviderServiceImpl.swift @@ -5,6 +5,9 @@ import RuuviVirtual import RuuviOntology import RuuviLocation import RuuviCore +#if canImport(RuuviVirtualOWM) +import RuuviVirtualOWM +#endif public final class VirtualProviderServiceImpl: VirtualProviderService { private let owmApi: OpenWeatherMapAPI diff --git a/project.yml b/project_frameworks.yml similarity index 99% rename from project.yml rename to project_frameworks.yml index 347bbb5f1..ebead8436 100644 --- a/project.yml +++ b/project_frameworks.yml @@ -1,4 +1,4 @@ -APP_NAME: &APP_NAME Ruuvi Station +APP_NAME: &APP_NAME frameworks DEVELOPMENT_TEAM: &DEVELOPMENT_TEAM 4MUYJ4YYH4 BUNDLE_ID_PREFIX: &BUNDLE_ID_PREFIX com.ruuvi @@ -114,7 +114,7 @@ targetTemplates: packages: BTKit: url: https://github.com/ruuvi/BTKit - from: 0.4.3 + version: 0.4.3 Charts: url: https://github.com/danielgindi/Charts from: 4.1.0 diff --git a/project_spm.yml b/project_spm.yml index 5bff5fd8b..f3a2cb3b3 100644 --- a/project_spm.yml +++ b/project_spm.yml @@ -1,4 +1,4 @@ -APP_NAME: &APP_NAME Ruuvi Station SPM +APP_NAME: &APP_NAME spm DEVELOPMENT_TEAM: &DEVELOPMENT_TEAM 4MUYJ4YYH4 BUNDLE_ID_PREFIX: &BUNDLE_ID_PREFIX com.ruuvi From 6241503c8f65de18c18cc5e6ecfa803866c8de3d Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Fri, 24 Nov 2023 23:23:27 +0200 Subject: [PATCH 08/84] Make mergable frameworks to improve launch time (#1724) * Make mergable frameworks to increase launch time Makes all frameworks, except depending on GRDB, mergable. See https://developer.apple.com/documentation/xcode/configuring-your-project-to-use-mergeable-libraries#Manually-configure-merging. @see: https://github.com/groue/GRDB.swift/issues/642 * make MERGEABLE_LIBRARY: true --- Packages/RuuviContext/target.yml | 4 ++++ Packages/RuuviOntology/target.yml | 4 ++++ Packages/RuuviPersistence/target.yml | 4 ++++ Packages/RuuviReactor/target.yml | 4 ++++ project_frameworks.yml | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/Packages/RuuviContext/target.yml b/Packages/RuuviContext/target.yml index 88120dd40..ecb1f1d4a 100644 --- a/Packages/RuuviContext/target.yml +++ b/Packages/RuuviContext/target.yml @@ -1,6 +1,10 @@ --- targets: RuuviContext: + # https://github.com/groue/GRDB.swift/issues/642 + settings: + base: + MERGEABLE_LIBRARY: false templates: - Framework dependencies: diff --git a/Packages/RuuviOntology/target.yml b/Packages/RuuviOntology/target.yml index 889ee6667..c080d36b3 100644 --- a/Packages/RuuviOntology/target.yml +++ b/Packages/RuuviOntology/target.yml @@ -1,6 +1,10 @@ --- targets: RuuviOntology: + # https://github.com/groue/GRDB.swift/issues/642 + settings: + base: + MERGEABLE_LIBRARY: false templates: - Framework dependencies: diff --git a/Packages/RuuviPersistence/target.yml b/Packages/RuuviPersistence/target.yml index 4ad07b62f..19cff3adc 100644 --- a/Packages/RuuviPersistence/target.yml +++ b/Packages/RuuviPersistence/target.yml @@ -1,6 +1,10 @@ --- targets: RuuviPersistence: + # https://github.com/groue/GRDB.swift/issues/642 + settings: + base: + MERGEABLE_LIBRARY: false templates: - Framework dependencies: diff --git a/Packages/RuuviReactor/target.yml b/Packages/RuuviReactor/target.yml index 6474428b9..a30ebde46 100644 --- a/Packages/RuuviReactor/target.yml +++ b/Packages/RuuviReactor/target.yml @@ -1,6 +1,10 @@ --- targets: RuuviReactor: + # https://github.com/groue/GRDB.swift/issues/642 + settings: + base: + MERGEABLE_LIBRARY: false templates: - Framework dependencies: diff --git a/project_frameworks.yml b/project_frameworks.yml index ebead8436..91234f0de 100644 --- a/project_frameworks.yml +++ b/project_frameworks.yml @@ -50,6 +50,7 @@ targetTemplates: CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString: "$(MARKETING_VERSION)" CFBundleVersion: $(CURRENT_PROJECT_VERSION) + MERGEABLE_LIBRARY: true Module: name: "${target_name}" type: framework @@ -80,6 +81,7 @@ targetTemplates: CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString: "$(MARKETING_VERSION)" CFBundleVersion: $(CURRENT_PROJECT_VERSION) + MERGEABLE_LIBRARY: true CommonFramework: name: "${target_name}" type: framework @@ -110,6 +112,7 @@ targetTemplates: CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString: "$(MARKETING_VERSION)" CFBundleVersion: $(CURRENT_PROJECT_VERSION) + MERGEABLE_LIBRARY: true packages: BTKit: @@ -259,6 +262,7 @@ targets: UIViewControllerBasedStatusBarAppearance: true settings: base: + MERGED_BINARY_TYPE: "manual" TARGETED_DEVICE_FAMILY: 1,2 SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true CODE_SIGN_ENTITLEMENTS: station/station.entitlements \ No newline at end of file From 5a8589fb6fb0e6460d2ed0cd3134f847cdf17bd7 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Fri, 24 Nov 2023 23:29:57 +0200 Subject: [PATCH 09/84] Remove confusing project files (#1725) --- iOS.xcodeproj/project.pbxproj | 6996 ----------------- .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/xcschemes/station.xcscheme | 98 - .../xcschemes/station_dev.xcscheme | 78 - macOS.xcodeproj/project.pbxproj | 4925 ------------ .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/xcschemes/station.xcscheme | 78 - 9 files changed, 12205 deletions(-) delete mode 100755 iOS.xcodeproj/project.pbxproj delete mode 100755 iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100755 iOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100755 iOS.xcodeproj/xcshareddata/xcschemes/station.xcscheme delete mode 100755 iOS.xcodeproj/xcshareddata/xcschemes/station_dev.xcscheme delete mode 100755 macOS.xcodeproj/project.pbxproj delete mode 100755 macOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100755 macOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100755 macOS.xcodeproj/xcshareddata/xcschemes/station.xcscheme diff --git a/iOS.xcodeproj/project.pbxproj b/iOS.xcodeproj/project.pbxproj deleted file mode 100755 index 7ef22eaf4..000000000 --- a/iOS.xcodeproj/project.pbxproj +++ /dev/null @@ -1,6996 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 52; - objects = { - -/* Begin PBXBuildFile section */ - 08E830207D43DAF06076D647 /* SignInModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87EFB230083D471777FBE5D0 /* SignInModuleInput.swift */; }; - 0E00C4F72685B971009B3C24 /* RuuviServiceExport in Frameworks */ = {isa = PBXBuildFile; productRef = 0E00C4F62685B971009B3C24 /* RuuviServiceExport */; }; - 0E00C4F92685B972009B3C24 /* RuuviServiceMeasurement in Frameworks */ = {isa = PBXBuildFile; productRef = 0E00C4F82685B972009B3C24 /* RuuviServiceMeasurement */; }; - 0E00C4FB2685B97D009B3C24 /* RuuviServiceExport in Frameworks */ = {isa = PBXBuildFile; productRef = 0E00C4FA2685B97D009B3C24 /* RuuviServiceExport */; }; - 0E00C4FD2685B97E009B3C24 /* RuuviServiceMeasurement in Frameworks */ = {isa = PBXBuildFile; productRef = 0E00C4FC2685B97E009B3C24 /* RuuviServiceMeasurement */; }; - 0E02ABBA237598C600ED4629 /* RURangeSeekSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E02ABB9237598C600ED4629 /* RURangeSeekSlider.swift */; }; - 0E02ABCB2379483A00ED4629 /* Double+Temperature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E02ABCA2379483A00ED4629 /* Double+Temperature.swift */; }; - 0E046F2722F04A0300BD4E9C /* WebTagSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E046F2622F04A0300BD4E9C /* WebTagSettings.storyboard */; }; - 0E046F2922F0561B00BD4E9C /* WebTagSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2822F0561B00BD4E9C /* WebTagSettingsViewInput.swift */; }; - 0E046F2B22F0563100BD4E9C /* WebTagSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2A22F0563100BD4E9C /* WebTagSettingsViewOutput.swift */; }; - 0E046F2E22F0569000BD4E9C /* WebTagSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2D22F0569000BD4E9C /* WebTagSettingsTableViewController.swift */; }; - 0E046F3022F057CC00BD4E9C /* WebTagSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2F22F057CC00BD4E9C /* WebTagSettingsRouterInput.swift */; }; - 0E046F3222F057DD00BD4E9C /* WebTagSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3122F057DD00BD4E9C /* WebTagSettingsRouter.swift */; }; - 0E046F3422F057FC00BD4E9C /* WebTagSettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3322F057FC00BD4E9C /* WebTagSettingsModuleInput.swift */; }; - 0E046F3622F0581E00BD4E9C /* WebTagSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3522F0581E00BD4E9C /* WebTagSettingsPresenter.swift */; }; - 0E046F3B22F05AA800BD4E9C /* WebTagSettingsTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3A22F05AA800BD4E9C /* WebTagSettingsTableInitializer.swift */; }; - 0E046F3D22F05B0900BD4E9C /* WebTagSettingsTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3C22F05B0900BD4E9C /* WebTagSettingsTableConfigurator.swift */; }; - 0E046F3F22F0702D00BD4E9C /* WebTagSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3E22F0702D00BD4E9C /* WebTagSettingsViewModel.swift */; }; - 0E046F4622F17EF400BD4E9C /* LocationPicker.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E046F4522F17EF400BD4E9C /* LocationPicker.storyboard */; }; - 0E046F4822F181DA00BD4E9C /* LocationPickerViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4722F181DA00BD4E9C /* LocationPickerViewInput.swift */; }; - 0E046F4A22F1820400BD4E9C /* LocationPickerViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4922F1820400BD4E9C /* LocationPickerViewOutput.swift */; }; - 0E046F4D22F1823C00BD4E9C /* LocationPickerAppleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4C22F1823C00BD4E9C /* LocationPickerAppleViewController.swift */; }; - 0E046F4F22F1827800BD4E9C /* LocationPickerRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4E22F1827800BD4E9C /* LocationPickerRouterInput.swift */; }; - 0E046F5122F1828900BD4E9C /* LocationPickerRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5022F1828900BD4E9C /* LocationPickerRouter.swift */; }; - 0E046F5322F182AB00BD4E9C /* LocationPickerModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5222F182AB00BD4E9C /* LocationPickerModuleInput.swift */; }; - 0E046F5522F182BF00BD4E9C /* LocationPickerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5422F182BF00BD4E9C /* LocationPickerPresenter.swift */; }; - 0E046F5822F182F500BD4E9C /* LocationPickerAppleInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5722F182F500BD4E9C /* LocationPickerAppleInitializer.swift */; }; - 0E046F5A22F1832600BD4E9C /* LocationPickerAppleConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5922F1832600BD4E9C /* LocationPickerAppleConfigurator.swift */; }; - 0E046F6222F193B300BD4E9C /* LocationPickerModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F6122F193B300BD4E9C /* LocationPickerModuleOutput.swift */; }; - 0E0501282685FDD3007060C4 /* RuuviDaemonError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0501262685FDD3007060C4 /* RuuviDaemonError+LocalizedError.swift */; }; - 0E0501292685FDD3007060C4 /* RuuviDaemonError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0501262685FDD3007060C4 /* RuuviDaemonError+LocalizedError.swift */; }; - 0E05012A2685FDD3007060C4 /* RuuviDFUError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0501272685FDD3007060C4 /* RuuviDFUError+LocalizedError.swift */; }; - 0E05012B2685FDD3007060C4 /* RuuviDFUError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0501272685FDD3007060C4 /* RuuviDFUError+LocalizedError.swift */; }; - 0E05012D2685FDE8007060C4 /* RuuviDaemonBackground in Frameworks */ = {isa = PBXBuildFile; productRef = 0E05012C2685FDE8007060C4 /* RuuviDaemonBackground */; }; - 0E05012F2685FDE8007060C4 /* RuuviDaemonOperation in Frameworks */ = {isa = PBXBuildFile; productRef = 0E05012E2685FDE8007060C4 /* RuuviDaemonOperation */; }; - 0E0501312685FDE8007060C4 /* RuuviDaemonRuuviTag in Frameworks */ = {isa = PBXBuildFile; productRef = 0E0501302685FDE8007060C4 /* RuuviDaemonRuuviTag */; }; - 0E0501332685FDE8007060C4 /* RuuviDaemonVirtualTag in Frameworks */ = {isa = PBXBuildFile; productRef = 0E0501322685FDE8007060C4 /* RuuviDaemonVirtualTag */; }; - 0E0501352685FDEF007060C4 /* RuuviDaemonBackground in Frameworks */ = {isa = PBXBuildFile; productRef = 0E0501342685FDEF007060C4 /* RuuviDaemonBackground */; }; - 0E0501372685FDEF007060C4 /* RuuviDaemonOperation in Frameworks */ = {isa = PBXBuildFile; productRef = 0E0501362685FDEF007060C4 /* RuuviDaemonOperation */; }; - 0E0501392685FDF0007060C4 /* RuuviDaemonRuuviTag in Frameworks */ = {isa = PBXBuildFile; productRef = 0E0501382685FDF0007060C4 /* RuuviDaemonRuuviTag */; }; - 0E05013B2685FDF0007060C4 /* RuuviDaemonVirtualTag in Frameworks */ = {isa = PBXBuildFile; productRef = 0E05013A2685FDF0007060C4 /* RuuviDaemonVirtualTag */; }; - 0E05016C268603CE007060C4 /* AppStateServiceImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E050161268603CE007060C4 /* AppStateServiceImpl.swift */; }; - 0E05016D268603CE007060C4 /* AppStateServiceImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E050161268603CE007060C4 /* AppStateServiceImpl.swift */; }; - 0E05016E268603CE007060C4 /* AppStateService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E050162268603CE007060C4 /* AppStateService.swift */; }; - 0E05016F268603CE007060C4 /* AppStateService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E050162268603CE007060C4 /* AppStateService.swift */; }; - 0E050170268603CE007060C4 /* UniversalLinkCoordinatormpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E050166268603CE007060C4 /* UniversalLinkCoordinatormpl.swift */; }; - 0E050171268603CE007060C4 /* UniversalLinkCoordinatormpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E050166268603CE007060C4 /* UniversalLinkCoordinatormpl.swift */; }; - 0E050172268603CE007060C4 /* UniversalLinkCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E050167268603CE007060C4 /* UniversalLinkCoordinator.swift */; }; - 0E050173268603CE007060C4 /* UniversalLinkCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E050167268603CE007060C4 /* UniversalLinkCoordinator.swift */; }; - 0E050174268603CE007060C4 /* UniversalLinkRouterImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E05016A268603CE007060C4 /* UniversalLinkRouterImpl.swift */; }; - 0E050175268603CE007060C4 /* UniversalLinkRouterImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E05016A268603CE007060C4 /* UniversalLinkRouterImpl.swift */; }; - 0E050176268603CE007060C4 /* UniversalLinkRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E05016B268603CE007060C4 /* UniversalLinkRouter.swift */; }; - 0E050177268603CE007060C4 /* UniversalLinkRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E05016B268603CE007060C4 /* UniversalLinkRouter.swift */; }; - 0E050179268603DD007060C4 /* ChartFilterOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E050178268603DD007060C4 /* ChartFilterOperation.swift */; }; - 0E05017A268603DD007060C4 /* ChartFilterOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E050178268603DD007060C4 /* ChartFilterOperation.swift */; }; - 0E09672022AE7F5C00E85F48 /* Welcome.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E09671F22AE7F5C00E85F48 /* Welcome.storyboard */; }; - 0E09672222AE7FCF00E85F48 /* WelcomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E09672122AE7FCF00E85F48 /* WelcomeViewController.swift */; }; - 0E09672522AE897000E85F48 /* CALayer+IB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E09672422AE897000E85F48 /* CALayer+IB.swift */; }; - 0E09672822AE8D7A00E85F48 /* Discover.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E09672722AE8D7A00E85F48 /* Discover.storyboard */; }; - 0E09672C22AE94F000E85F48 /* DiscoverDeviceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E09672B22AE94F000E85F48 /* DiscoverDeviceTableViewCell.swift */; }; - 0E0A381923616AC3003A0364 /* UserDefaults+Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0A381823616AC3003A0364 /* UserDefaults+Optional.swift */; }; - 0E11D13D267DFA09002D0686 /* Localize_Swift in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D13C267DFA08002D0686 /* Localize_Swift */; }; - 0E11D13F267DFA13002D0686 /* Localize_Swift in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D13E267DFA13002D0686 /* Localize_Swift */; }; - 0E11D14E267DFC75002D0686 /* RuuviCloud in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D14D267DFC75002D0686 /* RuuviCloud */; }; - 0E11D150267DFC75002D0686 /* RuuviCloudApi in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D14F267DFC75002D0686 /* RuuviCloudApi */; }; - 0E11D152267DFC75002D0686 /* RuuviCloudPure in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D151267DFC75002D0686 /* RuuviCloudPure */; }; - 0E11D154267DFC7B002D0686 /* RuuviContext in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D153267DFC7B002D0686 /* RuuviContext */; }; - 0E11D156267DFC7B002D0686 /* RuuviContextRealm in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D155267DFC7B002D0686 /* RuuviContextRealm */; }; - 0E11D158267DFC7B002D0686 /* RuuviContextSQLite in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D157267DFC7B002D0686 /* RuuviContextSQLite */; }; - 0E11D15A267DFC80002D0686 /* RuuviCore in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D159267DFC80002D0686 /* RuuviCore */; }; - 0E11D15C267DFC80002D0686 /* RuuviCoreImage in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D15B267DFC80002D0686 /* RuuviCoreImage */; }; - 0E11D15E267DFC8C002D0686 /* RuuviDaemon in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D15D267DFC8C002D0686 /* RuuviDaemon */; }; - 0E11D160267DFC8C002D0686 /* RuuviDaemonCloudSync in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D15F267DFC8C002D0686 /* RuuviDaemonCloudSync */; }; - 0E11D162267DFC95002D0686 /* RuuviLocal in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D161267DFC95002D0686 /* RuuviLocal */; }; - 0E11D164267DFC95002D0686 /* RuuviLocalUserDefaults in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D163267DFC95002D0686 /* RuuviLocalUserDefaults */; }; - 0E11D166267DFC9C002D0686 /* RuuviOntology in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D165267DFC9C002D0686 /* RuuviOntology */; }; - 0E11D168267DFC9C002D0686 /* RuuviOntologyRealm in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D167267DFC9C002D0686 /* RuuviOntologyRealm */; }; - 0E11D16A267DFC9C002D0686 /* RuuviOntologySQLite in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D169267DFC9C002D0686 /* RuuviOntologySQLite */; }; - 0E11D16C267DFCA2002D0686 /* RuuviPersistence in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D16B267DFCA2002D0686 /* RuuviPersistence */; }; - 0E11D16E267DFCA2002D0686 /* RuuviPersistenceRealm in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D16D267DFCA2002D0686 /* RuuviPersistenceRealm */; }; - 0E11D170267DFCA2002D0686 /* RuuviPersistenceSQLite in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D16F267DFCA2002D0686 /* RuuviPersistenceSQLite */; }; - 0E11D172267DFCA8002D0686 /* RuuviPool in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D171267DFCA8002D0686 /* RuuviPool */; }; - 0E11D174267DFCA8002D0686 /* RuuviPoolCoordinator in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D173267DFCA8002D0686 /* RuuviPoolCoordinator */; }; - 0E11D176267DFCAE002D0686 /* RuuviReactor in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D175267DFCAE002D0686 /* RuuviReactor */; }; - 0E11D178267DFCAE002D0686 /* RuuviReactorImpl in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D177267DFCAE002D0686 /* RuuviReactorImpl */; }; - 0E11D17A267DFCB6002D0686 /* RuuviRepository in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D179267DFCB6002D0686 /* RuuviRepository */; }; - 0E11D17C267DFCB6002D0686 /* RuuviRepositoryCoordinator in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D17B267DFCB6002D0686 /* RuuviRepositoryCoordinator */; }; - 0E11D17E267DFCBD002D0686 /* RuuviService in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D17D267DFCBD002D0686 /* RuuviService */; }; - 0E11D180267DFCBD002D0686 /* RuuviServiceAlert in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D17F267DFCBD002D0686 /* RuuviServiceAlert */; }; - 0E11D182267DFCBE002D0686 /* RuuviServiceAppSettings in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D181267DFCBE002D0686 /* RuuviServiceAppSettings */; }; - 0E11D184267DFCBE002D0686 /* RuuviServiceCloudSync in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D183267DFCBE002D0686 /* RuuviServiceCloudSync */; }; - 0E11D186267DFCBE002D0686 /* RuuviServiceFactory in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D185267DFCBE002D0686 /* RuuviServiceFactory */; }; - 0E11D188267DFCBE002D0686 /* RuuviServiceOffsetCalibration in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D187267DFCBE002D0686 /* RuuviServiceOffsetCalibration */; }; - 0E11D18A267DFCBE002D0686 /* RuuviServiceOwnership in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D189267DFCBE002D0686 /* RuuviServiceOwnership */; }; - 0E11D18C267DFCBE002D0686 /* RuuviServiceSensorProperties in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D18B267DFCBE002D0686 /* RuuviServiceSensorProperties */; }; - 0E11D18E267DFCBE002D0686 /* RuuviServiceSensorRecords in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D18D267DFCBE002D0686 /* RuuviServiceSensorRecords */; }; - 0E11D190267DFCC7002D0686 /* RuuviStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D18F267DFCC7002D0686 /* RuuviStorage */; }; - 0E11D192267DFCC7002D0686 /* RuuviStorageCoordinator in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D191267DFCC7002D0686 /* RuuviStorageCoordinator */; }; - 0E11D194267DFCCD002D0686 /* RuuviUser in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D193267DFCCD002D0686 /* RuuviUser */; }; - 0E11D196267DFCCD002D0686 /* RuuviUserCoordinator in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D195267DFCCD002D0686 /* RuuviUserCoordinator */; }; - 0E11D198267DFCDA002D0686 /* RuuviCloud in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D197267DFCDA002D0686 /* RuuviCloud */; }; - 0E11D19A267DFCDA002D0686 /* RuuviCloudApi in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D199267DFCDA002D0686 /* RuuviCloudApi */; }; - 0E11D19C267DFCDA002D0686 /* RuuviCloudPure in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D19B267DFCDA002D0686 /* RuuviCloudPure */; }; - 0E11D19E267DFCDA002D0686 /* RuuviContext in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D19D267DFCDA002D0686 /* RuuviContext */; }; - 0E11D1A0267DFCDA002D0686 /* RuuviContextRealm in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D19F267DFCDA002D0686 /* RuuviContextRealm */; }; - 0E11D1A2267DFCDA002D0686 /* RuuviContextSQLite in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1A1267DFCDA002D0686 /* RuuviContextSQLite */; }; - 0E11D1A4267DFCDA002D0686 /* RuuviCore in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1A3267DFCDA002D0686 /* RuuviCore */; }; - 0E11D1A6267DFCDA002D0686 /* RuuviCoreImage in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1A5267DFCDA002D0686 /* RuuviCoreImage */; }; - 0E11D1A8267DFCDA002D0686 /* RuuviDaemon in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1A7267DFCDA002D0686 /* RuuviDaemon */; }; - 0E11D1AA267DFCDA002D0686 /* RuuviDaemonCloudSync in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1A9267DFCDA002D0686 /* RuuviDaemonCloudSync */; }; - 0E11D1AC267DFCDA002D0686 /* RuuviLocal in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1AB267DFCDA002D0686 /* RuuviLocal */; }; - 0E11D1AE267DFCDA002D0686 /* RuuviLocalUserDefaults in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1AD267DFCDA002D0686 /* RuuviLocalUserDefaults */; }; - 0E11D1B0267DFCDA002D0686 /* RuuviOntology in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1AF267DFCDA002D0686 /* RuuviOntology */; }; - 0E11D1B2267DFCDA002D0686 /* RuuviOntologyRealm in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1B1267DFCDA002D0686 /* RuuviOntologyRealm */; }; - 0E11D1B4267DFCDA002D0686 /* RuuviOntologySQLite in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1B3267DFCDA002D0686 /* RuuviOntologySQLite */; }; - 0E11D1B6267DFCDA002D0686 /* RuuviPersistence in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1B5267DFCDA002D0686 /* RuuviPersistence */; }; - 0E11D1B8267DFCDA002D0686 /* RuuviPersistenceRealm in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1B7267DFCDA002D0686 /* RuuviPersistenceRealm */; }; - 0E11D1BA267DFCDA002D0686 /* RuuviPersistenceSQLite in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1B9267DFCDA002D0686 /* RuuviPersistenceSQLite */; }; - 0E11D1BC267DFCDA002D0686 /* RuuviPool in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1BB267DFCDA002D0686 /* RuuviPool */; }; - 0E11D1BE267DFCDB002D0686 /* RuuviPoolCoordinator in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1BD267DFCDB002D0686 /* RuuviPoolCoordinator */; }; - 0E11D1C0267DFCDB002D0686 /* RuuviReactor in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1BF267DFCDB002D0686 /* RuuviReactor */; }; - 0E11D1C2267DFCDB002D0686 /* RuuviReactorImpl in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1C1267DFCDB002D0686 /* RuuviReactorImpl */; }; - 0E11D1C4267DFCDB002D0686 /* RuuviRepository in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1C3267DFCDB002D0686 /* RuuviRepository */; }; - 0E11D1C6267DFCDB002D0686 /* RuuviRepositoryCoordinator in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1C5267DFCDB002D0686 /* RuuviRepositoryCoordinator */; }; - 0E11D1C8267DFCDB002D0686 /* RuuviService in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1C7267DFCDB002D0686 /* RuuviService */; }; - 0E11D1CA267DFCDB002D0686 /* RuuviServiceAlert in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1C9267DFCDB002D0686 /* RuuviServiceAlert */; }; - 0E11D1CC267DFCDB002D0686 /* RuuviServiceAppSettings in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1CB267DFCDB002D0686 /* RuuviServiceAppSettings */; }; - 0E11D1CE267DFCDB002D0686 /* RuuviServiceCloudSync in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1CD267DFCDB002D0686 /* RuuviServiceCloudSync */; }; - 0E11D1D0267DFCDB002D0686 /* RuuviServiceFactory in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1CF267DFCDB002D0686 /* RuuviServiceFactory */; }; - 0E11D1D2267DFCDB002D0686 /* RuuviServiceOffsetCalibration in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1D1267DFCDB002D0686 /* RuuviServiceOffsetCalibration */; }; - 0E11D1D4267DFCDB002D0686 /* RuuviServiceOwnership in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1D3267DFCDB002D0686 /* RuuviServiceOwnership */; }; - 0E11D1D6267DFCDB002D0686 /* RuuviServiceSensorProperties in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1D5267DFCDB002D0686 /* RuuviServiceSensorProperties */; }; - 0E11D1D8267DFCDB002D0686 /* RuuviServiceSensorRecords in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1D7267DFCDB002D0686 /* RuuviServiceSensorRecords */; }; - 0E11D1DA267DFCDB002D0686 /* RuuviStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1D9267DFCDB002D0686 /* RuuviStorage */; }; - 0E11D1DC267DFCDB002D0686 /* RuuviStorageCoordinator in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1DB267DFCDB002D0686 /* RuuviStorageCoordinator */; }; - 0E11D1DE267DFCDB002D0686 /* RuuviUser in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1DD267DFCDB002D0686 /* RuuviUser */; }; - 0E11D1E0267DFCDB002D0686 /* RuuviUserCoordinator in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1DF267DFCDB002D0686 /* RuuviUserCoordinator */; }; - 0E11D1E8267DFF2F002D0686 /* LightRoute in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1E7267DFF2F002D0686 /* LightRoute */; }; - 0E11D1EA267DFF38002D0686 /* LightRoute in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1E9267DFF38002D0686 /* LightRoute */; }; - 0E11D1ED267E0010002D0686 /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1EC267E0010002D0686 /* FirebaseAnalytics */; }; - 0E11D1EF267E0010002D0686 /* FirebaseRemoteConfig in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1EE267E0010002D0686 /* FirebaseRemoteConfig */; }; - 0E11D1F1267E0010002D0686 /* FirebaseCrashlytics in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1F0267E0010002D0686 /* FirebaseCrashlytics */; }; - 0E11D1F3267E0040002D0686 /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1F2267E0040002D0686 /* FirebaseAnalytics */; }; - 0E11D1F5267E0040002D0686 /* FirebaseCrashlytics in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1F4267E0040002D0686 /* FirebaseCrashlytics */; }; - 0E11D1F7267E0040002D0686 /* FirebaseRemoteConfig in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1F6267E0040002D0686 /* FirebaseRemoteConfig */; }; - 0E11D1FA267E008D002D0686 /* Swinject in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1F9267E008D002D0686 /* Swinject */; }; - 0E11D1FC267E00AC002D0686 /* Swinject in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1FB267E00AC002D0686 /* Swinject */; }; - 0E11D1FF267E02BC002D0686 /* RangeSeekSlider in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D1FE267E02BC002D0686 /* RangeSeekSlider */; }; - 0E11D201267E02D2002D0686 /* RangeSeekSlider in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D200267E02D2002D0686 /* RangeSeekSlider */; }; - 0E11D204267E0336002D0686 /* GestureInstructions in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D203267E0336002D0686 /* GestureInstructions */; }; - 0E11D206267E0346002D0686 /* GestureInstructions in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D205267E0346002D0686 /* GestureInstructions */; }; - 0E11D209267E037A002D0686 /* SwinjectPropertyLoader in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D208267E037A002D0686 /* SwinjectPropertyLoader */; }; - 0E11D20B267E038C002D0686 /* SwinjectPropertyLoader in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D20A267E038C002D0686 /* SwinjectPropertyLoader */; }; - 0E11D20E267E0510002D0686 /* NordicDFU in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D20D267E0510002D0686 /* NordicDFU */; }; - 0E11D210267E051D002D0686 /* NordicDFU in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D20F267E051D002D0686 /* NordicDFU */; }; - 0E11D216267E13D1002D0686 /* FirebaseInAppMessaging-Beta in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D215267E13D1002D0686 /* FirebaseInAppMessaging-Beta */; }; - 0E11D218267E13D1002D0686 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D217267E13D1002D0686 /* FirebaseMessaging */; }; - 0E11D21A267E13DB002D0686 /* FirebaseInAppMessaging-Beta in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D219267E13DB002D0686 /* FirebaseInAppMessaging-Beta */; }; - 0E11D21C267E13DB002D0686 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D21B267E13DB002D0686 /* FirebaseMessaging */; }; - 0E197C6123C352380074015B /* TagSettingsAlertDescriptionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C6023C352380074015B /* TagSettingsAlertDescriptionCell.swift */; }; - 0E197C6223C352380074015B /* TagSettingsAlertDescriptionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C6023C352380074015B /* TagSettingsAlertDescriptionCell.swift */; }; - 0E197C6623C4A47A0074015B /* MailComposerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C6523C4A47A0074015B /* MailComposerPresenter.swift */; }; - 0E197C6723C4A47A0074015B /* MailComposerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C6523C4A47A0074015B /* MailComposerPresenter.swift */; }; - 0E197C6B23C4A52A0074015B /* MailComposerPresenterMessageUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C6A23C4A52A0074015B /* MailComposerPresenterMessageUI.swift */; }; - 0E197C6C23C4A52A0074015B /* MailComposerPresenterMessageUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C6A23C4A52A0074015B /* MailComposerPresenterMessageUI.swift */; }; - 0E197C6F23C4A7D00074015B /* Presentation.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0E197C6E23C4A7D00074015B /* Presentation.plist */; }; - 0E197C7023C4A7D00074015B /* Presentation.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0E197C6E23C4A7D00074015B /* Presentation.plist */; }; - 0E197C7D23C5CD7C0074015B /* UIDevice+ReadableModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C7C23C5CD7C0074015B /* UIDevice+ReadableModel.swift */; }; - 0E197C7E23C5CD7C0074015B /* UIDevice+ReadableModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C7C23C5CD7C0074015B /* UIDevice+ReadableModel.swift */; }; - 0E197C8123C5CDBE0074015B /* iOSDeviceModelMapping.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0E197C8023C5CDBE0074015B /* iOSDeviceModelMapping.plist */; }; - 0E197C8223C5CDBE0074015B /* iOSDeviceModelMapping.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0E197C8023C5CDBE0074015B /* iOSDeviceModelMapping.plist */; }; - 0E1B2F32239DEF120060C469 /* TagSettingsAlertHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1B2F31239DEF120060C469 /* TagSettingsAlertHeaderCell.swift */; }; - 0E1B2F33239DEF120060C469 /* TagSettingsAlertHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1B2F31239DEF120060C469 /* TagSettingsAlertHeaderCell.swift */; }; - 0E1B2F36239DF0120060C469 /* TagSettingsAlertControlsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1B2F35239DF0120060C469 /* TagSettingsAlertControlsCell.swift */; }; - 0E1B2F37239DF0120060C469 /* TagSettingsAlertControlsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1B2F35239DF0120060C469 /* TagSettingsAlertControlsCell.swift */; }; - 0E1C1DA822B387A00032F6CA /* AppAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DA722B387A00032F6CA /* AppAssembly.swift */; }; - 0E1C1DAF22B38F780032F6CA /* ActivityPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DAE22B38F780032F6CA /* ActivityPresenter.swift */; }; - 0E1C1DB322B390080032F6CA /* ActivityPresenterRuuviLogo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DB222B390080032F6CA /* ActivityPresenterRuuviLogo.swift */; }; - 0E1C1DB522B3903B0032F6CA /* ActivityRuuviLogo.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C1DB422B3903B0032F6CA /* ActivityRuuviLogo.storyboard */; }; - 0E1C1DB722B390BC0032F6CA /* ActivityRuuviLogoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DB622B390BC0032F6CA /* ActivityRuuviLogoViewController.swift */; }; - 0E1C1DB922B390ED0032F6CA /* ActivitySpinnerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DB822B390ED0032F6CA /* ActivitySpinnerView.swift */; }; - 0E1C1DBB22B3919F0032F6CA /* UIApplication+ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DBA22B3919F0032F6CA /* UIApplication+ViewController.swift */; }; - 0E1C1DBE22B3921E0032F6CA /* PresentationAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DBD22B3921E0032F6CA /* PresentationAssembly.swift */; }; - 0E1C1DC122B3955E0032F6CA /* ErrorPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DC022B3955E0032F6CA /* ErrorPresenter.swift */; }; - 0E1C1DC422B395C00032F6CA /* ErrorPresenterAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DC322B395C00032F6CA /* ErrorPresenterAlert.swift */; }; - 0E1C1DD122B3BDFC0032F6CA /* Cards.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C1DD022B3BDFC0032F6CA /* Cards.storyboard */; }; - 0E1C1DD322B3BF180032F6CA /* CardsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DD222B3BF180032F6CA /* CardsViewInput.swift */; }; - 0E1C1DD522B3BF3A0032F6CA /* CardsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DD422B3BF3A0032F6CA /* CardsViewOutput.swift */; }; - 0E1C1DDD22B3C2160032F6CA /* CardsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DDC22B3C2160032F6CA /* CardsModuleInput.swift */; }; - 0E1C1DDF22B3C2330032F6CA /* CardsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DDE22B3C2330032F6CA /* CardsPresenter.swift */; }; - 0E1C1DE222B3C25F0032F6CA /* CardsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE122B3C25F0032F6CA /* CardsRouterInput.swift */; }; - 0E1C1DE422B3C2710032F6CA /* CardsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE322B3C2710032F6CA /* CardsRouter.swift */; }; - 0E1C1DE822B3C2B60032F6CA /* CardsScrollInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE722B3C2B60032F6CA /* CardsScrollInitializer.swift */; }; - 0E1C1DEA22B3C2E60032F6CA /* CardsScrollConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE922B3C2E60032F6CA /* CardsScrollConfigurator.swift */; }; - 0E1C1DF122B3FDE30032F6CA /* Menu.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF022B3FDE30032F6CA /* Menu.storyboard */; }; - 0E1C1DF322B3FEFF0032F6CA /* MenuViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF222B3FEFF0032F6CA /* MenuViewInput.swift */; }; - 0E1C1DF522B3FF1D0032F6CA /* MenuViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF422B3FF1D0032F6CA /* MenuViewOutput.swift */; }; - 0E1C1DF822B3FF480032F6CA /* MenuTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF722B3FF480032F6CA /* MenuTableViewController.swift */; }; - 0E1C1DFA22B3FFBF0032F6CA /* MenuRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF922B3FFBF0032F6CA /* MenuRouterInput.swift */; }; - 0E1C1DFC22B3FFD90032F6CA /* MenuRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFB22B3FFD90032F6CA /* MenuRouter.swift */; }; - 0E1C1DFE22B3FFFC0032F6CA /* MenuModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFD22B3FFFC0032F6CA /* MenuModuleInput.swift */; }; - 0E1C1E0022B400130032F6CA /* MenuPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFF22B400130032F6CA /* MenuPresenter.swift */; }; - 0E1C1E0322B400590032F6CA /* MenuTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0222B400590032F6CA /* MenuTableInitializer.swift */; }; - 0E1C1E0522B400890032F6CA /* MenuTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0422B400890032F6CA /* MenuTableConfigurator.swift */; }; - 0E1C1E0922B4024E0032F6CA /* MenuTableTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0822B4024E0032F6CA /* MenuTableTransitioningDelegate.swift */; }; - 0E1C1E0B22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0A22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift */; }; - 0E1C1E0D22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0C22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift */; }; - 0E1C1E0F22B4049F0032F6CA /* MenuTablePresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0E22B4049E0032F6CA /* MenuTablePresentationController.swift */; }; - 0E1C1E1122B756B40032F6CA /* CardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E1022B756B40032F6CA /* CardView.swift */; }; - 0E1C1E1322B756D30032F6CA /* CardView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C1E1222B756D30032F6CA /* CardView.xib */; }; - 0E211C2A234C5FE900FC37B0 /* CardsRouterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E211C29234C5FE900FC37B0 /* CardsRouterDelegate.swift */; }; - 0E2513522684A10A004A522A /* RuuviNotification in Frameworks */ = {isa = PBXBuildFile; productRef = 0E2513512684A10A004A522A /* RuuviNotification */; }; - 0E2513542684A10A004A522A /* RuuviNotificationLocal in Frameworks */ = {isa = PBXBuildFile; productRef = 0E2513532684A10A004A522A /* RuuviNotificationLocal */; }; - 0E2513562684A113004A522A /* RuuviNotification in Frameworks */ = {isa = PBXBuildFile; productRef = 0E2513552684A113004A522A /* RuuviNotification */; }; - 0E2513582684A113004A522A /* RuuviNotificationLocal in Frameworks */ = {isa = PBXBuildFile; productRef = 0E2513572684A113004A522A /* RuuviNotificationLocal */; }; - 0E2513662684CFF7004A522A /* RuuviNotifier in Frameworks */ = {isa = PBXBuildFile; productRef = 0E2513652684CFF7004A522A /* RuuviNotifier */; }; - 0E2513682684CFF7004A522A /* RuuviNotifierImpl in Frameworks */ = {isa = PBXBuildFile; productRef = 0E2513672684CFF7004A522A /* RuuviNotifierImpl */; }; - 0E25136A2684D000004A522A /* RuuviNotifier in Frameworks */ = {isa = PBXBuildFile; productRef = 0E2513692684D000004A522A /* RuuviNotifier */; }; - 0E25136C2684D001004A522A /* RuuviNotifierImpl in Frameworks */ = {isa = PBXBuildFile; productRef = 0E25136B2684D001004A522A /* RuuviNotifierImpl */; }; - 0E290A852660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E290A842660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift */; }; - 0E290A862660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E290A842660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift */; }; - 0E2AFFA0266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2AFF9F266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift */; }; - 0E2AFFA1266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2AFF9F266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift */; }; - 0E31B04223BBA37C00660412 /* WebTagSettingsAlertsHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E31B04123BBA37C00660412 /* WebTagSettingsAlertsHeaderFooterView.swift */; }; - 0E31B04323BBA37C00660412 /* WebTagSettingsAlertsHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E31B04123BBA37C00660412 /* WebTagSettingsAlertsHeaderFooterView.swift */; }; - 0E31B04623BBA3F900660412 /* WebTagSettingsAlertsHeaderFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E31B04523BBA3F900660412 /* WebTagSettingsAlertsHeaderFooterView.xib */; }; - 0E31B04723BBA3F900660412 /* WebTagSettingsAlertsHeaderFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E31B04523BBA3F900660412 /* WebTagSettingsAlertsHeaderFooterView.xib */; }; - 0E341BBD2372E75C0085BB54 /* TagChartsTransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E341BBC2372E75C0085BB54 /* TagChartsTransitionManager.swift */; }; - 0E3FF735238157B700EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E3FF734238157B700EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.xib */; }; - 0E3FF7372381591800EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3FF7362381591800EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.swift */; }; - 0E502FBE22B2817900E8A6CC /* DiscoverRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E502FBD22B2817900E8A6CC /* DiscoverRouterInput.swift */; }; - 0E502FC022B2819B00E8A6CC /* DiscoverRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E502FBF22B2819B00E8A6CC /* DiscoverRouter.swift */; }; - 0E53A3F1232DFC6200ACED49 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0E53A3F3232DFC6200ACED49 /* InfoPlist.strings */; }; - 0E53A3FB232F4D5000ACED49 /* DiscoverNoDevicesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53A3FA232F4D5000ACED49 /* DiscoverNoDevicesTableViewCell.swift */; }; - 0E53DA6022CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA5F22CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift */; }; - 0E53DA6222CC93EB00BC6D64 /* SwipeDownToDismissTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6122CC93EB00BC6D64 /* SwipeDownToDismissTransitionAnimation.swift */; }; - 0E53DA6422CC943900BC6D64 /* SwipeDownToDismissInteractiveTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6322CC943900BC6D64 /* SwipeDownToDismissInteractiveTransition.swift */; }; - 0E53DA6722CC964200BC6D64 /* SwipeDownToDismissNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6622CC964200BC6D64 /* SwipeDownToDismissNavigationController.swift */; }; - 0E5C300B22CF629100B52E39 /* PhotoPickerPresenterSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C300A22CF629100B52E39 /* PhotoPickerPresenterSheet.swift */; }; - 0E5C301A22CF644900B52E39 /* PermissionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C301922CF644900B52E39 /* PermissionPresenter.swift */; }; - 0E5C301C22CF646B00B52E39 /* PermissionPresenterAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C301B22CF646A00B52E39 /* PermissionPresenterAlert.swift */; }; - 0E62297A26A7F84F0041DCDD /* OnboardRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E62297826A7F84F0041DCDD /* OnboardRouter.swift */; }; - 0E62297B26A7F84F0041DCDD /* OnboardRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E62297826A7F84F0041DCDD /* OnboardRouter.swift */; }; - 0E62297C26A7F84F0041DCDD /* AppRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E62297926A7F84F0041DCDD /* AppRouter.swift */; }; - 0E62297D26A7F84F0041DCDD /* AppRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E62297926A7F84F0041DCDD /* AppRouter.swift */; }; - 0E62298026A7FA7C0041DCDD /* RuuviOnboard in Frameworks */ = {isa = PBXBuildFile; productRef = 0E62297F26A7FA7C0041DCDD /* RuuviOnboard */; }; - 0E62298226A7FA8A0041DCDD /* RuuviOnboard in Frameworks */ = {isa = PBXBuildFile; productRef = 0E62298126A7FA8A0041DCDD /* RuuviOnboard */; }; - 0E62AEC922E065CC00A49BFB /* TagSettingsMoreInfoHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E62AEC822E065CC00A49BFB /* TagSettingsMoreInfoHeaderFooterView.swift */; }; - 0E62AECB22E065F000A49BFB /* TagSettingsMoreInfoHeaderFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E62AECA22E065F000A49BFB /* TagSettingsMoreInfoHeaderFooterView.xib */; }; - 0E6C471723D305960016B46E /* StationUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E6C471623D305960016B46E /* StationUITests.swift */; }; - 0E70A46022AF9567006CB87C /* ViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A45F22AF9567006CB87C /* ViewInput.swift */; }; - 0E70A46322AF959E006CB87C /* Localizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A46222AF959E006CB87C /* Localizable.swift */; }; - 0E70A46C22AF9705006CB87C /* DiscoverTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A46B22AF9705006CB87C /* DiscoverTableViewController.swift */; }; - 0E70A46E22AF9763006CB87C /* DiscoverViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A46D22AF9763006CB87C /* DiscoverViewInput.swift */; }; - 0E70A47022AF9790006CB87C /* DiscoverViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A46F22AF9790006CB87C /* DiscoverViewOutput.swift */; }; - 0E70A47322AF9953006CB87C /* DiscoverModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A47222AF9953006CB87C /* DiscoverModuleInput.swift */; }; - 0E70A47522AF9978006CB87C /* DiscoverPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A47422AF9978006CB87C /* DiscoverPresenter.swift */; }; - 0E70A47B22AF9BE2006CB87C /* DiscoverTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A47A22AF9BE2006CB87C /* DiscoverTableInitializer.swift */; }; - 0E70A47D22AF9BFE006CB87C /* DiscoverTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A47C22AF9BFE006CB87C /* DiscoverTableConfigurator.swift */; }; - 0E79F28B244328D50048BF86 /* DiscoverAddWithMACTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E79F28A244328D50048BF86 /* DiscoverAddWithMACTableViewCell.swift */; }; - 0E79F28C244328D50048BF86 /* DiscoverAddWithMACTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E79F28A244328D50048BF86 /* DiscoverAddWithMACTableViewCell.swift */; }; - 0E84BF4D239795B000A37E1A /* DiscoverModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF4C239795AF00A37E1A /* DiscoverModuleOutput.swift */; }; - 0E84BF552397F29800A37E1A /* Heartbeat.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E84BF542397F29800A37E1A /* Heartbeat.storyboard */; }; - 0E84BF572397F33E00A37E1A /* HeartbeatViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF562397F33E00A37E1A /* HeartbeatViewInput.swift */; }; - 0E84BF592397F3C600A37E1A /* HeartbeatViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF582397F3C600A37E1A /* HeartbeatViewModel.swift */; }; - 0E84BF5B2397F3DF00A37E1A /* HeartbeatViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF5A2397F3DF00A37E1A /* HeartbeatViewOutput.swift */; }; - 0E84BF5F2397F6BE00A37E1A /* HeartbeatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF5E2397F6BE00A37E1A /* HeartbeatViewController.swift */; }; - 0E84BF612397F73100A37E1A /* HeartbeatEnvironmentObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF602397F73100A37E1A /* HeartbeatEnvironmentObject.swift */; }; - 0E84BF632397F76A00A37E1A /* HeartbeatList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF622397F76A00A37E1A /* HeartbeatList.swift */; }; - 0E84BF652397F9DC00A37E1A /* HeartbeatTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF642397F9DC00A37E1A /* HeartbeatTableViewController.swift */; }; - 0E84BF67239801AF00A37E1A /* HeartbeatRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF66239801AF00A37E1A /* HeartbeatRouterInput.swift */; }; - 0E84BF69239801C100A37E1A /* HeartbeatRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF68239801C100A37E1A /* HeartbeatRouter.swift */; }; - 0E84BF6B239802A400A37E1A /* HeartbeatModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF6A239802A400A37E1A /* HeartbeatModuleInput.swift */; }; - 0E84BF6D239802CA00A37E1A /* HeartbeatPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF6C239802CA00A37E1A /* HeartbeatPresenter.swift */; }; - 0E84BF6F2398031B00A37E1A /* HeartbeatInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF6E2398031B00A37E1A /* HeartbeatInitializer.swift */; }; - 0E84BF712398035C00A37E1A /* HeartbeatConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF702398035C00A37E1A /* HeartbeatConfigurator.swift */; }; - 0E8A100223845E5100A9CBA6 /* Defaults.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E8A100123845E5100A9CBA6 /* Defaults.storyboard */; }; - 0E8A100A23845F3900A9CBA6 /* DefaultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100923845F3900A9CBA6 /* DefaultsViewController.swift */; }; - 0E8A100C23845F7100A9CBA6 /* DefaultsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100B23845F7100A9CBA6 /* DefaultsViewInput.swift */; }; - 0E8A100E23845F8C00A9CBA6 /* DefaultsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100D23845F8C00A9CBA6 /* DefaultsViewOutput.swift */; }; - 0E8A101023845FAE00A9CBA6 /* DefaultsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100F23845FAE00A9CBA6 /* DefaultsViewModel.swift */; }; - 0E8A10122384605A00A9CBA6 /* DefaultsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10112384605A00A9CBA6 /* DefaultsTableViewController.swift */; }; - 0E8A10142384610400A9CBA6 /* DefaultsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10132384610400A9CBA6 /* DefaultsRouter.swift */; }; - 0E8A10162384612300A9CBA6 /* DefaultsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10152384612300A9CBA6 /* DefaultsRouterInput.swift */; }; - 0E8A10182384613E00A9CBA6 /* DefaultsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10172384613E00A9CBA6 /* DefaultsModuleInput.swift */; }; - 0E8A101A2384615400A9CBA6 /* DefaultsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10192384615400A9CBA6 /* DefaultsPresenter.swift */; }; - 0E8A101C2384618700A9CBA6 /* DefaultsInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A101B2384618700A9CBA6 /* DefaultsInitializer.swift */; }; - 0E8A101E238461D400A9CBA6 /* DefaultsConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A101D238461D400A9CBA6 /* DefaultsConfigurator.swift */; }; - 0E8A10202384633200A9CBA6 /* DefaultsEnvironmentObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A101F2384633200A9CBA6 /* DefaultsEnvironmentObject.swift */; }; - 0E8A10222384637F00A9CBA6 /* DefaultsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10212384637F00A9CBA6 /* DefaultsList.swift */; }; - 0E8A102523846CEB00A9CBA6 /* DefaultsSwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A102423846CEB00A9CBA6 /* DefaultsSwitchTableViewCell.swift */; }; - 0E8BD2AB23851CF2008B31EF /* DefaultsStepperTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8BD2AA23851CF2008B31EF /* DefaultsStepperTableViewCell.swift */; }; - 0E8BD2B0238566AB008B31EF /* CardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E1022B756B40032F6CA /* CardView.swift */; }; - 0E8BD2B2238566AB008B31EF /* DiscoverTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A46B22AF9705006CB87C /* DiscoverTableViewController.swift */; }; - 0E8BD2B3238566AB008B31EF /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5522CCE46D00172EEB /* Optional.swift */; }; - 0E8BD2B8238566AB008B31EF /* CALayer+IB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E09672422AE897000E85F48 /* CALayer+IB.swift */; }; - 0E8BD2BA238566AB008B31EF /* MenuTablePresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0E22B4049E0032F6CA /* MenuTablePresentationController.swift */; }; - 0E8BD2BD238566AB008B31EF /* TagSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863022CBB00D0026C7A5 /* TagSettingsViewInput.swift */; }; - 0E8BD2BE238566AB008B31EF /* DefaultsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100D23845F8C00A9CBA6 /* DefaultsViewOutput.swift */; }; - 0E8BD2BF238566AB008B31EF /* MenuPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFF22B400130032F6CA /* MenuPresenter.swift */; }; - 0E8BD2C0238566AB008B31EF /* ForegroundRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF6F5BD235E01170052BA25 /* ForegroundRouter.swift */; }; - 0E8BD2C1238566AB008B31EF /* MenuTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF722B3FF480032F6CA /* MenuTableViewController.swift */; }; - 0E8BD2C2238566AB008B31EF /* AboutRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F822B7D28C0015F9E0 /* AboutRouterInput.swift */; }; - 0E8BD2C4238566AB008B31EF /* WelcomeConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215722B8FD800015F9E0 /* WelcomeConfigurator.swift */; }; - 0E8BD2C5238566AB008B31EF /* ForegroundModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF35A2350618E0061D11B /* ForegroundModuleInput.swift */; }; - 0E8BD2C6238566AB008B31EF /* AboutViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F422B7D1A40015F9E0 /* AboutViewOutput.swift */; }; - 0E8BD2C9238566AB008B31EF /* TagChartsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0DC2333714C00FFA577 /* TagChartsViewModel.swift */; }; - 0E8BD2CC238566AB008B31EF /* PermissionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C301922CF644900B52E39 /* PermissionPresenter.swift */; }; - 0E8BD2CD238566AB008B31EF /* LocationPickerRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4E22F1827800BD4E9C /* LocationPickerRouterInput.swift */; }; - 0E8BD2CF238566AB008B31EF /* TagChartsTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0D223336B4200FFA577 /* TagChartsTransitioningDelegate.swift */; }; - 0E8BD2D0238566AB008B31EF /* WebTagSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3122F057DD00BD4E9C /* WebTagSettingsRouter.swift */; }; - 0E8BD2D1238566AB008B31EF /* DefaultsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10192384615400A9CBA6 /* DefaultsPresenter.swift */; }; - 0E8BD2D2238566AB008B31EF /* WelcomeViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214622B8FC3E0015F9E0 /* WelcomeViewInput.swift */; }; - 0E8BD2D3238566AB008B31EF /* ForegroundList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF354235056DC0061D11B /* ForegroundList.swift */; }; - 0E8BD2D4238566AB008B31EF /* SettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E222B7C8C10015F9E0 /* SettingsPresenter.swift */; }; - 0E8BD2D5238566AB008B31EF /* LanguageTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF07F2320089A0025A191 /* LanguageTableConfigurator.swift */; }; - 0E8BD2D6238566AB008B31EF /* MenuTablePresentTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0A22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift */; }; - 0E8BD2D7238566AB008B31EF /* WebTagSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2822F0561B00BD4E9C /* WebTagSettingsViewInput.swift */; }; - 0E8BD2D8238566AB008B31EF /* WelcomeRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214B22B8FCC70015F9E0 /* WelcomeRouterInput.swift */; }; - 0E8BD2DA238566AB008B31EF /* MenuModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20CC22B7BD6C0015F9E0 /* MenuModuleOutput.swift */; }; - 0E8BD2DD238566AB008B31EF /* Localizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A46222AF959E006CB87C /* Localizable.swift */; }; - 0E8BD2DE238566AB008B31EF /* LocationPickerAppleInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5722F182F500BD4E9C /* LocationPickerAppleInitializer.swift */; }; - 0E8BD2DF238566AB008B31EF /* TagChartsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0CC2333672F00FFA577 /* TagChartsPresenter.swift */; }; - 0E8BD2E0238566AB008B31EF /* DefaultsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10212384637F00A9CBA6 /* DefaultsList.swift */; }; - 0E8BD2E2238566AB008B31EF /* WelcomePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215222B8FD1F0015F9E0 /* WelcomePresenter.swift */; }; - 0E8BD2E4238566AB008B31EF /* CardsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DD422B3BF3A0032F6CA /* CardsViewOutput.swift */; }; - 0E8BD2E5238566AB008B31EF /* DefaultsSwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A102423846CEB00A9CBA6 /* DefaultsSwitchTableViewCell.swift */; }; - 0E8BD2E6238566AB008B31EF /* DefaultsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100B23845F7100A9CBA6 /* DefaultsViewInput.swift */; }; - 0E8BD2E7238566AB008B31EF /* LocationPickerRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5022F1828900BD4E9C /* LocationPickerRouter.swift */; }; - 0E8BD2E8238566AB008B31EF /* WebTagSettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3322F057FC00BD4E9C /* WebTagSettingsModuleInput.swift */; }; - 0E8BD2E9238566AB008B31EF /* MenuTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0422B400890032F6CA /* MenuTableConfigurator.swift */; }; - 0E8BD2ED238566AB008B31EF /* DefaultsStepperTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8BD2AA23851CF2008B31EF /* DefaultsStepperTableViewCell.swift */; }; - 0E8BD2F0238566AB008B31EF /* SettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20DE22B7C8790015F9E0 /* SettingsRouter.swift */; }; - 0E8BD2F3238566AB008B31EF /* SwipeDownToDismissNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6622CC964200BC6D64 /* SwipeDownToDismissNavigationController.swift */; }; - 0E8BD2F4238566AB008B31EF /* DefaultsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10152384612300A9CBA6 /* DefaultsRouterInput.swift */; }; - 0E8BD2F5238566AB008B31EF /* AboutPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FE22B7D2DD0015F9E0 /* AboutPresenter.swift */; }; - 0E8BD2F6238566AB008B31EF /* TagChartsPresentTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0D423336BA300FFA577 /* TagChartsPresentTransitionAnimation.swift */; }; - 0E8BD2F7238566AB008B31EF /* TagSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5122CCB9DE00172EEB /* TagSettingsViewModel.swift */; }; - 0E8BD2F8238566AB008B31EF /* CardsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DDE22B3C2330032F6CA /* CardsPresenter.swift */; }; - 0E8BD2F9238566AB008B31EF /* DiscoverWebTagsInfoHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3FF7362381591800EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.swift */; }; - 0E8BD2FC238566AB008B31EF /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F4F22CCB92000172EEB /* Observable.swift */; }; - 0E8BD2FD238566AB008B31EF /* ForegroundTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF6F5C1235E02000052BA25 /* ForegroundTableViewController.swift */; }; - 0E8BD300238566AB008B31EF /* TagSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863222CBB0250026C7A5 /* TagSettingsViewOutput.swift */; }; - 0E8BD301238566AB008B31EF /* ForegroundViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF36F23507CE80061D11B /* ForegroundViewModel.swift */; }; - 0E8BD302238566AB008B31EF /* CardsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20C522B7915C0015F9E0 /* CardsViewModel.swift */; }; - 0E8BD303238566AB008B31EF /* UIApplication+ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DBA22B3919F0032F6CA /* UIApplication+ViewController.swift */; }; - 0E8BD304238566AB008B31EF /* WebTagSettingsTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3C22F05B0900BD4E9C /* WebTagSettingsTableConfigurator.swift */; }; - 0E8BD308238566AB008B31EF /* TagSettingsMoreInfoHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E62AEC822E065CC00A49BFB /* TagSettingsMoreInfoHeaderFooterView.swift */; }; - 0E8BD30A238566AB008B31EF /* PermissionPresenterAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C301B22CF646A00B52E39 /* PermissionPresenterAlert.swift */; }; - 0E8BD30C238566AB008B31EF /* MainRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB213B22B8FAD50015F9E0 /* MainRouter.swift */; }; - 0E8BD30D238566AB008B31EF /* TagChartsScrollViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0C023335D8400FFA577 /* TagChartsScrollViewController.swift */; }; - 0E8BD30F238566AB008B31EF /* PhotoPickerPresenterSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C300A22CF629100B52E39 /* PhotoPickerPresenterSheet.swift */; }; - 0E8BD310238566AB008B31EF /* AboutConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB210222B7D3210015F9E0 /* AboutConfigurator.swift */; }; - 0E8BD311238566AB008B31EF /* AboutViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F222B7D1900015F9E0 /* AboutViewInput.swift */; }; - 0E8BD312238566AB008B31EF /* TagChartsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0C223335DA700FFA577 /* TagChartsViewInput.swift */; }; - 0E8BD313238566AB008B31EF /* LanguageTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF071232007910025A191 /* LanguageTableViewController.swift */; }; - 0E8BD314238566AB008B31EF /* DefaultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100923845F3900A9CBA6 /* DefaultsViewController.swift */; }; - 0E8BD316238566AB008B31EF /* DefaultsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100F23845FAE00A9CBA6 /* DefaultsViewModel.swift */; }; - 0E8BD317238566AB008B31EF /* TagChartsScrollConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0D02333679800FFA577 /* TagChartsScrollConfigurator.swift */; }; - 0E8BD319238566AB008B31EF /* LanguageViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF06F232007740025A191 /* LanguageViewOutput.swift */; }; - 0E8BD31A238566AB008B31EF /* DefaultsConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A101D238461D400A9CBA6 /* DefaultsConfigurator.swift */; }; - 0E8BD31B238566AB008B31EF /* MenuRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFB22B3FFD90032F6CA /* MenuRouter.swift */; }; - 0E8BD31C238566AB008B31EF /* ForegroundRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF36723507A1A0061D11B /* ForegroundRouterInput.swift */; }; - 0E8BD320238566AB008B31EF /* DefaultsInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A101B2384618700A9CBA6 /* DefaultsInitializer.swift */; }; - 0E8BD322238566AB008B31EF /* MainInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214122B8FBA50015F9E0 /* MainInitializer.swift */; }; - 0E8BD324238566AB008B31EF /* ForegroundSwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9D5F1F2351BE3C0076FFD8 /* ForegroundSwitchTableViewCell.swift */; }; - 0E8BD326238566AB008B31EF /* MenuTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0222B400590032F6CA /* MenuTableInitializer.swift */; }; - 0E8BD327238566AB008B31EF /* LocationPickerViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4922F1820400BD4E9C /* LocationPickerViewOutput.swift */; }; - 0E8BD328238566AB008B31EF /* WebTagSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2D22F0569000BD4E9C /* WebTagSettingsTableViewController.swift */; }; - 0E8BD329238566AB008B31EF /* WelcomeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214D22B8FCDC0015F9E0 /* WelcomeRouter.swift */; }; - 0E8BD32E238566AB008B31EF /* TagSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863622CBB04E0026C7A5 /* TagSettingsRouter.swift */; }; - 0E8BD32F238566AB008B31EF /* DiscoverDeviceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E09672B22AE94F000E85F48 /* DiscoverDeviceTableViewCell.swift */; }; - 0E8BD330238566AB008B31EF /* AboutInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB210022B7D2F50015F9E0 /* AboutInitializer.swift */; }; - 0E8BD331238566AB008B31EF /* ForegroundEnvironmentObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE5B47C23508F6D00D5ED32 /* ForegroundEnvironmentObject.swift */; }; - 0E8BD332238566AB008B31EF /* MenuTableEmbededViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20CA22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift */; }; - 0E8BD334238566AB008B31EF /* TagChartsDismissTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0D623336C6E00FFA577 /* TagChartsDismissTransitionAnimation.swift */; }; - 0E8BD335238566AB008B31EF /* Date+Ruuvi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF5B72A22D62CD900D9D14A /* Date+Ruuvi.swift */; }; - 0E8BD339238566AB008B31EF /* CardsScrollViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECB5A8D2381807500E78757 /* CardsScrollViewController.swift */; }; - 0E8BD33A238566AB008B31EF /* LanguagePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF07A232008420025A191 /* LanguagePresenter.swift */; }; - 0E8BD33C238566AB008B31EF /* TagSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2862D22CBAFC80026C7A5 /* TagSettingsTableViewController.swift */; }; - 0E8BD33E238566AB008B31EF /* LocationPickerModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5222F182AB00BD4E9C /* LocationPickerModuleInput.swift */; }; - 0E8BD343238566AB008B31EF /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D222B7C7AC0015F9E0 /* SettingsTableViewController.swift */; }; - 0E8BD345238566AB008B31EF /* SwipeDownToDismissTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6122CC93EB00BC6D64 /* SwipeDownToDismissTransitionAnimation.swift */; }; - 0E8BD348238566AB008B31EF /* SettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20DC22B7C8650015F9E0 /* SettingsRouterInput.swift */; }; - 0E8BD349238566AB008B31EF /* ForegroundStepperTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF6F5BF235E01CD0052BA25 /* ForegroundStepperTableViewCell.swift */; }; - 0E8BD34A238566AB008B31EF /* MenuTableTransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215922BA28860015F9E0 /* MenuTableTransitionManager.swift */; }; - 0E8BD34B238566AB008B31EF /* TagChartsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0C423335DBF00FFA577 /* TagChartsViewOutput.swift */; }; - 0E8BD34C238566AB008B31EF /* DefaultsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10132384610400A9CBA6 /* DefaultsRouter.swift */; }; - 0E8BD34D238566AB008B31EF /* ForegroundViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF35F23506BD60061D11B /* ForegroundViewInput.swift */; }; - 0E8BD34E238566AB008B31EF /* WebTagSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2F22F057CC00BD4E9C /* WebTagSettingsRouterInput.swift */; }; - 0E8BD353238566AB008B31EF /* LocalizationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9D0AB0231EBEFD00C6BDA7 /* LocalizationService.swift */; }; - 0E8BD354238566AB008B31EF /* RURangeSeekSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E02ABB9237598C600ED4629 /* RURangeSeekSlider.swift */; }; - 0E8BD355238566AB008B31EF /* CardsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DDC22B3C2160032F6CA /* CardsModuleInput.swift */; }; - 0E8BD356238566AB008B31EF /* LanguageRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF074232007CC0025A191 /* LanguageRouterInput.swift */; }; - 0E8BD359238566AB008B31EF /* ForegroundViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF35D23506BC40061D11B /* ForegroundViewOutput.swift */; }; - 0E8BD35A238566AB008B31EF /* LanguageModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF078232008140025A191 /* LanguageModuleInput.swift */; }; - 0E8BD35B238566AB008B31EF /* PresentationAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DBD22B3921E0032F6CA /* PresentationAssembly.swift */; }; - 0E8BD35C238566AB008B31EF /* DiscoverWebTagTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9F979522EAFC820015ADE2 /* DiscoverWebTagTableViewCell.swift */; }; - 0E8BD35D238566AB008B31EF /* AboutModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FC22B7D2C90015F9E0 /* AboutModuleInput.swift */; }; - 0E8BD35E238566AB008B31EF /* WelcomeViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214822B8FC570015F9E0 /* WelcomeViewOutput.swift */; }; - 0E8BD35F238566AB008B31EF /* MainNavigationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB213E22B8FB840015F9E0 /* MainNavigationDelegate.swift */; }; - 0E8BD363238566AB008B31EF /* WebTagSettingsTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3A22F05AA800BD4E9C /* WebTagSettingsTableInitializer.swift */; }; - 0E8BD364238566AB008B31EF /* MenuRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF922B3FFBF0032F6CA /* MenuRouterInput.swift */; }; - 0E8BD365238566AB008B31EF /* LanguageRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF076232007D80025A191 /* LanguageRouter.swift */; }; - 0E8BD367238566AB008B31EF /* TagChartsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0CA2333671100FFA577 /* TagChartsModuleInput.swift */; }; - 0E8BD368238566AB008B31EF /* Double+Temperature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E02ABCA2379483A00ED4629 /* Double+Temperature.swift */; }; - 0E8BD36C238566AB008B31EF /* ActivityPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DAE22B38F780032F6CA /* ActivityPresenter.swift */; }; - 0E8BD36D238566AB008B31EF /* MenuViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF422B3FF1D0032F6CA /* MenuViewOutput.swift */; }; - 0E8BD36E238566AB008B31EF /* DiscoverViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A46D22AF9763006CB87C /* DiscoverViewInput.swift */; }; - 0E8BD36F238566AB008B31EF /* LocationPickerAppleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4C22F1823C00BD4E9C /* LocationPickerAppleViewController.swift */; }; - 0E8BD370238566AB008B31EF /* TagSettingsTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2864122CBB13F0026C7A5 /* TagSettingsTableConfigurator.swift */; }; - 0E8BD372238566AB008B31EF /* SwipeDownToDismissTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA5F22CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift */; }; - 0E8BD373238566AB008B31EF /* MenuViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF222B3FEFF0032F6CA /* MenuViewInput.swift */; }; - 0E8BD374238566AB008B31EF /* ActivitySpinnerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DB822B390ED0032F6CA /* ActivitySpinnerView.swift */; }; - 0E8BD376238566AB008B31EF /* ActivityPresenterRuuviLogo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DB222B390080032F6CA /* ActivityPresenterRuuviLogo.swift */; }; - 0E8BD377238566AB008B31EF /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F622B7D2090015F9E0 /* AboutViewController.swift */; }; - 0E8BD378238566AB008B31EF /* DiscoverRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E502FBD22B2817900E8A6CC /* DiscoverRouterInput.swift */; }; - 0E8BD37A238566AB008B31EF /* DefaultsEnvironmentObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A101F2384633200A9CBA6 /* DefaultsEnvironmentObject.swift */; }; - 0E8BD37C238566AB008B31EF /* ViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A45F22AF9567006CB87C /* ViewInput.swift */; }; - 0E8BD37D238566AB008B31EF /* UserDefaults+Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0A381823616AC3003A0364 /* UserDefaults+Optional.swift */; }; - 0E8BD37E238566AB008B31EF /* TagChartsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0C6233366DC00FFA577 /* TagChartsRouterInput.swift */; }; - 0E8BD37F238566AB008B31EF /* CardsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DD222B3BF180032F6CA /* CardsViewInput.swift */; }; - 0E8BD380238566AB008B31EF /* DiscoverPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A47422AF9978006CB87C /* DiscoverPresenter.swift */; }; - 0E8BD381238566AB008B31EF /* LanguageViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF06D232007510025A191 /* LanguageViewInput.swift */; }; - 0E8BD382238566AB008B31EF /* AboutRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FA22B7D2990015F9E0 /* AboutRouter.swift */; }; - 0E8BD384238566AB008B31EF /* TagChartsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0C8233366F000FFA577 /* TagChartsRouter.swift */; }; - 0E8BD385238566AB008B31EF /* DiscoverTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A47A22AF9BE2006CB87C /* DiscoverTableInitializer.swift */; }; - 0E8BD386238566AB008B31EF /* DiscoverViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A46F22AF9790006CB87C /* DiscoverViewOutput.swift */; }; - 0E8BD387238566AB008B31EF /* DiscoverRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E502FBF22B2819B00E8A6CC /* DiscoverRouter.swift */; }; - 0E8BD388238566AB008B31EF /* WelcomeModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215022B8FD070015F9E0 /* WelcomeModuleInput.swift */; }; - 0E8BD389238566AB008B31EF /* PhotoPickerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5822CF621000172EEB /* PhotoPickerPresenter.swift */; }; - 0E8BD38A238566AB008B31EF /* LocationPickerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5422F182BF00BD4E9C /* LocationPickerPresenter.swift */; }; - 0E8BD38D238566AB008B31EF /* DefaultsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10172384613E00A9CBA6 /* DefaultsModuleInput.swift */; }; - 0E8BD390238566AB008B31EF /* TagSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863A22CBB08C0026C7A5 /* TagSettingsPresenter.swift */; }; - 0E8BD391238566AB008B31EF /* TagChartsModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0E22333893600FFA577 /* TagChartsModuleOutput.swift */; }; - 0E8BD393238566AB008B31EF /* SwipeDownToDismissInteractiveTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6322CC943900BC6D64 /* SwipeDownToDismissInteractiveTransition.swift */; }; - 0E8BD394238566AB008B31EF /* TagSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863422CBB03A0026C7A5 /* TagSettingsRouterInput.swift */; }; - 0E8BD395238566AB008B31EF /* NSObject+Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5322CCBBE800172EEB /* NSObject+Observable.swift */; }; - 0E8BD396238566AB008B31EF /* TagSettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863822CBB06C0026C7A5 /* TagSettingsModuleInput.swift */; }; - 0E8BD398238566AB008B31EF /* LocationPickerAppleConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5922F1832600BD4E9C /* LocationPickerAppleConfigurator.swift */; }; - 0E8BD399238566AB008B31EF /* AppAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DA722B387A00032F6CA /* AppAssembly.swift */; }; - 0E8BD39B238566AB008B31EF /* MenuTableDismissTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0C22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift */; }; - 0E8BD39C238566AB008B31EF /* DiscoverModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A47222AF9953006CB87C /* DiscoverModuleInput.swift */; }; - 0E8BD39E238566AB008B31EF /* SettingsTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E722B7C92C0015F9E0 /* SettingsTableConfigurator.swift */; }; - 0E8BD3A0238566AB008B31EF /* LanguageTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF07D2320086A0025A191 /* LanguageTableInitializer.swift */; }; - 0E8BD3A1238566AB008B31EF /* LocationPickerModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F6122F193B300BD4E9C /* LocationPickerModuleOutput.swift */; }; - 0E8BD3A2238566AB008B31EF /* DiscoverTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A47C22AF9BFE006CB87C /* DiscoverTableConfigurator.swift */; }; - 0E8BD3A4238566AB008B31EF /* LocationPickerViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4722F181DA00BD4E9C /* LocationPickerViewInput.swift */; }; - 0E8BD3A5238566AB008B31EF /* SettingsTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E522B7C8F20015F9E0 /* SettingsTableInitializer.swift */; }; - 0E8BD3A6238566AB008B31EF /* TagChartsTransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E341BBC2372E75C0085BB54 /* TagChartsTransitionManager.swift */; }; - 0E8BD3A7238566AB008B31EF /* ActivityRuuviLogoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DB622B390BC0032F6CA /* ActivityRuuviLogoViewController.swift */; }; - 0E8BD3A8238566AB008B31EF /* TagChartsScrollInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0CE2333676C00FFA577 /* TagChartsScrollInitializer.swift */; }; - 0E8BD3A9238566AB008B31EF /* ForegroundConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF36D23507BF00061D11B /* ForegroundConfigurator.swift */; }; - 0E8BD3AA238566AB008B31EF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64333D2820B0C45900CDF4B6 /* AppDelegate.swift */; }; - 0E8BD3AB238566AB008B31EF /* TagSettingsTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863F22CBB1340026C7A5 /* TagSettingsTableInitializer.swift */; }; - 0E8BD3B1238566AB008B31EF /* WebTagSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3E22F0702D00BD4E9C /* WebTagSettingsViewModel.swift */; }; - 0E8BD3B2238566AB008B31EF /* MainConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214322B8FBC50015F9E0 /* MainConfigurator.swift */; }; - 0E8BD3B3238566AB008B31EF /* WebTagSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3522F0581E00BD4E9C /* WebTagSettingsPresenter.swift */; }; - 0E8BD3B4238566AB008B31EF /* MenuModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFD22B3FFFC0032F6CA /* MenuModuleInput.swift */; }; - 0E8BD3B6238566AB008B31EF /* CardsScrollInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE722B3C2B60032F6CA /* CardsScrollInitializer.swift */; }; - 0E8BD3B7238566AB008B31EF /* DefaultsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10112384605A00A9CBA6 /* DefaultsTableViewController.swift */; }; - 0E8BD3BA238566AB008B31EF /* MenuTableTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0822B4024E0032F6CA /* MenuTableTransitioningDelegate.swift */; }; - 0E8BD3BB238566AB008B31EF /* ErrorPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DC022B3955E0032F6CA /* ErrorPresenter.swift */; }; - 0E8BD3BC238566AB008B31EF /* LanguageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF08123200B1B0025A191 /* LanguageTableViewCell.swift */; }; - 0E8BD3C1238566AB008B31EF /* ForegroundRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF36123506C050061D11B /* ForegroundRow.swift */; }; - 0E8BD3C2238566AB008B31EF /* SettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D722B7C8060015F9E0 /* SettingsViewOutput.swift */; }; - 0E8BD3C3238566AB008B31EF /* ForegroundPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF365235079F50061D11B /* ForegroundPresenter.swift */; }; - 0E8BD3C4238566AB008B31EF /* DiscoverNoDevicesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53A3FA232F4D5000ACED49 /* DiscoverNoDevicesTableViewCell.swift */; }; - 0E8BD3C5238566AB008B31EF /* SettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E022B7C8A90015F9E0 /* SettingsModuleInput.swift */; }; - 0E8BD3C6238566AB008B31EF /* CardsScrollConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE922B3C2E60032F6CA /* CardsScrollConfigurator.swift */; }; - 0E8BD3C9238566AB008B31EF /* WebTagSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2A22F0563100BD4E9C /* WebTagSettingsViewOutput.swift */; }; - 0E8BD3CA238566AB008B31EF /* CardsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE322B3C2710032F6CA /* CardsRouter.swift */; }; - 0E8BD3CB238566AB008B31EF /* WelcomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E09672122AE7FCF00E85F48 /* WelcomeViewController.swift */; }; - 0E8BD3CC238566AB008B31EF /* CardsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE122B3C25F0032F6CA /* CardsRouterInput.swift */; }; - 0E8BD3CD238566AB008B31EF /* WelcomeInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215522B8FD590015F9E0 /* WelcomeInitializer.swift */; }; - 0E8BD3CF238566AB008B31EF /* SettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D522B7C7E70015F9E0 /* SettingsViewInput.swift */; }; - 0E8BD3D2238566AB008B31EF /* CardsRouterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E211C29234C5FE900FC37B0 /* CardsRouterDelegate.swift */; }; - 0E8BD3D5238566AB008B31EF /* ErrorPresenterAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DC322B395C00032F6CA /* ErrorPresenterAlert.swift */; }; - 0E8BD3D6238566AB008B31EF /* ForegroundViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF358235060EF0061D11B /* ForegroundViewController.swift */; }; - 0E8BD3D8238566AB008B31EF /* ForegroundInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF36B23507BC00061D11B /* ForegroundInitializer.swift */; }; - 0E8BD3DF238566AB008B31EF /* Montserrat-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6486971120E0439200CCD7C1 /* Montserrat-Regular.ttf */; }; - 0E8BD3E0238566AB008B31EF /* About.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20EE22B7D1580015F9E0 /* About.storyboard */; }; - 0E8BD3E1238566AB008B31EF /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0ECDF1B42313D65500A09ACA /* GoogleService-Info.plist */; }; - 0E8BD3E2238566AB008B31EF /* DiscoverWebTagsInfoHeaderFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E3FF734238157B700EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.xib */; }; - 0E8BD3E4238566AB008B31EF /* Foreground.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0ECFF35623505F8D0061D11B /* Foreground.storyboard */; }; - 0E8BD3E5238566AB008B31EF /* LocationPicker.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E046F4522F17EF400BD4E9C /* LocationPicker.storyboard */; }; - 0E8BD3E6238566AB008B31EF /* Defaults.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E8A100123845E5100A9CBA6 /* Defaults.storyboard */; }; - 0E8BD3E7238566AB008B31EF /* Cards.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C1DD022B3BDFC0032F6CA /* Cards.storyboard */; }; - 0E8BD3E8238566AB008B31EF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 64333D3120B0C45A00CDF4B6 /* LaunchScreen.storyboard */; }; - 0E8BD3EA238566AB008B31EF /* Oswald-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6486970F20E042E000CCD7C1 /* Oswald-Bold.ttf */; }; - 0E8BD3EB238566AB008B31EF /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20C922B7A7200015F9E0 /* Localizable.strings */; }; - 0E8BD3EC238566AB008B31EF /* Discover.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E09672722AE8D7A00E85F48 /* Discover.storyboard */; }; - 0E8BD3ED238566AB008B31EF /* TagSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EF2862B22CBAF5D0026C7A5 /* TagSettings.storyboard */; }; - 0E8BD3EE238566AB008B31EF /* TagCharts.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E8FD0BE23335D6900FFA577 /* TagCharts.storyboard */; }; - 0E8BD3EF238566AB008B31EF /* Muli-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6467818F225CFB170072856A /* Muli-Regular.ttf */; }; - 0E8BD3F0238566AB008B31EF /* Oswald-ExtraLight.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 643EEC2A2266435100D4E837 /* Oswald-ExtraLight.ttf */; }; - 0E8BD3F1238566AB008B31EF /* Language.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EBAF06B232006E00025A191 /* Language.storyboard */; }; - 0E8BD3F2238566AB008B31EF /* Welcome.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E09671F22AE7F5C00E85F48 /* Welcome.storyboard */; }; - 0E8BD3F3238566AB008B31EF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0E53A3F3232DFC6200ACED49 /* InfoPlist.strings */; }; - 0E8BD3F4238566AB008B31EF /* ActivityRuuviLogo.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C1DB422B3903B0032F6CA /* ActivityRuuviLogo.storyboard */; }; - 0E8BD3F5238566AB008B31EF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 64333D2F20B0C45A00CDF4B6 /* Assets.xcassets */; }; - 0E8BD3F7238566AB008B31EF /* CardView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C1E1222B756D30032F6CA /* CardView.xib */; }; - 0E8BD3F8238566AB008B31EF /* Menu.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF022B3FDE30032F6CA /* Menu.storyboard */; }; - 0E8BD3F9238566AB008B31EF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 64333D2C20B0C45900CDF4B6 /* Main.storyboard */; }; - 0E8BD3FA238566AB008B31EF /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20D022B7C6F30015F9E0 /* Settings.storyboard */; }; - 0E8BD3FB238566AB008B31EF /* Muli-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 64678190225D02CE0072856A /* Muli-Bold.ttf */; }; - 0E8BD3FC238566AB008B31EF /* TagSettingsMoreInfoHeaderFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E62AECA22E065F000A49BFB /* TagSettingsMoreInfoHeaderFooterView.xib */; }; - 0E8BD3FD238566AB008B31EF /* Montserrat-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 643C651E21C38F490037BE5B /* Montserrat-Bold.ttf */; }; - 0E8BD3FE238566AB008B31EF /* WebTagSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E046F2622F04A0300BD4E9C /* WebTagSettings.storyboard */; }; - 0E8E3D60268227530082EC29 /* RuuviCoreError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8E3D5E268227530082EC29 /* RuuviCoreError+LocalizedError.swift */; }; - 0E8E3D61268227530082EC29 /* RuuviCoreError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8E3D5E268227530082EC29 /* RuuviCoreError+LocalizedError.swift */; }; - 0E8E3D62268227530082EC29 /* RuuviVirtualError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8E3D5F268227530082EC29 /* RuuviVirtualError+LocalizedError.swift */; }; - 0E8E3D63268227530082EC29 /* RuuviVirtualError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8E3D5F268227530082EC29 /* RuuviVirtualError+LocalizedError.swift */; }; - 0E8E3D6A268228130082EC29 /* DiscoverRuuviTagViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8E3D68268228130082EC29 /* DiscoverRuuviTagViewModel.swift */; }; - 0E8E3D6B268228130082EC29 /* DiscoverRuuviTagViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8E3D68268228130082EC29 /* DiscoverRuuviTagViewModel.swift */; }; - 0E8E3D6C268228130082EC29 /* DiscoverVirtualTagViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8E3D69268228130082EC29 /* DiscoverVirtualTagViewModel.swift */; }; - 0E8E3D6D268228130082EC29 /* DiscoverVirtualTagViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8E3D69268228130082EC29 /* DiscoverVirtualTagViewModel.swift */; }; - 0E8E3D70268228760082EC29 /* RuuviVirtual in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D6F268228760082EC29 /* RuuviVirtual */; }; - 0E8E3D72268228760082EC29 /* RuuviVirtualModel in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D71268228760082EC29 /* RuuviVirtualModel */; }; - 0E8E3D74268228760082EC29 /* RuuviVirtualOWM in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D73268228760082EC29 /* RuuviVirtualOWM */; }; - 0E8E3D76268228760082EC29 /* RuuviVirtualPersistence in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D75268228760082EC29 /* RuuviVirtualPersistence */; }; - 0E8E3D78268228760082EC29 /* RuuviVirtualReactor in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D77268228760082EC29 /* RuuviVirtualReactor */; }; - 0E8E3D7A268228760082EC29 /* RuuviVirtualRepository in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D79268228760082EC29 /* RuuviVirtualRepository */; }; - 0E8E3D7C268228760082EC29 /* RuuviVirtualService in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D7B268228760082EC29 /* RuuviVirtualService */; }; - 0E8E3D7E268228760082EC29 /* RuuviVirtualStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D7D268228760082EC29 /* RuuviVirtualStorage */; }; - 0E8E3D80268228820082EC29 /* RuuviVirtual in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D7F268228820082EC29 /* RuuviVirtual */; }; - 0E8E3D82268228820082EC29 /* RuuviVirtualModel in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D81268228820082EC29 /* RuuviVirtualModel */; }; - 0E8E3D84268228820082EC29 /* RuuviVirtualOWM in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D83268228820082EC29 /* RuuviVirtualOWM */; }; - 0E8E3D86268228820082EC29 /* RuuviVirtualPersistence in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D85268228820082EC29 /* RuuviVirtualPersistence */; }; - 0E8E3D88268228820082EC29 /* RuuviVirtualReactor in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D87268228820082EC29 /* RuuviVirtualReactor */; }; - 0E8E3D8A268228820082EC29 /* RuuviVirtualRepository in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D89268228820082EC29 /* RuuviVirtualRepository */; }; - 0E8E3D8C268228820082EC29 /* RuuviVirtualService in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D8B268228820082EC29 /* RuuviVirtualService */; }; - 0E8E3D8E268228820082EC29 /* RuuviVirtualStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D8D268228820082EC29 /* RuuviVirtualStorage */; }; - 0E8E3D9C26822ADD0082EC29 /* RuuviLocation in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D9B26822ADD0082EC29 /* RuuviLocation */; }; - 0E8E3D9E26822ADD0082EC29 /* RuuviLocationService in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D9D26822ADD0082EC29 /* RuuviLocationService */; }; - 0E8E3DA026822AE40082EC29 /* RuuviLocation in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3D9F26822AE40082EC29 /* RuuviLocation */; }; - 0E8E3DA226822AE40082EC29 /* RuuviLocationService in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3DA126822AE40082EC29 /* RuuviLocationService */; }; - 0E8E3DA426822B0D0082EC29 /* RuuviCoreLocation in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3DA326822B0D0082EC29 /* RuuviCoreLocation */; }; - 0E8E3DA626822B130082EC29 /* RuuviCoreLocation in Frameworks */ = {isa = PBXBuildFile; productRef = 0E8E3DA526822B130082EC29 /* RuuviCoreLocation */; }; - 0E8FD0BF23335D6900FFA577 /* TagCharts.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E8FD0BE23335D6900FFA577 /* TagCharts.storyboard */; }; - 0E8FD0C123335D8400FFA577 /* TagChartsScrollViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0C023335D8400FFA577 /* TagChartsScrollViewController.swift */; }; - 0E8FD0C323335DA700FFA577 /* TagChartsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0C223335DA700FFA577 /* TagChartsViewInput.swift */; }; - 0E8FD0C523335DBF00FFA577 /* TagChartsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0C423335DBF00FFA577 /* TagChartsViewOutput.swift */; }; - 0E8FD0C7233366DC00FFA577 /* TagChartsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0C6233366DC00FFA577 /* TagChartsRouterInput.swift */; }; - 0E8FD0C9233366F000FFA577 /* TagChartsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0C8233366F000FFA577 /* TagChartsRouter.swift */; }; - 0E8FD0CB2333671100FFA577 /* TagChartsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0CA2333671100FFA577 /* TagChartsModuleInput.swift */; }; - 0E8FD0CD2333672F00FFA577 /* TagChartsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0CC2333672F00FFA577 /* TagChartsPresenter.swift */; }; - 0E8FD0CF2333676C00FFA577 /* TagChartsScrollInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0CE2333676C00FFA577 /* TagChartsScrollInitializer.swift */; }; - 0E8FD0D12333679800FFA577 /* TagChartsScrollConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0D02333679800FFA577 /* TagChartsScrollConfigurator.swift */; }; - 0E8FD0D323336B4200FFA577 /* TagChartsTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0D223336B4200FFA577 /* TagChartsTransitioningDelegate.swift */; }; - 0E8FD0D523336BA300FFA577 /* TagChartsPresentTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0D423336BA300FFA577 /* TagChartsPresentTransitionAnimation.swift */; }; - 0E8FD0D723336C6E00FFA577 /* TagChartsDismissTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0D623336C6E00FFA577 /* TagChartsDismissTransitionAnimation.swift */; }; - 0E8FD0DD2333714C00FFA577 /* TagChartsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0DC2333714C00FFA577 /* TagChartsViewModel.swift */; }; - 0E8FD0E32333893600FFA577 /* TagChartsModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0E22333893600FFA577 /* TagChartsModuleOutput.swift */; }; - 0E92A9552686366D00187E4F /* TemperatureUnit+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A94C2686366C00187E4F /* TemperatureUnit+Localization.swift */; }; - 0E92A9562686366D00187E4F /* TemperatureUnit+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A94C2686366C00187E4F /* TemperatureUnit+Localization.swift */; }; - 0E92A9572686366D00187E4F /* ExportHeadersProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A94E2686366C00187E4F /* ExportHeadersProvider.swift */; }; - 0E92A9582686366D00187E4F /* ExportHeadersProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A94E2686366C00187E4F /* ExportHeadersProvider.swift */; }; - 0E92A9592686366D00187E4F /* HeartbeatDaemonTitles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A94F2686366C00187E4F /* HeartbeatDaemonTitles.swift */; }; - 0E92A95A2686366D00187E4F /* HeartbeatDaemonTitles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A94F2686366C00187E4F /* HeartbeatDaemonTitles.swift */; }; - 0E92A95B2686366D00187E4F /* RuuviNotifierTitlesImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9502686366C00187E4F /* RuuviNotifierTitlesImpl.swift */; }; - 0E92A95C2686366D00187E4F /* RuuviNotifierTitlesImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9502686366C00187E4F /* RuuviNotifierTitlesImpl.swift */; }; - 0E92A95D2686366D00187E4F /* MeasurementType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9512686366C00187E4F /* MeasurementType.swift */; }; - 0E92A95E2686366D00187E4F /* MeasurementType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9512686366C00187E4F /* MeasurementType.swift */; }; - 0E92A95F2686366D00187E4F /* HumidityUnit+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9522686366C00187E4F /* HumidityUnit+Localization.swift */; }; - 0E92A9602686366D00187E4F /* HumidityUnit+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9522686366C00187E4F /* HumidityUnit+Localization.swift */; }; - 0E92A9612686366D00187E4F /* Language+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9532686366D00187E4F /* Language+Localization.swift */; }; - 0E92A9622686366D00187E4F /* Language+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9532686366D00187E4F /* Language+Localization.swift */; }; - 0E92A9632686366D00187E4F /* VirtualLocation+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9542686366D00187E4F /* VirtualLocation+Localization.swift */; }; - 0E92A9642686366D00187E4F /* VirtualLocation+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9542686366D00187E4F /* VirtualLocation+Localization.swift */; }; - 0E92A9662686368000187E4F /* RUError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9652686367F00187E4F /* RUError.swift */; }; - 0E92A9672686368000187E4F /* RUError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9652686367F00187E4F /* RUError.swift */; }; - 0E92A9692686369200187E4F /* DateValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9682686369200187E4F /* DateValueFormatter.swift */; }; - 0E92A96A2686369200187E4F /* DateValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9682686369200187E4F /* DateValueFormatter.swift */; }; - 0E92A96C2686369E00187E4F /* Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A96B2686369E00187E4F /* Debouncer.swift */; }; - 0E92A96D2686369E00187E4F /* Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A96B2686369E00187E4F /* Debouncer.swift */; }; - 0E92A96F268636A700187E4F /* RuuviServiceGATT in Frameworks */ = {isa = PBXBuildFile; productRef = 0E92A96E268636A700187E4F /* RuuviServiceGATT */; }; - 0E92A971268636AE00187E4F /* RuuviServiceGATT in Frameworks */ = {isa = PBXBuildFile; productRef = 0E92A970268636AE00187E4F /* RuuviServiceGATT */; }; - 0E9D0AB1231EBEFD00C6BDA7 /* LocalizationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9D0AB0231EBEFD00C6BDA7 /* LocalizationService.swift */; }; - 0E9D5F202351BE3C0076FFD8 /* ForegroundSwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9D5F1F2351BE3C0076FFD8 /* ForegroundSwitchTableViewCell.swift */; }; - 0E9E775A238CCE5F006D7013 /* String+Replace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9E7759238CCE5F006D7013 /* String+Replace.swift */; }; - 0E9E775B238CCE5F006D7013 /* String+Replace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9E7759238CCE5F006D7013 /* String+Replace.swift */; }; - 0E9F979622EAFC820015ADE2 /* DiscoverWebTagTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9F979522EAFC820015ADE2 /* DiscoverWebTagTableViewCell.swift */; }; - 0EA796712664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796702664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift */; }; - 0EA796722664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796702664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift */; }; - 0EA796752664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796742664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift */; }; - 0EA796762664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796742664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift */; }; - 0EA796792664B37F002BA25D /* RuuviLocalError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796782664B37F002BA25D /* RuuviLocalError+LocalizedError.swift */; }; - 0EA7967A2664B37F002BA25D /* RuuviLocalError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796782664B37F002BA25D /* RuuviLocalError+LocalizedError.swift */; }; - 0EA7967D2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA7967C2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift */; }; - 0EA7967E2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA7967C2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift */; }; - 0EA796812664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796802664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift */; }; - 0EA796822664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796802664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift */; }; - 0EA796852664B84D002BA25D /* RuuviReactorError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796842664B84D002BA25D /* RuuviReactorError+LocalizedError.swift */; }; - 0EA796862664B84D002BA25D /* RuuviReactorError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796842664B84D002BA25D /* RuuviReactorError+LocalizedError.swift */; }; - 0EA796892664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796882664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift */; }; - 0EA7968A2664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796882664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift */; }; - 0EA7968D2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA7968C2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift */; }; - 0EA7968E2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA7968C2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift */; }; - 0EA92FDB2387E734008F1558 /* TagSettingsAlertsHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA92FDA2387E734008F1558 /* TagSettingsAlertsHeaderFooterView.swift */; }; - 0EA92FDC2387E734008F1558 /* TagSettingsAlertsHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA92FDA2387E734008F1558 /* TagSettingsAlertsHeaderFooterView.swift */; }; - 0EA92FDF2387E74C008F1558 /* TagSettingsAlertsHeaderFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0EA92FDE2387E74C008F1558 /* TagSettingsAlertsHeaderFooterView.xib */; }; - 0EA92FE02387E74C008F1558 /* TagSettingsAlertsHeaderFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0EA92FDE2387E74C008F1558 /* TagSettingsAlertsHeaderFooterView.xib */; }; - 0EAD33D52399271C00EC5BAA /* DiscoverModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF4C239795AF00A37E1A /* DiscoverModuleOutput.swift */; }; - 0EAD33D72399273D00EC5BAA /* Heartbeat.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E84BF542397F29800A37E1A /* Heartbeat.storyboard */; }; - 0EAD33D82399273D00EC5BAA /* HeartbeatInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF6E2398031B00A37E1A /* HeartbeatInitializer.swift */; }; - 0EAD33D92399273D00EC5BAA /* HeartbeatConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF702398035C00A37E1A /* HeartbeatConfigurator.swift */; }; - 0EAD33DA2399273D00EC5BAA /* HeartbeatModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF6A239802A400A37E1A /* HeartbeatModuleInput.swift */; }; - 0EAD33DB2399273D00EC5BAA /* HeartbeatPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF6C239802CA00A37E1A /* HeartbeatPresenter.swift */; }; - 0EAD33DC2399273D00EC5BAA /* HeartbeatRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF66239801AF00A37E1A /* HeartbeatRouterInput.swift */; }; - 0EAD33DD2399273D00EC5BAA /* HeartbeatRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF68239801C100A37E1A /* HeartbeatRouter.swift */; }; - 0EAD33DE2399273D00EC5BAA /* HeartbeatList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF622397F76A00A37E1A /* HeartbeatList.swift */; }; - 0EAD33DF2399273D00EC5BAA /* HeartbeatEnvironmentObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF602397F73100A37E1A /* HeartbeatEnvironmentObject.swift */; }; - 0EAD33E02399273D00EC5BAA /* HeartbeatTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF642397F9DC00A37E1A /* HeartbeatTableViewController.swift */; }; - 0EAD33E12399273D00EC5BAA /* HeartbeatViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF562397F33E00A37E1A /* HeartbeatViewInput.swift */; }; - 0EAD33E22399273D00EC5BAA /* HeartbeatViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF582397F3C600A37E1A /* HeartbeatViewModel.swift */; }; - 0EAD33E32399273D00EC5BAA /* HeartbeatViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF5A2397F3DF00A37E1A /* HeartbeatViewOutput.swift */; }; - 0EAD33E42399273D00EC5BAA /* HeartbeatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF5E2397F6BE00A37E1A /* HeartbeatViewController.swift */; }; - 0EB48DE6261A1816008E0D2D /* FeatureToggles.json in Resources */ = {isa = PBXBuildFile; fileRef = 0EB48DE5261A1816008E0D2D /* FeatureToggles.json */; }; - 0EB48DE7261A1816008E0D2D /* FeatureToggles.json in Resources */ = {isa = PBXBuildFile; fileRef = 0EB48DE5261A1816008E0D2D /* FeatureToggles.json */; }; - 0EB66B182686053800375BCC /* FeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B0A2686053800375BCC /* FeatureToggleProvider.swift */; }; - 0EB66B192686053800375BCC /* FeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B0A2686053800375BCC /* FeatureToggleProvider.swift */; }; - 0EB66B1A2686053800375BCC /* FallbackFeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B0B2686053800375BCC /* FallbackFeatureToggleProvider.swift */; }; - 0EB66B1B2686053800375BCC /* FallbackFeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B0B2686053800375BCC /* FallbackFeatureToggleProvider.swift */; }; - 0EB66B1C2686053800375BCC /* FirebaseFeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B0C2686053800375BCC /* FirebaseFeatureToggleProvider.swift */; }; - 0EB66B1D2686053800375BCC /* FirebaseFeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B0C2686053800375BCC /* FirebaseFeatureToggleProvider.swift */; }; - 0EB66B1E2686053800375BCC /* LocalFeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B0D2686053800375BCC /* LocalFeatureToggleProvider.swift */; }; - 0EB66B1F2686053800375BCC /* LocalFeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B0D2686053800375BCC /* LocalFeatureToggleProvider.swift */; }; - 0EB66B202686053800375BCC /* FirebaseRemoteConfigService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B102686053800375BCC /* FirebaseRemoteConfigService.swift */; }; - 0EB66B212686053800375BCC /* FirebaseRemoteConfigService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B102686053800375BCC /* FirebaseRemoteConfigService.swift */; }; - 0EB66B222686053800375BCC /* RemoteConfigService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B112686053800375BCC /* RemoteConfigService.swift */; }; - 0EB66B232686053800375BCC /* RemoteConfigService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B112686053800375BCC /* RemoteConfigService.swift */; }; - 0EB66B242686053800375BCC /* FeatureToggleService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B122686053800375BCC /* FeatureToggleService.swift */; }; - 0EB66B252686053800375BCC /* FeatureToggleService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B122686053800375BCC /* FeatureToggleService.swift */; }; - 0EB66B262686053800375BCC /* FeatureToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B132686053800375BCC /* FeatureToggle.swift */; }; - 0EB66B272686053800375BCC /* FeatureToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B132686053800375BCC /* FeatureToggle.swift */; }; - 0EB66B282686053800375BCC /* InfoProviderImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B162686053800375BCC /* InfoProviderImpl.swift */; }; - 0EB66B292686053800375BCC /* InfoProviderImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B162686053800375BCC /* InfoProviderImpl.swift */; }; - 0EB66B2A2686053800375BCC /* InfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B172686053800375BCC /* InfoProvider.swift */; }; - 0EB66B2B2686053800375BCC /* InfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B172686053800375BCC /* InfoProvider.swift */; }; - 0EB8B9142683519200FE130E /* RuuviMigration in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB8B9132683519200FE130E /* RuuviMigration */; }; - 0EB8B9162683519200FE130E /* RuuviMigrationImpl in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB8B9152683519200FE130E /* RuuviMigrationImpl */; }; - 0EB8B9182683519900FE130E /* RuuviMigration in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB8B9172683519900FE130E /* RuuviMigration */; }; - 0EB8B91A2683519900FE130E /* RuuviMigrationImpl in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB8B9192683519900FE130E /* RuuviMigrationImpl */; }; - 0EB8B9272683592700FE130E /* Networking.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0EB8B9262683592700FE130E /* Networking.plist */; }; - 0EB8B9282683592700FE130E /* Networking.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0EB8B9262683592700FE130E /* Networking.plist */; }; - 0EB8B93026837A4700FE130E /* RuuviCoreDiff in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB8B92F26837A4700FE130E /* RuuviCoreDiff */; }; - 0EB8B93226837A4700FE130E /* RuuviCorePermission in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB8B93126837A4700FE130E /* RuuviCorePermission */; }; - 0EB8B93426837A4700FE130E /* RuuviCorePN in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB8B93326837A4700FE130E /* RuuviCorePN */; }; - 0EB8B93626837A5100FE130E /* RuuviCoreDiff in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB8B93526837A5100FE130E /* RuuviCoreDiff */; }; - 0EB8B93826837A5100FE130E /* RuuviCorePermission in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB8B93726837A5100FE130E /* RuuviCorePermission */; }; - 0EB8B93A26837A5100FE130E /* RuuviCorePN in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB8B93926837A5100FE130E /* RuuviCorePN */; }; - 0EBAF06C232006E00025A191 /* Language.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EBAF06B232006E00025A191 /* Language.storyboard */; }; - 0EBAF06E232007510025A191 /* LanguageViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF06D232007510025A191 /* LanguageViewInput.swift */; }; - 0EBAF070232007740025A191 /* LanguageViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF06F232007740025A191 /* LanguageViewOutput.swift */; }; - 0EBAF072232007910025A191 /* LanguageTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF071232007910025A191 /* LanguageTableViewController.swift */; }; - 0EBAF075232007CC0025A191 /* LanguageRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF074232007CC0025A191 /* LanguageRouterInput.swift */; }; - 0EBAF077232007D80025A191 /* LanguageRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF076232007D80025A191 /* LanguageRouter.swift */; }; - 0EBAF079232008140025A191 /* LanguageModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF078232008140025A191 /* LanguageModuleInput.swift */; }; - 0EBAF07B232008420025A191 /* LanguagePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF07A232008420025A191 /* LanguagePresenter.swift */; }; - 0EBAF07E2320086A0025A191 /* LanguageTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF07D2320086A0025A191 /* LanguageTableInitializer.swift */; }; - 0EBAF0802320089A0025A191 /* LanguageTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF07F2320089A0025A191 /* LanguageTableConfigurator.swift */; }; - 0EBAF08223200B1B0025A191 /* LanguageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF08123200B1B0025A191 /* LanguageTableViewCell.swift */; }; - 0EC50F5022CCB92000172EEB /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F4F22CCB92000172EEB /* Observable.swift */; }; - 0EC50F5222CCB9DE00172EEB /* TagSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5122CCB9DE00172EEB /* TagSettingsViewModel.swift */; }; - 0EC50F5422CCBBE800172EEB /* NSObject+Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5322CCBBE800172EEB /* NSObject+Observable.swift */; }; - 0EC50F5622CCE46D00172EEB /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5522CCE46D00172EEB /* Optional.swift */; }; - 0EC50F5922CF621000172EEB /* PhotoPickerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5822CF621000172EEB /* PhotoPickerPresenter.swift */; }; - 0ECB5A8E2381807500E78757 /* CardsScrollViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECB5A8D2381807500E78757 /* CardsScrollViewController.swift */; }; - 0ECDF1B52313D65500A09ACA /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0ECDF1B42313D65500A09ACA /* GoogleService-Info.plist */; }; - 0ECFF355235056DC0061D11B /* ForegroundList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF354235056DC0061D11B /* ForegroundList.swift */; }; - 0ECFF35723505F8D0061D11B /* Foreground.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0ECFF35623505F8D0061D11B /* Foreground.storyboard */; }; - 0ECFF359235060EF0061D11B /* ForegroundViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF358235060EF0061D11B /* ForegroundViewController.swift */; }; - 0ECFF35B2350618E0061D11B /* ForegroundModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF35A2350618E0061D11B /* ForegroundModuleInput.swift */; }; - 0ECFF35E23506BC40061D11B /* ForegroundViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF35D23506BC40061D11B /* ForegroundViewOutput.swift */; }; - 0ECFF36023506BD60061D11B /* ForegroundViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF35F23506BD60061D11B /* ForegroundViewInput.swift */; }; - 0ECFF36223506C050061D11B /* ForegroundRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF36123506C050061D11B /* ForegroundRow.swift */; }; - 0ECFF366235079F50061D11B /* ForegroundPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF365235079F50061D11B /* ForegroundPresenter.swift */; }; - 0ECFF36823507A1A0061D11B /* ForegroundRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF36723507A1A0061D11B /* ForegroundRouterInput.swift */; }; - 0ECFF36C23507BC00061D11B /* ForegroundInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF36B23507BC00061D11B /* ForegroundInitializer.swift */; }; - 0ECFF36E23507BF00061D11B /* ForegroundConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF36D23507BF00061D11B /* ForegroundConfigurator.swift */; }; - 0ECFF37023507CE80061D11B /* ForegroundViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF36F23507CE80061D11B /* ForegroundViewModel.swift */; }; - 0EE36E5C269748A80021B746 /* FirmwareRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E46269748A70021B746 /* FirmwareRepository.swift */; }; - 0EE36E5D269748A80021B746 /* FirmwareRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E46269748A70021B746 /* FirmwareRepository.swift */; }; - 0EE36E5E269748A80021B746 /* DFUModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E48269748A70021B746 /* DFUModuleInput.swift */; }; - 0EE36E5F269748A80021B746 /* DFUModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E48269748A70021B746 /* DFUModuleInput.swift */; }; - 0EE36E60269748A80021B746 /* DFUPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E49269748A70021B746 /* DFUPresenter.swift */; }; - 0EE36E61269748A80021B746 /* DFUPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E49269748A70021B746 /* DFUPresenter.swift */; }; - 0EE36E62269748A80021B746 /* Publishers+System.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E4B269748A70021B746 /* Publishers+System.swift */; }; - 0EE36E63269748A80021B746 /* Publishers+System.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E4B269748A70021B746 /* Publishers+System.swift */; }; - 0EE36E64269748A80021B746 /* URLSession+downloadTaskPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E4C269748A70021B746 /* URLSession+downloadTaskPublisher.swift */; }; - 0EE36E65269748A80021B746 /* URLSession+downloadTaskPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E4C269748A70021B746 /* URLSession+downloadTaskPublisher.swift */; }; - 0EE36E66269748A80021B746 /* View+Any.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E4D269748A70021B746 /* View+Any.swift */; }; - 0EE36E67269748A80021B746 /* View+Any.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E4D269748A70021B746 /* View+Any.swift */; }; - 0EE36E68269748A80021B746 /* Spinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E4F269748A70021B746 /* Spinner.swift */; }; - 0EE36E69269748A80021B746 /* Spinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E4F269748A70021B746 /* Spinner.swift */; }; - 0EE36E6A269748A80021B746 /* LargeButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E50269748A70021B746 /* LargeButtonStyle.swift */; }; - 0EE36E6B269748A80021B746 /* LargeButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E50269748A70021B746 /* LargeButtonStyle.swift */; }; - 0EE36E6C269748A80021B746 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E51269748A70021B746 /* ProgressBar.swift */; }; - 0EE36E6D269748A80021B746 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E51269748A70021B746 /* ProgressBar.swift */; }; - 0EE36E6E269748A80021B746 /* Feedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E52269748A70021B746 /* Feedback.swift */; }; - 0EE36E6F269748A80021B746 /* Feedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E52269748A70021B746 /* Feedback.swift */; }; - 0EE36E70269748A80021B746 /* DFUViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E54269748A70021B746 /* DFUViewModel.swift */; }; - 0EE36E71269748A80021B746 /* DFUViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E54269748A70021B746 /* DFUViewModel.swift */; }; - 0EE36E72269748A80021B746 /* DFUUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E56269748A70021B746 /* DFUUIView.swift */; }; - 0EE36E73269748A80021B746 /* DFUUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E56269748A70021B746 /* DFUUIView.swift */; }; - 0EE36E74269748A80021B746 /* DFUInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E58269748A70021B746 /* DFUInteractorInput.swift */; }; - 0EE36E75269748A80021B746 /* DFUInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E58269748A70021B746 /* DFUInteractorInput.swift */; }; - 0EE36E76269748A80021B746 /* DFUInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E59269748A70021B746 /* DFUInteractor.swift */; }; - 0EE36E77269748A80021B746 /* DFUInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E59269748A70021B746 /* DFUInteractor.swift */; }; - 0EE36E78269748A80021B746 /* LatestRelease.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E5A269748A70021B746 /* LatestRelease.swift */; }; - 0EE36E79269748A80021B746 /* LatestRelease.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E5A269748A70021B746 /* LatestRelease.swift */; }; - 0EE36E7A269748A80021B746 /* DFUModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E5B269748A70021B746 /* DFUModuleFactory.swift */; }; - 0EE36E7B269748A80021B746 /* DFUModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E5B269748A70021B746 /* DFUModuleFactory.swift */; }; - 0EE36E7E269749280021B746 /* RuuviColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E7D269749270021B746 /* RuuviColor.swift */; }; - 0EE36E7F269749280021B746 /* RuuviColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E7D269749270021B746 /* RuuviColor.swift */; }; - 0EE36EB9269F054E0021B746 /* Charts in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE36EB8269F054E0021B746 /* Charts */; }; - 0EE36EBB269F05600021B746 /* Charts in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE36EBA269F05600021B746 /* Charts */; }; - 0EE49B9523B74775003012C2 /* WebTagSettingsAlertHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE49B9423B74775003012C2 /* WebTagSettingsAlertHeaderCell.swift */; }; - 0EE49B9623B74775003012C2 /* WebTagSettingsAlertHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE49B9423B74775003012C2 /* WebTagSettingsAlertHeaderCell.swift */; }; - 0EE49B9923B877CF003012C2 /* WebTagSettingsAlertControlsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE49B9823B877CF003012C2 /* WebTagSettingsAlertControlsCell.swift */; }; - 0EE49B9A23B877CF003012C2 /* WebTagSettingsAlertControlsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE49B9823B877CF003012C2 /* WebTagSettingsAlertControlsCell.swift */; }; - 0EE5B47D23508F6D00D5ED32 /* ForegroundEnvironmentObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE5B47C23508F6D00D5ED32 /* ForegroundEnvironmentObject.swift */; }; - 0EE98A7926493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE98A7826493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift */; }; - 0EE98A7A26493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE98A7826493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift */; }; - 0EEB20C622B7915C0015F9E0 /* CardsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20C522B7915C0015F9E0 /* CardsViewModel.swift */; }; - 0EEB20C722B7A7200015F9E0 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20C922B7A7200015F9E0 /* Localizable.strings */; }; - 0EEB20CB22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20CA22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift */; }; - 0EEB20CD22B7BD6C0015F9E0 /* MenuModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20CC22B7BD6C0015F9E0 /* MenuModuleOutput.swift */; }; - 0EEB20D122B7C6F30015F9E0 /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20D022B7C6F30015F9E0 /* Settings.storyboard */; }; - 0EEB20D322B7C7AC0015F9E0 /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D222B7C7AC0015F9E0 /* SettingsTableViewController.swift */; }; - 0EEB20D622B7C7E70015F9E0 /* SettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D522B7C7E70015F9E0 /* SettingsViewInput.swift */; }; - 0EEB20D822B7C8060015F9E0 /* SettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D722B7C8060015F9E0 /* SettingsViewOutput.swift */; }; - 0EEB20DD22B7C8650015F9E0 /* SettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20DC22B7C8650015F9E0 /* SettingsRouterInput.swift */; }; - 0EEB20DF22B7C8790015F9E0 /* SettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20DE22B7C8790015F9E0 /* SettingsRouter.swift */; }; - 0EEB20E122B7C8A90015F9E0 /* SettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E022B7C8A90015F9E0 /* SettingsModuleInput.swift */; }; - 0EEB20E322B7C8C10015F9E0 /* SettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E222B7C8C10015F9E0 /* SettingsPresenter.swift */; }; - 0EEB20E622B7C8F20015F9E0 /* SettingsTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E522B7C8F20015F9E0 /* SettingsTableInitializer.swift */; }; - 0EEB20E822B7C92C0015F9E0 /* SettingsTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E722B7C92C0015F9E0 /* SettingsTableConfigurator.swift */; }; - 0EEB20EF22B7D1580015F9E0 /* About.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20EE22B7D1580015F9E0 /* About.storyboard */; }; - 0EEB20F322B7D1900015F9E0 /* AboutViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F222B7D1900015F9E0 /* AboutViewInput.swift */; }; - 0EEB20F522B7D1A40015F9E0 /* AboutViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F422B7D1A40015F9E0 /* AboutViewOutput.swift */; }; - 0EEB20F722B7D2090015F9E0 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F622B7D2090015F9E0 /* AboutViewController.swift */; }; - 0EEB20F922B7D28C0015F9E0 /* AboutRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F822B7D28C0015F9E0 /* AboutRouterInput.swift */; }; - 0EEB20FB22B7D2990015F9E0 /* AboutRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FA22B7D2990015F9E0 /* AboutRouter.swift */; }; - 0EEB20FD22B7D2C90015F9E0 /* AboutModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FC22B7D2C90015F9E0 /* AboutModuleInput.swift */; }; - 0EEB20FF22B7D2DD0015F9E0 /* AboutPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FE22B7D2DD0015F9E0 /* AboutPresenter.swift */; }; - 0EEB210122B7D2F50015F9E0 /* AboutInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB210022B7D2F50015F9E0 /* AboutInitializer.swift */; }; - 0EEB210322B7D3220015F9E0 /* AboutConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB210222B7D3210015F9E0 /* AboutConfigurator.swift */; }; - 0EEB213C22B8FAD50015F9E0 /* MainRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB213B22B8FAD50015F9E0 /* MainRouter.swift */; }; - 0EEB213F22B8FB840015F9E0 /* MainNavigationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB213E22B8FB840015F9E0 /* MainNavigationDelegate.swift */; }; - 0EEB214222B8FBA50015F9E0 /* MainInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214122B8FBA50015F9E0 /* MainInitializer.swift */; }; - 0EEB214422B8FBC50015F9E0 /* MainConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214322B8FBC50015F9E0 /* MainConfigurator.swift */; }; - 0EEB214722B8FC3E0015F9E0 /* WelcomeViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214622B8FC3E0015F9E0 /* WelcomeViewInput.swift */; }; - 0EEB214922B8FC570015F9E0 /* WelcomeViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214822B8FC570015F9E0 /* WelcomeViewOutput.swift */; }; - 0EEB214C22B8FCC70015F9E0 /* WelcomeRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214B22B8FCC70015F9E0 /* WelcomeRouterInput.swift */; }; - 0EEB214E22B8FCDC0015F9E0 /* WelcomeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214D22B8FCDC0015F9E0 /* WelcomeRouter.swift */; }; - 0EEB215122B8FD070015F9E0 /* WelcomeModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215022B8FD070015F9E0 /* WelcomeModuleInput.swift */; }; - 0EEB215322B8FD1F0015F9E0 /* WelcomePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215222B8FD1F0015F9E0 /* WelcomePresenter.swift */; }; - 0EEB215622B8FD590015F9E0 /* WelcomeInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215522B8FD590015F9E0 /* WelcomeInitializer.swift */; }; - 0EEB215822B8FD800015F9E0 /* WelcomeConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215722B8FD800015F9E0 /* WelcomeConfigurator.swift */; }; - 0EEB215A22BA28860015F9E0 /* MenuTableTransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215922BA28860015F9E0 /* MenuTableTransitionManager.swift */; }; - 0EEEBDE626860F6700589D56 /* RuuviAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 0EEEBDE526860F6700589D56 /* RuuviAnalytics */; }; - 0EEEBDE826860F6700589D56 /* RuuviAnalyticsImpl in Frameworks */ = {isa = PBXBuildFile; productRef = 0EEEBDE726860F6700589D56 /* RuuviAnalyticsImpl */; }; - 0EEEBDEA26860F6D00589D56 /* RuuviAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 0EEEBDE926860F6D00589D56 /* RuuviAnalytics */; }; - 0EEEBDEC26860F6D00589D56 /* RuuviAnalyticsImpl in Frameworks */ = {isa = PBXBuildFile; productRef = 0EEEBDEB26860F6D00589D56 /* RuuviAnalyticsImpl */; }; - 0EF2862C22CBAF5D0026C7A5 /* TagSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EF2862B22CBAF5D0026C7A5 /* TagSettings.storyboard */; }; - 0EF2862E22CBAFC80026C7A5 /* TagSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2862D22CBAFC80026C7A5 /* TagSettingsTableViewController.swift */; }; - 0EF2863122CBB00D0026C7A5 /* TagSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863022CBB00D0026C7A5 /* TagSettingsViewInput.swift */; }; - 0EF2863322CBB0250026C7A5 /* TagSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863222CBB0250026C7A5 /* TagSettingsViewOutput.swift */; }; - 0EF2863522CBB03A0026C7A5 /* TagSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863422CBB03A0026C7A5 /* TagSettingsRouterInput.swift */; }; - 0EF2863722CBB04E0026C7A5 /* TagSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863622CBB04E0026C7A5 /* TagSettingsRouter.swift */; }; - 0EF2863922CBB06C0026C7A5 /* TagSettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863822CBB06C0026C7A5 /* TagSettingsModuleInput.swift */; }; - 0EF2863B22CBB08C0026C7A5 /* TagSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863A22CBB08C0026C7A5 /* TagSettingsPresenter.swift */; }; - 0EF2864022CBB1340026C7A5 /* TagSettingsTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863F22CBB1340026C7A5 /* TagSettingsTableInitializer.swift */; }; - 0EF2864222CBB13F0026C7A5 /* TagSettingsTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2864122CBB13F0026C7A5 /* TagSettingsTableConfigurator.swift */; }; - 0EF4E344268318DE00D83CC7 /* RuuviDFU in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E343268318DE00D83CC7 /* RuuviDFU */; }; - 0EF4E346268318DE00D83CC7 /* RuuviDFUImpl in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E345268318DE00D83CC7 /* RuuviDFUImpl */; }; - 0EF4E348268318E600D83CC7 /* RuuviDFU in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E347268318E600D83CC7 /* RuuviDFU */; }; - 0EF4E34A268318E600D83CC7 /* RuuviDFUImpl in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E349268318E600D83CC7 /* RuuviDFUImpl */; }; - 0EF4E34F268319A400D83CC7 /* DfuFirmware+Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF4E34E268319A400D83CC7 /* DfuFirmware+Log.swift */; }; - 0EF4E350268319A400D83CC7 /* DfuFirmware+Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF4E34E268319A400D83CC7 /* DfuFirmware+Log.swift */; }; - 0EF5B72B22D62CD900D9D14A /* Date+Ruuvi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF5B72A22D62CD900D9D14A /* Date+Ruuvi.swift */; }; - 0EF6F5BE235E01170052BA25 /* ForegroundRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF6F5BD235E01170052BA25 /* ForegroundRouter.swift */; }; - 0EF6F5C0235E01CD0052BA25 /* ForegroundStepperTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF6F5BF235E01CD0052BA25 /* ForegroundStepperTableViewCell.swift */; }; - 0EF6F5C2235E02000052BA25 /* ForegroundTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF6F5C1235E02000052BA25 /* ForegroundTableViewController.swift */; }; - 1F3C224646FB9B196464E9DD /* SignInConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B469B53431F206F4D0EC60 /* SignInConfigurator.swift */; }; - 248444E4B7F8C3D6454D4D1B /* ShareModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5710E4EF18D419D01D60405E /* ShareModuleOutput.swift */; }; - 26BA929FDA200CCAC9964651 /* SharePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC1D67615D6DBA9E2FC5B402 /* SharePresenter.swift */; }; - 2BB81E4733D8EC40BECC68EF /* ShareViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 354B5B6F50E98F55D6A672BA /* ShareViewModel.swift */; }; - 34238B2C062103E10D2BC65D /* SignInViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BD498E7491E278B4EF4919C /* SignInViewOutput.swift */; }; - 3BA1E7A8054CF95D80BAE3F9 /* ShareViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE5C4AD5C54EF024669EAF47 /* ShareViewOutput.swift */; }; - 3E9E7B1756AB4F6867DD3634 /* SignInInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85B8587156E1062D613B8960 /* SignInInitializer.swift */; }; - 4F8FB6FCCB69D64B47FF440B /* ShareConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB681E62A66E5924A87859B1 /* ShareConfigurator.swift */; }; - 6204554EB76ED0EFDE0DC290 /* ShareRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD7AE39C23B8C52BB202BB5E /* ShareRouter.swift */; }; - 64333D2920B0C45900CDF4B6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64333D2820B0C45900CDF4B6 /* AppDelegate.swift */; }; - 64333D2E20B0C45900CDF4B6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 64333D2C20B0C45900CDF4B6 /* Main.storyboard */; }; - 64333D3020B0C45A00CDF4B6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 64333D2F20B0C45A00CDF4B6 /* Assets.xcassets */; }; - 64333D3320B0C45A00CDF4B6 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 64333D3120B0C45A00CDF4B6 /* LaunchScreen.storyboard */; }; - 64333D3E20B0C45A00CDF4B6 /* StationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64333D3D20B0C45A00CDF4B6 /* StationTests.swift */; }; - 643C651F21C38F490037BE5B /* Montserrat-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 643C651E21C38F490037BE5B /* Montserrat-Bold.ttf */; }; - 643EEC2B2266435100D4E837 /* Oswald-ExtraLight.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 643EEC2A2266435100D4E837 /* Oswald-ExtraLight.ttf */; }; - 64678191225D03300072856A /* Muli-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 64678190225D02CE0072856A /* Muli-Bold.ttf */; }; - 64678192225D03330072856A /* Muli-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6467818F225CFB170072856A /* Muli-Regular.ttf */; }; - 6486971020E0436A00CCD7C1 /* Oswald-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6486970F20E042E000CCD7C1 /* Oswald-Bold.ttf */; }; - 6486971220E0439200CCD7C1 /* Montserrat-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6486971120E0439200CCD7C1 /* Montserrat-Regular.ttf */; }; - 660EB2582669278E000FD22B /* DfuDevicesScannerConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2462669278E000FD22B /* DfuDevicesScannerConfigurator.swift */; }; - 660EB2592669278E000FD22B /* DfuDevicesScannerConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2462669278E000FD22B /* DfuDevicesScannerConfigurator.swift */; }; - 660EB25B2669278E000FD22B /* DfuDevicesScannerInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2472669278E000FD22B /* DfuDevicesScannerInitializer.swift */; }; - 660EB25C2669278E000FD22B /* DfuDevicesScannerInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2472669278E000FD22B /* DfuDevicesScannerInitializer.swift */; }; - 660EB25E2669278E000FD22B /* DfuDevicesScannerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2492669278E000FD22B /* DfuDevicesScannerPresenter.swift */; }; - 660EB25F2669278E000FD22B /* DfuDevicesScannerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2492669278E000FD22B /* DfuDevicesScannerPresenter.swift */; }; - 660EB2612669278E000FD22B /* DfuDevicesScannerModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB24A2669278E000FD22B /* DfuDevicesScannerModuleInput.swift */; }; - 660EB2622669278E000FD22B /* DfuDevicesScannerModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB24A2669278E000FD22B /* DfuDevicesScannerModuleInput.swift */; }; - 660EB2642669278E000FD22B /* DfuDevicesScannerModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB24B2669278E000FD22B /* DfuDevicesScannerModuleOutput.swift */; }; - 660EB2652669278E000FD22B /* DfuDevicesScannerModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB24B2669278E000FD22B /* DfuDevicesScannerModuleOutput.swift */; }; - 660EB2672669278E000FD22B /* DfuNoDeviceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB24E2669278E000FD22B /* DfuNoDeviceTableViewCell.swift */; }; - 660EB2682669278E000FD22B /* DfuNoDeviceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB24E2669278E000FD22B /* DfuNoDeviceTableViewCell.swift */; }; - 660EB26A2669278E000FD22B /* DfuDeviceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB24F2669278E000FD22B /* DfuDeviceTableViewCell.swift */; }; - 660EB26B2669278E000FD22B /* DfuDeviceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB24F2669278E000FD22B /* DfuDeviceTableViewCell.swift */; }; - 660EB26D2669278E000FD22B /* DfuDevicesScannerViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2502669278E000FD22B /* DfuDevicesScannerViewInput.swift */; }; - 660EB26E2669278E000FD22B /* DfuDevicesScannerViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2502669278E000FD22B /* DfuDevicesScannerViewInput.swift */; }; - 660EB2702669278E000FD22B /* DfuDevicesScannerTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2512669278E000FD22B /* DfuDevicesScannerTableViewController.swift */; }; - 660EB2712669278E000FD22B /* DfuDevicesScannerTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2512669278E000FD22B /* DfuDevicesScannerTableViewController.swift */; }; - 660EB2732669278E000FD22B /* DfuDevicesScannerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2522669278E000FD22B /* DfuDevicesScannerViewModel.swift */; }; - 660EB2742669278E000FD22B /* DfuDevicesScannerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2522669278E000FD22B /* DfuDevicesScannerViewModel.swift */; }; - 660EB2762669278E000FD22B /* DfuDevicesScannerViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2532669278E000FD22B /* DfuDevicesScannerViewOutput.swift */; }; - 660EB2772669278E000FD22B /* DfuDevicesScannerViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2532669278E000FD22B /* DfuDevicesScannerViewOutput.swift */; }; - 660EB2792669278E000FD22B /* DfuDevicesScanner.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 660EB2542669278E000FD22B /* DfuDevicesScanner.storyboard */; }; - 660EB27A2669278E000FD22B /* DfuDevicesScanner.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 660EB2542669278E000FD22B /* DfuDevicesScanner.storyboard */; }; - 660EB27C2669278E000FD22B /* DfuDevicesScannerRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2562669278E000FD22B /* DfuDevicesScannerRouterInput.swift */; }; - 660EB27D2669278E000FD22B /* DfuDevicesScannerRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2562669278E000FD22B /* DfuDevicesScannerRouterInput.swift */; }; - 660EB27F2669278E000FD22B /* DfuDevicesScannerRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2572669278E000FD22B /* DfuDevicesScannerRouter.swift */; }; - 660EB2802669278E000FD22B /* DfuDevicesScannerRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2572669278E000FD22B /* DfuDevicesScannerRouter.swift */; }; - 660EB29C266928E6000FD22B /* UIViewController+Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB29B266928E6000FD22B /* UIViewController+Alert.swift */; }; - 660EB29D266928E6000FD22B /* UIViewController+Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB29B266928E6000FD22B /* UIViewController+Alert.swift */; }; - 663155DD2667F40C005B90A6 /* UpdateFirmwareAppleInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155CD2667F40C005B90A6 /* UpdateFirmwareAppleInitializer.swift */; }; - 663155DE2667F40C005B90A6 /* UpdateFirmwareAppleInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155CD2667F40C005B90A6 /* UpdateFirmwareAppleInitializer.swift */; }; - 663155E02667F40C005B90A6 /* UpdateFirmwareConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155CE2667F40C005B90A6 /* UpdateFirmwareConfigurator.swift */; }; - 663155E12667F40C005B90A6 /* UpdateFirmwareConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155CE2667F40C005B90A6 /* UpdateFirmwareConfigurator.swift */; }; - 663155E32667F40C005B90A6 /* UpdateFirmwarePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D02667F40C005B90A6 /* UpdateFirmwarePresenter.swift */; }; - 663155E42667F40C005B90A6 /* UpdateFirmwarePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D02667F40C005B90A6 /* UpdateFirmwarePresenter.swift */; }; - 663155E62667F40C005B90A6 /* UpdateFirmwareModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D12667F40C005B90A6 /* UpdateFirmwareModuleOutput.swift */; }; - 663155E72667F40C005B90A6 /* UpdateFirmwareModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D12667F40C005B90A6 /* UpdateFirmwareModuleOutput.swift */; }; - 663155E92667F40C005B90A6 /* UpdateFirmwareModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D22667F40C005B90A6 /* UpdateFirmwareModuleInput.swift */; }; - 663155EA2667F40C005B90A6 /* UpdateFirmwareModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D22667F40C005B90A6 /* UpdateFirmwareModuleInput.swift */; }; - 663155EC2667F40C005B90A6 /* UpdateFirmwareAppleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D52667F40C005B90A6 /* UpdateFirmwareAppleViewController.swift */; }; - 663155ED2667F40C005B90A6 /* UpdateFirmwareAppleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D52667F40C005B90A6 /* UpdateFirmwareAppleViewController.swift */; }; - 663155EF2667F40C005B90A6 /* UpdateFirmwareViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D62667F40C005B90A6 /* UpdateFirmwareViewOutput.swift */; }; - 663155F02667F40C005B90A6 /* UpdateFirmwareViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D62667F40C005B90A6 /* UpdateFirmwareViewOutput.swift */; }; - 663155F22667F40C005B90A6 /* UpdateFirmwareViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D72667F40C005B90A6 /* UpdateFirmwareViewInput.swift */; }; - 663155F32667F40C005B90A6 /* UpdateFirmwareViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D72667F40C005B90A6 /* UpdateFirmwareViewInput.swift */; }; - 663155F82667F40C005B90A6 /* UpdateFirmware.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 663155D92667F40C005B90A6 /* UpdateFirmware.storyboard */; }; - 663155F92667F40C005B90A6 /* UpdateFirmware.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 663155D92667F40C005B90A6 /* UpdateFirmware.storyboard */; }; - 663155FB2667F40C005B90A6 /* UpdateFirmwareRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155DB2667F40C005B90A6 /* UpdateFirmwareRouter.swift */; }; - 663155FC2667F40C005B90A6 /* UpdateFirmwareRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155DB2667F40C005B90A6 /* UpdateFirmwareRouter.swift */; }; - 663155FE2667F40C005B90A6 /* UpdateFirmwareRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155DC2667F40C005B90A6 /* UpdateFirmwareRouterInput.swift */; }; - 663155FF2667F40C005B90A6 /* UpdateFirmwareRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155DC2667F40C005B90A6 /* UpdateFirmwareRouterInput.swift */; }; - 66718A3A266A685700A380F8 /* DfuFlashAppleInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A28266A685700A380F8 /* DfuFlashAppleInitializer.swift */; }; - 66718A3B266A685700A380F8 /* DfuFlashAppleInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A28266A685700A380F8 /* DfuFlashAppleInitializer.swift */; }; - 66718A3D266A685700A380F8 /* DfuFlashConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A29266A685700A380F8 /* DfuFlashConfigurator.swift */; }; - 66718A3E266A685700A380F8 /* DfuFlashConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A29266A685700A380F8 /* DfuFlashConfigurator.swift */; }; - 66718A40266A685700A380F8 /* DfuFlashModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A2B266A685700A380F8 /* DfuFlashModuleInput.swift */; }; - 66718A41266A685700A380F8 /* DfuFlashModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A2B266A685700A380F8 /* DfuFlashModuleInput.swift */; }; - 66718A43266A685700A380F8 /* DfuFlashModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A2C266A685700A380F8 /* DfuFlashModuleOutput.swift */; }; - 66718A44266A685700A380F8 /* DfuFlashModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A2C266A685700A380F8 /* DfuFlashModuleOutput.swift */; }; - 66718A46266A685700A380F8 /* DfuFlashPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A2D266A685700A380F8 /* DfuFlashPresenter.swift */; }; - 66718A47266A685700A380F8 /* DfuFlashPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A2D266A685700A380F8 /* DfuFlashPresenter.swift */; }; - 66718A49266A685700A380F8 /* DfuFlashAppleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A30266A685700A380F8 /* DfuFlashAppleViewController.swift */; }; - 66718A4A266A685700A380F8 /* DfuFlashAppleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A30266A685700A380F8 /* DfuFlashAppleViewController.swift */; }; - 66718A4C266A685700A380F8 /* DfuLogTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A32266A685700A380F8 /* DfuLogTableViewCell.swift */; }; - 66718A4D266A685700A380F8 /* DfuLogTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A32266A685700A380F8 /* DfuLogTableViewCell.swift */; }; - 66718A4F266A685700A380F8 /* DfuFlashViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A33266A685700A380F8 /* DfuFlashViewModel.swift */; }; - 66718A50266A685700A380F8 /* DfuFlashViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A33266A685700A380F8 /* DfuFlashViewModel.swift */; }; - 66718A52266A685700A380F8 /* DfuFlashViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A34266A685700A380F8 /* DfuFlashViewInput.swift */; }; - 66718A53266A685700A380F8 /* DfuFlashViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A34266A685700A380F8 /* DfuFlashViewInput.swift */; }; - 66718A55266A685700A380F8 /* DfuFlashViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A35266A685700A380F8 /* DfuFlashViewOutput.swift */; }; - 66718A56266A685700A380F8 /* DfuFlashViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A35266A685700A380F8 /* DfuFlashViewOutput.swift */; }; - 66718A58266A685700A380F8 /* DfuFlash.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 66718A36266A685700A380F8 /* DfuFlash.storyboard */; }; - 66718A59266A685700A380F8 /* DfuFlash.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 66718A36266A685700A380F8 /* DfuFlash.storyboard */; }; - 66718A5B266A685700A380F8 /* DfuFlashRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A38266A685700A380F8 /* DfuFlashRouter.swift */; }; - 66718A5C266A685700A380F8 /* DfuFlashRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A38266A685700A380F8 /* DfuFlashRouter.swift */; }; - 66718A5E266A685700A380F8 /* DfuFlashRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A39266A685700A380F8 /* DfuFlashRouterInput.swift */; }; - 66718A5F266A685700A380F8 /* DfuFlashRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A39266A685700A380F8 /* DfuFlashRouterInput.swift */; }; - 66718A65266A6CA700A380F8 /* DfuFilePickerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A62266A6CA700A380F8 /* DfuFilePickerPresenter.swift */; }; - 66718A66266A6CA700A380F8 /* DfuFilePickerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A62266A6CA700A380F8 /* DfuFilePickerPresenter.swift */; }; - 66718A68266A6CA700A380F8 /* DfuFilePickerPresenterSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A64266A6CA700A380F8 /* DfuFilePickerPresenterSheet.swift */; }; - 66718A69266A6CA700A380F8 /* DfuFilePickerPresenterSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A64266A6CA700A380F8 /* DfuFilePickerPresenterSheet.swift */; }; - 66718A6C266BD0E800A380F8 /* Color+Ruuvi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A6B266BD0E800A380F8 /* Color+Ruuvi.swift */; }; - 66718A6D266BD0E800A380F8 /* Color+Ruuvi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A6B266BD0E800A380F8 /* Color+Ruuvi.swift */; }; - 66BC44952657AED400A03253 /* OffsetCorrection.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 66BC44832657AED400A03253 /* OffsetCorrection.storyboard */; }; - 66BC44962657AED400A03253 /* OffsetCorrection.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 66BC44832657AED400A03253 /* OffsetCorrection.storyboard */; }; - 66BC44982657AED400A03253 /* OffsetCorrectionAppleInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44862657AED400A03253 /* OffsetCorrectionAppleInitializer.swift */; }; - 66BC44992657AED400A03253 /* OffsetCorrectionAppleInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44862657AED400A03253 /* OffsetCorrectionAppleInitializer.swift */; }; - 66BC449B2657AED400A03253 /* OffsetCorrectionConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44872657AED400A03253 /* OffsetCorrectionConfigurator.swift */; }; - 66BC449C2657AED400A03253 /* OffsetCorrectionConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44872657AED400A03253 /* OffsetCorrectionConfigurator.swift */; }; - 66BC449E2657AED400A03253 /* OffsetCorrectionModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44892657AED400A03253 /* OffsetCorrectionModuleOutput.swift */; }; - 66BC449F2657AED400A03253 /* OffsetCorrectionModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44892657AED400A03253 /* OffsetCorrectionModuleOutput.swift */; }; - 66BC44A12657AED400A03253 /* OffsetCorrectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448A2657AED400A03253 /* OffsetCorrectionPresenter.swift */; }; - 66BC44A22657AED400A03253 /* OffsetCorrectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448A2657AED400A03253 /* OffsetCorrectionPresenter.swift */; }; - 66BC44A42657AED400A03253 /* OffsetCorrectionModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448B2657AED400A03253 /* OffsetCorrectionModuleInput.swift */; }; - 66BC44A52657AED400A03253 /* OffsetCorrectionModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448B2657AED400A03253 /* OffsetCorrectionModuleInput.swift */; }; - 66BC44A72657AED400A03253 /* OffsetCorrectionAppleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448E2657AED400A03253 /* OffsetCorrectionAppleViewController.swift */; }; - 66BC44A82657AED400A03253 /* OffsetCorrectionAppleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448E2657AED400A03253 /* OffsetCorrectionAppleViewController.swift */; }; - 66BC44AA2657AED400A03253 /* OffsetCorrectionViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448F2657AED400A03253 /* OffsetCorrectionViewInput.swift */; }; - 66BC44AB2657AED400A03253 /* OffsetCorrectionViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448F2657AED400A03253 /* OffsetCorrectionViewInput.swift */; }; - 66BC44AD2657AED400A03253 /* OffsetCorrectionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44902657AED400A03253 /* OffsetCorrectionViewModel.swift */; }; - 66BC44AE2657AED400A03253 /* OffsetCorrectionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44902657AED400A03253 /* OffsetCorrectionViewModel.swift */; }; - 66BC44B02657AED400A03253 /* OffsetCorrectionViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44912657AED400A03253 /* OffsetCorrectionViewOutput.swift */; }; - 66BC44B12657AED400A03253 /* OffsetCorrectionViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44912657AED400A03253 /* OffsetCorrectionViewOutput.swift */; }; - 66BC44B32657AED400A03253 /* OffsetCorrectionRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44932657AED400A03253 /* OffsetCorrectionRouter.swift */; }; - 66BC44B42657AED400A03253 /* OffsetCorrectionRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44932657AED400A03253 /* OffsetCorrectionRouter.swift */; }; - 66BC44B62657AED400A03253 /* OffsetCorrectionRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44942657AED400A03253 /* OffsetCorrectionRouterInput.swift */; }; - 66BC44B72657AED400A03253 /* OffsetCorrectionRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44942657AED400A03253 /* OffsetCorrectionRouterInput.swift */; }; - 7350803A8D6DD23F1057994F /* SignInPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E29B5190CB557178D11AB2CE /* SignInPresenter.swift */; }; - 74E67721EFA7BF9397D52B1F /* SignInViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC59D3B5AD8926DBDD79AA1C /* SignInViewModel.swift */; }; - 898D45D0BF0ABBCB2E68FBE9 /* ShareInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 392F0E992BEAA3382C2CF709 /* ShareInitializer.swift */; }; - 8A37F49EA3B84BB415491B03 /* SignInModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B3006A5FB2173EC6AA2728D /* SignInModuleOutput.swift */; }; - A907A1D3245F7C6600041F6E /* ProgressBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A907A1D2245F7C6600041F6E /* ProgressBarView.swift */; }; - A907A1D4245F7C6600041F6E /* ProgressBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A907A1D2245F7C6600041F6E /* ProgressBarView.swift */; }; - A907A1D72460376600041F6E /* TagChartViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A907A1D62460376600041F6E /* TagChartViewModel.swift */; }; - A907A1D82460376600041F6E /* TagChartViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A907A1D62460376600041F6E /* TagChartViewModel.swift */; }; - A907BB1124AE620A009DA3DB /* UIWindow+Orientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A907BB1024AE620A009DA3DB /* UIWindow+Orientation.swift */; }; - A907BB1224AE620D009DA3DB /* UIWindow+Orientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A907BB1024AE620A009DA3DB /* UIWindow+Orientation.swift */; }; - A90E168F24604F7400631E6C /* TagChartPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E168E24604F7400631E6C /* TagChartPresenter.swift */; }; - A90E169024604F7400631E6C /* TagChartPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E168E24604F7400631E6C /* TagChartPresenter.swift */; }; - A90E169324604FD100631E6C /* TagChartModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E169224604FD100631E6C /* TagChartModuleInput.swift */; }; - A90E169424604FD100631E6C /* TagChartModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E169224604FD100631E6C /* TagChartModuleInput.swift */; }; - A90E16972460504C00631E6C /* TagChartModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E16962460504C00631E6C /* TagChartModuleOutput.swift */; }; - A90E16982460504C00631E6C /* TagChartModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E16962460504C00631E6C /* TagChartModuleOutput.swift */; }; - A90E169C24606ABF00631E6C /* TagChartsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E169B24606ABF00631E6C /* TagChartsInteractor.swift */; }; - A90E169D24606ABF00631E6C /* TagChartsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E169B24606ABF00631E6C /* TagChartsInteractor.swift */; }; - A90E16A024606B0500631E6C /* TagChartsInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E169F24606B0500631E6C /* TagChartsInteractorInput.swift */; }; - A90E16A124606B0500631E6C /* TagChartsInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E169F24606B0500631E6C /* TagChartsInteractorInput.swift */; }; - A90E16A424606B2000631E6C /* TagChartsInteractorOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E16A324606B2000631E6C /* TagChartsInteractorOutput.swift */; }; - A90E16A524606B2000631E6C /* TagChartsInteractorOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E16A324606B2000631E6C /* TagChartsInteractorOutput.swift */; }; - A90E16A92460975600631E6C /* TagChartAssembler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E16A82460975600631E6C /* TagChartAssembler.swift */; }; - A90E16AA24609B9B00631E6C /* TagChartAssembler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E16A82460975600631E6C /* TagChartAssembler.swift */; }; - A91D02EE2511207200694733 /* SelectionTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02DD2511207200694733 /* SelectionTableConfigurator.swift */; }; - A91D02EF2511207200694733 /* SelectionTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02DD2511207200694733 /* SelectionTableConfigurator.swift */; }; - A91D02F12511207200694733 /* SelectionTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02DE2511207200694733 /* SelectionTableInitializer.swift */; }; - A91D02F22511207200694733 /* SelectionTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02DE2511207200694733 /* SelectionTableInitializer.swift */; }; - A91D02F42511207300694733 /* SelectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E02511207200694733 /* SelectionPresenter.swift */; }; - A91D02F52511207300694733 /* SelectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E02511207200694733 /* SelectionPresenter.swift */; }; - A91D02F72511207300694733 /* SelectionModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E12511207200694733 /* SelectionModuleInput.swift */; }; - A91D02F82511207300694733 /* SelectionModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E12511207200694733 /* SelectionModuleInput.swift */; }; - A91D02FA2511207300694733 /* SelectionViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E32511207200694733 /* SelectionViewInput.swift */; }; - A91D02FB2511207300694733 /* SelectionViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E32511207200694733 /* SelectionViewInput.swift */; }; - A91D02FD2511207300694733 /* SelectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E52511207200694733 /* SelectionTableViewCell.swift */; }; - A91D02FE2511207300694733 /* SelectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E52511207200694733 /* SelectionTableViewCell.swift */; }; - A91D03002511207300694733 /* SelectionTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E62511207200694733 /* SelectionTableViewController.swift */; }; - A91D03012511207300694733 /* SelectionTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E62511207200694733 /* SelectionTableViewController.swift */; }; - A91D03032511207300694733 /* SelectionViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E72511207200694733 /* SelectionViewOutput.swift */; }; - A91D03042511207300694733 /* SelectionViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E72511207200694733 /* SelectionViewOutput.swift */; }; - A91D03062511207300694733 /* SelectionRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E92511207200694733 /* SelectionRouter.swift */; }; - A91D03072511207300694733 /* SelectionRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E92511207200694733 /* SelectionRouter.swift */; }; - A91D03092511207300694733 /* SelectionRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02EA2511207200694733 /* SelectionRouterInput.swift */; }; - A91D030A2511207300694733 /* SelectionRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02EA2511207200694733 /* SelectionRouterInput.swift */; }; - A91D030D251121C800694733 /* Selection.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A91D030C251121C800694733 /* Selection.storyboard */; }; - A91D030E251121C800694733 /* Selection.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A91D030C251121C800694733 /* Selection.storyboard */; }; - A91D0311251123B400694733 /* SelectionModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D0310251123B400694733 /* SelectionModuleOutput.swift */; }; - A91D0312251123B400694733 /* SelectionModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D0310251123B400694733 /* SelectionModuleOutput.swift */; }; - A91D0316251124F900694733 /* SelectionItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D0315251124F900694733 /* SelectionItem.swift */; }; - A91D0317251124F900694733 /* SelectionItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D0315251124F900694733 /* SelectionItem.swift */; }; - A91D031A25113EAA00694733 /* UnitPressure+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D031925113EAA00694733 /* UnitPressure+Extension.swift */; }; - A91D031B25113EAA00694733 /* UnitPressure+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D031925113EAA00694733 /* UnitPressure+Extension.swift */; }; - A92A66BD2450C640002918E7 /* UITableViewCell+ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92A66BC2450C640002918E7 /* UITableViewCell+ReusableView.swift */; }; - A92A66BE2450C64A002918E7 /* UITableViewCell+ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92A66BC2450C640002918E7 /* UITableViewCell+ReusableView.swift */; }; - A92E3C5A2426415100D981D5 /* TagChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92E3C592426415100D981D5 /* TagChartView.swift */; }; - A92E3C5B2426428D00D981D5 /* TagChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92E3C592426415100D981D5 /* TagChartView.swift */; }; - A92E3C63242644B800D981D5 /* TagChartViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92E3C62242644B800D981D5 /* TagChartViewInput.swift */; }; - A92E3C64242644B800D981D5 /* TagChartViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92E3C62242644B800D981D5 /* TagChartViewInput.swift */; }; - A93052B8242BFCC000FB62B1 /* TagChartViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93052B7242BFCC000FB62B1 /* TagChartViewOutput.swift */; }; - A93052B9242BFCF800FB62B1 /* TagChartViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93052B7242BFCC000FB62B1 /* TagChartViewOutput.swift */; }; - A935E47625A49E8F009538C4 /* MeasurementsServiceFiSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = A935E47525A49E8F009538C4 /* MeasurementsServiceFiSpec.swift */; }; - A935E47D25A49E9E009538C4 /* MeasurementsServiceRuSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = A935E47C25A49E9E009538C4 /* MeasurementsServiceRuSpec.swift */; }; - A93CDCAB25657C1D00018C6C /* MenuViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93CDCAA25657C1D00018C6C /* MenuViewModel.swift */; }; - A93CDCAC25657C1D00018C6C /* MenuViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93CDCAA25657C1D00018C6C /* MenuViewModel.swift */; }; - A93CDCCF25659BA600018C6C /* AlertPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93CDCCE25659BA600018C6C /* AlertPresenter.swift */; }; - A93CDCD025659BA600018C6C /* AlertPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93CDCCE25659BA600018C6C /* AlertPresenter.swift */; }; - A93CDCDE25659BF600018C6C /* AlertPresenterImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93CDCDD25659BF600018C6C /* AlertPresenterImpl.swift */; }; - A93CDCDF25659BF600018C6C /* AlertPresenterImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93CDCDD25659BF600018C6C /* AlertPresenterImpl.swift */; }; - A949A83B24707FD0006B7F4F /* LocalizedCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949A83A24707FD0006B7F4F /* LocalizedCache.swift */; }; - A949A83C24707FDD006B7F4F /* LocalizedCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949A83A24707FD0006B7F4F /* LocalizedCache.swift */; }; - A94FFD48241C34EA00888017 /* MockAlertPersistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9100D82241AD1E4004007FD /* MockAlertPersistence.swift */; }; - A94FFD4A241D45C600888017 /* MockRuuviTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = A94FFD49241D45C600888017 /* MockRuuviTag.swift */; }; - A94FFD4C241D512900888017 /* MockLocalNotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A94FFD4B241D512900888017 /* MockLocalNotificationsManager.swift */; }; - A94FFD4E241D57E700888017 /* MockCalibrationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = A94FFD4D241D57E700888017 /* MockCalibrationService.swift */; }; - A94FFD50241D6BA300888017 /* MockAlertServiceObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = A94FFD4F241D6BA300888017 /* MockAlertServiceObserver.swift */; }; - A9646466247BAE6B0001D55D /* AdvancedViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646454247BAE6A0001D55D /* AdvancedViewInput.swift */; }; - A9646467247BAE6B0001D55D /* AdvancedViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646454247BAE6A0001D55D /* AdvancedViewInput.swift */; }; - A964646C247BAE6B0001D55D /* AdvancedStepperTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646458247BAE6A0001D55D /* AdvancedStepperTableViewCell.swift */; }; - A964646D247BAE6B0001D55D /* AdvancedStepperTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646458247BAE6A0001D55D /* AdvancedStepperTableViewCell.swift */; }; - A964646F247BAE6B0001D55D /* AdvancedSwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646459247BAE6A0001D55D /* AdvancedSwitchTableViewCell.swift */; }; - A9646470247BAE6B0001D55D /* AdvancedSwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646459247BAE6A0001D55D /* AdvancedSwitchTableViewCell.swift */; }; - A9646472247BAE6B0001D55D /* AdvancedTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645A247BAE6A0001D55D /* AdvancedTableViewController.swift */; }; - A9646473247BAE6B0001D55D /* AdvancedTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645A247BAE6A0001D55D /* AdvancedTableViewController.swift */; }; - A9646475247BAE6B0001D55D /* AdvancedViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645B247BAE6A0001D55D /* AdvancedViewOutput.swift */; }; - A9646476247BAE6B0001D55D /* AdvancedViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645B247BAE6A0001D55D /* AdvancedViewOutput.swift */; }; - A9646478247BAE6B0001D55D /* AdvancedViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645C247BAE6A0001D55D /* AdvancedViewModel.swift */; }; - A9646479247BAE6B0001D55D /* AdvancedViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645C247BAE6A0001D55D /* AdvancedViewModel.swift */; }; - A964647B247BAE6B0001D55D /* AdvancedConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645E247BAE6A0001D55D /* AdvancedConfigurator.swift */; }; - A964647C247BAE6B0001D55D /* AdvancedConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645E247BAE6A0001D55D /* AdvancedConfigurator.swift */; }; - A964647E247BAE6B0001D55D /* AdvancedInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645F247BAE6A0001D55D /* AdvancedInitializer.swift */; }; - A964647F247BAE6B0001D55D /* AdvancedInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645F247BAE6A0001D55D /* AdvancedInitializer.swift */; }; - A9646481247BAE6B0001D55D /* AdvancedModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646461247BAE6A0001D55D /* AdvancedModuleInput.swift */; }; - A9646482247BAE6B0001D55D /* AdvancedModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646461247BAE6A0001D55D /* AdvancedModuleInput.swift */; }; - A9646484247BAE6B0001D55D /* AdvancedPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646462247BAE6A0001D55D /* AdvancedPresenter.swift */; }; - A9646485247BAE6B0001D55D /* AdvancedPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646462247BAE6A0001D55D /* AdvancedPresenter.swift */; }; - A9646487247BAE6B0001D55D /* AdvancedRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646464247BAE6A0001D55D /* AdvancedRouterInput.swift */; }; - A9646488247BAE6B0001D55D /* AdvancedRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646464247BAE6A0001D55D /* AdvancedRouterInput.swift */; }; - A964648A247BAE6B0001D55D /* AdvancedRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646465247BAE6A0001D55D /* AdvancedRouter.swift */; }; - A964648B247BAE6B0001D55D /* AdvancedRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646465247BAE6A0001D55D /* AdvancedRouter.swift */; }; - A964648E247BAEBA0001D55D /* AdvancedSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A964648D247BAEBA0001D55D /* AdvancedSettings.storyboard */; }; - A964648F247BAEBA0001D55D /* AdvancedSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A964648D247BAEBA0001D55D /* AdvancedSettings.storyboard */; }; - A971B0DC24215334008EF50D /* XCTest+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A971B0DB24215334008EF50D /* XCTest+Extension.swift */; }; - A976CA7E24A928C20099BDC1 /* AdvancedDisclosureTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A976CA7D24A928C20099BDC1 /* AdvancedDisclosureTableViewCell.swift */; }; - A976CA7F24A928C20099BDC1 /* AdvancedDisclosureTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A976CA7D24A928C20099BDC1 /* AdvancedDisclosureTableViewCell.swift */; }; - A980573825807118000D03AB /* AboutViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A980573725807118000D03AB /* AboutViewModel.swift */; }; - A980573925807118000D03AB /* AboutViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A980573725807118000D03AB /* AboutViewModel.swift */; }; - A98BC875250E4265001CEFDC /* Double+Round.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98BC874250E4265001CEFDC /* Double+Round.swift */; }; - A98BC876250E4265001CEFDC /* Double+Round.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98BC874250E4265001CEFDC /* Double+Round.swift */; }; - A98D3F06256CBD410066588B /* ShareModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AE2284D927021C0BEA560B0 /* ShareModuleInput.swift */; }; - A98D3F0C256CBD600066588B /* ShareConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB681E62A66E5924A87859B1 /* ShareConfigurator.swift */; }; - A98D3F0D256CBD600066588B /* ShareInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 392F0E992BEAA3382C2CF709 /* ShareInitializer.swift */; }; - A98D3F0E256CBD600066588B /* ShareRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9546F1EFEE8F8CFC22377BB4 /* ShareRouterInput.swift */; }; - A98D3F0F256CBD600066588B /* ShareViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 167F75FD2FDAD002C10686FA /* ShareViewInput.swift */; }; - A98D3F10256CBD600066588B /* ShareViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 354B5B6F50E98F55D6A672BA /* ShareViewModel.swift */; }; - A98D3F11256CBD600066588B /* ShareRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD7AE39C23B8C52BB202BB5E /* ShareRouter.swift */; }; - A98D3F12256CBD600066588B /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC417B8977A47FFAE71585F0 /* ShareViewController.swift */; }; - A98D3F13256CBD600066588B /* SharePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC1D67615D6DBA9E2FC5B402 /* SharePresenter.swift */; }; - A98D3F14256CBD600066588B /* ShareModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5710E4EF18D419D01D60405E /* ShareModuleOutput.swift */; }; - A98D3F15256CBD600066588B /* ShareViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE5C4AD5C54EF024669EAF47 /* ShareViewOutput.swift */; }; - A9A48A5D244CD9EB0004FD50 /* UIWindow+Shake.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9A48A5B244CD9E70004FD50 /* UIWindow+Shake.swift */; }; - A9A67BFA24C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9A67BF924C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift */; }; - A9A67BFB24C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9A67BF924C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift */; }; - A9B5742D253B978D00DB7353 /* SignIn.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A9B5742C253B978D00DB7353 /* SignIn.storyboard */; }; - A9B5743E253B992B00DB7353 /* SignIn.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A9B5742C253B978D00DB7353 /* SignIn.storyboard */; }; - A9B5743F253B993100DB7353 /* SignInConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B469B53431F206F4D0EC60 /* SignInConfigurator.swift */; }; - A9B57441253B994700DB7353 /* SignInRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E816312622E83E3B42001DC /* SignInRouterInput.swift */; }; - A9B57442253B994700DB7353 /* SignInRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F0552F1D17F403B7DE508B5 /* SignInRouter.swift */; }; - A9B57443253B994700DB7353 /* SignInViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A7D6325DFC865D2D11BD1D1 /* SignInViewInput.swift */; }; - A9B57444253B994700DB7353 /* SignInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6DB40883B83C652584EBB9A /* SignInViewController.swift */; }; - A9B57445253B994700DB7353 /* SignInPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E29B5190CB557178D11AB2CE /* SignInPresenter.swift */; }; - A9B57446253B994700DB7353 /* SignInModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87EFB230083D471777FBE5D0 /* SignInModuleInput.swift */; }; - A9B57447253B994700DB7353 /* SignInModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B3006A5FB2173EC6AA2728D /* SignInModuleOutput.swift */; }; - A9B57448253B994700DB7353 /* SignInViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC59D3B5AD8926DBDD79AA1C /* SignInViewModel.swift */; }; - A9B57449253B994700DB7353 /* SignInInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85B8587156E1062D613B8960 /* SignInInitializer.swift */; }; - A9B5744A253B994700DB7353 /* SignInViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BD498E7491E278B4EF4919C /* SignInViewOutput.swift */; }; - A9BB94CC2540AB610042B190 /* AlertViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BB94CB2540AB610042B190 /* AlertViewModel.swift */; }; - A9BB94CD2540AB610042B190 /* AlertViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BB94CB2540AB610042B190 /* AlertViewModel.swift */; }; - A9BD38BA24F6108300904BBE /* Humidity+Offset.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BD38B924F6108300904BBE /* Humidity+Offset.swift */; }; - A9BD38BB24F6108300904BBE /* Humidity+Offset.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BD38B924F6108300904BBE /* Humidity+Offset.swift */; }; - A9E5994025572CF700F9E5CC /* Share.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A9E5993F25572CF700F9E5CC /* Share.storyboard */; }; - A9E5994125572CF700F9E5CC /* Share.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A9E5993F25572CF700F9E5CC /* Share.storyboard */; }; - A9E5994A2557341F00F9E5CC /* ShareDescriptionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E599492557341F00F9E5CC /* ShareDescriptionTableViewCell.swift */; }; - A9E5994B2557341F00F9E5CC /* ShareDescriptionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E599492557341F00F9E5CC /* ShareDescriptionTableViewCell.swift */; }; - A9E599582557345200F9E5CC /* ShareEmailInputTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E599572557345200F9E5CC /* ShareEmailInputTableViewCell.swift */; }; - A9E599592557345200F9E5CC /* ShareEmailInputTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E599572557345200F9E5CC /* ShareEmailInputTableViewCell.swift */; }; - A9E599612557346600F9E5CC /* ShareSendButtonTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E599602557346600F9E5CC /* ShareSendButtonTableViewCell.swift */; }; - A9E599622557346600F9E5CC /* ShareSendButtonTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E599602557346600F9E5CC /* ShareSendButtonTableViewCell.swift */; }; - A9E5996A255734A000F9E5CC /* ShareEmailTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E59969255734A000F9E5CC /* ShareEmailTableViewCell.swift */; }; - A9E5996B255734A000F9E5CC /* ShareEmailTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E59969255734A000F9E5CC /* ShareEmailTableViewCell.swift */; }; - A9E6774825A33081000B75A3 /* String+Characters.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E6774725A33081000B75A3 /* String+Characters.swift */; }; - A9E6774925A33081000B75A3 /* String+Characters.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E6774725A33081000B75A3 /* String+Characters.swift */; }; - A9E6774B25A33081000B75A3 /* String+Characters.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E6774725A33081000B75A3 /* String+Characters.swift */; }; - A9E6775125A331D6000B75A3 /* MeasurementsServiceEnSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E6770D25A30D0A000B75A3 /* MeasurementsServiceEnSpec.swift */; }; - A9E6775C25A331E1000B75A3 /* MeasurementsServiceSvSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E6771925A31556000B75A3 /* MeasurementsServiceSvSpec.swift */; }; - A9F4471624B79959001E63AF /* TagSettingsModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9F4471524B79959001E63AF /* TagSettingsModuleOutput.swift */; }; - A9F4471724B79959001E63AF /* TagSettingsModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9F4471524B79959001E63AF /* TagSettingsModuleOutput.swift */; }; - ABCA915676F9A8C975D9F2A3 /* SignInViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A7D6325DFC865D2D11BD1D1 /* SignInViewInput.swift */; }; - B198F488C89E6DFFD1EECAF3 /* ShareRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9546F1EFEE8F8CFC22377BB4 /* ShareRouterInput.swift */; }; - B2A3FB2578B246F6CBBF0CA9 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC417B8977A47FFAE71585F0 /* ShareViewController.swift */; }; - B6FA27492FB1F63393783EFC /* ShareViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 167F75FD2FDAD002C10686FA /* ShareViewInput.swift */; }; - C8D6714C7E0237B74676EA08 /* SignInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6DB40883B83C652584EBB9A /* SignInViewController.swift */; }; - C9D6ACA6CB9694F6C33414CE /* ShareModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AE2284D927021C0BEA560B0 /* ShareModuleInput.swift */; }; - D037B55274A07756F884696B /* SignInRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F0552F1D17F403B7DE508B5 /* SignInRouter.swift */; }; - E8C4E5B85668D51EC22BC75A /* SignInRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E816312622E83E3B42001DC /* SignInRouterInput.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 64333D3A20B0C45A00CDF4B6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 64333D1D20B0C45900CDF4B6 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 64333D2420B0C45900CDF4B6; - remoteInfo = station; - }; - 64333D4520B0C45B00CDF4B6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 64333D1D20B0C45900CDF4B6 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 64333D2420B0C45900CDF4B6; - remoteInfo = station; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 0E02ABB9237598C600ED4629 /* RURangeSeekSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RURangeSeekSlider.swift; sourceTree = ""; }; - 0E02ABCA2379483A00ED4629 /* Double+Temperature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+Temperature.swift"; sourceTree = ""; }; - 0E046F2622F04A0300BD4E9C /* WebTagSettings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = WebTagSettings.storyboard; sourceTree = ""; }; - 0E046F2822F0561B00BD4E9C /* WebTagSettingsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsViewInput.swift; sourceTree = ""; }; - 0E046F2A22F0563100BD4E9C /* WebTagSettingsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsViewOutput.swift; sourceTree = ""; }; - 0E046F2D22F0569000BD4E9C /* WebTagSettingsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsTableViewController.swift; sourceTree = ""; }; - 0E046F2F22F057CC00BD4E9C /* WebTagSettingsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsRouterInput.swift; sourceTree = ""; }; - 0E046F3122F057DD00BD4E9C /* WebTagSettingsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsRouter.swift; sourceTree = ""; }; - 0E046F3322F057FC00BD4E9C /* WebTagSettingsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsModuleInput.swift; sourceTree = ""; }; - 0E046F3522F0581E00BD4E9C /* WebTagSettingsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsPresenter.swift; sourceTree = ""; }; - 0E046F3A22F05AA800BD4E9C /* WebTagSettingsTableInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsTableInitializer.swift; sourceTree = ""; }; - 0E046F3C22F05B0900BD4E9C /* WebTagSettingsTableConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsTableConfigurator.swift; sourceTree = ""; }; - 0E046F3E22F0702D00BD4E9C /* WebTagSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsViewModel.swift; sourceTree = ""; }; - 0E046F4522F17EF400BD4E9C /* LocationPicker.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LocationPicker.storyboard; sourceTree = ""; }; - 0E046F4722F181DA00BD4E9C /* LocationPickerViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerViewInput.swift; sourceTree = ""; }; - 0E046F4922F1820400BD4E9C /* LocationPickerViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerViewOutput.swift; sourceTree = ""; }; - 0E046F4C22F1823C00BD4E9C /* LocationPickerAppleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerAppleViewController.swift; sourceTree = ""; }; - 0E046F4E22F1827800BD4E9C /* LocationPickerRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerRouterInput.swift; sourceTree = ""; }; - 0E046F5022F1828900BD4E9C /* LocationPickerRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerRouter.swift; sourceTree = ""; }; - 0E046F5222F182AB00BD4E9C /* LocationPickerModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerModuleInput.swift; sourceTree = ""; }; - 0E046F5422F182BF00BD4E9C /* LocationPickerPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerPresenter.swift; sourceTree = ""; }; - 0E046F5722F182F500BD4E9C /* LocationPickerAppleInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerAppleInitializer.swift; sourceTree = ""; }; - 0E046F5922F1832600BD4E9C /* LocationPickerAppleConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerAppleConfigurator.swift; sourceTree = ""; }; - 0E046F6122F193B300BD4E9C /* LocationPickerModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerModuleOutput.swift; sourceTree = ""; }; - 0E0501262685FDD3007060C4 /* RuuviDaemonError+LocalizedError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RuuviDaemonError+LocalizedError.swift"; sourceTree = ""; }; - 0E0501272685FDD3007060C4 /* RuuviDFUError+LocalizedError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RuuviDFUError+LocalizedError.swift"; sourceTree = ""; }; - 0E050161268603CE007060C4 /* AppStateServiceImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppStateServiceImpl.swift; sourceTree = ""; }; - 0E050162268603CE007060C4 /* AppStateService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppStateService.swift; sourceTree = ""; }; - 0E050166268603CE007060C4 /* UniversalLinkCoordinatormpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniversalLinkCoordinatormpl.swift; sourceTree = ""; }; - 0E050167268603CE007060C4 /* UniversalLinkCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniversalLinkCoordinator.swift; sourceTree = ""; }; - 0E05016A268603CE007060C4 /* UniversalLinkRouterImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniversalLinkRouterImpl.swift; sourceTree = ""; }; - 0E05016B268603CE007060C4 /* UniversalLinkRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniversalLinkRouter.swift; sourceTree = ""; }; - 0E050178268603DD007060C4 /* ChartFilterOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartFilterOperation.swift; sourceTree = ""; }; - 0E09671F22AE7F5C00E85F48 /* Welcome.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Welcome.storyboard; sourceTree = ""; }; - 0E09672122AE7FCF00E85F48 /* WelcomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeViewController.swift; sourceTree = ""; }; - 0E09672422AE897000E85F48 /* CALayer+IB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CALayer+IB.swift"; sourceTree = ""; }; - 0E09672722AE8D7A00E85F48 /* Discover.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Discover.storyboard; sourceTree = ""; }; - 0E09672B22AE94F000E85F48 /* DiscoverDeviceTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverDeviceTableViewCell.swift; sourceTree = ""; }; - 0E0A381823616AC3003A0364 /* UserDefaults+Optional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Optional.swift"; sourceTree = ""; }; - 0E11D140267DFA30002D0686 /* RuuviReactor */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviReactor; path = Packages/RuuviReactor; sourceTree = ""; }; - 0E11D141267DFA30002D0686 /* RuuviDaemon */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviDaemon; path = Packages/RuuviDaemon; sourceTree = ""; }; - 0E11D142267DFA30002D0686 /* RuuviRepository */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviRepository; path = Packages/RuuviRepository; sourceTree = ""; }; - 0E11D143267DFA30002D0686 /* RuuviContext */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviContext; path = Packages/RuuviContext; sourceTree = ""; }; - 0E11D144267DFA31002D0686 /* RuuviUser */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviUser; path = Packages/RuuviUser; sourceTree = ""; }; - 0E11D145267DFA31002D0686 /* RuuviCore */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviCore; path = Packages/RuuviCore; sourceTree = ""; }; - 0E11D146267DFA31002D0686 /* RuuviCloud */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviCloud; path = Packages/RuuviCloud; sourceTree = ""; }; - 0E11D147267DFA31002D0686 /* RuuviOntology */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviOntology; path = Packages/RuuviOntology; sourceTree = ""; }; - 0E11D148267DFA31002D0686 /* RuuviPersistence */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviPersistence; path = Packages/RuuviPersistence; sourceTree = ""; }; - 0E11D149267DFA31002D0686 /* RuuviService */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviService; path = Packages/RuuviService; sourceTree = ""; }; - 0E11D14A267DFA31002D0686 /* RuuviPool */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviPool; path = Packages/RuuviPool; sourceTree = ""; }; - 0E11D14B267DFA31002D0686 /* RuuviStorage */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviStorage; path = Packages/RuuviStorage; sourceTree = ""; }; - 0E11D14C267DFA31002D0686 /* RuuviLocal */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviLocal; path = Packages/RuuviLocal; sourceTree = ""; }; - 0E197C6023C352380074015B /* TagSettingsAlertDescriptionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsAlertDescriptionCell.swift; sourceTree = ""; }; - 0E197C6523C4A47A0074015B /* MailComposerPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailComposerPresenter.swift; sourceTree = ""; }; - 0E197C6A23C4A52A0074015B /* MailComposerPresenterMessageUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailComposerPresenterMessageUI.swift; sourceTree = ""; }; - 0E197C6E23C4A7D00074015B /* Presentation.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Presentation.plist; sourceTree = ""; }; - 0E197C7C23C5CD7C0074015B /* UIDevice+ReadableModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+ReadableModel.swift"; sourceTree = ""; }; - 0E197C8023C5CDBE0074015B /* iOSDeviceModelMapping.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = iOSDeviceModelMapping.plist; sourceTree = ""; }; - 0E1B2F31239DEF120060C469 /* TagSettingsAlertHeaderCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsAlertHeaderCell.swift; sourceTree = ""; }; - 0E1B2F35239DF0120060C469 /* TagSettingsAlertControlsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsAlertControlsCell.swift; sourceTree = ""; }; - 0E1C1DA722B387A00032F6CA /* AppAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppAssembly.swift; sourceTree = ""; }; - 0E1C1DAE22B38F780032F6CA /* ActivityPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityPresenter.swift; sourceTree = ""; }; - 0E1C1DB222B390080032F6CA /* ActivityPresenterRuuviLogo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityPresenterRuuviLogo.swift; sourceTree = ""; }; - 0E1C1DB422B3903B0032F6CA /* ActivityRuuviLogo.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ActivityRuuviLogo.storyboard; sourceTree = ""; }; - 0E1C1DB622B390BC0032F6CA /* ActivityRuuviLogoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityRuuviLogoViewController.swift; sourceTree = ""; }; - 0E1C1DB822B390ED0032F6CA /* ActivitySpinnerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivitySpinnerView.swift; sourceTree = ""; }; - 0E1C1DBA22B3919F0032F6CA /* UIApplication+ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+ViewController.swift"; sourceTree = ""; }; - 0E1C1DBD22B3921E0032F6CA /* PresentationAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentationAssembly.swift; sourceTree = ""; }; - 0E1C1DC022B3955E0032F6CA /* ErrorPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorPresenter.swift; sourceTree = ""; }; - 0E1C1DC322B395C00032F6CA /* ErrorPresenterAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorPresenterAlert.swift; sourceTree = ""; }; - 0E1C1DD022B3BDFC0032F6CA /* Cards.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Cards.storyboard; sourceTree = ""; }; - 0E1C1DD222B3BF180032F6CA /* CardsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsViewInput.swift; sourceTree = ""; }; - 0E1C1DD422B3BF3A0032F6CA /* CardsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsViewOutput.swift; sourceTree = ""; }; - 0E1C1DDC22B3C2160032F6CA /* CardsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsModuleInput.swift; sourceTree = ""; }; - 0E1C1DDE22B3C2330032F6CA /* CardsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsPresenter.swift; sourceTree = ""; }; - 0E1C1DE122B3C25F0032F6CA /* CardsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsRouterInput.swift; sourceTree = ""; }; - 0E1C1DE322B3C2710032F6CA /* CardsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsRouter.swift; sourceTree = ""; }; - 0E1C1DE722B3C2B60032F6CA /* CardsScrollInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsScrollInitializer.swift; sourceTree = ""; }; - 0E1C1DE922B3C2E60032F6CA /* CardsScrollConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsScrollConfigurator.swift; sourceTree = ""; }; - 0E1C1DF022B3FDE30032F6CA /* Menu.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Menu.storyboard; sourceTree = ""; }; - 0E1C1DF222B3FEFF0032F6CA /* MenuViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuViewInput.swift; sourceTree = ""; }; - 0E1C1DF422B3FF1D0032F6CA /* MenuViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuViewOutput.swift; sourceTree = ""; }; - 0E1C1DF722B3FF480032F6CA /* MenuTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableViewController.swift; sourceTree = ""; }; - 0E1C1DF922B3FFBF0032F6CA /* MenuRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuRouterInput.swift; sourceTree = ""; }; - 0E1C1DFB22B3FFD90032F6CA /* MenuRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuRouter.swift; sourceTree = ""; }; - 0E1C1DFD22B3FFFC0032F6CA /* MenuModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuModuleInput.swift; sourceTree = ""; }; - 0E1C1DFF22B400130032F6CA /* MenuPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuPresenter.swift; sourceTree = ""; }; - 0E1C1E0222B400590032F6CA /* MenuTableInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableInitializer.swift; sourceTree = ""; }; - 0E1C1E0422B400890032F6CA /* MenuTableConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableConfigurator.swift; sourceTree = ""; }; - 0E1C1E0822B4024E0032F6CA /* MenuTableTransitioningDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableTransitioningDelegate.swift; sourceTree = ""; }; - 0E1C1E0A22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTablePresentTransitionAnimation.swift; sourceTree = ""; }; - 0E1C1E0C22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableDismissTransitionAnimation.swift; sourceTree = ""; }; - 0E1C1E0E22B4049E0032F6CA /* MenuTablePresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTablePresentationController.swift; sourceTree = ""; }; - 0E1C1E1022B756B40032F6CA /* CardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardView.swift; sourceTree = ""; }; - 0E1C1E1222B756D30032F6CA /* CardView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CardView.xib; sourceTree = ""; }; - 0E211C29234C5FE900FC37B0 /* CardsRouterDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsRouterDelegate.swift; sourceTree = ""; }; - 0E2513642684CDF0004A522A /* RuuviNotifier */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviNotifier; path = Packages/RuuviNotifier; sourceTree = ""; }; - 0E290A842660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+AnyRuuviTagSensor.swift"; sourceTree = ""; }; - 0E2AFF9F266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviRepositoryError+LocalizedError.swift"; sourceTree = ""; }; - 0E31B04123BBA37C00660412 /* WebTagSettingsAlertsHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsAlertsHeaderFooterView.swift; sourceTree = ""; }; - 0E31B04523BBA3F900660412 /* WebTagSettingsAlertsHeaderFooterView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = WebTagSettingsAlertsHeaderFooterView.xib; sourceTree = ""; }; - 0E341BBC2372E75C0085BB54 /* TagChartsTransitionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsTransitionManager.swift; sourceTree = ""; }; - 0E3FF734238157B700EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DiscoverWebTagsInfoHeaderFooterView.xib; sourceTree = ""; }; - 0E3FF7362381591800EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscoverWebTagsInfoHeaderFooterView.swift; sourceTree = ""; }; - 0E502FBD22B2817900E8A6CC /* DiscoverRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverRouterInput.swift; sourceTree = ""; }; - 0E502FBF22B2819B00E8A6CC /* DiscoverRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverRouter.swift; sourceTree = ""; }; - 0E53A3F2232DFC6200ACED49 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 0E53A3F4232DFC6400ACED49 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = ""; }; - 0E53A3F5232DFC6500ACED49 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/InfoPlist.strings; sourceTree = ""; }; - 0E53A3FA232F4D5000ACED49 /* DiscoverNoDevicesTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverNoDevicesTableViewCell.swift; sourceTree = ""; }; - 0E53DA5F22CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeDownToDismissTransitioningDelegate.swift; sourceTree = ""; }; - 0E53DA6122CC93EB00BC6D64 /* SwipeDownToDismissTransitionAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeDownToDismissTransitionAnimation.swift; sourceTree = ""; }; - 0E53DA6322CC943900BC6D64 /* SwipeDownToDismissInteractiveTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeDownToDismissInteractiveTransition.swift; sourceTree = ""; }; - 0E53DA6622CC964200BC6D64 /* SwipeDownToDismissNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeDownToDismissNavigationController.swift; sourceTree = ""; }; - 0E5C300A22CF629100B52E39 /* PhotoPickerPresenterSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPickerPresenterSheet.swift; sourceTree = ""; }; - 0E5C301922CF644900B52E39 /* PermissionPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionPresenter.swift; sourceTree = ""; }; - 0E5C301B22CF646A00B52E39 /* PermissionPresenterAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionPresenterAlert.swift; sourceTree = ""; }; - 0E62297826A7F84F0041DCDD /* OnboardRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardRouter.swift; sourceTree = ""; }; - 0E62297926A7F84F0041DCDD /* AppRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppRouter.swift; sourceTree = ""; }; - 0E62297E26A7F8890041DCDD /* RuuviOnboard */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviOnboard; path = Modules/RuuviOnboard; sourceTree = ""; }; - 0E62AEC822E065CC00A49BFB /* TagSettingsMoreInfoHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsMoreInfoHeaderFooterView.swift; sourceTree = ""; }; - 0E62AECA22E065F000A49BFB /* TagSettingsMoreInfoHeaderFooterView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TagSettingsMoreInfoHeaderFooterView.xib; sourceTree = ""; }; - 0E6C471623D305960016B46E /* StationUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StationUITests.swift; sourceTree = ""; }; - 0E70A45F22AF9567006CB87C /* ViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewInput.swift; sourceTree = ""; }; - 0E70A46222AF959E006CB87C /* Localizable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Localizable.swift; sourceTree = ""; }; - 0E70A46B22AF9705006CB87C /* DiscoverTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscoverTableViewController.swift; sourceTree = ""; }; - 0E70A46D22AF9763006CB87C /* DiscoverViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverViewInput.swift; sourceTree = ""; }; - 0E70A46F22AF9790006CB87C /* DiscoverViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverViewOutput.swift; sourceTree = ""; }; - 0E70A47222AF9953006CB87C /* DiscoverModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverModuleInput.swift; sourceTree = ""; }; - 0E70A47422AF9978006CB87C /* DiscoverPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverPresenter.swift; sourceTree = ""; }; - 0E70A47A22AF9BE2006CB87C /* DiscoverTableInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscoverTableInitializer.swift; sourceTree = ""; }; - 0E70A47C22AF9BFE006CB87C /* DiscoverTableConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverTableConfigurator.swift; sourceTree = ""; }; - 0E79F28A244328D50048BF86 /* DiscoverAddWithMACTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverAddWithMACTableViewCell.swift; sourceTree = ""; }; - 0E84BF4C239795AF00A37E1A /* DiscoverModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverModuleOutput.swift; sourceTree = ""; }; - 0E84BF542397F29800A37E1A /* Heartbeat.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Heartbeat.storyboard; sourceTree = ""; }; - 0E84BF562397F33E00A37E1A /* HeartbeatViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatViewInput.swift; sourceTree = ""; }; - 0E84BF582397F3C600A37E1A /* HeartbeatViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatViewModel.swift; sourceTree = ""; }; - 0E84BF5A2397F3DF00A37E1A /* HeartbeatViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatViewOutput.swift; sourceTree = ""; }; - 0E84BF5E2397F6BE00A37E1A /* HeartbeatViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatViewController.swift; sourceTree = ""; }; - 0E84BF602397F73100A37E1A /* HeartbeatEnvironmentObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatEnvironmentObject.swift; sourceTree = ""; }; - 0E84BF622397F76A00A37E1A /* HeartbeatList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatList.swift; sourceTree = ""; }; - 0E84BF642397F9DC00A37E1A /* HeartbeatTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatTableViewController.swift; sourceTree = ""; }; - 0E84BF66239801AF00A37E1A /* HeartbeatRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatRouterInput.swift; sourceTree = ""; }; - 0E84BF68239801C100A37E1A /* HeartbeatRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatRouter.swift; sourceTree = ""; }; - 0E84BF6A239802A400A37E1A /* HeartbeatModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatModuleInput.swift; sourceTree = ""; }; - 0E84BF6C239802CA00A37E1A /* HeartbeatPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatPresenter.swift; sourceTree = ""; }; - 0E84BF6E2398031B00A37E1A /* HeartbeatInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatInitializer.swift; sourceTree = ""; }; - 0E84BF702398035C00A37E1A /* HeartbeatConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatConfigurator.swift; sourceTree = ""; }; - 0E8A100123845E5100A9CBA6 /* Defaults.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Defaults.storyboard; sourceTree = ""; }; - 0E8A100923845F3900A9CBA6 /* DefaultsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsViewController.swift; sourceTree = ""; }; - 0E8A100B23845F7100A9CBA6 /* DefaultsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsViewInput.swift; sourceTree = ""; }; - 0E8A100D23845F8C00A9CBA6 /* DefaultsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsViewOutput.swift; sourceTree = ""; }; - 0E8A100F23845FAE00A9CBA6 /* DefaultsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsViewModel.swift; sourceTree = ""; }; - 0E8A10112384605A00A9CBA6 /* DefaultsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsTableViewController.swift; sourceTree = ""; }; - 0E8A10132384610400A9CBA6 /* DefaultsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsRouter.swift; sourceTree = ""; }; - 0E8A10152384612300A9CBA6 /* DefaultsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsRouterInput.swift; sourceTree = ""; }; - 0E8A10172384613E00A9CBA6 /* DefaultsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsModuleInput.swift; sourceTree = ""; }; - 0E8A10192384615400A9CBA6 /* DefaultsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsPresenter.swift; sourceTree = ""; }; - 0E8A101B2384618700A9CBA6 /* DefaultsInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsInitializer.swift; sourceTree = ""; }; - 0E8A101D238461D400A9CBA6 /* DefaultsConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsConfigurator.swift; sourceTree = ""; }; - 0E8A101F2384633200A9CBA6 /* DefaultsEnvironmentObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsEnvironmentObject.swift; sourceTree = ""; }; - 0E8A10212384637F00A9CBA6 /* DefaultsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsList.swift; sourceTree = ""; }; - 0E8A102423846CEB00A9CBA6 /* DefaultsSwitchTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsSwitchTableViewCell.swift; sourceTree = ""; }; - 0E8BAC97245C716B00D380FB /* Combine.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Combine.framework; path = System/Library/Frameworks/Combine.framework; sourceTree = SDKROOT; }; - 0E8BD2AA23851CF2008B31EF /* DefaultsStepperTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsStepperTableViewCell.swift; sourceTree = ""; }; - 0E8BD404238566AB008B31EF /* station_dev.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = station_dev.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 0E8E3D5E268227530082EC29 /* RuuviCoreError+LocalizedError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RuuviCoreError+LocalizedError.swift"; sourceTree = ""; }; - 0E8E3D5F268227530082EC29 /* RuuviVirtualError+LocalizedError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RuuviVirtualError+LocalizedError.swift"; sourceTree = ""; }; - 0E8E3D68268228130082EC29 /* DiscoverRuuviTagViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscoverRuuviTagViewModel.swift; sourceTree = ""; }; - 0E8E3D69268228130082EC29 /* DiscoverVirtualTagViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscoverVirtualTagViewModel.swift; sourceTree = ""; }; - 0E8E3D6E2682284D0082EC29 /* RuuviVirtual */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviVirtual; path = Packages/RuuviVirtual; sourceTree = ""; }; - 0E8E3D9A26822A850082EC29 /* RuuviLocation */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviLocation; path = Packages/RuuviLocation; sourceTree = ""; }; - 0E8FD0BE23335D6900FFA577 /* TagCharts.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = TagCharts.storyboard; sourceTree = ""; }; - 0E8FD0C023335D8400FFA577 /* TagChartsScrollViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsScrollViewController.swift; sourceTree = ""; }; - 0E8FD0C223335DA700FFA577 /* TagChartsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewInput.swift; sourceTree = ""; }; - 0E8FD0C423335DBF00FFA577 /* TagChartsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewOutput.swift; sourceTree = ""; }; - 0E8FD0C6233366DC00FFA577 /* TagChartsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsRouterInput.swift; sourceTree = ""; }; - 0E8FD0C8233366F000FFA577 /* TagChartsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsRouter.swift; sourceTree = ""; }; - 0E8FD0CA2333671100FFA577 /* TagChartsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsModuleInput.swift; sourceTree = ""; }; - 0E8FD0CC2333672F00FFA577 /* TagChartsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsPresenter.swift; sourceTree = ""; }; - 0E8FD0CE2333676C00FFA577 /* TagChartsScrollInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsScrollInitializer.swift; sourceTree = ""; }; - 0E8FD0D02333679800FFA577 /* TagChartsScrollConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsScrollConfigurator.swift; sourceTree = ""; }; - 0E8FD0D223336B4200FFA577 /* TagChartsTransitioningDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsTransitioningDelegate.swift; sourceTree = ""; }; - 0E8FD0D423336BA300FFA577 /* TagChartsPresentTransitionAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsPresentTransitionAnimation.swift; sourceTree = ""; }; - 0E8FD0D623336C6E00FFA577 /* TagChartsDismissTransitionAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsDismissTransitionAnimation.swift; sourceTree = ""; }; - 0E8FD0DC2333714C00FFA577 /* TagChartsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewModel.swift; sourceTree = ""; }; - 0E8FD0E22333893600FFA577 /* TagChartsModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsModuleOutput.swift; sourceTree = ""; }; - 0E92A94C2686366C00187E4F /* TemperatureUnit+Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TemperatureUnit+Localization.swift"; sourceTree = ""; }; - 0E92A94E2686366C00187E4F /* ExportHeadersProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExportHeadersProvider.swift; sourceTree = ""; }; - 0E92A94F2686366C00187E4F /* HeartbeatDaemonTitles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeartbeatDaemonTitles.swift; sourceTree = ""; }; - 0E92A9502686366C00187E4F /* RuuviNotifierTitlesImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RuuviNotifierTitlesImpl.swift; sourceTree = ""; }; - 0E92A9512686366C00187E4F /* MeasurementType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeasurementType.swift; sourceTree = ""; }; - 0E92A9522686366C00187E4F /* HumidityUnit+Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "HumidityUnit+Localization.swift"; sourceTree = ""; }; - 0E92A9532686366D00187E4F /* Language+Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Language+Localization.swift"; sourceTree = ""; }; - 0E92A9542686366D00187E4F /* VirtualLocation+Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "VirtualLocation+Localization.swift"; sourceTree = ""; }; - 0E92A9652686367F00187E4F /* RUError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RUError.swift; sourceTree = ""; }; - 0E92A9682686369200187E4F /* DateValueFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateValueFormatter.swift; sourceTree = ""; }; - 0E92A96B2686369E00187E4F /* Debouncer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Debouncer.swift; sourceTree = ""; }; - 0E9D0AAF231E9BD800C6BDA7 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - 0E9D0AB0231EBEFD00C6BDA7 /* LocalizationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationService.swift; sourceTree = ""; }; - 0E9D5F1F2351BE3C0076FFD8 /* ForegroundSwitchTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundSwitchTableViewCell.swift; sourceTree = ""; }; - 0E9E7759238CCE5F006D7013 /* String+Replace.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Replace.swift"; sourceTree = ""; }; - 0E9F979522EAFC820015ADE2 /* DiscoverWebTagTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverWebTagTableViewCell.swift; sourceTree = ""; }; - 0EA796702664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviCloudError+LocalizedError.swift"; sourceTree = ""; }; - 0EA796742664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviCloudApiError+LocalizedError.swift"; sourceTree = ""; }; - 0EA796782664B37F002BA25D /* RuuviLocalError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviLocalError+LocalizedError.swift"; sourceTree = ""; }; - 0EA7967C2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviPersistenceError+LocalizedError.swift"; sourceTree = ""; }; - 0EA796802664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviPoolError+LocalizedError.swift"; sourceTree = ""; }; - 0EA796842664B84D002BA25D /* RuuviReactorError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviReactorError+LocalizedError.swift"; sourceTree = ""; }; - 0EA796882664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviServiceError+LocalizedError.swift"; sourceTree = ""; }; - 0EA7968C2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviStorageError+LocalizedError.swift"; sourceTree = ""; }; - 0EA92FDA2387E734008F1558 /* TagSettingsAlertsHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsAlertsHeaderFooterView.swift; sourceTree = ""; }; - 0EA92FDE2387E74C008F1558 /* TagSettingsAlertsHeaderFooterView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TagSettingsAlertsHeaderFooterView.xib; sourceTree = ""; }; - 0EB48DE5261A1816008E0D2D /* FeatureToggles.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = FeatureToggles.json; sourceTree = ""; }; - 0EB66B0A2686053800375BCC /* FeatureToggleProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureToggleProvider.swift; sourceTree = ""; }; - 0EB66B0B2686053800375BCC /* FallbackFeatureToggleProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FallbackFeatureToggleProvider.swift; sourceTree = ""; }; - 0EB66B0C2686053800375BCC /* FirebaseFeatureToggleProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirebaseFeatureToggleProvider.swift; sourceTree = ""; }; - 0EB66B0D2686053800375BCC /* LocalFeatureToggleProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalFeatureToggleProvider.swift; sourceTree = ""; }; - 0EB66B102686053800375BCC /* FirebaseRemoteConfigService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirebaseRemoteConfigService.swift; sourceTree = ""; }; - 0EB66B112686053800375BCC /* RemoteConfigService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteConfigService.swift; sourceTree = ""; }; - 0EB66B122686053800375BCC /* FeatureToggleService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureToggleService.swift; sourceTree = ""; }; - 0EB66B132686053800375BCC /* FeatureToggle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureToggle.swift; sourceTree = ""; }; - 0EB66B162686053800375BCC /* InfoProviderImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InfoProviderImpl.swift; sourceTree = ""; }; - 0EB66B172686053800375BCC /* InfoProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InfoProvider.swift; sourceTree = ""; }; - 0EB8B9122683517100FE130E /* RuuviMigration */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviMigration; path = Packages/RuuviMigration; sourceTree = ""; }; - 0EB8B9262683592700FE130E /* Networking.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Networking.plist; sourceTree = ""; }; - 0EB8B94126849F2B00FE130E /* RuuviNotification */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviNotification; path = Packages/RuuviNotification; sourceTree = ""; }; - 0EBAF06B232006E00025A191 /* Language.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Language.storyboard; sourceTree = ""; }; - 0EBAF06D232007510025A191 /* LanguageViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageViewInput.swift; sourceTree = ""; }; - 0EBAF06F232007740025A191 /* LanguageViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageViewOutput.swift; sourceTree = ""; }; - 0EBAF071232007910025A191 /* LanguageTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageTableViewController.swift; sourceTree = ""; }; - 0EBAF074232007CC0025A191 /* LanguageRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageRouterInput.swift; sourceTree = ""; }; - 0EBAF076232007D80025A191 /* LanguageRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageRouter.swift; sourceTree = ""; }; - 0EBAF078232008140025A191 /* LanguageModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageModuleInput.swift; sourceTree = ""; }; - 0EBAF07A232008420025A191 /* LanguagePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguagePresenter.swift; sourceTree = ""; }; - 0EBAF07D2320086A0025A191 /* LanguageTableInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageTableInitializer.swift; sourceTree = ""; }; - 0EBAF07F2320089A0025A191 /* LanguageTableConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageTableConfigurator.swift; sourceTree = ""; }; - 0EBAF08123200B1B0025A191 /* LanguageTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageTableViewCell.swift; sourceTree = ""; }; - 0EBAF0832320120F0025A191 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - 0EC50F4F22CCB92000172EEB /* Observable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Observable.swift; sourceTree = ""; }; - 0EC50F5122CCB9DE00172EEB /* TagSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsViewModel.swift; sourceTree = ""; }; - 0EC50F5322CCBBE800172EEB /* NSObject+Observable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSObject+Observable.swift"; sourceTree = ""; }; - 0EC50F5522CCE46D00172EEB /* Optional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Optional.swift; sourceTree = ""; }; - 0EC50F5822CF621000172EEB /* PhotoPickerPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPickerPresenter.swift; sourceTree = ""; }; - 0ECB5A8D2381807500E78757 /* CardsScrollViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardsScrollViewController.swift; sourceTree = ""; }; - 0ECDF1B42313D65500A09ACA /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; - 0ECDF1B62313D7DA00A09ACA /* station.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = station.entitlements; sourceTree = ""; }; - 0ECFF354235056DC0061D11B /* ForegroundList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundList.swift; sourceTree = ""; }; - 0ECFF35623505F8D0061D11B /* Foreground.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Foreground.storyboard; sourceTree = ""; }; - 0ECFF358235060EF0061D11B /* ForegroundViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundViewController.swift; sourceTree = ""; }; - 0ECFF35A2350618E0061D11B /* ForegroundModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundModuleInput.swift; sourceTree = ""; }; - 0ECFF35D23506BC40061D11B /* ForegroundViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundViewOutput.swift; sourceTree = ""; }; - 0ECFF35F23506BD60061D11B /* ForegroundViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundViewInput.swift; sourceTree = ""; }; - 0ECFF36123506C050061D11B /* ForegroundRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundRow.swift; sourceTree = ""; }; - 0ECFF365235079F50061D11B /* ForegroundPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundPresenter.swift; sourceTree = ""; }; - 0ECFF36723507A1A0061D11B /* ForegroundRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundRouterInput.swift; sourceTree = ""; }; - 0ECFF36B23507BC00061D11B /* ForegroundInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundInitializer.swift; sourceTree = ""; }; - 0ECFF36D23507BF00061D11B /* ForegroundConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundConfigurator.swift; sourceTree = ""; }; - 0ECFF36F23507CE80061D11B /* ForegroundViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundViewModel.swift; sourceTree = ""; }; - 0EE36E46269748A70021B746 /* FirmwareRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirmwareRepository.swift; sourceTree = ""; }; - 0EE36E48269748A70021B746 /* DFUModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DFUModuleInput.swift; sourceTree = ""; }; - 0EE36E49269748A70021B746 /* DFUPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DFUPresenter.swift; sourceTree = ""; }; - 0EE36E4B269748A70021B746 /* Publishers+System.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Publishers+System.swift"; sourceTree = ""; }; - 0EE36E4C269748A70021B746 /* URLSession+downloadTaskPublisher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "URLSession+downloadTaskPublisher.swift"; sourceTree = ""; }; - 0EE36E4D269748A70021B746 /* View+Any.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+Any.swift"; sourceTree = ""; }; - 0EE36E4F269748A70021B746 /* Spinner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Spinner.swift; sourceTree = ""; }; - 0EE36E50269748A70021B746 /* LargeButtonStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LargeButtonStyle.swift; sourceTree = ""; }; - 0EE36E51269748A70021B746 /* ProgressBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; - 0EE36E52269748A70021B746 /* Feedback.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Feedback.swift; sourceTree = ""; }; - 0EE36E54269748A70021B746 /* DFUViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DFUViewModel.swift; sourceTree = ""; }; - 0EE36E56269748A70021B746 /* DFUUIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DFUUIView.swift; sourceTree = ""; }; - 0EE36E58269748A70021B746 /* DFUInteractorInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DFUInteractorInput.swift; sourceTree = ""; }; - 0EE36E59269748A70021B746 /* DFUInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DFUInteractor.swift; sourceTree = ""; }; - 0EE36E5A269748A70021B746 /* LatestRelease.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LatestRelease.swift; sourceTree = ""; }; - 0EE36E5B269748A70021B746 /* DFUModuleFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DFUModuleFactory.swift; sourceTree = ""; }; - 0EE36E7D269749270021B746 /* RuuviColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RuuviColor.swift; sourceTree = ""; }; - 0EE49B9423B74775003012C2 /* WebTagSettingsAlertHeaderCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsAlertHeaderCell.swift; sourceTree = ""; }; - 0EE49B9823B877CF003012C2 /* WebTagSettingsAlertControlsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsAlertControlsCell.swift; sourceTree = ""; }; - 0EE49BB123B8C40D003012C2 /* MacInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = MacInfo.plist; sourceTree = ""; }; - 0EE49BB223B8C40D003012C2 /* DevInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = DevInfo.plist; sourceTree = ""; }; - 0EE5B47C23508F6D00D5ED32 /* ForegroundEnvironmentObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundEnvironmentObject.swift; sourceTree = ""; }; - 0EE98A7826493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLEXFeatureTogglesViewController.swift; sourceTree = ""; }; - 0EEB20C522B7915C0015F9E0 /* CardsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsViewModel.swift; sourceTree = ""; }; - 0EEB20C822B7A7200015F9E0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - 0EEB20CA22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableEmbededViewController.swift; sourceTree = ""; }; - 0EEB20CC22B7BD6C0015F9E0 /* MenuModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuModuleOutput.swift; sourceTree = ""; }; - 0EEB20D022B7C6F30015F9E0 /* Settings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Settings.storyboard; sourceTree = ""; }; - 0EEB20D222B7C7AC0015F9E0 /* SettingsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableViewController.swift; sourceTree = ""; }; - 0EEB20D522B7C7E70015F9E0 /* SettingsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewInput.swift; sourceTree = ""; }; - 0EEB20D722B7C8060015F9E0 /* SettingsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewOutput.swift; sourceTree = ""; }; - 0EEB20DC22B7C8650015F9E0 /* SettingsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsRouterInput.swift; sourceTree = ""; }; - 0EEB20DE22B7C8790015F9E0 /* SettingsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsRouter.swift; sourceTree = ""; }; - 0EEB20E022B7C8A90015F9E0 /* SettingsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsModuleInput.swift; sourceTree = ""; }; - 0EEB20E222B7C8C10015F9E0 /* SettingsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsPresenter.swift; sourceTree = ""; }; - 0EEB20E522B7C8F20015F9E0 /* SettingsTableInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableInitializer.swift; sourceTree = ""; }; - 0EEB20E722B7C92C0015F9E0 /* SettingsTableConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableConfigurator.swift; sourceTree = ""; }; - 0EEB20EE22B7D1580015F9E0 /* About.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = About.storyboard; sourceTree = ""; }; - 0EEB20F222B7D1900015F9E0 /* AboutViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewInput.swift; sourceTree = ""; }; - 0EEB20F422B7D1A40015F9E0 /* AboutViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewOutput.swift; sourceTree = ""; }; - 0EEB20F622B7D2090015F9E0 /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = ""; }; - 0EEB20F822B7D28C0015F9E0 /* AboutRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutRouterInput.swift; sourceTree = ""; }; - 0EEB20FA22B7D2990015F9E0 /* AboutRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutRouter.swift; sourceTree = ""; }; - 0EEB20FC22B7D2C90015F9E0 /* AboutModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutModuleInput.swift; sourceTree = ""; }; - 0EEB20FE22B7D2DD0015F9E0 /* AboutPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutPresenter.swift; sourceTree = ""; }; - 0EEB210022B7D2F50015F9E0 /* AboutInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutInitializer.swift; sourceTree = ""; }; - 0EEB210222B7D3210015F9E0 /* AboutConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutConfigurator.swift; sourceTree = ""; }; - 0EEB213B22B8FAD50015F9E0 /* MainRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainRouter.swift; sourceTree = ""; }; - 0EEB213E22B8FB840015F9E0 /* MainNavigationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainNavigationDelegate.swift; sourceTree = ""; }; - 0EEB214122B8FBA50015F9E0 /* MainInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainInitializer.swift; sourceTree = ""; }; - 0EEB214322B8FBC50015F9E0 /* MainConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainConfigurator.swift; sourceTree = ""; }; - 0EEB214622B8FC3E0015F9E0 /* WelcomeViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeViewInput.swift; sourceTree = ""; }; - 0EEB214822B8FC570015F9E0 /* WelcomeViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeViewOutput.swift; sourceTree = ""; }; - 0EEB214B22B8FCC70015F9E0 /* WelcomeRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeRouterInput.swift; sourceTree = ""; }; - 0EEB214D22B8FCDC0015F9E0 /* WelcomeRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeRouter.swift; sourceTree = ""; }; - 0EEB215022B8FD070015F9E0 /* WelcomeModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeModuleInput.swift; sourceTree = ""; }; - 0EEB215222B8FD1F0015F9E0 /* WelcomePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomePresenter.swift; sourceTree = ""; }; - 0EEB215522B8FD590015F9E0 /* WelcomeInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeInitializer.swift; sourceTree = ""; }; - 0EEB215722B8FD800015F9E0 /* WelcomeConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeConfigurator.swift; sourceTree = ""; }; - 0EEB215922BA28860015F9E0 /* MenuTableTransitionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableTransitionManager.swift; sourceTree = ""; }; - 0EF2862B22CBAF5D0026C7A5 /* TagSettings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = TagSettings.storyboard; sourceTree = ""; }; - 0EF2862D22CBAFC80026C7A5 /* TagSettingsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsTableViewController.swift; sourceTree = ""; }; - 0EF2863022CBB00D0026C7A5 /* TagSettingsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsViewInput.swift; sourceTree = ""; }; - 0EF2863222CBB0250026C7A5 /* TagSettingsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsViewOutput.swift; sourceTree = ""; }; - 0EF2863422CBB03A0026C7A5 /* TagSettingsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsRouterInput.swift; sourceTree = ""; }; - 0EF2863622CBB04E0026C7A5 /* TagSettingsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsRouter.swift; sourceTree = ""; }; - 0EF2863822CBB06C0026C7A5 /* TagSettingsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsModuleInput.swift; sourceTree = ""; }; - 0EF2863A22CBB08C0026C7A5 /* TagSettingsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsPresenter.swift; sourceTree = ""; }; - 0EF2863F22CBB1340026C7A5 /* TagSettingsTableInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TagSettingsTableInitializer.swift; sourceTree = ""; }; - 0EF2864122CBB13F0026C7A5 /* TagSettingsTableConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsTableConfigurator.swift; sourceTree = ""; }; - 0EF3D9E726860B5C0040A85E /* RuuviAnalytics */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviAnalytics; path = Packages/RuuviAnalytics; sourceTree = ""; }; - 0EF4E342268318BE00D83CC7 /* RuuviDFU */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviDFU; path = Packages/RuuviDFU; sourceTree = ""; }; - 0EF4E34E268319A400D83CC7 /* DfuFirmware+Log.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DfuFirmware+Log.swift"; sourceTree = ""; }; - 0EF5B72A22D62CD900D9D14A /* Date+Ruuvi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Ruuvi.swift"; sourceTree = ""; }; - 0EF6F5BD235E01170052BA25 /* ForegroundRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForegroundRouter.swift; sourceTree = ""; }; - 0EF6F5BF235E01CD0052BA25 /* ForegroundStepperTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForegroundStepperTableViewCell.swift; sourceTree = ""; }; - 0EF6F5C1235E02000052BA25 /* ForegroundTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForegroundTableViewController.swift; sourceTree = ""; }; - 167F75FD2FDAD002C10686FA /* ShareViewInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareViewInput.swift; sourceTree = ""; }; - 28B469B53431F206F4D0EC60 /* SignInConfigurator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInConfigurator.swift; sourceTree = ""; }; - 310159B7264484D700A5E8E8 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Main.strings; sourceTree = ""; }; - 310159B82644864400A5E8E8 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - 310159B92644864C00A5E8E8 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = ""; }; - 354B5B6F50E98F55D6A672BA /* ShareViewModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareViewModel.swift; sourceTree = ""; }; - 392F0E992BEAA3382C2CF709 /* ShareInitializer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareInitializer.swift; sourceTree = ""; }; - 4A7D6325DFC865D2D11BD1D1 /* SignInViewInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInViewInput.swift; sourceTree = ""; }; - 4BD498E7491E278B4EF4919C /* SignInViewOutput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInViewOutput.swift; sourceTree = ""; }; - 4E816312622E83E3B42001DC /* SignInRouterInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInRouterInput.swift; sourceTree = ""; }; - 5710E4EF18D419D01D60405E /* ShareModuleOutput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareModuleOutput.swift; sourceTree = ""; }; - 64333D2520B0C45900CDF4B6 /* station.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = station.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 64333D2820B0C45900CDF4B6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 64333D2D20B0C45900CDF4B6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 64333D2F20B0C45A00CDF4B6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 64333D3220B0C45A00CDF4B6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 64333D3420B0C45A00CDF4B6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 64333D3920B0C45A00CDF4B6 /* stationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = stationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 64333D3D20B0C45A00CDF4B6 /* StationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StationTests.swift; sourceTree = ""; }; - 64333D3F20B0C45B00CDF4B6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 64333D4420B0C45B00CDF4B6 /* stationUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = stationUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 64333D4A20B0C45B00CDF4B6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 643C651E21C38F490037BE5B /* Montserrat-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Montserrat-Bold.ttf"; sourceTree = ""; }; - 643EEC2A2266435100D4E837 /* Oswald-ExtraLight.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Oswald-ExtraLight.ttf"; sourceTree = ""; }; - 6467818F225CFB170072856A /* Muli-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Muli-Regular.ttf"; sourceTree = ""; }; - 64678190225D02CE0072856A /* Muli-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Muli-Bold.ttf"; sourceTree = ""; }; - 6486970F20E042E000CCD7C1 /* Oswald-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Oswald-Bold.ttf"; sourceTree = ""; }; - 6486971120E0439200CCD7C1 /* Montserrat-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Montserrat-Regular.ttf"; sourceTree = ""; }; - 64A2DAE224310B2900DE6699 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - 64A2DAE324310B2900DE6699 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InfoPlist.strings; sourceTree = ""; }; - 660EB2462669278E000FD22B /* DfuDevicesScannerConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerConfigurator.swift; sourceTree = ""; }; - 660EB2472669278E000FD22B /* DfuDevicesScannerInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerInitializer.swift; sourceTree = ""; }; - 660EB2492669278E000FD22B /* DfuDevicesScannerPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerPresenter.swift; sourceTree = ""; }; - 660EB24A2669278E000FD22B /* DfuDevicesScannerModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerModuleInput.swift; sourceTree = ""; }; - 660EB24B2669278E000FD22B /* DfuDevicesScannerModuleOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerModuleOutput.swift; sourceTree = ""; }; - 660EB24E2669278E000FD22B /* DfuNoDeviceTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuNoDeviceTableViewCell.swift; sourceTree = ""; }; - 660EB24F2669278E000FD22B /* DfuDeviceTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDeviceTableViewCell.swift; sourceTree = ""; }; - 660EB2502669278E000FD22B /* DfuDevicesScannerViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerViewInput.swift; sourceTree = ""; }; - 660EB2512669278E000FD22B /* DfuDevicesScannerTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerTableViewController.swift; sourceTree = ""; }; - 660EB2522669278E000FD22B /* DfuDevicesScannerViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerViewModel.swift; sourceTree = ""; }; - 660EB2532669278E000FD22B /* DfuDevicesScannerViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerViewOutput.swift; sourceTree = ""; }; - 660EB2542669278E000FD22B /* DfuDevicesScanner.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = DfuDevicesScanner.storyboard; sourceTree = ""; }; - 660EB2562669278E000FD22B /* DfuDevicesScannerRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerRouterInput.swift; sourceTree = ""; }; - 660EB2572669278E000FD22B /* DfuDevicesScannerRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerRouter.swift; sourceTree = ""; }; - 660EB29B266928E6000FD22B /* UIViewController+Alert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Alert.swift"; sourceTree = ""; }; - 663155CD2667F40C005B90A6 /* UpdateFirmwareAppleInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareAppleInitializer.swift; sourceTree = ""; }; - 663155CE2667F40C005B90A6 /* UpdateFirmwareConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareConfigurator.swift; sourceTree = ""; }; - 663155D02667F40C005B90A6 /* UpdateFirmwarePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwarePresenter.swift; sourceTree = ""; }; - 663155D12667F40C005B90A6 /* UpdateFirmwareModuleOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareModuleOutput.swift; sourceTree = ""; }; - 663155D22667F40C005B90A6 /* UpdateFirmwareModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareModuleInput.swift; sourceTree = ""; }; - 663155D52667F40C005B90A6 /* UpdateFirmwareAppleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareAppleViewController.swift; sourceTree = ""; }; - 663155D62667F40C005B90A6 /* UpdateFirmwareViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareViewOutput.swift; sourceTree = ""; }; - 663155D72667F40C005B90A6 /* UpdateFirmwareViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareViewInput.swift; sourceTree = ""; }; - 663155D92667F40C005B90A6 /* UpdateFirmware.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = UpdateFirmware.storyboard; sourceTree = ""; }; - 663155DB2667F40C005B90A6 /* UpdateFirmwareRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareRouter.swift; sourceTree = ""; }; - 663155DC2667F40C005B90A6 /* UpdateFirmwareRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareRouterInput.swift; sourceTree = ""; }; - 66718A28266A685700A380F8 /* DfuFlashAppleInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashAppleInitializer.swift; sourceTree = ""; }; - 66718A29266A685700A380F8 /* DfuFlashConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashConfigurator.swift; sourceTree = ""; }; - 66718A2B266A685700A380F8 /* DfuFlashModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashModuleInput.swift; sourceTree = ""; }; - 66718A2C266A685700A380F8 /* DfuFlashModuleOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashModuleOutput.swift; sourceTree = ""; }; - 66718A2D266A685700A380F8 /* DfuFlashPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashPresenter.swift; sourceTree = ""; }; - 66718A30266A685700A380F8 /* DfuFlashAppleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashAppleViewController.swift; sourceTree = ""; }; - 66718A32266A685700A380F8 /* DfuLogTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuLogTableViewCell.swift; sourceTree = ""; }; - 66718A33266A685700A380F8 /* DfuFlashViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashViewModel.swift; sourceTree = ""; }; - 66718A34266A685700A380F8 /* DfuFlashViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashViewInput.swift; sourceTree = ""; }; - 66718A35266A685700A380F8 /* DfuFlashViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashViewOutput.swift; sourceTree = ""; }; - 66718A36266A685700A380F8 /* DfuFlash.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = DfuFlash.storyboard; sourceTree = ""; }; - 66718A38266A685700A380F8 /* DfuFlashRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashRouter.swift; sourceTree = ""; }; - 66718A39266A685700A380F8 /* DfuFlashRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashRouterInput.swift; sourceTree = ""; }; - 66718A62266A6CA700A380F8 /* DfuFilePickerPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFilePickerPresenter.swift; sourceTree = ""; }; - 66718A64266A6CA700A380F8 /* DfuFilePickerPresenterSheet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFilePickerPresenterSheet.swift; sourceTree = ""; }; - 66718A6B266BD0E800A380F8 /* Color+Ruuvi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Ruuvi.swift"; sourceTree = ""; }; - 66BC44832657AED400A03253 /* OffsetCorrection.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = OffsetCorrection.storyboard; sourceTree = ""; }; - 66BC44862657AED400A03253 /* OffsetCorrectionAppleInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionAppleInitializer.swift; sourceTree = ""; }; - 66BC44872657AED400A03253 /* OffsetCorrectionConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionConfigurator.swift; sourceTree = ""; }; - 66BC44892657AED400A03253 /* OffsetCorrectionModuleOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionModuleOutput.swift; sourceTree = ""; }; - 66BC448A2657AED400A03253 /* OffsetCorrectionPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionPresenter.swift; sourceTree = ""; }; - 66BC448B2657AED400A03253 /* OffsetCorrectionModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionModuleInput.swift; sourceTree = ""; }; - 66BC448E2657AED400A03253 /* OffsetCorrectionAppleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionAppleViewController.swift; sourceTree = ""; }; - 66BC448F2657AED400A03253 /* OffsetCorrectionViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionViewInput.swift; sourceTree = ""; }; - 66BC44902657AED400A03253 /* OffsetCorrectionViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionViewModel.swift; sourceTree = ""; }; - 66BC44912657AED400A03253 /* OffsetCorrectionViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionViewOutput.swift; sourceTree = ""; }; - 66BC44932657AED400A03253 /* OffsetCorrectionRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionRouter.swift; sourceTree = ""; }; - 66BC44942657AED400A03253 /* OffsetCorrectionRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionRouterInput.swift; sourceTree = ""; }; - 6AE2284D927021C0BEA560B0 /* ShareModuleInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareModuleInput.swift; sourceTree = ""; }; - 6F0552F1D17F403B7DE508B5 /* SignInRouter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInRouter.swift; sourceTree = ""; }; - 85B8587156E1062D613B8960 /* SignInInitializer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInInitializer.swift; sourceTree = ""; }; - 87EFB230083D471777FBE5D0 /* SignInModuleInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInModuleInput.swift; sourceTree = ""; }; - 9546F1EFEE8F8CFC22377BB4 /* ShareRouterInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareRouterInput.swift; sourceTree = ""; }; - 9B3006A5FB2173EC6AA2728D /* SignInModuleOutput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInModuleOutput.swift; sourceTree = ""; }; - A907A1D2245F7C6600041F6E /* ProgressBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarView.swift; sourceTree = ""; }; - A907A1D62460376600041F6E /* TagChartViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartViewModel.swift; sourceTree = ""; }; - A907BB1024AE620A009DA3DB /* UIWindow+Orientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindow+Orientation.swift"; sourceTree = ""; }; - A90E168E24604F7400631E6C /* TagChartPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartPresenter.swift; sourceTree = ""; }; - A90E169224604FD100631E6C /* TagChartModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TagChartModuleInput.swift; path = station/Classes/Presentation/Modules/Dashboard/Chart/Presenter/TagChartModuleInput.swift; sourceTree = SOURCE_ROOT; }; - A90E16962460504C00631E6C /* TagChartModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartModuleOutput.swift; sourceTree = ""; }; - A90E169B24606ABF00631E6C /* TagChartsInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsInteractor.swift; sourceTree = ""; }; - A90E169F24606B0500631E6C /* TagChartsInteractorInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsInteractorInput.swift; sourceTree = ""; }; - A90E16A324606B2000631E6C /* TagChartsInteractorOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsInteractorOutput.swift; sourceTree = ""; }; - A90E16A82460975600631E6C /* TagChartAssembler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartAssembler.swift; sourceTree = ""; }; - A9100D82241AD1E4004007FD /* MockAlertPersistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAlertPersistence.swift; sourceTree = ""; }; - A91D02DD2511207200694733 /* SelectionTableConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionTableConfigurator.swift; sourceTree = ""; }; - A91D02DE2511207200694733 /* SelectionTableInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionTableInitializer.swift; sourceTree = ""; }; - A91D02E02511207200694733 /* SelectionPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionPresenter.swift; sourceTree = ""; }; - A91D02E12511207200694733 /* SelectionModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionModuleInput.swift; sourceTree = ""; }; - A91D02E32511207200694733 /* SelectionViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionViewInput.swift; sourceTree = ""; }; - A91D02E52511207200694733 /* SelectionTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionTableViewCell.swift; sourceTree = ""; }; - A91D02E62511207200694733 /* SelectionTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionTableViewController.swift; sourceTree = ""; }; - A91D02E72511207200694733 /* SelectionViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionViewOutput.swift; sourceTree = ""; }; - A91D02E92511207200694733 /* SelectionRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionRouter.swift; sourceTree = ""; }; - A91D02EA2511207200694733 /* SelectionRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionRouterInput.swift; sourceTree = ""; }; - A91D030C251121C800694733 /* Selection.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Selection.storyboard; sourceTree = ""; }; - A91D0310251123B400694733 /* SelectionModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectionModuleOutput.swift; sourceTree = ""; }; - A91D0315251124F900694733 /* SelectionItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectionItem.swift; sourceTree = ""; }; - A91D031925113EAA00694733 /* UnitPressure+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UnitPressure+Extension.swift"; sourceTree = ""; }; - A92A66BC2450C640002918E7 /* UITableViewCell+ReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableViewCell+ReusableView.swift"; sourceTree = ""; }; - A92C75DF24896BA100E332FE /* Appfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = Appfile; sourceTree = ""; }; - A92C75E024896BA100E332FE /* Fastfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = Fastfile; sourceTree = ""; }; - A92C75E124896BA100E332FE /* Gemfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = Gemfile; sourceTree = ""; }; - A92C75E2248982A000E332FE /* Pluginfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = Pluginfile; sourceTree = ""; }; - A92E3C592426415100D981D5 /* TagChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartView.swift; sourceTree = ""; }; - A92E3C62242644B800D981D5 /* TagChartViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartViewInput.swift; sourceTree = ""; }; - A93052B7242BFCC000FB62B1 /* TagChartViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartViewOutput.swift; sourceTree = ""; }; - A935E47525A49E8F009538C4 /* MeasurementsServiceFiSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeasurementsServiceFiSpec.swift; sourceTree = ""; }; - A935E47C25A49E9E009538C4 /* MeasurementsServiceRuSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeasurementsServiceRuSpec.swift; sourceTree = ""; }; - A93CDCAA25657C1D00018C6C /* MenuViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuViewModel.swift; sourceTree = ""; }; - A93CDCCE25659BA600018C6C /* AlertPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertPresenter.swift; sourceTree = ""; }; - A93CDCDD25659BF600018C6C /* AlertPresenterImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertPresenterImpl.swift; sourceTree = ""; }; - A949A83A24707FD0006B7F4F /* LocalizedCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedCache.swift; sourceTree = ""; }; - A94FFD3B241C1D0D00888017 /* AlertServiceSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertServiceSpec.swift; sourceTree = ""; }; - A94FFD49241D45C600888017 /* MockRuuviTag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRuuviTag.swift; sourceTree = ""; }; - A94FFD4B241D512900888017 /* MockLocalNotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockLocalNotificationsManager.swift; sourceTree = ""; }; - A94FFD4D241D57E700888017 /* MockCalibrationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCalibrationService.swift; sourceTree = ""; }; - A94FFD4F241D6BA300888017 /* MockAlertServiceObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAlertServiceObserver.swift; sourceTree = ""; }; - A9646454247BAE6A0001D55D /* AdvancedViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedViewInput.swift; sourceTree = ""; }; - A9646458247BAE6A0001D55D /* AdvancedStepperTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedStepperTableViewCell.swift; sourceTree = ""; }; - A9646459247BAE6A0001D55D /* AdvancedSwitchTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedSwitchTableViewCell.swift; sourceTree = ""; }; - A964645A247BAE6A0001D55D /* AdvancedTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedTableViewController.swift; sourceTree = ""; }; - A964645B247BAE6A0001D55D /* AdvancedViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedViewOutput.swift; sourceTree = ""; }; - A964645C247BAE6A0001D55D /* AdvancedViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedViewModel.swift; sourceTree = ""; }; - A964645E247BAE6A0001D55D /* AdvancedConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedConfigurator.swift; sourceTree = ""; }; - A964645F247BAE6A0001D55D /* AdvancedInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedInitializer.swift; sourceTree = ""; }; - A9646461247BAE6A0001D55D /* AdvancedModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedModuleInput.swift; sourceTree = ""; }; - A9646462247BAE6A0001D55D /* AdvancedPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedPresenter.swift; sourceTree = ""; }; - A9646464247BAE6A0001D55D /* AdvancedRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedRouterInput.swift; sourceTree = ""; }; - A9646465247BAE6A0001D55D /* AdvancedRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedRouter.swift; sourceTree = ""; }; - A964648D247BAEBA0001D55D /* AdvancedSettings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = AdvancedSettings.storyboard; sourceTree = ""; }; - A96B1F2225A7943E00D3ED9C /* station.localization.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; name = station.localization.json; path = station.localization/station.localization.json; sourceTree = SOURCE_ROOT; }; - A971B0DB24215334008EF50D /* XCTest+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCTest+Extension.swift"; sourceTree = ""; }; - A976CA7D24A928C20099BDC1 /* AdvancedDisclosureTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedDisclosureTableViewCell.swift; sourceTree = ""; }; - A980573725807118000D03AB /* AboutViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewModel.swift; sourceTree = ""; }; - A986147A248C49B00030F197 /* Matchfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Matchfile; sourceTree = ""; }; - A98BC874250E4265001CEFDC /* Double+Round.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+Round.swift"; sourceTree = ""; }; - A9A48A5B244CD9E70004FD50 /* UIWindow+Shake.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindow+Shake.swift"; sourceTree = ""; }; - A9A67BF924C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSObjectProtocol+Invalidation.swift"; sourceTree = ""; }; - A9B5742C253B978D00DB7353 /* SignIn.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = SignIn.storyboard; sourceTree = ""; }; - A9BB94CB2540AB610042B190 /* AlertViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertViewModel.swift; sourceTree = ""; }; - A9BD38B924F6108300904BBE /* Humidity+Offset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Humidity+Offset.swift"; sourceTree = ""; }; - A9E5993F25572CF700F9E5CC /* Share.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Share.storyboard; sourceTree = ""; }; - A9E599492557341F00F9E5CC /* ShareDescriptionTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareDescriptionTableViewCell.swift; sourceTree = ""; }; - A9E599572557345200F9E5CC /* ShareEmailInputTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareEmailInputTableViewCell.swift; sourceTree = ""; }; - A9E599602557346600F9E5CC /* ShareSendButtonTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareSendButtonTableViewCell.swift; sourceTree = ""; }; - A9E59969255734A000F9E5CC /* ShareEmailTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareEmailTableViewCell.swift; sourceTree = ""; }; - A9E6770D25A30D0A000B75A3 /* MeasurementsServiceEnSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeasurementsServiceEnSpec.swift; sourceTree = ""; }; - A9E6771925A31556000B75A3 /* MeasurementsServiceSvSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeasurementsServiceSvSpec.swift; sourceTree = ""; }; - A9E6774725A33081000B75A3 /* String+Characters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Characters.swift"; sourceTree = ""; }; - A9F4471524B79959001E63AF /* TagSettingsModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsModuleOutput.swift; sourceTree = ""; }; - AB681E62A66E5924A87859B1 /* ShareConfigurator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareConfigurator.swift; sourceTree = ""; }; - BD7AE39C23B8C52BB202BB5E /* ShareRouter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareRouter.swift; sourceTree = ""; }; - CC1D67615D6DBA9E2FC5B402 /* SharePresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SharePresenter.swift; sourceTree = ""; }; - CE5C4AD5C54EF024669EAF47 /* ShareViewOutput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareViewOutput.swift; sourceTree = ""; }; - E29B5190CB557178D11AB2CE /* SignInPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInPresenter.swift; sourceTree = ""; }; - E6DB40883B83C652584EBB9A /* SignInViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInViewController.swift; sourceTree = ""; }; - FC417B8977A47FFAE71585F0 /* ShareViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; }; - FC59D3B5AD8926DBDD79AA1C /* SignInViewModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInViewModel.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 0E8BD3DC238566AB008B31EF /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 0EEEBDEA26860F6D00589D56 /* RuuviAnalytics in Frameworks */, - 0E11D18A267DFCBE002D0686 /* RuuviServiceOwnership in Frameworks */, - 0E11D17C267DFCB6002D0686 /* RuuviRepositoryCoordinator in Frameworks */, - 0EB8B93026837A4700FE130E /* RuuviCoreDiff in Frameworks */, - 0E11D154267DFC7B002D0686 /* RuuviContext in Frameworks */, - 0E11D1F5267E0040002D0686 /* FirebaseCrashlytics in Frameworks */, - 0E11D152267DFC75002D0686 /* RuuviCloudPure in Frameworks */, - 0E8E3DA626822B130082EC29 /* RuuviCoreLocation in Frameworks */, - 0E11D184267DFCBE002D0686 /* RuuviServiceCloudSync in Frameworks */, - 0E8E3D86268228820082EC29 /* RuuviVirtualPersistence in Frameworks */, - 0E11D17A267DFCB6002D0686 /* RuuviRepository in Frameworks */, - 0E0501312685FDE8007060C4 /* RuuviDaemonRuuviTag in Frameworks */, - 0E11D210267E051D002D0686 /* NordicDFU in Frameworks */, - 0E11D14E267DFC75002D0686 /* RuuviCloud in Frameworks */, - 0E11D13F267DFA13002D0686 /* Localize_Swift in Frameworks */, - 0E8E3D80268228820082EC29 /* RuuviVirtual in Frameworks */, - 0E11D194267DFCCD002D0686 /* RuuviUser in Frameworks */, - 0E8E3D84268228820082EC29 /* RuuviVirtualOWM in Frameworks */, - 0E11D1EA267DFF38002D0686 /* LightRoute in Frameworks */, - 0E00C4FD2685B97E009B3C24 /* RuuviServiceMeasurement in Frameworks */, - 0E11D206267E0346002D0686 /* GestureInstructions in Frameworks */, - 0E11D180267DFCBD002D0686 /* RuuviServiceAlert in Frameworks */, - 0EE36EBB269F05600021B746 /* Charts in Frameworks */, - 0E11D20B267E038C002D0686 /* SwinjectPropertyLoader in Frameworks */, - 0EB8B9182683519900FE130E /* RuuviMigration in Frameworks */, - 0E8E3D8C268228820082EC29 /* RuuviVirtualService in Frameworks */, - 0E11D156267DFC7B002D0686 /* RuuviContextRealm in Frameworks */, - 0E2513562684A113004A522A /* RuuviNotification in Frameworks */, - 0E8E3D8E268228820082EC29 /* RuuviVirtualStorage in Frameworks */, - 0E11D168267DFC9C002D0686 /* RuuviOntologyRealm in Frameworks */, - 0E11D18E267DFCBE002D0686 /* RuuviServiceSensorRecords in Frameworks */, - 0E11D164267DFC95002D0686 /* RuuviLocalUserDefaults in Frameworks */, - 0EB8B91A2683519900FE130E /* RuuviMigrationImpl in Frameworks */, - 0E11D18C267DFCBE002D0686 /* RuuviServiceSensorProperties in Frameworks */, - 0E11D1F3267E0040002D0686 /* FirebaseAnalytics in Frameworks */, - 0E11D21A267E13DB002D0686 /* FirebaseInAppMessaging-Beta in Frameworks */, - 0E05012D2685FDE8007060C4 /* RuuviDaemonBackground in Frameworks */, - 0E11D174267DFCA8002D0686 /* RuuviPoolCoordinator in Frameworks */, - 0E11D15A267DFC80002D0686 /* RuuviCore in Frameworks */, - 0E11D16E267DFCA2002D0686 /* RuuviPersistenceRealm in Frameworks */, - 0E11D150267DFC75002D0686 /* RuuviCloudApi in Frameworks */, - 0E11D170267DFCA2002D0686 /* RuuviPersistenceSQLite in Frameworks */, - 0E2513682684CFF7004A522A /* RuuviNotifierImpl in Frameworks */, - 0E11D158267DFC7B002D0686 /* RuuviContextSQLite in Frameworks */, - 0E11D162267DFC95002D0686 /* RuuviLocal in Frameworks */, - 0E11D178267DFCAE002D0686 /* RuuviReactorImpl in Frameworks */, - 0E8E3D82268228820082EC29 /* RuuviVirtualModel in Frameworks */, - 0E11D1FC267E00AC002D0686 /* Swinject in Frameworks */, - 0E11D21C267E13DB002D0686 /* FirebaseMessaging in Frameworks */, - 0E8E3D88268228820082EC29 /* RuuviVirtualReactor in Frameworks */, - 0E11D186267DFCBE002D0686 /* RuuviServiceFactory in Frameworks */, - 0EB8B93426837A4700FE130E /* RuuviCorePN in Frameworks */, - 0E11D196267DFCCD002D0686 /* RuuviUserCoordinator in Frameworks */, - 0E8E3D8A268228820082EC29 /* RuuviVirtualRepository in Frameworks */, - 0E05012F2685FDE8007060C4 /* RuuviDaemonOperation in Frameworks */, - 0EEEBDEC26860F6D00589D56 /* RuuviAnalyticsImpl in Frameworks */, - 0E92A96F268636A700187E4F /* RuuviServiceGATT in Frameworks */, - 0E11D192267DFCC7002D0686 /* RuuviStorageCoordinator in Frameworks */, - 0E0501332685FDE8007060C4 /* RuuviDaemonVirtualTag in Frameworks */, - 0EB8B93226837A4700FE130E /* RuuviCorePermission in Frameworks */, - 0E11D190267DFCC7002D0686 /* RuuviStorage in Frameworks */, - 0E8E3D9E26822ADD0082EC29 /* RuuviLocationService in Frameworks */, - 0E11D16A267DFC9C002D0686 /* RuuviOntologySQLite in Frameworks */, - 0E00C4FB2685B97D009B3C24 /* RuuviServiceExport in Frameworks */, - 0E11D172267DFCA8002D0686 /* RuuviPool in Frameworks */, - 0E2513582684A113004A522A /* RuuviNotificationLocal in Frameworks */, - 0E11D160267DFC8C002D0686 /* RuuviDaemonCloudSync in Frameworks */, - 0EF4E346268318DE00D83CC7 /* RuuviDFUImpl in Frameworks */, - 0EF4E344268318DE00D83CC7 /* RuuviDFU in Frameworks */, - 0E11D188267DFCBE002D0686 /* RuuviServiceOffsetCalibration in Frameworks */, - 0E11D17E267DFCBD002D0686 /* RuuviService in Frameworks */, - 0E11D1F7267E0040002D0686 /* FirebaseRemoteConfig in Frameworks */, - 0E11D16C267DFCA2002D0686 /* RuuviPersistence in Frameworks */, - 0E11D15E267DFC8C002D0686 /* RuuviDaemon in Frameworks */, - 0E11D201267E02D2002D0686 /* RangeSeekSlider in Frameworks */, - 0E2513662684CFF7004A522A /* RuuviNotifier in Frameworks */, - 0E11D15C267DFC80002D0686 /* RuuviCoreImage in Frameworks */, - 0E11D182267DFCBE002D0686 /* RuuviServiceAppSettings in Frameworks */, - 0E62298026A7FA7C0041DCDD /* RuuviOnboard in Frameworks */, - 0E11D166267DFC9C002D0686 /* RuuviOntology in Frameworks */, - 0E11D176267DFCAE002D0686 /* RuuviReactor in Frameworks */, - 0E8E3D9C26822ADD0082EC29 /* RuuviLocation in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D2220B0C45900CDF4B6 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 0EEEBDE626860F6700589D56 /* RuuviAnalytics in Frameworks */, - 0E11D1D4267DFCDB002D0686 /* RuuviServiceOwnership in Frameworks */, - 0E11D1C6267DFCDB002D0686 /* RuuviRepositoryCoordinator in Frameworks */, - 0EB8B93626837A5100FE130E /* RuuviCoreDiff in Frameworks */, - 0E11D19E267DFCDA002D0686 /* RuuviContext in Frameworks */, - 0E11D1EF267E0010002D0686 /* FirebaseRemoteConfig in Frameworks */, - 0E11D19C267DFCDA002D0686 /* RuuviCloudPure in Frameworks */, - 0E8E3DA426822B0D0082EC29 /* RuuviCoreLocation in Frameworks */, - 0E11D1CE267DFCDB002D0686 /* RuuviServiceCloudSync in Frameworks */, - 0E8E3D76268228760082EC29 /* RuuviVirtualPersistence in Frameworks */, - 0E11D1C4267DFCDB002D0686 /* RuuviRepository in Frameworks */, - 0E0501392685FDF0007060C4 /* RuuviDaemonRuuviTag in Frameworks */, - 0E11D20E267E0510002D0686 /* NordicDFU in Frameworks */, - 0E11D198267DFCDA002D0686 /* RuuviCloud in Frameworks */, - 0E11D13D267DFA09002D0686 /* Localize_Swift in Frameworks */, - 0E8E3D70268228760082EC29 /* RuuviVirtual in Frameworks */, - 0E11D1DE267DFCDB002D0686 /* RuuviUser in Frameworks */, - 0E8E3D74268228760082EC29 /* RuuviVirtualOWM in Frameworks */, - 0E11D1E8267DFF2F002D0686 /* LightRoute in Frameworks */, - 0E00C4F92685B972009B3C24 /* RuuviServiceMeasurement in Frameworks */, - 0E11D204267E0336002D0686 /* GestureInstructions in Frameworks */, - 0E11D1CA267DFCDB002D0686 /* RuuviServiceAlert in Frameworks */, - 0EE36EB9269F054E0021B746 /* Charts in Frameworks */, - 0E11D209267E037A002D0686 /* SwinjectPropertyLoader in Frameworks */, - 0EB8B9142683519200FE130E /* RuuviMigration in Frameworks */, - 0E8E3D7C268228760082EC29 /* RuuviVirtualService in Frameworks */, - 0E11D1A0267DFCDA002D0686 /* RuuviContextRealm in Frameworks */, - 0E2513522684A10A004A522A /* RuuviNotification in Frameworks */, - 0E8E3D7E268228760082EC29 /* RuuviVirtualStorage in Frameworks */, - 0E11D1B2267DFCDA002D0686 /* RuuviOntologyRealm in Frameworks */, - 0E11D1D8267DFCDB002D0686 /* RuuviServiceSensorRecords in Frameworks */, - 0E11D1AE267DFCDA002D0686 /* RuuviLocalUserDefaults in Frameworks */, - 0EB8B9162683519200FE130E /* RuuviMigrationImpl in Frameworks */, - 0E11D1D6267DFCDB002D0686 /* RuuviServiceSensorProperties in Frameworks */, - 0E11D1ED267E0010002D0686 /* FirebaseAnalytics in Frameworks */, - 0E11D216267E13D1002D0686 /* FirebaseInAppMessaging-Beta in Frameworks */, - 0E0501352685FDEF007060C4 /* RuuviDaemonBackground in Frameworks */, - 0E11D1BE267DFCDB002D0686 /* RuuviPoolCoordinator in Frameworks */, - 0E11D1A4267DFCDA002D0686 /* RuuviCore in Frameworks */, - 0E11D1F1267E0010002D0686 /* FirebaseCrashlytics in Frameworks */, - 0E11D1B8267DFCDA002D0686 /* RuuviPersistenceRealm in Frameworks */, - 0E11D19A267DFCDA002D0686 /* RuuviCloudApi in Frameworks */, - 0E25136C2684D001004A522A /* RuuviNotifierImpl in Frameworks */, - 0E11D1BA267DFCDA002D0686 /* RuuviPersistenceSQLite in Frameworks */, - 0E11D1A2267DFCDA002D0686 /* RuuviContextSQLite in Frameworks */, - 0E11D1AC267DFCDA002D0686 /* RuuviLocal in Frameworks */, - 0E8E3D72268228760082EC29 /* RuuviVirtualModel in Frameworks */, - 0E11D1FA267E008D002D0686 /* Swinject in Frameworks */, - 0E11D218267E13D1002D0686 /* FirebaseMessaging in Frameworks */, - 0E8E3D78268228760082EC29 /* RuuviVirtualReactor in Frameworks */, - 0E11D1C2267DFCDB002D0686 /* RuuviReactorImpl in Frameworks */, - 0EB8B93A26837A5100FE130E /* RuuviCorePN in Frameworks */, - 0E11D1D0267DFCDB002D0686 /* RuuviServiceFactory in Frameworks */, - 0E8E3D7A268228760082EC29 /* RuuviVirtualRepository in Frameworks */, - 0E0501372685FDEF007060C4 /* RuuviDaemonOperation in Frameworks */, - 0EEEBDE826860F6700589D56 /* RuuviAnalyticsImpl in Frameworks */, - 0E92A971268636AE00187E4F /* RuuviServiceGATT in Frameworks */, - 0E11D1E0267DFCDB002D0686 /* RuuviUserCoordinator in Frameworks */, - 0E05013B2685FDF0007060C4 /* RuuviDaemonVirtualTag in Frameworks */, - 0EB8B93826837A5100FE130E /* RuuviCorePermission in Frameworks */, - 0E11D1DC267DFCDB002D0686 /* RuuviStorageCoordinator in Frameworks */, - 0E8E3DA226822AE40082EC29 /* RuuviLocationService in Frameworks */, - 0E11D1DA267DFCDB002D0686 /* RuuviStorage in Frameworks */, - 0E00C4F72685B971009B3C24 /* RuuviServiceExport in Frameworks */, - 0E11D1B4267DFCDA002D0686 /* RuuviOntologySQLite in Frameworks */, - 0E2513542684A10A004A522A /* RuuviNotificationLocal in Frameworks */, - 0E11D1BC267DFCDA002D0686 /* RuuviPool in Frameworks */, - 0EF4E34A268318E600D83CC7 /* RuuviDFUImpl in Frameworks */, - 0EF4E348268318E600D83CC7 /* RuuviDFU in Frameworks */, - 0E11D1AA267DFCDA002D0686 /* RuuviDaemonCloudSync in Frameworks */, - 0E11D1D2267DFCDB002D0686 /* RuuviServiceOffsetCalibration in Frameworks */, - 0E11D1C8267DFCDB002D0686 /* RuuviService in Frameworks */, - 0E11D1B6267DFCDA002D0686 /* RuuviPersistence in Frameworks */, - 0E11D1A8267DFCDA002D0686 /* RuuviDaemon in Frameworks */, - 0E11D1FF267E02BC002D0686 /* RangeSeekSlider in Frameworks */, - 0E25136A2684D000004A522A /* RuuviNotifier in Frameworks */, - 0E11D1A6267DFCDA002D0686 /* RuuviCoreImage in Frameworks */, - 0E11D1CC267DFCDB002D0686 /* RuuviServiceAppSettings in Frameworks */, - 0E62298226A7FA8A0041DCDD /* RuuviOnboard in Frameworks */, - 0E11D1B0267DFCDA002D0686 /* RuuviOntology in Frameworks */, - 0E11D1C0267DFCDB002D0686 /* RuuviReactor in Frameworks */, - 0E8E3DA026822AE40082EC29 /* RuuviLocation in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D3620B0C45A00CDF4B6 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D4120B0C45B00CDF4B6 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 0E02ABB8237598B200ED4629 /* RangeSeekSlider */ = { - isa = PBXGroup; - children = ( - 0E02ABB9237598C600ED4629 /* RURangeSeekSlider.swift */, - ); - path = RangeSeekSlider; - sourceTree = ""; - }; - 0E046F2022F049C500BD4E9C /* WebTagSettings */ = { - isa = PBXGroup; - children = ( - 0E046F2622F04A0300BD4E9C /* WebTagSettings.storyboard */, - 0E046F2522F049F000BD4E9C /* Assembly */, - 0E046F2322F049E200BD4E9C /* Presenter */, - 0E046F2222F049DE00BD4E9C /* Router */, - 0E046F2122F049D900BD4E9C /* View */, - ); - path = WebTagSettings; - sourceTree = ""; - }; - 0E046F2122F049D900BD4E9C /* View */ = { - isa = PBXGroup; - children = ( - 0E046F2C22F0563E00BD4E9C /* Table */, - 0E046F3E22F0702D00BD4E9C /* WebTagSettingsViewModel.swift */, - 0E046F2822F0561B00BD4E9C /* WebTagSettingsViewInput.swift */, - 0E046F2A22F0563100BD4E9C /* WebTagSettingsViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E046F2222F049DE00BD4E9C /* Router */ = { - isa = PBXGroup; - children = ( - 0E046F2F22F057CC00BD4E9C /* WebTagSettingsRouterInput.swift */, - 0E046F3122F057DD00BD4E9C /* WebTagSettingsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E046F2322F049E200BD4E9C /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E046F3322F057FC00BD4E9C /* WebTagSettingsModuleInput.swift */, - 0E046F3522F0581E00BD4E9C /* WebTagSettingsPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E046F2522F049F000BD4E9C /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E046F3922F05A9300BD4E9C /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E046F2C22F0563E00BD4E9C /* Table */ = { - isa = PBXGroup; - children = ( - 0E31B04023BBA34C00660412 /* SectionHeader */, - 0EE49B9323B74704003012C2 /* Cells */, - 0E046F2D22F0569000BD4E9C /* WebTagSettingsTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E046F3722F0585E00BD4E9C /* Transitions */ = { - isa = PBXGroup; - children = ( - 0E046F3822F0589000BD4E9C /* SwipeDownToDismiss */, - ); - path = Transitions; - sourceTree = ""; - }; - 0E046F3822F0589000BD4E9C /* SwipeDownToDismiss */ = { - isa = PBXGroup; - children = ( - 0E53DA6622CC964200BC6D64 /* SwipeDownToDismissNavigationController.swift */, - 0E53DA5F22CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift */, - 0E53DA6122CC93EB00BC6D64 /* SwipeDownToDismissTransitionAnimation.swift */, - 0E53DA6322CC943900BC6D64 /* SwipeDownToDismissInteractiveTransition.swift */, - ); - path = SwipeDownToDismiss; - sourceTree = ""; - }; - 0E046F3922F05A9300BD4E9C /* Table */ = { - isa = PBXGroup; - children = ( - 0E046F3A22F05AA800BD4E9C /* WebTagSettingsTableInitializer.swift */, - 0E046F3C22F05B0900BD4E9C /* WebTagSettingsTableConfigurator.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E046F4022F17EC600BD4E9C /* LocationPicker */ = { - isa = PBXGroup; - children = ( - 0E046F4522F17EF400BD4E9C /* LocationPicker.storyboard */, - 0E046F4422F17EE100BD4E9C /* Assembly */, - 0E046F4322F17EDC00BD4E9C /* Presenter */, - 0E046F4222F17ED700BD4E9C /* Router */, - 0E046F4122F17ED300BD4E9C /* View */, - ); - path = LocationPicker; - sourceTree = ""; - }; - 0E046F4122F17ED300BD4E9C /* View */ = { - isa = PBXGroup; - children = ( - 0E046F4B22F1821000BD4E9C /* Apple */, - 0E046F4722F181DA00BD4E9C /* LocationPickerViewInput.swift */, - 0E046F4922F1820400BD4E9C /* LocationPickerViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E046F4222F17ED700BD4E9C /* Router */ = { - isa = PBXGroup; - children = ( - 0E046F4E22F1827800BD4E9C /* LocationPickerRouterInput.swift */, - 0E046F5022F1828900BD4E9C /* LocationPickerRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E046F4322F17EDC00BD4E9C /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E046F5222F182AB00BD4E9C /* LocationPickerModuleInput.swift */, - 0E046F6122F193B300BD4E9C /* LocationPickerModuleOutput.swift */, - 0E046F5422F182BF00BD4E9C /* LocationPickerPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E046F4422F17EE100BD4E9C /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E046F5622F182E600BD4E9C /* Apple */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E046F4B22F1821000BD4E9C /* Apple */ = { - isa = PBXGroup; - children = ( - 0E046F4C22F1823C00BD4E9C /* LocationPickerAppleViewController.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 0E046F5622F182E600BD4E9C /* Apple */ = { - isa = PBXGroup; - children = ( - 0E046F5722F182F500BD4E9C /* LocationPickerAppleInitializer.swift */, - 0E046F5922F1832600BD4E9C /* LocationPickerAppleConfigurator.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 0E05015F268603CE007060C4 /* AppState */ = { - isa = PBXGroup; - children = ( - 0E050160268603CE007060C4 /* Impl */, - 0E050162268603CE007060C4 /* AppStateService.swift */, - ); - path = AppState; - sourceTree = ""; - }; - 0E050160268603CE007060C4 /* Impl */ = { - isa = PBXGroup; - children = ( - 0E050161268603CE007060C4 /* AppStateServiceImpl.swift */, - ); - path = Impl; - sourceTree = ""; - }; - 0E050163268603CE007060C4 /* UniversalLinks */ = { - isa = PBXGroup; - children = ( - 0E050164268603CE007060C4 /* Coordinator */, - 0E050168268603CE007060C4 /* Router */, - ); - path = UniversalLinks; - sourceTree = ""; - }; - 0E050164268603CE007060C4 /* Coordinator */ = { - isa = PBXGroup; - children = ( - 0E050165268603CE007060C4 /* Impl */, - 0E050167268603CE007060C4 /* UniversalLinkCoordinator.swift */, - ); - path = Coordinator; - sourceTree = ""; - }; - 0E050165268603CE007060C4 /* Impl */ = { - isa = PBXGroup; - children = ( - 0E050166268603CE007060C4 /* UniversalLinkCoordinatormpl.swift */, - ); - path = Impl; - sourceTree = ""; - }; - 0E050168268603CE007060C4 /* Router */ = { - isa = PBXGroup; - children = ( - 0E050169268603CE007060C4 /* Impl */, - 0E05016B268603CE007060C4 /* UniversalLinkRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E050169268603CE007060C4 /* Impl */ = { - isa = PBXGroup; - children = ( - 0E05016A268603CE007060C4 /* UniversalLinkRouterImpl.swift */, - ); - path = Impl; - sourceTree = ""; - }; - 0E09671522AE74CB00E85F48 /* Application */ = { - isa = PBXGroup; - children = ( - 0E05015F268603CE007060C4 /* AppState */, - 0EB66B082686053800375BCC /* Features */, - 0EB66B142686053800375BCC /* Info */, - 0E050163268603CE007060C4 /* UniversalLinks */, - 0E1C1DA722B387A00032F6CA /* AppAssembly.swift */, - 64333D2820B0C45900CDF4B6 /* AppDelegate.swift */, - ); - path = Application; - sourceTree = ""; - }; - 0E09671622AE74D600E85F48 /* Classes */ = { - isa = PBXGroup; - children = ( - 0E09671522AE74CB00E85F48 /* Application */, - 0E09671922AE764200E85F48 /* Presentation */, - 0E62297726A7F84F0041DCDD /* Routers */, - ); - path = Classes; - sourceTree = ""; - }; - 0E09671722AE762900E85F48 /* Resources */ = { - isa = PBXGroup; - children = ( - 0EB48DE4261A17F4008E0D2D /* JSONs */, - 0E1C1DC722B396180032F6CA /* Strings */, - 0E09671A22AE769F00E85F48 /* Plists */, - 0E09671822AE763500E85F48 /* Images */, - 6486970E20E042BC00CCD7C1 /* Fonts */, - ); - path = Resources; - sourceTree = ""; - }; - 0E09671822AE763500E85F48 /* Images */ = { - isa = PBXGroup; - children = ( - 64333D2F20B0C45A00CDF4B6 /* Assets.xcassets */, - ); - path = Images; - sourceTree = ""; - }; - 0E09671922AE764200E85F48 /* Presentation */ = { - isa = PBXGroup; - children = ( - 0E1C1DBC22B3920C0032F6CA /* Assembly */, - 0EC50F4E22CCB91000172EEB /* Binding */, - 0EE36E7C269749270021B746 /* Colors */, - 0E70A45E22AF9558006CB87C /* Contract */, - 0EE98A772649386000AAB3ED /* FLEX */, - 0E09671B22AE76B700E85F48 /* Launch */, - 0E70A46122AF958E006CB87C /* Localization */, - 0E09671C22AE76CC00E85F48 /* Modules */, - 0E1C1DAC22B38F220032F6CA /* Presenters */, - 0E046F3722F0585E00BD4E9C /* Transitions */, - ); - path = Presentation; - sourceTree = ""; - }; - 0E09671A22AE769F00E85F48 /* Plists */ = { - isa = PBXGroup; - children = ( - 0EB8B9262683592700FE130E /* Networking.plist */, - 0E197C8023C5CDBE0074015B /* iOSDeviceModelMapping.plist */, - 0ECDF1B42313D65500A09ACA /* GoogleService-Info.plist */, - 64333D3420B0C45A00CDF4B6 /* Info.plist */, - 0EE49BB223B8C40D003012C2 /* DevInfo.plist */, - 0EE49BB123B8C40D003012C2 /* MacInfo.plist */, - ); - path = Plists; - sourceTree = ""; - }; - 0E09671B22AE76B700E85F48 /* Launch */ = { - isa = PBXGroup; - children = ( - 64333D3120B0C45A00CDF4B6 /* LaunchScreen.storyboard */, - ); - path = Launch; - sourceTree = ""; - }; - 0E09671C22AE76CC00E85F48 /* Modules */ = { - isa = PBXGroup; - children = ( - 0EEB20E922B7D1350015F9E0 /* About */, - 0E1C1DCE22B3BDAE0032F6CA /* Dashboard */, - 0E09672622AE8D6A00E85F48 /* Discover */, - 0E046F4022F17EC600BD4E9C /* LocationPicker */, - 0E09671D22AE76D800E85F48 /* Main */, - 0E1C1DEB22B3FDB40032F6CA /* Menu */, - 0EEB20CE22B7C6DA0015F9E0 /* Settings */, - 0EF2862522CBAF280026C7A5 /* TagSettings */, - 0E046F2022F049C500BD4E9C /* WebTagSettings */, - 0E09671E22AE7F2600E85F48 /* Welcome */, - 71A3760FF84549A5FB45C805 /* SignIn */, - DB47D7C8D6149FEA8DD05FDC /* Share */, - ); - path = Modules; - sourceTree = ""; - }; - 0E09671D22AE76D800E85F48 /* Main */ = { - isa = PBXGroup; - children = ( - 64333D2C20B0C45900CDF4B6 /* Main.storyboard */, - 0EEB213D22B8FB6B0015F9E0 /* Transition */, - 0EEB214022B8FB930015F9E0 /* Assembly */, - 0EEB213A22B8FABD0015F9E0 /* Router */, - ); - path = Main; - sourceTree = ""; - }; - 0E09671E22AE7F2600E85F48 /* Welcome */ = { - isa = PBXGroup; - children = ( - 0E09671F22AE7F5C00E85F48 /* Welcome.storyboard */, - 0EEB215422B8FD440015F9E0 /* Assembly */, - 0EEB214F22B8FCF80015F9E0 /* Presenter */, - 0EEB214A22B8FCB50015F9E0 /* Router */, - 0EEB214522B8FC2E0015F9E0 /* View */, - ); - path = Welcome; - sourceTree = ""; - }; - 0E09672322AE895600E85F48 /* Extensions */ = { - isa = PBXGroup; - children = ( - 0E92A94D2686366C00187E4F /* Structs */, - 0EA7966F2664A7B3002BA25D /* Errors */, - 0E92A9522686366C00187E4F /* HumidityUnit+Localization.swift */, - 0E92A9532686366D00187E4F /* Language+Localization.swift */, - 0E92A9512686366C00187E4F /* MeasurementType.swift */, - 0E92A94C2686366C00187E4F /* TemperatureUnit+Localization.swift */, - 0E92A9542686366D00187E4F /* VirtualLocation+Localization.swift */, - 0E290A842660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift */, - 0E09672422AE897000E85F48 /* CALayer+IB.swift */, - 66718A6B266BD0E800A380F8 /* Color+Ruuvi.swift */, - 0EF5B72A22D62CD900D9D14A /* Date+Ruuvi.swift */, - A98BC874250E4265001CEFDC /* Double+Round.swift */, - 0E02ABCA2379483A00ED4629 /* Double+Temperature.swift */, - 0EF4E34E268319A400D83CC7 /* DfuFirmware+Log.swift */, - A9BD38B924F6108300904BBE /* Humidity+Offset.swift */, - A9A67BF924C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift */, - A9E6774725A33081000B75A3 /* String+Characters.swift */, - 0E9E7759238CCE5F006D7013 /* String+Replace.swift */, - 0E1C1DBA22B3919F0032F6CA /* UIApplication+ViewController.swift */, - 0E197C7C23C5CD7C0074015B /* UIDevice+ReadableModel.swift */, - A92A66BC2450C640002918E7 /* UITableViewCell+ReusableView.swift */, - 660EB29B266928E6000FD22B /* UIViewController+Alert.swift */, - A907BB1024AE620A009DA3DB /* UIWindow+Orientation.swift */, - A9A48A5B244CD9E70004FD50 /* UIWindow+Shake.swift */, - A91D031925113EAA00694733 /* UnitPressure+Extension.swift */, - 0E0A381823616AC3003A0364 /* UserDefaults+Optional.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 0E09672622AE8D6A00E85F48 /* Discover */ = { - isa = PBXGroup; - children = ( - 0E09672722AE8D7A00E85F48 /* Discover.storyboard */, - 0E70A47622AF9B69006CB87C /* Assembly */, - 0E70A47122AF993F006CB87C /* Presenter */, - 0E502FBC22B2816400E8A6CC /* Router */, - 0E70A46922AF96B9006CB87C /* View */, - ); - path = Discover; - sourceTree = ""; - }; - 0E197C6423C4A44C0074015B /* MailComposer */ = { - isa = PBXGroup; - children = ( - 0E197C6923C4A4960074015B /* MessageUI */, - 0E197C6523C4A47A0074015B /* MailComposerPresenter.swift */, - ); - path = MailComposer; - sourceTree = ""; - }; - 0E197C6923C4A4960074015B /* MessageUI */ = { - isa = PBXGroup; - children = ( - 0E197C6A23C4A52A0074015B /* MailComposerPresenterMessageUI.swift */, - ); - path = MessageUI; - sourceTree = ""; - }; - 0E1C1DAC22B38F220032F6CA /* Presenters */ = { - isa = PBXGroup; - children = ( - 0E1C1DAD22B38F320032F6CA /* Activity */, - A93CDCCC25659B8600018C6C /* Alert */, - 66718A61266A6CA700A380F8 /* DfuFilePicker */, - 0E1C1DBF22B3954E0032F6CA /* Error */, - 0E197C6423C4A44C0074015B /* MailComposer */, - 0E5C301722CF642F00B52E39 /* Permission */, - 0EC50F5722CF61F700172EEB /* PhotoPicker */, - ); - path = Presenters; - sourceTree = ""; - }; - 0E1C1DAD22B38F320032F6CA /* Activity */ = { - isa = PBXGroup; - children = ( - 0E1C1DB022B38F840032F6CA /* RuuviLogo */, - 0E1C1DAE22B38F780032F6CA /* ActivityPresenter.swift */, - ); - path = Activity; - sourceTree = ""; - }; - 0E1C1DB022B38F840032F6CA /* RuuviLogo */ = { - isa = PBXGroup; - children = ( - 0E1C1DB122B38FFA0032F6CA /* View */, - 0E1C1DB222B390080032F6CA /* ActivityPresenterRuuviLogo.swift */, - ); - path = RuuviLogo; - sourceTree = ""; - }; - 0E1C1DB122B38FFA0032F6CA /* View */ = { - isa = PBXGroup; - children = ( - 0E1C1DB422B3903B0032F6CA /* ActivityRuuviLogo.storyboard */, - 0E1C1DB622B390BC0032F6CA /* ActivityRuuviLogoViewController.swift */, - 0E1C1DB822B390ED0032F6CA /* ActivitySpinnerView.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E1C1DBC22B3920C0032F6CA /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E1C1DBD22B3921E0032F6CA /* PresentationAssembly.swift */, - 0E197C6E23C4A7D00074015B /* Presentation.plist */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E1C1DBF22B3954E0032F6CA /* Error */ = { - isa = PBXGroup; - children = ( - 0E1C1DC222B395B10032F6CA /* Alert */, - 0E1C1DC022B3955E0032F6CA /* ErrorPresenter.swift */, - ); - path = Error; - sourceTree = ""; - }; - 0E1C1DC222B395B10032F6CA /* Alert */ = { - isa = PBXGroup; - children = ( - 0E1C1DC322B395C00032F6CA /* ErrorPresenterAlert.swift */, - ); - path = Alert; - sourceTree = ""; - }; - 0E1C1DC722B396180032F6CA /* Strings */ = { - isa = PBXGroup; - children = ( - A96B1F2225A7943E00D3ED9C /* station.localization.json */, - 0EEB20C922B7A7200015F9E0 /* Localizable.strings */, - 0E53A3F3232DFC6200ACED49 /* InfoPlist.strings */, - ); - path = Strings; - sourceTree = ""; - }; - 0E1C1DCE22B3BDAE0032F6CA /* Dashboard */ = { - isa = PBXGroup; - children = ( - 0E8FD0D823336E8E00FFA577 /* Cards */, - 0E8FD0D923336EB200FFA577 /* Charts */, - A90E168C24604F0E00631E6C /* Chart */, - ); - path = Dashboard; - sourceTree = ""; - }; - 0E1C1DCF22B3BDBB0032F6CA /* View */ = { - isa = PBXGroup; - children = ( - 0E1C1DD622B3BF760032F6CA /* Scroll */, - 0E1C1DD222B3BF180032F6CA /* CardsViewInput.swift */, - 0E1C1DD422B3BF3A0032F6CA /* CardsViewOutput.swift */, - 0EEB20C522B7915C0015F9E0 /* CardsViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E1C1DD622B3BF760032F6CA /* Scroll */ = { - isa = PBXGroup; - children = ( - 0ECB5A8F2381809900E78757 /* View */, - 0ECB5A8D2381807500E78757 /* CardsScrollViewController.swift */, - ); - path = Scroll; - sourceTree = ""; - }; - 0E1C1DDB22B3C1F30032F6CA /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E1C1DDC22B3C2160032F6CA /* CardsModuleInput.swift */, - 0E1C1DDE22B3C2330032F6CA /* CardsPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E1C1DE022B3C24F0032F6CA /* Router */ = { - isa = PBXGroup; - children = ( - 0E1C1DE122B3C25F0032F6CA /* CardsRouterInput.swift */, - 0E211C29234C5FE900FC37B0 /* CardsRouterDelegate.swift */, - 0E1C1DE322B3C2710032F6CA /* CardsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E1C1DE522B3C2900032F6CA /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E1C1DE622B3C2A80032F6CA /* Scroll */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E1C1DE622B3C2A80032F6CA /* Scroll */ = { - isa = PBXGroup; - children = ( - 0E1C1DE722B3C2B60032F6CA /* CardsScrollInitializer.swift */, - 0E1C1DE922B3C2E60032F6CA /* CardsScrollConfigurator.swift */, - ); - path = Scroll; - sourceTree = ""; - }; - 0E1C1DEB22B3FDB40032F6CA /* Menu */ = { - isa = PBXGroup; - children = ( - 0E1C1DF022B3FDE30032F6CA /* Menu.storyboard */, - 0E1C1DEF22B3FDD60032F6CA /* Assembly */, - 0E1C1E0622B401A80032F6CA /* Transition */, - 0E1C1DEE22B3FDCC0032F6CA /* Presenter */, - 0E1C1DED22B3FDC70032F6CA /* Router */, - 0E1C1DEC22B3FDBB0032F6CA /* View */, - ); - path = Menu; - sourceTree = ""; - }; - 0E1C1DEC22B3FDBB0032F6CA /* View */ = { - isa = PBXGroup; - children = ( - 0E1C1DF622B3FF2F0032F6CA /* Table */, - 0E1C1DF222B3FEFF0032F6CA /* MenuViewInput.swift */, - 0E1C1DF422B3FF1D0032F6CA /* MenuViewOutput.swift */, - A93CDCAA25657C1D00018C6C /* MenuViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E1C1DED22B3FDC70032F6CA /* Router */ = { - isa = PBXGroup; - children = ( - 0E1C1DF922B3FFBF0032F6CA /* MenuRouterInput.swift */, - 0E1C1DFB22B3FFD90032F6CA /* MenuRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E1C1DEE22B3FDCC0032F6CA /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E1C1DFD22B3FFFC0032F6CA /* MenuModuleInput.swift */, - 0EEB20CC22B7BD6C0015F9E0 /* MenuModuleOutput.swift */, - 0E1C1DFF22B400130032F6CA /* MenuPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E1C1DEF22B3FDD60032F6CA /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E1C1E0122B400470032F6CA /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E1C1DF622B3FF2F0032F6CA /* Table */ = { - isa = PBXGroup; - children = ( - 0EEB20CA22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift */, - 0E1C1DF722B3FF480032F6CA /* MenuTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E1C1E0122B400470032F6CA /* Table */ = { - isa = PBXGroup; - children = ( - 0E1C1E0222B400590032F6CA /* MenuTableInitializer.swift */, - 0E1C1E0422B400890032F6CA /* MenuTableConfigurator.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E1C1E0622B401A80032F6CA /* Transition */ = { - isa = PBXGroup; - children = ( - 0E1C1E0722B4022F0032F6CA /* Table */, - ); - path = Transition; - sourceTree = ""; - }; - 0E1C1E0722B4022F0032F6CA /* Table */ = { - isa = PBXGroup; - children = ( - 0EEB215922BA28860015F9E0 /* MenuTableTransitionManager.swift */, - 0E1C1E0822B4024E0032F6CA /* MenuTableTransitioningDelegate.swift */, - 0E1C1E0A22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift */, - 0E1C1E0C22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift */, - 0E1C1E0E22B4049E0032F6CA /* MenuTablePresentationController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E31B04023BBA34C00660412 /* SectionHeader */ = { - isa = PBXGroup; - children = ( - 0E31B04123BBA37C00660412 /* WebTagSettingsAlertsHeaderFooterView.swift */, - 0E31B04523BBA3F900660412 /* WebTagSettingsAlertsHeaderFooterView.xib */, - ); - path = SectionHeader; - sourceTree = ""; - }; - 0E3FF731238156AF00EB98F9 /* SectionHeader */ = { - isa = PBXGroup; - children = ( - 0E3FF7362381591800EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.swift */, - 0E3FF734238157B700EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.xib */, - ); - path = SectionHeader; - sourceTree = ""; - }; - 0E502FBC22B2816400E8A6CC /* Router */ = { - isa = PBXGroup; - children = ( - 0E502FBD22B2817900E8A6CC /* DiscoverRouterInput.swift */, - 0E502FBF22B2819B00E8A6CC /* DiscoverRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E5C301722CF642F00B52E39 /* Permission */ = { - isa = PBXGroup; - children = ( - 0E5C301822CF643C00B52E39 /* Alert */, - 0E5C301922CF644900B52E39 /* PermissionPresenter.swift */, - ); - path = Permission; - sourceTree = ""; - }; - 0E5C301822CF643C00B52E39 /* Alert */ = { - isa = PBXGroup; - children = ( - 0E5C301B22CF646A00B52E39 /* PermissionPresenterAlert.swift */, - ); - path = Alert; - sourceTree = ""; - }; - 0E62297726A7F84F0041DCDD /* Routers */ = { - isa = PBXGroup; - children = ( - 0E62297826A7F84F0041DCDD /* OnboardRouter.swift */, - 0E62297926A7F84F0041DCDD /* AppRouter.swift */, - ); - path = Routers; - sourceTree = ""; - }; - 0E70A45E22AF9558006CB87C /* Contract */ = { - isa = PBXGroup; - children = ( - 0E70A45F22AF9567006CB87C /* ViewInput.swift */, - ); - path = Contract; - sourceTree = ""; - }; - 0E70A46122AF958E006CB87C /* Localization */ = { - isa = PBXGroup; - children = ( - 0E70A46222AF959E006CB87C /* Localizable.swift */, - A949A83A24707FD0006B7F4F /* LocalizedCache.swift */, - 0E9D0AB0231EBEFD00C6BDA7 /* LocalizationService.swift */, - ); - path = Localization; - sourceTree = ""; - }; - 0E70A46922AF96B9006CB87C /* View */ = { - isa = PBXGroup; - children = ( - 0E8E3D67268228130082EC29 /* Model */, - 0E70A46A22AF96C5006CB87C /* Table */, - 0E70A46D22AF9763006CB87C /* DiscoverViewInput.swift */, - 0E70A46F22AF9790006CB87C /* DiscoverViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E70A46A22AF96C5006CB87C /* Table */ = { - isa = PBXGroup; - children = ( - 0EF26D172381A12F005BD84E /* Cell */, - 0E3FF731238156AF00EB98F9 /* SectionHeader */, - 0E70A46B22AF9705006CB87C /* DiscoverTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E70A47122AF993F006CB87C /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E70A47222AF9953006CB87C /* DiscoverModuleInput.swift */, - 0E84BF4C239795AF00A37E1A /* DiscoverModuleOutput.swift */, - 0E70A47422AF9978006CB87C /* DiscoverPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E70A47622AF9B69006CB87C /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E70A47922AF9BC6006CB87C /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E70A47922AF9BC6006CB87C /* Table */ = { - isa = PBXGroup; - children = ( - 0E70A47A22AF9BE2006CB87C /* DiscoverTableInitializer.swift */, - 0E70A47C22AF9BFE006CB87C /* DiscoverTableConfigurator.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E84BF4F2397F24D00A37E1A /* Heartbeat */ = { - isa = PBXGroup; - children = ( - 0E84BF542397F29800A37E1A /* Heartbeat.storyboard */, - 0E84BF532397F28800A37E1A /* Assembly */, - 0E84BF522397F28200A37E1A /* Presenter */, - 0E84BF512397F27E00A37E1A /* Router */, - 0E84BF502397F27900A37E1A /* View */, - ); - path = Heartbeat; - sourceTree = ""; - }; - 0E84BF502397F27900A37E1A /* View */ = { - isa = PBXGroup; - children = ( - 0E84BF5C2397F3E600A37E1A /* SwiftUI */, - 0E84BF5D2397F3F000A37E1A /* Table */, - 0E84BF562397F33E00A37E1A /* HeartbeatViewInput.swift */, - 0E84BF582397F3C600A37E1A /* HeartbeatViewModel.swift */, - 0E84BF5A2397F3DF00A37E1A /* HeartbeatViewOutput.swift */, - 0E84BF5E2397F6BE00A37E1A /* HeartbeatViewController.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E84BF512397F27E00A37E1A /* Router */ = { - isa = PBXGroup; - children = ( - 0E84BF66239801AF00A37E1A /* HeartbeatRouterInput.swift */, - 0E84BF68239801C100A37E1A /* HeartbeatRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E84BF522397F28200A37E1A /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E84BF6A239802A400A37E1A /* HeartbeatModuleInput.swift */, - 0E84BF6C239802CA00A37E1A /* HeartbeatPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E84BF532397F28800A37E1A /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E84BF6E2398031B00A37E1A /* HeartbeatInitializer.swift */, - 0E84BF702398035C00A37E1A /* HeartbeatConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E84BF5C2397F3E600A37E1A /* SwiftUI */ = { - isa = PBXGroup; - children = ( - 0E84BF622397F76A00A37E1A /* HeartbeatList.swift */, - 0E84BF602397F73100A37E1A /* HeartbeatEnvironmentObject.swift */, - ); - path = SwiftUI; - sourceTree = ""; - }; - 0E84BF5D2397F3F000A37E1A /* Table */ = { - isa = PBXGroup; - children = ( - 0E84BF642397F9DC00A37E1A /* HeartbeatTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E8A100023845E1200A9CBA6 /* Defaults */ = { - isa = PBXGroup; - children = ( - 0E8A100123845E5100A9CBA6 /* Defaults.storyboard */, - 0E8A100623845E9400A9CBA6 /* Assembly */, - 0E8A100523845E8A00A9CBA6 /* Presenter */, - 0E8A100423845E8200A9CBA6 /* Router */, - 0E8A100323845E7D00A9CBA6 /* View */, - ); - path = Defaults; - sourceTree = ""; - }; - 0E8A100323845E7D00A9CBA6 /* View */ = { - isa = PBXGroup; - children = ( - 0E8A100723845F1B00A9CBA6 /* SwiftUI */, - 0E8A100823845F2300A9CBA6 /* Table */, - 0E8A100923845F3900A9CBA6 /* DefaultsViewController.swift */, - 0E8A100B23845F7100A9CBA6 /* DefaultsViewInput.swift */, - 0E8A100D23845F8C00A9CBA6 /* DefaultsViewOutput.swift */, - 0E8A100F23845FAE00A9CBA6 /* DefaultsViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E8A100423845E8200A9CBA6 /* Router */ = { - isa = PBXGroup; - children = ( - 0E8A10152384612300A9CBA6 /* DefaultsRouterInput.swift */, - 0E8A10132384610400A9CBA6 /* DefaultsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E8A100523845E8A00A9CBA6 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E8A10172384613E00A9CBA6 /* DefaultsModuleInput.swift */, - 0E8A10192384615400A9CBA6 /* DefaultsPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E8A100623845E9400A9CBA6 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E8A101B2384618700A9CBA6 /* DefaultsInitializer.swift */, - 0E8A101D238461D400A9CBA6 /* DefaultsConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E8A100723845F1B00A9CBA6 /* SwiftUI */ = { - isa = PBXGroup; - children = ( - 0E8A10212384637F00A9CBA6 /* DefaultsList.swift */, - 0E8A101F2384633200A9CBA6 /* DefaultsEnvironmentObject.swift */, - ); - path = SwiftUI; - sourceTree = ""; - }; - 0E8A100823845F2300A9CBA6 /* Table */ = { - isa = PBXGroup; - children = ( - 0E8A102323846CCE00A9CBA6 /* Cells */, - 0E8A10112384605A00A9CBA6 /* DefaultsTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E8A102323846CCE00A9CBA6 /* Cells */ = { - isa = PBXGroup; - children = ( - 0E8A102423846CEB00A9CBA6 /* DefaultsSwitchTableViewCell.swift */, - 0E8BD2AA23851CF2008B31EF /* DefaultsStepperTableViewCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - 0E8E3D67268228130082EC29 /* Model */ = { - isa = PBXGroup; - children = ( - 0E8E3D68268228130082EC29 /* DiscoverRuuviTagViewModel.swift */, - 0E8E3D69268228130082EC29 /* DiscoverVirtualTagViewModel.swift */, - ); - path = Model; - sourceTree = ""; - }; - 0E8FD0B923335D4300FFA577 /* View */ = { - isa = PBXGroup; - children = ( - 0E8FD0DA23336FCA00FFA577 /* Scroll */, - 0E8FD0C223335DA700FFA577 /* TagChartsViewInput.swift */, - 0E8FD0C423335DBF00FFA577 /* TagChartsViewOutput.swift */, - 0E8FD0DC2333714C00FFA577 /* TagChartsViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E8FD0BA23335D4700FFA577 /* Router */ = { - isa = PBXGroup; - children = ( - 0E8FD0C6233366DC00FFA577 /* TagChartsRouterInput.swift */, - 0E8FD0C8233366F000FFA577 /* TagChartsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E8FD0BB23335D4C00FFA577 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E8FD0CA2333671100FFA577 /* TagChartsModuleInput.swift */, - 0E8FD0E22333893600FFA577 /* TagChartsModuleOutput.swift */, - 0E8FD0CC2333672F00FFA577 /* TagChartsPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E8FD0BC23335D5200FFA577 /* Transition */ = { - isa = PBXGroup; - children = ( - 0E8FD0D223336B4200FFA577 /* TagChartsTransitioningDelegate.swift */, - 0E341BBC2372E75C0085BB54 /* TagChartsTransitionManager.swift */, - 0E8FD0D423336BA300FFA577 /* TagChartsPresentTransitionAnimation.swift */, - 0E8FD0D623336C6E00FFA577 /* TagChartsDismissTransitionAnimation.swift */, - ); - path = Transition; - sourceTree = ""; - }; - 0E8FD0BD23335D5800FFA577 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E8FD0DB2333704400FFA577 /* Scroll */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E8FD0D823336E8E00FFA577 /* Cards */ = { - isa = PBXGroup; - children = ( - 0E1C1DD022B3BDFC0032F6CA /* Cards.storyboard */, - 0E1C1DE522B3C2900032F6CA /* Assembly */, - 0E1C1DDB22B3C1F30032F6CA /* Presenter */, - 0E1C1DE022B3C24F0032F6CA /* Router */, - 0E1C1DCF22B3BDBB0032F6CA /* View */, - ); - path = Cards; - sourceTree = ""; - }; - 0E8FD0D923336EB200FFA577 /* Charts */ = { - isa = PBXGroup; - children = ( - 0E8FD0BE23335D6900FFA577 /* TagCharts.storyboard */, - 0E8FD0BD23335D5800FFA577 /* Assembly */, - 0E8FD0BC23335D5200FFA577 /* Transition */, - 0E8FD0BB23335D4C00FFA577 /* Presenter */, - A90E169A24606A3900631E6C /* Interactor */, - 0E8FD0BA23335D4700FFA577 /* Router */, - 0E8FD0B923335D4300FFA577 /* View */, - ); - path = Charts; - sourceTree = ""; - }; - 0E8FD0DA23336FCA00FFA577 /* Scroll */ = { - isa = PBXGroup; - children = ( - 0E8FD0C023335D8400FFA577 /* TagChartsScrollViewController.swift */, - ); - path = Scroll; - sourceTree = ""; - }; - 0E8FD0DB2333704400FFA577 /* Scroll */ = { - isa = PBXGroup; - children = ( - 0E8FD0CE2333676C00FFA577 /* TagChartsScrollInitializer.swift */, - 0E8FD0D02333679800FFA577 /* TagChartsScrollConfigurator.swift */, - ); - path = Scroll; - sourceTree = ""; - }; - 0E92A94D2686366C00187E4F /* Structs */ = { - isa = PBXGroup; - children = ( - 0E92A94E2686366C00187E4F /* ExportHeadersProvider.swift */, - 0E92A94F2686366C00187E4F /* HeartbeatDaemonTitles.swift */, - 0E92A9502686366C00187E4F /* RuuviNotifierTitlesImpl.swift */, - ); - path = Structs; - sourceTree = ""; - }; - 0E9D5F1E2351BCBA0076FFD8 /* Cells */ = { - isa = PBXGroup; - children = ( - 0EF6F5BF235E01CD0052BA25 /* ForegroundStepperTableViewCell.swift */, - 0E9D5F1F2351BE3C0076FFD8 /* ForegroundSwitchTableViewCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - 0EA7966F2664A7B3002BA25D /* Errors */ = { - isa = PBXGroup; - children = ( - 0E92A9652686367F00187E4F /* RUError.swift */, - 0E0501262685FDD3007060C4 /* RuuviDaemonError+LocalizedError.swift */, - 0E0501272685FDD3007060C4 /* RuuviDFUError+LocalizedError.swift */, - 0E8E3D5E268227530082EC29 /* RuuviCoreError+LocalizedError.swift */, - 0E8E3D5F268227530082EC29 /* RuuviVirtualError+LocalizedError.swift */, - 0EA796702664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift */, - 0EA796742664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift */, - 0EA796782664B37F002BA25D /* RuuviLocalError+LocalizedError.swift */, - 0EA7967C2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift */, - 0EA796802664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift */, - 0EA796842664B84D002BA25D /* RuuviReactorError+LocalizedError.swift */, - 0EA796882664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift */, - 0EA7968C2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift */, - 0E2AFF9F266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift */, - ); - path = Errors; - sourceTree = ""; - }; - 0EAD33F3239A571B00EC5BAA /* Cells */ = { - isa = PBXGroup; - children = ( - 0E1B2F31239DEF120060C469 /* TagSettingsAlertHeaderCell.swift */, - 0E1B2F35239DF0120060C469 /* TagSettingsAlertControlsCell.swift */, - 0E197C6023C352380074015B /* TagSettingsAlertDescriptionCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - 0EB48DE4261A17F4008E0D2D /* JSONs */ = { - isa = PBXGroup; - children = ( - 0EB48DE5261A1816008E0D2D /* FeatureToggles.json */, - ); - path = JSONs; - sourceTree = ""; - }; - 0EB66B082686053800375BCC /* Features */ = { - isa = PBXGroup; - children = ( - 0EB66B092686053800375BCC /* Providers */, - 0EB66B0E2686053800375BCC /* RemoteConfig */, - 0EB66B122686053800375BCC /* FeatureToggleService.swift */, - 0EB66B132686053800375BCC /* FeatureToggle.swift */, - ); - path = Features; - sourceTree = ""; - }; - 0EB66B092686053800375BCC /* Providers */ = { - isa = PBXGroup; - children = ( - 0EB66B0A2686053800375BCC /* FeatureToggleProvider.swift */, - 0EB66B0B2686053800375BCC /* FallbackFeatureToggleProvider.swift */, - 0EB66B0C2686053800375BCC /* FirebaseFeatureToggleProvider.swift */, - 0EB66B0D2686053800375BCC /* LocalFeatureToggleProvider.swift */, - ); - path = Providers; - sourceTree = ""; - }; - 0EB66B0E2686053800375BCC /* RemoteConfig */ = { - isa = PBXGroup; - children = ( - 0EB66B0F2686053800375BCC /* Firebase */, - 0EB66B112686053800375BCC /* RemoteConfigService.swift */, - ); - path = RemoteConfig; - sourceTree = ""; - }; - 0EB66B0F2686053800375BCC /* Firebase */ = { - isa = PBXGroup; - children = ( - 0EB66B102686053800375BCC /* FirebaseRemoteConfigService.swift */, - ); - path = Firebase; - sourceTree = ""; - }; - 0EB66B142686053800375BCC /* Info */ = { - isa = PBXGroup; - children = ( - 0EB66B152686053800375BCC /* Impl */, - 0EB66B172686053800375BCC /* InfoProvider.swift */, - ); - path = Info; - sourceTree = ""; - }; - 0EB66B152686053800375BCC /* Impl */ = { - isa = PBXGroup; - children = ( - 0EB66B162686053800375BCC /* InfoProviderImpl.swift */, - ); - path = Impl; - sourceTree = ""; - }; - 0EBAF062232000F50025A191 /* Module */ = { - isa = PBXGroup; - children = ( - 0EEB20D022B7C6F30015F9E0 /* Settings.storyboard */, - 0EEB20DB22B7C83E0015F9E0 /* Assembly */, - 0EEB20DA22B7C8380015F9E0 /* Presenter */, - 0EEB20D922B7C8330015F9E0 /* Router */, - 0EEB20CF22B7C6E40015F9E0 /* View */, - ); - path = Module; - sourceTree = ""; - }; - 0EBAF063232001080025A191 /* Submodules */ = { - isa = PBXGroup; - children = ( - A9828E54247BAC0700E7E9D4 /* Advanced */, - 0E8A100023845E1200A9CBA6 /* Defaults */, - 0ECFF34F235056770061D11B /* Foreground */, - 0E84BF4F2397F24D00A37E1A /* Heartbeat */, - 0EBAF066232005600025A191 /* Language */, - A91D02D92511207200694733 /* Selection */, - ); - path = Submodules; - sourceTree = ""; - }; - 0EBAF066232005600025A191 /* Language */ = { - isa = PBXGroup; - children = ( - 0EBAF06B232006E00025A191 /* Language.storyboard */, - 0EBAF06A232005740025A191 /* Assembly */, - 0EBAF0692320056F0025A191 /* Presenter */, - 0EBAF0682320056B0025A191 /* Router */, - 0EBAF067232005670025A191 /* View */, - ); - path = Language; - sourceTree = ""; - }; - 0EBAF067232005670025A191 /* View */ = { - isa = PBXGroup; - children = ( - 0EBAF073232007940025A191 /* Table */, - 0EBAF06D232007510025A191 /* LanguageViewInput.swift */, - 0EBAF06F232007740025A191 /* LanguageViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 0EBAF0682320056B0025A191 /* Router */ = { - isa = PBXGroup; - children = ( - 0EBAF074232007CC0025A191 /* LanguageRouterInput.swift */, - 0EBAF076232007D80025A191 /* LanguageRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0EBAF0692320056F0025A191 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0EBAF078232008140025A191 /* LanguageModuleInput.swift */, - 0EBAF07A232008420025A191 /* LanguagePresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0EBAF06A232005740025A191 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0EBAF07C2320085F0025A191 /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - 0EBAF073232007940025A191 /* Table */ = { - isa = PBXGroup; - children = ( - 0EBAF08123200B1B0025A191 /* LanguageTableViewCell.swift */, - 0EBAF071232007910025A191 /* LanguageTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0EBAF07C2320085F0025A191 /* Table */ = { - isa = PBXGroup; - children = ( - 0EBAF07D2320086A0025A191 /* LanguageTableInitializer.swift */, - 0EBAF07F2320089A0025A191 /* LanguageTableConfigurator.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0EC50F4E22CCB91000172EEB /* Binding */ = { - isa = PBXGroup; - children = ( - 0EC50F4F22CCB92000172EEB /* Observable.swift */, - 0EC50F5522CCE46D00172EEB /* Optional.swift */, - 0EC50F5322CCBBE800172EEB /* NSObject+Observable.swift */, - ); - path = Binding; - sourceTree = ""; - }; - 0EC50F5722CF61F700172EEB /* PhotoPicker */ = { - isa = PBXGroup; - children = ( - 0EC50F5A22CF624200172EEB /* Sheet */, - 0EC50F5822CF621000172EEB /* PhotoPickerPresenter.swift */, - ); - path = PhotoPicker; - sourceTree = ""; - }; - 0EC50F5A22CF624200172EEB /* Sheet */ = { - isa = PBXGroup; - children = ( - 0E5C300A22CF629100B52E39 /* PhotoPickerPresenterSheet.swift */, - ); - path = Sheet; - sourceTree = ""; - }; - 0ECB5A8F2381809900E78757 /* View */ = { - isa = PBXGroup; - children = ( - 0E1C1E1222B756D30032F6CA /* CardView.xib */, - 0E1C1E1022B756B40032F6CA /* CardView.swift */, - ); - path = View; - sourceTree = ""; - }; - 0ECFF34F235056770061D11B /* Foreground */ = { - isa = PBXGroup; - children = ( - 0ECFF35623505F8D0061D11B /* Foreground.storyboard */, - 0ECFF353235056920061D11B /* Assembly */, - 0ECFF3522350568C0061D11B /* Presenter */, - 0ECFF351235056870061D11B /* Router */, - 0ECFF3502350567E0061D11B /* View */, - ); - path = Foreground; - sourceTree = ""; - }; - 0ECFF3502350567E0061D11B /* View */ = { - isa = PBXGroup; - children = ( - 0ECFF35C23506B8A0061D11B /* SwiftUI */, - 0EE5B4802351AB3C00D5ED32 /* Table */, - 0ECFF35F23506BD60061D11B /* ForegroundViewInput.swift */, - 0ECFF35D23506BC40061D11B /* ForegroundViewOutput.swift */, - 0ECFF358235060EF0061D11B /* ForegroundViewController.swift */, - 0ECFF36F23507CE80061D11B /* ForegroundViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - 0ECFF351235056870061D11B /* Router */ = { - isa = PBXGroup; - children = ( - 0ECFF36723507A1A0061D11B /* ForegroundRouterInput.swift */, - 0EF6F5BD235E01170052BA25 /* ForegroundRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0ECFF3522350568C0061D11B /* Presenter */ = { - isa = PBXGroup; - children = ( - 0ECFF35A2350618E0061D11B /* ForegroundModuleInput.swift */, - 0ECFF365235079F50061D11B /* ForegroundPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0ECFF353235056920061D11B /* Assembly */ = { - isa = PBXGroup; - children = ( - 0ECFF36B23507BC00061D11B /* ForegroundInitializer.swift */, - 0ECFF36D23507BF00061D11B /* ForegroundConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 0ECFF35C23506B8A0061D11B /* SwiftUI */ = { - isa = PBXGroup; - children = ( - 0ECFF354235056DC0061D11B /* ForegroundList.swift */, - 0ECFF36123506C050061D11B /* ForegroundRow.swift */, - 0EE5B47C23508F6D00D5ED32 /* ForegroundEnvironmentObject.swift */, - ); - path = SwiftUI; - sourceTree = ""; - }; - 0EE36E44269748A70021B746 /* DFU */ = { - isa = PBXGroup; - children = ( - 0EE36E45269748A70021B746 /* FirmwareRepository */, - 0EE36E47269748A70021B746 /* Presenter */, - 0EE36E4A269748A70021B746 /* Extensions */, - 0EE36E4E269748A70021B746 /* Common */, - 0EE36E53269748A70021B746 /* View */, - 0EE36E57269748A70021B746 /* Interactor */, - 0EE36E5B269748A70021B746 /* DFUModuleFactory.swift */, - ); - path = DFU; - sourceTree = ""; - }; - 0EE36E45269748A70021B746 /* FirmwareRepository */ = { - isa = PBXGroup; - children = ( - 0EE36E46269748A70021B746 /* FirmwareRepository.swift */, - ); - path = FirmwareRepository; - sourceTree = ""; - }; - 0EE36E47269748A70021B746 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0EE36E48269748A70021B746 /* DFUModuleInput.swift */, - 0EE36E49269748A70021B746 /* DFUPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0EE36E4A269748A70021B746 /* Extensions */ = { - isa = PBXGroup; - children = ( - 0EE36E4B269748A70021B746 /* Publishers+System.swift */, - 0EE36E4C269748A70021B746 /* URLSession+downloadTaskPublisher.swift */, - 0EE36E4D269748A70021B746 /* View+Any.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 0EE36E4E269748A70021B746 /* Common */ = { - isa = PBXGroup; - children = ( - 0EE36E4F269748A70021B746 /* Spinner.swift */, - 0EE36E50269748A70021B746 /* LargeButtonStyle.swift */, - 0EE36E51269748A70021B746 /* ProgressBar.swift */, - 0EE36E52269748A70021B746 /* Feedback.swift */, - ); - path = Common; - sourceTree = ""; - }; - 0EE36E53269748A70021B746 /* View */ = { - isa = PBXGroup; - children = ( - 0EE36E54269748A70021B746 /* DFUViewModel.swift */, - 0EE36E55269748A70021B746 /* SwiftUI */, - ); - path = View; - sourceTree = ""; - }; - 0EE36E55269748A70021B746 /* SwiftUI */ = { - isa = PBXGroup; - children = ( - 0EE36E56269748A70021B746 /* DFUUIView.swift */, - ); - path = SwiftUI; - sourceTree = ""; - }; - 0EE36E57269748A70021B746 /* Interactor */ = { - isa = PBXGroup; - children = ( - 0EE36E58269748A70021B746 /* DFUInteractorInput.swift */, - 0EE36E59269748A70021B746 /* DFUInteractor.swift */, - 0EE36E5A269748A70021B746 /* LatestRelease.swift */, - ); - path = Interactor; - sourceTree = ""; - }; - 0EE36E7C269749270021B746 /* Colors */ = { - isa = PBXGroup; - children = ( - 0EE36E7D269749270021B746 /* RuuviColor.swift */, - ); - path = Colors; - sourceTree = ""; - }; - 0EE49B9323B74704003012C2 /* Cells */ = { - isa = PBXGroup; - children = ( - 0EE49B9423B74775003012C2 /* WebTagSettingsAlertHeaderCell.swift */, - 0EE49B9823B877CF003012C2 /* WebTagSettingsAlertControlsCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - 0EE5B4802351AB3C00D5ED32 /* Table */ = { - isa = PBXGroup; - children = ( - 0E9D5F1E2351BCBA0076FFD8 /* Cells */, - 0EF6F5C1235E02000052BA25 /* ForegroundTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0EE98A772649386000AAB3ED /* FLEX */ = { - isa = PBXGroup; - children = ( - 0EE98A7826493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift */, - ); - path = FLEX; - sourceTree = ""; - }; - 0EEB20CE22B7C6DA0015F9E0 /* Settings */ = { - isa = PBXGroup; - children = ( - 0EBAF062232000F50025A191 /* Module */, - 0EBAF063232001080025A191 /* Submodules */, - ); - path = Settings; - sourceTree = ""; - }; - 0EEB20CF22B7C6E40015F9E0 /* View */ = { - isa = PBXGroup; - children = ( - 0EEB20D422B7C7BE0015F9E0 /* Table */, - 0EEB20D522B7C7E70015F9E0 /* SettingsViewInput.swift */, - 0EEB20D722B7C8060015F9E0 /* SettingsViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 0EEB20D422B7C7BE0015F9E0 /* Table */ = { - isa = PBXGroup; - children = ( - 0EEB20D222B7C7AC0015F9E0 /* SettingsTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0EEB20D922B7C8330015F9E0 /* Router */ = { - isa = PBXGroup; - children = ( - 0EEB20DC22B7C8650015F9E0 /* SettingsRouterInput.swift */, - 0EEB20DE22B7C8790015F9E0 /* SettingsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0EEB20DA22B7C8380015F9E0 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0EEB20E022B7C8A90015F9E0 /* SettingsModuleInput.swift */, - 0EEB20E222B7C8C10015F9E0 /* SettingsPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0EEB20DB22B7C83E0015F9E0 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0EEB20E422B7C8E60015F9E0 /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - 0EEB20E422B7C8E60015F9E0 /* Table */ = { - isa = PBXGroup; - children = ( - 0EEB20E522B7C8F20015F9E0 /* SettingsTableInitializer.swift */, - 0EEB20E722B7C92C0015F9E0 /* SettingsTableConfigurator.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0EEB20E922B7D1350015F9E0 /* About */ = { - isa = PBXGroup; - children = ( - 0EEB20EE22B7D1580015F9E0 /* About.storyboard */, - 0EEB20ED22B7D14A0015F9E0 /* Assembly */, - 0EEB20EC22B7D1440015F9E0 /* Presenter */, - 0EEB20EB22B7D1400015F9E0 /* Router */, - 0EEB20EA22B7D13B0015F9E0 /* View */, - ); - path = About; - sourceTree = ""; - }; - 0EEB20EA22B7D13B0015F9E0 /* View */ = { - isa = PBXGroup; - children = ( - 0EEB20F222B7D1900015F9E0 /* AboutViewInput.swift */, - 0EEB20F422B7D1A40015F9E0 /* AboutViewOutput.swift */, - 0EEB20F622B7D2090015F9E0 /* AboutViewController.swift */, - A980573725807118000D03AB /* AboutViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - 0EEB20EB22B7D1400015F9E0 /* Router */ = { - isa = PBXGroup; - children = ( - 0EEB20F822B7D28C0015F9E0 /* AboutRouterInput.swift */, - 0EEB20FA22B7D2990015F9E0 /* AboutRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0EEB20EC22B7D1440015F9E0 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0EEB20FC22B7D2C90015F9E0 /* AboutModuleInput.swift */, - 0EEB20FE22B7D2DD0015F9E0 /* AboutPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0EEB20ED22B7D14A0015F9E0 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0EEB210022B7D2F50015F9E0 /* AboutInitializer.swift */, - 0EEB210222B7D3210015F9E0 /* AboutConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 0EEB213A22B8FABD0015F9E0 /* Router */ = { - isa = PBXGroup; - children = ( - 0EEB213B22B8FAD50015F9E0 /* MainRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0EEB213D22B8FB6B0015F9E0 /* Transition */ = { - isa = PBXGroup; - children = ( - 0EEB213E22B8FB840015F9E0 /* MainNavigationDelegate.swift */, - ); - path = Transition; - sourceTree = ""; - }; - 0EEB214022B8FB930015F9E0 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0EEB214122B8FBA50015F9E0 /* MainInitializer.swift */, - 0EEB214322B8FBC50015F9E0 /* MainConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 0EEB214522B8FC2E0015F9E0 /* View */ = { - isa = PBXGroup; - children = ( - 0EEB214622B8FC3E0015F9E0 /* WelcomeViewInput.swift */, - 0EEB214822B8FC570015F9E0 /* WelcomeViewOutput.swift */, - 0E09672122AE7FCF00E85F48 /* WelcomeViewController.swift */, - ); - path = View; - sourceTree = ""; - }; - 0EEB214A22B8FCB50015F9E0 /* Router */ = { - isa = PBXGroup; - children = ( - 0EEB214B22B8FCC70015F9E0 /* WelcomeRouterInput.swift */, - 0EEB214D22B8FCDC0015F9E0 /* WelcomeRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0EEB214F22B8FCF80015F9E0 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0EEB215022B8FD070015F9E0 /* WelcomeModuleInput.swift */, - 0EEB215222B8FD1F0015F9E0 /* WelcomePresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0EEB215422B8FD440015F9E0 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0EEB215522B8FD590015F9E0 /* WelcomeInitializer.swift */, - 0EEB215722B8FD800015F9E0 /* WelcomeConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 0EF26D172381A12F005BD84E /* Cell */ = { - isa = PBXGroup; - children = ( - 0E9F979522EAFC820015ADE2 /* DiscoverWebTagTableViewCell.swift */, - 0E53A3FA232F4D5000ACED49 /* DiscoverNoDevicesTableViewCell.swift */, - 0E09672B22AE94F000E85F48 /* DiscoverDeviceTableViewCell.swift */, - 0E79F28A244328D50048BF86 /* DiscoverAddWithMACTableViewCell.swift */, - ); - path = Cell; - sourceTree = ""; - }; - 0EF2862522CBAF280026C7A5 /* TagSettings */ = { - isa = PBXGroup; - children = ( - 0EF2862B22CBAF5D0026C7A5 /* TagSettings.storyboard */, - 0EF2862A22CBAF480026C7A5 /* Assembly */, - 0EF2862822CBAF3C0026C7A5 /* Presenter */, - 0EF2862722CBAF370026C7A5 /* Router */, - 66BC44812657AED400A03253 /* Submodules */, - 0EF2862622CBAF320026C7A5 /* View */, - ); - path = TagSettings; - sourceTree = ""; - }; - 0EF2862622CBAF320026C7A5 /* View */ = { - isa = PBXGroup; - children = ( - 0EF2862F22CBAFF10026C7A5 /* Table */, - 0EC50F5122CCB9DE00172EEB /* TagSettingsViewModel.swift */, - 0EF2863022CBB00D0026C7A5 /* TagSettingsViewInput.swift */, - 0EF2863222CBB0250026C7A5 /* TagSettingsViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 0EF2862722CBAF370026C7A5 /* Router */ = { - isa = PBXGroup; - children = ( - 0EF2863422CBB03A0026C7A5 /* TagSettingsRouterInput.swift */, - 0EF2863622CBB04E0026C7A5 /* TagSettingsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0EF2862822CBAF3C0026C7A5 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E92A96B2686369E00187E4F /* Debouncer.swift */, - 0EF2863822CBB06C0026C7A5 /* TagSettingsModuleInput.swift */, - 0EF2863A22CBB08C0026C7A5 /* TagSettingsPresenter.swift */, - A9F4471524B79959001E63AF /* TagSettingsModuleOutput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0EF2862A22CBAF480026C7A5 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0EF2863E22CBB1110026C7A5 /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - 0EF2862F22CBAFF10026C7A5 /* Table */ = { - isa = PBXGroup; - children = ( - 0EAD33F3239A571B00EC5BAA /* Cells */, - 0E02ABB8237598B200ED4629 /* RangeSeekSlider */, - 0EF4D0A522E0657F00947E04 /* SectionHeader */, - 0EF2862D22CBAFC80026C7A5 /* TagSettingsTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0EF2863E22CBB1110026C7A5 /* Table */ = { - isa = PBXGroup; - children = ( - 0EF2863F22CBB1340026C7A5 /* TagSettingsTableInitializer.swift */, - 0EF2864122CBB13F0026C7A5 /* TagSettingsTableConfigurator.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0EF4D0A522E0657F00947E04 /* SectionHeader */ = { - isa = PBXGroup; - children = ( - 0E62AEC822E065CC00A49BFB /* TagSettingsMoreInfoHeaderFooterView.swift */, - 0E62AECA22E065F000A49BFB /* TagSettingsMoreInfoHeaderFooterView.xib */, - 0EA92FDA2387E734008F1558 /* TagSettingsAlertsHeaderFooterView.swift */, - 0EA92FDE2387E74C008F1558 /* TagSettingsAlertsHeaderFooterView.xib */, - ); - path = SectionHeader; - sourceTree = ""; - }; - 11629D6C45208918E104E77F /* Assembly */ = { - isa = PBXGroup; - children = ( - 28B469B53431F206F4D0EC60 /* SignInConfigurator.swift */, - 85B8587156E1062D613B8960 /* SignInInitializer.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 31017308C4E5B3282DF4AAF9 /* ViewController */ = { - isa = PBXGroup; - children = ( - E6DB40883B83C652584EBB9A /* SignInViewController.swift */, - ); - path = ViewController; - sourceTree = ""; - }; - 321CE77F6EB26F685032F835 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 0E8BAC97245C716B00D380FB /* Combine.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 3D930628B855379BB9A9B1FF /* Assembly */ = { - isa = PBXGroup; - children = ( - AB681E62A66E5924A87859B1 /* ShareConfigurator.swift */, - 392F0E992BEAA3382C2CF709 /* ShareInitializer.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 64333D1C20B0C45900CDF4B6 = { - isa = PBXGroup; - children = ( - 0E62297E26A7F8890041DCDD /* RuuviOnboard */, - 0EF3D9E726860B5C0040A85E /* RuuviAnalytics */, - 0E2513642684CDF0004A522A /* RuuviNotifier */, - 0EB8B94126849F2B00FE130E /* RuuviNotification */, - 0EB8B9122683517100FE130E /* RuuviMigration */, - 0EF4E342268318BE00D83CC7 /* RuuviDFU */, - 0E8E3D9A26822A850082EC29 /* RuuviLocation */, - 0E8E3D6E2682284D0082EC29 /* RuuviVirtual */, - 0E11D146267DFA31002D0686 /* RuuviCloud */, - 0E11D143267DFA30002D0686 /* RuuviContext */, - 0E11D145267DFA31002D0686 /* RuuviCore */, - 0E11D141267DFA30002D0686 /* RuuviDaemon */, - 0E11D14C267DFA31002D0686 /* RuuviLocal */, - 0E11D147267DFA31002D0686 /* RuuviOntology */, - 0E11D148267DFA31002D0686 /* RuuviPersistence */, - 0E11D14A267DFA31002D0686 /* RuuviPool */, - 0E11D140267DFA30002D0686 /* RuuviReactor */, - 0E11D142267DFA30002D0686 /* RuuviRepository */, - 0E11D149267DFA31002D0686 /* RuuviService */, - 0E11D14B267DFA31002D0686 /* RuuviStorage */, - 0E11D144267DFA31002D0686 /* RuuviUser */, - A92C75DD24896B7400E332FE /* Fastlane */, - 64333D2720B0C45900CDF4B6 /* station */, - 64333D3C20B0C45A00CDF4B6 /* stationTests */, - 64333D4720B0C45B00CDF4B6 /* stationUITests */, - 64333D2620B0C45900CDF4B6 /* Products */, - 321CE77F6EB26F685032F835 /* Frameworks */, - ); - sourceTree = ""; - }; - 64333D2620B0C45900CDF4B6 /* Products */ = { - isa = PBXGroup; - children = ( - 64333D2520B0C45900CDF4B6 /* station.app */, - 64333D3920B0C45A00CDF4B6 /* stationTests.xctest */, - 64333D4420B0C45B00CDF4B6 /* stationUITests.xctest */, - 0E8BD404238566AB008B31EF /* station_dev.app */, - ); - name = Products; - sourceTree = ""; - }; - 64333D2720B0C45900CDF4B6 /* station */ = { - isa = PBXGroup; - children = ( - 0ECDF1B62313D7DA00A09ACA /* station.entitlements */, - 0E09671622AE74D600E85F48 /* Classes */, - 0E09672322AE895600E85F48 /* Extensions */, - 0E09671722AE762900E85F48 /* Resources */, - ); - path = station; - sourceTree = ""; - }; - 64333D3C20B0C45A00CDF4B6 /* stationTests */ = { - isa = PBXGroup; - children = ( - A971B0DA2421531C008EF50D /* Extensions */, - A94FFD25241C0F8000888017 /* Services */, - 64333D3D20B0C45A00CDF4B6 /* StationTests.swift */, - 64333D3F20B0C45B00CDF4B6 /* Info.plist */, - ); - path = stationTests; - sourceTree = ""; - }; - 64333D4720B0C45B00CDF4B6 /* stationUITests */ = { - isa = PBXGroup; - children = ( - 0E6C471623D305960016B46E /* StationUITests.swift */, - 64333D4A20B0C45B00CDF4B6 /* Info.plist */, - ); - path = stationUITests; - sourceTree = ""; - }; - 6486970E20E042BC00CCD7C1 /* Fonts */ = { - isa = PBXGroup; - children = ( - 64678190225D02CE0072856A /* Muli-Bold.ttf */, - 6467818F225CFB170072856A /* Muli-Regular.ttf */, - 643C651E21C38F490037BE5B /* Montserrat-Bold.ttf */, - 6486971120E0439200CCD7C1 /* Montserrat-Regular.ttf */, - 6486970F20E042E000CCD7C1 /* Oswald-Bold.ttf */, - 643EEC2A2266435100D4E837 /* Oswald-ExtraLight.ttf */, - ); - path = Fonts; - sourceTree = ""; - }; - 660EB2432669278E000FD22B /* Submodules */ = { - isa = PBXGroup; - children = ( - 660EB2442669278E000FD22B /* DfuDevicesScanner */, - ); - path = Submodules; - sourceTree = ""; - }; - 660EB2442669278E000FD22B /* DfuDevicesScanner */ = { - isa = PBXGroup; - children = ( - 660EB2542669278E000FD22B /* DfuDevicesScanner.storyboard */, - 660EB2452669278E000FD22B /* Assembly */, - 660EB2482669278E000FD22B /* Presenter */, - 660EB2552669278E000FD22B /* Router */, - 66718A24266A685700A380F8 /* Submodules */, - 660EB24C2669278E000FD22B /* View */, - ); - path = DfuDevicesScanner; - sourceTree = ""; - }; - 660EB2452669278E000FD22B /* Assembly */ = { - isa = PBXGroup; - children = ( - 660EB2462669278E000FD22B /* DfuDevicesScannerConfigurator.swift */, - 660EB2472669278E000FD22B /* DfuDevicesScannerInitializer.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 660EB2482669278E000FD22B /* Presenter */ = { - isa = PBXGroup; - children = ( - 660EB2492669278E000FD22B /* DfuDevicesScannerPresenter.swift */, - 660EB24A2669278E000FD22B /* DfuDevicesScannerModuleInput.swift */, - 660EB24B2669278E000FD22B /* DfuDevicesScannerModuleOutput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 660EB24C2669278E000FD22B /* View */ = { - isa = PBXGroup; - children = ( - 660EB24D2669278E000FD22B /* Cells */, - 660EB2502669278E000FD22B /* DfuDevicesScannerViewInput.swift */, - 660EB2512669278E000FD22B /* DfuDevicesScannerTableViewController.swift */, - 660EB2522669278E000FD22B /* DfuDevicesScannerViewModel.swift */, - 660EB2532669278E000FD22B /* DfuDevicesScannerViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 660EB24D2669278E000FD22B /* Cells */ = { - isa = PBXGroup; - children = ( - 660EB24E2669278E000FD22B /* DfuNoDeviceTableViewCell.swift */, - 660EB24F2669278E000FD22B /* DfuDeviceTableViewCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - 660EB2552669278E000FD22B /* Router */ = { - isa = PBXGroup; - children = ( - 660EB2562669278E000FD22B /* DfuDevicesScannerRouterInput.swift */, - 660EB2572669278E000FD22B /* DfuDevicesScannerRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 663155CA2667F40C005B90A6 /* UpdateFirmware */ = { - isa = PBXGroup; - children = ( - 663155D92667F40C005B90A6 /* UpdateFirmware.storyboard */, - 663155CB2667F40C005B90A6 /* Assembly */, - 663155CF2667F40C005B90A6 /* Presenter */, - 663155DA2667F40C005B90A6 /* Router */, - 660EB2432669278E000FD22B /* Submodules */, - 663155D32667F40C005B90A6 /* View */, - ); - path = UpdateFirmware; - sourceTree = ""; - }; - 663155CB2667F40C005B90A6 /* Assembly */ = { - isa = PBXGroup; - children = ( - 663155CC2667F40C005B90A6 /* Apple */, - ); - path = Assembly; - sourceTree = ""; - }; - 663155CC2667F40C005B90A6 /* Apple */ = { - isa = PBXGroup; - children = ( - 663155CD2667F40C005B90A6 /* UpdateFirmwareAppleInitializer.swift */, - 663155CE2667F40C005B90A6 /* UpdateFirmwareConfigurator.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 663155CF2667F40C005B90A6 /* Presenter */ = { - isa = PBXGroup; - children = ( - 663155D02667F40C005B90A6 /* UpdateFirmwarePresenter.swift */, - 663155D12667F40C005B90A6 /* UpdateFirmwareModuleOutput.swift */, - 663155D22667F40C005B90A6 /* UpdateFirmwareModuleInput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 663155D32667F40C005B90A6 /* View */ = { - isa = PBXGroup; - children = ( - 663155D42667F40C005B90A6 /* Apple */, - 663155D62667F40C005B90A6 /* UpdateFirmwareViewOutput.swift */, - 663155D72667F40C005B90A6 /* UpdateFirmwareViewInput.swift */, - ); - path = View; - sourceTree = ""; - }; - 663155D42667F40C005B90A6 /* Apple */ = { - isa = PBXGroup; - children = ( - 663155D52667F40C005B90A6 /* UpdateFirmwareAppleViewController.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 663155DA2667F40C005B90A6 /* Router */ = { - isa = PBXGroup; - children = ( - 663155DB2667F40C005B90A6 /* UpdateFirmwareRouter.swift */, - 663155DC2667F40C005B90A6 /* UpdateFirmwareRouterInput.swift */, - ); - path = Router; - sourceTree = ""; - }; - 66718A24266A685700A380F8 /* Submodules */ = { - isa = PBXGroup; - children = ( - 66718A25266A685700A380F8 /* DfuFlash */, - ); - path = Submodules; - sourceTree = ""; - }; - 66718A25266A685700A380F8 /* DfuFlash */ = { - isa = PBXGroup; - children = ( - 66718A36266A685700A380F8 /* DfuFlash.storyboard */, - 66718A26266A685700A380F8 /* Assembly */, - 66718A2A266A685700A380F8 /* Presenter */, - 66718A37266A685700A380F8 /* Router */, - 66718A2E266A685700A380F8 /* View */, - ); - path = DfuFlash; - sourceTree = ""; - }; - 66718A26266A685700A380F8 /* Assembly */ = { - isa = PBXGroup; - children = ( - 66718A27266A685700A380F8 /* Apple */, - ); - path = Assembly; - sourceTree = ""; - }; - 66718A27266A685700A380F8 /* Apple */ = { - isa = PBXGroup; - children = ( - 66718A28266A685700A380F8 /* DfuFlashAppleInitializer.swift */, - 66718A29266A685700A380F8 /* DfuFlashConfigurator.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 66718A2A266A685700A380F8 /* Presenter */ = { - isa = PBXGroup; - children = ( - 66718A2B266A685700A380F8 /* DfuFlashModuleInput.swift */, - 66718A2C266A685700A380F8 /* DfuFlashModuleOutput.swift */, - 66718A2D266A685700A380F8 /* DfuFlashPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 66718A2E266A685700A380F8 /* View */ = { - isa = PBXGroup; - children = ( - 66718A2F266A685700A380F8 /* Apple */, - 66718A31266A685700A380F8 /* Cells */, - 66718A33266A685700A380F8 /* DfuFlashViewModel.swift */, - 66718A34266A685700A380F8 /* DfuFlashViewInput.swift */, - 66718A35266A685700A380F8 /* DfuFlashViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 66718A2F266A685700A380F8 /* Apple */ = { - isa = PBXGroup; - children = ( - 66718A30266A685700A380F8 /* DfuFlashAppleViewController.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 66718A31266A685700A380F8 /* Cells */ = { - isa = PBXGroup; - children = ( - 66718A32266A685700A380F8 /* DfuLogTableViewCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - 66718A37266A685700A380F8 /* Router */ = { - isa = PBXGroup; - children = ( - 66718A38266A685700A380F8 /* DfuFlashRouter.swift */, - 66718A39266A685700A380F8 /* DfuFlashRouterInput.swift */, - ); - path = Router; - sourceTree = ""; - }; - 66718A61266A6CA700A380F8 /* DfuFilePicker */ = { - isa = PBXGroup; - children = ( - 66718A62266A6CA700A380F8 /* DfuFilePickerPresenter.swift */, - 66718A63266A6CA700A380F8 /* Sheet */, - ); - path = DfuFilePicker; - sourceTree = ""; - }; - 66718A63266A6CA700A380F8 /* Sheet */ = { - isa = PBXGroup; - children = ( - 66718A64266A6CA700A380F8 /* DfuFilePickerPresenterSheet.swift */, - ); - path = Sheet; - sourceTree = ""; - }; - 66BC44812657AED400A03253 /* Submodules */ = { - isa = PBXGroup; - children = ( - 0EE36E44269748A70021B746 /* DFU */, - 66BC44822657AED400A03253 /* OffsetCorrection */, - 663155CA2667F40C005B90A6 /* UpdateFirmware */, - ); - path = Submodules; - sourceTree = ""; - }; - 66BC44822657AED400A03253 /* OffsetCorrection */ = { - isa = PBXGroup; - children = ( - 66BC44832657AED400A03253 /* OffsetCorrection.storyboard */, - 66BC44842657AED400A03253 /* Assembly */, - 66BC44882657AED400A03253 /* Presenter */, - 66BC44922657AED400A03253 /* Router */, - 66BC448C2657AED400A03253 /* View */, - ); - path = OffsetCorrection; - sourceTree = ""; - }; - 66BC44842657AED400A03253 /* Assembly */ = { - isa = PBXGroup; - children = ( - 66BC44852657AED400A03253 /* Apple */, - ); - path = Assembly; - sourceTree = ""; - }; - 66BC44852657AED400A03253 /* Apple */ = { - isa = PBXGroup; - children = ( - 66BC44862657AED400A03253 /* OffsetCorrectionAppleInitializer.swift */, - 66BC44872657AED400A03253 /* OffsetCorrectionConfigurator.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 66BC44882657AED400A03253 /* Presenter */ = { - isa = PBXGroup; - children = ( - 66BC44892657AED400A03253 /* OffsetCorrectionModuleOutput.swift */, - 66BC448A2657AED400A03253 /* OffsetCorrectionPresenter.swift */, - 66BC448B2657AED400A03253 /* OffsetCorrectionModuleInput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 66BC448C2657AED400A03253 /* View */ = { - isa = PBXGroup; - children = ( - 66BC448D2657AED400A03253 /* Apple */, - 66BC448F2657AED400A03253 /* OffsetCorrectionViewInput.swift */, - 66BC44902657AED400A03253 /* OffsetCorrectionViewModel.swift */, - 66BC44912657AED400A03253 /* OffsetCorrectionViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 66BC448D2657AED400A03253 /* Apple */ = { - isa = PBXGroup; - children = ( - 66BC448E2657AED400A03253 /* OffsetCorrectionAppleViewController.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 66BC44922657AED400A03253 /* Router */ = { - isa = PBXGroup; - children = ( - 66BC44932657AED400A03253 /* OffsetCorrectionRouter.swift */, - 66BC44942657AED400A03253 /* OffsetCorrectionRouterInput.swift */, - ); - path = Router; - sourceTree = ""; - }; - 6C62E43912ACBCF757914A64 /* Router */ = { - isa = PBXGroup; - children = ( - 4E816312622E83E3B42001DC /* SignInRouterInput.swift */, - 6F0552F1D17F403B7DE508B5 /* SignInRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 71A3760FF84549A5FB45C805 /* SignIn */ = { - isa = PBXGroup; - children = ( - A9B5742C253B978D00DB7353 /* SignIn.storyboard */, - 11629D6C45208918E104E77F /* Assembly */, - 9430BF42054B093449B0B9FB /* Presenter */, - 6C62E43912ACBCF757914A64 /* Router */, - 975CCF09FE9E0AEF7A6CEEF8 /* View */, - ); - path = SignIn; - sourceTree = ""; - }; - 89F27275323C3CBC88A9180D /* View */ = { - isa = PBXGroup; - children = ( - A9E599482557340200F9E5CC /* Cells */, - 167F75FD2FDAD002C10686FA /* ShareViewInput.swift */, - CE5C4AD5C54EF024669EAF47 /* ShareViewOutput.swift */, - 354B5B6F50E98F55D6A672BA /* ShareViewModel.swift */, - 9607EC149920F19A54BE896D /* ViewController */, - ); - path = View; - sourceTree = ""; - }; - 910C826026E94BD80C07FBD2 /* Router */ = { - isa = PBXGroup; - children = ( - 9546F1EFEE8F8CFC22377BB4 /* ShareRouterInput.swift */, - BD7AE39C23B8C52BB202BB5E /* ShareRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 9430BF42054B093449B0B9FB /* Presenter */ = { - isa = PBXGroup; - children = ( - 87EFB230083D471777FBE5D0 /* SignInModuleInput.swift */, - 9B3006A5FB2173EC6AA2728D /* SignInModuleOutput.swift */, - E29B5190CB557178D11AB2CE /* SignInPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 9607EC149920F19A54BE896D /* ViewController */ = { - isa = PBXGroup; - children = ( - FC417B8977A47FFAE71585F0 /* ShareViewController.swift */, - ); - path = ViewController; - sourceTree = ""; - }; - 975CCF09FE9E0AEF7A6CEEF8 /* View */ = { - isa = PBXGroup; - children = ( - 4A7D6325DFC865D2D11BD1D1 /* SignInViewInput.swift */, - 4BD498E7491E278B4EF4919C /* SignInViewOutput.swift */, - FC59D3B5AD8926DBDD79AA1C /* SignInViewModel.swift */, - 31017308C4E5B3282DF4AAF9 /* ViewController */, - ); - path = View; - sourceTree = ""; - }; - A907A1D1245F7C4400041F6E /* ProgressBar */ = { - isa = PBXGroup; - children = ( - A907A1D2245F7C6600041F6E /* ProgressBarView.swift */, - ); - path = ProgressBar; - sourceTree = ""; - }; - A90E168C24604F0E00631E6C /* Chart */ = { - isa = PBXGroup; - children = ( - A90E16A72460974100631E6C /* Assembly */, - A90E168D24604F4600631E6C /* Presenter */, - A92E3C4724261BD000D981D5 /* View */, - ); - path = Chart; - sourceTree = ""; - }; - A90E168D24604F4600631E6C /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E050178268603DD007060C4 /* ChartFilterOperation.swift */, - A90E168E24604F7400631E6C /* TagChartPresenter.swift */, - A90E169224604FD100631E6C /* TagChartModuleInput.swift */, - A90E16962460504C00631E6C /* TagChartModuleOutput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - A90E169A24606A3900631E6C /* Interactor */ = { - isa = PBXGroup; - children = ( - A90E169B24606ABF00631E6C /* TagChartsInteractor.swift */, - A90E169F24606B0500631E6C /* TagChartsInteractorInput.swift */, - A90E16A324606B2000631E6C /* TagChartsInteractorOutput.swift */, - ); - path = Interactor; - sourceTree = ""; - }; - A90E16A72460974100631E6C /* Assembly */ = { - isa = PBXGroup; - children = ( - A90E16A82460975600631E6C /* TagChartAssembler.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - A9100D81241AD1D0004007FD /* Mock */ = { - isa = PBXGroup; - children = ( - A9100D82241AD1E4004007FD /* MockAlertPersistence.swift */, - A94FFD49241D45C600888017 /* MockRuuviTag.swift */, - A94FFD4B241D512900888017 /* MockLocalNotificationsManager.swift */, - A94FFD4D241D57E700888017 /* MockCalibrationService.swift */, - A94FFD4F241D6BA300888017 /* MockAlertServiceObserver.swift */, - ); - name = Mock; - path = ../..; - sourceTree = ""; - }; - A91D02D92511207200694733 /* Selection */ = { - isa = PBXGroup; - children = ( - A91D030C251121C800694733 /* Selection.storyboard */, - A91D02DB2511207200694733 /* Assembly */, - A91D02DF2511207200694733 /* Presenter */, - A91D02E22511207200694733 /* View */, - A91D0314251124E800694733 /* Model */, - A91D02E82511207200694733 /* Router */, - ); - path = Selection; - sourceTree = ""; - }; - A91D02DB2511207200694733 /* Assembly */ = { - isa = PBXGroup; - children = ( - A91D02DC2511207200694733 /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - A91D02DC2511207200694733 /* Table */ = { - isa = PBXGroup; - children = ( - A91D02DD2511207200694733 /* SelectionTableConfigurator.swift */, - A91D02DE2511207200694733 /* SelectionTableInitializer.swift */, - ); - path = Table; - sourceTree = ""; - }; - A91D02DF2511207200694733 /* Presenter */ = { - isa = PBXGroup; - children = ( - A91D02E02511207200694733 /* SelectionPresenter.swift */, - A91D02E12511207200694733 /* SelectionModuleInput.swift */, - A91D0310251123B400694733 /* SelectionModuleOutput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - A91D02E22511207200694733 /* View */ = { - isa = PBXGroup; - children = ( - A91D02E42511207200694733 /* Table */, - A91D02E32511207200694733 /* SelectionViewInput.swift */, - A91D02E72511207200694733 /* SelectionViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - A91D02E42511207200694733 /* Table */ = { - isa = PBXGroup; - children = ( - A91D02E52511207200694733 /* SelectionTableViewCell.swift */, - A91D02E62511207200694733 /* SelectionTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - A91D02E82511207200694733 /* Router */ = { - isa = PBXGroup; - children = ( - A91D02E92511207200694733 /* SelectionRouter.swift */, - A91D02EA2511207200694733 /* SelectionRouterInput.swift */, - ); - path = Router; - sourceTree = ""; - }; - A91D0314251124E800694733 /* Model */ = { - isa = PBXGroup; - children = ( - A91D0315251124F900694733 /* SelectionItem.swift */, - ); - path = Model; - sourceTree = ""; - }; - A92C75DD24896B7400E332FE /* Fastlane */ = { - isa = PBXGroup; - children = ( - A92C75DE24896BA100E332FE /* fastlane */, - A92C75E124896BA100E332FE /* Gemfile */, - ); - name = Fastlane; - sourceTree = ""; - }; - A92C75DE24896BA100E332FE /* fastlane */ = { - isa = PBXGroup; - children = ( - A986147A248C49B00030F197 /* Matchfile */, - A92C75E2248982A000E332FE /* Pluginfile */, - A92C75DF24896BA100E332FE /* Appfile */, - A92C75E024896BA100E332FE /* Fastfile */, - ); - path = fastlane; - sourceTree = ""; - }; - A92E3C4724261BD000D981D5 /* View */ = { - isa = PBXGroup; - children = ( - A92E3C612426446500D981D5 /* ChartView */, - A92E3C62242644B800D981D5 /* TagChartViewInput.swift */, - A93052B7242BFCC000FB62B1 /* TagChartViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - A92E3C612426446500D981D5 /* ChartView */ = { - isa = PBXGroup; - children = ( - A907A1D1245F7C4400041F6E /* ProgressBar */, - 0E92A9682686369200187E4F /* DateValueFormatter.swift */, - A92E3C592426415100D981D5 /* TagChartView.swift */, - A907A1D62460376600041F6E /* TagChartViewModel.swift */, - ); - path = ChartView; - sourceTree = ""; - }; - A93CDCCC25659B8600018C6C /* Alert */ = { - isa = PBXGroup; - children = ( - A93CDCDC25659BC500018C6C /* ViewModel */, - A93CDCCD25659B9400018C6C /* Impl */, - A93CDCCE25659BA600018C6C /* AlertPresenter.swift */, - ); - path = Alert; - sourceTree = ""; - }; - A93CDCCD25659B9400018C6C /* Impl */ = { - isa = PBXGroup; - children = ( - A93CDCDD25659BF600018C6C /* AlertPresenterImpl.swift */, - ); - path = Impl; - sourceTree = ""; - }; - A93CDCDC25659BC500018C6C /* ViewModel */ = { - isa = PBXGroup; - children = ( - A9BB94CB2540AB610042B190 /* AlertViewModel.swift */, - ); - path = ViewModel; - sourceTree = ""; - }; - A94FFD25241C0F8000888017 /* Services */ = { - isa = PBXGroup; - children = ( - A97B06482593B817003EE069 /* MeasurementsService */, - A94FFD27241C0FA400888017 /* Alert */, - ); - path = Services; - sourceTree = ""; - }; - A94FFD27241C0FA400888017 /* Alert */ = { - isa = PBXGroup; - children = ( - A94FFD3B241C1D0D00888017 /* AlertServiceSpec.swift */, - A9100D81241AD1D0004007FD /* Mock */, - ); - path = Alert; - sourceTree = ""; - }; - A9646453247BAE6A0001D55D /* View */ = { - isa = PBXGroup; - children = ( - A9646456247BAE6A0001D55D /* Table */, - A9646454247BAE6A0001D55D /* AdvancedViewInput.swift */, - A964645B247BAE6A0001D55D /* AdvancedViewOutput.swift */, - A964645C247BAE6A0001D55D /* AdvancedViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - A9646456247BAE6A0001D55D /* Table */ = { - isa = PBXGroup; - children = ( - A9646457247BAE6A0001D55D /* Cells */, - A964645A247BAE6A0001D55D /* AdvancedTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - A9646457247BAE6A0001D55D /* Cells */ = { - isa = PBXGroup; - children = ( - A9646458247BAE6A0001D55D /* AdvancedStepperTableViewCell.swift */, - A9646459247BAE6A0001D55D /* AdvancedSwitchTableViewCell.swift */, - A976CA7D24A928C20099BDC1 /* AdvancedDisclosureTableViewCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - A964645D247BAE6A0001D55D /* Assembly */ = { - isa = PBXGroup; - children = ( - A964645E247BAE6A0001D55D /* AdvancedConfigurator.swift */, - A964645F247BAE6A0001D55D /* AdvancedInitializer.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - A9646460247BAE6A0001D55D /* Presenter */ = { - isa = PBXGroup; - children = ( - A9646461247BAE6A0001D55D /* AdvancedModuleInput.swift */, - A9646462247BAE6A0001D55D /* AdvancedPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - A9646463247BAE6A0001D55D /* Router */ = { - isa = PBXGroup; - children = ( - A9646464247BAE6A0001D55D /* AdvancedRouterInput.swift */, - A9646465247BAE6A0001D55D /* AdvancedRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - A971B0DA2421531C008EF50D /* Extensions */ = { - isa = PBXGroup; - children = ( - A971B0DB24215334008EF50D /* XCTest+Extension.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - A97B06482593B817003EE069 /* MeasurementsService */ = { - isa = PBXGroup; - children = ( - A9E6770D25A30D0A000B75A3 /* MeasurementsServiceEnSpec.swift */, - A9E6771925A31556000B75A3 /* MeasurementsServiceSvSpec.swift */, - A935E47525A49E8F009538C4 /* MeasurementsServiceFiSpec.swift */, - A935E47C25A49E9E009538C4 /* MeasurementsServiceRuSpec.swift */, - ); - path = MeasurementsService; - sourceTree = ""; - }; - A9828E54247BAC0700E7E9D4 /* Advanced */ = { - isa = PBXGroup; - children = ( - A964648D247BAEBA0001D55D /* AdvancedSettings.storyboard */, - A964645D247BAE6A0001D55D /* Assembly */, - A9646460247BAE6A0001D55D /* Presenter */, - A9646463247BAE6A0001D55D /* Router */, - A9646453247BAE6A0001D55D /* View */, - ); - path = Advanced; - sourceTree = ""; - }; - A9E599482557340200F9E5CC /* Cells */ = { - isa = PBXGroup; - children = ( - A9E599492557341F00F9E5CC /* ShareDescriptionTableViewCell.swift */, - A9E599572557345200F9E5CC /* ShareEmailInputTableViewCell.swift */, - A9E599602557346600F9E5CC /* ShareSendButtonTableViewCell.swift */, - A9E59969255734A000F9E5CC /* ShareEmailTableViewCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - C11DEEB04EEFF836E529DA0B /* Presenter */ = { - isa = PBXGroup; - children = ( - 6AE2284D927021C0BEA560B0 /* ShareModuleInput.swift */, - 5710E4EF18D419D01D60405E /* ShareModuleOutput.swift */, - CC1D67615D6DBA9E2FC5B402 /* SharePresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - DB47D7C8D6149FEA8DD05FDC /* Share */ = { - isa = PBXGroup; - children = ( - A9E5993F25572CF700F9E5CC /* Share.storyboard */, - 3D930628B855379BB9A9B1FF /* Assembly */, - C11DEEB04EEFF836E529DA0B /* Presenter */, - 910C826026E94BD80C07FBD2 /* Router */, - 89F27275323C3CBC88A9180D /* View */, - ); - path = Share; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 0E8BD2AC238566AB008B31EF /* station_dev */ = { - isa = PBXNativeTarget; - buildConfigurationList = 0E8BD401238566AB008B31EF /* Build configuration list for PBXNativeTarget "station_dev" */; - buildPhases = ( - A96B1EF925A7208900D3ED9C /* SwiftGen */, - 0E8BD2AE238566AB008B31EF /* Sources */, - 0E8BD3DC238566AB008B31EF /* Frameworks */, - 0E8BD3DE238566AB008B31EF /* Resources */, - A9AB575A2413CCEC006FD3D2 /* Fetch secrets */, - 0E8301592393FC2B0003F2EF /* Swiftlint */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = station_dev; - packageProductDependencies = ( - 0E11D13E267DFA13002D0686 /* Localize_Swift */, - 0E11D14D267DFC75002D0686 /* RuuviCloud */, - 0E11D14F267DFC75002D0686 /* RuuviCloudApi */, - 0E11D151267DFC75002D0686 /* RuuviCloudPure */, - 0E11D153267DFC7B002D0686 /* RuuviContext */, - 0E11D155267DFC7B002D0686 /* RuuviContextRealm */, - 0E11D157267DFC7B002D0686 /* RuuviContextSQLite */, - 0E11D159267DFC80002D0686 /* RuuviCore */, - 0E11D15B267DFC80002D0686 /* RuuviCoreImage */, - 0E11D15D267DFC8C002D0686 /* RuuviDaemon */, - 0E11D15F267DFC8C002D0686 /* RuuviDaemonCloudSync */, - 0E11D161267DFC95002D0686 /* RuuviLocal */, - 0E11D163267DFC95002D0686 /* RuuviLocalUserDefaults */, - 0E11D165267DFC9C002D0686 /* RuuviOntology */, - 0E11D167267DFC9C002D0686 /* RuuviOntologyRealm */, - 0E11D169267DFC9C002D0686 /* RuuviOntologySQLite */, - 0E11D16B267DFCA2002D0686 /* RuuviPersistence */, - 0E11D16D267DFCA2002D0686 /* RuuviPersistenceRealm */, - 0E11D16F267DFCA2002D0686 /* RuuviPersistenceSQLite */, - 0E11D171267DFCA8002D0686 /* RuuviPool */, - 0E11D173267DFCA8002D0686 /* RuuviPoolCoordinator */, - 0E11D175267DFCAE002D0686 /* RuuviReactor */, - 0E11D177267DFCAE002D0686 /* RuuviReactorImpl */, - 0E11D179267DFCB6002D0686 /* RuuviRepository */, - 0E11D17B267DFCB6002D0686 /* RuuviRepositoryCoordinator */, - 0E11D17D267DFCBD002D0686 /* RuuviService */, - 0E11D17F267DFCBD002D0686 /* RuuviServiceAlert */, - 0E11D181267DFCBE002D0686 /* RuuviServiceAppSettings */, - 0E11D183267DFCBE002D0686 /* RuuviServiceCloudSync */, - 0E11D185267DFCBE002D0686 /* RuuviServiceFactory */, - 0E11D187267DFCBE002D0686 /* RuuviServiceOffsetCalibration */, - 0E11D189267DFCBE002D0686 /* RuuviServiceOwnership */, - 0E11D18B267DFCBE002D0686 /* RuuviServiceSensorProperties */, - 0E11D18D267DFCBE002D0686 /* RuuviServiceSensorRecords */, - 0E11D18F267DFCC7002D0686 /* RuuviStorage */, - 0E11D191267DFCC7002D0686 /* RuuviStorageCoordinator */, - 0E11D193267DFCCD002D0686 /* RuuviUser */, - 0E11D195267DFCCD002D0686 /* RuuviUserCoordinator */, - 0E11D1E9267DFF38002D0686 /* LightRoute */, - 0E11D1F2267E0040002D0686 /* FirebaseAnalytics */, - 0E11D1F4267E0040002D0686 /* FirebaseCrashlytics */, - 0E11D1F6267E0040002D0686 /* FirebaseRemoteConfig */, - 0E11D1FB267E00AC002D0686 /* Swinject */, - 0E11D200267E02D2002D0686 /* RangeSeekSlider */, - 0E11D205267E0346002D0686 /* GestureInstructions */, - 0E11D20A267E038C002D0686 /* SwinjectPropertyLoader */, - 0E11D20F267E051D002D0686 /* NordicDFU */, - 0E11D219267E13DB002D0686 /* FirebaseInAppMessaging-Beta */, - 0E11D21B267E13DB002D0686 /* FirebaseMessaging */, - 0E8E3D7F268228820082EC29 /* RuuviVirtual */, - 0E8E3D81268228820082EC29 /* RuuviVirtualModel */, - 0E8E3D83268228820082EC29 /* RuuviVirtualOWM */, - 0E8E3D85268228820082EC29 /* RuuviVirtualPersistence */, - 0E8E3D87268228820082EC29 /* RuuviVirtualReactor */, - 0E8E3D89268228820082EC29 /* RuuviVirtualRepository */, - 0E8E3D8B268228820082EC29 /* RuuviVirtualService */, - 0E8E3D8D268228820082EC29 /* RuuviVirtualStorage */, - 0E8E3D9B26822ADD0082EC29 /* RuuviLocation */, - 0E8E3D9D26822ADD0082EC29 /* RuuviLocationService */, - 0E8E3DA526822B130082EC29 /* RuuviCoreLocation */, - 0EF4E343268318DE00D83CC7 /* RuuviDFU */, - 0EF4E345268318DE00D83CC7 /* RuuviDFUImpl */, - 0EB8B9172683519900FE130E /* RuuviMigration */, - 0EB8B9192683519900FE130E /* RuuviMigrationImpl */, - 0EB8B92F26837A4700FE130E /* RuuviCoreDiff */, - 0EB8B93126837A4700FE130E /* RuuviCorePermission */, - 0EB8B93326837A4700FE130E /* RuuviCorePN */, - 0E2513552684A113004A522A /* RuuviNotification */, - 0E2513572684A113004A522A /* RuuviNotificationLocal */, - 0E2513652684CFF7004A522A /* RuuviNotifier */, - 0E2513672684CFF7004A522A /* RuuviNotifierImpl */, - 0E00C4FA2685B97D009B3C24 /* RuuviServiceExport */, - 0E00C4FC2685B97E009B3C24 /* RuuviServiceMeasurement */, - 0E05012C2685FDE8007060C4 /* RuuviDaemonBackground */, - 0E05012E2685FDE8007060C4 /* RuuviDaemonOperation */, - 0E0501302685FDE8007060C4 /* RuuviDaemonRuuviTag */, - 0E0501322685FDE8007060C4 /* RuuviDaemonVirtualTag */, - 0EEEBDE926860F6D00589D56 /* RuuviAnalytics */, - 0EEEBDEB26860F6D00589D56 /* RuuviAnalyticsImpl */, - 0E92A96E268636A700187E4F /* RuuviServiceGATT */, - 0EE36EBA269F05600021B746 /* Charts */, - 0E62297F26A7FA7C0041DCDD /* RuuviOnboard */, - ); - productName = station; - productReference = 0E8BD404238566AB008B31EF /* station_dev.app */; - productType = "com.apple.product-type.application"; - }; - 64333D2420B0C45900CDF4B6 /* station */ = { - isa = PBXNativeTarget; - buildConfigurationList = 64333D4D20B0C45B00CDF4B6 /* Build configuration list for PBXNativeTarget "station" */; - buildPhases = ( - 31884FB625C7442E002BC63F /* SwiftGen */, - 64333D2120B0C45900CDF4B6 /* Sources */, - 64333D2220B0C45900CDF4B6 /* Frameworks */, - 64333D2320B0C45900CDF4B6 /* Resources */, - A9AB57592413CCAB006FD3D2 /* Fetch secrets */, - A986147C248CD47A0030F197 /* Crashlytics */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = station; - packageProductDependencies = ( - 0E11D13C267DFA08002D0686 /* Localize_Swift */, - 0E11D197267DFCDA002D0686 /* RuuviCloud */, - 0E11D199267DFCDA002D0686 /* RuuviCloudApi */, - 0E11D19B267DFCDA002D0686 /* RuuviCloudPure */, - 0E11D19D267DFCDA002D0686 /* RuuviContext */, - 0E11D19F267DFCDA002D0686 /* RuuviContextRealm */, - 0E11D1A1267DFCDA002D0686 /* RuuviContextSQLite */, - 0E11D1A3267DFCDA002D0686 /* RuuviCore */, - 0E11D1A5267DFCDA002D0686 /* RuuviCoreImage */, - 0E11D1A7267DFCDA002D0686 /* RuuviDaemon */, - 0E11D1A9267DFCDA002D0686 /* RuuviDaemonCloudSync */, - 0E11D1AB267DFCDA002D0686 /* RuuviLocal */, - 0E11D1AD267DFCDA002D0686 /* RuuviLocalUserDefaults */, - 0E11D1AF267DFCDA002D0686 /* RuuviOntology */, - 0E11D1B1267DFCDA002D0686 /* RuuviOntologyRealm */, - 0E11D1B3267DFCDA002D0686 /* RuuviOntologySQLite */, - 0E11D1B5267DFCDA002D0686 /* RuuviPersistence */, - 0E11D1B7267DFCDA002D0686 /* RuuviPersistenceRealm */, - 0E11D1B9267DFCDA002D0686 /* RuuviPersistenceSQLite */, - 0E11D1BB267DFCDA002D0686 /* RuuviPool */, - 0E11D1BD267DFCDB002D0686 /* RuuviPoolCoordinator */, - 0E11D1BF267DFCDB002D0686 /* RuuviReactor */, - 0E11D1C1267DFCDB002D0686 /* RuuviReactorImpl */, - 0E11D1C3267DFCDB002D0686 /* RuuviRepository */, - 0E11D1C5267DFCDB002D0686 /* RuuviRepositoryCoordinator */, - 0E11D1C7267DFCDB002D0686 /* RuuviService */, - 0E11D1C9267DFCDB002D0686 /* RuuviServiceAlert */, - 0E11D1CB267DFCDB002D0686 /* RuuviServiceAppSettings */, - 0E11D1CD267DFCDB002D0686 /* RuuviServiceCloudSync */, - 0E11D1CF267DFCDB002D0686 /* RuuviServiceFactory */, - 0E11D1D1267DFCDB002D0686 /* RuuviServiceOffsetCalibration */, - 0E11D1D3267DFCDB002D0686 /* RuuviServiceOwnership */, - 0E11D1D5267DFCDB002D0686 /* RuuviServiceSensorProperties */, - 0E11D1D7267DFCDB002D0686 /* RuuviServiceSensorRecords */, - 0E11D1D9267DFCDB002D0686 /* RuuviStorage */, - 0E11D1DB267DFCDB002D0686 /* RuuviStorageCoordinator */, - 0E11D1DD267DFCDB002D0686 /* RuuviUser */, - 0E11D1DF267DFCDB002D0686 /* RuuviUserCoordinator */, - 0E11D1E7267DFF2F002D0686 /* LightRoute */, - 0E11D1EC267E0010002D0686 /* FirebaseAnalytics */, - 0E11D1EE267E0010002D0686 /* FirebaseRemoteConfig */, - 0E11D1F0267E0010002D0686 /* FirebaseCrashlytics */, - 0E11D1F9267E008D002D0686 /* Swinject */, - 0E11D1FE267E02BC002D0686 /* RangeSeekSlider */, - 0E11D203267E0336002D0686 /* GestureInstructions */, - 0E11D208267E037A002D0686 /* SwinjectPropertyLoader */, - 0E11D20D267E0510002D0686 /* NordicDFU */, - 0E11D215267E13D1002D0686 /* FirebaseInAppMessaging-Beta */, - 0E11D217267E13D1002D0686 /* FirebaseMessaging */, - 0E8E3D6F268228760082EC29 /* RuuviVirtual */, - 0E8E3D71268228760082EC29 /* RuuviVirtualModel */, - 0E8E3D73268228760082EC29 /* RuuviVirtualOWM */, - 0E8E3D75268228760082EC29 /* RuuviVirtualPersistence */, - 0E8E3D77268228760082EC29 /* RuuviVirtualReactor */, - 0E8E3D79268228760082EC29 /* RuuviVirtualRepository */, - 0E8E3D7B268228760082EC29 /* RuuviVirtualService */, - 0E8E3D7D268228760082EC29 /* RuuviVirtualStorage */, - 0E8E3D9F26822AE40082EC29 /* RuuviLocation */, - 0E8E3DA126822AE40082EC29 /* RuuviLocationService */, - 0E8E3DA326822B0D0082EC29 /* RuuviCoreLocation */, - 0EF4E347268318E600D83CC7 /* RuuviDFU */, - 0EF4E349268318E600D83CC7 /* RuuviDFUImpl */, - 0EB8B9132683519200FE130E /* RuuviMigration */, - 0EB8B9152683519200FE130E /* RuuviMigrationImpl */, - 0EB8B93526837A5100FE130E /* RuuviCoreDiff */, - 0EB8B93726837A5100FE130E /* RuuviCorePermission */, - 0EB8B93926837A5100FE130E /* RuuviCorePN */, - 0E2513512684A10A004A522A /* RuuviNotification */, - 0E2513532684A10A004A522A /* RuuviNotificationLocal */, - 0E2513692684D000004A522A /* RuuviNotifier */, - 0E25136B2684D001004A522A /* RuuviNotifierImpl */, - 0E00C4F62685B971009B3C24 /* RuuviServiceExport */, - 0E00C4F82685B972009B3C24 /* RuuviServiceMeasurement */, - 0E0501342685FDEF007060C4 /* RuuviDaemonBackground */, - 0E0501362685FDEF007060C4 /* RuuviDaemonOperation */, - 0E0501382685FDF0007060C4 /* RuuviDaemonRuuviTag */, - 0E05013A2685FDF0007060C4 /* RuuviDaemonVirtualTag */, - 0EEEBDE526860F6700589D56 /* RuuviAnalytics */, - 0EEEBDE726860F6700589D56 /* RuuviAnalyticsImpl */, - 0E92A970268636AE00187E4F /* RuuviServiceGATT */, - 0EE36EB8269F054E0021B746 /* Charts */, - 0E62298126A7FA8A0041DCDD /* RuuviOnboard */, - ); - productName = station; - productReference = 64333D2520B0C45900CDF4B6 /* station.app */; - productType = "com.apple.product-type.application"; - }; - 64333D3820B0C45A00CDF4B6 /* stationTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 64333D5020B0C45B00CDF4B6 /* Build configuration list for PBXNativeTarget "stationTests" */; - buildPhases = ( - E237490C592528A732D4EB7D /* [CP] Check Pods Manifest.lock */, - 64333D3520B0C45A00CDF4B6 /* Sources */, - 64333D3620B0C45A00CDF4B6 /* Frameworks */, - 64333D3720B0C45A00CDF4B6 /* Resources */, - 8BBA424823EFFBB654E49320 /* [CP] Copy Pods Resources */, - B2718B0350BA2A18235E5F63 /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 64333D3B20B0C45A00CDF4B6 /* PBXTargetDependency */, - ); - name = stationTests; - productName = stationTests; - productReference = 64333D3920B0C45A00CDF4B6 /* stationTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 64333D4320B0C45B00CDF4B6 /* stationUITests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 64333D5320B0C45B00CDF4B6 /* Build configuration list for PBXNativeTarget "stationUITests" */; - buildPhases = ( - 64333D4020B0C45B00CDF4B6 /* Sources */, - 64333D4120B0C45B00CDF4B6 /* Frameworks */, - 64333D4220B0C45B00CDF4B6 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 64333D4620B0C45B00CDF4B6 /* PBXTargetDependency */, - ); - name = stationUITests; - productName = stationUITests; - productReference = 64333D4420B0C45B00CDF4B6 /* stationUITests.xctest */; - productType = "com.apple.product-type.bundle.ui-testing"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 64333D1D20B0C45900CDF4B6 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0930; - LastUpgradeCheck = 1250; - ORGANIZATIONNAME = "Ruuvi Innovations Oy"; - TargetAttributes = { - 64333D2420B0C45900CDF4B6 = { - CreatedOnToolsVersion = 9.3.1; - SystemCapabilities = { - com.apple.Push = { - enabled = 1; - }; - }; - }; - 64333D3820B0C45A00CDF4B6 = { - CreatedOnToolsVersion = 9.3.1; - TestTargetID = 64333D2420B0C45900CDF4B6; - }; - 64333D4320B0C45B00CDF4B6 = { - CreatedOnToolsVersion = 9.3.1; - LastSwiftMigration = 1130; - TestTargetID = 64333D2420B0C45900CDF4B6; - }; - }; - }; - buildConfigurationList = 64333D2020B0C45900CDF4B6 /* Build configuration list for PBXProject "iOS" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ru, - fi, - sv, - fr, - ); - mainGroup = 64333D1C20B0C45900CDF4B6; - packageReferences = ( - 0E11D13B267DFA08002D0686 /* XCRemoteSwiftPackageReference "Localize-Swift" */, - 0E11D1E6267DFF2F002D0686 /* XCRemoteSwiftPackageReference "LightRoute" */, - 0E11D1EB267E0010002D0686 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, - 0E11D1F8267E008D002D0686 /* XCRemoteSwiftPackageReference "Swinject" */, - 0E11D1FD267E02BC002D0686 /* XCRemoteSwiftPackageReference "RangeSeekSlider" */, - 0E11D202267E0336002D0686 /* XCRemoteSwiftPackageReference "GestureInstructions" */, - 0E11D207267E0379002D0686 /* XCRemoteSwiftPackageReference "SwinjectPropertyLoader" */, - 0E11D20C267E0510002D0686 /* XCRemoteSwiftPackageReference "IOS-Pods-DFU-Library" */, - 0EE36EB7269F054E0021B746 /* XCRemoteSwiftPackageReference "Charts" */, - ); - productRefGroup = 64333D2620B0C45900CDF4B6 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 64333D2420B0C45900CDF4B6 /* station */, - 0E8BD2AC238566AB008B31EF /* station_dev */, - 64333D3820B0C45A00CDF4B6 /* stationTests */, - 64333D4320B0C45B00CDF4B6 /* stationUITests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 0E8BD3DE238566AB008B31EF /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 0E8BD3DF238566AB008B31EF /* Montserrat-Regular.ttf in Resources */, - 0E8BD3E0238566AB008B31EF /* About.storyboard in Resources */, - 0E8BD3E1238566AB008B31EF /* GoogleService-Info.plist in Resources */, - 0E197C7023C4A7D00074015B /* Presentation.plist in Resources */, - 0E31B04723BBA3F900660412 /* WebTagSettingsAlertsHeaderFooterView.xib in Resources */, - 0E8BD3E2238566AB008B31EF /* DiscoverWebTagsInfoHeaderFooterView.xib in Resources */, - 66BC44962657AED400A03253 /* OffsetCorrection.storyboard in Resources */, - 0E8BD3E4238566AB008B31EF /* Foreground.storyboard in Resources */, - 0E8BD3E5238566AB008B31EF /* LocationPicker.storyboard in Resources */, - 0E8BD3E6238566AB008B31EF /* Defaults.storyboard in Resources */, - 0E8BD3E7238566AB008B31EF /* Cards.storyboard in Resources */, - 0E8BD3E8238566AB008B31EF /* LaunchScreen.storyboard in Resources */, - 0E8BD3EA238566AB008B31EF /* Oswald-Bold.ttf in Resources */, - 0E8BD3EB238566AB008B31EF /* Localizable.strings in Resources */, - 66718A59266A685700A380F8 /* DfuFlash.storyboard in Resources */, - 0E8BD3EC238566AB008B31EF /* Discover.storyboard in Resources */, - 0E8BD3ED238566AB008B31EF /* TagSettings.storyboard in Resources */, - 0E8BD3EE238566AB008B31EF /* TagCharts.storyboard in Resources */, - 0E8BD3EF238566AB008B31EF /* Muli-Regular.ttf in Resources */, - 0EA92FE02387E74C008F1558 /* TagSettingsAlertsHeaderFooterView.xib in Resources */, - 0E8BD3F0238566AB008B31EF /* Oswald-ExtraLight.ttf in Resources */, - 0E8BD3F1238566AB008B31EF /* Language.storyboard in Resources */, - 0E8BD3F2238566AB008B31EF /* Welcome.storyboard in Resources */, - 0EAD33D72399273D00EC5BAA /* Heartbeat.storyboard in Resources */, - 0E8BD3F3238566AB008B31EF /* InfoPlist.strings in Resources */, - A9E5994125572CF700F9E5CC /* Share.storyboard in Resources */, - 660EB27A2669278E000FD22B /* DfuDevicesScanner.storyboard in Resources */, - 0E8BD3F4238566AB008B31EF /* ActivityRuuviLogo.storyboard in Resources */, - 0E8BD3F5238566AB008B31EF /* Assets.xcassets in Resources */, - A91D030E251121C800694733 /* Selection.storyboard in Resources */, - 0E8BD3F7238566AB008B31EF /* CardView.xib in Resources */, - 0E8BD3F8238566AB008B31EF /* Menu.storyboard in Resources */, - A964648F247BAEBA0001D55D /* AdvancedSettings.storyboard in Resources */, - 0E8BD3F9238566AB008B31EF /* Main.storyboard in Resources */, - 0EB8B9282683592700FE130E /* Networking.plist in Resources */, - 0E8BD3FA238566AB008B31EF /* Settings.storyboard in Resources */, - 0EB48DE7261A1816008E0D2D /* FeatureToggles.json in Resources */, - 0E8BD3FB238566AB008B31EF /* Muli-Bold.ttf in Resources */, - 663155F92667F40C005B90A6 /* UpdateFirmware.storyboard in Resources */, - 0E8BD3FC238566AB008B31EF /* TagSettingsMoreInfoHeaderFooterView.xib in Resources */, - 0E197C8223C5CDBE0074015B /* iOSDeviceModelMapping.plist in Resources */, - 0E8BD3FD238566AB008B31EF /* Montserrat-Bold.ttf in Resources */, - A9B5742D253B978D00DB7353 /* SignIn.storyboard in Resources */, - 0E8BD3FE238566AB008B31EF /* WebTagSettings.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D2320B0C45900CDF4B6 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 6486971220E0439200CCD7C1 /* Montserrat-Regular.ttf in Resources */, - 0EEB20EF22B7D1580015F9E0 /* About.storyboard in Resources */, - 0ECDF1B52313D65500A09ACA /* GoogleService-Info.plist in Resources */, - 0E197C6F23C4A7D00074015B /* Presentation.plist in Resources */, - 0E31B04623BBA3F900660412 /* WebTagSettingsAlertsHeaderFooterView.xib in Resources */, - 0E3FF735238157B700EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.xib in Resources */, - 66BC44952657AED400A03253 /* OffsetCorrection.storyboard in Resources */, - 0ECFF35723505F8D0061D11B /* Foreground.storyboard in Resources */, - 0E046F4622F17EF400BD4E9C /* LocationPicker.storyboard in Resources */, - 0E8A100223845E5100A9CBA6 /* Defaults.storyboard in Resources */, - 0E1C1DD122B3BDFC0032F6CA /* Cards.storyboard in Resources */, - 64333D3320B0C45A00CDF4B6 /* LaunchScreen.storyboard in Resources */, - 6486971020E0436A00CCD7C1 /* Oswald-Bold.ttf in Resources */, - 0EEB20C722B7A7200015F9E0 /* Localizable.strings in Resources */, - 66718A58266A685700A380F8 /* DfuFlash.storyboard in Resources */, - 0E09672822AE8D7A00E85F48 /* Discover.storyboard in Resources */, - 0EF2862C22CBAF5D0026C7A5 /* TagSettings.storyboard in Resources */, - 0E8FD0BF23335D6900FFA577 /* TagCharts.storyboard in Resources */, - 64678192225D03330072856A /* Muli-Regular.ttf in Resources */, - 0EA92FDF2387E74C008F1558 /* TagSettingsAlertsHeaderFooterView.xib in Resources */, - 643EEC2B2266435100D4E837 /* Oswald-ExtraLight.ttf in Resources */, - 0EBAF06C232006E00025A191 /* Language.storyboard in Resources */, - 0E09672022AE7F5C00E85F48 /* Welcome.storyboard in Resources */, - 0E53A3F1232DFC6200ACED49 /* InfoPlist.strings in Resources */, - 0E84BF552397F29800A37E1A /* Heartbeat.storyboard in Resources */, - A9E5994025572CF700F9E5CC /* Share.storyboard in Resources */, - 660EB2792669278E000FD22B /* DfuDevicesScanner.storyboard in Resources */, - 0E1C1DB522B3903B0032F6CA /* ActivityRuuviLogo.storyboard in Resources */, - 64333D3020B0C45A00CDF4B6 /* Assets.xcassets in Resources */, - A91D030D251121C800694733 /* Selection.storyboard in Resources */, - 0E1C1E1322B756D30032F6CA /* CardView.xib in Resources */, - 0E1C1DF122B3FDE30032F6CA /* Menu.storyboard in Resources */, - A964648E247BAEBA0001D55D /* AdvancedSettings.storyboard in Resources */, - 64333D2E20B0C45900CDF4B6 /* Main.storyboard in Resources */, - 0EB8B9272683592700FE130E /* Networking.plist in Resources */, - 0EEB20D122B7C6F30015F9E0 /* Settings.storyboard in Resources */, - 0EB48DE6261A1816008E0D2D /* FeatureToggles.json in Resources */, - 64678191225D03300072856A /* Muli-Bold.ttf in Resources */, - 663155F82667F40C005B90A6 /* UpdateFirmware.storyboard in Resources */, - 0E62AECB22E065F000A49BFB /* TagSettingsMoreInfoHeaderFooterView.xib in Resources */, - 0E197C8123C5CDBE0074015B /* iOSDeviceModelMapping.plist in Resources */, - 643C651F21C38F490037BE5B /* Montserrat-Bold.ttf in Resources */, - A9B5743E253B992B00DB7353 /* SignIn.storyboard in Resources */, - 0E046F2722F04A0300BD4E9C /* WebTagSettings.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D3720B0C45A00CDF4B6 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D4220B0C45B00CDF4B6 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 0E8301592393FC2B0003F2EF /* Swiftlint */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = Swiftlint; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; - }; - 31884FB625C7442E002BC63F /* SwiftGen */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = SwiftGen; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "if which swiftgen >/dev/null; then\n swiftgen\nelse\n echo \"warning: SwiftGen not installed, download it from https://github.com/SwiftGen/SwiftGen\"\nfi\n"; - }; - 8BBA424823EFFBB654E49320 /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-stationTests/Pods-stationTests-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - A96B1EF925A7208900D3ED9C /* SwiftGen */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = SwiftGen; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "if which swiftgen >/dev/null; then\n swiftgen\nelse\n echo \"warning: SwiftGen not installed, download it from https://github.com/SwiftGen/SwiftGen\"\nfi\n"; - }; - A986147C248CD47A0030F197 /* Crashlytics */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}", - "$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", - ); - name = Crashlytics; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${BUILD_DIR%Build/*}SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run\"\n"; - }; - A9AB57592413CCAB006FD3D2 /* Fetch secrets */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(SRCROOT)/station/Classes/Networking/Assembly/Networking.plist", - "$(SRCROOT)/station/Resources/Plists/GoogleService-Info.plist", - ); - name = "Fetch secrets"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "BUILD_APP_DIR=${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}\nif [[ ! -z \"$CI\" ]]; then \n exit 1;\nfi\ngit clone git@github.com:ruuvi/com.ruuvi.station.ios.keystore.git\nif [ $? -eq 0 ]; then\n /bin/cp -rf com.ruuvi.station.ios.keystore/GoogleService-Info.plist \"$BUILD_APP_DIR/GoogleService-Info.plist\"\n /bin/cp -rf com.ruuvi.station.ios.keystore/Networking.plist \"$BUILD_APP_DIR/Networking.plist\"\n rm -rf com.ruuvi.station.ios.keystore\nelse\n if grep -q \"{ set your API key here }\" $SCRIPT_INPUT_FILE_0; then\n echo \"warning: Missing OpenWeatherMap API key. In order to make Virtual Sensors work please obtain API key on https://openweathermap.org and put into station/Classes/Networking/Assembly/Networking.plist\"\n fi\n if grep -q \"1:925543306936:ios:84f5fda343c52e7671c64d\" $SCRIPT_INPUT_FILE_1; then\n echo \"warning: Demo GoogleServices credentials. If you want to use your own GoogleServices credentials, please replace the station/Resources/Plists/GoogleService-Info.plist file\"\n fi\nfi\n"; - }; - A9AB575A2413CCEC006FD3D2 /* Fetch secrets */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(SRCROOT)/station/Classes/Networking/Assembly/Networking.plist", - "$(SRCROOT)/station/Resources/Plists/GoogleService-Info.plist", - ); - name = "Fetch secrets"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "BUILD_APP_DIR=${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}\ngit clone git@github.com:ruuvi/com.ruuvi.station.ios.keystore.git\nif [ $? -eq 0 ]; then\n /bin/cp -rf com.ruuvi.station.ios.keystore/GoogleService-Info.plist \"$BUILD_APP_DIR/GoogleService-Info.plist\"\n /bin/cp -rf com.ruuvi.station.ios.keystore/Networking.plist \"$BUILD_APP_DIR/Networking.plist\"\n rm -rf com.ruuvi.station.ios.keystore\nelse\n if grep -q \"{ set your API key here }\" $SCRIPT_INPUT_FILE_0; then\n echo \"warning: Missing OpenWeatherMap API key. In order to make Virtual Sensors work please obtain API key on https://openweathermap.org and put into station/Classes/Networking/Assembly/Networking.plist\"\n fi\n if grep -q \"1:925543306936:ios:84f5fda343c52e7671c64d\" $SCRIPT_INPUT_FILE_1; then\n echo \"warning: Demo GoogleServices credentials. If you want to use your own GoogleServices credentials, please replace the station/Resources/Plists/GoogleService-Info.plist file\"\n fi\nfi\n"; - }; - B2718B0350BA2A18235E5F63 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-stationTests/Pods-stationTests-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - E237490C592528A732D4EB7D /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-stationTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 0E8BD2AE238566AB008B31EF /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 0E8BD2B0238566AB008B31EF /* CardView.swift in Sources */, - 0EB66B192686053800375BCC /* FeatureToggleProvider.swift in Sources */, - A92E3C5B2426428D00D981D5 /* TagChartView.swift in Sources */, - 0E8BD2B2238566AB008B31EF /* DiscoverTableViewController.swift in Sources */, - 0E8BD2B3238566AB008B31EF /* Optional.swift in Sources */, - 660EB26B2669278E000FD22B /* DfuDeviceTableViewCell.swift in Sources */, - 0EA7968A2664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift in Sources */, - 0E8BD2B8238566AB008B31EF /* CALayer+IB.swift in Sources */, - 0E8BD2BA238566AB008B31EF /* MenuTablePresentationController.swift in Sources */, - 0E92A96D2686369E00187E4F /* Debouncer.swift in Sources */, - 0E8BD2BD238566AB008B31EF /* TagSettingsViewInput.swift in Sources */, - 0EAD33DE2399273D00EC5BAA /* HeartbeatList.swift in Sources */, - 0E8BD2BE238566AB008B31EF /* DefaultsViewOutput.swift in Sources */, - 0E8BD2BF238566AB008B31EF /* MenuPresenter.swift in Sources */, - 0E8BD2C0238566AB008B31EF /* ForegroundRouter.swift in Sources */, - 0E8BD2C1238566AB008B31EF /* MenuTableViewController.swift in Sources */, - 0E8BD2C2238566AB008B31EF /* AboutRouterInput.swift in Sources */, - A9646473247BAE6B0001D55D /* AdvancedTableViewController.swift in Sources */, - 0E8BD2C4238566AB008B31EF /* WelcomeConfigurator.swift in Sources */, - 0E8E3D63268227530082EC29 /* RuuviVirtualError+LocalizedError.swift in Sources */, - 0E8BD2C5238566AB008B31EF /* ForegroundModuleInput.swift in Sources */, - 0EA796762664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift in Sources */, - 66BC44992657AED400A03253 /* OffsetCorrectionAppleInitializer.swift in Sources */, - 0E8BD2C6238566AB008B31EF /* AboutViewOutput.swift in Sources */, - 0E92A96A2686369200187E4F /* DateValueFormatter.swift in Sources */, - 0E8BD2C9238566AB008B31EF /* TagChartsViewModel.swift in Sources */, - A9646485247BAE6B0001D55D /* AdvancedPresenter.swift in Sources */, - 0E8BD2CC238566AB008B31EF /* PermissionPresenter.swift in Sources */, - 66718A5C266A685700A380F8 /* DfuFlashRouter.swift in Sources */, - 0E62297D26A7F84F0041DCDD /* AppRouter.swift in Sources */, - 66718A5F266A685700A380F8 /* DfuFlashRouterInput.swift in Sources */, - 0EAD33D82399273D00EC5BAA /* HeartbeatInitializer.swift in Sources */, - 0E8BD2CD238566AB008B31EF /* LocationPickerRouterInput.swift in Sources */, - A9F4471724B79959001E63AF /* TagSettingsModuleOutput.swift in Sources */, - 0E197C7E23C5CD7C0074015B /* UIDevice+ReadableModel.swift in Sources */, - 0E9E775B238CCE5F006D7013 /* String+Replace.swift in Sources */, - A91D02FE2511207300694733 /* SelectionTableViewCell.swift in Sources */, - A90E16A124606B0500631E6C /* TagChartsInteractorInput.swift in Sources */, - A91D02F82511207300694733 /* SelectionModuleInput.swift in Sources */, - 0E8BD2CF238566AB008B31EF /* TagChartsTransitioningDelegate.swift in Sources */, - 0E8BD2D0238566AB008B31EF /* WebTagSettingsRouter.swift in Sources */, - 660EB26E2669278E000FD22B /* DfuDevicesScannerViewInput.swift in Sources */, - 663155DE2667F40C005B90A6 /* UpdateFirmwareAppleInitializer.swift in Sources */, - A92A66BE2450C64A002918E7 /* UITableViewCell+ReusableView.swift in Sources */, - 0E8BD2D1238566AB008B31EF /* DefaultsPresenter.swift in Sources */, - 0E8BD2D2238566AB008B31EF /* WelcomeViewInput.swift in Sources */, - 0E8BD2D3238566AB008B31EF /* ForegroundList.swift in Sources */, - 0E8BD2D4238566AB008B31EF /* SettingsPresenter.swift in Sources */, - 663155FF2667F40C005B90A6 /* UpdateFirmwareRouterInput.swift in Sources */, - A91D02F52511207300694733 /* SelectionPresenter.swift in Sources */, - 0EB66B1D2686053800375BCC /* FirebaseFeatureToggleProvider.swift in Sources */, - 0E8BD2D5238566AB008B31EF /* LanguageTableConfigurator.swift in Sources */, - 0E8E3D6B268228130082EC29 /* DiscoverRuuviTagViewModel.swift in Sources */, - 0E197C6C23C4A52A0074015B /* MailComposerPresenterMessageUI.swift in Sources */, - 0E197C6723C4A47A0074015B /* MailComposerPresenter.swift in Sources */, - A9A48A5D244CD9EB0004FD50 /* UIWindow+Shake.swift in Sources */, - 0E8E3D6D268228130082EC29 /* DiscoverVirtualTagViewModel.swift in Sources */, - 0E8BD2D6238566AB008B31EF /* MenuTablePresentTransitionAnimation.swift in Sources */, - 0E92A9562686366D00187E4F /* TemperatureUnit+Localization.swift in Sources */, - 0E8BD2D7238566AB008B31EF /* WebTagSettingsViewInput.swift in Sources */, - A907A1D82460376600041F6E /* TagChartViewModel.swift in Sources */, - 0EE36E5F269748A80021B746 /* DFUModuleInput.swift in Sources */, - 0E8BD2D8238566AB008B31EF /* WelcomeRouterInput.swift in Sources */, - 0E8BD2DA238566AB008B31EF /* MenuModuleOutput.swift in Sources */, - 0EE98A7A26493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift in Sources */, - 66BC449C2657AED400A03253 /* OffsetCorrectionConfigurator.swift in Sources */, - 66718A3B266A685700A380F8 /* DfuFlashAppleInitializer.swift in Sources */, - 0E8BD2DD238566AB008B31EF /* Localizable.swift in Sources */, - 0EB66B212686053800375BCC /* FirebaseRemoteConfigService.swift in Sources */, - 0EB66B252686053800375BCC /* FeatureToggleService.swift in Sources */, - 0E197C6223C352380074015B /* TagSettingsAlertDescriptionCell.swift in Sources */, - 0E8BD2DE238566AB008B31EF /* LocationPickerAppleInitializer.swift in Sources */, - 0E8BD2DF238566AB008B31EF /* TagChartsPresenter.swift in Sources */, - 66718A53266A685700A380F8 /* DfuFlashViewInput.swift in Sources */, - A90E16A524606B2000631E6C /* TagChartsInteractorOutput.swift in Sources */, - 66BC44B12657AED400A03253 /* OffsetCorrectionViewOutput.swift in Sources */, - 663155F02667F40C005B90A6 /* UpdateFirmwareViewOutput.swift in Sources */, - 0E8BD2E0238566AB008B31EF /* DefaultsList.swift in Sources */, - 0E8BD2E2238566AB008B31EF /* WelcomePresenter.swift in Sources */, - 66718A47266A685700A380F8 /* DfuFlashPresenter.swift in Sources */, - 0E8BD2E4238566AB008B31EF /* CardsViewOutput.swift in Sources */, - 0E8BD2E5238566AB008B31EF /* DefaultsSwitchTableViewCell.swift in Sources */, - 66718A66266A6CA700A380F8 /* DfuFilePickerPresenter.swift in Sources */, - 0E8BD2E6238566AB008B31EF /* DefaultsViewInput.swift in Sources */, - 0E8BD2E7238566AB008B31EF /* LocationPickerRouter.swift in Sources */, - 0E8BD2E8238566AB008B31EF /* WebTagSettingsModuleInput.swift in Sources */, - 0E8BD2E9238566AB008B31EF /* MenuTableConfigurator.swift in Sources */, - 0EAD33E22399273D00EC5BAA /* HeartbeatViewModel.swift in Sources */, - A949A83C24707FDD006B7F4F /* LocalizedCache.swift in Sources */, - 0E8BD2ED238566AB008B31EF /* DefaultsStepperTableViewCell.swift in Sources */, - 0EA7967A2664B37F002BA25D /* RuuviLocalError+LocalizedError.swift in Sources */, - 66718A4D266A685700A380F8 /* DfuLogTableViewCell.swift in Sources */, - A91D0317251124F900694733 /* SelectionItem.swift in Sources */, - 0E8BD2F0238566AB008B31EF /* SettingsRouter.swift in Sources */, - 0EE49B9A23B877CF003012C2 /* WebTagSettingsAlertControlsCell.swift in Sources */, - 0EE36E69269748A80021B746 /* Spinner.swift in Sources */, - 0EA92FDC2387E734008F1558 /* TagSettingsAlertsHeaderFooterView.swift in Sources */, - 0E8BD2F3238566AB008B31EF /* SwipeDownToDismissNavigationController.swift in Sources */, - 0E8BD2F4238566AB008B31EF /* DefaultsRouterInput.swift in Sources */, - 0E8BD2F5238566AB008B31EF /* AboutPresenter.swift in Sources */, - 0E8E3D61268227530082EC29 /* RuuviCoreError+LocalizedError.swift in Sources */, - 0E8BD2F6238566AB008B31EF /* TagChartsPresentTransitionAnimation.swift in Sources */, - 0EB66B272686053800375BCC /* FeatureToggle.swift in Sources */, - 0E8BD2F7238566AB008B31EF /* TagSettingsViewModel.swift in Sources */, - 0E8BD2F8238566AB008B31EF /* CardsPresenter.swift in Sources */, - 0EB66B232686053800375BCC /* RemoteConfigService.swift in Sources */, - 0E8BD2F9238566AB008B31EF /* DiscoverWebTagsInfoHeaderFooterView.swift in Sources */, - 0E8BD2FC238566AB008B31EF /* Observable.swift in Sources */, - 0E92A9672686368000187E4F /* RUError.swift in Sources */, - 0E8BD2FD238566AB008B31EF /* ForegroundTableViewController.swift in Sources */, - 0EE36E5D269748A80021B746 /* FirmwareRepository.swift in Sources */, - 0E8BD300238566AB008B31EF /* TagSettingsViewOutput.swift in Sources */, - 660EB2622669278E000FD22B /* DfuDevicesScannerModuleInput.swift in Sources */, - 0E8BD301238566AB008B31EF /* ForegroundViewModel.swift in Sources */, - 0E8BD302238566AB008B31EF /* CardsViewModel.swift in Sources */, - 660EB2802669278E000FD22B /* DfuDevicesScannerRouter.swift in Sources */, - 0E8BD303238566AB008B31EF /* UIApplication+ViewController.swift in Sources */, - 0E8BD304238566AB008B31EF /* WebTagSettingsTableConfigurator.swift in Sources */, - 0E8BD308238566AB008B31EF /* TagSettingsMoreInfoHeaderFooterView.swift in Sources */, - 0E05016F268603CE007060C4 /* AppStateService.swift in Sources */, - 0E8BD30A238566AB008B31EF /* PermissionPresenterAlert.swift in Sources */, - 0E8BD30C238566AB008B31EF /* MainRouter.swift in Sources */, - 0E8BD30D238566AB008B31EF /* TagChartsScrollViewController.swift in Sources */, - 0E8BD30F238566AB008B31EF /* PhotoPickerPresenterSheet.swift in Sources */, - 0E8BD310238566AB008B31EF /* AboutConfigurator.swift in Sources */, - 0E8BD311238566AB008B31EF /* AboutViewInput.swift in Sources */, - 0E8BD312238566AB008B31EF /* TagChartsViewInput.swift in Sources */, - 0E8BD313238566AB008B31EF /* LanguageTableViewController.swift in Sources */, - A9646470247BAE6B0001D55D /* AdvancedSwitchTableViewCell.swift in Sources */, - 0E8BD314238566AB008B31EF /* DefaultsViewController.swift in Sources */, - 0E79F28C244328D50048BF86 /* DiscoverAddWithMACTableViewCell.swift in Sources */, - 66BC44AB2657AED400A03253 /* OffsetCorrectionViewInput.swift in Sources */, - 0E8BD316238566AB008B31EF /* DefaultsViewModel.swift in Sources */, - 0E8BD317238566AB008B31EF /* TagChartsScrollConfigurator.swift in Sources */, - 0E8BD319238566AB008B31EF /* LanguageViewOutput.swift in Sources */, - 0E8BD31A238566AB008B31EF /* DefaultsConfigurator.swift in Sources */, - 0E8BD31B238566AB008B31EF /* MenuRouter.swift in Sources */, - 0E8BD31C238566AB008B31EF /* ForegroundRouterInput.swift in Sources */, - 0EAD33D92399273D00EC5BAA /* HeartbeatConfigurator.swift in Sources */, - 0E92A9582686366D00187E4F /* ExportHeadersProvider.swift in Sources */, - A9E599592557345200F9E5CC /* ShareEmailInputTableViewCell.swift in Sources */, - 660EB2652669278E000FD22B /* DfuDevicesScannerModuleOutput.swift in Sources */, - 0EE36E71269748A80021B746 /* DFUViewModel.swift in Sources */, - A9646482247BAE6B0001D55D /* AdvancedModuleInput.swift in Sources */, - 0E8BD320238566AB008B31EF /* DefaultsInitializer.swift in Sources */, - 0E8BD322238566AB008B31EF /* MainInitializer.swift in Sources */, - 66718A50266A685700A380F8 /* DfuFlashViewModel.swift in Sources */, - 0E8BD324238566AB008B31EF /* ForegroundSwitchTableViewCell.swift in Sources */, - 0E2AFFA1266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift in Sources */, - 0E8BD326238566AB008B31EF /* MenuTableInitializer.swift in Sources */, - 0E8BD327238566AB008B31EF /* LocationPickerViewOutput.swift in Sources */, - 663155E42667F40C005B90A6 /* UpdateFirmwarePresenter.swift in Sources */, - 0EE49B9623B74775003012C2 /* WebTagSettingsAlertHeaderCell.swift in Sources */, - 0E8BD328238566AB008B31EF /* WebTagSettingsTableViewController.swift in Sources */, - 0EE36E79269748A80021B746 /* LatestRelease.swift in Sources */, - 0E8BD329238566AB008B31EF /* WelcomeRouter.swift in Sources */, - 66BC44A52657AED400A03253 /* OffsetCorrectionModuleInput.swift in Sources */, - A9E5994B2557341F00F9E5CC /* ShareDescriptionTableViewCell.swift in Sources */, - A91D0312251123B400694733 /* SelectionModuleOutput.swift in Sources */, - 0EAD33E02399273D00EC5BAA /* HeartbeatTableViewController.swift in Sources */, - 0EA796722664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift in Sources */, - A91D02F22511207200694733 /* SelectionTableInitializer.swift in Sources */, - A93CDCDF25659BF600018C6C /* AlertPresenterImpl.swift in Sources */, - 660EB2682669278E000FD22B /* DfuNoDeviceTableViewCell.swift in Sources */, - 0E8BD32E238566AB008B31EF /* TagSettingsRouter.swift in Sources */, - 0E62297B26A7F84F0041DCDD /* OnboardRouter.swift in Sources */, - 0E8BD32F238566AB008B31EF /* DiscoverDeviceTableViewCell.swift in Sources */, - 0E8BD330238566AB008B31EF /* AboutInitializer.swift in Sources */, - 0E8BD331238566AB008B31EF /* ForegroundEnvironmentObject.swift in Sources */, - 0E8BD332238566AB008B31EF /* MenuTableEmbededViewController.swift in Sources */, - A907BB1224AE620D009DA3DB /* UIWindow+Orientation.swift in Sources */, - 0E050173268603CE007060C4 /* UniversalLinkCoordinator.swift in Sources */, - 0EAD33DD2399273D00EC5BAA /* HeartbeatRouter.swift in Sources */, - 0E8BD334238566AB008B31EF /* TagChartsDismissTransitionAnimation.swift in Sources */, - 66718A41266A685700A380F8 /* DfuFlashModuleInput.swift in Sources */, - 660EB29D266928E6000FD22B /* UIViewController+Alert.swift in Sources */, - 0E8BD335238566AB008B31EF /* Date+Ruuvi.swift in Sources */, - 0EA796862664B84D002BA25D /* RuuviReactorError+LocalizedError.swift in Sources */, - 0E8BD339238566AB008B31EF /* CardsScrollViewController.swift in Sources */, - 0E8BD33A238566AB008B31EF /* LanguagePresenter.swift in Sources */, - 66718A56266A685700A380F8 /* DfuFlashViewOutput.swift in Sources */, - 0E8BD33C238566AB008B31EF /* TagSettingsTableViewController.swift in Sources */, - 0EB66B1B2686053800375BCC /* FallbackFeatureToggleProvider.swift in Sources */, - 0E8BD33E238566AB008B31EF /* LocationPickerModuleInput.swift in Sources */, - 0E92A9622686366D00187E4F /* Language+Localization.swift in Sources */, - A90E16982460504C00631E6C /* TagChartModuleOutput.swift in Sources */, - A91D02FB2511207300694733 /* SelectionViewInput.swift in Sources */, - 0E8BD343238566AB008B31EF /* SettingsTableViewController.swift in Sources */, - 0EAD33DC2399273D00EC5BAA /* HeartbeatRouterInput.swift in Sources */, - 66BC449F2657AED400A03253 /* OffsetCorrectionModuleOutput.swift in Sources */, - 0EF4E350268319A400D83CC7 /* DfuFirmware+Log.swift in Sources */, - 0EAD33DF2399273D00EC5BAA /* HeartbeatEnvironmentObject.swift in Sources */, - 0EE36E63269748A80021B746 /* Publishers+System.swift in Sources */, - 660EB2712669278E000FD22B /* DfuDevicesScannerTableViewController.swift in Sources */, - 0E8BD345238566AB008B31EF /* SwipeDownToDismissTransitionAnimation.swift in Sources */, - A9E5996B255734A000F9E5CC /* ShareEmailTableViewCell.swift in Sources */, - 660EB2742669278E000FD22B /* DfuDevicesScannerViewModel.swift in Sources */, - 0E8BD348238566AB008B31EF /* SettingsRouterInput.swift in Sources */, - 0EAD33E32399273D00EC5BAA /* HeartbeatViewOutput.swift in Sources */, - 0E8BD349238566AB008B31EF /* ForegroundStepperTableViewCell.swift in Sources */, - 0E8BD34A238566AB008B31EF /* MenuTableTransitionManager.swift in Sources */, - 0EA7968E2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift in Sources */, - 0E8BD34B238566AB008B31EF /* TagChartsViewOutput.swift in Sources */, - A976CA7F24A928C20099BDC1 /* AdvancedDisclosureTableViewCell.swift in Sources */, - A93CDCAC25657C1D00018C6C /* MenuViewModel.swift in Sources */, - 663155FC2667F40C005B90A6 /* UpdateFirmwareRouter.swift in Sources */, - 0E8BD34C238566AB008B31EF /* DefaultsRouter.swift in Sources */, - 0E92A95A2686366D00187E4F /* HeartbeatDaemonTitles.swift in Sources */, - A91D03042511207300694733 /* SelectionViewOutput.swift in Sources */, - 663155F32667F40C005B90A6 /* UpdateFirmwareViewInput.swift in Sources */, - 0E8BD34D238566AB008B31EF /* ForegroundViewInput.swift in Sources */, - 0EE36E77269748A80021B746 /* DFUInteractor.swift in Sources */, - 0E050171268603CE007060C4 /* UniversalLinkCoordinatormpl.swift in Sources */, - 0E8BD34E238566AB008B31EF /* WebTagSettingsRouterInput.swift in Sources */, - 66718A44266A685700A380F8 /* DfuFlashModuleOutput.swift in Sources */, - A91D03072511207300694733 /* SelectionRouter.swift in Sources */, - 0EE36E75269748A80021B746 /* DFUInteractorInput.swift in Sources */, - 0E8BD353238566AB008B31EF /* LocalizationService.swift in Sources */, - 0E8BD354238566AB008B31EF /* RURangeSeekSlider.swift in Sources */, - 0E8BD355238566AB008B31EF /* CardsModuleInput.swift in Sources */, - 0E8BD356238566AB008B31EF /* LanguageRouterInput.swift in Sources */, - 0E8BD359238566AB008B31EF /* ForegroundViewOutput.swift in Sources */, - 0E1B2F37239DF0120060C469 /* TagSettingsAlertControlsCell.swift in Sources */, - 0EE36E6B269748A80021B746 /* LargeButtonStyle.swift in Sources */, - 0E8BD35A238566AB008B31EF /* LanguageModuleInput.swift in Sources */, - 663155ED2667F40C005B90A6 /* UpdateFirmwareAppleViewController.swift in Sources */, - 0E8BD35B238566AB008B31EF /* PresentationAssembly.swift in Sources */, - A91D02EF2511207200694733 /* SelectionTableConfigurator.swift in Sources */, - 0E8BD35C238566AB008B31EF /* DiscoverWebTagTableViewCell.swift in Sources */, - 0E8BD35D238566AB008B31EF /* AboutModuleInput.swift in Sources */, - 0E05016D268603CE007060C4 /* AppStateServiceImpl.swift in Sources */, - 0E8BD35E238566AB008B31EF /* WelcomeViewOutput.swift in Sources */, - 0EAD33DA2399273D00EC5BAA /* HeartbeatModuleInput.swift in Sources */, - A91D03012511207300694733 /* SelectionTableViewController.swift in Sources */, - 0E8BD35F238566AB008B31EF /* MainNavigationDelegate.swift in Sources */, - 0E8BD363238566AB008B31EF /* WebTagSettingsTableInitializer.swift in Sources */, - 0E8BD364238566AB008B31EF /* MenuRouterInput.swift in Sources */, - 0E92A95E2686366D00187E4F /* MeasurementType.swift in Sources */, - 0EA796822664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift in Sources */, - 0E8BD365238566AB008B31EF /* LanguageRouter.swift in Sources */, - 0E8BD367238566AB008B31EF /* TagChartsModuleInput.swift in Sources */, - A9A67BFB24C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift in Sources */, - 0E8BD368238566AB008B31EF /* Double+Temperature.swift in Sources */, - 0E05012B2685FDD3007060C4 /* RuuviDFUError+LocalizedError.swift in Sources */, - 0E8BD36C238566AB008B31EF /* ActivityPresenter.swift in Sources */, - A980573925807118000D03AB /* AboutViewModel.swift in Sources */, - 0E8BD36D238566AB008B31EF /* MenuViewOutput.swift in Sources */, - 0E8BD36E238566AB008B31EF /* DiscoverViewInput.swift in Sources */, - 0EAD33DB2399273D00EC5BAA /* HeartbeatPresenter.swift in Sources */, - 0E8BD36F238566AB008B31EF /* LocationPickerAppleViewController.swift in Sources */, - 0E8BD370238566AB008B31EF /* TagSettingsTableConfigurator.swift in Sources */, - 0E8BD372238566AB008B31EF /* SwipeDownToDismissTransitioningDelegate.swift in Sources */, - 0E8BD373238566AB008B31EF /* MenuViewInput.swift in Sources */, - 0E8BD374238566AB008B31EF /* ActivitySpinnerView.swift in Sources */, - A9E6774925A33081000B75A3 /* String+Characters.swift in Sources */, - A91D030A2511207300694733 /* SelectionRouterInput.swift in Sources */, - 0E050177268603CE007060C4 /* UniversalLinkRouter.swift in Sources */, - 0E8BD376238566AB008B31EF /* ActivityPresenterRuuviLogo.swift in Sources */, - 0EAD33E42399273D00EC5BAA /* HeartbeatViewController.swift in Sources */, - 0E8BD377238566AB008B31EF /* AboutViewController.swift in Sources */, - 663155E12667F40C005B90A6 /* UpdateFirmwareConfigurator.swift in Sources */, - 0E8BD378238566AB008B31EF /* DiscoverRouterInput.swift in Sources */, - 66BC44A22657AED400A03253 /* OffsetCorrectionPresenter.swift in Sources */, - 66BC44AE2657AED400A03253 /* OffsetCorrectionViewModel.swift in Sources */, - 0E8BD37A238566AB008B31EF /* DefaultsEnvironmentObject.swift in Sources */, - 0E8BD37C238566AB008B31EF /* ViewInput.swift in Sources */, - 0E8BD37D238566AB008B31EF /* UserDefaults+Optional.swift in Sources */, - 0E8BD37E238566AB008B31EF /* TagChartsRouterInput.swift in Sources */, - 0E8BD37F238566AB008B31EF /* CardsViewInput.swift in Sources */, - 0E8BD380238566AB008B31EF /* DiscoverPresenter.swift in Sources */, - 0E8BD381238566AB008B31EF /* LanguageViewInput.swift in Sources */, - 0E8BD382238566AB008B31EF /* AboutRouter.swift in Sources */, - 0E8BD384238566AB008B31EF /* TagChartsRouter.swift in Sources */, - 0E8BD385238566AB008B31EF /* DiscoverTableInitializer.swift in Sources */, - 66718A6D266BD0E800A380F8 /* Color+Ruuvi.swift in Sources */, - 0E8BD386238566AB008B31EF /* DiscoverViewOutput.swift in Sources */, - 0E8BD387238566AB008B31EF /* DiscoverRouter.swift in Sources */, - A93052B9242BFCF800FB62B1 /* TagChartViewOutput.swift in Sources */, - A964647F247BAE6B0001D55D /* AdvancedInitializer.swift in Sources */, - A93CDCD025659BA600018C6C /* AlertPresenter.swift in Sources */, - 0E8BD388238566AB008B31EF /* WelcomeModuleInput.swift in Sources */, - 66718A4A266A685700A380F8 /* DfuFlashAppleViewController.swift in Sources */, - 0E8BD389238566AB008B31EF /* PhotoPickerPresenter.swift in Sources */, - 0E8BD38A238566AB008B31EF /* LocationPickerPresenter.swift in Sources */, - A964646D247BAE6B0001D55D /* AdvancedStepperTableViewCell.swift in Sources */, - 0E8BD38D238566AB008B31EF /* DefaultsModuleInput.swift in Sources */, - 0E8BD390238566AB008B31EF /* TagSettingsPresenter.swift in Sources */, - 663155E72667F40C005B90A6 /* UpdateFirmwareModuleOutput.swift in Sources */, - 0E92A9602686366D00187E4F /* HumidityUnit+Localization.swift in Sources */, - 0E8BD391238566AB008B31EF /* TagChartsModuleOutput.swift in Sources */, - 0E8BD393238566AB008B31EF /* SwipeDownToDismissInteractiveTransition.swift in Sources */, - 0E8BD394238566AB008B31EF /* TagSettingsRouterInput.swift in Sources */, - 0E8BD395238566AB008B31EF /* NSObject+Observable.swift in Sources */, - 0E0501292685FDD3007060C4 /* RuuviDaemonError+LocalizedError.swift in Sources */, - 0E8BD396238566AB008B31EF /* TagSettingsModuleInput.swift in Sources */, - 66718A3E266A685700A380F8 /* DfuFlashConfigurator.swift in Sources */, - 0E8BD398238566AB008B31EF /* LocationPickerAppleConfigurator.swift in Sources */, - 0E8BD399238566AB008B31EF /* AppAssembly.swift in Sources */, - A9646467247BAE6B0001D55D /* AdvancedViewInput.swift in Sources */, - 0EB66B2B2686053800375BCC /* InfoProvider.swift in Sources */, - 0E8BD39B238566AB008B31EF /* MenuTableDismissTransitionAnimation.swift in Sources */, - 0E8BD39C238566AB008B31EF /* DiscoverModuleInput.swift in Sources */, - 0E8BD39E238566AB008B31EF /* SettingsTableConfigurator.swift in Sources */, - 0E8BD3A0238566AB008B31EF /* LanguageTableInitializer.swift in Sources */, - 0EB66B1F2686053800375BCC /* LocalFeatureToggleProvider.swift in Sources */, - 660EB2772669278E000FD22B /* DfuDevicesScannerViewOutput.swift in Sources */, - 660EB27D2669278E000FD22B /* DfuDevicesScannerRouterInput.swift in Sources */, - 0E8BD3A1238566AB008B31EF /* LocationPickerModuleOutput.swift in Sources */, - 0E8BD3A2238566AB008B31EF /* DiscoverTableConfigurator.swift in Sources */, - 0E8BD3A4238566AB008B31EF /* LocationPickerViewInput.swift in Sources */, - 660EB25C2669278E000FD22B /* DfuDevicesScannerInitializer.swift in Sources */, - 0E8BD3A5238566AB008B31EF /* SettingsTableInitializer.swift in Sources */, - 0E8BD3A6238566AB008B31EF /* TagChartsTransitionManager.swift in Sources */, - 0E8BD3A7238566AB008B31EF /* ActivityRuuviLogoViewController.swift in Sources */, - 0EE36E6F269748A80021B746 /* Feedback.swift in Sources */, - 0EA7967E2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift in Sources */, - 0E8BD3A8238566AB008B31EF /* TagChartsScrollInitializer.swift in Sources */, - A90E169D24606ABF00631E6C /* TagChartsInteractor.swift in Sources */, - 0EAD33E12399273D00EC5BAA /* HeartbeatViewInput.swift in Sources */, - 0E8BD3A9238566AB008B31EF /* ForegroundConfigurator.swift in Sources */, - 0E8BD3AA238566AB008B31EF /* AppDelegate.swift in Sources */, - 0E8BD3AB238566AB008B31EF /* TagSettingsTableInitializer.swift in Sources */, - A9BD38BB24F6108300904BBE /* Humidity+Offset.swift in Sources */, - A964647C247BAE6B0001D55D /* AdvancedConfigurator.swift in Sources */, - 0E05017A268603DD007060C4 /* ChartFilterOperation.swift in Sources */, - 0E8BD3B1238566AB008B31EF /* WebTagSettingsViewModel.swift in Sources */, - 0E050175268603CE007060C4 /* UniversalLinkRouterImpl.swift in Sources */, - 0E92A95C2686366D00187E4F /* RuuviNotifierTitlesImpl.swift in Sources */, - 0E8BD3B2238566AB008B31EF /* MainConfigurator.swift in Sources */, - A90E16AA24609B9B00631E6C /* TagChartAssembler.swift in Sources */, - 0E8BD3B3238566AB008B31EF /* WebTagSettingsPresenter.swift in Sources */, - 0E8BD3B4238566AB008B31EF /* MenuModuleInput.swift in Sources */, - 0E8BD3B6238566AB008B31EF /* CardsScrollInitializer.swift in Sources */, - 0E8BD3B7238566AB008B31EF /* DefaultsTableViewController.swift in Sources */, - A98BC876250E4265001CEFDC /* Double+Round.swift in Sources */, - 0E8BD3BA238566AB008B31EF /* MenuTableTransitioningDelegate.swift in Sources */, - 0E8BD3BB238566AB008B31EF /* ErrorPresenter.swift in Sources */, - 660EB2592669278E000FD22B /* DfuDevicesScannerConfigurator.swift in Sources */, - 0E92A9642686366D00187E4F /* VirtualLocation+Localization.swift in Sources */, - 66718A69266A6CA700A380F8 /* DfuFilePickerPresenterSheet.swift in Sources */, - 0EE36E7B269748A80021B746 /* DFUModuleFactory.swift in Sources */, - 0E8BD3BC238566AB008B31EF /* LanguageTableViewCell.swift in Sources */, - 0E31B04323BBA37C00660412 /* WebTagSettingsAlertsHeaderFooterView.swift in Sources */, - 0E8BD3C1238566AB008B31EF /* ForegroundRow.swift in Sources */, - 0E8BD3C2238566AB008B31EF /* SettingsViewOutput.swift in Sources */, - 0E290A862660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift in Sources */, - 0E8BD3C3238566AB008B31EF /* ForegroundPresenter.swift in Sources */, - 0E8BD3C4238566AB008B31EF /* DiscoverNoDevicesTableViewCell.swift in Sources */, - 0EAD33D52399271C00EC5BAA /* DiscoverModuleOutput.swift in Sources */, - A9646476247BAE6B0001D55D /* AdvancedViewOutput.swift in Sources */, - 660EB25F2669278E000FD22B /* DfuDevicesScannerPresenter.swift in Sources */, - 0E8BD3C5238566AB008B31EF /* SettingsModuleInput.swift in Sources */, - 0E8BD3C6238566AB008B31EF /* CardsScrollConfigurator.swift in Sources */, - 0E8BD3C9238566AB008B31EF /* WebTagSettingsViewOutput.swift in Sources */, - 663155EA2667F40C005B90A6 /* UpdateFirmwareModuleInput.swift in Sources */, - 0E8BD3CA238566AB008B31EF /* CardsRouter.swift in Sources */, - 0E8BD3CB238566AB008B31EF /* WelcomeViewController.swift in Sources */, - A9646488247BAE6B0001D55D /* AdvancedRouterInput.swift in Sources */, - 0E8BD3CC238566AB008B31EF /* CardsRouterInput.swift in Sources */, - A91D031B25113EAA00694733 /* UnitPressure+Extension.swift in Sources */, - 0EE36E65269748A80021B746 /* URLSession+downloadTaskPublisher.swift in Sources */, - 0E8BD3CD238566AB008B31EF /* WelcomeInitializer.swift in Sources */, - A9E599622557346600F9E5CC /* ShareSendButtonTableViewCell.swift in Sources */, - A9646479247BAE6B0001D55D /* AdvancedViewModel.swift in Sources */, - A92E3C64242644B800D981D5 /* TagChartViewInput.swift in Sources */, - 0E1B2F33239DEF120060C469 /* TagSettingsAlertHeaderCell.swift in Sources */, - A90E169024604F7400631E6C /* TagChartPresenter.swift in Sources */, - 0EE36E67269748A80021B746 /* View+Any.swift in Sources */, - A907A1D4245F7C6600041F6E /* ProgressBarView.swift in Sources */, - 0E8BD3CF238566AB008B31EF /* SettingsViewInput.swift in Sources */, - 0EE36E61269748A80021B746 /* DFUPresenter.swift in Sources */, - 0E8BD3D2238566AB008B31EF /* CardsRouterDelegate.swift in Sources */, - A90E169424604FD100631E6C /* TagChartModuleInput.swift in Sources */, - 66BC44A82657AED400A03253 /* OffsetCorrectionAppleViewController.swift in Sources */, - A964648B247BAE6B0001D55D /* AdvancedRouter.swift in Sources */, - 0E8BD3D5238566AB008B31EF /* ErrorPresenterAlert.swift in Sources */, - 66BC44B42657AED400A03253 /* OffsetCorrectionRouter.swift in Sources */, - 0E8BD3D6238566AB008B31EF /* ForegroundViewController.swift in Sources */, - 66BC44B72657AED400A03253 /* OffsetCorrectionRouterInput.swift in Sources */, - 0E8BD3D8238566AB008B31EF /* ForegroundInitializer.swift in Sources */, - 1F3C224646FB9B196464E9DD /* SignInConfigurator.swift in Sources */, - 3E9E7B1756AB4F6867DD3634 /* SignInInitializer.swift in Sources */, - 08E830207D43DAF06076D647 /* SignInModuleInput.swift in Sources */, - 8A37F49EA3B84BB415491B03 /* SignInModuleOutput.swift in Sources */, - 7350803A8D6DD23F1057994F /* SignInPresenter.swift in Sources */, - E8C4E5B85668D51EC22BC75A /* SignInRouterInput.swift in Sources */, - D037B55274A07756F884696B /* SignInRouter.swift in Sources */, - ABCA915676F9A8C975D9F2A3 /* SignInViewInput.swift in Sources */, - 0EE36E6D269748A80021B746 /* ProgressBar.swift in Sources */, - 34238B2C062103E10D2BC65D /* SignInViewOutput.swift in Sources */, - 0EE36E7F269749280021B746 /* RuuviColor.swift in Sources */, - 74E67721EFA7BF9397D52B1F /* SignInViewModel.swift in Sources */, - C8D6714C7E0237B74676EA08 /* SignInViewController.swift in Sources */, - 0EE36E73269748A80021B746 /* DFUUIView.swift in Sources */, - A9BB94CD2540AB610042B190 /* AlertViewModel.swift in Sources */, - 0EB66B292686053800375BCC /* InfoProviderImpl.swift in Sources */, - 4F8FB6FCCB69D64B47FF440B /* ShareConfigurator.swift in Sources */, - 898D45D0BF0ABBCB2E68FBE9 /* ShareInitializer.swift in Sources */, - C9D6ACA6CB9694F6C33414CE /* ShareModuleInput.swift in Sources */, - 248444E4B7F8C3D6454D4D1B /* ShareModuleOutput.swift in Sources */, - 26BA929FDA200CCAC9964651 /* SharePresenter.swift in Sources */, - B198F488C89E6DFFD1EECAF3 /* ShareRouterInput.swift in Sources */, - 6204554EB76ED0EFDE0DC290 /* ShareRouter.swift in Sources */, - B6FA27492FB1F63393783EFC /* ShareViewInput.swift in Sources */, - 3BA1E7A8054CF95D80BAE3F9 /* ShareViewOutput.swift in Sources */, - 2BB81E4733D8EC40BECC68EF /* ShareViewModel.swift in Sources */, - B2A3FB2578B246F6CBBF0CA9 /* ShareViewController.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D2120B0C45900CDF4B6 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 0E1C1E1122B756B40032F6CA /* CardView.swift in Sources */, - A9B57445253B994700DB7353 /* SignInPresenter.swift in Sources */, - 0EA796792664B37F002BA25D /* RuuviLocalError+LocalizedError.swift in Sources */, - 66BC44A72657AED400A03253 /* OffsetCorrectionAppleViewController.swift in Sources */, - 660EB25E2669278E000FD22B /* DfuDevicesScannerPresenter.swift in Sources */, - 0EA7967D2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift in Sources */, - 0E70A46C22AF9705006CB87C /* DiscoverTableViewController.swift in Sources */, - 0EC50F5622CCE46D00172EEB /* Optional.swift in Sources */, - A9B57442253B994700DB7353 /* SignInRouter.swift in Sources */, - 660EB2732669278E000FD22B /* DfuDevicesScannerViewModel.swift in Sources */, - 66BC44A42657AED400A03253 /* OffsetCorrectionModuleInput.swift in Sources */, - 0E09672522AE897000E85F48 /* CALayer+IB.swift in Sources */, - 660EB2702669278E000FD22B /* DfuDevicesScannerTableViewController.swift in Sources */, - A92A66BD2450C640002918E7 /* UITableViewCell+ReusableView.swift in Sources */, - A93CDCDE25659BF600018C6C /* AlertPresenterImpl.swift in Sources */, - 0E8E3D60268227530082EC29 /* RuuviCoreError+LocalizedError.swift in Sources */, - 0E1C1E0F22B4049F0032F6CA /* MenuTablePresentationController.swift in Sources */, - 663155F22667F40C005B90A6 /* UpdateFirmwareViewInput.swift in Sources */, - A9646472247BAE6B0001D55D /* AdvancedTableViewController.swift in Sources */, - 0EF2863122CBB00D0026C7A5 /* TagSettingsViewInput.swift in Sources */, - 0E92A96C2686369E00187E4F /* Debouncer.swift in Sources */, - A9B57447253B994700DB7353 /* SignInModuleOutput.swift in Sources */, - 0EE36E70269748A80021B746 /* DFUViewModel.swift in Sources */, - 0E8A100E23845F8C00A9CBA6 /* DefaultsViewOutput.swift in Sources */, - 0E1C1E0022B400130032F6CA /* MenuPresenter.swift in Sources */, - 0EF6F5BE235E01170052BA25 /* ForegroundRouter.swift in Sources */, - A91D03062511207300694733 /* SelectionRouter.swift in Sources */, - 660EB26D2669278E000FD22B /* DfuDevicesScannerViewInput.swift in Sources */, - 0E1C1DF822B3FF480032F6CA /* MenuTableViewController.swift in Sources */, - 0EEB20F922B7D28C0015F9E0 /* AboutRouterInput.swift in Sources */, - 0EEB215822B8FD800015F9E0 /* WelcomeConfigurator.swift in Sources */, - 0E84BF572397F33E00A37E1A /* HeartbeatViewInput.swift in Sources */, - 0ECFF35B2350618E0061D11B /* ForegroundModuleInput.swift in Sources */, - A91D0316251124F900694733 /* SelectionItem.swift in Sources */, - 0EEB20F522B7D1A40015F9E0 /* AboutViewOutput.swift in Sources */, - A98D3F15256CBD600066588B /* ShareViewOutput.swift in Sources */, - 663155DD2667F40C005B90A6 /* UpdateFirmwareAppleInitializer.swift in Sources */, - A92E3C63242644B800D981D5 /* TagChartViewInput.swift in Sources */, - A9E5994A2557341F00F9E5CC /* ShareDescriptionTableViewCell.swift in Sources */, - A91D03092511207300694733 /* SelectionRouterInput.swift in Sources */, - 0E8FD0DD2333714C00FFA577 /* TagChartsViewModel.swift in Sources */, - A964647E247BAE6B0001D55D /* AdvancedInitializer.swift in Sources */, - A98D3F11256CBD600066588B /* ShareRouter.swift in Sources */, - 0E05012A2685FDD3007060C4 /* RuuviDFUError+LocalizedError.swift in Sources */, - 0E5C301A22CF644900B52E39 /* PermissionPresenter.swift in Sources */, - 0EE36E64269748A80021B746 /* URLSession+downloadTaskPublisher.swift in Sources */, - A976CA7E24A928C20099BDC1 /* AdvancedDisclosureTableViewCell.swift in Sources */, - 66718A3D266A685700A380F8 /* DfuFlashConfigurator.swift in Sources */, - 0E046F4F22F1827800BD4E9C /* LocationPickerRouterInput.swift in Sources */, - 0E92A95B2686366D00187E4F /* RuuviNotifierTitlesImpl.swift in Sources */, - 0E9E775A238CCE5F006D7013 /* String+Replace.swift in Sources */, - 0E197C7D23C5CD7C0074015B /* UIDevice+ReadableModel.swift in Sources */, - 663155FB2667F40C005B90A6 /* UpdateFirmwareRouter.swift in Sources */, - A90E16A024606B0500631E6C /* TagChartsInteractorInput.swift in Sources */, - 66BC44982657AED400A03253 /* OffsetCorrectionAppleInitializer.swift in Sources */, - 0E84BF592397F3C600A37E1A /* HeartbeatViewModel.swift in Sources */, - 663155FE2667F40C005B90A6 /* UpdateFirmwareRouterInput.swift in Sources */, - 0E8FD0D323336B4200FFA577 /* TagChartsTransitioningDelegate.swift in Sources */, - 0EE36E6A269748A80021B746 /* LargeButtonStyle.swift in Sources */, - 0E046F3222F057DD00BD4E9C /* WebTagSettingsRouter.swift in Sources */, - 66718A3A266A685700A380F8 /* DfuFlashAppleInitializer.swift in Sources */, - 0E8A101A2384615400A9CBA6 /* DefaultsPresenter.swift in Sources */, - A9B57446253B994700DB7353 /* SignInModuleInput.swift in Sources */, - A91D02F72511207300694733 /* SelectionModuleInput.swift in Sources */, - 0EEB214722B8FC3E0015F9E0 /* WelcomeViewInput.swift in Sources */, - A9BB94CC2540AB610042B190 /* AlertViewModel.swift in Sources */, - 0ECFF355235056DC0061D11B /* ForegroundList.swift in Sources */, - 0EEB20E322B7C8C10015F9E0 /* SettingsPresenter.swift in Sources */, - 0EBAF0802320089A0025A191 /* LanguageTableConfigurator.swift in Sources */, - 0E197C6B23C4A52A0074015B /* MailComposerPresenterMessageUI.swift in Sources */, - 663155E92667F40C005B90A6 /* UpdateFirmwareModuleInput.swift in Sources */, - 0E197C6623C4A47A0074015B /* MailComposerPresenter.swift in Sources */, - 66718A55266A685700A380F8 /* DfuFlashViewOutput.swift in Sources */, - 0E1C1E0B22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift in Sources */, - 0E046F2922F0561B00BD4E9C /* WebTagSettingsViewInput.swift in Sources */, - 0E8E3D6C268228130082EC29 /* DiscoverVirtualTagViewModel.swift in Sources */, - A907A1D72460376600041F6E /* TagChartViewModel.swift in Sources */, - 0EEB214C22B8FCC70015F9E0 /* WelcomeRouterInput.swift in Sources */, - 0EEB20CD22B7BD6C0015F9E0 /* MenuModuleOutput.swift in Sources */, - 0E70A46322AF959E006CB87C /* Localizable.swift in Sources */, - 66BC44B02657AED400A03253 /* OffsetCorrectionViewOutput.swift in Sources */, - 0E197C6123C352380074015B /* TagSettingsAlertDescriptionCell.swift in Sources */, - 0E046F5822F182F500BD4E9C /* LocationPickerAppleInitializer.swift in Sources */, - 0E8FD0CD2333672F00FFA577 /* TagChartsPresenter.swift in Sources */, - A9E599582557345200F9E5CC /* ShareEmailInputTableViewCell.swift in Sources */, - A90E16A424606B2000631E6C /* TagChartsInteractorOutput.swift in Sources */, - A91D02F12511207200694733 /* SelectionTableInitializer.swift in Sources */, - 0E8A10222384637F00A9CBA6 /* DefaultsList.swift in Sources */, - 0EEB215322B8FD1F0015F9E0 /* WelcomePresenter.swift in Sources */, - 0E1C1DD522B3BF3A0032F6CA /* CardsViewOutput.swift in Sources */, - 0E92A9692686369200187E4F /* DateValueFormatter.swift in Sources */, - 66718A46266A685700A380F8 /* DfuFlashPresenter.swift in Sources */, - 0E8A102523846CEB00A9CBA6 /* DefaultsSwitchTableViewCell.swift in Sources */, - 0E8A100C23845F7100A9CBA6 /* DefaultsViewInput.swift in Sources */, - 66718A6C266BD0E800A380F8 /* Color+Ruuvi.swift in Sources */, - 0E046F5122F1828900BD4E9C /* LocationPickerRouter.swift in Sources */, - 0E046F3422F057FC00BD4E9C /* WebTagSettingsModuleInput.swift in Sources */, - 660EB29C266928E6000FD22B /* UIViewController+Alert.swift in Sources */, - 66718A4C266A685700A380F8 /* DfuLogTableViewCell.swift in Sources */, - 0E1C1E0522B400890032F6CA /* MenuTableConfigurator.swift in Sources */, - 0E2AFFA0266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift in Sources */, - 0E8BD2AB23851CF2008B31EF /* DefaultsStepperTableViewCell.swift in Sources */, - 0EEB20DF22B7C8790015F9E0 /* SettingsRouter.swift in Sources */, - A9B5743F253B993100DB7353 /* SignInConfigurator.swift in Sources */, - 660EB25B2669278E000FD22B /* DfuDevicesScannerInitializer.swift in Sources */, - 0EA92FDB2387E734008F1558 /* TagSettingsAlertsHeaderFooterView.swift in Sources */, - 0EE49B9923B877CF003012C2 /* WebTagSettingsAlertControlsCell.swift in Sources */, - 0E53DA6722CC964200BC6D64 /* SwipeDownToDismissNavigationController.swift in Sources */, - A9B57448253B994700DB7353 /* SignInViewModel.swift in Sources */, - 0EB66B262686053800375BCC /* FeatureToggle.swift in Sources */, - A9B57444253B994700DB7353 /* SignInViewController.swift in Sources */, - 0E8A10162384612300A9CBA6 /* DefaultsRouterInput.swift in Sources */, - 0EA796712664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift in Sources */, - 0EEB20FF22B7D2DD0015F9E0 /* AboutPresenter.swift in Sources */, - 0E8FD0D523336BA300FFA577 /* TagChartsPresentTransitionAnimation.swift in Sources */, - 0E84BF612397F73100A37E1A /* HeartbeatEnvironmentObject.swift in Sources */, - A964648A247BAE6B0001D55D /* AdvancedRouter.swift in Sources */, - 0EC50F5222CCB9DE00172EEB /* TagSettingsViewModel.swift in Sources */, - 0EA796852664B84D002BA25D /* RuuviReactorError+LocalizedError.swift in Sources */, - 0E1C1DDF22B3C2330032F6CA /* CardsPresenter.swift in Sources */, - 0E3FF7372381591800EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.swift in Sources */, - 0EC50F5022CCB92000172EEB /* Observable.swift in Sources */, - A9BD38BA24F6108300904BBE /* Humidity+Offset.swift in Sources */, - 0EF6F5C2235E02000052BA25 /* ForegroundTableViewController.swift in Sources */, - 0EF2863322CBB0250026C7A5 /* TagSettingsViewOutput.swift in Sources */, - 0E0501282685FDD3007060C4 /* RuuviDaemonError+LocalizedError.swift in Sources */, - 0ECFF37023507CE80061D11B /* ForegroundViewModel.swift in Sources */, - 0EEB20C622B7915C0015F9E0 /* CardsViewModel.swift in Sources */, - 0EB66B1A2686053800375BCC /* FallbackFeatureToggleProvider.swift in Sources */, - A98D3F13256CBD600066588B /* SharePresenter.swift in Sources */, - 0EE36E66269748A80021B746 /* View+Any.swift in Sources */, - 0E1C1DBB22B3919F0032F6CA /* UIApplication+ViewController.swift in Sources */, - 0E046F3D22F05B0900BD4E9C /* WebTagSettingsTableConfigurator.swift in Sources */, - A9E599612557346600F9E5CC /* ShareSendButtonTableViewCell.swift in Sources */, - 0E62AEC922E065CC00A49BFB /* TagSettingsMoreInfoHeaderFooterView.swift in Sources */, - A98D3F0E256CBD600066588B /* ShareRouterInput.swift in Sources */, - 0E5C301C22CF646B00B52E39 /* PermissionPresenterAlert.swift in Sources */, - 0EEB213C22B8FAD50015F9E0 /* MainRouter.swift in Sources */, - 0E8FD0C123335D8400FFA577 /* TagChartsScrollViewController.swift in Sources */, - 0E5C300B22CF629100B52E39 /* PhotoPickerPresenterSheet.swift in Sources */, - 0EEB210322B7D3220015F9E0 /* AboutConfigurator.swift in Sources */, - 0EEB20F322B7D1900015F9E0 /* AboutViewInput.swift in Sources */, - 0E8FD0C323335DA700FFA577 /* TagChartsViewInput.swift in Sources */, - 0EBAF072232007910025A191 /* LanguageTableViewController.swift in Sources */, - A964646C247BAE6B0001D55D /* AdvancedStepperTableViewCell.swift in Sources */, - 0E8A100A23845F3900A9CBA6 /* DefaultsViewController.swift in Sources */, - 0E84BF712398035C00A37E1A /* HeartbeatConfigurator.swift in Sources */, - 0E92A9662686368000187E4F /* RUError.swift in Sources */, - 0E79F28B244328D50048BF86 /* DiscoverAddWithMACTableViewCell.swift in Sources */, - 66718A40266A685700A380F8 /* DfuFlashModuleInput.swift in Sources */, - A91D02EE2511207200694733 /* SelectionTableConfigurator.swift in Sources */, - 66BC44B32657AED400A03253 /* OffsetCorrectionRouter.swift in Sources */, - 0E8A101023845FAE00A9CBA6 /* DefaultsViewModel.swift in Sources */, - 0E8FD0D12333679800FFA577 /* TagChartsScrollConfigurator.swift in Sources */, - 660EB26A2669278E000FD22B /* DfuDeviceTableViewCell.swift in Sources */, - 0EBAF070232007740025A191 /* LanguageViewOutput.swift in Sources */, - 0E8A101E238461D400A9CBA6 /* DefaultsConfigurator.swift in Sources */, - 66BC449B2657AED400A03253 /* OffsetCorrectionConfigurator.swift in Sources */, - 0E1C1DFC22B3FFD90032F6CA /* MenuRouter.swift in Sources */, - 0ECFF36823507A1A0061D11B /* ForegroundRouterInput.swift in Sources */, - 0EA796812664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift in Sources */, - 0EA7968D2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift in Sources */, - 0EE36E78269748A80021B746 /* LatestRelease.swift in Sources */, - 0E8A101C2384618700A9CBA6 /* DefaultsInitializer.swift in Sources */, - A9E5996A255734A000F9E5CC /* ShareEmailTableViewCell.swift in Sources */, - 0EEB214222B8FBA50015F9E0 /* MainInitializer.swift in Sources */, - 663155E02667F40C005B90A6 /* UpdateFirmwareConfigurator.swift in Sources */, - 0E9D5F202351BE3C0076FFD8 /* ForegroundSwitchTableViewCell.swift in Sources */, - 0EE36E6C269748A80021B746 /* ProgressBar.swift in Sources */, - 0E1C1E0322B400590032F6CA /* MenuTableInitializer.swift in Sources */, - 0E046F4A22F1820400BD4E9C /* LocationPickerViewOutput.swift in Sources */, - 66BC44B62657AED400A03253 /* OffsetCorrectionRouterInput.swift in Sources */, - 0E62297C26A7F84F0041DCDD /* AppRouter.swift in Sources */, - 0EE49B9523B74775003012C2 /* WebTagSettingsAlertHeaderCell.swift in Sources */, - 0EB66B282686053800375BCC /* InfoProviderImpl.swift in Sources */, - 0EE36E74269748A80021B746 /* DFUInteractorInput.swift in Sources */, - 0E046F2E22F0569000BD4E9C /* WebTagSettingsTableViewController.swift in Sources */, - 0EEB214E22B8FCDC0015F9E0 /* WelcomeRouter.swift in Sources */, - A93CDCCF25659BA600018C6C /* AlertPresenter.swift in Sources */, - 66718A43266A685700A380F8 /* DfuFlashModuleOutput.swift in Sources */, - 663155EC2667F40C005B90A6 /* UpdateFirmwareAppleViewController.swift in Sources */, - A9646487247BAE6B0001D55D /* AdvancedRouterInput.swift in Sources */, - 0EB66B242686053800375BCC /* FeatureToggleService.swift in Sources */, - A93CDCAB25657C1D00018C6C /* MenuViewModel.swift in Sources */, - 0EF2863722CBB04E0026C7A5 /* TagSettingsRouter.swift in Sources */, - 0E09672C22AE94F000E85F48 /* DiscoverDeviceTableViewCell.swift in Sources */, - 0EEB210122B7D2F50015F9E0 /* AboutInitializer.swift in Sources */, - 66718A65266A6CA700A380F8 /* DfuFilePickerPresenter.swift in Sources */, - 660EB2642669278E000FD22B /* DfuDevicesScannerModuleOutput.swift in Sources */, - 0E92A9572686366D00187E4F /* ExportHeadersProvider.swift in Sources */, - A92E3C5A2426415100D981D5 /* TagChartView.swift in Sources */, - 0EB66B1E2686053800375BCC /* LocalFeatureToggleProvider.swift in Sources */, - 0EE5B47D23508F6D00D5ED32 /* ForegroundEnvironmentObject.swift in Sources */, - 0EEB20CB22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift in Sources */, - 0EB66B222686053800375BCC /* RemoteConfigService.swift in Sources */, - 663155E62667F40C005B90A6 /* UpdateFirmwareModuleOutput.swift in Sources */, - A98D3F06256CBD410066588B /* ShareModuleInput.swift in Sources */, - A949A83B24707FD0006B7F4F /* LocalizedCache.swift in Sources */, - 0E8FD0D723336C6E00FFA577 /* TagChartsDismissTransitionAnimation.swift in Sources */, - 0E84BF5F2397F6BE00A37E1A /* HeartbeatViewController.swift in Sources */, - 0E84BF67239801AF00A37E1A /* HeartbeatRouterInput.swift in Sources */, - 0EF5B72B22D62CD900D9D14A /* Date+Ruuvi.swift in Sources */, - 0EE36E7A269748A80021B746 /* DFUModuleFactory.swift in Sources */, - 66718A5E266A685700A380F8 /* DfuFlashRouterInput.swift in Sources */, - A98D3F0F256CBD600066588B /* ShareViewInput.swift in Sources */, - 0E050172268603CE007060C4 /* UniversalLinkCoordinator.swift in Sources */, - 0ECB5A8E2381807500E78757 /* CardsScrollViewController.swift in Sources */, - 0E8E3D62268227530082EC29 /* RuuviVirtualError+LocalizedError.swift in Sources */, - 0EE36E72269748A80021B746 /* DFUUIView.swift in Sources */, - 0E92A9612686366D00187E4F /* Language+Localization.swift in Sources */, - 0EBAF07B232008420025A191 /* LanguagePresenter.swift in Sources */, - A980573825807118000D03AB /* AboutViewModel.swift in Sources */, - 663155EF2667F40C005B90A6 /* UpdateFirmwareViewOutput.swift in Sources */, - 0EB66B1C2686053800375BCC /* FirebaseFeatureToggleProvider.swift in Sources */, - 660EB2582669278E000FD22B /* DfuDevicesScannerConfigurator.swift in Sources */, - A9A67BFA24C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift in Sources */, - 660EB2612669278E000FD22B /* DfuDevicesScannerModuleInput.swift in Sources */, - 0E92A9552686366D00187E4F /* TemperatureUnit+Localization.swift in Sources */, - 0E84BF4D239795B000A37E1A /* DiscoverModuleOutput.swift in Sources */, - A9646478247BAE6B0001D55D /* AdvancedViewModel.swift in Sources */, - A9B57441253B994700DB7353 /* SignInRouterInput.swift in Sources */, - A9646484247BAE6B0001D55D /* AdvancedPresenter.swift in Sources */, - 0EF2862E22CBAFC80026C7A5 /* TagSettingsTableViewController.swift in Sources */, - 0E046F5322F182AB00BD4E9C /* LocationPickerModuleInput.swift in Sources */, - A90E16972460504C00631E6C /* TagChartModuleOutput.swift in Sources */, - A91D031A25113EAA00694733 /* UnitPressure+Extension.swift in Sources */, - 0EEB20D322B7C7AC0015F9E0 /* SettingsTableViewController.swift in Sources */, - 0E53DA6222CC93EB00BC6D64 /* SwipeDownToDismissTransitionAnimation.swift in Sources */, - 0E05016E268603CE007060C4 /* AppStateService.swift in Sources */, - A98BC875250E4265001CEFDC /* Double+Round.swift in Sources */, - A9646481247BAE6B0001D55D /* AdvancedModuleInput.swift in Sources */, - 0E84BF6F2398031B00A37E1A /* HeartbeatInitializer.swift in Sources */, - A9E6774825A33081000B75A3 /* String+Characters.swift in Sources */, - 0EEB20DD22B7C8650015F9E0 /* SettingsRouterInput.swift in Sources */, - 0EB66B2A2686053800375BCC /* InfoProvider.swift in Sources */, - 0EF6F5C0235E01CD0052BA25 /* ForegroundStepperTableViewCell.swift in Sources */, - 0EEB215A22BA28860015F9E0 /* MenuTableTransitionManager.swift in Sources */, - A91D02FD2511207300694733 /* SelectionTableViewCell.swift in Sources */, - 0E8FD0C523335DBF00FFA577 /* TagChartsViewOutput.swift in Sources */, - 0E8A10142384610400A9CBA6 /* DefaultsRouter.swift in Sources */, - 0ECFF36023506BD60061D11B /* ForegroundViewInput.swift in Sources */, - 0E046F3022F057CC00BD4E9C /* WebTagSettingsRouterInput.swift in Sources */, - 0E9D0AB1231EBEFD00C6BDA7 /* LocalizationService.swift in Sources */, - 0E02ABBA237598C600ED4629 /* RURangeSeekSlider.swift in Sources */, - 0EA796892664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift in Sources */, - 660EB27C2669278E000FD22B /* DfuDevicesScannerRouterInput.swift in Sources */, - 0E1C1DDD22B3C2160032F6CA /* CardsModuleInput.swift in Sources */, - A91D02FA2511207300694733 /* SelectionViewInput.swift in Sources */, - 663155E32667F40C005B90A6 /* UpdateFirmwarePresenter.swift in Sources */, - A98D3F0C256CBD600066588B /* ShareConfigurator.swift in Sources */, - 0EBAF075232007CC0025A191 /* LanguageRouterInput.swift in Sources */, - 0ECFF35E23506BC40061D11B /* ForegroundViewOutput.swift in Sources */, - 0EBAF079232008140025A191 /* LanguageModuleInput.swift in Sources */, - 66BC44AA2657AED400A03253 /* OffsetCorrectionViewInput.swift in Sources */, - 0E1B2F36239DF0120060C469 /* TagSettingsAlertControlsCell.swift in Sources */, - 0E1C1DBE22B3921E0032F6CA /* PresentationAssembly.swift in Sources */, - A90E16A92460975600631E6C /* TagChartAssembler.swift in Sources */, - 0E9F979622EAFC820015ADE2 /* DiscoverWebTagTableViewCell.swift in Sources */, - 0EEB20FD22B7D2C90015F9E0 /* AboutModuleInput.swift in Sources */, - 0EEB214922B8FC570015F9E0 /* WelcomeViewOutput.swift in Sources */, - A9B57443253B994700DB7353 /* SignInViewInput.swift in Sources */, - 0EEB213F22B8FB840015F9E0 /* MainNavigationDelegate.swift in Sources */, - 0EF4E34F268319A400D83CC7 /* DfuFirmware+Log.swift in Sources */, - A9B57449253B994700DB7353 /* SignInInitializer.swift in Sources */, - 0E046F3B22F05AA800BD4E9C /* WebTagSettingsTableInitializer.swift in Sources */, - 0E1C1DFA22B3FFBF0032F6CA /* MenuRouterInput.swift in Sources */, - 0EBAF077232007D80025A191 /* LanguageRouter.swift in Sources */, - 66BC44AD2657AED400A03253 /* OffsetCorrectionViewModel.swift in Sources */, - 0E8FD0CB2333671100FFA577 /* TagChartsModuleInput.swift in Sources */, - 0EE36E5E269748A80021B746 /* DFUModuleInput.swift in Sources */, - 0E02ABCB2379483A00ED4629 /* Double+Temperature.swift in Sources */, - 66718A49266A685700A380F8 /* DfuFlashAppleViewController.swift in Sources */, - 0EE98A7926493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift in Sources */, - 0E1C1DAF22B38F780032F6CA /* ActivityPresenter.swift in Sources */, - 660EB2762669278E000FD22B /* DfuDevicesScannerViewOutput.swift in Sources */, - 0E1C1DF522B3FF1D0032F6CA /* MenuViewOutput.swift in Sources */, - 0E70A46E22AF9763006CB87C /* DiscoverViewInput.swift in Sources */, - 0E046F4D22F1823C00BD4E9C /* LocationPickerAppleViewController.swift in Sources */, - 0EF2864222CBB13F0026C7A5 /* TagSettingsTableConfigurator.swift in Sources */, - 66718A4F266A685700A380F8 /* DfuFlashViewModel.swift in Sources */, - 0E53DA6022CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift in Sources */, - 0E1C1DF322B3FEFF0032F6CA /* MenuViewInput.swift in Sources */, - 0E1C1DB922B390ED0032F6CA /* ActivitySpinnerView.swift in Sources */, - 66BC44A12657AED400A03253 /* OffsetCorrectionPresenter.swift in Sources */, - 0E1C1DB322B390080032F6CA /* ActivityPresenterRuuviLogo.swift in Sources */, - 0EEB20F722B7D2090015F9E0 /* AboutViewController.swift in Sources */, - 0E502FBE22B2817900E8A6CC /* DiscoverRouterInput.swift in Sources */, - 0E8A10202384633200A9CBA6 /* DefaultsEnvironmentObject.swift in Sources */, - A98D3F14256CBD600066588B /* ShareModuleOutput.swift in Sources */, - A98D3F10256CBD600066588B /* ShareViewModel.swift in Sources */, - 0E70A46022AF9567006CB87C /* ViewInput.swift in Sources */, - 0E0A381923616AC3003A0364 /* UserDefaults+Optional.swift in Sources */, - 0E8FD0C7233366DC00FFA577 /* TagChartsRouterInput.swift in Sources */, - 0E1C1DD322B3BF180032F6CA /* CardsViewInput.swift in Sources */, - 0E70A47522AF9978006CB87C /* DiscoverPresenter.swift in Sources */, - 0EBAF06E232007510025A191 /* LanguageViewInput.swift in Sources */, - 0EEB20FB22B7D2990015F9E0 /* AboutRouter.swift in Sources */, - 0E84BF6D239802CA00A37E1A /* HeartbeatPresenter.swift in Sources */, - 0E8FD0C9233366F000FFA577 /* TagChartsRouter.swift in Sources */, - 0E70A47B22AF9BE2006CB87C /* DiscoverTableInitializer.swift in Sources */, - 0E70A47022AF9790006CB87C /* DiscoverViewOutput.swift in Sources */, - 0E050174268603CE007060C4 /* UniversalLinkRouterImpl.swift in Sources */, - 0E502FC022B2819B00E8A6CC /* DiscoverRouter.swift in Sources */, - 66718A68266A6CA700A380F8 /* DfuFilePickerPresenterSheet.swift in Sources */, - 0EEB215122B8FD070015F9E0 /* WelcomeModuleInput.swift in Sources */, - 0E050170268603CE007060C4 /* UniversalLinkCoordinatormpl.swift in Sources */, - 0EC50F5922CF621000172EEB /* PhotoPickerPresenter.swift in Sources */, - A93052B8242BFCC000FB62B1 /* TagChartViewOutput.swift in Sources */, - 0E046F5522F182BF00BD4E9C /* LocationPickerPresenter.swift in Sources */, - 0E8A10182384613E00A9CBA6 /* DefaultsModuleInput.swift in Sources */, - 0EE36E60269748A80021B746 /* DFUPresenter.swift in Sources */, - 66BC449E2657AED400A03253 /* OffsetCorrectionModuleOutput.swift in Sources */, - 0EF2863B22CBB08C0026C7A5 /* TagSettingsPresenter.swift in Sources */, - 0E8FD0E32333893600FFA577 /* TagChartsModuleOutput.swift in Sources */, - A91D03032511207300694733 /* SelectionViewOutput.swift in Sources */, - 0E53DA6422CC943900BC6D64 /* SwipeDownToDismissInteractiveTransition.swift in Sources */, - 0E050176268603CE007060C4 /* UniversalLinkRouter.swift in Sources */, - 0EF2863522CBB03A0026C7A5 /* TagSettingsRouterInput.swift in Sources */, - 0EC50F5422CCBBE800172EEB /* NSObject+Observable.swift in Sources */, - 0EF2863922CBB06C0026C7A5 /* TagSettingsModuleInput.swift in Sources */, - 0E046F5A22F1832600BD4E9C /* LocationPickerAppleConfigurator.swift in Sources */, - 0E1C1DA822B387A00032F6CA /* AppAssembly.swift in Sources */, - 0E1C1E0D22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift in Sources */, - 0E70A47322AF9953006CB87C /* DiscoverModuleInput.swift in Sources */, - 0E84BF69239801C100A37E1A /* HeartbeatRouter.swift in Sources */, - 0EEB20E822B7C92C0015F9E0 /* SettingsTableConfigurator.swift in Sources */, - 0E8E3D6A268228130082EC29 /* DiscoverRuuviTagViewModel.swift in Sources */, - 0EBAF07E2320086A0025A191 /* LanguageTableInitializer.swift in Sources */, - 0EE36E5C269748A80021B746 /* FirmwareRepository.swift in Sources */, - 0E046F6222F193B300BD4E9C /* LocationPickerModuleOutput.swift in Sources */, - A964647B247BAE6B0001D55D /* AdvancedConfigurator.swift in Sources */, - 0E70A47D22AF9BFE006CB87C /* DiscoverTableConfigurator.swift in Sources */, - 0EE36E62269748A80021B746 /* Publishers+System.swift in Sources */, - 0E046F4822F181DA00BD4E9C /* LocationPickerViewInput.swift in Sources */, - 0EEB20E622B7C8F20015F9E0 /* SettingsTableInitializer.swift in Sources */, - 0E341BBD2372E75C0085BB54 /* TagChartsTransitionManager.swift in Sources */, - 0E1C1DB722B390BC0032F6CA /* ActivityRuuviLogoViewController.swift in Sources */, - 0E8FD0CF2333676C00FFA577 /* TagChartsScrollInitializer.swift in Sources */, - 0ECFF36E23507BF00061D11B /* ForegroundConfigurator.swift in Sources */, - A90E169C24606ABF00631E6C /* TagChartsInteractor.swift in Sources */, - 0EB66B182686053800375BCC /* FeatureToggleProvider.swift in Sources */, - A907BB1124AE620A009DA3DB /* UIWindow+Orientation.swift in Sources */, - 64333D2920B0C45900CDF4B6 /* AppDelegate.swift in Sources */, - 0EF2864022CBB1340026C7A5 /* TagSettingsTableInitializer.swift in Sources */, - 0EA796752664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift in Sources */, - 0E046F3F22F0702D00BD4E9C /* WebTagSettingsViewModel.swift in Sources */, - 66718A5B266A685700A380F8 /* DfuFlashRouter.swift in Sources */, - 0EEB214422B8FBC50015F9E0 /* MainConfigurator.swift in Sources */, - 0E046F3622F0581E00BD4E9C /* WebTagSettingsPresenter.swift in Sources */, - 0E92A95D2686366D00187E4F /* MeasurementType.swift in Sources */, - 0E1C1DFE22B3FFFC0032F6CA /* MenuModuleInput.swift in Sources */, - 0E1C1DE822B3C2B60032F6CA /* CardsScrollInitializer.swift in Sources */, - 0E8A10122384605A00A9CBA6 /* DefaultsTableViewController.swift in Sources */, - 0E1C1E0922B4024E0032F6CA /* MenuTableTransitioningDelegate.swift in Sources */, - 660EB2672669278E000FD22B /* DfuNoDeviceTableViewCell.swift in Sources */, - 0E1C1DC122B3955E0032F6CA /* ErrorPresenter.swift in Sources */, - 0EBAF08223200B1B0025A191 /* LanguageTableViewCell.swift in Sources */, - A98D3F12256CBD600066588B /* ShareViewController.swift in Sources */, - 0ECFF36223506C050061D11B /* ForegroundRow.swift in Sources */, - 0E62297A26A7F84F0041DCDD /* OnboardRouter.swift in Sources */, - 0EEB20D822B7C8060015F9E0 /* SettingsViewOutput.swift in Sources */, - 0E31B04223BBA37C00660412 /* WebTagSettingsAlertsHeaderFooterView.swift in Sources */, - 0E92A95F2686366D00187E4F /* HumidityUnit+Localization.swift in Sources */, - A91D0311251123B400694733 /* SelectionModuleOutput.swift in Sources */, - 0ECFF366235079F50061D11B /* ForegroundPresenter.swift in Sources */, - 0E53A3FB232F4D5000ACED49 /* DiscoverNoDevicesTableViewCell.swift in Sources */, - 66718A52266A685700A380F8 /* DfuFlashViewInput.swift in Sources */, - 660EB27F2669278E000FD22B /* DfuDevicesScannerRouter.swift in Sources */, - 0EEB20E122B7C8A90015F9E0 /* SettingsModuleInput.swift in Sources */, - A9B5744A253B994700DB7353 /* SignInViewOutput.swift in Sources */, - 0E1C1DEA22B3C2E60032F6CA /* CardsScrollConfigurator.swift in Sources */, - 0EB66B202686053800375BCC /* FirebaseRemoteConfigService.swift in Sources */, - 0E84BF652397F9DC00A37E1A /* HeartbeatTableViewController.swift in Sources */, - 0E046F2B22F0563100BD4E9C /* WebTagSettingsViewOutput.swift in Sources */, - 0E1C1DE422B3C2710032F6CA /* CardsRouter.swift in Sources */, - 0E05016C268603CE007060C4 /* AppStateServiceImpl.swift in Sources */, - 0E09672222AE7FCF00E85F48 /* WelcomeViewController.swift in Sources */, - 0E92A9592686366D00187E4F /* HeartbeatDaemonTitles.swift in Sources */, - 0E1C1DE222B3C25F0032F6CA /* CardsRouterInput.swift in Sources */, - 0EEB215622B8FD590015F9E0 /* WelcomeInitializer.swift in Sources */, - A9646466247BAE6B0001D55D /* AdvancedViewInput.swift in Sources */, - 0EE36E6E269748A80021B746 /* Feedback.swift in Sources */, - 0E84BF5B2397F3DF00A37E1A /* HeartbeatViewOutput.swift in Sources */, - 0EEB20D622B7C7E70015F9E0 /* SettingsViewInput.swift in Sources */, - 0E050179268603DD007060C4 /* ChartFilterOperation.swift in Sources */, - 0E1B2F32239DEF120060C469 /* TagSettingsAlertHeaderCell.swift in Sources */, - A90E168F24604F7400631E6C /* TagChartPresenter.swift in Sources */, - A9F4471624B79959001E63AF /* TagSettingsModuleOutput.swift in Sources */, - A907A1D3245F7C6600041F6E /* ProgressBarView.swift in Sources */, - 0E211C2A234C5FE900FC37B0 /* CardsRouterDelegate.swift in Sources */, - 0E84BF6B239802A400A37E1A /* HeartbeatModuleInput.swift in Sources */, - A90E169324604FD100631E6C /* TagChartModuleInput.swift in Sources */, - 0E92A9632686366D00187E4F /* VirtualLocation+Localization.swift in Sources */, - A9646475247BAE6B0001D55D /* AdvancedViewOutput.swift in Sources */, - 0E1C1DC422B395C00032F6CA /* ErrorPresenterAlert.swift in Sources */, - 0EE36E7E269749280021B746 /* RuuviColor.swift in Sources */, - 0ECFF359235060EF0061D11B /* ForegroundViewController.swift in Sources */, - A91D03002511207300694733 /* SelectionTableViewController.swift in Sources */, - 0EE36E76269748A80021B746 /* DFUInteractor.swift in Sources */, - 0ECFF36C23507BC00061D11B /* ForegroundInitializer.swift in Sources */, - A964646F247BAE6B0001D55D /* AdvancedSwitchTableViewCell.swift in Sources */, - A98D3F0D256CBD600066588B /* ShareInitializer.swift in Sources */, - 0E84BF632397F76A00A37E1A /* HeartbeatList.swift in Sources */, - 0EE36E68269748A80021B746 /* Spinner.swift in Sources */, - A91D02F42511207300694733 /* SelectionPresenter.swift in Sources */, - 0E290A852660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D3520B0C45A00CDF4B6 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - A9E6775125A331D6000B75A3 /* MeasurementsServiceEnSpec.swift in Sources */, - A94FFD4C241D512900888017 /* MockLocalNotificationsManager.swift in Sources */, - A935E47625A49E8F009538C4 /* MeasurementsServiceFiSpec.swift in Sources */, - A94FFD48241C34EA00888017 /* MockAlertPersistence.swift in Sources */, - A94FFD4A241D45C600888017 /* MockRuuviTag.swift in Sources */, - A9E6775C25A331E1000B75A3 /* MeasurementsServiceSvSpec.swift in Sources */, - A935E47D25A49E9E009538C4 /* MeasurementsServiceRuSpec.swift in Sources */, - A94FFD50241D6BA300888017 /* MockAlertServiceObserver.swift in Sources */, - A9E6774B25A33081000B75A3 /* String+Characters.swift in Sources */, - A971B0DC24215334008EF50D /* XCTest+Extension.swift in Sources */, - A94FFD4E241D57E700888017 /* MockCalibrationService.swift in Sources */, - 64333D3E20B0C45A00CDF4B6 /* StationTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D4020B0C45B00CDF4B6 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 0E6C471723D305960016B46E /* StationUITests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 64333D3B20B0C45A00CDF4B6 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 64333D2420B0C45900CDF4B6 /* station */; - targetProxy = 64333D3A20B0C45A00CDF4B6 /* PBXContainerItemProxy */; - }; - 64333D4620B0C45B00CDF4B6 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 64333D2420B0C45900CDF4B6 /* station */; - targetProxy = 64333D4520B0C45B00CDF4B6 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 0E53A3F3232DFC6200ACED49 /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 0E53A3F2232DFC6200ACED49 /* en */, - 0E53A3F4232DFC6400ACED49 /* ru */, - 0E53A3F5232DFC6500ACED49 /* fi */, - 64A2DAE324310B2900DE6699 /* sv */, - 310159B92644864C00A5E8E8 /* fr */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; - 0EEB20C922B7A7200015F9E0 /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 0EEB20C822B7A7200015F9E0 /* en */, - 0E9D0AAF231E9BD800C6BDA7 /* ru */, - 0EBAF0832320120F0025A191 /* fi */, - 64A2DAE224310B2900DE6699 /* sv */, - 310159B82644864400A5E8E8 /* fr */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - 64333D2C20B0C45900CDF4B6 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 64333D2D20B0C45900CDF4B6 /* Base */, - 310159B7264484D700A5E8E8 /* fr */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 64333D3120B0C45A00CDF4B6 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 64333D3220B0C45A00CDF4B6 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 0E8BD402238566AB008B31EF /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = station/station.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - INFOPLIST_FILE = "$(SRCROOT)/station/Resources/Plists/DevInfo.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 0.7.2; - OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D DEVELOPMENT"; - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.station; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 0E8BD403238566AB008B31EF /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = station/station.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - INFOPLIST_FILE = "$(SRCROOT)/station/Resources/Plists/DevInfo.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 0.7.2; - OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS"; - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.station; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 64333D4B20B0C45B00CDF4B6 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 64333D4C20B0C45B00CDF4B6 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 64333D4E20B0C45B00CDF4B6 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = station/station.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - FRAMEWORK_SEARCH_PATHS = "$(inherited)"; - INFOPLIST_FILE = "$(SRCROOT)/station/Resources/Plists/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 0.7.2; - OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS"; - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.station; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 64333D4F20B0C45B00CDF4B6 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = station/station.entitlements; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - INFOPLIST_FILE = "$(SRCROOT)/station/Resources/Plists/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 0.7.2; - OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS"; - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.station; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 64333D5120B0C45B00CDF4B6 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - INFOPLIST_FILE = stationTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.stationTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/station.app/station"; - }; - name = Debug; - }; - 64333D5220B0C45B00CDF4B6 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - INFOPLIST_FILE = stationTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.stationTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/station.app/station"; - }; - name = Release; - }; - 64333D5420B0C45B00CDF4B6 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - INFOPLIST_FILE = stationUITests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.stationUITests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_TARGET_NAME = station; - }; - name = Debug; - }; - 64333D5520B0C45B00CDF4B6 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - INFOPLIST_FILE = stationUITests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.stationUITests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_TARGET_NAME = station; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 0E8BD401238566AB008B31EF /* Build configuration list for PBXNativeTarget "station_dev" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 0E8BD402238566AB008B31EF /* Debug */, - 0E8BD403238566AB008B31EF /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 64333D2020B0C45900CDF4B6 /* Build configuration list for PBXProject "iOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 64333D4B20B0C45B00CDF4B6 /* Debug */, - 64333D4C20B0C45B00CDF4B6 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 64333D4D20B0C45B00CDF4B6 /* Build configuration list for PBXNativeTarget "station" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 64333D4E20B0C45B00CDF4B6 /* Debug */, - 64333D4F20B0C45B00CDF4B6 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 64333D5020B0C45B00CDF4B6 /* Build configuration list for PBXNativeTarget "stationTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 64333D5120B0C45B00CDF4B6 /* Debug */, - 64333D5220B0C45B00CDF4B6 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 64333D5320B0C45B00CDF4B6 /* Build configuration list for PBXNativeTarget "stationUITests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 64333D5420B0C45B00CDF4B6 /* Debug */, - 64333D5520B0C45B00CDF4B6 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - 0E11D13B267DFA08002D0686 /* XCRemoteSwiftPackageReference "Localize-Swift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/marmelroy/Localize-Swift"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 3.2.0; - }; - }; - 0E11D1E6267DFF2F002D0686 /* XCRemoteSwiftPackageReference "LightRoute" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/rinat-enikeev/LightRoute"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.2.2; - }; - }; - 0E11D1EB267E0010002D0686 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "http://github.com/firebase/firebase-ios-sdk"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 8.2.0; - }; - }; - 0E11D1F8267E008D002D0686 /* XCRemoteSwiftPackageReference "Swinject" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/Swinject/Swinject"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.7.1; - }; - }; - 0E11D1FD267E02BC002D0686 /* XCRemoteSwiftPackageReference "RangeSeekSlider" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/rinat-enikeev/RangeSeekSlider"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.8.2; - }; - }; - 0E11D202267E0336002D0686 /* XCRemoteSwiftPackageReference "GestureInstructions" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/rinat-enikeev/GestureInstructions"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 0.0.2; - }; - }; - 0E11D207267E0379002D0686 /* XCRemoteSwiftPackageReference "SwinjectPropertyLoader" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/rinat-enikeev/SwinjectPropertyLoader"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.0.2; - }; - }; - 0E11D20C267E0510002D0686 /* XCRemoteSwiftPackageReference "IOS-Pods-DFU-Library" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/NordicSemiconductor/IOS-Pods-DFU-Library"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 4.10.3; - }; - }; - 0EE36EB7269F054E0021B746 /* XCRemoteSwiftPackageReference "Charts" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/danielgindi/Charts"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 4.0.1; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 0E00C4F62685B971009B3C24 /* RuuviServiceExport */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceExport; - }; - 0E00C4F82685B972009B3C24 /* RuuviServiceMeasurement */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceMeasurement; - }; - 0E00C4FA2685B97D009B3C24 /* RuuviServiceExport */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceExport; - }; - 0E00C4FC2685B97E009B3C24 /* RuuviServiceMeasurement */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceMeasurement; - }; - 0E05012C2685FDE8007060C4 /* RuuviDaemonBackground */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemonBackground; - }; - 0E05012E2685FDE8007060C4 /* RuuviDaemonOperation */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemonOperation; - }; - 0E0501302685FDE8007060C4 /* RuuviDaemonRuuviTag */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemonRuuviTag; - }; - 0E0501322685FDE8007060C4 /* RuuviDaemonVirtualTag */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemonVirtualTag; - }; - 0E0501342685FDEF007060C4 /* RuuviDaemonBackground */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemonBackground; - }; - 0E0501362685FDEF007060C4 /* RuuviDaemonOperation */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemonOperation; - }; - 0E0501382685FDF0007060C4 /* RuuviDaemonRuuviTag */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemonRuuviTag; - }; - 0E05013A2685FDF0007060C4 /* RuuviDaemonVirtualTag */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemonVirtualTag; - }; - 0E11D13C267DFA08002D0686 /* Localize_Swift */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D13B267DFA08002D0686 /* XCRemoteSwiftPackageReference "Localize-Swift" */; - productName = Localize_Swift; - }; - 0E11D13E267DFA13002D0686 /* Localize_Swift */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D13B267DFA08002D0686 /* XCRemoteSwiftPackageReference "Localize-Swift" */; - productName = Localize_Swift; - }; - 0E11D14D267DFC75002D0686 /* RuuviCloud */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCloud; - }; - 0E11D14F267DFC75002D0686 /* RuuviCloudApi */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCloudApi; - }; - 0E11D151267DFC75002D0686 /* RuuviCloudPure */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCloudPure; - }; - 0E11D153267DFC7B002D0686 /* RuuviContext */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviContext; - }; - 0E11D155267DFC7B002D0686 /* RuuviContextRealm */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviContextRealm; - }; - 0E11D157267DFC7B002D0686 /* RuuviContextSQLite */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviContextSQLite; - }; - 0E11D159267DFC80002D0686 /* RuuviCore */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCore; - }; - 0E11D15B267DFC80002D0686 /* RuuviCoreImage */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCoreImage; - }; - 0E11D15D267DFC8C002D0686 /* RuuviDaemon */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemon; - }; - 0E11D15F267DFC8C002D0686 /* RuuviDaemonCloudSync */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemonCloudSync; - }; - 0E11D161267DFC95002D0686 /* RuuviLocal */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviLocal; - }; - 0E11D163267DFC95002D0686 /* RuuviLocalUserDefaults */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviLocalUserDefaults; - }; - 0E11D165267DFC9C002D0686 /* RuuviOntology */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviOntology; - }; - 0E11D167267DFC9C002D0686 /* RuuviOntologyRealm */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviOntologyRealm; - }; - 0E11D169267DFC9C002D0686 /* RuuviOntologySQLite */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviOntologySQLite; - }; - 0E11D16B267DFCA2002D0686 /* RuuviPersistence */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviPersistence; - }; - 0E11D16D267DFCA2002D0686 /* RuuviPersistenceRealm */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviPersistenceRealm; - }; - 0E11D16F267DFCA2002D0686 /* RuuviPersistenceSQLite */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviPersistenceSQLite; - }; - 0E11D171267DFCA8002D0686 /* RuuviPool */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviPool; - }; - 0E11D173267DFCA8002D0686 /* RuuviPoolCoordinator */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviPoolCoordinator; - }; - 0E11D175267DFCAE002D0686 /* RuuviReactor */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviReactor; - }; - 0E11D177267DFCAE002D0686 /* RuuviReactorImpl */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviReactorImpl; - }; - 0E11D179267DFCB6002D0686 /* RuuviRepository */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviRepository; - }; - 0E11D17B267DFCB6002D0686 /* RuuviRepositoryCoordinator */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviRepositoryCoordinator; - }; - 0E11D17D267DFCBD002D0686 /* RuuviService */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviService; - }; - 0E11D17F267DFCBD002D0686 /* RuuviServiceAlert */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceAlert; - }; - 0E11D181267DFCBE002D0686 /* RuuviServiceAppSettings */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceAppSettings; - }; - 0E11D183267DFCBE002D0686 /* RuuviServiceCloudSync */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceCloudSync; - }; - 0E11D185267DFCBE002D0686 /* RuuviServiceFactory */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceFactory; - }; - 0E11D187267DFCBE002D0686 /* RuuviServiceOffsetCalibration */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceOffsetCalibration; - }; - 0E11D189267DFCBE002D0686 /* RuuviServiceOwnership */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceOwnership; - }; - 0E11D18B267DFCBE002D0686 /* RuuviServiceSensorProperties */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceSensorProperties; - }; - 0E11D18D267DFCBE002D0686 /* RuuviServiceSensorRecords */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceSensorRecords; - }; - 0E11D18F267DFCC7002D0686 /* RuuviStorage */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviStorage; - }; - 0E11D191267DFCC7002D0686 /* RuuviStorageCoordinator */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviStorageCoordinator; - }; - 0E11D193267DFCCD002D0686 /* RuuviUser */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviUser; - }; - 0E11D195267DFCCD002D0686 /* RuuviUserCoordinator */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviUserCoordinator; - }; - 0E11D197267DFCDA002D0686 /* RuuviCloud */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCloud; - }; - 0E11D199267DFCDA002D0686 /* RuuviCloudApi */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCloudApi; - }; - 0E11D19B267DFCDA002D0686 /* RuuviCloudPure */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCloudPure; - }; - 0E11D19D267DFCDA002D0686 /* RuuviContext */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviContext; - }; - 0E11D19F267DFCDA002D0686 /* RuuviContextRealm */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviContextRealm; - }; - 0E11D1A1267DFCDA002D0686 /* RuuviContextSQLite */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviContextSQLite; - }; - 0E11D1A3267DFCDA002D0686 /* RuuviCore */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCore; - }; - 0E11D1A5267DFCDA002D0686 /* RuuviCoreImage */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCoreImage; - }; - 0E11D1A7267DFCDA002D0686 /* RuuviDaemon */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemon; - }; - 0E11D1A9267DFCDA002D0686 /* RuuviDaemonCloudSync */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemonCloudSync; - }; - 0E11D1AB267DFCDA002D0686 /* RuuviLocal */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviLocal; - }; - 0E11D1AD267DFCDA002D0686 /* RuuviLocalUserDefaults */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviLocalUserDefaults; - }; - 0E11D1AF267DFCDA002D0686 /* RuuviOntology */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviOntology; - }; - 0E11D1B1267DFCDA002D0686 /* RuuviOntologyRealm */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviOntologyRealm; - }; - 0E11D1B3267DFCDA002D0686 /* RuuviOntologySQLite */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviOntologySQLite; - }; - 0E11D1B5267DFCDA002D0686 /* RuuviPersistence */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviPersistence; - }; - 0E11D1B7267DFCDA002D0686 /* RuuviPersistenceRealm */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviPersistenceRealm; - }; - 0E11D1B9267DFCDA002D0686 /* RuuviPersistenceSQLite */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviPersistenceSQLite; - }; - 0E11D1BB267DFCDA002D0686 /* RuuviPool */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviPool; - }; - 0E11D1BD267DFCDB002D0686 /* RuuviPoolCoordinator */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviPoolCoordinator; - }; - 0E11D1BF267DFCDB002D0686 /* RuuviReactor */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviReactor; - }; - 0E11D1C1267DFCDB002D0686 /* RuuviReactorImpl */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviReactorImpl; - }; - 0E11D1C3267DFCDB002D0686 /* RuuviRepository */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviRepository; - }; - 0E11D1C5267DFCDB002D0686 /* RuuviRepositoryCoordinator */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviRepositoryCoordinator; - }; - 0E11D1C7267DFCDB002D0686 /* RuuviService */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviService; - }; - 0E11D1C9267DFCDB002D0686 /* RuuviServiceAlert */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceAlert; - }; - 0E11D1CB267DFCDB002D0686 /* RuuviServiceAppSettings */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceAppSettings; - }; - 0E11D1CD267DFCDB002D0686 /* RuuviServiceCloudSync */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceCloudSync; - }; - 0E11D1CF267DFCDB002D0686 /* RuuviServiceFactory */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceFactory; - }; - 0E11D1D1267DFCDB002D0686 /* RuuviServiceOffsetCalibration */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceOffsetCalibration; - }; - 0E11D1D3267DFCDB002D0686 /* RuuviServiceOwnership */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceOwnership; - }; - 0E11D1D5267DFCDB002D0686 /* RuuviServiceSensorProperties */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceSensorProperties; - }; - 0E11D1D7267DFCDB002D0686 /* RuuviServiceSensorRecords */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceSensorRecords; - }; - 0E11D1D9267DFCDB002D0686 /* RuuviStorage */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviStorage; - }; - 0E11D1DB267DFCDB002D0686 /* RuuviStorageCoordinator */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviStorageCoordinator; - }; - 0E11D1DD267DFCDB002D0686 /* RuuviUser */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviUser; - }; - 0E11D1DF267DFCDB002D0686 /* RuuviUserCoordinator */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviUserCoordinator; - }; - 0E11D1E7267DFF2F002D0686 /* LightRoute */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D1E6267DFF2F002D0686 /* XCRemoteSwiftPackageReference "LightRoute" */; - productName = LightRoute; - }; - 0E11D1E9267DFF38002D0686 /* LightRoute */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D1E6267DFF2F002D0686 /* XCRemoteSwiftPackageReference "LightRoute" */; - productName = LightRoute; - }; - 0E11D1EC267E0010002D0686 /* FirebaseAnalytics */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D1EB267E0010002D0686 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseAnalytics; - }; - 0E11D1EE267E0010002D0686 /* FirebaseRemoteConfig */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D1EB267E0010002D0686 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseRemoteConfig; - }; - 0E11D1F0267E0010002D0686 /* FirebaseCrashlytics */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D1EB267E0010002D0686 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseCrashlytics; - }; - 0E11D1F2267E0040002D0686 /* FirebaseAnalytics */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D1EB267E0010002D0686 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseAnalytics; - }; - 0E11D1F4267E0040002D0686 /* FirebaseCrashlytics */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D1EB267E0010002D0686 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseCrashlytics; - }; - 0E11D1F6267E0040002D0686 /* FirebaseRemoteConfig */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D1EB267E0010002D0686 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseRemoteConfig; - }; - 0E11D1F9267E008D002D0686 /* Swinject */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D1F8267E008D002D0686 /* XCRemoteSwiftPackageReference "Swinject" */; - productName = Swinject; - }; - 0E11D1FB267E00AC002D0686 /* Swinject */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D1F8267E008D002D0686 /* XCRemoteSwiftPackageReference "Swinject" */; - productName = Swinject; - }; - 0E11D1FE267E02BC002D0686 /* RangeSeekSlider */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D1FD267E02BC002D0686 /* XCRemoteSwiftPackageReference "RangeSeekSlider" */; - productName = RangeSeekSlider; - }; - 0E11D200267E02D2002D0686 /* RangeSeekSlider */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D1FD267E02BC002D0686 /* XCRemoteSwiftPackageReference "RangeSeekSlider" */; - productName = RangeSeekSlider; - }; - 0E11D203267E0336002D0686 /* GestureInstructions */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D202267E0336002D0686 /* XCRemoteSwiftPackageReference "GestureInstructions" */; - productName = GestureInstructions; - }; - 0E11D205267E0346002D0686 /* GestureInstructions */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D202267E0336002D0686 /* XCRemoteSwiftPackageReference "GestureInstructions" */; - productName = GestureInstructions; - }; - 0E11D208267E037A002D0686 /* SwinjectPropertyLoader */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D207267E0379002D0686 /* XCRemoteSwiftPackageReference "SwinjectPropertyLoader" */; - productName = SwinjectPropertyLoader; - }; - 0E11D20A267E038C002D0686 /* SwinjectPropertyLoader */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D207267E0379002D0686 /* XCRemoteSwiftPackageReference "SwinjectPropertyLoader" */; - productName = SwinjectPropertyLoader; - }; - 0E11D20D267E0510002D0686 /* NordicDFU */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D20C267E0510002D0686 /* XCRemoteSwiftPackageReference "IOS-Pods-DFU-Library" */; - productName = NordicDFU; - }; - 0E11D20F267E051D002D0686 /* NordicDFU */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D20C267E0510002D0686 /* XCRemoteSwiftPackageReference "IOS-Pods-DFU-Library" */; - productName = NordicDFU; - }; - 0E11D215267E13D1002D0686 /* FirebaseInAppMessaging-Beta */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D1EB267E0010002D0686 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = "FirebaseInAppMessaging-Beta"; - }; - 0E11D217267E13D1002D0686 /* FirebaseMessaging */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D1EB267E0010002D0686 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseMessaging; - }; - 0E11D219267E13DB002D0686 /* FirebaseInAppMessaging-Beta */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D1EB267E0010002D0686 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = "FirebaseInAppMessaging-Beta"; - }; - 0E11D21B267E13DB002D0686 /* FirebaseMessaging */ = { - isa = XCSwiftPackageProductDependency; - package = 0E11D1EB267E0010002D0686 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseMessaging; - }; - 0E2513512684A10A004A522A /* RuuviNotification */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviNotification; - }; - 0E2513532684A10A004A522A /* RuuviNotificationLocal */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviNotificationLocal; - }; - 0E2513552684A113004A522A /* RuuviNotification */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviNotification; - }; - 0E2513572684A113004A522A /* RuuviNotificationLocal */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviNotificationLocal; - }; - 0E2513652684CFF7004A522A /* RuuviNotifier */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviNotifier; - }; - 0E2513672684CFF7004A522A /* RuuviNotifierImpl */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviNotifierImpl; - }; - 0E2513692684D000004A522A /* RuuviNotifier */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviNotifier; - }; - 0E25136B2684D001004A522A /* RuuviNotifierImpl */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviNotifierImpl; - }; - 0E62297F26A7FA7C0041DCDD /* RuuviOnboard */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviOnboard; - }; - 0E62298126A7FA8A0041DCDD /* RuuviOnboard */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviOnboard; - }; - 0E8E3D6F268228760082EC29 /* RuuviVirtual */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtual; - }; - 0E8E3D71268228760082EC29 /* RuuviVirtualModel */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualModel; - }; - 0E8E3D73268228760082EC29 /* RuuviVirtualOWM */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualOWM; - }; - 0E8E3D75268228760082EC29 /* RuuviVirtualPersistence */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualPersistence; - }; - 0E8E3D77268228760082EC29 /* RuuviVirtualReactor */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualReactor; - }; - 0E8E3D79268228760082EC29 /* RuuviVirtualRepository */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualRepository; - }; - 0E8E3D7B268228760082EC29 /* RuuviVirtualService */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualService; - }; - 0E8E3D7D268228760082EC29 /* RuuviVirtualStorage */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualStorage; - }; - 0E8E3D7F268228820082EC29 /* RuuviVirtual */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtual; - }; - 0E8E3D81268228820082EC29 /* RuuviVirtualModel */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualModel; - }; - 0E8E3D83268228820082EC29 /* RuuviVirtualOWM */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualOWM; - }; - 0E8E3D85268228820082EC29 /* RuuviVirtualPersistence */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualPersistence; - }; - 0E8E3D87268228820082EC29 /* RuuviVirtualReactor */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualReactor; - }; - 0E8E3D89268228820082EC29 /* RuuviVirtualRepository */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualRepository; - }; - 0E8E3D8B268228820082EC29 /* RuuviVirtualService */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualService; - }; - 0E8E3D8D268228820082EC29 /* RuuviVirtualStorage */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualStorage; - }; - 0E8E3D9B26822ADD0082EC29 /* RuuviLocation */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviLocation; - }; - 0E8E3D9D26822ADD0082EC29 /* RuuviLocationService */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviLocationService; - }; - 0E8E3D9F26822AE40082EC29 /* RuuviLocation */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviLocation; - }; - 0E8E3DA126822AE40082EC29 /* RuuviLocationService */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviLocationService; - }; - 0E8E3DA326822B0D0082EC29 /* RuuviCoreLocation */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCoreLocation; - }; - 0E8E3DA526822B130082EC29 /* RuuviCoreLocation */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCoreLocation; - }; - 0E92A96E268636A700187E4F /* RuuviServiceGATT */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceGATT; - }; - 0E92A970268636AE00187E4F /* RuuviServiceGATT */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceGATT; - }; - 0EB8B9132683519200FE130E /* RuuviMigration */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviMigration; - }; - 0EB8B9152683519200FE130E /* RuuviMigrationImpl */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviMigrationImpl; - }; - 0EB8B9172683519900FE130E /* RuuviMigration */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviMigration; - }; - 0EB8B9192683519900FE130E /* RuuviMigrationImpl */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviMigrationImpl; - }; - 0EB8B92F26837A4700FE130E /* RuuviCoreDiff */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCoreDiff; - }; - 0EB8B93126837A4700FE130E /* RuuviCorePermission */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCorePermission; - }; - 0EB8B93326837A4700FE130E /* RuuviCorePN */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCorePN; - }; - 0EB8B93526837A5100FE130E /* RuuviCoreDiff */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCoreDiff; - }; - 0EB8B93726837A5100FE130E /* RuuviCorePermission */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCorePermission; - }; - 0EB8B93926837A5100FE130E /* RuuviCorePN */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCorePN; - }; - 0EE36EB8269F054E0021B746 /* Charts */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE36EB7269F054E0021B746 /* XCRemoteSwiftPackageReference "Charts" */; - productName = Charts; - }; - 0EE36EBA269F05600021B746 /* Charts */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE36EB7269F054E0021B746 /* XCRemoteSwiftPackageReference "Charts" */; - productName = Charts; - }; - 0EEEBDE526860F6700589D56 /* RuuviAnalytics */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviAnalytics; - }; - 0EEEBDE726860F6700589D56 /* RuuviAnalyticsImpl */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviAnalyticsImpl; - }; - 0EEEBDE926860F6D00589D56 /* RuuviAnalytics */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviAnalytics; - }; - 0EEEBDEB26860F6D00589D56 /* RuuviAnalyticsImpl */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviAnalyticsImpl; - }; - 0EF4E343268318DE00D83CC7 /* RuuviDFU */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDFU; - }; - 0EF4E345268318DE00D83CC7 /* RuuviDFUImpl */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDFUImpl; - }; - 0EF4E347268318E600D83CC7 /* RuuviDFU */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDFU; - }; - 0EF4E349268318E600D83CC7 /* RuuviDFUImpl */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDFUImpl; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 64333D1D20B0C45900CDF4B6 /* Project object */; -} diff --git a/iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100755 index 919434a62..000000000 --- a/iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/iOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/iOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100755 index 18d981003..000000000 --- a/iOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/iOS.xcodeproj/xcshareddata/xcschemes/station.xcscheme b/iOS.xcodeproj/xcshareddata/xcschemes/station.xcscheme deleted file mode 100755 index df1b7dd1e..000000000 --- a/iOS.xcodeproj/xcshareddata/xcschemes/station.xcscheme +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/iOS.xcodeproj/xcshareddata/xcschemes/station_dev.xcscheme b/iOS.xcodeproj/xcshareddata/xcschemes/station_dev.xcscheme deleted file mode 100755 index 73e5fdec5..000000000 --- a/iOS.xcodeproj/xcshareddata/xcschemes/station_dev.xcscheme +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/macOS.xcodeproj/project.pbxproj b/macOS.xcodeproj/project.pbxproj deleted file mode 100755 index 5510adc5d..000000000 --- a/macOS.xcodeproj/project.pbxproj +++ /dev/null @@ -1,4925 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 52; - objects = { - -/* Begin PBXBuildFile section */ - 0E00C5012685BA1D009B3C24 /* RuuviServiceExport in Frameworks */ = {isa = PBXBuildFile; productRef = 0E00C5002685BA1D009B3C24 /* RuuviServiceExport */; }; - 0E00C5032685BA1D009B3C24 /* RuuviServiceMeasurement in Frameworks */ = {isa = PBXBuildFile; productRef = 0E00C5022685BA1D009B3C24 /* RuuviServiceMeasurement */; }; - 0E05014026860099007060C4 /* RuuviDaemonError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E05013E26860099007060C4 /* RuuviDaemonError+LocalizedError.swift */; }; - 0E05014126860099007060C4 /* RuuviDFUError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E05013F26860099007060C4 /* RuuviDFUError+LocalizedError.swift */; }; - 0E050143268601F5007060C4 /* RuuviDaemonBackground in Frameworks */ = {isa = PBXBuildFile; productRef = 0E050142268601F5007060C4 /* RuuviDaemonBackground */; }; - 0E050145268601F5007060C4 /* RuuviDaemonOperation in Frameworks */ = {isa = PBXBuildFile; productRef = 0E050144268601F5007060C4 /* RuuviDaemonOperation */; }; - 0E050147268601F6007060C4 /* RuuviDaemonRuuviTag in Frameworks */ = {isa = PBXBuildFile; productRef = 0E050146268601F6007060C4 /* RuuviDaemonRuuviTag */; }; - 0E050149268601F6007060C4 /* RuuviDaemonVirtualTag in Frameworks */ = {isa = PBXBuildFile; productRef = 0E050148268601F6007060C4 /* RuuviDaemonVirtualTag */; }; - 0E05015726860375007060C4 /* AppStateServiceImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E05014C26860375007060C4 /* AppStateServiceImpl.swift */; }; - 0E05015826860375007060C4 /* AppStateService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E05014D26860375007060C4 /* AppStateService.swift */; }; - 0E05015926860375007060C4 /* UniversalLinkCoordinatormpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E05015126860375007060C4 /* UniversalLinkCoordinatormpl.swift */; }; - 0E05015A26860375007060C4 /* UniversalLinkCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E05015226860375007060C4 /* UniversalLinkCoordinator.swift */; }; - 0E05015B26860375007060C4 /* UniversalLinkRouterImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E05015526860375007060C4 /* UniversalLinkRouterImpl.swift */; }; - 0E05015C26860375007060C4 /* UniversalLinkRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E05015626860375007060C4 /* UniversalLinkRouter.swift */; }; - 0E05015E26860386007060C4 /* ChartFilterOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E05015D26860385007060C4 /* ChartFilterOperation.swift */; }; - 0E11D212267E1310002D0686 /* FirebaseInAppMessaging-Beta in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D211267E1310002D0686 /* FirebaseInAppMessaging-Beta */; }; - 0E11D214267E1317002D0686 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = 0E11D213267E1317002D0686 /* FirebaseMessaging */; }; - 0E197C6323C352380074015B /* TagSettingsAlertDescriptionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C6023C352380074015B /* TagSettingsAlertDescriptionCell.swift */; }; - 0E197C6823C4A47A0074015B /* MailComposerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C6523C4A47A0074015B /* MailComposerPresenter.swift */; }; - 0E197C6D23C4A52A0074015B /* MailComposerPresenterMessageUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C6A23C4A52A0074015B /* MailComposerPresenterMessageUI.swift */; }; - 0E197C7123C4A7D00074015B /* Presentation.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0E197C6E23C4A7D00074015B /* Presentation.plist */; }; - 0E197C7F23C5CD7C0074015B /* UIDevice+ReadableModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C7C23C5CD7C0074015B /* UIDevice+ReadableModel.swift */; }; - 0E197C8323C5CDBE0074015B /* iOSDeviceModelMapping.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0E197C8023C5CDBE0074015B /* iOSDeviceModelMapping.plist */; }; - 0E1B2F34239DEF120060C469 /* TagSettingsAlertHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1B2F31239DEF120060C469 /* TagSettingsAlertHeaderCell.swift */; }; - 0E1B2F38239DF0120060C469 /* TagSettingsAlertControlsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1B2F35239DF0120060C469 /* TagSettingsAlertControlsCell.swift */; }; - 0E25135B2684A1FD004A522A /* RuuviNotification in Frameworks */ = {isa = PBXBuildFile; productRef = 0E25135A2684A1FD004A522A /* RuuviNotification */; }; - 0E25135D2684A1FD004A522A /* RuuviNotificationLocal in Frameworks */ = {isa = PBXBuildFile; productRef = 0E25135C2684A1FD004A522A /* RuuviNotificationLocal */; }; - 0E2513712684D09B004A522A /* RuuviNotifier in Frameworks */ = {isa = PBXBuildFile; productRef = 0E2513702684D09B004A522A /* RuuviNotifier */; }; - 0E2513732684D09B004A522A /* RuuviNotifierImpl in Frameworks */ = {isa = PBXBuildFile; productRef = 0E2513722684D09B004A522A /* RuuviNotifierImpl */; }; - 0E290A872660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E290A842660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift */; }; - 0E2AFFA2266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2AFF9F266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift */; }; - 0E31B04423BBA37C00660412 /* WebTagSettingsAlertsHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E31B04123BBA37C00660412 /* WebTagSettingsAlertsHeaderFooterView.swift */; }; - 0E31B04823BBA3F900660412 /* WebTagSettingsAlertsHeaderFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E31B04523BBA3F900660412 /* WebTagSettingsAlertsHeaderFooterView.xib */; }; - 0E5BF779267BCCB900EBF2D6 /* RuuviCoreImage in Frameworks */ = {isa = PBXBuildFile; productRef = 0E5BF778267BCCB900EBF2D6 /* RuuviCoreImage */; }; - 0E62298626A7FB4E0041DCDD /* OnboardRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E62298426A7FB4D0041DCDD /* OnboardRouter.swift */; }; - 0E62298726A7FB4E0041DCDD /* AppRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E62298526A7FB4D0041DCDD /* AppRouter.swift */; }; - 0E62298A26A7FB860041DCDD /* RuuviOnboard in Frameworks */ = {isa = PBXBuildFile; productRef = 0E62298926A7FB860041DCDD /* RuuviOnboard */; }; - 0E6BAD7A23856A01003A2D4C /* CardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E1022B756B40032F6CA /* CardView.swift */; }; - 0E6BAD7C23856A01003A2D4C /* DiscoverTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A46B22AF9705006CB87C /* DiscoverTableViewController.swift */; }; - 0E6BAD7D23856A01003A2D4C /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5522CCE46D00172EEB /* Optional.swift */; }; - 0E6BAD8223856A01003A2D4C /* CALayer+IB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E09672422AE897000E85F48 /* CALayer+IB.swift */; }; - 0E6BAD8423856A01003A2D4C /* MenuTablePresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0E22B4049E0032F6CA /* MenuTablePresentationController.swift */; }; - 0E6BAD8723856A01003A2D4C /* TagSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863022CBB00D0026C7A5 /* TagSettingsViewInput.swift */; }; - 0E6BAD8823856A01003A2D4C /* DefaultsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100D23845F8C00A9CBA6 /* DefaultsViewOutput.swift */; }; - 0E6BAD8923856A01003A2D4C /* MenuPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFF22B400130032F6CA /* MenuPresenter.swift */; }; - 0E6BAD8A23856A01003A2D4C /* ForegroundRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF6F5BD235E01170052BA25 /* ForegroundRouter.swift */; }; - 0E6BAD8B23856A01003A2D4C /* MenuTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF722B3FF480032F6CA /* MenuTableViewController.swift */; }; - 0E6BAD8C23856A01003A2D4C /* AboutRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F822B7D28C0015F9E0 /* AboutRouterInput.swift */; }; - 0E6BAD8E23856A01003A2D4C /* WelcomeConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215722B8FD800015F9E0 /* WelcomeConfigurator.swift */; }; - 0E6BAD8F23856A01003A2D4C /* ForegroundModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF35A2350618E0061D11B /* ForegroundModuleInput.swift */; }; - 0E6BAD9023856A01003A2D4C /* AboutViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F422B7D1A40015F9E0 /* AboutViewOutput.swift */; }; - 0E6BAD9323856A01003A2D4C /* TagChartsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0DC2333714C00FFA577 /* TagChartsViewModel.swift */; }; - 0E6BAD9623856A01003A2D4C /* PermissionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C301922CF644900B52E39 /* PermissionPresenter.swift */; }; - 0E6BAD9723856A01003A2D4C /* LocationPickerRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4E22F1827800BD4E9C /* LocationPickerRouterInput.swift */; }; - 0E6BAD9923856A01003A2D4C /* TagChartsTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0D223336B4200FFA577 /* TagChartsTransitioningDelegate.swift */; }; - 0E6BAD9A23856A01003A2D4C /* WebTagSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3122F057DD00BD4E9C /* WebTagSettingsRouter.swift */; }; - 0E6BAD9B23856A01003A2D4C /* DefaultsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10192384615400A9CBA6 /* DefaultsPresenter.swift */; }; - 0E6BAD9C23856A01003A2D4C /* WelcomeViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214622B8FC3E0015F9E0 /* WelcomeViewInput.swift */; }; - 0E6BAD9D23856A01003A2D4C /* ForegroundList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF354235056DC0061D11B /* ForegroundList.swift */; }; - 0E6BAD9E23856A01003A2D4C /* SettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E222B7C8C10015F9E0 /* SettingsPresenter.swift */; }; - 0E6BAD9F23856A01003A2D4C /* LanguageTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF07F2320089A0025A191 /* LanguageTableConfigurator.swift */; }; - 0E6BADA023856A01003A2D4C /* MenuTablePresentTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0A22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift */; }; - 0E6BADA123856A01003A2D4C /* WebTagSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2822F0561B00BD4E9C /* WebTagSettingsViewInput.swift */; }; - 0E6BADA223856A01003A2D4C /* WelcomeRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214B22B8FCC70015F9E0 /* WelcomeRouterInput.swift */; }; - 0E6BADA423856A01003A2D4C /* MenuModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20CC22B7BD6C0015F9E0 /* MenuModuleOutput.swift */; }; - 0E6BADA723856A01003A2D4C /* Localizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A46222AF959E006CB87C /* Localizable.swift */; }; - 0E6BADA823856A01003A2D4C /* LocationPickerAppleInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5722F182F500BD4E9C /* LocationPickerAppleInitializer.swift */; }; - 0E6BADA923856A01003A2D4C /* TagChartsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0CC2333672F00FFA577 /* TagChartsPresenter.swift */; }; - 0E6BADAA23856A01003A2D4C /* DefaultsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10212384637F00A9CBA6 /* DefaultsList.swift */; }; - 0E6BADAC23856A01003A2D4C /* WelcomePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215222B8FD1F0015F9E0 /* WelcomePresenter.swift */; }; - 0E6BADAE23856A01003A2D4C /* CardsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DD422B3BF3A0032F6CA /* CardsViewOutput.swift */; }; - 0E6BADAF23856A01003A2D4C /* DefaultsSwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A102423846CEB00A9CBA6 /* DefaultsSwitchTableViewCell.swift */; }; - 0E6BADB023856A01003A2D4C /* DefaultsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100B23845F7100A9CBA6 /* DefaultsViewInput.swift */; }; - 0E6BADB123856A01003A2D4C /* LocationPickerRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5022F1828900BD4E9C /* LocationPickerRouter.swift */; }; - 0E6BADB223856A01003A2D4C /* WebTagSettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3322F057FC00BD4E9C /* WebTagSettingsModuleInput.swift */; }; - 0E6BADB323856A01003A2D4C /* MenuTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0422B400890032F6CA /* MenuTableConfigurator.swift */; }; - 0E6BADB723856A01003A2D4C /* DefaultsStepperTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8BD2AA23851CF2008B31EF /* DefaultsStepperTableViewCell.swift */; }; - 0E6BADBA23856A01003A2D4C /* SettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20DE22B7C8790015F9E0 /* SettingsRouter.swift */; }; - 0E6BADBD23856A01003A2D4C /* SwipeDownToDismissNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6622CC964200BC6D64 /* SwipeDownToDismissNavigationController.swift */; }; - 0E6BADBE23856A01003A2D4C /* DefaultsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10152384612300A9CBA6 /* DefaultsRouterInput.swift */; }; - 0E6BADBF23856A01003A2D4C /* AboutPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FE22B7D2DD0015F9E0 /* AboutPresenter.swift */; }; - 0E6BADC023856A01003A2D4C /* TagChartsPresentTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0D423336BA300FFA577 /* TagChartsPresentTransitionAnimation.swift */; }; - 0E6BADC123856A01003A2D4C /* TagSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5122CCB9DE00172EEB /* TagSettingsViewModel.swift */; }; - 0E6BADC223856A01003A2D4C /* CardsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DDE22B3C2330032F6CA /* CardsPresenter.swift */; }; - 0E6BADC323856A01003A2D4C /* DiscoverWebTagsInfoHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3FF7362381591800EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.swift */; }; - 0E6BADC623856A01003A2D4C /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F4F22CCB92000172EEB /* Observable.swift */; }; - 0E6BADC723856A01003A2D4C /* ForegroundTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF6F5C1235E02000052BA25 /* ForegroundTableViewController.swift */; }; - 0E6BADCA23856A01003A2D4C /* TagSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863222CBB0250026C7A5 /* TagSettingsViewOutput.swift */; }; - 0E6BADCB23856A01003A2D4C /* ForegroundViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF36F23507CE80061D11B /* ForegroundViewModel.swift */; }; - 0E6BADCC23856A01003A2D4C /* CardsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20C522B7915C0015F9E0 /* CardsViewModel.swift */; }; - 0E6BADCD23856A01003A2D4C /* UIApplication+ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DBA22B3919F0032F6CA /* UIApplication+ViewController.swift */; }; - 0E6BADCE23856A01003A2D4C /* WebTagSettingsTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3C22F05B0900BD4E9C /* WebTagSettingsTableConfigurator.swift */; }; - 0E6BADD223856A01003A2D4C /* TagSettingsMoreInfoHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E62AEC822E065CC00A49BFB /* TagSettingsMoreInfoHeaderFooterView.swift */; }; - 0E6BADD423856A01003A2D4C /* PermissionPresenterAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C301B22CF646A00B52E39 /* PermissionPresenterAlert.swift */; }; - 0E6BADD623856A01003A2D4C /* MainRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB213B22B8FAD50015F9E0 /* MainRouter.swift */; }; - 0E6BADD723856A01003A2D4C /* TagChartsScrollViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0C023335D8400FFA577 /* TagChartsScrollViewController.swift */; }; - 0E6BADD923856A01003A2D4C /* PhotoPickerPresenterSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C300A22CF629100B52E39 /* PhotoPickerPresenterSheet.swift */; }; - 0E6BADDA23856A01003A2D4C /* AboutConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB210222B7D3210015F9E0 /* AboutConfigurator.swift */; }; - 0E6BADDB23856A01003A2D4C /* AboutViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F222B7D1900015F9E0 /* AboutViewInput.swift */; }; - 0E6BADDC23856A01003A2D4C /* TagChartsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0C223335DA700FFA577 /* TagChartsViewInput.swift */; }; - 0E6BADDD23856A01003A2D4C /* LanguageTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF071232007910025A191 /* LanguageTableViewController.swift */; }; - 0E6BADDE23856A01003A2D4C /* DefaultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100923845F3900A9CBA6 /* DefaultsViewController.swift */; }; - 0E6BADE023856A01003A2D4C /* DefaultsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100F23845FAE00A9CBA6 /* DefaultsViewModel.swift */; }; - 0E6BADE123856A01003A2D4C /* TagChartsScrollConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0D02333679800FFA577 /* TagChartsScrollConfigurator.swift */; }; - 0E6BADE323856A01003A2D4C /* LanguageViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF06F232007740025A191 /* LanguageViewOutput.swift */; }; - 0E6BADE423856A01003A2D4C /* DefaultsConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A101D238461D400A9CBA6 /* DefaultsConfigurator.swift */; }; - 0E6BADE523856A01003A2D4C /* MenuRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFB22B3FFD90032F6CA /* MenuRouter.swift */; }; - 0E6BADE623856A01003A2D4C /* ForegroundRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF36723507A1A0061D11B /* ForegroundRouterInput.swift */; }; - 0E6BADEA23856A01003A2D4C /* DefaultsInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A101B2384618700A9CBA6 /* DefaultsInitializer.swift */; }; - 0E6BADEC23856A01003A2D4C /* MainInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214122B8FBA50015F9E0 /* MainInitializer.swift */; }; - 0E6BADEE23856A01003A2D4C /* ForegroundSwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9D5F1F2351BE3C0076FFD8 /* ForegroundSwitchTableViewCell.swift */; }; - 0E6BADF023856A01003A2D4C /* MenuTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0222B400590032F6CA /* MenuTableInitializer.swift */; }; - 0E6BADF123856A01003A2D4C /* LocationPickerViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4922F1820400BD4E9C /* LocationPickerViewOutput.swift */; }; - 0E6BADF223856A01003A2D4C /* WebTagSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2D22F0569000BD4E9C /* WebTagSettingsTableViewController.swift */; }; - 0E6BADF323856A01003A2D4C /* WelcomeRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214D22B8FCDC0015F9E0 /* WelcomeRouter.swift */; }; - 0E6BADF823856A01003A2D4C /* TagSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863622CBB04E0026C7A5 /* TagSettingsRouter.swift */; }; - 0E6BADF923856A01003A2D4C /* DiscoverDeviceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E09672B22AE94F000E85F48 /* DiscoverDeviceTableViewCell.swift */; }; - 0E6BADFA23856A01003A2D4C /* AboutInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB210022B7D2F50015F9E0 /* AboutInitializer.swift */; }; - 0E6BADFB23856A01003A2D4C /* ForegroundEnvironmentObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE5B47C23508F6D00D5ED32 /* ForegroundEnvironmentObject.swift */; }; - 0E6BADFC23856A01003A2D4C /* MenuTableEmbededViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20CA22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift */; }; - 0E6BADFE23856A01003A2D4C /* TagChartsDismissTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0D623336C6E00FFA577 /* TagChartsDismissTransitionAnimation.swift */; }; - 0E6BADFF23856A01003A2D4C /* Date+Ruuvi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF5B72A22D62CD900D9D14A /* Date+Ruuvi.swift */; }; - 0E6BAE0323856A01003A2D4C /* CardsScrollViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECB5A8D2381807500E78757 /* CardsScrollViewController.swift */; }; - 0E6BAE0423856A01003A2D4C /* LanguagePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF07A232008420025A191 /* LanguagePresenter.swift */; }; - 0E6BAE0623856A01003A2D4C /* TagSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2862D22CBAFC80026C7A5 /* TagSettingsTableViewController.swift */; }; - 0E6BAE0823856A01003A2D4C /* LocationPickerModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5222F182AB00BD4E9C /* LocationPickerModuleInput.swift */; }; - 0E6BAE0D23856A01003A2D4C /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D222B7C7AC0015F9E0 /* SettingsTableViewController.swift */; }; - 0E6BAE0F23856A01003A2D4C /* SwipeDownToDismissTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6122CC93EB00BC6D64 /* SwipeDownToDismissTransitionAnimation.swift */; }; - 0E6BAE1223856A01003A2D4C /* SettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20DC22B7C8650015F9E0 /* SettingsRouterInput.swift */; }; - 0E6BAE1323856A01003A2D4C /* ForegroundStepperTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF6F5BF235E01CD0052BA25 /* ForegroundStepperTableViewCell.swift */; }; - 0E6BAE1423856A01003A2D4C /* MenuTableTransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215922BA28860015F9E0 /* MenuTableTransitionManager.swift */; }; - 0E6BAE1523856A01003A2D4C /* TagChartsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0C423335DBF00FFA577 /* TagChartsViewOutput.swift */; }; - 0E6BAE1623856A01003A2D4C /* DefaultsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10132384610400A9CBA6 /* DefaultsRouter.swift */; }; - 0E6BAE1723856A01003A2D4C /* ForegroundViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF35F23506BD60061D11B /* ForegroundViewInput.swift */; }; - 0E6BAE1823856A01003A2D4C /* WebTagSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2F22F057CC00BD4E9C /* WebTagSettingsRouterInput.swift */; }; - 0E6BAE1D23856A01003A2D4C /* LocalizationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9D0AB0231EBEFD00C6BDA7 /* LocalizationService.swift */; }; - 0E6BAE1E23856A01003A2D4C /* RURangeSeekSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E02ABB9237598C600ED4629 /* RURangeSeekSlider.swift */; }; - 0E6BAE1F23856A01003A2D4C /* CardsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DDC22B3C2160032F6CA /* CardsModuleInput.swift */; }; - 0E6BAE2023856A01003A2D4C /* LanguageRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF074232007CC0025A191 /* LanguageRouterInput.swift */; }; - 0E6BAE2323856A01003A2D4C /* ForegroundViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF35D23506BC40061D11B /* ForegroundViewOutput.swift */; }; - 0E6BAE2423856A01003A2D4C /* LanguageModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF078232008140025A191 /* LanguageModuleInput.swift */; }; - 0E6BAE2523856A01003A2D4C /* PresentationAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DBD22B3921E0032F6CA /* PresentationAssembly.swift */; }; - 0E6BAE2623856A01003A2D4C /* DiscoverWebTagTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9F979522EAFC820015ADE2 /* DiscoverWebTagTableViewCell.swift */; }; - 0E6BAE2723856A01003A2D4C /* AboutModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FC22B7D2C90015F9E0 /* AboutModuleInput.swift */; }; - 0E6BAE2823856A01003A2D4C /* WelcomeViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214822B8FC570015F9E0 /* WelcomeViewOutput.swift */; }; - 0E6BAE2923856A01003A2D4C /* MainNavigationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB213E22B8FB840015F9E0 /* MainNavigationDelegate.swift */; }; - 0E6BAE2D23856A01003A2D4C /* WebTagSettingsTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3A22F05AA800BD4E9C /* WebTagSettingsTableInitializer.swift */; }; - 0E6BAE2E23856A01003A2D4C /* MenuRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF922B3FFBF0032F6CA /* MenuRouterInput.swift */; }; - 0E6BAE2F23856A01003A2D4C /* LanguageRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF076232007D80025A191 /* LanguageRouter.swift */; }; - 0E6BAE3123856A01003A2D4C /* TagChartsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0CA2333671100FFA577 /* TagChartsModuleInput.swift */; }; - 0E6BAE3223856A01003A2D4C /* Double+Temperature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E02ABCA2379483A00ED4629 /* Double+Temperature.swift */; }; - 0E6BAE3623856A01003A2D4C /* ActivityPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DAE22B38F780032F6CA /* ActivityPresenter.swift */; }; - 0E6BAE3723856A01003A2D4C /* MenuViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF422B3FF1D0032F6CA /* MenuViewOutput.swift */; }; - 0E6BAE3823856A01003A2D4C /* DiscoverViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A46D22AF9763006CB87C /* DiscoverViewInput.swift */; }; - 0E6BAE3923856A01003A2D4C /* LocationPickerAppleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4C22F1823C00BD4E9C /* LocationPickerAppleViewController.swift */; }; - 0E6BAE3A23856A01003A2D4C /* TagSettingsTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2864122CBB13F0026C7A5 /* TagSettingsTableConfigurator.swift */; }; - 0E6BAE3C23856A01003A2D4C /* SwipeDownToDismissTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA5F22CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift */; }; - 0E6BAE3D23856A01003A2D4C /* MenuViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF222B3FEFF0032F6CA /* MenuViewInput.swift */; }; - 0E6BAE3E23856A01003A2D4C /* ActivitySpinnerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DB822B390ED0032F6CA /* ActivitySpinnerView.swift */; }; - 0E6BAE4023856A01003A2D4C /* ActivityPresenterRuuviLogo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DB222B390080032F6CA /* ActivityPresenterRuuviLogo.swift */; }; - 0E6BAE4123856A01003A2D4C /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F622B7D2090015F9E0 /* AboutViewController.swift */; }; - 0E6BAE4223856A01003A2D4C /* DiscoverRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E502FBD22B2817900E8A6CC /* DiscoverRouterInput.swift */; }; - 0E6BAE4423856A01003A2D4C /* DefaultsEnvironmentObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A101F2384633200A9CBA6 /* DefaultsEnvironmentObject.swift */; }; - 0E6BAE4623856A01003A2D4C /* ViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A45F22AF9567006CB87C /* ViewInput.swift */; }; - 0E6BAE4723856A01003A2D4C /* UserDefaults+Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0A381823616AC3003A0364 /* UserDefaults+Optional.swift */; }; - 0E6BAE4823856A01003A2D4C /* TagChartsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0C6233366DC00FFA577 /* TagChartsRouterInput.swift */; }; - 0E6BAE4923856A01003A2D4C /* CardsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DD222B3BF180032F6CA /* CardsViewInput.swift */; }; - 0E6BAE4A23856A01003A2D4C /* DiscoverPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A47422AF9978006CB87C /* DiscoverPresenter.swift */; }; - 0E6BAE4B23856A01003A2D4C /* LanguageViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF06D232007510025A191 /* LanguageViewInput.swift */; }; - 0E6BAE4C23856A01003A2D4C /* AboutRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FA22B7D2990015F9E0 /* AboutRouter.swift */; }; - 0E6BAE4E23856A01003A2D4C /* TagChartsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0C8233366F000FFA577 /* TagChartsRouter.swift */; }; - 0E6BAE4F23856A01003A2D4C /* DiscoverTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A47A22AF9BE2006CB87C /* DiscoverTableInitializer.swift */; }; - 0E6BAE5023856A01003A2D4C /* DiscoverViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A46F22AF9790006CB87C /* DiscoverViewOutput.swift */; }; - 0E6BAE5123856A01003A2D4C /* DiscoverRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E502FBF22B2819B00E8A6CC /* DiscoverRouter.swift */; }; - 0E6BAE5223856A01003A2D4C /* WelcomeModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215022B8FD070015F9E0 /* WelcomeModuleInput.swift */; }; - 0E6BAE5323856A01003A2D4C /* PhotoPickerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5822CF621000172EEB /* PhotoPickerPresenter.swift */; }; - 0E6BAE5423856A01003A2D4C /* LocationPickerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5422F182BF00BD4E9C /* LocationPickerPresenter.swift */; }; - 0E6BAE5723856A01003A2D4C /* DefaultsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10172384613E00A9CBA6 /* DefaultsModuleInput.swift */; }; - 0E6BAE5A23856A01003A2D4C /* TagSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863A22CBB08C0026C7A5 /* TagSettingsPresenter.swift */; }; - 0E6BAE5B23856A01003A2D4C /* TagChartsModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0E22333893600FFA577 /* TagChartsModuleOutput.swift */; }; - 0E6BAE5D23856A01003A2D4C /* SwipeDownToDismissInteractiveTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6322CC943900BC6D64 /* SwipeDownToDismissInteractiveTransition.swift */; }; - 0E6BAE5E23856A01003A2D4C /* TagSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863422CBB03A0026C7A5 /* TagSettingsRouterInput.swift */; }; - 0E6BAE5F23856A01003A2D4C /* NSObject+Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5322CCBBE800172EEB /* NSObject+Observable.swift */; }; - 0E6BAE6023856A01003A2D4C /* TagSettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863822CBB06C0026C7A5 /* TagSettingsModuleInput.swift */; }; - 0E6BAE6223856A01003A2D4C /* LocationPickerAppleConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5922F1832600BD4E9C /* LocationPickerAppleConfigurator.swift */; }; - 0E6BAE6323856A01003A2D4C /* AppAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DA722B387A00032F6CA /* AppAssembly.swift */; }; - 0E6BAE6523856A01003A2D4C /* MenuTableDismissTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0C22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift */; }; - 0E6BAE6623856A01003A2D4C /* DiscoverModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A47222AF9953006CB87C /* DiscoverModuleInput.swift */; }; - 0E6BAE6823856A01003A2D4C /* SettingsTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E722B7C92C0015F9E0 /* SettingsTableConfigurator.swift */; }; - 0E6BAE6A23856A01003A2D4C /* LanguageTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF07D2320086A0025A191 /* LanguageTableInitializer.swift */; }; - 0E6BAE6B23856A01003A2D4C /* LocationPickerModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F6122F193B300BD4E9C /* LocationPickerModuleOutput.swift */; }; - 0E6BAE6C23856A01003A2D4C /* DiscoverTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A47C22AF9BFE006CB87C /* DiscoverTableConfigurator.swift */; }; - 0E6BAE6E23856A01003A2D4C /* LocationPickerViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4722F181DA00BD4E9C /* LocationPickerViewInput.swift */; }; - 0E6BAE6F23856A01003A2D4C /* SettingsTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E522B7C8F20015F9E0 /* SettingsTableInitializer.swift */; }; - 0E6BAE7023856A01003A2D4C /* TagChartsTransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E341BBC2372E75C0085BB54 /* TagChartsTransitionManager.swift */; }; - 0E6BAE7123856A01003A2D4C /* ActivityRuuviLogoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DB622B390BC0032F6CA /* ActivityRuuviLogoViewController.swift */; }; - 0E6BAE7223856A01003A2D4C /* TagChartsScrollInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8FD0CE2333676C00FFA577 /* TagChartsScrollInitializer.swift */; }; - 0E6BAE7323856A01003A2D4C /* ForegroundConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF36D23507BF00061D11B /* ForegroundConfigurator.swift */; }; - 0E6BAE7423856A01003A2D4C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64333D2820B0C45900CDF4B6 /* AppDelegate.swift */; }; - 0E6BAE7523856A01003A2D4C /* TagSettingsTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863F22CBB1340026C7A5 /* TagSettingsTableInitializer.swift */; }; - 0E6BAE7B23856A01003A2D4C /* WebTagSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3E22F0702D00BD4E9C /* WebTagSettingsViewModel.swift */; }; - 0E6BAE7C23856A01003A2D4C /* MainConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB214322B8FBC50015F9E0 /* MainConfigurator.swift */; }; - 0E6BAE7D23856A01003A2D4C /* WebTagSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3522F0581E00BD4E9C /* WebTagSettingsPresenter.swift */; }; - 0E6BAE7E23856A01003A2D4C /* MenuModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFD22B3FFFC0032F6CA /* MenuModuleInput.swift */; }; - 0E6BAE8023856A01003A2D4C /* CardsScrollInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE722B3C2B60032F6CA /* CardsScrollInitializer.swift */; }; - 0E6BAE8123856A01003A2D4C /* DefaultsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10112384605A00A9CBA6 /* DefaultsTableViewController.swift */; }; - 0E6BAE8423856A01003A2D4C /* MenuTableTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0822B4024E0032F6CA /* MenuTableTransitioningDelegate.swift */; }; - 0E6BAE8523856A01003A2D4C /* ErrorPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DC022B3955E0032F6CA /* ErrorPresenter.swift */; }; - 0E6BAE8623856A01003A2D4C /* LanguageTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF08123200B1B0025A191 /* LanguageTableViewCell.swift */; }; - 0E6BAE8B23856A01003A2D4C /* ForegroundRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF36123506C050061D11B /* ForegroundRow.swift */; }; - 0E6BAE8C23856A01003A2D4C /* SettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D722B7C8060015F9E0 /* SettingsViewOutput.swift */; }; - 0E6BAE8D23856A01003A2D4C /* ForegroundPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF365235079F50061D11B /* ForegroundPresenter.swift */; }; - 0E6BAE8E23856A01003A2D4C /* DiscoverNoDevicesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53A3FA232F4D5000ACED49 /* DiscoverNoDevicesTableViewCell.swift */; }; - 0E6BAE8F23856A01003A2D4C /* SettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E022B7C8A90015F9E0 /* SettingsModuleInput.swift */; }; - 0E6BAE9023856A01003A2D4C /* CardsScrollConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE922B3C2E60032F6CA /* CardsScrollConfigurator.swift */; }; - 0E6BAE9323856A01003A2D4C /* WebTagSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2A22F0563100BD4E9C /* WebTagSettingsViewOutput.swift */; }; - 0E6BAE9423856A01003A2D4C /* CardsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE322B3C2710032F6CA /* CardsRouter.swift */; }; - 0E6BAE9523856A01003A2D4C /* WelcomeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E09672122AE7FCF00E85F48 /* WelcomeViewController.swift */; }; - 0E6BAE9623856A01003A2D4C /* CardsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE122B3C25F0032F6CA /* CardsRouterInput.swift */; }; - 0E6BAE9723856A01003A2D4C /* WelcomeInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215522B8FD590015F9E0 /* WelcomeInitializer.swift */; }; - 0E6BAE9923856A01003A2D4C /* SettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D522B7C7E70015F9E0 /* SettingsViewInput.swift */; }; - 0E6BAE9C23856A01003A2D4C /* CardsRouterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E211C29234C5FE900FC37B0 /* CardsRouterDelegate.swift */; }; - 0E6BAE9F23856A01003A2D4C /* ErrorPresenterAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DC322B395C00032F6CA /* ErrorPresenterAlert.swift */; }; - 0E6BAEA023856A01003A2D4C /* ForegroundViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF358235060EF0061D11B /* ForegroundViewController.swift */; }; - 0E6BAEA223856A01003A2D4C /* ForegroundInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECFF36B23507BC00061D11B /* ForegroundInitializer.swift */; }; - 0E6BAEA923856A01003A2D4C /* Montserrat-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6486971120E0439200CCD7C1 /* Montserrat-Regular.ttf */; }; - 0E6BAEAA23856A01003A2D4C /* About.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20EE22B7D1580015F9E0 /* About.storyboard */; }; - 0E6BAEAB23856A01003A2D4C /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0ECDF1B42313D65500A09ACA /* GoogleService-Info.plist */; }; - 0E6BAEAC23856A01003A2D4C /* DiscoverWebTagsInfoHeaderFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E3FF734238157B700EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.xib */; }; - 0E6BAEAE23856A01003A2D4C /* Foreground.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0ECFF35623505F8D0061D11B /* Foreground.storyboard */; }; - 0E6BAEAF23856A01003A2D4C /* LocationPicker.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E046F4522F17EF400BD4E9C /* LocationPicker.storyboard */; }; - 0E6BAEB023856A01003A2D4C /* Defaults.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E8A100123845E5100A9CBA6 /* Defaults.storyboard */; }; - 0E6BAEB123856A01003A2D4C /* Cards.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C1DD022B3BDFC0032F6CA /* Cards.storyboard */; }; - 0E6BAEB223856A01003A2D4C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 64333D3120B0C45A00CDF4B6 /* LaunchScreen.storyboard */; }; - 0E6BAEB423856A01003A2D4C /* Oswald-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6486970F20E042E000CCD7C1 /* Oswald-Bold.ttf */; }; - 0E6BAEB523856A01003A2D4C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20C922B7A7200015F9E0 /* Localizable.strings */; }; - 0E6BAEB623856A01003A2D4C /* Discover.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E09672722AE8D7A00E85F48 /* Discover.storyboard */; }; - 0E6BAEB723856A01003A2D4C /* TagSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EF2862B22CBAF5D0026C7A5 /* TagSettings.storyboard */; }; - 0E6BAEB823856A01003A2D4C /* TagCharts.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E8FD0BE23335D6900FFA577 /* TagCharts.storyboard */; }; - 0E6BAEB923856A01003A2D4C /* Muli-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6467818F225CFB170072856A /* Muli-Regular.ttf */; }; - 0E6BAEBA23856A01003A2D4C /* Oswald-ExtraLight.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 643EEC2A2266435100D4E837 /* Oswald-ExtraLight.ttf */; }; - 0E6BAEBB23856A01003A2D4C /* Language.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EBAF06B232006E00025A191 /* Language.storyboard */; }; - 0E6BAEBC23856A01003A2D4C /* Welcome.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E09671F22AE7F5C00E85F48 /* Welcome.storyboard */; }; - 0E6BAEBD23856A01003A2D4C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0E53A3F3232DFC6200ACED49 /* InfoPlist.strings */; }; - 0E6BAEBE23856A01003A2D4C /* ActivityRuuviLogo.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C1DB422B3903B0032F6CA /* ActivityRuuviLogo.storyboard */; }; - 0E6BAEBF23856A01003A2D4C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 64333D2F20B0C45A00CDF4B6 /* Assets.xcassets */; }; - 0E6BAEC123856A01003A2D4C /* CardView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C1E1222B756D30032F6CA /* CardView.xib */; }; - 0E6BAEC223856A01003A2D4C /* Menu.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF022B3FDE30032F6CA /* Menu.storyboard */; }; - 0E6BAEC323856A01003A2D4C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 64333D2C20B0C45900CDF4B6 /* Main.storyboard */; }; - 0E6BAEC423856A01003A2D4C /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20D022B7C6F30015F9E0 /* Settings.storyboard */; }; - 0E6BAEC523856A01003A2D4C /* Muli-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 64678190225D02CE0072856A /* Muli-Bold.ttf */; }; - 0E6BAEC623856A01003A2D4C /* TagSettingsMoreInfoHeaderFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E62AECA22E065F000A49BFB /* TagSettingsMoreInfoHeaderFooterView.xib */; }; - 0E6BAEC723856A01003A2D4C /* Montserrat-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 643C651E21C38F490037BE5B /* Montserrat-Bold.ttf */; }; - 0E6BAEC823856A01003A2D4C /* WebTagSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E046F2622F04A0300BD4E9C /* WebTagSettings.storyboard */; }; - 0E79F28D244328D50048BF86 /* DiscoverAddWithMACTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E79F28A244328D50048BF86 /* DiscoverAddWithMACTableViewCell.swift */; }; - 0E92A97B268636F700187E4F /* TemperatureUnit+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A972268636F500187E4F /* TemperatureUnit+Localization.swift */; }; - 0E92A97C268636F700187E4F /* ExportHeadersProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A974268636F500187E4F /* ExportHeadersProvider.swift */; }; - 0E92A97D268636F700187E4F /* HeartbeatDaemonTitles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A975268636F500187E4F /* HeartbeatDaemonTitles.swift */; }; - 0E92A97E268636F700187E4F /* RuuviNotifierTitlesImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A976268636F500187E4F /* RuuviNotifierTitlesImpl.swift */; }; - 0E92A97F268636F700187E4F /* VirtualLocation+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A977268636F600187E4F /* VirtualLocation+Localization.swift */; }; - 0E92A980268636F700187E4F /* HumidityUnit+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A978268636F600187E4F /* HumidityUnit+Localization.swift */; }; - 0E92A981268636F700187E4F /* MeasurementType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A979268636F600187E4F /* MeasurementType.swift */; }; - 0E92A982268636F700187E4F /* Language+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A97A268636F700187E4F /* Language+Localization.swift */; }; - 0E92A9842686370000187E4F /* RUError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9832686370000187E4F /* RUError.swift */; }; - 0E92A9862686371F00187E4F /* DateValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9852686371E00187E4F /* DateValueFormatter.swift */; }; - 0E92A9882686373000187E4F /* Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E92A9872686373000187E4F /* Debouncer.swift */; }; - 0E92A98A2686373900187E4F /* RuuviServiceGATT in Frameworks */ = {isa = PBXBuildFile; productRef = 0E92A9892686373900187E4F /* RuuviServiceGATT */; }; - 0E9E775C238CCE5F006D7013 /* String+Replace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9E7759238CCE5F006D7013 /* String+Replace.swift */; }; - 0EA796732664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796702664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift */; }; - 0EA796772664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796742664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift */; }; - 0EA7967B2664B37F002BA25D /* RuuviLocalError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796782664B37F002BA25D /* RuuviLocalError+LocalizedError.swift */; }; - 0EA7967F2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA7967C2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift */; }; - 0EA796832664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796802664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift */; }; - 0EA796872664B84D002BA25D /* RuuviReactorError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796842664B84D002BA25D /* RuuviReactorError+LocalizedError.swift */; }; - 0EA7968B2664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796882664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift */; }; - 0EA7968F2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA7968C2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift */; }; - 0EA92FDD2387E734008F1558 /* TagSettingsAlertsHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA92FDA2387E734008F1558 /* TagSettingsAlertsHeaderFooterView.swift */; }; - 0EA92FE12387E74C008F1558 /* TagSettingsAlertsHeaderFooterView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0EA92FDE2387E74C008F1558 /* TagSettingsAlertsHeaderFooterView.xib */; }; - 0EAD33D62399272000EC5BAA /* DiscoverModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF4C239795AF00A37E1A /* DiscoverModuleOutput.swift */; }; - 0EAD33E52399273E00EC5BAA /* Heartbeat.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E84BF542397F29800A37E1A /* Heartbeat.storyboard */; }; - 0EAD33E62399273E00EC5BAA /* HeartbeatInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF6E2398031B00A37E1A /* HeartbeatInitializer.swift */; }; - 0EAD33E72399273E00EC5BAA /* HeartbeatConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF702398035C00A37E1A /* HeartbeatConfigurator.swift */; }; - 0EAD33E82399273E00EC5BAA /* HeartbeatModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF6A239802A400A37E1A /* HeartbeatModuleInput.swift */; }; - 0EAD33E92399273E00EC5BAA /* HeartbeatPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF6C239802CA00A37E1A /* HeartbeatPresenter.swift */; }; - 0EAD33EA2399273E00EC5BAA /* HeartbeatRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF66239801AF00A37E1A /* HeartbeatRouterInput.swift */; }; - 0EAD33EB2399273E00EC5BAA /* HeartbeatRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF68239801C100A37E1A /* HeartbeatRouter.swift */; }; - 0EAD33EC2399273E00EC5BAA /* HeartbeatList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF622397F76A00A37E1A /* HeartbeatList.swift */; }; - 0EAD33ED2399273E00EC5BAA /* HeartbeatEnvironmentObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF602397F73100A37E1A /* HeartbeatEnvironmentObject.swift */; }; - 0EAD33EE2399273E00EC5BAA /* HeartbeatTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF642397F9DC00A37E1A /* HeartbeatTableViewController.swift */; }; - 0EAD33EF2399273E00EC5BAA /* HeartbeatViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF562397F33E00A37E1A /* HeartbeatViewInput.swift */; }; - 0EAD33F02399273E00EC5BAA /* HeartbeatViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF582397F3C600A37E1A /* HeartbeatViewModel.swift */; }; - 0EAD33F12399273E00EC5BAA /* HeartbeatViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF5A2397F3DF00A37E1A /* HeartbeatViewOutput.swift */; }; - 0EAD33F22399273E00EC5BAA /* HeartbeatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF5E2397F6BE00A37E1A /* HeartbeatViewController.swift */; }; - 0EB48DE8261A1816008E0D2D /* FeatureToggles.json in Resources */ = {isa = PBXBuildFile; fileRef = 0EB48DE5261A1816008E0D2D /* FeatureToggles.json */; }; - 0EB66B3C2686058F00375BCC /* FeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B2E2686058F00375BCC /* FeatureToggleProvider.swift */; }; - 0EB66B3D2686058F00375BCC /* FallbackFeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B2F2686058F00375BCC /* FallbackFeatureToggleProvider.swift */; }; - 0EB66B3E2686058F00375BCC /* FirebaseFeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B302686058F00375BCC /* FirebaseFeatureToggleProvider.swift */; }; - 0EB66B3F2686058F00375BCC /* LocalFeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B312686058F00375BCC /* LocalFeatureToggleProvider.swift */; }; - 0EB66B402686058F00375BCC /* FirebaseRemoteConfigService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B342686058F00375BCC /* FirebaseRemoteConfigService.swift */; }; - 0EB66B412686058F00375BCC /* RemoteConfigService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B352686058F00375BCC /* RemoteConfigService.swift */; }; - 0EB66B422686058F00375BCC /* FeatureToggleService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B362686058F00375BCC /* FeatureToggleService.swift */; }; - 0EB66B432686058F00375BCC /* FeatureToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B372686058F00375BCC /* FeatureToggle.swift */; }; - 0EB66B442686058F00375BCC /* InfoProviderImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B3A2686058F00375BCC /* InfoProviderImpl.swift */; }; - 0EB66B452686058F00375BCC /* InfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB66B3B2686058F00375BCC /* InfoProvider.swift */; }; - 0EB8B91D2683525900FE130E /* RuuviMigration in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB8B91C2683525900FE130E /* RuuviMigration */; }; - 0EB8B91F2683525900FE130E /* RuuviMigrationImpl in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB8B91E2683525900FE130E /* RuuviMigrationImpl */; }; - 0EB8B92E2683599100FE130E /* Networking.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0EB8B92D2683599100FE130E /* Networking.plist */; }; - 0EB8B93C26837B6900FE130E /* RuuviCoreDiff in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB8B93B26837B6900FE130E /* RuuviCoreDiff */; }; - 0EB8B93E26837B6900FE130E /* RuuviCorePermission in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB8B93D26837B6900FE130E /* RuuviCorePermission */; }; - 0EB8B94026837B6A00FE130E /* RuuviCorePN in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB8B93F26837B6A00FE130E /* RuuviCorePN */; }; - 0EB97865267C769E0032CC05 /* RuuviPersistenceRealm in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB97864267C769E0032CC05 /* RuuviPersistenceRealm */; }; - 0EB97867267C769E0032CC05 /* RuuviPersistenceSQLite in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB97866267C769E0032CC05 /* RuuviPersistenceSQLite */; }; - 0EB97869267C7B640032CC05 /* RuuviDaemonCloudSync in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB97868267C7B640032CC05 /* RuuviDaemonCloudSync */; }; - 0EB9786B267C7B6C0032CC05 /* RuuviStorageCoordinator in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB9786A267C7B6C0032CC05 /* RuuviStorageCoordinator */; }; - 0EB9786D267C85BE0032CC05 /* RuuviPoolCoordinator in Frameworks */ = {isa = PBXBuildFile; productRef = 0EB9786C267C85BE0032CC05 /* RuuviPoolCoordinator */; }; - 0EBE42C7267C8A97002888EC /* RuuviReactorImpl in Frameworks */ = {isa = PBXBuildFile; productRef = 0EBE42C6267C8A97002888EC /* RuuviReactorImpl */; }; - 0EBE42C9267C8A9B002888EC /* RuuviRepositoryCoordinator in Frameworks */ = {isa = PBXBuildFile; productRef = 0EBE42C8267C8A9B002888EC /* RuuviRepositoryCoordinator */; }; - 0EBE42CB267C8AA1002888EC /* RuuviUserCoordinator in Frameworks */ = {isa = PBXBuildFile; productRef = 0EBE42CA267C8AA1002888EC /* RuuviUserCoordinator */; }; - 0EBE42D1267CA726002888EC /* Localize_Swift in Frameworks */ = {isa = PBXBuildFile; productRef = 0EBE42D0267CA726002888EC /* Localize_Swift */; }; - 0EBE42D4267CA889002888EC /* BTKit in Frameworks */ = {isa = PBXBuildFile; productRef = 0EBE42D3267CA889002888EC /* BTKit */; }; - 0EE11235267BBDC1008DA8D9 /* RuuviCloud in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE11234267BBDC1008DA8D9 /* RuuviCloud */; }; - 0EE11237267BBDC1008DA8D9 /* RuuviCloudApi in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE11236267BBDC1008DA8D9 /* RuuviCloudApi */; }; - 0EE11239267BBDC1008DA8D9 /* RuuviCloudPure in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE11238267BBDC1008DA8D9 /* RuuviCloudPure */; }; - 0EE1123B267BBDC1008DA8D9 /* RuuviContext in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE1123A267BBDC1008DA8D9 /* RuuviContext */; }; - 0EE1123D267BBDC1008DA8D9 /* RuuviCore in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE1123C267BBDC1008DA8D9 /* RuuviCore */; }; - 0EE11241267BBDC1008DA8D9 /* RuuviLocal in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE11240267BBDC1008DA8D9 /* RuuviLocal */; }; - 0EE11243267BBDC1008DA8D9 /* RuuviLocalUserDefaults in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE11242267BBDC1008DA8D9 /* RuuviLocalUserDefaults */; }; - 0EE11245267BBDC1008DA8D9 /* RuuviOntology in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE11244267BBDC1008DA8D9 /* RuuviOntology */; }; - 0EE11247267BBDC1008DA8D9 /* RuuviPersistence in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE11246267BBDC1008DA8D9 /* RuuviPersistence */; }; - 0EE11249267BBDC1008DA8D9 /* RuuviPool in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE11248267BBDC1008DA8D9 /* RuuviPool */; }; - 0EE1124D267BBDC1008DA8D9 /* RuuviRepository in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE1124C267BBDC1008DA8D9 /* RuuviRepository */; }; - 0EE1124F267BBDC1008DA8D9 /* RuuviService in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE1124E267BBDC1008DA8D9 /* RuuviService */; }; - 0EE11251267BBDC1008DA8D9 /* RuuviStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE11250267BBDC1008DA8D9 /* RuuviStorage */; }; - 0EE11253267BBDC1008DA8D9 /* RuuviUser in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE11252267BBDC1008DA8D9 /* RuuviUser */; }; - 0EE1125C267BC327008DA8D9 /* LightRoute in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE1125B267BC327008DA8D9 /* LightRoute */; }; - 0EE1125F267BC34A008DA8D9 /* RuuviReactor in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE1125E267BC34A008DA8D9 /* RuuviReactor */; }; - 0EE11262267BC395008DA8D9 /* Swinject in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE11261267BC395008DA8D9 /* Swinject */; }; - 0EE11265267BC3CC008DA8D9 /* NordicDFU in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE11264267BC3CC008DA8D9 /* NordicDFU */; }; - 0EE11268267BC477008DA8D9 /* RangeSeekSlider in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE11267267BC477008DA8D9 /* RangeSeekSlider */; }; - 0EE1126B267BC4A7008DA8D9 /* GestureInstructions in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE1126A267BC4A7008DA8D9 /* GestureInstructions */; }; - 0EE11270267BC5D6008DA8D9 /* FirebaseRemoteConfig in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE1126F267BC5D6008DA8D9 /* FirebaseRemoteConfig */; }; - 0EE11272267BC5D6008DA8D9 /* FirebaseCrashlytics in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE11271267BC5D6008DA8D9 /* FirebaseCrashlytics */; }; - 0EE11275267BC751008DA8D9 /* SwinjectPropertyLoader in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE11274267BC751008DA8D9 /* SwinjectPropertyLoader */; }; - 0EE11278267BC7A3008DA8D9 /* RuuviDaemon in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE11277267BC7A3008DA8D9 /* RuuviDaemon */; }; - 0EE1127B267BC7E3008DA8D9 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE1127A267BC7E3008DA8D9 /* RxSwift */; }; - 0EE36E98269749DF0021B746 /* FirmwareRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E82269749DE0021B746 /* FirmwareRepository.swift */; }; - 0EE36E99269749DF0021B746 /* DFUModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E84269749DE0021B746 /* DFUModuleInput.swift */; }; - 0EE36E9A269749DF0021B746 /* DFUPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E85269749DE0021B746 /* DFUPresenter.swift */; }; - 0EE36E9B269749DF0021B746 /* Publishers+System.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E87269749DE0021B746 /* Publishers+System.swift */; }; - 0EE36E9C269749DF0021B746 /* URLSession+downloadTaskPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E88269749DE0021B746 /* URLSession+downloadTaskPublisher.swift */; }; - 0EE36E9D269749DF0021B746 /* View+Any.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E89269749DE0021B746 /* View+Any.swift */; }; - 0EE36E9E269749DF0021B746 /* Spinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E8B269749DE0021B746 /* Spinner.swift */; }; - 0EE36E9F269749DF0021B746 /* LargeButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E8C269749DE0021B746 /* LargeButtonStyle.swift */; }; - 0EE36EA0269749DF0021B746 /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E8D269749DE0021B746 /* ProgressBar.swift */; }; - 0EE36EA1269749DF0021B746 /* Feedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E8E269749DE0021B746 /* Feedback.swift */; }; - 0EE36EA2269749DF0021B746 /* DFUViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E90269749DE0021B746 /* DFUViewModel.swift */; }; - 0EE36EA3269749DF0021B746 /* DFUUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E92269749DE0021B746 /* DFUUIView.swift */; }; - 0EE36EA4269749DF0021B746 /* DFUInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E94269749DE0021B746 /* DFUInteractorInput.swift */; }; - 0EE36EA5269749DF0021B746 /* DFUInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E95269749DE0021B746 /* DFUInteractor.swift */; }; - 0EE36EA6269749DF0021B746 /* LatestRelease.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E96269749DE0021B746 /* LatestRelease.swift */; }; - 0EE36EA7269749DF0021B746 /* DFUModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E97269749DE0021B746 /* DFUModuleFactory.swift */; }; - 0EE36EAA269749F20021B746 /* RuuviColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36EA9269749F10021B746 /* RuuviColor.swift */; }; - 0EE36EBE269F06CA0021B746 /* Charts in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE36EBD269F06CA0021B746 /* Charts */; }; - 0EE49B9723B74775003012C2 /* WebTagSettingsAlertHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE49B9423B74775003012C2 /* WebTagSettingsAlertHeaderCell.swift */; }; - 0EE49B9B23B877CF003012C2 /* WebTagSettingsAlertControlsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE49B9823B877CF003012C2 /* WebTagSettingsAlertControlsCell.swift */; }; - 0EE98A7B26493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE98A7826493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift */; }; - 0EF00EFF267C6A930082AA8D /* RuuviContextRealm in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF00EFE267C6A930082AA8D /* RuuviContextRealm */; }; - 0EF00F01267C6A960082AA8D /* RuuviContextSQLite in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF00F00267C6A960082AA8D /* RuuviContextSQLite */; }; - 0EF00F03267C6B160082AA8D /* RuuviServiceFactory in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF00F02267C6B160082AA8D /* RuuviServiceFactory */; }; - 0EF4E31126823F3D00D83CC7 /* RuuviCoreError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF4E30F26823F3D00D83CC7 /* RuuviCoreError+LocalizedError.swift */; }; - 0EF4E31226823F3D00D83CC7 /* RuuviVirtualError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF4E31026823F3D00D83CC7 /* RuuviVirtualError+LocalizedError.swift */; }; - 0EF4E31826823F6100D83CC7 /* DiscoverRuuviTagViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF4E31626823F6100D83CC7 /* DiscoverRuuviTagViewModel.swift */; }; - 0EF4E31926823F6100D83CC7 /* DiscoverVirtualTagViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF4E31726823F6100D83CC7 /* DiscoverVirtualTagViewModel.swift */; }; - 0EF4E31D2682403500D83CC7 /* RuuviCoreLocation in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E31C2682403500D83CC7 /* RuuviCoreLocation */; }; - 0EF4E31F2682403500D83CC7 /* RuuviLocation in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E31E2682403500D83CC7 /* RuuviLocation */; }; - 0EF4E3212682403500D83CC7 /* RuuviLocationService in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E3202682403500D83CC7 /* RuuviLocationService */; }; - 0EF4E3232682403500D83CC7 /* RuuviVirtual in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E3222682403500D83CC7 /* RuuviVirtual */; }; - 0EF4E3252682403500D83CC7 /* RuuviVirtualModel in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E3242682403500D83CC7 /* RuuviVirtualModel */; }; - 0EF4E3272682403500D83CC7 /* RuuviVirtualOWM in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E3262682403500D83CC7 /* RuuviVirtualOWM */; }; - 0EF4E3292682403500D83CC7 /* RuuviVirtualPersistence in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E3282682403500D83CC7 /* RuuviVirtualPersistence */; }; - 0EF4E32B2682403500D83CC7 /* RuuviVirtualReactor in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E32A2682403500D83CC7 /* RuuviVirtualReactor */; }; - 0EF4E32D2682403500D83CC7 /* RuuviVirtualRepository in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E32C2682403500D83CC7 /* RuuviVirtualRepository */; }; - 0EF4E32F2682403500D83CC7 /* RuuviVirtualService in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E32E2682403500D83CC7 /* RuuviVirtualService */; }; - 0EF4E3312682403500D83CC7 /* RuuviVirtualStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E3302682403500D83CC7 /* RuuviVirtualStorage */; }; - 0EF4E35226831A0C00D83CC7 /* DfuFirmware+Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF4E35126831A0B00D83CC7 /* DfuFirmware+Log.swift */; }; - 0EF4E35726831B1100D83CC7 /* RuuviDFU in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E35626831B1100D83CC7 /* RuuviDFU */; }; - 0EF4E35926831B1100D83CC7 /* RuuviDFUImpl in Frameworks */ = {isa = PBXBuildFile; productRef = 0EF4E35826831B1100D83CC7 /* RuuviDFUImpl */; }; - 660EB25A2669278E000FD22B /* DfuDevicesScannerConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2462669278E000FD22B /* DfuDevicesScannerConfigurator.swift */; }; - 660EB25D2669278E000FD22B /* DfuDevicesScannerInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2472669278E000FD22B /* DfuDevicesScannerInitializer.swift */; }; - 660EB2602669278E000FD22B /* DfuDevicesScannerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2492669278E000FD22B /* DfuDevicesScannerPresenter.swift */; }; - 660EB2632669278E000FD22B /* DfuDevicesScannerModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB24A2669278E000FD22B /* DfuDevicesScannerModuleInput.swift */; }; - 660EB2662669278E000FD22B /* DfuDevicesScannerModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB24B2669278E000FD22B /* DfuDevicesScannerModuleOutput.swift */; }; - 660EB2692669278E000FD22B /* DfuNoDeviceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB24E2669278E000FD22B /* DfuNoDeviceTableViewCell.swift */; }; - 660EB26C2669278E000FD22B /* DfuDeviceTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB24F2669278E000FD22B /* DfuDeviceTableViewCell.swift */; }; - 660EB26F2669278E000FD22B /* DfuDevicesScannerViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2502669278E000FD22B /* DfuDevicesScannerViewInput.swift */; }; - 660EB2722669278E000FD22B /* DfuDevicesScannerTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2512669278E000FD22B /* DfuDevicesScannerTableViewController.swift */; }; - 660EB2752669278E000FD22B /* DfuDevicesScannerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2522669278E000FD22B /* DfuDevicesScannerViewModel.swift */; }; - 660EB2782669278E000FD22B /* DfuDevicesScannerViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2532669278E000FD22B /* DfuDevicesScannerViewOutput.swift */; }; - 660EB27B2669278E000FD22B /* DfuDevicesScanner.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 660EB2542669278E000FD22B /* DfuDevicesScanner.storyboard */; }; - 660EB27E2669278E000FD22B /* DfuDevicesScannerRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2562669278E000FD22B /* DfuDevicesScannerRouterInput.swift */; }; - 660EB2812669278E000FD22B /* DfuDevicesScannerRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB2572669278E000FD22B /* DfuDevicesScannerRouter.swift */; }; - 660EB29E266928E6000FD22B /* UIViewController+Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB29B266928E6000FD22B /* UIViewController+Alert.swift */; }; - 663155DF2667F40C005B90A6 /* UpdateFirmwareAppleInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155CD2667F40C005B90A6 /* UpdateFirmwareAppleInitializer.swift */; }; - 663155E22667F40C005B90A6 /* UpdateFirmwareConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155CE2667F40C005B90A6 /* UpdateFirmwareConfigurator.swift */; }; - 663155E52667F40C005B90A6 /* UpdateFirmwarePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D02667F40C005B90A6 /* UpdateFirmwarePresenter.swift */; }; - 663155E82667F40C005B90A6 /* UpdateFirmwareModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D12667F40C005B90A6 /* UpdateFirmwareModuleOutput.swift */; }; - 663155EB2667F40C005B90A6 /* UpdateFirmwareModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D22667F40C005B90A6 /* UpdateFirmwareModuleInput.swift */; }; - 663155EE2667F40C005B90A6 /* UpdateFirmwareAppleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D52667F40C005B90A6 /* UpdateFirmwareAppleViewController.swift */; }; - 663155F12667F40C005B90A6 /* UpdateFirmwareViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D62667F40C005B90A6 /* UpdateFirmwareViewOutput.swift */; }; - 663155F42667F40C005B90A6 /* UpdateFirmwareViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155D72667F40C005B90A6 /* UpdateFirmwareViewInput.swift */; }; - 663155FA2667F40C005B90A6 /* UpdateFirmware.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 663155D92667F40C005B90A6 /* UpdateFirmware.storyboard */; }; - 663155FD2667F40C005B90A6 /* UpdateFirmwareRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155DB2667F40C005B90A6 /* UpdateFirmwareRouter.swift */; }; - 663156002667F40C005B90A6 /* UpdateFirmwareRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663155DC2667F40C005B90A6 /* UpdateFirmwareRouterInput.swift */; }; - 66718A3C266A685700A380F8 /* DfuFlashAppleInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A28266A685700A380F8 /* DfuFlashAppleInitializer.swift */; }; - 66718A3F266A685700A380F8 /* DfuFlashConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A29266A685700A380F8 /* DfuFlashConfigurator.swift */; }; - 66718A42266A685700A380F8 /* DfuFlashModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A2B266A685700A380F8 /* DfuFlashModuleInput.swift */; }; - 66718A45266A685700A380F8 /* DfuFlashModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A2C266A685700A380F8 /* DfuFlashModuleOutput.swift */; }; - 66718A48266A685700A380F8 /* DfuFlashPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A2D266A685700A380F8 /* DfuFlashPresenter.swift */; }; - 66718A4B266A685700A380F8 /* DfuFlashAppleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A30266A685700A380F8 /* DfuFlashAppleViewController.swift */; }; - 66718A4E266A685700A380F8 /* DfuLogTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A32266A685700A380F8 /* DfuLogTableViewCell.swift */; }; - 66718A51266A685700A380F8 /* DfuFlashViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A33266A685700A380F8 /* DfuFlashViewModel.swift */; }; - 66718A54266A685700A380F8 /* DfuFlashViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A34266A685700A380F8 /* DfuFlashViewInput.swift */; }; - 66718A57266A685700A380F8 /* DfuFlashViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A35266A685700A380F8 /* DfuFlashViewOutput.swift */; }; - 66718A5A266A685700A380F8 /* DfuFlash.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 66718A36266A685700A380F8 /* DfuFlash.storyboard */; }; - 66718A5D266A685700A380F8 /* DfuFlashRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A38266A685700A380F8 /* DfuFlashRouter.swift */; }; - 66718A60266A685700A380F8 /* DfuFlashRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A39266A685700A380F8 /* DfuFlashRouterInput.swift */; }; - 66718A67266A6CA700A380F8 /* DfuFilePickerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A62266A6CA700A380F8 /* DfuFilePickerPresenter.swift */; }; - 66718A6A266A6CA700A380F8 /* DfuFilePickerPresenterSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A64266A6CA700A380F8 /* DfuFilePickerPresenterSheet.swift */; }; - 66718A6E266BD0E800A380F8 /* Color+Ruuvi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A6B266BD0E800A380F8 /* Color+Ruuvi.swift */; }; - 66BC44972657AED400A03253 /* OffsetCorrection.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 66BC44832657AED400A03253 /* OffsetCorrection.storyboard */; }; - 66BC449A2657AED400A03253 /* OffsetCorrectionAppleInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44862657AED400A03253 /* OffsetCorrectionAppleInitializer.swift */; }; - 66BC449D2657AED400A03253 /* OffsetCorrectionConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44872657AED400A03253 /* OffsetCorrectionConfigurator.swift */; }; - 66BC44A02657AED400A03253 /* OffsetCorrectionModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44892657AED400A03253 /* OffsetCorrectionModuleOutput.swift */; }; - 66BC44A32657AED400A03253 /* OffsetCorrectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448A2657AED400A03253 /* OffsetCorrectionPresenter.swift */; }; - 66BC44A62657AED400A03253 /* OffsetCorrectionModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448B2657AED400A03253 /* OffsetCorrectionModuleInput.swift */; }; - 66BC44A92657AED400A03253 /* OffsetCorrectionAppleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448E2657AED400A03253 /* OffsetCorrectionAppleViewController.swift */; }; - 66BC44AC2657AED400A03253 /* OffsetCorrectionViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448F2657AED400A03253 /* OffsetCorrectionViewInput.swift */; }; - 66BC44AF2657AED400A03253 /* OffsetCorrectionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44902657AED400A03253 /* OffsetCorrectionViewModel.swift */; }; - 66BC44B22657AED400A03253 /* OffsetCorrectionViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44912657AED400A03253 /* OffsetCorrectionViewOutput.swift */; }; - 66BC44B52657AED400A03253 /* OffsetCorrectionRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44932657AED400A03253 /* OffsetCorrectionRouter.swift */; }; - 66BC44B82657AED400A03253 /* OffsetCorrectionRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44942657AED400A03253 /* OffsetCorrectionRouterInput.swift */; }; - A907A1D5245F7C6600041F6E /* ProgressBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A907A1D2245F7C6600041F6E /* ProgressBarView.swift */; }; - A907A1D92460376600041F6E /* TagChartViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A907A1D62460376600041F6E /* TagChartViewModel.swift */; }; - A907BB1324AE620E009DA3DB /* UIWindow+Orientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A907BB1024AE620A009DA3DB /* UIWindow+Orientation.swift */; }; - A90E169124604F7400631E6C /* TagChartPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E168E24604F7400631E6C /* TagChartPresenter.swift */; }; - A90E169524604FD100631E6C /* TagChartModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E169224604FD100631E6C /* TagChartModuleInput.swift */; }; - A90E16992460504C00631E6C /* TagChartModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E16962460504C00631E6C /* TagChartModuleOutput.swift */; }; - A90E169E24606ABF00631E6C /* TagChartsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E169B24606ABF00631E6C /* TagChartsInteractor.swift */; }; - A90E16A224606B0500631E6C /* TagChartsInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E169F24606B0500631E6C /* TagChartsInteractorInput.swift */; }; - A90E16A624606B2000631E6C /* TagChartsInteractorOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E16A324606B2000631E6C /* TagChartsInteractorOutput.swift */; }; - A90E16AB24609B9B00631E6C /* TagChartAssembler.swift in Sources */ = {isa = PBXBuildFile; fileRef = A90E16A82460975600631E6C /* TagChartAssembler.swift */; }; - A91D02F02511207200694733 /* SelectionTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02DD2511207200694733 /* SelectionTableConfigurator.swift */; }; - A91D02F32511207200694733 /* SelectionTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02DE2511207200694733 /* SelectionTableInitializer.swift */; }; - A91D02F62511207300694733 /* SelectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E02511207200694733 /* SelectionPresenter.swift */; }; - A91D02F92511207300694733 /* SelectionModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E12511207200694733 /* SelectionModuleInput.swift */; }; - A91D02FC2511207300694733 /* SelectionViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E32511207200694733 /* SelectionViewInput.swift */; }; - A91D02FF2511207300694733 /* SelectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E52511207200694733 /* SelectionTableViewCell.swift */; }; - A91D03022511207300694733 /* SelectionTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E62511207200694733 /* SelectionTableViewController.swift */; }; - A91D03052511207300694733 /* SelectionViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E72511207200694733 /* SelectionViewOutput.swift */; }; - A91D03082511207300694733 /* SelectionRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E92511207200694733 /* SelectionRouter.swift */; }; - A91D030B2511207300694733 /* SelectionRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02EA2511207200694733 /* SelectionRouterInput.swift */; }; - A91D030F251121C800694733 /* Selection.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A91D030C251121C800694733 /* Selection.storyboard */; }; - A91D0313251123B400694733 /* SelectionModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D0310251123B400694733 /* SelectionModuleOutput.swift */; }; - A91D0318251124F900694733 /* SelectionItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D0315251124F900694733 /* SelectionItem.swift */; }; - A91D031C25113EAA00694733 /* UnitPressure+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D031925113EAA00694733 /* UnitPressure+Extension.swift */; }; - A92A66BF2450C64B002918E7 /* UITableViewCell+ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92A66BC2450C640002918E7 /* UITableViewCell+ReusableView.swift */; }; - A92E3C5C2426428E00D981D5 /* TagChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92E3C592426415100D981D5 /* TagChartView.swift */; }; - A92E3C65242644B800D981D5 /* TagChartViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92E3C62242644B800D981D5 /* TagChartViewInput.swift */; }; - A93052BA242BFCF900FB62B1 /* TagChartViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93052B7242BFCC000FB62B1 /* TagChartViewOutput.swift */; }; - A93CDCAD25657C1D00018C6C /* MenuViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93CDCAA25657C1D00018C6C /* MenuViewModel.swift */; }; - A93CDCD125659BA600018C6C /* AlertPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93CDCCE25659BA600018C6C /* AlertPresenter.swift */; }; - A93CDCE025659BF600018C6C /* AlertPresenterImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93CDCDD25659BF600018C6C /* AlertPresenterImpl.swift */; }; - A949A83D24707FDE006B7F4F /* LocalizedCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949A83A24707FD0006B7F4F /* LocalizedCache.swift */; }; - A9646468247BAE6B0001D55D /* AdvancedViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646454247BAE6A0001D55D /* AdvancedViewInput.swift */; }; - A964646E247BAE6B0001D55D /* AdvancedStepperTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646458247BAE6A0001D55D /* AdvancedStepperTableViewCell.swift */; }; - A9646471247BAE6B0001D55D /* AdvancedSwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646459247BAE6A0001D55D /* AdvancedSwitchTableViewCell.swift */; }; - A9646474247BAE6B0001D55D /* AdvancedTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645A247BAE6A0001D55D /* AdvancedTableViewController.swift */; }; - A9646477247BAE6B0001D55D /* AdvancedViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645B247BAE6A0001D55D /* AdvancedViewOutput.swift */; }; - A964647A247BAE6B0001D55D /* AdvancedViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645C247BAE6A0001D55D /* AdvancedViewModel.swift */; }; - A964647D247BAE6B0001D55D /* AdvancedConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645E247BAE6A0001D55D /* AdvancedConfigurator.swift */; }; - A9646480247BAE6B0001D55D /* AdvancedInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645F247BAE6A0001D55D /* AdvancedInitializer.swift */; }; - A9646483247BAE6B0001D55D /* AdvancedModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646461247BAE6A0001D55D /* AdvancedModuleInput.swift */; }; - A9646486247BAE6B0001D55D /* AdvancedPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646462247BAE6A0001D55D /* AdvancedPresenter.swift */; }; - A9646489247BAE6B0001D55D /* AdvancedRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646464247BAE6A0001D55D /* AdvancedRouterInput.swift */; }; - A964648C247BAE6B0001D55D /* AdvancedRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646465247BAE6A0001D55D /* AdvancedRouter.swift */; }; - A9646490247BAEBA0001D55D /* AdvancedSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A964648D247BAEBA0001D55D /* AdvancedSettings.storyboard */; }; - A976CA8024A928C20099BDC1 /* AdvancedDisclosureTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A976CA7D24A928C20099BDC1 /* AdvancedDisclosureTableViewCell.swift */; }; - A980573A25807118000D03AB /* AboutViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A980573725807118000D03AB /* AboutViewModel.swift */; }; - A98BC877250E4265001CEFDC /* Double+Round.swift in Sources */ = {isa = PBXBuildFile; fileRef = A98BC874250E4265001CEFDC /* Double+Round.swift */; }; - A98D3F00256CBD400066588B /* ShareModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AE2284D927021C0BEA560B0 /* ShareModuleInput.swift */; }; - A98D3F16256CBD610066588B /* ShareConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB681E62A66E5924A87859B1 /* ShareConfigurator.swift */; }; - A98D3F17256CBD610066588B /* ShareInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 392F0E992BEAA3382C2CF709 /* ShareInitializer.swift */; }; - A98D3F18256CBD610066588B /* ShareRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9546F1EFEE8F8CFC22377BB4 /* ShareRouterInput.swift */; }; - A98D3F19256CBD610066588B /* ShareViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 167F75FD2FDAD002C10686FA /* ShareViewInput.swift */; }; - A98D3F1A256CBD610066588B /* ShareViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 354B5B6F50E98F55D6A672BA /* ShareViewModel.swift */; }; - A98D3F1B256CBD610066588B /* ShareRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD7AE39C23B8C52BB202BB5E /* ShareRouter.swift */; }; - A98D3F1C256CBD610066588B /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC417B8977A47FFAE71585F0 /* ShareViewController.swift */; }; - A98D3F1D256CBD610066588B /* SharePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC1D67615D6DBA9E2FC5B402 /* SharePresenter.swift */; }; - A98D3F1E256CBD610066588B /* ShareModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5710E4EF18D419D01D60405E /* ShareModuleOutput.swift */; }; - A98D3F1F256CBD610066588B /* ShareViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE5C4AD5C54EF024669EAF47 /* ShareViewOutput.swift */; }; - A9A67BFC24C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9A67BF924C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift */; }; - A9B57438253B992A00DB7353 /* SignIn.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A9B5742C253B978D00DB7353 /* SignIn.storyboard */; }; - A9B57440253B993200DB7353 /* SignInConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B469B53431F206F4D0EC60 /* SignInConfigurator.swift */; }; - A9B5744B253B994900DB7353 /* SignInRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E816312622E83E3B42001DC /* SignInRouterInput.swift */; }; - A9B5744C253B994900DB7353 /* SignInRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F0552F1D17F403B7DE508B5 /* SignInRouter.swift */; }; - A9B5744D253B994900DB7353 /* SignInViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A7D6325DFC865D2D11BD1D1 /* SignInViewInput.swift */; }; - A9B5744E253B994900DB7353 /* SignInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6DB40883B83C652584EBB9A /* SignInViewController.swift */; }; - A9B5744F253B994900DB7353 /* SignInPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E29B5190CB557178D11AB2CE /* SignInPresenter.swift */; }; - A9B57450253B994900DB7353 /* SignInModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87EFB230083D471777FBE5D0 /* SignInModuleInput.swift */; }; - A9B57451253B994900DB7353 /* SignInModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B3006A5FB2173EC6AA2728D /* SignInModuleOutput.swift */; }; - A9B57452253B994900DB7353 /* SignInViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC59D3B5AD8926DBDD79AA1C /* SignInViewModel.swift */; }; - A9B57453253B994900DB7353 /* SignInInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85B8587156E1062D613B8960 /* SignInInitializer.swift */; }; - A9B57454253B994900DB7353 /* SignInViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BD498E7491E278B4EF4919C /* SignInViewOutput.swift */; }; - A9BB94CE2540AB610042B190 /* AlertViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BB94CB2540AB610042B190 /* AlertViewModel.swift */; }; - A9BD38BC24F6108300904BBE /* Humidity+Offset.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BD38B924F6108300904BBE /* Humidity+Offset.swift */; }; - A9E5994225572CF700F9E5CC /* Share.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A9E5993F25572CF700F9E5CC /* Share.storyboard */; }; - A9E5994C2557341F00F9E5CC /* ShareDescriptionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E599492557341F00F9E5CC /* ShareDescriptionTableViewCell.swift */; }; - A9E5995A2557345200F9E5CC /* ShareEmailInputTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E599572557345200F9E5CC /* ShareEmailInputTableViewCell.swift */; }; - A9E599632557346600F9E5CC /* ShareSendButtonTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E599602557346600F9E5CC /* ShareSendButtonTableViewCell.swift */; }; - A9E5996C255734A000F9E5CC /* ShareEmailTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E59969255734A000F9E5CC /* ShareEmailTableViewCell.swift */; }; - A9E6774A25A33081000B75A3 /* String+Characters.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E6774725A33081000B75A3 /* String+Characters.swift */; }; - A9F4471824B79959001E63AF /* TagSettingsModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9F4471524B79959001E63AF /* TagSettingsModuleOutput.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 0E02ABB9237598C600ED4629 /* RURangeSeekSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RURangeSeekSlider.swift; sourceTree = ""; }; - 0E02ABCA2379483A00ED4629 /* Double+Temperature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+Temperature.swift"; sourceTree = ""; }; - 0E046F2622F04A0300BD4E9C /* WebTagSettings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = WebTagSettings.storyboard; sourceTree = ""; }; - 0E046F2822F0561B00BD4E9C /* WebTagSettingsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsViewInput.swift; sourceTree = ""; }; - 0E046F2A22F0563100BD4E9C /* WebTagSettingsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsViewOutput.swift; sourceTree = ""; }; - 0E046F2D22F0569000BD4E9C /* WebTagSettingsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsTableViewController.swift; sourceTree = ""; }; - 0E046F2F22F057CC00BD4E9C /* WebTagSettingsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsRouterInput.swift; sourceTree = ""; }; - 0E046F3122F057DD00BD4E9C /* WebTagSettingsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsRouter.swift; sourceTree = ""; }; - 0E046F3322F057FC00BD4E9C /* WebTagSettingsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsModuleInput.swift; sourceTree = ""; }; - 0E046F3522F0581E00BD4E9C /* WebTagSettingsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsPresenter.swift; sourceTree = ""; }; - 0E046F3A22F05AA800BD4E9C /* WebTagSettingsTableInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsTableInitializer.swift; sourceTree = ""; }; - 0E046F3C22F05B0900BD4E9C /* WebTagSettingsTableConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsTableConfigurator.swift; sourceTree = ""; }; - 0E046F3E22F0702D00BD4E9C /* WebTagSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsViewModel.swift; sourceTree = ""; }; - 0E046F4522F17EF400BD4E9C /* LocationPicker.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LocationPicker.storyboard; sourceTree = ""; }; - 0E046F4722F181DA00BD4E9C /* LocationPickerViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerViewInput.swift; sourceTree = ""; }; - 0E046F4922F1820400BD4E9C /* LocationPickerViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerViewOutput.swift; sourceTree = ""; }; - 0E046F4C22F1823C00BD4E9C /* LocationPickerAppleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerAppleViewController.swift; sourceTree = ""; }; - 0E046F4E22F1827800BD4E9C /* LocationPickerRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerRouterInput.swift; sourceTree = ""; }; - 0E046F5022F1828900BD4E9C /* LocationPickerRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerRouter.swift; sourceTree = ""; }; - 0E046F5222F182AB00BD4E9C /* LocationPickerModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerModuleInput.swift; sourceTree = ""; }; - 0E046F5422F182BF00BD4E9C /* LocationPickerPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerPresenter.swift; sourceTree = ""; }; - 0E046F5722F182F500BD4E9C /* LocationPickerAppleInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerAppleInitializer.swift; sourceTree = ""; }; - 0E046F5922F1832600BD4E9C /* LocationPickerAppleConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerAppleConfigurator.swift; sourceTree = ""; }; - 0E046F6122F193B300BD4E9C /* LocationPickerModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerModuleOutput.swift; sourceTree = ""; }; - 0E05013E26860099007060C4 /* RuuviDaemonError+LocalizedError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RuuviDaemonError+LocalizedError.swift"; sourceTree = ""; }; - 0E05013F26860099007060C4 /* RuuviDFUError+LocalizedError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RuuviDFUError+LocalizedError.swift"; sourceTree = ""; }; - 0E05014C26860375007060C4 /* AppStateServiceImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppStateServiceImpl.swift; sourceTree = ""; }; - 0E05014D26860375007060C4 /* AppStateService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppStateService.swift; sourceTree = ""; }; - 0E05015126860375007060C4 /* UniversalLinkCoordinatormpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniversalLinkCoordinatormpl.swift; sourceTree = ""; }; - 0E05015226860375007060C4 /* UniversalLinkCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniversalLinkCoordinator.swift; sourceTree = ""; }; - 0E05015526860375007060C4 /* UniversalLinkRouterImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniversalLinkRouterImpl.swift; sourceTree = ""; }; - 0E05015626860375007060C4 /* UniversalLinkRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniversalLinkRouter.swift; sourceTree = ""; }; - 0E05015D26860385007060C4 /* ChartFilterOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartFilterOperation.swift; sourceTree = ""; }; - 0E09671F22AE7F5C00E85F48 /* Welcome.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Welcome.storyboard; sourceTree = ""; }; - 0E09672122AE7FCF00E85F48 /* WelcomeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeViewController.swift; sourceTree = ""; }; - 0E09672422AE897000E85F48 /* CALayer+IB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CALayer+IB.swift"; sourceTree = ""; }; - 0E09672722AE8D7A00E85F48 /* Discover.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Discover.storyboard; sourceTree = ""; }; - 0E09672B22AE94F000E85F48 /* DiscoverDeviceTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverDeviceTableViewCell.swift; sourceTree = ""; }; - 0E0A381823616AC3003A0364 /* UserDefaults+Optional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Optional.swift"; sourceTree = ""; }; - 0E197C6023C352380074015B /* TagSettingsAlertDescriptionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsAlertDescriptionCell.swift; sourceTree = ""; }; - 0E197C6523C4A47A0074015B /* MailComposerPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailComposerPresenter.swift; sourceTree = ""; }; - 0E197C6A23C4A52A0074015B /* MailComposerPresenterMessageUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailComposerPresenterMessageUI.swift; sourceTree = ""; }; - 0E197C6E23C4A7D00074015B /* Presentation.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Presentation.plist; sourceTree = ""; }; - 0E197C7C23C5CD7C0074015B /* UIDevice+ReadableModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+ReadableModel.swift"; sourceTree = ""; }; - 0E197C8023C5CDBE0074015B /* iOSDeviceModelMapping.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = iOSDeviceModelMapping.plist; sourceTree = ""; }; - 0E1B2F31239DEF120060C469 /* TagSettingsAlertHeaderCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsAlertHeaderCell.swift; sourceTree = ""; }; - 0E1B2F35239DF0120060C469 /* TagSettingsAlertControlsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsAlertControlsCell.swift; sourceTree = ""; }; - 0E1C1DA722B387A00032F6CA /* AppAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppAssembly.swift; sourceTree = ""; }; - 0E1C1DAE22B38F780032F6CA /* ActivityPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityPresenter.swift; sourceTree = ""; }; - 0E1C1DB222B390080032F6CA /* ActivityPresenterRuuviLogo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityPresenterRuuviLogo.swift; sourceTree = ""; }; - 0E1C1DB422B3903B0032F6CA /* ActivityRuuviLogo.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ActivityRuuviLogo.storyboard; sourceTree = ""; }; - 0E1C1DB622B390BC0032F6CA /* ActivityRuuviLogoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityRuuviLogoViewController.swift; sourceTree = ""; }; - 0E1C1DB822B390ED0032F6CA /* ActivitySpinnerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivitySpinnerView.swift; sourceTree = ""; }; - 0E1C1DBA22B3919F0032F6CA /* UIApplication+ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+ViewController.swift"; sourceTree = ""; }; - 0E1C1DBD22B3921E0032F6CA /* PresentationAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentationAssembly.swift; sourceTree = ""; }; - 0E1C1DC022B3955E0032F6CA /* ErrorPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorPresenter.swift; sourceTree = ""; }; - 0E1C1DC322B395C00032F6CA /* ErrorPresenterAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorPresenterAlert.swift; sourceTree = ""; }; - 0E1C1DD022B3BDFC0032F6CA /* Cards.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Cards.storyboard; sourceTree = ""; }; - 0E1C1DD222B3BF180032F6CA /* CardsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsViewInput.swift; sourceTree = ""; }; - 0E1C1DD422B3BF3A0032F6CA /* CardsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsViewOutput.swift; sourceTree = ""; }; - 0E1C1DDC22B3C2160032F6CA /* CardsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsModuleInput.swift; sourceTree = ""; }; - 0E1C1DDE22B3C2330032F6CA /* CardsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsPresenter.swift; sourceTree = ""; }; - 0E1C1DE122B3C25F0032F6CA /* CardsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsRouterInput.swift; sourceTree = ""; }; - 0E1C1DE322B3C2710032F6CA /* CardsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsRouter.swift; sourceTree = ""; }; - 0E1C1DE722B3C2B60032F6CA /* CardsScrollInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsScrollInitializer.swift; sourceTree = ""; }; - 0E1C1DE922B3C2E60032F6CA /* CardsScrollConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsScrollConfigurator.swift; sourceTree = ""; }; - 0E1C1DF022B3FDE30032F6CA /* Menu.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Menu.storyboard; sourceTree = ""; }; - 0E1C1DF222B3FEFF0032F6CA /* MenuViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuViewInput.swift; sourceTree = ""; }; - 0E1C1DF422B3FF1D0032F6CA /* MenuViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuViewOutput.swift; sourceTree = ""; }; - 0E1C1DF722B3FF480032F6CA /* MenuTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableViewController.swift; sourceTree = ""; }; - 0E1C1DF922B3FFBF0032F6CA /* MenuRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuRouterInput.swift; sourceTree = ""; }; - 0E1C1DFB22B3FFD90032F6CA /* MenuRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuRouter.swift; sourceTree = ""; }; - 0E1C1DFD22B3FFFC0032F6CA /* MenuModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuModuleInput.swift; sourceTree = ""; }; - 0E1C1DFF22B400130032F6CA /* MenuPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuPresenter.swift; sourceTree = ""; }; - 0E1C1E0222B400590032F6CA /* MenuTableInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableInitializer.swift; sourceTree = ""; }; - 0E1C1E0422B400890032F6CA /* MenuTableConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableConfigurator.swift; sourceTree = ""; }; - 0E1C1E0822B4024E0032F6CA /* MenuTableTransitioningDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableTransitioningDelegate.swift; sourceTree = ""; }; - 0E1C1E0A22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTablePresentTransitionAnimation.swift; sourceTree = ""; }; - 0E1C1E0C22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableDismissTransitionAnimation.swift; sourceTree = ""; }; - 0E1C1E0E22B4049E0032F6CA /* MenuTablePresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTablePresentationController.swift; sourceTree = ""; }; - 0E1C1E1022B756B40032F6CA /* CardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardView.swift; sourceTree = ""; }; - 0E1C1E1222B756D30032F6CA /* CardView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = CardView.xib; sourceTree = ""; }; - 0E211C29234C5FE900FC37B0 /* CardsRouterDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsRouterDelegate.swift; sourceTree = ""; }; - 0E2513592684A1D3004A522A /* RuuviNotification */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviNotification; path = Packages/RuuviNotification; sourceTree = ""; }; - 0E25136F2684D074004A522A /* RuuviNotifier */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviNotifier; path = Packages/RuuviNotifier; sourceTree = ""; }; - 0E290A842660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+AnyRuuviTagSensor.swift"; sourceTree = ""; }; - 0E2AFF9F266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviRepositoryError+LocalizedError.swift"; sourceTree = ""; }; - 0E31B04123BBA37C00660412 /* WebTagSettingsAlertsHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsAlertsHeaderFooterView.swift; sourceTree = ""; }; - 0E31B04523BBA3F900660412 /* WebTagSettingsAlertsHeaderFooterView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = WebTagSettingsAlertsHeaderFooterView.xib; sourceTree = ""; }; - 0E341BBC2372E75C0085BB54 /* TagChartsTransitionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsTransitionManager.swift; sourceTree = ""; }; - 0E3FF734238157B700EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DiscoverWebTagsInfoHeaderFooterView.xib; sourceTree = ""; }; - 0E3FF7362381591800EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscoverWebTagsInfoHeaderFooterView.swift; sourceTree = ""; }; - 0E502FBD22B2817900E8A6CC /* DiscoverRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverRouterInput.swift; sourceTree = ""; }; - 0E502FBF22B2819B00E8A6CC /* DiscoverRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverRouter.swift; sourceTree = ""; }; - 0E53A3F2232DFC6200ACED49 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 0E53A3F4232DFC6400ACED49 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = ""; }; - 0E53A3F5232DFC6500ACED49 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/InfoPlist.strings; sourceTree = ""; }; - 0E53A3FA232F4D5000ACED49 /* DiscoverNoDevicesTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverNoDevicesTableViewCell.swift; sourceTree = ""; }; - 0E53DA5F22CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeDownToDismissTransitioningDelegate.swift; sourceTree = ""; }; - 0E53DA6122CC93EB00BC6D64 /* SwipeDownToDismissTransitionAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeDownToDismissTransitionAnimation.swift; sourceTree = ""; }; - 0E53DA6322CC943900BC6D64 /* SwipeDownToDismissInteractiveTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeDownToDismissInteractiveTransition.swift; sourceTree = ""; }; - 0E53DA6622CC964200BC6D64 /* SwipeDownToDismissNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeDownToDismissNavigationController.swift; sourceTree = ""; }; - 0E5C300A22CF629100B52E39 /* PhotoPickerPresenterSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPickerPresenterSheet.swift; sourceTree = ""; }; - 0E5C301922CF644900B52E39 /* PermissionPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionPresenter.swift; sourceTree = ""; }; - 0E5C301B22CF646A00B52E39 /* PermissionPresenterAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionPresenterAlert.swift; sourceTree = ""; }; - 0E62298426A7FB4D0041DCDD /* OnboardRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OnboardRouter.swift; sourceTree = ""; }; - 0E62298526A7FB4D0041DCDD /* AppRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppRouter.swift; sourceTree = ""; }; - 0E62298826A7FB640041DCDD /* RuuviOnboard */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviOnboard; path = Modules/RuuviOnboard; sourceTree = ""; }; - 0E62AEC822E065CC00A49BFB /* TagSettingsMoreInfoHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsMoreInfoHeaderFooterView.swift; sourceTree = ""; }; - 0E62AECA22E065F000A49BFB /* TagSettingsMoreInfoHeaderFooterView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TagSettingsMoreInfoHeaderFooterView.xib; sourceTree = ""; }; - 0E6BAECE23856A01003A2D4C /* Ruuvi Station.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Ruuvi Station.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 0E70A45F22AF9567006CB87C /* ViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewInput.swift; sourceTree = ""; }; - 0E70A46222AF959E006CB87C /* Localizable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Localizable.swift; sourceTree = ""; }; - 0E70A46B22AF9705006CB87C /* DiscoverTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscoverTableViewController.swift; sourceTree = ""; }; - 0E70A46D22AF9763006CB87C /* DiscoverViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverViewInput.swift; sourceTree = ""; }; - 0E70A46F22AF9790006CB87C /* DiscoverViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverViewOutput.swift; sourceTree = ""; }; - 0E70A47222AF9953006CB87C /* DiscoverModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverModuleInput.swift; sourceTree = ""; }; - 0E70A47422AF9978006CB87C /* DiscoverPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverPresenter.swift; sourceTree = ""; }; - 0E70A47A22AF9BE2006CB87C /* DiscoverTableInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscoverTableInitializer.swift; sourceTree = ""; }; - 0E70A47C22AF9BFE006CB87C /* DiscoverTableConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverTableConfigurator.swift; sourceTree = ""; }; - 0E79F28A244328D50048BF86 /* DiscoverAddWithMACTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverAddWithMACTableViewCell.swift; sourceTree = ""; }; - 0E84BF4C239795AF00A37E1A /* DiscoverModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverModuleOutput.swift; sourceTree = ""; }; - 0E84BF542397F29800A37E1A /* Heartbeat.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Heartbeat.storyboard; sourceTree = ""; }; - 0E84BF562397F33E00A37E1A /* HeartbeatViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatViewInput.swift; sourceTree = ""; }; - 0E84BF582397F3C600A37E1A /* HeartbeatViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatViewModel.swift; sourceTree = ""; }; - 0E84BF5A2397F3DF00A37E1A /* HeartbeatViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatViewOutput.swift; sourceTree = ""; }; - 0E84BF5E2397F6BE00A37E1A /* HeartbeatViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatViewController.swift; sourceTree = ""; }; - 0E84BF602397F73100A37E1A /* HeartbeatEnvironmentObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatEnvironmentObject.swift; sourceTree = ""; }; - 0E84BF622397F76A00A37E1A /* HeartbeatList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatList.swift; sourceTree = ""; }; - 0E84BF642397F9DC00A37E1A /* HeartbeatTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatTableViewController.swift; sourceTree = ""; }; - 0E84BF66239801AF00A37E1A /* HeartbeatRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatRouterInput.swift; sourceTree = ""; }; - 0E84BF68239801C100A37E1A /* HeartbeatRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatRouter.swift; sourceTree = ""; }; - 0E84BF6A239802A400A37E1A /* HeartbeatModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatModuleInput.swift; sourceTree = ""; }; - 0E84BF6C239802CA00A37E1A /* HeartbeatPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatPresenter.swift; sourceTree = ""; }; - 0E84BF6E2398031B00A37E1A /* HeartbeatInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatInitializer.swift; sourceTree = ""; }; - 0E84BF702398035C00A37E1A /* HeartbeatConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatConfigurator.swift; sourceTree = ""; }; - 0E8A100123845E5100A9CBA6 /* Defaults.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Defaults.storyboard; sourceTree = ""; }; - 0E8A100923845F3900A9CBA6 /* DefaultsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsViewController.swift; sourceTree = ""; }; - 0E8A100B23845F7100A9CBA6 /* DefaultsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsViewInput.swift; sourceTree = ""; }; - 0E8A100D23845F8C00A9CBA6 /* DefaultsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsViewOutput.swift; sourceTree = ""; }; - 0E8A100F23845FAE00A9CBA6 /* DefaultsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsViewModel.swift; sourceTree = ""; }; - 0E8A10112384605A00A9CBA6 /* DefaultsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsTableViewController.swift; sourceTree = ""; }; - 0E8A10132384610400A9CBA6 /* DefaultsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsRouter.swift; sourceTree = ""; }; - 0E8A10152384612300A9CBA6 /* DefaultsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsRouterInput.swift; sourceTree = ""; }; - 0E8A10172384613E00A9CBA6 /* DefaultsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsModuleInput.swift; sourceTree = ""; }; - 0E8A10192384615400A9CBA6 /* DefaultsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsPresenter.swift; sourceTree = ""; }; - 0E8A101B2384618700A9CBA6 /* DefaultsInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsInitializer.swift; sourceTree = ""; }; - 0E8A101D238461D400A9CBA6 /* DefaultsConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsConfigurator.swift; sourceTree = ""; }; - 0E8A101F2384633200A9CBA6 /* DefaultsEnvironmentObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsEnvironmentObject.swift; sourceTree = ""; }; - 0E8A10212384637F00A9CBA6 /* DefaultsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsList.swift; sourceTree = ""; }; - 0E8A102423846CEB00A9CBA6 /* DefaultsSwitchTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsSwitchTableViewCell.swift; sourceTree = ""; }; - 0E8BAC97245C716B00D380FB /* Combine.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Combine.framework; path = System/Library/Frameworks/Combine.framework; sourceTree = SDKROOT; }; - 0E8BD2AA23851CF2008B31EF /* DefaultsStepperTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsStepperTableViewCell.swift; sourceTree = ""; }; - 0E8FD0BE23335D6900FFA577 /* TagCharts.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = TagCharts.storyboard; sourceTree = ""; }; - 0E8FD0C023335D8400FFA577 /* TagChartsScrollViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsScrollViewController.swift; sourceTree = ""; }; - 0E8FD0C223335DA700FFA577 /* TagChartsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewInput.swift; sourceTree = ""; }; - 0E8FD0C423335DBF00FFA577 /* TagChartsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewOutput.swift; sourceTree = ""; }; - 0E8FD0C6233366DC00FFA577 /* TagChartsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsRouterInput.swift; sourceTree = ""; }; - 0E8FD0C8233366F000FFA577 /* TagChartsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsRouter.swift; sourceTree = ""; }; - 0E8FD0CA2333671100FFA577 /* TagChartsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsModuleInput.swift; sourceTree = ""; }; - 0E8FD0CC2333672F00FFA577 /* TagChartsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsPresenter.swift; sourceTree = ""; }; - 0E8FD0CE2333676C00FFA577 /* TagChartsScrollInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsScrollInitializer.swift; sourceTree = ""; }; - 0E8FD0D02333679800FFA577 /* TagChartsScrollConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsScrollConfigurator.swift; sourceTree = ""; }; - 0E8FD0D223336B4200FFA577 /* TagChartsTransitioningDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsTransitioningDelegate.swift; sourceTree = ""; }; - 0E8FD0D423336BA300FFA577 /* TagChartsPresentTransitionAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsPresentTransitionAnimation.swift; sourceTree = ""; }; - 0E8FD0D623336C6E00FFA577 /* TagChartsDismissTransitionAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsDismissTransitionAnimation.swift; sourceTree = ""; }; - 0E8FD0DC2333714C00FFA577 /* TagChartsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewModel.swift; sourceTree = ""; }; - 0E8FD0E22333893600FFA577 /* TagChartsModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsModuleOutput.swift; sourceTree = ""; }; - 0E92A972268636F500187E4F /* TemperatureUnit+Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TemperatureUnit+Localization.swift"; sourceTree = ""; }; - 0E92A974268636F500187E4F /* ExportHeadersProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExportHeadersProvider.swift; sourceTree = ""; }; - 0E92A975268636F500187E4F /* HeartbeatDaemonTitles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeartbeatDaemonTitles.swift; sourceTree = ""; }; - 0E92A976268636F500187E4F /* RuuviNotifierTitlesImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RuuviNotifierTitlesImpl.swift; sourceTree = ""; }; - 0E92A977268636F600187E4F /* VirtualLocation+Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "VirtualLocation+Localization.swift"; sourceTree = ""; }; - 0E92A978268636F600187E4F /* HumidityUnit+Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "HumidityUnit+Localization.swift"; sourceTree = ""; }; - 0E92A979268636F600187E4F /* MeasurementType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeasurementType.swift; sourceTree = ""; }; - 0E92A97A268636F700187E4F /* Language+Localization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Language+Localization.swift"; sourceTree = ""; }; - 0E92A9832686370000187E4F /* RUError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RUError.swift; sourceTree = ""; }; - 0E92A9852686371E00187E4F /* DateValueFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateValueFormatter.swift; sourceTree = ""; }; - 0E92A9872686373000187E4F /* Debouncer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Debouncer.swift; sourceTree = ""; }; - 0E9D0AAF231E9BD800C6BDA7 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - 0E9D0AB0231EBEFD00C6BDA7 /* LocalizationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationService.swift; sourceTree = ""; }; - 0E9D5F1F2351BE3C0076FFD8 /* ForegroundSwitchTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundSwitchTableViewCell.swift; sourceTree = ""; }; - 0E9E7759238CCE5F006D7013 /* String+Replace.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Replace.swift"; sourceTree = ""; }; - 0E9F979522EAFC820015ADE2 /* DiscoverWebTagTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverWebTagTableViewCell.swift; sourceTree = ""; }; - 0EA796702664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviCloudError+LocalizedError.swift"; sourceTree = ""; }; - 0EA796742664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviCloudApiError+LocalizedError.swift"; sourceTree = ""; }; - 0EA796782664B37F002BA25D /* RuuviLocalError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviLocalError+LocalizedError.swift"; sourceTree = ""; }; - 0EA7967C2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviPersistenceError+LocalizedError.swift"; sourceTree = ""; }; - 0EA796802664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviPoolError+LocalizedError.swift"; sourceTree = ""; }; - 0EA796842664B84D002BA25D /* RuuviReactorError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviReactorError+LocalizedError.swift"; sourceTree = ""; }; - 0EA796882664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviServiceError+LocalizedError.swift"; sourceTree = ""; }; - 0EA7968C2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviStorageError+LocalizedError.swift"; sourceTree = ""; }; - 0EA92FDA2387E734008F1558 /* TagSettingsAlertsHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsAlertsHeaderFooterView.swift; sourceTree = ""; }; - 0EA92FDE2387E74C008F1558 /* TagSettingsAlertsHeaderFooterView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TagSettingsAlertsHeaderFooterView.xib; sourceTree = ""; }; - 0EB48DE5261A1816008E0D2D /* FeatureToggles.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = FeatureToggles.json; sourceTree = ""; }; - 0EB66B2E2686058F00375BCC /* FeatureToggleProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureToggleProvider.swift; sourceTree = ""; }; - 0EB66B2F2686058F00375BCC /* FallbackFeatureToggleProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FallbackFeatureToggleProvider.swift; sourceTree = ""; }; - 0EB66B302686058F00375BCC /* FirebaseFeatureToggleProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirebaseFeatureToggleProvider.swift; sourceTree = ""; }; - 0EB66B312686058F00375BCC /* LocalFeatureToggleProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalFeatureToggleProvider.swift; sourceTree = ""; }; - 0EB66B342686058F00375BCC /* FirebaseRemoteConfigService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirebaseRemoteConfigService.swift; sourceTree = ""; }; - 0EB66B352686058F00375BCC /* RemoteConfigService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteConfigService.swift; sourceTree = ""; }; - 0EB66B362686058F00375BCC /* FeatureToggleService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureToggleService.swift; sourceTree = ""; }; - 0EB66B372686058F00375BCC /* FeatureToggle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureToggle.swift; sourceTree = ""; }; - 0EB66B3A2686058F00375BCC /* InfoProviderImpl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InfoProviderImpl.swift; sourceTree = ""; }; - 0EB66B3B2686058F00375BCC /* InfoProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InfoProvider.swift; sourceTree = ""; }; - 0EB8B91B2683523200FE130E /* RuuviMigration */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviMigration; path = Packages/RuuviMigration; sourceTree = ""; }; - 0EB8B92D2683599100FE130E /* Networking.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Networking.plist; sourceTree = ""; }; - 0EBAF06B232006E00025A191 /* Language.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Language.storyboard; sourceTree = ""; }; - 0EBAF06D232007510025A191 /* LanguageViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageViewInput.swift; sourceTree = ""; }; - 0EBAF06F232007740025A191 /* LanguageViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageViewOutput.swift; sourceTree = ""; }; - 0EBAF071232007910025A191 /* LanguageTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageTableViewController.swift; sourceTree = ""; }; - 0EBAF074232007CC0025A191 /* LanguageRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageRouterInput.swift; sourceTree = ""; }; - 0EBAF076232007D80025A191 /* LanguageRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageRouter.swift; sourceTree = ""; }; - 0EBAF078232008140025A191 /* LanguageModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageModuleInput.swift; sourceTree = ""; }; - 0EBAF07A232008420025A191 /* LanguagePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguagePresenter.swift; sourceTree = ""; }; - 0EBAF07D2320086A0025A191 /* LanguageTableInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageTableInitializer.swift; sourceTree = ""; }; - 0EBAF07F2320089A0025A191 /* LanguageTableConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageTableConfigurator.swift; sourceTree = ""; }; - 0EBAF08123200B1B0025A191 /* LanguageTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageTableViewCell.swift; sourceTree = ""; }; - 0EBAF0832320120F0025A191 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - 0EC50F4F22CCB92000172EEB /* Observable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Observable.swift; sourceTree = ""; }; - 0EC50F5122CCB9DE00172EEB /* TagSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsViewModel.swift; sourceTree = ""; }; - 0EC50F5322CCBBE800172EEB /* NSObject+Observable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSObject+Observable.swift"; sourceTree = ""; }; - 0EC50F5522CCE46D00172EEB /* Optional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Optional.swift; sourceTree = ""; }; - 0EC50F5822CF621000172EEB /* PhotoPickerPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPickerPresenter.swift; sourceTree = ""; }; - 0ECB5A8D2381807500E78757 /* CardsScrollViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardsScrollViewController.swift; sourceTree = ""; }; - 0ECDF1B42313D65500A09ACA /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; - 0ECDF1B62313D7DA00A09ACA /* station.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = station.entitlements; sourceTree = ""; }; - 0ECFF354235056DC0061D11B /* ForegroundList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundList.swift; sourceTree = ""; }; - 0ECFF35623505F8D0061D11B /* Foreground.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Foreground.storyboard; sourceTree = ""; }; - 0ECFF358235060EF0061D11B /* ForegroundViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundViewController.swift; sourceTree = ""; }; - 0ECFF35A2350618E0061D11B /* ForegroundModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundModuleInput.swift; sourceTree = ""; }; - 0ECFF35D23506BC40061D11B /* ForegroundViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundViewOutput.swift; sourceTree = ""; }; - 0ECFF35F23506BD60061D11B /* ForegroundViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundViewInput.swift; sourceTree = ""; }; - 0ECFF36123506C050061D11B /* ForegroundRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundRow.swift; sourceTree = ""; }; - 0ECFF365235079F50061D11B /* ForegroundPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundPresenter.swift; sourceTree = ""; }; - 0ECFF36723507A1A0061D11B /* ForegroundRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundRouterInput.swift; sourceTree = ""; }; - 0ECFF36B23507BC00061D11B /* ForegroundInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundInitializer.swift; sourceTree = ""; }; - 0ECFF36D23507BF00061D11B /* ForegroundConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundConfigurator.swift; sourceTree = ""; }; - 0ECFF36F23507CE80061D11B /* ForegroundViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundViewModel.swift; sourceTree = ""; }; - 0EE11227267BBD0E008DA8D9 /* RuuviCloud */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviCloud; path = Packages/RuuviCloud; sourceTree = ""; }; - 0EE11228267BBD0E008DA8D9 /* RuuviStorage */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviStorage; path = Packages/RuuviStorage; sourceTree = ""; }; - 0EE11229267BBD0E008DA8D9 /* RuuviPersistence */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviPersistence; path = Packages/RuuviPersistence; sourceTree = ""; }; - 0EE1122A267BBD0E008DA8D9 /* RuuviContext */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviContext; path = Packages/RuuviContext; sourceTree = ""; }; - 0EE1122D267BBD0F008DA8D9 /* RuuviRepository */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviRepository; path = Packages/RuuviRepository; sourceTree = ""; }; - 0EE1122E267BBD0F008DA8D9 /* RuuviPool */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviPool; path = Packages/RuuviPool; sourceTree = ""; }; - 0EE1122F267BBD0F008DA8D9 /* RuuviService */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviService; path = Packages/RuuviService; sourceTree = ""; }; - 0EE11230267BBD0F008DA8D9 /* RuuviUser */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviUser; path = Packages/RuuviUser; sourceTree = ""; }; - 0EE11231267BBD0F008DA8D9 /* RuuviLocal */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviLocal; path = Packages/RuuviLocal; sourceTree = ""; }; - 0EE11232267BBD0F008DA8D9 /* RuuviOntology */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviOntology; path = Packages/RuuviOntology; sourceTree = ""; }; - 0EE1125D267BC33D008DA8D9 /* RuuviReactor */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviReactor; path = Packages/RuuviReactor; sourceTree = ""; }; - 0EE11276267BC77D008DA8D9 /* RuuviDaemon */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviDaemon; path = Packages/RuuviDaemon; sourceTree = ""; }; - 0EE1127D267BC968008DA8D9 /* RuuviCore */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviCore; path = Packages/RuuviCore; sourceTree = ""; }; - 0EE36E82269749DE0021B746 /* FirmwareRepository.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirmwareRepository.swift; sourceTree = ""; }; - 0EE36E84269749DE0021B746 /* DFUModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DFUModuleInput.swift; sourceTree = ""; }; - 0EE36E85269749DE0021B746 /* DFUPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DFUPresenter.swift; sourceTree = ""; }; - 0EE36E87269749DE0021B746 /* Publishers+System.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Publishers+System.swift"; sourceTree = ""; }; - 0EE36E88269749DE0021B746 /* URLSession+downloadTaskPublisher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "URLSession+downloadTaskPublisher.swift"; sourceTree = ""; }; - 0EE36E89269749DE0021B746 /* View+Any.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "View+Any.swift"; sourceTree = ""; }; - 0EE36E8B269749DE0021B746 /* Spinner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Spinner.swift; sourceTree = ""; }; - 0EE36E8C269749DE0021B746 /* LargeButtonStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LargeButtonStyle.swift; sourceTree = ""; }; - 0EE36E8D269749DE0021B746 /* ProgressBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; - 0EE36E8E269749DE0021B746 /* Feedback.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Feedback.swift; sourceTree = ""; }; - 0EE36E90269749DE0021B746 /* DFUViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DFUViewModel.swift; sourceTree = ""; }; - 0EE36E92269749DE0021B746 /* DFUUIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DFUUIView.swift; sourceTree = ""; }; - 0EE36E94269749DE0021B746 /* DFUInteractorInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DFUInteractorInput.swift; sourceTree = ""; }; - 0EE36E95269749DE0021B746 /* DFUInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DFUInteractor.swift; sourceTree = ""; }; - 0EE36E96269749DE0021B746 /* LatestRelease.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LatestRelease.swift; sourceTree = ""; }; - 0EE36E97269749DE0021B746 /* DFUModuleFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DFUModuleFactory.swift; sourceTree = ""; }; - 0EE36EA9269749F10021B746 /* RuuviColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RuuviColor.swift; sourceTree = ""; }; - 0EE49B9423B74775003012C2 /* WebTagSettingsAlertHeaderCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsAlertHeaderCell.swift; sourceTree = ""; }; - 0EE49B9823B877CF003012C2 /* WebTagSettingsAlertControlsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsAlertControlsCell.swift; sourceTree = ""; }; - 0EE49BB123B8C40D003012C2 /* MacInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = MacInfo.plist; sourceTree = ""; }; - 0EE49BB223B8C40D003012C2 /* DevInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = DevInfo.plist; sourceTree = ""; }; - 0EE5B47C23508F6D00D5ED32 /* ForegroundEnvironmentObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForegroundEnvironmentObject.swift; sourceTree = ""; }; - 0EE98A7826493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLEXFeatureTogglesViewController.swift; sourceTree = ""; }; - 0EEB20C522B7915C0015F9E0 /* CardsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsViewModel.swift; sourceTree = ""; }; - 0EEB20C822B7A7200015F9E0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - 0EEB20CA22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableEmbededViewController.swift; sourceTree = ""; }; - 0EEB20CC22B7BD6C0015F9E0 /* MenuModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuModuleOutput.swift; sourceTree = ""; }; - 0EEB20D022B7C6F30015F9E0 /* Settings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Settings.storyboard; sourceTree = ""; }; - 0EEB20D222B7C7AC0015F9E0 /* SettingsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableViewController.swift; sourceTree = ""; }; - 0EEB20D522B7C7E70015F9E0 /* SettingsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewInput.swift; sourceTree = ""; }; - 0EEB20D722B7C8060015F9E0 /* SettingsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewOutput.swift; sourceTree = ""; }; - 0EEB20DC22B7C8650015F9E0 /* SettingsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsRouterInput.swift; sourceTree = ""; }; - 0EEB20DE22B7C8790015F9E0 /* SettingsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsRouter.swift; sourceTree = ""; }; - 0EEB20E022B7C8A90015F9E0 /* SettingsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsModuleInput.swift; sourceTree = ""; }; - 0EEB20E222B7C8C10015F9E0 /* SettingsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsPresenter.swift; sourceTree = ""; }; - 0EEB20E522B7C8F20015F9E0 /* SettingsTableInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableInitializer.swift; sourceTree = ""; }; - 0EEB20E722B7C92C0015F9E0 /* SettingsTableConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableConfigurator.swift; sourceTree = ""; }; - 0EEB20EE22B7D1580015F9E0 /* About.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = About.storyboard; sourceTree = ""; }; - 0EEB20F222B7D1900015F9E0 /* AboutViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewInput.swift; sourceTree = ""; }; - 0EEB20F422B7D1A40015F9E0 /* AboutViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewOutput.swift; sourceTree = ""; }; - 0EEB20F622B7D2090015F9E0 /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = ""; }; - 0EEB20F822B7D28C0015F9E0 /* AboutRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutRouterInput.swift; sourceTree = ""; }; - 0EEB20FA22B7D2990015F9E0 /* AboutRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutRouter.swift; sourceTree = ""; }; - 0EEB20FC22B7D2C90015F9E0 /* AboutModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutModuleInput.swift; sourceTree = ""; }; - 0EEB20FE22B7D2DD0015F9E0 /* AboutPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutPresenter.swift; sourceTree = ""; }; - 0EEB210022B7D2F50015F9E0 /* AboutInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutInitializer.swift; sourceTree = ""; }; - 0EEB210222B7D3210015F9E0 /* AboutConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutConfigurator.swift; sourceTree = ""; }; - 0EEB213B22B8FAD50015F9E0 /* MainRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainRouter.swift; sourceTree = ""; }; - 0EEB213E22B8FB840015F9E0 /* MainNavigationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainNavigationDelegate.swift; sourceTree = ""; }; - 0EEB214122B8FBA50015F9E0 /* MainInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainInitializer.swift; sourceTree = ""; }; - 0EEB214322B8FBC50015F9E0 /* MainConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainConfigurator.swift; sourceTree = ""; }; - 0EEB214622B8FC3E0015F9E0 /* WelcomeViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeViewInput.swift; sourceTree = ""; }; - 0EEB214822B8FC570015F9E0 /* WelcomeViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeViewOutput.swift; sourceTree = ""; }; - 0EEB214B22B8FCC70015F9E0 /* WelcomeRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeRouterInput.swift; sourceTree = ""; }; - 0EEB214D22B8FCDC0015F9E0 /* WelcomeRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeRouter.swift; sourceTree = ""; }; - 0EEB215022B8FD070015F9E0 /* WelcomeModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeModuleInput.swift; sourceTree = ""; }; - 0EEB215222B8FD1F0015F9E0 /* WelcomePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomePresenter.swift; sourceTree = ""; }; - 0EEB215522B8FD590015F9E0 /* WelcomeInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeInitializer.swift; sourceTree = ""; }; - 0EEB215722B8FD800015F9E0 /* WelcomeConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeConfigurator.swift; sourceTree = ""; }; - 0EEB215922BA28860015F9E0 /* MenuTableTransitionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableTransitionManager.swift; sourceTree = ""; }; - 0EF2862B22CBAF5D0026C7A5 /* TagSettings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = TagSettings.storyboard; sourceTree = ""; }; - 0EF2862D22CBAFC80026C7A5 /* TagSettingsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsTableViewController.swift; sourceTree = ""; }; - 0EF2863022CBB00D0026C7A5 /* TagSettingsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsViewInput.swift; sourceTree = ""; }; - 0EF2863222CBB0250026C7A5 /* TagSettingsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsViewOutput.swift; sourceTree = ""; }; - 0EF2863422CBB03A0026C7A5 /* TagSettingsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsRouterInput.swift; sourceTree = ""; }; - 0EF2863622CBB04E0026C7A5 /* TagSettingsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsRouter.swift; sourceTree = ""; }; - 0EF2863822CBB06C0026C7A5 /* TagSettingsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsModuleInput.swift; sourceTree = ""; }; - 0EF2863A22CBB08C0026C7A5 /* TagSettingsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsPresenter.swift; sourceTree = ""; }; - 0EF2863F22CBB1340026C7A5 /* TagSettingsTableInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TagSettingsTableInitializer.swift; sourceTree = ""; }; - 0EF2864122CBB13F0026C7A5 /* TagSettingsTableConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsTableConfigurator.swift; sourceTree = ""; }; - 0EF4E30F26823F3D00D83CC7 /* RuuviCoreError+LocalizedError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RuuviCoreError+LocalizedError.swift"; sourceTree = ""; }; - 0EF4E31026823F3D00D83CC7 /* RuuviVirtualError+LocalizedError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RuuviVirtualError+LocalizedError.swift"; sourceTree = ""; }; - 0EF4E31626823F6100D83CC7 /* DiscoverRuuviTagViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscoverRuuviTagViewModel.swift; sourceTree = ""; }; - 0EF4E31726823F6100D83CC7 /* DiscoverVirtualTagViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiscoverVirtualTagViewModel.swift; sourceTree = ""; }; - 0EF4E31A2682400C00D83CC7 /* RuuviLocation */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviLocation; path = Packages/RuuviLocation; sourceTree = ""; }; - 0EF4E31B2682401200D83CC7 /* RuuviVirtual */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviVirtual; path = Packages/RuuviVirtual; sourceTree = ""; }; - 0EF4E35126831A0B00D83CC7 /* DfuFirmware+Log.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DfuFirmware+Log.swift"; sourceTree = ""; }; - 0EF4E35526831AFF00D83CC7 /* RuuviDFU */ = {isa = PBXFileReference; lastKnownFileType = folder; name = RuuviDFU; path = Packages/RuuviDFU; sourceTree = ""; }; - 0EF5B72A22D62CD900D9D14A /* Date+Ruuvi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Ruuvi.swift"; sourceTree = ""; }; - 0EF6F5BD235E01170052BA25 /* ForegroundRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForegroundRouter.swift; sourceTree = ""; }; - 0EF6F5BF235E01CD0052BA25 /* ForegroundStepperTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForegroundStepperTableViewCell.swift; sourceTree = ""; }; - 0EF6F5C1235E02000052BA25 /* ForegroundTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForegroundTableViewController.swift; sourceTree = ""; }; - 167F75FD2FDAD002C10686FA /* ShareViewInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareViewInput.swift; sourceTree = ""; }; - 28B469B53431F206F4D0EC60 /* SignInConfigurator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInConfigurator.swift; sourceTree = ""; }; - 310159B7264484D700A5E8E8 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Main.strings; sourceTree = ""; }; - 310159B82644864400A5E8E8 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - 310159B92644864C00A5E8E8 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = ""; }; - 354B5B6F50E98F55D6A672BA /* ShareViewModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareViewModel.swift; sourceTree = ""; }; - 392F0E992BEAA3382C2CF709 /* ShareInitializer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareInitializer.swift; sourceTree = ""; }; - 4A7D6325DFC865D2D11BD1D1 /* SignInViewInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInViewInput.swift; sourceTree = ""; }; - 4BD498E7491E278B4EF4919C /* SignInViewOutput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInViewOutput.swift; sourceTree = ""; }; - 4E816312622E83E3B42001DC /* SignInRouterInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInRouterInput.swift; sourceTree = ""; }; - 5710E4EF18D419D01D60405E /* ShareModuleOutput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareModuleOutput.swift; sourceTree = ""; }; - 64333D2820B0C45900CDF4B6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 64333D2D20B0C45900CDF4B6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 64333D2F20B0C45A00CDF4B6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 64333D3220B0C45A00CDF4B6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 64333D3420B0C45A00CDF4B6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 643C651E21C38F490037BE5B /* Montserrat-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Montserrat-Bold.ttf"; sourceTree = ""; }; - 643EEC2A2266435100D4E837 /* Oswald-ExtraLight.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Oswald-ExtraLight.ttf"; sourceTree = ""; }; - 6467818F225CFB170072856A /* Muli-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Muli-Regular.ttf"; sourceTree = ""; }; - 64678190225D02CE0072856A /* Muli-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Muli-Bold.ttf"; sourceTree = ""; }; - 6486970F20E042E000CCD7C1 /* Oswald-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Oswald-Bold.ttf"; sourceTree = ""; }; - 6486971120E0439200CCD7C1 /* Montserrat-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Montserrat-Regular.ttf"; sourceTree = ""; }; - 64A2DAE224310B2900DE6699 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - 64A2DAE324310B2900DE6699 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InfoPlist.strings; sourceTree = ""; }; - 660EB2462669278E000FD22B /* DfuDevicesScannerConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerConfigurator.swift; sourceTree = ""; }; - 660EB2472669278E000FD22B /* DfuDevicesScannerInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerInitializer.swift; sourceTree = ""; }; - 660EB2492669278E000FD22B /* DfuDevicesScannerPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerPresenter.swift; sourceTree = ""; }; - 660EB24A2669278E000FD22B /* DfuDevicesScannerModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerModuleInput.swift; sourceTree = ""; }; - 660EB24B2669278E000FD22B /* DfuDevicesScannerModuleOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerModuleOutput.swift; sourceTree = ""; }; - 660EB24E2669278E000FD22B /* DfuNoDeviceTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuNoDeviceTableViewCell.swift; sourceTree = ""; }; - 660EB24F2669278E000FD22B /* DfuDeviceTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDeviceTableViewCell.swift; sourceTree = ""; }; - 660EB2502669278E000FD22B /* DfuDevicesScannerViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerViewInput.swift; sourceTree = ""; }; - 660EB2512669278E000FD22B /* DfuDevicesScannerTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerTableViewController.swift; sourceTree = ""; }; - 660EB2522669278E000FD22B /* DfuDevicesScannerViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerViewModel.swift; sourceTree = ""; }; - 660EB2532669278E000FD22B /* DfuDevicesScannerViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerViewOutput.swift; sourceTree = ""; }; - 660EB2542669278E000FD22B /* DfuDevicesScanner.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = DfuDevicesScanner.storyboard; sourceTree = ""; }; - 660EB2562669278E000FD22B /* DfuDevicesScannerRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerRouterInput.swift; sourceTree = ""; }; - 660EB2572669278E000FD22B /* DfuDevicesScannerRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuDevicesScannerRouter.swift; sourceTree = ""; }; - 660EB29B266928E6000FD22B /* UIViewController+Alert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Alert.swift"; sourceTree = ""; }; - 663155CD2667F40C005B90A6 /* UpdateFirmwareAppleInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareAppleInitializer.swift; sourceTree = ""; }; - 663155CE2667F40C005B90A6 /* UpdateFirmwareConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareConfigurator.swift; sourceTree = ""; }; - 663155D02667F40C005B90A6 /* UpdateFirmwarePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwarePresenter.swift; sourceTree = ""; }; - 663155D12667F40C005B90A6 /* UpdateFirmwareModuleOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareModuleOutput.swift; sourceTree = ""; }; - 663155D22667F40C005B90A6 /* UpdateFirmwareModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareModuleInput.swift; sourceTree = ""; }; - 663155D52667F40C005B90A6 /* UpdateFirmwareAppleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareAppleViewController.swift; sourceTree = ""; }; - 663155D62667F40C005B90A6 /* UpdateFirmwareViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareViewOutput.swift; sourceTree = ""; }; - 663155D72667F40C005B90A6 /* UpdateFirmwareViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareViewInput.swift; sourceTree = ""; }; - 663155D92667F40C005B90A6 /* UpdateFirmware.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = UpdateFirmware.storyboard; sourceTree = ""; }; - 663155DB2667F40C005B90A6 /* UpdateFirmwareRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareRouter.swift; sourceTree = ""; }; - 663155DC2667F40C005B90A6 /* UpdateFirmwareRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateFirmwareRouterInput.swift; sourceTree = ""; }; - 66718A28266A685700A380F8 /* DfuFlashAppleInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashAppleInitializer.swift; sourceTree = ""; }; - 66718A29266A685700A380F8 /* DfuFlashConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashConfigurator.swift; sourceTree = ""; }; - 66718A2B266A685700A380F8 /* DfuFlashModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashModuleInput.swift; sourceTree = ""; }; - 66718A2C266A685700A380F8 /* DfuFlashModuleOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashModuleOutput.swift; sourceTree = ""; }; - 66718A2D266A685700A380F8 /* DfuFlashPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashPresenter.swift; sourceTree = ""; }; - 66718A30266A685700A380F8 /* DfuFlashAppleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashAppleViewController.swift; sourceTree = ""; }; - 66718A32266A685700A380F8 /* DfuLogTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuLogTableViewCell.swift; sourceTree = ""; }; - 66718A33266A685700A380F8 /* DfuFlashViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashViewModel.swift; sourceTree = ""; }; - 66718A34266A685700A380F8 /* DfuFlashViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashViewInput.swift; sourceTree = ""; }; - 66718A35266A685700A380F8 /* DfuFlashViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashViewOutput.swift; sourceTree = ""; }; - 66718A36266A685700A380F8 /* DfuFlash.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = DfuFlash.storyboard; sourceTree = ""; }; - 66718A38266A685700A380F8 /* DfuFlashRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashRouter.swift; sourceTree = ""; }; - 66718A39266A685700A380F8 /* DfuFlashRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFlashRouterInput.swift; sourceTree = ""; }; - 66718A62266A6CA700A380F8 /* DfuFilePickerPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFilePickerPresenter.swift; sourceTree = ""; }; - 66718A64266A6CA700A380F8 /* DfuFilePickerPresenterSheet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DfuFilePickerPresenterSheet.swift; sourceTree = ""; }; - 66718A6B266BD0E800A380F8 /* Color+Ruuvi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Ruuvi.swift"; sourceTree = ""; }; - 66BC44832657AED400A03253 /* OffsetCorrection.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = OffsetCorrection.storyboard; sourceTree = ""; }; - 66BC44862657AED400A03253 /* OffsetCorrectionAppleInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionAppleInitializer.swift; sourceTree = ""; }; - 66BC44872657AED400A03253 /* OffsetCorrectionConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionConfigurator.swift; sourceTree = ""; }; - 66BC44892657AED400A03253 /* OffsetCorrectionModuleOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionModuleOutput.swift; sourceTree = ""; }; - 66BC448A2657AED400A03253 /* OffsetCorrectionPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionPresenter.swift; sourceTree = ""; }; - 66BC448B2657AED400A03253 /* OffsetCorrectionModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionModuleInput.swift; sourceTree = ""; }; - 66BC448E2657AED400A03253 /* OffsetCorrectionAppleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionAppleViewController.swift; sourceTree = ""; }; - 66BC448F2657AED400A03253 /* OffsetCorrectionViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionViewInput.swift; sourceTree = ""; }; - 66BC44902657AED400A03253 /* OffsetCorrectionViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionViewModel.swift; sourceTree = ""; }; - 66BC44912657AED400A03253 /* OffsetCorrectionViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionViewOutput.swift; sourceTree = ""; }; - 66BC44932657AED400A03253 /* OffsetCorrectionRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionRouter.swift; sourceTree = ""; }; - 66BC44942657AED400A03253 /* OffsetCorrectionRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionRouterInput.swift; sourceTree = ""; }; - 6AE2284D927021C0BEA560B0 /* ShareModuleInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareModuleInput.swift; sourceTree = ""; }; - 6F0552F1D17F403B7DE508B5 /* SignInRouter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInRouter.swift; sourceTree = ""; }; - 85B8587156E1062D613B8960 /* SignInInitializer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInInitializer.swift; sourceTree = ""; }; - 87EFB230083D471777FBE5D0 /* SignInModuleInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInModuleInput.swift; sourceTree = ""; }; - 9546F1EFEE8F8CFC22377BB4 /* ShareRouterInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareRouterInput.swift; sourceTree = ""; }; - 9B3006A5FB2173EC6AA2728D /* SignInModuleOutput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInModuleOutput.swift; sourceTree = ""; }; - A907A1D2245F7C6600041F6E /* ProgressBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBarView.swift; sourceTree = ""; }; - A907A1D62460376600041F6E /* TagChartViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartViewModel.swift; sourceTree = ""; }; - A907BB1024AE620A009DA3DB /* UIWindow+Orientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindow+Orientation.swift"; sourceTree = ""; }; - A90E168E24604F7400631E6C /* TagChartPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartPresenter.swift; sourceTree = ""; }; - A90E169224604FD100631E6C /* TagChartModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = TagChartModuleInput.swift; path = station/Classes/Presentation/Modules/Dashboard/Chart/Presenter/TagChartModuleInput.swift; sourceTree = SOURCE_ROOT; }; - A90E16962460504C00631E6C /* TagChartModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartModuleOutput.swift; sourceTree = ""; }; - A90E169B24606ABF00631E6C /* TagChartsInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsInteractor.swift; sourceTree = ""; }; - A90E169F24606B0500631E6C /* TagChartsInteractorInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsInteractorInput.swift; sourceTree = ""; }; - A90E16A324606B2000631E6C /* TagChartsInteractorOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsInteractorOutput.swift; sourceTree = ""; }; - A90E16A82460975600631E6C /* TagChartAssembler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartAssembler.swift; sourceTree = ""; }; - A91D02DD2511207200694733 /* SelectionTableConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionTableConfigurator.swift; sourceTree = ""; }; - A91D02DE2511207200694733 /* SelectionTableInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionTableInitializer.swift; sourceTree = ""; }; - A91D02E02511207200694733 /* SelectionPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionPresenter.swift; sourceTree = ""; }; - A91D02E12511207200694733 /* SelectionModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionModuleInput.swift; sourceTree = ""; }; - A91D02E32511207200694733 /* SelectionViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionViewInput.swift; sourceTree = ""; }; - A91D02E52511207200694733 /* SelectionTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionTableViewCell.swift; sourceTree = ""; }; - A91D02E62511207200694733 /* SelectionTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionTableViewController.swift; sourceTree = ""; }; - A91D02E72511207200694733 /* SelectionViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionViewOutput.swift; sourceTree = ""; }; - A91D02E92511207200694733 /* SelectionRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionRouter.swift; sourceTree = ""; }; - A91D02EA2511207200694733 /* SelectionRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionRouterInput.swift; sourceTree = ""; }; - A91D030C251121C800694733 /* Selection.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Selection.storyboard; sourceTree = ""; }; - A91D0310251123B400694733 /* SelectionModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectionModuleOutput.swift; sourceTree = ""; }; - A91D0315251124F900694733 /* SelectionItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectionItem.swift; sourceTree = ""; }; - A91D031925113EAA00694733 /* UnitPressure+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UnitPressure+Extension.swift"; sourceTree = ""; }; - A92A66BC2450C640002918E7 /* UITableViewCell+ReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableViewCell+ReusableView.swift"; sourceTree = ""; }; - A92C75DF24896BA100E332FE /* Appfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = Appfile; sourceTree = ""; }; - A92C75E024896BA100E332FE /* Fastfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = Fastfile; sourceTree = ""; }; - A92C75E124896BA100E332FE /* Gemfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = Gemfile; sourceTree = ""; }; - A92C75E2248982A000E332FE /* Pluginfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = Pluginfile; sourceTree = ""; }; - A92E3C592426415100D981D5 /* TagChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartView.swift; sourceTree = ""; }; - A92E3C62242644B800D981D5 /* TagChartViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartViewInput.swift; sourceTree = ""; }; - A93052B7242BFCC000FB62B1 /* TagChartViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartViewOutput.swift; sourceTree = ""; }; - A93CDCAA25657C1D00018C6C /* MenuViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuViewModel.swift; sourceTree = ""; }; - A93CDCCE25659BA600018C6C /* AlertPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertPresenter.swift; sourceTree = ""; }; - A93CDCDD25659BF600018C6C /* AlertPresenterImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertPresenterImpl.swift; sourceTree = ""; }; - A949A83A24707FD0006B7F4F /* LocalizedCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedCache.swift; sourceTree = ""; }; - A9646454247BAE6A0001D55D /* AdvancedViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedViewInput.swift; sourceTree = ""; }; - A9646458247BAE6A0001D55D /* AdvancedStepperTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedStepperTableViewCell.swift; sourceTree = ""; }; - A9646459247BAE6A0001D55D /* AdvancedSwitchTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedSwitchTableViewCell.swift; sourceTree = ""; }; - A964645A247BAE6A0001D55D /* AdvancedTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedTableViewController.swift; sourceTree = ""; }; - A964645B247BAE6A0001D55D /* AdvancedViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedViewOutput.swift; sourceTree = ""; }; - A964645C247BAE6A0001D55D /* AdvancedViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedViewModel.swift; sourceTree = ""; }; - A964645E247BAE6A0001D55D /* AdvancedConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedConfigurator.swift; sourceTree = ""; }; - A964645F247BAE6A0001D55D /* AdvancedInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedInitializer.swift; sourceTree = ""; }; - A9646461247BAE6A0001D55D /* AdvancedModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedModuleInput.swift; sourceTree = ""; }; - A9646462247BAE6A0001D55D /* AdvancedPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedPresenter.swift; sourceTree = ""; }; - A9646464247BAE6A0001D55D /* AdvancedRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedRouterInput.swift; sourceTree = ""; }; - A9646465247BAE6A0001D55D /* AdvancedRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AdvancedRouter.swift; sourceTree = ""; }; - A964648D247BAEBA0001D55D /* AdvancedSettings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = AdvancedSettings.storyboard; sourceTree = ""; }; - A96B1F2225A7943E00D3ED9C /* station.localization.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; name = station.localization.json; path = station.localization/station.localization.json; sourceTree = SOURCE_ROOT; }; - A976CA7D24A928C20099BDC1 /* AdvancedDisclosureTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedDisclosureTableViewCell.swift; sourceTree = ""; }; - A980573725807118000D03AB /* AboutViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewModel.swift; sourceTree = ""; }; - A986147A248C49B00030F197 /* Matchfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Matchfile; sourceTree = ""; }; - A98BC874250E4265001CEFDC /* Double+Round.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+Round.swift"; sourceTree = ""; }; - A9A48A5B244CD9E70004FD50 /* UIWindow+Shake.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindow+Shake.swift"; sourceTree = ""; }; - A9A67BF924C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSObjectProtocol+Invalidation.swift"; sourceTree = ""; }; - A9B5742C253B978D00DB7353 /* SignIn.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = SignIn.storyboard; sourceTree = ""; }; - A9BB94CB2540AB610042B190 /* AlertViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertViewModel.swift; sourceTree = ""; }; - A9BD38B924F6108300904BBE /* Humidity+Offset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Humidity+Offset.swift"; sourceTree = ""; }; - A9E5993F25572CF700F9E5CC /* Share.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Share.storyboard; sourceTree = ""; }; - A9E599492557341F00F9E5CC /* ShareDescriptionTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareDescriptionTableViewCell.swift; sourceTree = ""; }; - A9E599572557345200F9E5CC /* ShareEmailInputTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareEmailInputTableViewCell.swift; sourceTree = ""; }; - A9E599602557346600F9E5CC /* ShareSendButtonTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareSendButtonTableViewCell.swift; sourceTree = ""; }; - A9E59969255734A000F9E5CC /* ShareEmailTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareEmailTableViewCell.swift; sourceTree = ""; }; - A9E6774725A33081000B75A3 /* String+Characters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Characters.swift"; sourceTree = ""; }; - A9F4471524B79959001E63AF /* TagSettingsModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsModuleOutput.swift; sourceTree = ""; }; - AB681E62A66E5924A87859B1 /* ShareConfigurator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareConfigurator.swift; sourceTree = ""; }; - BD7AE39C23B8C52BB202BB5E /* ShareRouter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareRouter.swift; sourceTree = ""; }; - CC1D67615D6DBA9E2FC5B402 /* SharePresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SharePresenter.swift; sourceTree = ""; }; - CE5C4AD5C54EF024669EAF47 /* ShareViewOutput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareViewOutput.swift; sourceTree = ""; }; - E29B5190CB557178D11AB2CE /* SignInPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInPresenter.swift; sourceTree = ""; }; - E6DB40883B83C652584EBB9A /* SignInViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInViewController.swift; sourceTree = ""; }; - FC417B8977A47FFAE71585F0 /* ShareViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; }; - FC59D3B5AD8926DBDD79AA1C /* SignInViewModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInViewModel.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 0E6BAEA623856A01003A2D4C /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 0EE1124F267BBDC1008DA8D9 /* RuuviService in Frameworks */, - 0EE11241267BBDC1008DA8D9 /* RuuviLocal in Frameworks */, - 0EE1123B267BBDC1008DA8D9 /* RuuviContext in Frameworks */, - 0EE11278267BC7A3008DA8D9 /* RuuviDaemon in Frameworks */, - 0EE11253267BBDC1008DA8D9 /* RuuviUser in Frameworks */, - 0E11D212267E1310002D0686 /* FirebaseInAppMessaging-Beta in Frameworks */, - 0EF00EFF267C6A930082AA8D /* RuuviContextRealm in Frameworks */, - 0E25135D2684A1FD004A522A /* RuuviNotificationLocal in Frameworks */, - 0EF4E32B2682403500D83CC7 /* RuuviVirtualReactor in Frameworks */, - 0EE1124D267BBDC1008DA8D9 /* RuuviRepository in Frameworks */, - 0EE1127B267BC7E3008DA8D9 /* RxSwift in Frameworks */, - 0E050143268601F5007060C4 /* RuuviDaemonBackground in Frameworks */, - 0EF4E31F2682403500D83CC7 /* RuuviLocation in Frameworks */, - 0EB97867267C769E0032CC05 /* RuuviPersistenceSQLite in Frameworks */, - 0E00C5032685BA1D009B3C24 /* RuuviServiceMeasurement in Frameworks */, - 0EF4E32D2682403500D83CC7 /* RuuviVirtualRepository in Frameworks */, - 0EE1123D267BBDC1008DA8D9 /* RuuviCore in Frameworks */, - 0E050149268601F6007060C4 /* RuuviDaemonVirtualTag in Frameworks */, - 0E050147268601F6007060C4 /* RuuviDaemonRuuviTag in Frameworks */, - 0EF00F01267C6A960082AA8D /* RuuviContextSQLite in Frameworks */, - 0EE1125F267BC34A008DA8D9 /* RuuviReactor in Frameworks */, - 0EE11265267BC3CC008DA8D9 /* NordicDFU in Frameworks */, - 0EB8B91F2683525900FE130E /* RuuviMigrationImpl in Frameworks */, - 0EE11272267BC5D6008DA8D9 /* FirebaseCrashlytics in Frameworks */, - 0EF4E35726831B1100D83CC7 /* RuuviDFU in Frameworks */, - 0EB8B91D2683525900FE130E /* RuuviMigration in Frameworks */, - 0EB9786D267C85BE0032CC05 /* RuuviPoolCoordinator in Frameworks */, - 0EF4E3252682403500D83CC7 /* RuuviVirtualModel in Frameworks */, - 0EE11239267BBDC1008DA8D9 /* RuuviCloudPure in Frameworks */, - 0EE11243267BBDC1008DA8D9 /* RuuviLocalUserDefaults in Frameworks */, - 0E050145268601F5007060C4 /* RuuviDaemonOperation in Frameworks */, - 0EF4E32F2682403500D83CC7 /* RuuviVirtualService in Frameworks */, - 0EE11247267BBDC1008DA8D9 /* RuuviPersistence in Frameworks */, - 0E5BF779267BCCB900EBF2D6 /* RuuviCoreImage in Frameworks */, - 0EE36EBE269F06CA0021B746 /* Charts in Frameworks */, - 0EE1126B267BC4A7008DA8D9 /* GestureInstructions in Frameworks */, - 0EE11235267BBDC1008DA8D9 /* RuuviCloud in Frameworks */, - 0EE11262267BC395008DA8D9 /* Swinject in Frameworks */, - 0EF4E31D2682403500D83CC7 /* RuuviCoreLocation in Frameworks */, - 0EB8B94026837B6A00FE130E /* RuuviCorePN in Frameworks */, - 0EF4E3292682403500D83CC7 /* RuuviVirtualPersistence in Frameworks */, - 0EE1125C267BC327008DA8D9 /* LightRoute in Frameworks */, - 0EBE42D1267CA726002888EC /* Localize_Swift in Frameworks */, - 0EBE42CB267C8AA1002888EC /* RuuviUserCoordinator in Frameworks */, - 0E62298A26A7FB860041DCDD /* RuuviOnboard in Frameworks */, - 0EB97865267C769E0032CC05 /* RuuviPersistenceRealm in Frameworks */, - 0EF4E3212682403500D83CC7 /* RuuviLocationService in Frameworks */, - 0EBE42D4267CA889002888EC /* BTKit in Frameworks */, - 0EBE42C7267C8A97002888EC /* RuuviReactorImpl in Frameworks */, - 0E25135B2684A1FD004A522A /* RuuviNotification in Frameworks */, - 0E11D214267E1317002D0686 /* FirebaseMessaging in Frameworks */, - 0E00C5012685BA1D009B3C24 /* RuuviServiceExport in Frameworks */, - 0EE11270267BC5D6008DA8D9 /* FirebaseRemoteConfig in Frameworks */, - 0EF4E3272682403500D83CC7 /* RuuviVirtualOWM in Frameworks */, - 0EF00F03267C6B160082AA8D /* RuuviServiceFactory in Frameworks */, - 0EF4E3232682403500D83CC7 /* RuuviVirtual in Frameworks */, - 0EE11251267BBDC1008DA8D9 /* RuuviStorage in Frameworks */, - 0EE11237267BBDC1008DA8D9 /* RuuviCloudApi in Frameworks */, - 0EE11249267BBDC1008DA8D9 /* RuuviPool in Frameworks */, - 0EB9786B267C7B6C0032CC05 /* RuuviStorageCoordinator in Frameworks */, - 0EB8B93E26837B6900FE130E /* RuuviCorePermission in Frameworks */, - 0E2513712684D09B004A522A /* RuuviNotifier in Frameworks */, - 0E92A98A2686373900187E4F /* RuuviServiceGATT in Frameworks */, - 0EF4E35926831B1100D83CC7 /* RuuviDFUImpl in Frameworks */, - 0EE11275267BC751008DA8D9 /* SwinjectPropertyLoader in Frameworks */, - 0EB8B93C26837B6900FE130E /* RuuviCoreDiff in Frameworks */, - 0EF4E3312682403500D83CC7 /* RuuviVirtualStorage in Frameworks */, - 0EB97869267C7B640032CC05 /* RuuviDaemonCloudSync in Frameworks */, - 0EE11245267BBDC1008DA8D9 /* RuuviOntology in Frameworks */, - 0EE11268267BC477008DA8D9 /* RangeSeekSlider in Frameworks */, - 0E2513732684D09B004A522A /* RuuviNotifierImpl in Frameworks */, - 0EBE42C9267C8A9B002888EC /* RuuviRepositoryCoordinator in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 0E02ABB8237598B200ED4629 /* RangeSeekSlider */ = { - isa = PBXGroup; - children = ( - 0E02ABB9237598C600ED4629 /* RURangeSeekSlider.swift */, - ); - path = RangeSeekSlider; - sourceTree = ""; - }; - 0E046F2022F049C500BD4E9C /* WebTagSettings */ = { - isa = PBXGroup; - children = ( - 0E046F2622F04A0300BD4E9C /* WebTagSettings.storyboard */, - 0E046F2522F049F000BD4E9C /* Assembly */, - 0E046F2322F049E200BD4E9C /* Presenter */, - 0E046F2222F049DE00BD4E9C /* Router */, - 0E046F2122F049D900BD4E9C /* View */, - ); - path = WebTagSettings; - sourceTree = ""; - }; - 0E046F2122F049D900BD4E9C /* View */ = { - isa = PBXGroup; - children = ( - 0E046F2C22F0563E00BD4E9C /* Table */, - 0E046F3E22F0702D00BD4E9C /* WebTagSettingsViewModel.swift */, - 0E046F2822F0561B00BD4E9C /* WebTagSettingsViewInput.swift */, - 0E046F2A22F0563100BD4E9C /* WebTagSettingsViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E046F2222F049DE00BD4E9C /* Router */ = { - isa = PBXGroup; - children = ( - 0E046F2F22F057CC00BD4E9C /* WebTagSettingsRouterInput.swift */, - 0E046F3122F057DD00BD4E9C /* WebTagSettingsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E046F2322F049E200BD4E9C /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E046F3322F057FC00BD4E9C /* WebTagSettingsModuleInput.swift */, - 0E046F3522F0581E00BD4E9C /* WebTagSettingsPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E046F2522F049F000BD4E9C /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E046F3922F05A9300BD4E9C /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E046F2C22F0563E00BD4E9C /* Table */ = { - isa = PBXGroup; - children = ( - 0E31B04023BBA34C00660412 /* SectionHeader */, - 0EE49B9323B74704003012C2 /* Cells */, - 0E046F2D22F0569000BD4E9C /* WebTagSettingsTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E046F3722F0585E00BD4E9C /* Transitions */ = { - isa = PBXGroup; - children = ( - 0E046F3822F0589000BD4E9C /* SwipeDownToDismiss */, - ); - path = Transitions; - sourceTree = ""; - }; - 0E046F3822F0589000BD4E9C /* SwipeDownToDismiss */ = { - isa = PBXGroup; - children = ( - 0E53DA6622CC964200BC6D64 /* SwipeDownToDismissNavigationController.swift */, - 0E53DA5F22CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift */, - 0E53DA6122CC93EB00BC6D64 /* SwipeDownToDismissTransitionAnimation.swift */, - 0E53DA6322CC943900BC6D64 /* SwipeDownToDismissInteractiveTransition.swift */, - ); - path = SwipeDownToDismiss; - sourceTree = ""; - }; - 0E046F3922F05A9300BD4E9C /* Table */ = { - isa = PBXGroup; - children = ( - 0E046F3A22F05AA800BD4E9C /* WebTagSettingsTableInitializer.swift */, - 0E046F3C22F05B0900BD4E9C /* WebTagSettingsTableConfigurator.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E046F4022F17EC600BD4E9C /* LocationPicker */ = { - isa = PBXGroup; - children = ( - 0E046F4522F17EF400BD4E9C /* LocationPicker.storyboard */, - 0E046F4422F17EE100BD4E9C /* Assembly */, - 0E046F4322F17EDC00BD4E9C /* Presenter */, - 0E046F4222F17ED700BD4E9C /* Router */, - 0E046F4122F17ED300BD4E9C /* View */, - ); - path = LocationPicker; - sourceTree = ""; - }; - 0E046F4122F17ED300BD4E9C /* View */ = { - isa = PBXGroup; - children = ( - 0E046F4B22F1821000BD4E9C /* Apple */, - 0E046F4722F181DA00BD4E9C /* LocationPickerViewInput.swift */, - 0E046F4922F1820400BD4E9C /* LocationPickerViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E046F4222F17ED700BD4E9C /* Router */ = { - isa = PBXGroup; - children = ( - 0E046F4E22F1827800BD4E9C /* LocationPickerRouterInput.swift */, - 0E046F5022F1828900BD4E9C /* LocationPickerRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E046F4322F17EDC00BD4E9C /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E046F5222F182AB00BD4E9C /* LocationPickerModuleInput.swift */, - 0E046F6122F193B300BD4E9C /* LocationPickerModuleOutput.swift */, - 0E046F5422F182BF00BD4E9C /* LocationPickerPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E046F4422F17EE100BD4E9C /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E046F5622F182E600BD4E9C /* Apple */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E046F4B22F1821000BD4E9C /* Apple */ = { - isa = PBXGroup; - children = ( - 0E046F4C22F1823C00BD4E9C /* LocationPickerAppleViewController.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 0E046F5622F182E600BD4E9C /* Apple */ = { - isa = PBXGroup; - children = ( - 0E046F5722F182F500BD4E9C /* LocationPickerAppleInitializer.swift */, - 0E046F5922F1832600BD4E9C /* LocationPickerAppleConfigurator.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 0E05014A26860375007060C4 /* AppState */ = { - isa = PBXGroup; - children = ( - 0E05014B26860375007060C4 /* Impl */, - 0E05014D26860375007060C4 /* AppStateService.swift */, - ); - path = AppState; - sourceTree = ""; - }; - 0E05014B26860375007060C4 /* Impl */ = { - isa = PBXGroup; - children = ( - 0E05014C26860375007060C4 /* AppStateServiceImpl.swift */, - ); - path = Impl; - sourceTree = ""; - }; - 0E05014E26860375007060C4 /* UniversalLinks */ = { - isa = PBXGroup; - children = ( - 0E05014F26860375007060C4 /* Coordinator */, - 0E05015326860375007060C4 /* Router */, - ); - path = UniversalLinks; - sourceTree = ""; - }; - 0E05014F26860375007060C4 /* Coordinator */ = { - isa = PBXGroup; - children = ( - 0E05015026860375007060C4 /* Impl */, - 0E05015226860375007060C4 /* UniversalLinkCoordinator.swift */, - ); - path = Coordinator; - sourceTree = ""; - }; - 0E05015026860375007060C4 /* Impl */ = { - isa = PBXGroup; - children = ( - 0E05015126860375007060C4 /* UniversalLinkCoordinatormpl.swift */, - ); - path = Impl; - sourceTree = ""; - }; - 0E05015326860375007060C4 /* Router */ = { - isa = PBXGroup; - children = ( - 0E05015426860375007060C4 /* Impl */, - 0E05015626860375007060C4 /* UniversalLinkRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E05015426860375007060C4 /* Impl */ = { - isa = PBXGroup; - children = ( - 0E05015526860375007060C4 /* UniversalLinkRouterImpl.swift */, - ); - path = Impl; - sourceTree = ""; - }; - 0E09671522AE74CB00E85F48 /* Application */ = { - isa = PBXGroup; - children = ( - 0E05014A26860375007060C4 /* AppState */, - 0EB66B2C2686058F00375BCC /* Features */, - 0EB66B382686058F00375BCC /* Info */, - 0E05014E26860375007060C4 /* UniversalLinks */, - 0E1C1DA722B387A00032F6CA /* AppAssembly.swift */, - 64333D2820B0C45900CDF4B6 /* AppDelegate.swift */, - ); - path = Application; - sourceTree = ""; - }; - 0E09671622AE74D600E85F48 /* Classes */ = { - isa = PBXGroup; - children = ( - 0E09671522AE74CB00E85F48 /* Application */, - 0E09671922AE764200E85F48 /* Presentation */, - 0E62298326A7FB4D0041DCDD /* Routers */, - ); - path = Classes; - sourceTree = ""; - }; - 0E09671722AE762900E85F48 /* Resources */ = { - isa = PBXGroup; - children = ( - 0EB48DE4261A17F4008E0D2D /* JSONs */, - 0E1C1DC722B396180032F6CA /* Strings */, - 0E09671A22AE769F00E85F48 /* Plists */, - 0E09671822AE763500E85F48 /* Images */, - 6486970E20E042BC00CCD7C1 /* Fonts */, - ); - path = Resources; - sourceTree = ""; - }; - 0E09671822AE763500E85F48 /* Images */ = { - isa = PBXGroup; - children = ( - 64333D2F20B0C45A00CDF4B6 /* Assets.xcassets */, - ); - path = Images; - sourceTree = ""; - }; - 0E09671922AE764200E85F48 /* Presentation */ = { - isa = PBXGroup; - children = ( - 0E1C1DBC22B3920C0032F6CA /* Assembly */, - 0EC50F4E22CCB91000172EEB /* Binding */, - 0EE36EA8269749F10021B746 /* Colors */, - 0E70A45E22AF9558006CB87C /* Contract */, - 0EE98A772649386000AAB3ED /* FLEX */, - 0E09671B22AE76B700E85F48 /* Launch */, - 0E70A46122AF958E006CB87C /* Localization */, - 0E09671C22AE76CC00E85F48 /* Modules */, - 0E1C1DAC22B38F220032F6CA /* Presenters */, - 0E046F3722F0585E00BD4E9C /* Transitions */, - ); - path = Presentation; - sourceTree = ""; - }; - 0E09671A22AE769F00E85F48 /* Plists */ = { - isa = PBXGroup; - children = ( - 0EB8B92D2683599100FE130E /* Networking.plist */, - 0E197C8023C5CDBE0074015B /* iOSDeviceModelMapping.plist */, - 0ECDF1B42313D65500A09ACA /* GoogleService-Info.plist */, - 64333D3420B0C45A00CDF4B6 /* Info.plist */, - 0EE49BB223B8C40D003012C2 /* DevInfo.plist */, - 0EE49BB123B8C40D003012C2 /* MacInfo.plist */, - ); - path = Plists; - sourceTree = ""; - }; - 0E09671B22AE76B700E85F48 /* Launch */ = { - isa = PBXGroup; - children = ( - 64333D3120B0C45A00CDF4B6 /* LaunchScreen.storyboard */, - ); - path = Launch; - sourceTree = ""; - }; - 0E09671C22AE76CC00E85F48 /* Modules */ = { - isa = PBXGroup; - children = ( - 0EEB20E922B7D1350015F9E0 /* About */, - 0E1C1DCE22B3BDAE0032F6CA /* Dashboard */, - 0E09672622AE8D6A00E85F48 /* Discover */, - 0E046F4022F17EC600BD4E9C /* LocationPicker */, - 0E09671D22AE76D800E85F48 /* Main */, - 0E1C1DEB22B3FDB40032F6CA /* Menu */, - 0EEB20CE22B7C6DA0015F9E0 /* Settings */, - 0EF2862522CBAF280026C7A5 /* TagSettings */, - 0E046F2022F049C500BD4E9C /* WebTagSettings */, - 0E09671E22AE7F2600E85F48 /* Welcome */, - 71A3760FF84549A5FB45C805 /* SignIn */, - DB47D7C8D6149FEA8DD05FDC /* Share */, - ); - path = Modules; - sourceTree = ""; - }; - 0E09671D22AE76D800E85F48 /* Main */ = { - isa = PBXGroup; - children = ( - 64333D2C20B0C45900CDF4B6 /* Main.storyboard */, - 0EEB213D22B8FB6B0015F9E0 /* Transition */, - 0EEB214022B8FB930015F9E0 /* Assembly */, - 0EEB213A22B8FABD0015F9E0 /* Router */, - ); - path = Main; - sourceTree = ""; - }; - 0E09671E22AE7F2600E85F48 /* Welcome */ = { - isa = PBXGroup; - children = ( - 0E09671F22AE7F5C00E85F48 /* Welcome.storyboard */, - 0EEB215422B8FD440015F9E0 /* Assembly */, - 0EEB214F22B8FCF80015F9E0 /* Presenter */, - 0EEB214A22B8FCB50015F9E0 /* Router */, - 0EEB214522B8FC2E0015F9E0 /* View */, - ); - path = Welcome; - sourceTree = ""; - }; - 0E09672322AE895600E85F48 /* Extensions */ = { - isa = PBXGroup; - children = ( - 0E92A973268636F500187E4F /* Structs */, - 0EA7966F2664A7B3002BA25D /* Errors */, - 0E92A978268636F600187E4F /* HumidityUnit+Localization.swift */, - 0E92A97A268636F700187E4F /* Language+Localization.swift */, - 0E92A979268636F600187E4F /* MeasurementType.swift */, - 0E92A972268636F500187E4F /* TemperatureUnit+Localization.swift */, - 0E92A977268636F600187E4F /* VirtualLocation+Localization.swift */, - 0E290A842660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift */, - 0E09672422AE897000E85F48 /* CALayer+IB.swift */, - 66718A6B266BD0E800A380F8 /* Color+Ruuvi.swift */, - 0EF5B72A22D62CD900D9D14A /* Date+Ruuvi.swift */, - 0EF4E35126831A0B00D83CC7 /* DfuFirmware+Log.swift */, - A98BC874250E4265001CEFDC /* Double+Round.swift */, - 0E02ABCA2379483A00ED4629 /* Double+Temperature.swift */, - A9BD38B924F6108300904BBE /* Humidity+Offset.swift */, - A9A67BF924C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift */, - A9E6774725A33081000B75A3 /* String+Characters.swift */, - 0E9E7759238CCE5F006D7013 /* String+Replace.swift */, - 0E1C1DBA22B3919F0032F6CA /* UIApplication+ViewController.swift */, - 0E197C7C23C5CD7C0074015B /* UIDevice+ReadableModel.swift */, - A92A66BC2450C640002918E7 /* UITableViewCell+ReusableView.swift */, - 660EB29B266928E6000FD22B /* UIViewController+Alert.swift */, - A907BB1024AE620A009DA3DB /* UIWindow+Orientation.swift */, - A9A48A5B244CD9E70004FD50 /* UIWindow+Shake.swift */, - A91D031925113EAA00694733 /* UnitPressure+Extension.swift */, - 0E0A381823616AC3003A0364 /* UserDefaults+Optional.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 0E09672622AE8D6A00E85F48 /* Discover */ = { - isa = PBXGroup; - children = ( - 0E09672722AE8D7A00E85F48 /* Discover.storyboard */, - 0E70A47622AF9B69006CB87C /* Assembly */, - 0E70A47122AF993F006CB87C /* Presenter */, - 0E502FBC22B2816400E8A6CC /* Router */, - 0E70A46922AF96B9006CB87C /* View */, - ); - path = Discover; - sourceTree = ""; - }; - 0E197C6423C4A44C0074015B /* MailComposer */ = { - isa = PBXGroup; - children = ( - 0E197C6923C4A4960074015B /* MessageUI */, - 0E197C6523C4A47A0074015B /* MailComposerPresenter.swift */, - ); - path = MailComposer; - sourceTree = ""; - }; - 0E197C6923C4A4960074015B /* MessageUI */ = { - isa = PBXGroup; - children = ( - 0E197C6A23C4A52A0074015B /* MailComposerPresenterMessageUI.swift */, - ); - path = MessageUI; - sourceTree = ""; - }; - 0E1C1DAC22B38F220032F6CA /* Presenters */ = { - isa = PBXGroup; - children = ( - 0E1C1DAD22B38F320032F6CA /* Activity */, - A93CDCCC25659B8600018C6C /* Alert */, - 66718A61266A6CA700A380F8 /* DfuFilePicker */, - 0E1C1DBF22B3954E0032F6CA /* Error */, - 0E197C6423C4A44C0074015B /* MailComposer */, - 0E5C301722CF642F00B52E39 /* Permission */, - 0EC50F5722CF61F700172EEB /* PhotoPicker */, - ); - path = Presenters; - sourceTree = ""; - }; - 0E1C1DAD22B38F320032F6CA /* Activity */ = { - isa = PBXGroup; - children = ( - 0E1C1DB022B38F840032F6CA /* RuuviLogo */, - 0E1C1DAE22B38F780032F6CA /* ActivityPresenter.swift */, - ); - path = Activity; - sourceTree = ""; - }; - 0E1C1DB022B38F840032F6CA /* RuuviLogo */ = { - isa = PBXGroup; - children = ( - 0E1C1DB122B38FFA0032F6CA /* View */, - 0E1C1DB222B390080032F6CA /* ActivityPresenterRuuviLogo.swift */, - ); - path = RuuviLogo; - sourceTree = ""; - }; - 0E1C1DB122B38FFA0032F6CA /* View */ = { - isa = PBXGroup; - children = ( - 0E1C1DB422B3903B0032F6CA /* ActivityRuuviLogo.storyboard */, - 0E1C1DB622B390BC0032F6CA /* ActivityRuuviLogoViewController.swift */, - 0E1C1DB822B390ED0032F6CA /* ActivitySpinnerView.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E1C1DBC22B3920C0032F6CA /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E1C1DBD22B3921E0032F6CA /* PresentationAssembly.swift */, - 0E197C6E23C4A7D00074015B /* Presentation.plist */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E1C1DBF22B3954E0032F6CA /* Error */ = { - isa = PBXGroup; - children = ( - 0E1C1DC222B395B10032F6CA /* Alert */, - 0E1C1DC022B3955E0032F6CA /* ErrorPresenter.swift */, - ); - path = Error; - sourceTree = ""; - }; - 0E1C1DC222B395B10032F6CA /* Alert */ = { - isa = PBXGroup; - children = ( - 0E1C1DC322B395C00032F6CA /* ErrorPresenterAlert.swift */, - ); - path = Alert; - sourceTree = ""; - }; - 0E1C1DC722B396180032F6CA /* Strings */ = { - isa = PBXGroup; - children = ( - A96B1F2225A7943E00D3ED9C /* station.localization.json */, - 0EEB20C922B7A7200015F9E0 /* Localizable.strings */, - 0E53A3F3232DFC6200ACED49 /* InfoPlist.strings */, - ); - path = Strings; - sourceTree = ""; - }; - 0E1C1DCE22B3BDAE0032F6CA /* Dashboard */ = { - isa = PBXGroup; - children = ( - 0E8FD0D823336E8E00FFA577 /* Cards */, - 0E8FD0D923336EB200FFA577 /* Charts */, - A90E168C24604F0E00631E6C /* Chart */, - ); - path = Dashboard; - sourceTree = ""; - }; - 0E1C1DCF22B3BDBB0032F6CA /* View */ = { - isa = PBXGroup; - children = ( - 0E1C1DD622B3BF760032F6CA /* Scroll */, - 0E1C1DD222B3BF180032F6CA /* CardsViewInput.swift */, - 0E1C1DD422B3BF3A0032F6CA /* CardsViewOutput.swift */, - 0EEB20C522B7915C0015F9E0 /* CardsViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E1C1DD622B3BF760032F6CA /* Scroll */ = { - isa = PBXGroup; - children = ( - 0ECB5A8F2381809900E78757 /* View */, - 0ECB5A8D2381807500E78757 /* CardsScrollViewController.swift */, - ); - path = Scroll; - sourceTree = ""; - }; - 0E1C1DDB22B3C1F30032F6CA /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E1C1DDC22B3C2160032F6CA /* CardsModuleInput.swift */, - 0E1C1DDE22B3C2330032F6CA /* CardsPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E1C1DE022B3C24F0032F6CA /* Router */ = { - isa = PBXGroup; - children = ( - 0E1C1DE122B3C25F0032F6CA /* CardsRouterInput.swift */, - 0E211C29234C5FE900FC37B0 /* CardsRouterDelegate.swift */, - 0E1C1DE322B3C2710032F6CA /* CardsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E1C1DE522B3C2900032F6CA /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E1C1DE622B3C2A80032F6CA /* Scroll */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E1C1DE622B3C2A80032F6CA /* Scroll */ = { - isa = PBXGroup; - children = ( - 0E1C1DE722B3C2B60032F6CA /* CardsScrollInitializer.swift */, - 0E1C1DE922B3C2E60032F6CA /* CardsScrollConfigurator.swift */, - ); - path = Scroll; - sourceTree = ""; - }; - 0E1C1DEB22B3FDB40032F6CA /* Menu */ = { - isa = PBXGroup; - children = ( - 0E1C1DF022B3FDE30032F6CA /* Menu.storyboard */, - 0E1C1DEF22B3FDD60032F6CA /* Assembly */, - 0E1C1E0622B401A80032F6CA /* Transition */, - 0E1C1DEE22B3FDCC0032F6CA /* Presenter */, - 0E1C1DED22B3FDC70032F6CA /* Router */, - 0E1C1DEC22B3FDBB0032F6CA /* View */, - ); - path = Menu; - sourceTree = ""; - }; - 0E1C1DEC22B3FDBB0032F6CA /* View */ = { - isa = PBXGroup; - children = ( - 0E1C1DF622B3FF2F0032F6CA /* Table */, - 0E1C1DF222B3FEFF0032F6CA /* MenuViewInput.swift */, - 0E1C1DF422B3FF1D0032F6CA /* MenuViewOutput.swift */, - A93CDCAA25657C1D00018C6C /* MenuViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E1C1DED22B3FDC70032F6CA /* Router */ = { - isa = PBXGroup; - children = ( - 0E1C1DF922B3FFBF0032F6CA /* MenuRouterInput.swift */, - 0E1C1DFB22B3FFD90032F6CA /* MenuRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E1C1DEE22B3FDCC0032F6CA /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E1C1DFD22B3FFFC0032F6CA /* MenuModuleInput.swift */, - 0EEB20CC22B7BD6C0015F9E0 /* MenuModuleOutput.swift */, - 0E1C1DFF22B400130032F6CA /* MenuPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E1C1DEF22B3FDD60032F6CA /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E1C1E0122B400470032F6CA /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E1C1DF622B3FF2F0032F6CA /* Table */ = { - isa = PBXGroup; - children = ( - 0EEB20CA22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift */, - 0E1C1DF722B3FF480032F6CA /* MenuTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E1C1E0122B400470032F6CA /* Table */ = { - isa = PBXGroup; - children = ( - 0E1C1E0222B400590032F6CA /* MenuTableInitializer.swift */, - 0E1C1E0422B400890032F6CA /* MenuTableConfigurator.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E1C1E0622B401A80032F6CA /* Transition */ = { - isa = PBXGroup; - children = ( - 0E1C1E0722B4022F0032F6CA /* Table */, - ); - path = Transition; - sourceTree = ""; - }; - 0E1C1E0722B4022F0032F6CA /* Table */ = { - isa = PBXGroup; - children = ( - 0EEB215922BA28860015F9E0 /* MenuTableTransitionManager.swift */, - 0E1C1E0822B4024E0032F6CA /* MenuTableTransitioningDelegate.swift */, - 0E1C1E0A22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift */, - 0E1C1E0C22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift */, - 0E1C1E0E22B4049E0032F6CA /* MenuTablePresentationController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E31B04023BBA34C00660412 /* SectionHeader */ = { - isa = PBXGroup; - children = ( - 0E31B04123BBA37C00660412 /* WebTagSettingsAlertsHeaderFooterView.swift */, - 0E31B04523BBA3F900660412 /* WebTagSettingsAlertsHeaderFooterView.xib */, - ); - path = SectionHeader; - sourceTree = ""; - }; - 0E3FF731238156AF00EB98F9 /* SectionHeader */ = { - isa = PBXGroup; - children = ( - 0E3FF7362381591800EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.swift */, - 0E3FF734238157B700EB98F9 /* DiscoverWebTagsInfoHeaderFooterView.xib */, - ); - path = SectionHeader; - sourceTree = ""; - }; - 0E502FBC22B2816400E8A6CC /* Router */ = { - isa = PBXGroup; - children = ( - 0E502FBD22B2817900E8A6CC /* DiscoverRouterInput.swift */, - 0E502FBF22B2819B00E8A6CC /* DiscoverRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E5C301722CF642F00B52E39 /* Permission */ = { - isa = PBXGroup; - children = ( - 0E5C301822CF643C00B52E39 /* Alert */, - 0E5C301922CF644900B52E39 /* PermissionPresenter.swift */, - ); - path = Permission; - sourceTree = ""; - }; - 0E5C301822CF643C00B52E39 /* Alert */ = { - isa = PBXGroup; - children = ( - 0E5C301B22CF646A00B52E39 /* PermissionPresenterAlert.swift */, - ); - path = Alert; - sourceTree = ""; - }; - 0E62298326A7FB4D0041DCDD /* Routers */ = { - isa = PBXGroup; - children = ( - 0E62298426A7FB4D0041DCDD /* OnboardRouter.swift */, - 0E62298526A7FB4D0041DCDD /* AppRouter.swift */, - ); - path = Routers; - sourceTree = ""; - }; - 0E70A45E22AF9558006CB87C /* Contract */ = { - isa = PBXGroup; - children = ( - 0E70A45F22AF9567006CB87C /* ViewInput.swift */, - ); - path = Contract; - sourceTree = ""; - }; - 0E70A46122AF958E006CB87C /* Localization */ = { - isa = PBXGroup; - children = ( - 0E70A46222AF959E006CB87C /* Localizable.swift */, - A949A83A24707FD0006B7F4F /* LocalizedCache.swift */, - 0E9D0AB0231EBEFD00C6BDA7 /* LocalizationService.swift */, - ); - path = Localization; - sourceTree = ""; - }; - 0E70A46922AF96B9006CB87C /* View */ = { - isa = PBXGroup; - children = ( - 0EF4E31526823F6100D83CC7 /* Model */, - 0E70A46A22AF96C5006CB87C /* Table */, - 0E70A46D22AF9763006CB87C /* DiscoverViewInput.swift */, - 0E70A46F22AF9790006CB87C /* DiscoverViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E70A46A22AF96C5006CB87C /* Table */ = { - isa = PBXGroup; - children = ( - 0EF26D172381A12F005BD84E /* Cell */, - 0E3FF731238156AF00EB98F9 /* SectionHeader */, - 0E70A46B22AF9705006CB87C /* DiscoverTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E70A47122AF993F006CB87C /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E70A47222AF9953006CB87C /* DiscoverModuleInput.swift */, - 0E84BF4C239795AF00A37E1A /* DiscoverModuleOutput.swift */, - 0E70A47422AF9978006CB87C /* DiscoverPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E70A47622AF9B69006CB87C /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E70A47922AF9BC6006CB87C /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E70A47922AF9BC6006CB87C /* Table */ = { - isa = PBXGroup; - children = ( - 0E70A47A22AF9BE2006CB87C /* DiscoverTableInitializer.swift */, - 0E70A47C22AF9BFE006CB87C /* DiscoverTableConfigurator.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E84BF4F2397F24D00A37E1A /* Heartbeat */ = { - isa = PBXGroup; - children = ( - 0E84BF542397F29800A37E1A /* Heartbeat.storyboard */, - 0E84BF532397F28800A37E1A /* Assembly */, - 0E84BF522397F28200A37E1A /* Presenter */, - 0E84BF512397F27E00A37E1A /* Router */, - 0E84BF502397F27900A37E1A /* View */, - ); - path = Heartbeat; - sourceTree = ""; - }; - 0E84BF502397F27900A37E1A /* View */ = { - isa = PBXGroup; - children = ( - 0E84BF5C2397F3E600A37E1A /* SwiftUI */, - 0E84BF5D2397F3F000A37E1A /* Table */, - 0E84BF562397F33E00A37E1A /* HeartbeatViewInput.swift */, - 0E84BF582397F3C600A37E1A /* HeartbeatViewModel.swift */, - 0E84BF5A2397F3DF00A37E1A /* HeartbeatViewOutput.swift */, - 0E84BF5E2397F6BE00A37E1A /* HeartbeatViewController.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E84BF512397F27E00A37E1A /* Router */ = { - isa = PBXGroup; - children = ( - 0E84BF66239801AF00A37E1A /* HeartbeatRouterInput.swift */, - 0E84BF68239801C100A37E1A /* HeartbeatRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E84BF522397F28200A37E1A /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E84BF6A239802A400A37E1A /* HeartbeatModuleInput.swift */, - 0E84BF6C239802CA00A37E1A /* HeartbeatPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E84BF532397F28800A37E1A /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E84BF6E2398031B00A37E1A /* HeartbeatInitializer.swift */, - 0E84BF702398035C00A37E1A /* HeartbeatConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E84BF5C2397F3E600A37E1A /* SwiftUI */ = { - isa = PBXGroup; - children = ( - 0E84BF622397F76A00A37E1A /* HeartbeatList.swift */, - 0E84BF602397F73100A37E1A /* HeartbeatEnvironmentObject.swift */, - ); - path = SwiftUI; - sourceTree = ""; - }; - 0E84BF5D2397F3F000A37E1A /* Table */ = { - isa = PBXGroup; - children = ( - 0E84BF642397F9DC00A37E1A /* HeartbeatTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E8A100023845E1200A9CBA6 /* Defaults */ = { - isa = PBXGroup; - children = ( - 0E8A100123845E5100A9CBA6 /* Defaults.storyboard */, - 0E8A100623845E9400A9CBA6 /* Assembly */, - 0E8A100523845E8A00A9CBA6 /* Presenter */, - 0E8A100423845E8200A9CBA6 /* Router */, - 0E8A100323845E7D00A9CBA6 /* View */, - ); - path = Defaults; - sourceTree = ""; - }; - 0E8A100323845E7D00A9CBA6 /* View */ = { - isa = PBXGroup; - children = ( - 0E8A100723845F1B00A9CBA6 /* SwiftUI */, - 0E8A100823845F2300A9CBA6 /* Table */, - 0E8A100923845F3900A9CBA6 /* DefaultsViewController.swift */, - 0E8A100B23845F7100A9CBA6 /* DefaultsViewInput.swift */, - 0E8A100D23845F8C00A9CBA6 /* DefaultsViewOutput.swift */, - 0E8A100F23845FAE00A9CBA6 /* DefaultsViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E8A100423845E8200A9CBA6 /* Router */ = { - isa = PBXGroup; - children = ( - 0E8A10152384612300A9CBA6 /* DefaultsRouterInput.swift */, - 0E8A10132384610400A9CBA6 /* DefaultsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E8A100523845E8A00A9CBA6 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E8A10172384613E00A9CBA6 /* DefaultsModuleInput.swift */, - 0E8A10192384615400A9CBA6 /* DefaultsPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E8A100623845E9400A9CBA6 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E8A101B2384618700A9CBA6 /* DefaultsInitializer.swift */, - 0E8A101D238461D400A9CBA6 /* DefaultsConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E8A100723845F1B00A9CBA6 /* SwiftUI */ = { - isa = PBXGroup; - children = ( - 0E8A10212384637F00A9CBA6 /* DefaultsList.swift */, - 0E8A101F2384633200A9CBA6 /* DefaultsEnvironmentObject.swift */, - ); - path = SwiftUI; - sourceTree = ""; - }; - 0E8A100823845F2300A9CBA6 /* Table */ = { - isa = PBXGroup; - children = ( - 0E8A102323846CCE00A9CBA6 /* Cells */, - 0E8A10112384605A00A9CBA6 /* DefaultsTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E8A102323846CCE00A9CBA6 /* Cells */ = { - isa = PBXGroup; - children = ( - 0E8A102423846CEB00A9CBA6 /* DefaultsSwitchTableViewCell.swift */, - 0E8BD2AA23851CF2008B31EF /* DefaultsStepperTableViewCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - 0E8FD0B923335D4300FFA577 /* View */ = { - isa = PBXGroup; - children = ( - 0E8FD0DA23336FCA00FFA577 /* Scroll */, - 0E8FD0C223335DA700FFA577 /* TagChartsViewInput.swift */, - 0E8FD0C423335DBF00FFA577 /* TagChartsViewOutput.swift */, - 0E8FD0DC2333714C00FFA577 /* TagChartsViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E8FD0BA23335D4700FFA577 /* Router */ = { - isa = PBXGroup; - children = ( - 0E8FD0C6233366DC00FFA577 /* TagChartsRouterInput.swift */, - 0E8FD0C8233366F000FFA577 /* TagChartsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E8FD0BB23335D4C00FFA577 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E8FD0CA2333671100FFA577 /* TagChartsModuleInput.swift */, - 0E8FD0E22333893600FFA577 /* TagChartsModuleOutput.swift */, - 0E8FD0CC2333672F00FFA577 /* TagChartsPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E8FD0BC23335D5200FFA577 /* Transition */ = { - isa = PBXGroup; - children = ( - 0E8FD0D223336B4200FFA577 /* TagChartsTransitioningDelegate.swift */, - 0E341BBC2372E75C0085BB54 /* TagChartsTransitionManager.swift */, - 0E8FD0D423336BA300FFA577 /* TagChartsPresentTransitionAnimation.swift */, - 0E8FD0D623336C6E00FFA577 /* TagChartsDismissTransitionAnimation.swift */, - ); - path = Transition; - sourceTree = ""; - }; - 0E8FD0BD23335D5800FFA577 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E8FD0DB2333704400FFA577 /* Scroll */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E8FD0D823336E8E00FFA577 /* Cards */ = { - isa = PBXGroup; - children = ( - 0E1C1DD022B3BDFC0032F6CA /* Cards.storyboard */, - 0E1C1DE522B3C2900032F6CA /* Assembly */, - 0E1C1DDB22B3C1F30032F6CA /* Presenter */, - 0E1C1DE022B3C24F0032F6CA /* Router */, - 0E1C1DCF22B3BDBB0032F6CA /* View */, - ); - path = Cards; - sourceTree = ""; - }; - 0E8FD0D923336EB200FFA577 /* Charts */ = { - isa = PBXGroup; - children = ( - 0E8FD0BE23335D6900FFA577 /* TagCharts.storyboard */, - 0E8FD0BD23335D5800FFA577 /* Assembly */, - 0E8FD0BC23335D5200FFA577 /* Transition */, - 0E8FD0BB23335D4C00FFA577 /* Presenter */, - A90E169A24606A3900631E6C /* Interactor */, - 0E8FD0BA23335D4700FFA577 /* Router */, - 0E8FD0B923335D4300FFA577 /* View */, - ); - path = Charts; - sourceTree = ""; - }; - 0E8FD0DA23336FCA00FFA577 /* Scroll */ = { - isa = PBXGroup; - children = ( - 0E8FD0C023335D8400FFA577 /* TagChartsScrollViewController.swift */, - ); - path = Scroll; - sourceTree = ""; - }; - 0E8FD0DB2333704400FFA577 /* Scroll */ = { - isa = PBXGroup; - children = ( - 0E8FD0CE2333676C00FFA577 /* TagChartsScrollInitializer.swift */, - 0E8FD0D02333679800FFA577 /* TagChartsScrollConfigurator.swift */, - ); - path = Scroll; - sourceTree = ""; - }; - 0E92A973268636F500187E4F /* Structs */ = { - isa = PBXGroup; - children = ( - 0E92A974268636F500187E4F /* ExportHeadersProvider.swift */, - 0E92A975268636F500187E4F /* HeartbeatDaemonTitles.swift */, - 0E92A976268636F500187E4F /* RuuviNotifierTitlesImpl.swift */, - ); - path = Structs; - sourceTree = ""; - }; - 0E9D5F1E2351BCBA0076FFD8 /* Cells */ = { - isa = PBXGroup; - children = ( - 0EF6F5BF235E01CD0052BA25 /* ForegroundStepperTableViewCell.swift */, - 0E9D5F1F2351BE3C0076FFD8 /* ForegroundSwitchTableViewCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - 0EA7966F2664A7B3002BA25D /* Errors */ = { - isa = PBXGroup; - children = ( - 0E92A9832686370000187E4F /* RUError.swift */, - 0E05013E26860099007060C4 /* RuuviDaemonError+LocalizedError.swift */, - 0E05013F26860099007060C4 /* RuuviDFUError+LocalizedError.swift */, - 0EF4E30F26823F3D00D83CC7 /* RuuviCoreError+LocalizedError.swift */, - 0EF4E31026823F3D00D83CC7 /* RuuviVirtualError+LocalizedError.swift */, - 0EA796702664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift */, - 0EA796742664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift */, - 0EA796782664B37F002BA25D /* RuuviLocalError+LocalizedError.swift */, - 0EA7967C2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift */, - 0EA796802664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift */, - 0EA796842664B84D002BA25D /* RuuviReactorError+LocalizedError.swift */, - 0EA796882664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift */, - 0EA7968C2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift */, - 0E2AFF9F266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift */, - ); - path = Errors; - sourceTree = ""; - }; - 0EAD33F3239A571B00EC5BAA /* Cells */ = { - isa = PBXGroup; - children = ( - 0E1B2F31239DEF120060C469 /* TagSettingsAlertHeaderCell.swift */, - 0E1B2F35239DF0120060C469 /* TagSettingsAlertControlsCell.swift */, - 0E197C6023C352380074015B /* TagSettingsAlertDescriptionCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - 0EB48DE4261A17F4008E0D2D /* JSONs */ = { - isa = PBXGroup; - children = ( - 0EB48DE5261A1816008E0D2D /* FeatureToggles.json */, - ); - path = JSONs; - sourceTree = ""; - }; - 0EB66B2C2686058F00375BCC /* Features */ = { - isa = PBXGroup; - children = ( - 0EB66B2D2686058F00375BCC /* Providers */, - 0EB66B322686058F00375BCC /* RemoteConfig */, - 0EB66B362686058F00375BCC /* FeatureToggleService.swift */, - 0EB66B372686058F00375BCC /* FeatureToggle.swift */, - ); - path = Features; - sourceTree = ""; - }; - 0EB66B2D2686058F00375BCC /* Providers */ = { - isa = PBXGroup; - children = ( - 0EB66B2E2686058F00375BCC /* FeatureToggleProvider.swift */, - 0EB66B2F2686058F00375BCC /* FallbackFeatureToggleProvider.swift */, - 0EB66B302686058F00375BCC /* FirebaseFeatureToggleProvider.swift */, - 0EB66B312686058F00375BCC /* LocalFeatureToggleProvider.swift */, - ); - path = Providers; - sourceTree = ""; - }; - 0EB66B322686058F00375BCC /* RemoteConfig */ = { - isa = PBXGroup; - children = ( - 0EB66B332686058F00375BCC /* Firebase */, - 0EB66B352686058F00375BCC /* RemoteConfigService.swift */, - ); - path = RemoteConfig; - sourceTree = ""; - }; - 0EB66B332686058F00375BCC /* Firebase */ = { - isa = PBXGroup; - children = ( - 0EB66B342686058F00375BCC /* FirebaseRemoteConfigService.swift */, - ); - path = Firebase; - sourceTree = ""; - }; - 0EB66B382686058F00375BCC /* Info */ = { - isa = PBXGroup; - children = ( - 0EB66B392686058F00375BCC /* Impl */, - 0EB66B3B2686058F00375BCC /* InfoProvider.swift */, - ); - path = Info; - sourceTree = ""; - }; - 0EB66B392686058F00375BCC /* Impl */ = { - isa = PBXGroup; - children = ( - 0EB66B3A2686058F00375BCC /* InfoProviderImpl.swift */, - ); - path = Impl; - sourceTree = ""; - }; - 0EBAF062232000F50025A191 /* Module */ = { - isa = PBXGroup; - children = ( - 0EEB20D022B7C6F30015F9E0 /* Settings.storyboard */, - 0EEB20DB22B7C83E0015F9E0 /* Assembly */, - 0EEB20DA22B7C8380015F9E0 /* Presenter */, - 0EEB20D922B7C8330015F9E0 /* Router */, - 0EEB20CF22B7C6E40015F9E0 /* View */, - ); - path = Module; - sourceTree = ""; - }; - 0EBAF063232001080025A191 /* Submodules */ = { - isa = PBXGroup; - children = ( - A9828E54247BAC0700E7E9D4 /* Advanced */, - 0E8A100023845E1200A9CBA6 /* Defaults */, - 0ECFF34F235056770061D11B /* Foreground */, - 0E84BF4F2397F24D00A37E1A /* Heartbeat */, - 0EBAF066232005600025A191 /* Language */, - A91D02D92511207200694733 /* Selection */, - ); - path = Submodules; - sourceTree = ""; - }; - 0EBAF066232005600025A191 /* Language */ = { - isa = PBXGroup; - children = ( - 0EBAF06B232006E00025A191 /* Language.storyboard */, - 0EBAF06A232005740025A191 /* Assembly */, - 0EBAF0692320056F0025A191 /* Presenter */, - 0EBAF0682320056B0025A191 /* Router */, - 0EBAF067232005670025A191 /* View */, - ); - path = Language; - sourceTree = ""; - }; - 0EBAF067232005670025A191 /* View */ = { - isa = PBXGroup; - children = ( - 0EBAF073232007940025A191 /* Table */, - 0EBAF06D232007510025A191 /* LanguageViewInput.swift */, - 0EBAF06F232007740025A191 /* LanguageViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 0EBAF0682320056B0025A191 /* Router */ = { - isa = PBXGroup; - children = ( - 0EBAF074232007CC0025A191 /* LanguageRouterInput.swift */, - 0EBAF076232007D80025A191 /* LanguageRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0EBAF0692320056F0025A191 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0EBAF078232008140025A191 /* LanguageModuleInput.swift */, - 0EBAF07A232008420025A191 /* LanguagePresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0EBAF06A232005740025A191 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0EBAF07C2320085F0025A191 /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - 0EBAF073232007940025A191 /* Table */ = { - isa = PBXGroup; - children = ( - 0EBAF08123200B1B0025A191 /* LanguageTableViewCell.swift */, - 0EBAF071232007910025A191 /* LanguageTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0EBAF07C2320085F0025A191 /* Table */ = { - isa = PBXGroup; - children = ( - 0EBAF07D2320086A0025A191 /* LanguageTableInitializer.swift */, - 0EBAF07F2320089A0025A191 /* LanguageTableConfigurator.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0EC50F4E22CCB91000172EEB /* Binding */ = { - isa = PBXGroup; - children = ( - 0EC50F4F22CCB92000172EEB /* Observable.swift */, - 0EC50F5522CCE46D00172EEB /* Optional.swift */, - 0EC50F5322CCBBE800172EEB /* NSObject+Observable.swift */, - ); - path = Binding; - sourceTree = ""; - }; - 0EC50F5722CF61F700172EEB /* PhotoPicker */ = { - isa = PBXGroup; - children = ( - 0EC50F5A22CF624200172EEB /* Sheet */, - 0EC50F5822CF621000172EEB /* PhotoPickerPresenter.swift */, - ); - path = PhotoPicker; - sourceTree = ""; - }; - 0EC50F5A22CF624200172EEB /* Sheet */ = { - isa = PBXGroup; - children = ( - 0E5C300A22CF629100B52E39 /* PhotoPickerPresenterSheet.swift */, - ); - path = Sheet; - sourceTree = ""; - }; - 0ECB5A8F2381809900E78757 /* View */ = { - isa = PBXGroup; - children = ( - 0E1C1E1222B756D30032F6CA /* CardView.xib */, - 0E1C1E1022B756B40032F6CA /* CardView.swift */, - ); - path = View; - sourceTree = ""; - }; - 0ECFF34F235056770061D11B /* Foreground */ = { - isa = PBXGroup; - children = ( - 0ECFF35623505F8D0061D11B /* Foreground.storyboard */, - 0ECFF353235056920061D11B /* Assembly */, - 0ECFF3522350568C0061D11B /* Presenter */, - 0ECFF351235056870061D11B /* Router */, - 0ECFF3502350567E0061D11B /* View */, - ); - path = Foreground; - sourceTree = ""; - }; - 0ECFF3502350567E0061D11B /* View */ = { - isa = PBXGroup; - children = ( - 0ECFF35C23506B8A0061D11B /* SwiftUI */, - 0EE5B4802351AB3C00D5ED32 /* Table */, - 0ECFF35F23506BD60061D11B /* ForegroundViewInput.swift */, - 0ECFF35D23506BC40061D11B /* ForegroundViewOutput.swift */, - 0ECFF358235060EF0061D11B /* ForegroundViewController.swift */, - 0ECFF36F23507CE80061D11B /* ForegroundViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - 0ECFF351235056870061D11B /* Router */ = { - isa = PBXGroup; - children = ( - 0ECFF36723507A1A0061D11B /* ForegroundRouterInput.swift */, - 0EF6F5BD235E01170052BA25 /* ForegroundRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0ECFF3522350568C0061D11B /* Presenter */ = { - isa = PBXGroup; - children = ( - 0ECFF35A2350618E0061D11B /* ForegroundModuleInput.swift */, - 0ECFF365235079F50061D11B /* ForegroundPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0ECFF353235056920061D11B /* Assembly */ = { - isa = PBXGroup; - children = ( - 0ECFF36B23507BC00061D11B /* ForegroundInitializer.swift */, - 0ECFF36D23507BF00061D11B /* ForegroundConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 0ECFF35C23506B8A0061D11B /* SwiftUI */ = { - isa = PBXGroup; - children = ( - 0ECFF354235056DC0061D11B /* ForegroundList.swift */, - 0ECFF36123506C050061D11B /* ForegroundRow.swift */, - 0EE5B47C23508F6D00D5ED32 /* ForegroundEnvironmentObject.swift */, - ); - path = SwiftUI; - sourceTree = ""; - }; - 0EE36E80269749DE0021B746 /* DFU */ = { - isa = PBXGroup; - children = ( - 0EE36E81269749DE0021B746 /* FirmwareRepository */, - 0EE36E83269749DE0021B746 /* Presenter */, - 0EE36E86269749DE0021B746 /* Extensions */, - 0EE36E8A269749DE0021B746 /* Common */, - 0EE36E8F269749DE0021B746 /* View */, - 0EE36E93269749DE0021B746 /* Interactor */, - 0EE36E97269749DE0021B746 /* DFUModuleFactory.swift */, - ); - path = DFU; - sourceTree = ""; - }; - 0EE36E81269749DE0021B746 /* FirmwareRepository */ = { - isa = PBXGroup; - children = ( - 0EE36E82269749DE0021B746 /* FirmwareRepository.swift */, - ); - path = FirmwareRepository; - sourceTree = ""; - }; - 0EE36E83269749DE0021B746 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0EE36E84269749DE0021B746 /* DFUModuleInput.swift */, - 0EE36E85269749DE0021B746 /* DFUPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0EE36E86269749DE0021B746 /* Extensions */ = { - isa = PBXGroup; - children = ( - 0EE36E87269749DE0021B746 /* Publishers+System.swift */, - 0EE36E88269749DE0021B746 /* URLSession+downloadTaskPublisher.swift */, - 0EE36E89269749DE0021B746 /* View+Any.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 0EE36E8A269749DE0021B746 /* Common */ = { - isa = PBXGroup; - children = ( - 0EE36E8B269749DE0021B746 /* Spinner.swift */, - 0EE36E8C269749DE0021B746 /* LargeButtonStyle.swift */, - 0EE36E8D269749DE0021B746 /* ProgressBar.swift */, - 0EE36E8E269749DE0021B746 /* Feedback.swift */, - ); - path = Common; - sourceTree = ""; - }; - 0EE36E8F269749DE0021B746 /* View */ = { - isa = PBXGroup; - children = ( - 0EE36E90269749DE0021B746 /* DFUViewModel.swift */, - 0EE36E91269749DE0021B746 /* SwiftUI */, - ); - path = View; - sourceTree = ""; - }; - 0EE36E91269749DE0021B746 /* SwiftUI */ = { - isa = PBXGroup; - children = ( - 0EE36E92269749DE0021B746 /* DFUUIView.swift */, - ); - path = SwiftUI; - sourceTree = ""; - }; - 0EE36E93269749DE0021B746 /* Interactor */ = { - isa = PBXGroup; - children = ( - 0EE36E94269749DE0021B746 /* DFUInteractorInput.swift */, - 0EE36E95269749DE0021B746 /* DFUInteractor.swift */, - 0EE36E96269749DE0021B746 /* LatestRelease.swift */, - ); - path = Interactor; - sourceTree = ""; - }; - 0EE36EA8269749F10021B746 /* Colors */ = { - isa = PBXGroup; - children = ( - 0EE36EA9269749F10021B746 /* RuuviColor.swift */, - ); - path = Colors; - sourceTree = ""; - }; - 0EE49B9323B74704003012C2 /* Cells */ = { - isa = PBXGroup; - children = ( - 0EE49B9423B74775003012C2 /* WebTagSettingsAlertHeaderCell.swift */, - 0EE49B9823B877CF003012C2 /* WebTagSettingsAlertControlsCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - 0EE5B4802351AB3C00D5ED32 /* Table */ = { - isa = PBXGroup; - children = ( - 0E9D5F1E2351BCBA0076FFD8 /* Cells */, - 0EF6F5C1235E02000052BA25 /* ForegroundTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0EE98A772649386000AAB3ED /* FLEX */ = { - isa = PBXGroup; - children = ( - 0EE98A7826493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift */, - ); - path = FLEX; - sourceTree = ""; - }; - 0EEB20CE22B7C6DA0015F9E0 /* Settings */ = { - isa = PBXGroup; - children = ( - 0EBAF062232000F50025A191 /* Module */, - 0EBAF063232001080025A191 /* Submodules */, - ); - path = Settings; - sourceTree = ""; - }; - 0EEB20CF22B7C6E40015F9E0 /* View */ = { - isa = PBXGroup; - children = ( - 0EEB20D422B7C7BE0015F9E0 /* Table */, - 0EEB20D522B7C7E70015F9E0 /* SettingsViewInput.swift */, - 0EEB20D722B7C8060015F9E0 /* SettingsViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 0EEB20D422B7C7BE0015F9E0 /* Table */ = { - isa = PBXGroup; - children = ( - 0EEB20D222B7C7AC0015F9E0 /* SettingsTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0EEB20D922B7C8330015F9E0 /* Router */ = { - isa = PBXGroup; - children = ( - 0EEB20DC22B7C8650015F9E0 /* SettingsRouterInput.swift */, - 0EEB20DE22B7C8790015F9E0 /* SettingsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0EEB20DA22B7C8380015F9E0 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0EEB20E022B7C8A90015F9E0 /* SettingsModuleInput.swift */, - 0EEB20E222B7C8C10015F9E0 /* SettingsPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0EEB20DB22B7C83E0015F9E0 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0EEB20E422B7C8E60015F9E0 /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - 0EEB20E422B7C8E60015F9E0 /* Table */ = { - isa = PBXGroup; - children = ( - 0EEB20E522B7C8F20015F9E0 /* SettingsTableInitializer.swift */, - 0EEB20E722B7C92C0015F9E0 /* SettingsTableConfigurator.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0EEB20E922B7D1350015F9E0 /* About */ = { - isa = PBXGroup; - children = ( - 0EEB20EE22B7D1580015F9E0 /* About.storyboard */, - 0EEB20ED22B7D14A0015F9E0 /* Assembly */, - 0EEB20EC22B7D1440015F9E0 /* Presenter */, - 0EEB20EB22B7D1400015F9E0 /* Router */, - 0EEB20EA22B7D13B0015F9E0 /* View */, - ); - path = About; - sourceTree = ""; - }; - 0EEB20EA22B7D13B0015F9E0 /* View */ = { - isa = PBXGroup; - children = ( - 0EEB20F222B7D1900015F9E0 /* AboutViewInput.swift */, - 0EEB20F422B7D1A40015F9E0 /* AboutViewOutput.swift */, - 0EEB20F622B7D2090015F9E0 /* AboutViewController.swift */, - A980573725807118000D03AB /* AboutViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - 0EEB20EB22B7D1400015F9E0 /* Router */ = { - isa = PBXGroup; - children = ( - 0EEB20F822B7D28C0015F9E0 /* AboutRouterInput.swift */, - 0EEB20FA22B7D2990015F9E0 /* AboutRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0EEB20EC22B7D1440015F9E0 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0EEB20FC22B7D2C90015F9E0 /* AboutModuleInput.swift */, - 0EEB20FE22B7D2DD0015F9E0 /* AboutPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0EEB20ED22B7D14A0015F9E0 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0EEB210022B7D2F50015F9E0 /* AboutInitializer.swift */, - 0EEB210222B7D3210015F9E0 /* AboutConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 0EEB213A22B8FABD0015F9E0 /* Router */ = { - isa = PBXGroup; - children = ( - 0EEB213B22B8FAD50015F9E0 /* MainRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0EEB213D22B8FB6B0015F9E0 /* Transition */ = { - isa = PBXGroup; - children = ( - 0EEB213E22B8FB840015F9E0 /* MainNavigationDelegate.swift */, - ); - path = Transition; - sourceTree = ""; - }; - 0EEB214022B8FB930015F9E0 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0EEB214122B8FBA50015F9E0 /* MainInitializer.swift */, - 0EEB214322B8FBC50015F9E0 /* MainConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 0EEB214522B8FC2E0015F9E0 /* View */ = { - isa = PBXGroup; - children = ( - 0EEB214622B8FC3E0015F9E0 /* WelcomeViewInput.swift */, - 0EEB214822B8FC570015F9E0 /* WelcomeViewOutput.swift */, - 0E09672122AE7FCF00E85F48 /* WelcomeViewController.swift */, - ); - path = View; - sourceTree = ""; - }; - 0EEB214A22B8FCB50015F9E0 /* Router */ = { - isa = PBXGroup; - children = ( - 0EEB214B22B8FCC70015F9E0 /* WelcomeRouterInput.swift */, - 0EEB214D22B8FCDC0015F9E0 /* WelcomeRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0EEB214F22B8FCF80015F9E0 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0EEB215022B8FD070015F9E0 /* WelcomeModuleInput.swift */, - 0EEB215222B8FD1F0015F9E0 /* WelcomePresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0EEB215422B8FD440015F9E0 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0EEB215522B8FD590015F9E0 /* WelcomeInitializer.swift */, - 0EEB215722B8FD800015F9E0 /* WelcomeConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 0EF26D172381A12F005BD84E /* Cell */ = { - isa = PBXGroup; - children = ( - 0E9F979522EAFC820015ADE2 /* DiscoverWebTagTableViewCell.swift */, - 0E53A3FA232F4D5000ACED49 /* DiscoverNoDevicesTableViewCell.swift */, - 0E09672B22AE94F000E85F48 /* DiscoverDeviceTableViewCell.swift */, - 0E79F28A244328D50048BF86 /* DiscoverAddWithMACTableViewCell.swift */, - ); - path = Cell; - sourceTree = ""; - }; - 0EF2862522CBAF280026C7A5 /* TagSettings */ = { - isa = PBXGroup; - children = ( - 0EF2862B22CBAF5D0026C7A5 /* TagSettings.storyboard */, - 0EF2862A22CBAF480026C7A5 /* Assembly */, - 0EF2862822CBAF3C0026C7A5 /* Presenter */, - 0EF2862722CBAF370026C7A5 /* Router */, - 66BC44812657AED400A03253 /* Submodules */, - 0EF2862622CBAF320026C7A5 /* View */, - ); - path = TagSettings; - sourceTree = ""; - }; - 0EF2862622CBAF320026C7A5 /* View */ = { - isa = PBXGroup; - children = ( - 0EF2862F22CBAFF10026C7A5 /* Table */, - 0EC50F5122CCB9DE00172EEB /* TagSettingsViewModel.swift */, - 0EF2863022CBB00D0026C7A5 /* TagSettingsViewInput.swift */, - 0EF2863222CBB0250026C7A5 /* TagSettingsViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 0EF2862722CBAF370026C7A5 /* Router */ = { - isa = PBXGroup; - children = ( - 0EF2863422CBB03A0026C7A5 /* TagSettingsRouterInput.swift */, - 0EF2863622CBB04E0026C7A5 /* TagSettingsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0EF2862822CBAF3C0026C7A5 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E92A9872686373000187E4F /* Debouncer.swift */, - 0EF2863822CBB06C0026C7A5 /* TagSettingsModuleInput.swift */, - 0EF2863A22CBB08C0026C7A5 /* TagSettingsPresenter.swift */, - A9F4471524B79959001E63AF /* TagSettingsModuleOutput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0EF2862A22CBAF480026C7A5 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0EF2863E22CBB1110026C7A5 /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - 0EF2862F22CBAFF10026C7A5 /* Table */ = { - isa = PBXGroup; - children = ( - 0EAD33F3239A571B00EC5BAA /* Cells */, - 0E02ABB8237598B200ED4629 /* RangeSeekSlider */, - 0EF4D0A522E0657F00947E04 /* SectionHeader */, - 0EF2862D22CBAFC80026C7A5 /* TagSettingsTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0EF2863E22CBB1110026C7A5 /* Table */ = { - isa = PBXGroup; - children = ( - 0EF2863F22CBB1340026C7A5 /* TagSettingsTableInitializer.swift */, - 0EF2864122CBB13F0026C7A5 /* TagSettingsTableConfigurator.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0EF4D0A522E0657F00947E04 /* SectionHeader */ = { - isa = PBXGroup; - children = ( - 0E62AEC822E065CC00A49BFB /* TagSettingsMoreInfoHeaderFooterView.swift */, - 0E62AECA22E065F000A49BFB /* TagSettingsMoreInfoHeaderFooterView.xib */, - 0EA92FDA2387E734008F1558 /* TagSettingsAlertsHeaderFooterView.swift */, - 0EA92FDE2387E74C008F1558 /* TagSettingsAlertsHeaderFooterView.xib */, - ); - path = SectionHeader; - sourceTree = ""; - }; - 0EF4E31526823F6100D83CC7 /* Model */ = { - isa = PBXGroup; - children = ( - 0EF4E31626823F6100D83CC7 /* DiscoverRuuviTagViewModel.swift */, - 0EF4E31726823F6100D83CC7 /* DiscoverVirtualTagViewModel.swift */, - ); - path = Model; - sourceTree = ""; - }; - 11629D6C45208918E104E77F /* Assembly */ = { - isa = PBXGroup; - children = ( - 28B469B53431F206F4D0EC60 /* SignInConfigurator.swift */, - 85B8587156E1062D613B8960 /* SignInInitializer.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 31017308C4E5B3282DF4AAF9 /* ViewController */ = { - isa = PBXGroup; - children = ( - E6DB40883B83C652584EBB9A /* SignInViewController.swift */, - ); - path = ViewController; - sourceTree = ""; - }; - 321CE77F6EB26F685032F835 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 0E8BAC97245C716B00D380FB /* Combine.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 3D930628B855379BB9A9B1FF /* Assembly */ = { - isa = PBXGroup; - children = ( - AB681E62A66E5924A87859B1 /* ShareConfigurator.swift */, - 392F0E992BEAA3382C2CF709 /* ShareInitializer.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 64333D1C20B0C45900CDF4B6 = { - isa = PBXGroup; - children = ( - 0E62298826A7FB640041DCDD /* RuuviOnboard */, - 0E25136F2684D074004A522A /* RuuviNotifier */, - 0E2513592684A1D3004A522A /* RuuviNotification */, - 0EB8B91B2683523200FE130E /* RuuviMigration */, - 0EF4E35526831AFF00D83CC7 /* RuuviDFU */, - 0EF4E31B2682401200D83CC7 /* RuuviVirtual */, - 0EF4E31A2682400C00D83CC7 /* RuuviLocation */, - 0EE1127D267BC968008DA8D9 /* RuuviCore */, - 0EE11276267BC77D008DA8D9 /* RuuviDaemon */, - 0EE1125D267BC33D008DA8D9 /* RuuviReactor */, - 0EE11227267BBD0E008DA8D9 /* RuuviCloud */, - 0EE1122A267BBD0E008DA8D9 /* RuuviContext */, - 0EE11231267BBD0F008DA8D9 /* RuuviLocal */, - 0EE11232267BBD0F008DA8D9 /* RuuviOntology */, - 0EE11229267BBD0E008DA8D9 /* RuuviPersistence */, - 0EE1122E267BBD0F008DA8D9 /* RuuviPool */, - 0EE1122D267BBD0F008DA8D9 /* RuuviRepository */, - 0EE1122F267BBD0F008DA8D9 /* RuuviService */, - 0EE11228267BBD0E008DA8D9 /* RuuviStorage */, - 0EE11230267BBD0F008DA8D9 /* RuuviUser */, - A92C75DD24896B7400E332FE /* Fastlane */, - 64333D2720B0C45900CDF4B6 /* station */, - 64333D2620B0C45900CDF4B6 /* Products */, - 321CE77F6EB26F685032F835 /* Frameworks */, - ); - sourceTree = ""; - }; - 64333D2620B0C45900CDF4B6 /* Products */ = { - isa = PBXGroup; - children = ( - 0E6BAECE23856A01003A2D4C /* Ruuvi Station.app */, - ); - name = Products; - sourceTree = ""; - }; - 64333D2720B0C45900CDF4B6 /* station */ = { - isa = PBXGroup; - children = ( - 0ECDF1B62313D7DA00A09ACA /* station.entitlements */, - 0E09671622AE74D600E85F48 /* Classes */, - 0E09672322AE895600E85F48 /* Extensions */, - 0E09671722AE762900E85F48 /* Resources */, - ); - path = station; - sourceTree = ""; - }; - 6486970E20E042BC00CCD7C1 /* Fonts */ = { - isa = PBXGroup; - children = ( - 64678190225D02CE0072856A /* Muli-Bold.ttf */, - 6467818F225CFB170072856A /* Muli-Regular.ttf */, - 643C651E21C38F490037BE5B /* Montserrat-Bold.ttf */, - 6486971120E0439200CCD7C1 /* Montserrat-Regular.ttf */, - 6486970F20E042E000CCD7C1 /* Oswald-Bold.ttf */, - 643EEC2A2266435100D4E837 /* Oswald-ExtraLight.ttf */, - ); - path = Fonts; - sourceTree = ""; - }; - 660EB2432669278E000FD22B /* Submodules */ = { - isa = PBXGroup; - children = ( - 660EB2442669278E000FD22B /* DfuDevicesScanner */, - ); - path = Submodules; - sourceTree = ""; - }; - 660EB2442669278E000FD22B /* DfuDevicesScanner */ = { - isa = PBXGroup; - children = ( - 660EB2542669278E000FD22B /* DfuDevicesScanner.storyboard */, - 660EB2452669278E000FD22B /* Assembly */, - 660EB2482669278E000FD22B /* Presenter */, - 660EB2552669278E000FD22B /* Router */, - 66718A24266A685700A380F8 /* Submodules */, - 660EB24C2669278E000FD22B /* View */, - ); - path = DfuDevicesScanner; - sourceTree = ""; - }; - 660EB2452669278E000FD22B /* Assembly */ = { - isa = PBXGroup; - children = ( - 660EB2462669278E000FD22B /* DfuDevicesScannerConfigurator.swift */, - 660EB2472669278E000FD22B /* DfuDevicesScannerInitializer.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 660EB2482669278E000FD22B /* Presenter */ = { - isa = PBXGroup; - children = ( - 660EB2492669278E000FD22B /* DfuDevicesScannerPresenter.swift */, - 660EB24A2669278E000FD22B /* DfuDevicesScannerModuleInput.swift */, - 660EB24B2669278E000FD22B /* DfuDevicesScannerModuleOutput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 660EB24C2669278E000FD22B /* View */ = { - isa = PBXGroup; - children = ( - 660EB24D2669278E000FD22B /* Cells */, - 660EB2502669278E000FD22B /* DfuDevicesScannerViewInput.swift */, - 660EB2512669278E000FD22B /* DfuDevicesScannerTableViewController.swift */, - 660EB2522669278E000FD22B /* DfuDevicesScannerViewModel.swift */, - 660EB2532669278E000FD22B /* DfuDevicesScannerViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 660EB24D2669278E000FD22B /* Cells */ = { - isa = PBXGroup; - children = ( - 660EB24E2669278E000FD22B /* DfuNoDeviceTableViewCell.swift */, - 660EB24F2669278E000FD22B /* DfuDeviceTableViewCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - 660EB2552669278E000FD22B /* Router */ = { - isa = PBXGroup; - children = ( - 660EB2562669278E000FD22B /* DfuDevicesScannerRouterInput.swift */, - 660EB2572669278E000FD22B /* DfuDevicesScannerRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 663155CA2667F40C005B90A6 /* UpdateFirmware */ = { - isa = PBXGroup; - children = ( - 663155D92667F40C005B90A6 /* UpdateFirmware.storyboard */, - 663155CB2667F40C005B90A6 /* Assembly */, - 663155CF2667F40C005B90A6 /* Presenter */, - 663155DA2667F40C005B90A6 /* Router */, - 660EB2432669278E000FD22B /* Submodules */, - 663155D32667F40C005B90A6 /* View */, - ); - path = UpdateFirmware; - sourceTree = ""; - }; - 663155CB2667F40C005B90A6 /* Assembly */ = { - isa = PBXGroup; - children = ( - 663155CC2667F40C005B90A6 /* Apple */, - ); - path = Assembly; - sourceTree = ""; - }; - 663155CC2667F40C005B90A6 /* Apple */ = { - isa = PBXGroup; - children = ( - 663155CD2667F40C005B90A6 /* UpdateFirmwareAppleInitializer.swift */, - 663155CE2667F40C005B90A6 /* UpdateFirmwareConfigurator.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 663155CF2667F40C005B90A6 /* Presenter */ = { - isa = PBXGroup; - children = ( - 663155D02667F40C005B90A6 /* UpdateFirmwarePresenter.swift */, - 663155D12667F40C005B90A6 /* UpdateFirmwareModuleOutput.swift */, - 663155D22667F40C005B90A6 /* UpdateFirmwareModuleInput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 663155D32667F40C005B90A6 /* View */ = { - isa = PBXGroup; - children = ( - 663155D42667F40C005B90A6 /* Apple */, - 663155D62667F40C005B90A6 /* UpdateFirmwareViewOutput.swift */, - 663155D72667F40C005B90A6 /* UpdateFirmwareViewInput.swift */, - ); - path = View; - sourceTree = ""; - }; - 663155D42667F40C005B90A6 /* Apple */ = { - isa = PBXGroup; - children = ( - 663155D52667F40C005B90A6 /* UpdateFirmwareAppleViewController.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 663155DA2667F40C005B90A6 /* Router */ = { - isa = PBXGroup; - children = ( - 663155DB2667F40C005B90A6 /* UpdateFirmwareRouter.swift */, - 663155DC2667F40C005B90A6 /* UpdateFirmwareRouterInput.swift */, - ); - path = Router; - sourceTree = ""; - }; - 66718A24266A685700A380F8 /* Submodules */ = { - isa = PBXGroup; - children = ( - 66718A25266A685700A380F8 /* DfuFlash */, - ); - path = Submodules; - sourceTree = ""; - }; - 66718A25266A685700A380F8 /* DfuFlash */ = { - isa = PBXGroup; - children = ( - 66718A36266A685700A380F8 /* DfuFlash.storyboard */, - 66718A26266A685700A380F8 /* Assembly */, - 66718A2A266A685700A380F8 /* Presenter */, - 66718A37266A685700A380F8 /* Router */, - 66718A2E266A685700A380F8 /* View */, - ); - path = DfuFlash; - sourceTree = ""; - }; - 66718A26266A685700A380F8 /* Assembly */ = { - isa = PBXGroup; - children = ( - 66718A27266A685700A380F8 /* Apple */, - ); - path = Assembly; - sourceTree = ""; - }; - 66718A27266A685700A380F8 /* Apple */ = { - isa = PBXGroup; - children = ( - 66718A28266A685700A380F8 /* DfuFlashAppleInitializer.swift */, - 66718A29266A685700A380F8 /* DfuFlashConfigurator.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 66718A2A266A685700A380F8 /* Presenter */ = { - isa = PBXGroup; - children = ( - 66718A2B266A685700A380F8 /* DfuFlashModuleInput.swift */, - 66718A2C266A685700A380F8 /* DfuFlashModuleOutput.swift */, - 66718A2D266A685700A380F8 /* DfuFlashPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 66718A2E266A685700A380F8 /* View */ = { - isa = PBXGroup; - children = ( - 66718A2F266A685700A380F8 /* Apple */, - 66718A31266A685700A380F8 /* Cells */, - 66718A33266A685700A380F8 /* DfuFlashViewModel.swift */, - 66718A34266A685700A380F8 /* DfuFlashViewInput.swift */, - 66718A35266A685700A380F8 /* DfuFlashViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 66718A2F266A685700A380F8 /* Apple */ = { - isa = PBXGroup; - children = ( - 66718A30266A685700A380F8 /* DfuFlashAppleViewController.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 66718A31266A685700A380F8 /* Cells */ = { - isa = PBXGroup; - children = ( - 66718A32266A685700A380F8 /* DfuLogTableViewCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - 66718A37266A685700A380F8 /* Router */ = { - isa = PBXGroup; - children = ( - 66718A38266A685700A380F8 /* DfuFlashRouter.swift */, - 66718A39266A685700A380F8 /* DfuFlashRouterInput.swift */, - ); - path = Router; - sourceTree = ""; - }; - 66718A61266A6CA700A380F8 /* DfuFilePicker */ = { - isa = PBXGroup; - children = ( - 66718A62266A6CA700A380F8 /* DfuFilePickerPresenter.swift */, - 66718A63266A6CA700A380F8 /* Sheet */, - ); - path = DfuFilePicker; - sourceTree = ""; - }; - 66718A63266A6CA700A380F8 /* Sheet */ = { - isa = PBXGroup; - children = ( - 66718A64266A6CA700A380F8 /* DfuFilePickerPresenterSheet.swift */, - ); - path = Sheet; - sourceTree = ""; - }; - 66BC44812657AED400A03253 /* Submodules */ = { - isa = PBXGroup; - children = ( - 0EE36E80269749DE0021B746 /* DFU */, - 66BC44822657AED400A03253 /* OffsetCorrection */, - 663155CA2667F40C005B90A6 /* UpdateFirmware */, - ); - path = Submodules; - sourceTree = ""; - }; - 66BC44822657AED400A03253 /* OffsetCorrection */ = { - isa = PBXGroup; - children = ( - 66BC44832657AED400A03253 /* OffsetCorrection.storyboard */, - 66BC44842657AED400A03253 /* Assembly */, - 66BC44882657AED400A03253 /* Presenter */, - 66BC44922657AED400A03253 /* Router */, - 66BC448C2657AED400A03253 /* View */, - ); - path = OffsetCorrection; - sourceTree = ""; - }; - 66BC44842657AED400A03253 /* Assembly */ = { - isa = PBXGroup; - children = ( - 66BC44852657AED400A03253 /* Apple */, - ); - path = Assembly; - sourceTree = ""; - }; - 66BC44852657AED400A03253 /* Apple */ = { - isa = PBXGroup; - children = ( - 66BC44862657AED400A03253 /* OffsetCorrectionAppleInitializer.swift */, - 66BC44872657AED400A03253 /* OffsetCorrectionConfigurator.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 66BC44882657AED400A03253 /* Presenter */ = { - isa = PBXGroup; - children = ( - 66BC44892657AED400A03253 /* OffsetCorrectionModuleOutput.swift */, - 66BC448A2657AED400A03253 /* OffsetCorrectionPresenter.swift */, - 66BC448B2657AED400A03253 /* OffsetCorrectionModuleInput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 66BC448C2657AED400A03253 /* View */ = { - isa = PBXGroup; - children = ( - 66BC448D2657AED400A03253 /* Apple */, - 66BC448F2657AED400A03253 /* OffsetCorrectionViewInput.swift */, - 66BC44902657AED400A03253 /* OffsetCorrectionViewModel.swift */, - 66BC44912657AED400A03253 /* OffsetCorrectionViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 66BC448D2657AED400A03253 /* Apple */ = { - isa = PBXGroup; - children = ( - 66BC448E2657AED400A03253 /* OffsetCorrectionAppleViewController.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 66BC44922657AED400A03253 /* Router */ = { - isa = PBXGroup; - children = ( - 66BC44932657AED400A03253 /* OffsetCorrectionRouter.swift */, - 66BC44942657AED400A03253 /* OffsetCorrectionRouterInput.swift */, - ); - path = Router; - sourceTree = ""; - }; - 6C62E43912ACBCF757914A64 /* Router */ = { - isa = PBXGroup; - children = ( - 4E816312622E83E3B42001DC /* SignInRouterInput.swift */, - 6F0552F1D17F403B7DE508B5 /* SignInRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 71A3760FF84549A5FB45C805 /* SignIn */ = { - isa = PBXGroup; - children = ( - A9B5742C253B978D00DB7353 /* SignIn.storyboard */, - 11629D6C45208918E104E77F /* Assembly */, - 9430BF42054B093449B0B9FB /* Presenter */, - 6C62E43912ACBCF757914A64 /* Router */, - 975CCF09FE9E0AEF7A6CEEF8 /* View */, - ); - path = SignIn; - sourceTree = ""; - }; - 89F27275323C3CBC88A9180D /* View */ = { - isa = PBXGroup; - children = ( - A9E599482557340200F9E5CC /* Cells */, - 167F75FD2FDAD002C10686FA /* ShareViewInput.swift */, - CE5C4AD5C54EF024669EAF47 /* ShareViewOutput.swift */, - 354B5B6F50E98F55D6A672BA /* ShareViewModel.swift */, - 9607EC149920F19A54BE896D /* ViewController */, - ); - path = View; - sourceTree = ""; - }; - 910C826026E94BD80C07FBD2 /* Router */ = { - isa = PBXGroup; - children = ( - 9546F1EFEE8F8CFC22377BB4 /* ShareRouterInput.swift */, - BD7AE39C23B8C52BB202BB5E /* ShareRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 9430BF42054B093449B0B9FB /* Presenter */ = { - isa = PBXGroup; - children = ( - 87EFB230083D471777FBE5D0 /* SignInModuleInput.swift */, - 9B3006A5FB2173EC6AA2728D /* SignInModuleOutput.swift */, - E29B5190CB557178D11AB2CE /* SignInPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 9607EC149920F19A54BE896D /* ViewController */ = { - isa = PBXGroup; - children = ( - FC417B8977A47FFAE71585F0 /* ShareViewController.swift */, - ); - path = ViewController; - sourceTree = ""; - }; - 975CCF09FE9E0AEF7A6CEEF8 /* View */ = { - isa = PBXGroup; - children = ( - 4A7D6325DFC865D2D11BD1D1 /* SignInViewInput.swift */, - 4BD498E7491E278B4EF4919C /* SignInViewOutput.swift */, - FC59D3B5AD8926DBDD79AA1C /* SignInViewModel.swift */, - 31017308C4E5B3282DF4AAF9 /* ViewController */, - ); - path = View; - sourceTree = ""; - }; - A907A1D1245F7C4400041F6E /* ProgressBar */ = { - isa = PBXGroup; - children = ( - A907A1D2245F7C6600041F6E /* ProgressBarView.swift */, - ); - path = ProgressBar; - sourceTree = ""; - }; - A90E168C24604F0E00631E6C /* Chart */ = { - isa = PBXGroup; - children = ( - A90E16A72460974100631E6C /* Assembly */, - A90E168D24604F4600631E6C /* Presenter */, - A92E3C4724261BD000D981D5 /* View */, - ); - path = Chart; - sourceTree = ""; - }; - A90E168D24604F4600631E6C /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E05015D26860385007060C4 /* ChartFilterOperation.swift */, - A90E168E24604F7400631E6C /* TagChartPresenter.swift */, - A90E169224604FD100631E6C /* TagChartModuleInput.swift */, - A90E16962460504C00631E6C /* TagChartModuleOutput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - A90E169A24606A3900631E6C /* Interactor */ = { - isa = PBXGroup; - children = ( - A90E169B24606ABF00631E6C /* TagChartsInteractor.swift */, - A90E169F24606B0500631E6C /* TagChartsInteractorInput.swift */, - A90E16A324606B2000631E6C /* TagChartsInteractorOutput.swift */, - ); - path = Interactor; - sourceTree = ""; - }; - A90E16A72460974100631E6C /* Assembly */ = { - isa = PBXGroup; - children = ( - A90E16A82460975600631E6C /* TagChartAssembler.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - A91D02D92511207200694733 /* Selection */ = { - isa = PBXGroup; - children = ( - A91D030C251121C800694733 /* Selection.storyboard */, - A91D02DB2511207200694733 /* Assembly */, - A91D02DF2511207200694733 /* Presenter */, - A91D02E22511207200694733 /* View */, - A91D0314251124E800694733 /* Model */, - A91D02E82511207200694733 /* Router */, - ); - path = Selection; - sourceTree = ""; - }; - A91D02DB2511207200694733 /* Assembly */ = { - isa = PBXGroup; - children = ( - A91D02DC2511207200694733 /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - A91D02DC2511207200694733 /* Table */ = { - isa = PBXGroup; - children = ( - A91D02DD2511207200694733 /* SelectionTableConfigurator.swift */, - A91D02DE2511207200694733 /* SelectionTableInitializer.swift */, - ); - path = Table; - sourceTree = ""; - }; - A91D02DF2511207200694733 /* Presenter */ = { - isa = PBXGroup; - children = ( - A91D02E02511207200694733 /* SelectionPresenter.swift */, - A91D02E12511207200694733 /* SelectionModuleInput.swift */, - A91D0310251123B400694733 /* SelectionModuleOutput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - A91D02E22511207200694733 /* View */ = { - isa = PBXGroup; - children = ( - A91D02E42511207200694733 /* Table */, - A91D02E32511207200694733 /* SelectionViewInput.swift */, - A91D02E72511207200694733 /* SelectionViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - A91D02E42511207200694733 /* Table */ = { - isa = PBXGroup; - children = ( - A91D02E52511207200694733 /* SelectionTableViewCell.swift */, - A91D02E62511207200694733 /* SelectionTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - A91D02E82511207200694733 /* Router */ = { - isa = PBXGroup; - children = ( - A91D02E92511207200694733 /* SelectionRouter.swift */, - A91D02EA2511207200694733 /* SelectionRouterInput.swift */, - ); - path = Router; - sourceTree = ""; - }; - A91D0314251124E800694733 /* Model */ = { - isa = PBXGroup; - children = ( - A91D0315251124F900694733 /* SelectionItem.swift */, - ); - path = Model; - sourceTree = ""; - }; - A92C75DD24896B7400E332FE /* Fastlane */ = { - isa = PBXGroup; - children = ( - A92C75DE24896BA100E332FE /* fastlane */, - A92C75E124896BA100E332FE /* Gemfile */, - ); - name = Fastlane; - sourceTree = ""; - }; - A92C75DE24896BA100E332FE /* fastlane */ = { - isa = PBXGroup; - children = ( - A986147A248C49B00030F197 /* Matchfile */, - A92C75E2248982A000E332FE /* Pluginfile */, - A92C75DF24896BA100E332FE /* Appfile */, - A92C75E024896BA100E332FE /* Fastfile */, - ); - path = fastlane; - sourceTree = ""; - }; - A92E3C4724261BD000D981D5 /* View */ = { - isa = PBXGroup; - children = ( - A92E3C612426446500D981D5 /* ChartView */, - A92E3C62242644B800D981D5 /* TagChartViewInput.swift */, - A93052B7242BFCC000FB62B1 /* TagChartViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - A92E3C612426446500D981D5 /* ChartView */ = { - isa = PBXGroup; - children = ( - A907A1D1245F7C4400041F6E /* ProgressBar */, - 0E92A9852686371E00187E4F /* DateValueFormatter.swift */, - A92E3C592426415100D981D5 /* TagChartView.swift */, - A907A1D62460376600041F6E /* TagChartViewModel.swift */, - ); - path = ChartView; - sourceTree = ""; - }; - A93CDCCC25659B8600018C6C /* Alert */ = { - isa = PBXGroup; - children = ( - A93CDCDC25659BC500018C6C /* ViewModel */, - A93CDCCD25659B9400018C6C /* Impl */, - A93CDCCE25659BA600018C6C /* AlertPresenter.swift */, - ); - path = Alert; - sourceTree = ""; - }; - A93CDCCD25659B9400018C6C /* Impl */ = { - isa = PBXGroup; - children = ( - A93CDCDD25659BF600018C6C /* AlertPresenterImpl.swift */, - ); - path = Impl; - sourceTree = ""; - }; - A93CDCDC25659BC500018C6C /* ViewModel */ = { - isa = PBXGroup; - children = ( - A9BB94CB2540AB610042B190 /* AlertViewModel.swift */, - ); - path = ViewModel; - sourceTree = ""; - }; - A9646453247BAE6A0001D55D /* View */ = { - isa = PBXGroup; - children = ( - A9646456247BAE6A0001D55D /* Table */, - A9646454247BAE6A0001D55D /* AdvancedViewInput.swift */, - A964645B247BAE6A0001D55D /* AdvancedViewOutput.swift */, - A964645C247BAE6A0001D55D /* AdvancedViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - A9646456247BAE6A0001D55D /* Table */ = { - isa = PBXGroup; - children = ( - A9646457247BAE6A0001D55D /* Cells */, - A964645A247BAE6A0001D55D /* AdvancedTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - A9646457247BAE6A0001D55D /* Cells */ = { - isa = PBXGroup; - children = ( - A9646458247BAE6A0001D55D /* AdvancedStepperTableViewCell.swift */, - A9646459247BAE6A0001D55D /* AdvancedSwitchTableViewCell.swift */, - A976CA7D24A928C20099BDC1 /* AdvancedDisclosureTableViewCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - A964645D247BAE6A0001D55D /* Assembly */ = { - isa = PBXGroup; - children = ( - A964645E247BAE6A0001D55D /* AdvancedConfigurator.swift */, - A964645F247BAE6A0001D55D /* AdvancedInitializer.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - A9646460247BAE6A0001D55D /* Presenter */ = { - isa = PBXGroup; - children = ( - A9646461247BAE6A0001D55D /* AdvancedModuleInput.swift */, - A9646462247BAE6A0001D55D /* AdvancedPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - A9646463247BAE6A0001D55D /* Router */ = { - isa = PBXGroup; - children = ( - A9646464247BAE6A0001D55D /* AdvancedRouterInput.swift */, - A9646465247BAE6A0001D55D /* AdvancedRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - A9828E54247BAC0700E7E9D4 /* Advanced */ = { - isa = PBXGroup; - children = ( - A964648D247BAEBA0001D55D /* AdvancedSettings.storyboard */, - A964645D247BAE6A0001D55D /* Assembly */, - A9646460247BAE6A0001D55D /* Presenter */, - A9646463247BAE6A0001D55D /* Router */, - A9646453247BAE6A0001D55D /* View */, - ); - path = Advanced; - sourceTree = ""; - }; - A9E599482557340200F9E5CC /* Cells */ = { - isa = PBXGroup; - children = ( - A9E599492557341F00F9E5CC /* ShareDescriptionTableViewCell.swift */, - A9E599572557345200F9E5CC /* ShareEmailInputTableViewCell.swift */, - A9E599602557346600F9E5CC /* ShareSendButtonTableViewCell.swift */, - A9E59969255734A000F9E5CC /* ShareEmailTableViewCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - C11DEEB04EEFF836E529DA0B /* Presenter */ = { - isa = PBXGroup; - children = ( - 6AE2284D927021C0BEA560B0 /* ShareModuleInput.swift */, - 5710E4EF18D419D01D60405E /* ShareModuleOutput.swift */, - CC1D67615D6DBA9E2FC5B402 /* SharePresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - DB47D7C8D6149FEA8DD05FDC /* Share */ = { - isa = PBXGroup; - children = ( - A9E5993F25572CF700F9E5CC /* Share.storyboard */, - 3D930628B855379BB9A9B1FF /* Assembly */, - C11DEEB04EEFF836E529DA0B /* Presenter */, - 910C826026E94BD80C07FBD2 /* Router */, - 89F27275323C3CBC88A9180D /* View */, - ); - path = Share; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 0E6BAD7623856A01003A2D4C /* station */ = { - isa = PBXNativeTarget; - buildConfigurationList = 0E6BAECB23856A01003A2D4C /* Build configuration list for PBXNativeTarget "station" */; - buildPhases = ( - 31884FB725C74449002BC63F /* SwiftGen */, - 0E6BAD7823856A01003A2D4C /* Sources */, - 0E6BAEA623856A01003A2D4C /* Frameworks */, - 0E6BAEA823856A01003A2D4C /* Resources */, - A9AB575D2414446E006FD3D2 /* Fetch secrets */, - 0E0C7F9423950A71007470C5 /* Swiftlint */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = station; - packageProductDependencies = ( - 0EE11234267BBDC1008DA8D9 /* RuuviCloud */, - 0EE11236267BBDC1008DA8D9 /* RuuviCloudApi */, - 0EE11238267BBDC1008DA8D9 /* RuuviCloudPure */, - 0EE1123A267BBDC1008DA8D9 /* RuuviContext */, - 0EE1123C267BBDC1008DA8D9 /* RuuviCore */, - 0EE11240267BBDC1008DA8D9 /* RuuviLocal */, - 0EE11242267BBDC1008DA8D9 /* RuuviLocalUserDefaults */, - 0EE11244267BBDC1008DA8D9 /* RuuviOntology */, - 0EE11246267BBDC1008DA8D9 /* RuuviPersistence */, - 0EE11248267BBDC1008DA8D9 /* RuuviPool */, - 0EE1124C267BBDC1008DA8D9 /* RuuviRepository */, - 0EE1124E267BBDC1008DA8D9 /* RuuviService */, - 0EE11250267BBDC1008DA8D9 /* RuuviStorage */, - 0EE11252267BBDC1008DA8D9 /* RuuviUser */, - 0EE1125B267BC327008DA8D9 /* LightRoute */, - 0EE1125E267BC34A008DA8D9 /* RuuviReactor */, - 0EE11261267BC395008DA8D9 /* Swinject */, - 0EE11264267BC3CC008DA8D9 /* NordicDFU */, - 0EE11267267BC477008DA8D9 /* RangeSeekSlider */, - 0EE1126A267BC4A7008DA8D9 /* GestureInstructions */, - 0EE1126F267BC5D6008DA8D9 /* FirebaseRemoteConfig */, - 0EE11271267BC5D6008DA8D9 /* FirebaseCrashlytics */, - 0EE11274267BC751008DA8D9 /* SwinjectPropertyLoader */, - 0EE11277267BC7A3008DA8D9 /* RuuviDaemon */, - 0EE1127A267BC7E3008DA8D9 /* RxSwift */, - 0E5BF778267BCCB900EBF2D6 /* RuuviCoreImage */, - 0EF00EFE267C6A930082AA8D /* RuuviContextRealm */, - 0EF00F00267C6A960082AA8D /* RuuviContextSQLite */, - 0EF00F02267C6B160082AA8D /* RuuviServiceFactory */, - 0EB97864267C769E0032CC05 /* RuuviPersistenceRealm */, - 0EB97866267C769E0032CC05 /* RuuviPersistenceSQLite */, - 0EB97868267C7B640032CC05 /* RuuviDaemonCloudSync */, - 0EB9786A267C7B6C0032CC05 /* RuuviStorageCoordinator */, - 0EB9786C267C85BE0032CC05 /* RuuviPoolCoordinator */, - 0EBE42C6267C8A97002888EC /* RuuviReactorImpl */, - 0EBE42C8267C8A9B002888EC /* RuuviRepositoryCoordinator */, - 0EBE42CA267C8AA1002888EC /* RuuviUserCoordinator */, - 0EBE42D0267CA726002888EC /* Localize_Swift */, - 0EBE42D3267CA889002888EC /* BTKit */, - 0E11D211267E1310002D0686 /* FirebaseInAppMessaging-Beta */, - 0E11D213267E1317002D0686 /* FirebaseMessaging */, - 0EF4E31C2682403500D83CC7 /* RuuviCoreLocation */, - 0EF4E31E2682403500D83CC7 /* RuuviLocation */, - 0EF4E3202682403500D83CC7 /* RuuviLocationService */, - 0EF4E3222682403500D83CC7 /* RuuviVirtual */, - 0EF4E3242682403500D83CC7 /* RuuviVirtualModel */, - 0EF4E3262682403500D83CC7 /* RuuviVirtualOWM */, - 0EF4E3282682403500D83CC7 /* RuuviVirtualPersistence */, - 0EF4E32A2682403500D83CC7 /* RuuviVirtualReactor */, - 0EF4E32C2682403500D83CC7 /* RuuviVirtualRepository */, - 0EF4E32E2682403500D83CC7 /* RuuviVirtualService */, - 0EF4E3302682403500D83CC7 /* RuuviVirtualStorage */, - 0EF4E35626831B1100D83CC7 /* RuuviDFU */, - 0EF4E35826831B1100D83CC7 /* RuuviDFUImpl */, - 0EB8B91C2683525900FE130E /* RuuviMigration */, - 0EB8B91E2683525900FE130E /* RuuviMigrationImpl */, - 0EB8B93B26837B6900FE130E /* RuuviCoreDiff */, - 0EB8B93D26837B6900FE130E /* RuuviCorePermission */, - 0EB8B93F26837B6A00FE130E /* RuuviCorePN */, - 0E25135A2684A1FD004A522A /* RuuviNotification */, - 0E25135C2684A1FD004A522A /* RuuviNotificationLocal */, - 0E2513702684D09B004A522A /* RuuviNotifier */, - 0E2513722684D09B004A522A /* RuuviNotifierImpl */, - 0E00C5002685BA1D009B3C24 /* RuuviServiceExport */, - 0E00C5022685BA1D009B3C24 /* RuuviServiceMeasurement */, - 0E050142268601F5007060C4 /* RuuviDaemonBackground */, - 0E050144268601F5007060C4 /* RuuviDaemonOperation */, - 0E050146268601F6007060C4 /* RuuviDaemonRuuviTag */, - 0E050148268601F6007060C4 /* RuuviDaemonVirtualTag */, - 0E92A9892686373900187E4F /* RuuviServiceGATT */, - 0EE36EBD269F06CA0021B746 /* Charts */, - 0E62298926A7FB860041DCDD /* RuuviOnboard */, - ); - productName = station; - productReference = 0E6BAECE23856A01003A2D4C /* Ruuvi Station.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 64333D1D20B0C45900CDF4B6 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0930; - LastUpgradeCheck = 1250; - ORGANIZATIONNAME = "Ruuvi Innovations Oy"; - }; - buildConfigurationList = 64333D2020B0C45900CDF4B6 /* Build configuration list for PBXProject "macOS" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ru, - fi, - sv, - fr, - ); - mainGroup = 64333D1C20B0C45900CDF4B6; - packageReferences = ( - 0EE1125A267BC327008DA8D9 /* XCRemoteSwiftPackageReference "LightRoute" */, - 0EE11260267BC395008DA8D9 /* XCRemoteSwiftPackageReference "Swinject" */, - 0EE11263267BC3CC008DA8D9 /* XCRemoteSwiftPackageReference "IOS-Pods-DFU-Library" */, - 0EE11266267BC477008DA8D9 /* XCRemoteSwiftPackageReference "RangeSeekSlider" */, - 0EE11269267BC4A7008DA8D9 /* XCRemoteSwiftPackageReference "GestureInstructions" */, - 0EE1126C267BC5D6008DA8D9 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, - 0EE11273267BC751008DA8D9 /* XCRemoteSwiftPackageReference "SwinjectPropertyLoader" */, - 0EE11279267BC7E2008DA8D9 /* XCRemoteSwiftPackageReference "RxSwift" */, - 0EBE42CF267CA725002888EC /* XCRemoteSwiftPackageReference "Localize-Swift" */, - 0EBE42D2267CA889002888EC /* XCRemoteSwiftPackageReference "BTKit" */, - 0EE36EBC269F06CA0021B746 /* XCRemoteSwiftPackageReference "Charts" */, - ); - productRefGroup = 64333D2620B0C45900CDF4B6 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 0E6BAD7623856A01003A2D4C /* station */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 0E6BAEA823856A01003A2D4C /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 0E6BAEA923856A01003A2D4C /* Montserrat-Regular.ttf in Resources */, - 0E6BAEAA23856A01003A2D4C /* About.storyboard in Resources */, - 0E6BAEAB23856A01003A2D4C /* GoogleService-Info.plist in Resources */, - 0E197C7123C4A7D00074015B /* Presentation.plist in Resources */, - 0E31B04823BBA3F900660412 /* WebTagSettingsAlertsHeaderFooterView.xib in Resources */, - 0E6BAEAC23856A01003A2D4C /* DiscoverWebTagsInfoHeaderFooterView.xib in Resources */, - 66BC44972657AED400A03253 /* OffsetCorrection.storyboard in Resources */, - 0E6BAEAE23856A01003A2D4C /* Foreground.storyboard in Resources */, - 0E6BAEAF23856A01003A2D4C /* LocationPicker.storyboard in Resources */, - 0E6BAEB023856A01003A2D4C /* Defaults.storyboard in Resources */, - 0E6BAEB123856A01003A2D4C /* Cards.storyboard in Resources */, - 0E6BAEB223856A01003A2D4C /* LaunchScreen.storyboard in Resources */, - 0E6BAEB423856A01003A2D4C /* Oswald-Bold.ttf in Resources */, - 0E6BAEB523856A01003A2D4C /* Localizable.strings in Resources */, - 66718A5A266A685700A380F8 /* DfuFlash.storyboard in Resources */, - 0E6BAEB623856A01003A2D4C /* Discover.storyboard in Resources */, - 0EB8B92E2683599100FE130E /* Networking.plist in Resources */, - 0E6BAEB723856A01003A2D4C /* TagSettings.storyboard in Resources */, - 0E6BAEB823856A01003A2D4C /* TagCharts.storyboard in Resources */, - 0E6BAEB923856A01003A2D4C /* Muli-Regular.ttf in Resources */, - 0EA92FE12387E74C008F1558 /* TagSettingsAlertsHeaderFooterView.xib in Resources */, - 0E6BAEBA23856A01003A2D4C /* Oswald-ExtraLight.ttf in Resources */, - 0E6BAEBB23856A01003A2D4C /* Language.storyboard in Resources */, - 0E6BAEBC23856A01003A2D4C /* Welcome.storyboard in Resources */, - 0EAD33E52399273E00EC5BAA /* Heartbeat.storyboard in Resources */, - 0E6BAEBD23856A01003A2D4C /* InfoPlist.strings in Resources */, - A9E5994225572CF700F9E5CC /* Share.storyboard in Resources */, - 660EB27B2669278E000FD22B /* DfuDevicesScanner.storyboard in Resources */, - 0E6BAEBE23856A01003A2D4C /* ActivityRuuviLogo.storyboard in Resources */, - 0E6BAEBF23856A01003A2D4C /* Assets.xcassets in Resources */, - A91D030F251121C800694733 /* Selection.storyboard in Resources */, - 0E6BAEC123856A01003A2D4C /* CardView.xib in Resources */, - 0E6BAEC223856A01003A2D4C /* Menu.storyboard in Resources */, - A9646490247BAEBA0001D55D /* AdvancedSettings.storyboard in Resources */, - 0E6BAEC323856A01003A2D4C /* Main.storyboard in Resources */, - 0E6BAEC423856A01003A2D4C /* Settings.storyboard in Resources */, - 0EB48DE8261A1816008E0D2D /* FeatureToggles.json in Resources */, - 0E6BAEC523856A01003A2D4C /* Muli-Bold.ttf in Resources */, - 663155FA2667F40C005B90A6 /* UpdateFirmware.storyboard in Resources */, - 0E6BAEC623856A01003A2D4C /* TagSettingsMoreInfoHeaderFooterView.xib in Resources */, - 0E197C8323C5CDBE0074015B /* iOSDeviceModelMapping.plist in Resources */, - 0E6BAEC723856A01003A2D4C /* Montserrat-Bold.ttf in Resources */, - A9B57438253B992A00DB7353 /* SignIn.storyboard in Resources */, - 0E6BAEC823856A01003A2D4C /* WebTagSettings.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 0E0C7F9423950A71007470C5 /* Swiftlint */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = Swiftlint; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; - }; - 31884FB725C74449002BC63F /* SwiftGen */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = SwiftGen; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "if which swiftgen >/dev/null; then\n swiftgen\nelse\n echo \"warning: SwiftGen not installed, download it from https://github.com/SwiftGen/SwiftGen\"\nfi\n"; - }; - A9AB575D2414446E006FD3D2 /* Fetch secrets */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(SRCROOT)/station/Classes/Networking/Assembly/Networking.plist", - "$(SRCROOT)/station/Resources/Plists/GoogleService-Info.plist", - ); - name = "Fetch secrets"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "BUILD_APP_DIR=${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}\ngit clone git@github.com:ruuvi/com.ruuvi.station.ios.keystore.git\nif [ $? -eq 0 ]; then\n /bin/cp -rf com.ruuvi.station.ios.keystore/GoogleService-Info.plist \"$BUILD_APP_DIR/Contents/Resources/GoogleService-Info.plist\"\n /bin/cp -rf com.ruuvi.station.ios.keystore/Networking.plist \"$BUILD_APP_DIR/Contents/Resources/Networking.plist\"\n rm -rf com.ruuvi.station.ios.keystore\nelse\n if grep -q \"{ set your API key here }\" $SCRIPT_INPUT_FILE_0; then\n echo \"warning: Missing OpenWeatherMap API key. In order to make Virtual Sensors work please obtain API key on https://openweathermap.org and put into station/Classes/Networking/Assembly/Networking.plist\"\n fi\n if grep -q \"1:925543306936:ios:84f5fda343c52e7671c64d\" $SCRIPT_INPUT_FILE_1; then\n echo \"warning: Demo GoogleServices credentials. If you want to use your own GoogleServices credentials, please replace the station/Resources/Plists/GoogleService-Info.plist file\"\n fi\nfi\n"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 0E6BAD7823856A01003A2D4C /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 0E6BAD7A23856A01003A2D4C /* CardView.swift in Sources */, - A9B5744F253B994900DB7353 /* SignInPresenter.swift in Sources */, - 0EA7967B2664B37F002BA25D /* RuuviLocalError+LocalizedError.swift in Sources */, - 66BC44A92657AED400A03253 /* OffsetCorrectionAppleViewController.swift in Sources */, - A92E3C5C2426428E00D981D5 /* TagChartView.swift in Sources */, - 660EB2602669278E000FD22B /* DfuDevicesScannerPresenter.swift in Sources */, - 0EA7967F2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift in Sources */, - 0E6BAD7C23856A01003A2D4C /* DiscoverTableViewController.swift in Sources */, - A9B5744C253B994900DB7353 /* SignInRouter.swift in Sources */, - 660EB2752669278E000FD22B /* DfuDevicesScannerViewModel.swift in Sources */, - 66BC44A62657AED400A03253 /* OffsetCorrectionModuleInput.swift in Sources */, - 0E6BAD7D23856A01003A2D4C /* Optional.swift in Sources */, - 0E6BAD8223856A01003A2D4C /* CALayer+IB.swift in Sources */, - 660EB2722669278E000FD22B /* DfuDevicesScannerTableViewController.swift in Sources */, - 0E6BAD8423856A01003A2D4C /* MenuTablePresentationController.swift in Sources */, - A93CDCE025659BF600018C6C /* AlertPresenterImpl.swift in Sources */, - A9646474247BAE6B0001D55D /* AdvancedTableViewController.swift in Sources */, - 663155F42667F40C005B90A6 /* UpdateFirmwareViewInput.swift in Sources */, - 0E6BAD8723856A01003A2D4C /* TagSettingsViewInput.swift in Sources */, - 0EAD33EC2399273E00EC5BAA /* HeartbeatList.swift in Sources */, - 0E92A9882686373000187E4F /* Debouncer.swift in Sources */, - A9B57451253B994900DB7353 /* SignInModuleOutput.swift in Sources */, - 0EE36EA2269749DF0021B746 /* DFUViewModel.swift in Sources */, - 0E6BAD8823856A01003A2D4C /* DefaultsViewOutput.swift in Sources */, - 0E6BAD8923856A01003A2D4C /* MenuPresenter.swift in Sources */, - A91D03082511207300694733 /* SelectionRouter.swift in Sources */, - 0E6BAD8A23856A01003A2D4C /* ForegroundRouter.swift in Sources */, - 660EB26F2669278E000FD22B /* DfuDevicesScannerViewInput.swift in Sources */, - 0E6BAD8B23856A01003A2D4C /* MenuTableViewController.swift in Sources */, - 0E6BAD8C23856A01003A2D4C /* AboutRouterInput.swift in Sources */, - 0E6BAD8E23856A01003A2D4C /* WelcomeConfigurator.swift in Sources */, - 0E6BAD8F23856A01003A2D4C /* ForegroundModuleInput.swift in Sources */, - A91D0318251124F900694733 /* SelectionItem.swift in Sources */, - 0E6BAD9023856A01003A2D4C /* AboutViewOutput.swift in Sources */, - A98D3F1F256CBD610066588B /* ShareViewOutput.swift in Sources */, - 663155DF2667F40C005B90A6 /* UpdateFirmwareAppleInitializer.swift in Sources */, - A9E5994C2557341F00F9E5CC /* ShareDescriptionTableViewCell.swift in Sources */, - A91D030B2511207300694733 /* SelectionRouterInput.swift in Sources */, - 0E6BAD9323856A01003A2D4C /* TagChartsViewModel.swift in Sources */, - A9646480247BAE6B0001D55D /* AdvancedInitializer.swift in Sources */, - 0E6BAD9623856A01003A2D4C /* PermissionPresenter.swift in Sources */, - A98D3F1B256CBD610066588B /* ShareRouter.swift in Sources */, - 0EAD33E62399273E00EC5BAA /* HeartbeatInitializer.swift in Sources */, - 0E05014126860099007060C4 /* RuuviDFUError+LocalizedError.swift in Sources */, - 0E6BAD9723856A01003A2D4C /* LocationPickerRouterInput.swift in Sources */, - 0EE36E9C269749DF0021B746 /* URLSession+downloadTaskPublisher.swift in Sources */, - 0E197C7F23C5CD7C0074015B /* UIDevice+ReadableModel.swift in Sources */, - 0E9E775C238CCE5F006D7013 /* String+Replace.swift in Sources */, - 66718A3F266A685700A380F8 /* DfuFlashConfigurator.swift in Sources */, - 0E92A97E268636F700187E4F /* RuuviNotifierTitlesImpl.swift in Sources */, - A90E16A224606B0500631E6C /* TagChartsInteractorInput.swift in Sources */, - 0E6BAD9923856A01003A2D4C /* TagChartsTransitioningDelegate.swift in Sources */, - 663155FD2667F40C005B90A6 /* UpdateFirmwareRouter.swift in Sources */, - 0E6BAD9A23856A01003A2D4C /* WebTagSettingsRouter.swift in Sources */, - 66BC449A2657AED400A03253 /* OffsetCorrectionAppleInitializer.swift in Sources */, - 0E6BAD9B23856A01003A2D4C /* DefaultsPresenter.swift in Sources */, - A92A66BF2450C64B002918E7 /* UITableViewCell+ReusableView.swift in Sources */, - 663156002667F40C005B90A6 /* UpdateFirmwareRouterInput.swift in Sources */, - 0EE36E9F269749DF0021B746 /* LargeButtonStyle.swift in Sources */, - 0E6BAD9C23856A01003A2D4C /* WelcomeViewInput.swift in Sources */, - 66718A3C266A685700A380F8 /* DfuFlashAppleInitializer.swift in Sources */, - A9B57450253B994900DB7353 /* SignInModuleInput.swift in Sources */, - A91D02F92511207300694733 /* SelectionModuleInput.swift in Sources */, - 0E6BAD9D23856A01003A2D4C /* ForegroundList.swift in Sources */, - A9BB94CE2540AB610042B190 /* AlertViewModel.swift in Sources */, - 0E6BAD9E23856A01003A2D4C /* SettingsPresenter.swift in Sources */, - 0E6BAD9F23856A01003A2D4C /* LanguageTableConfigurator.swift in Sources */, - 0E197C6D23C4A52A0074015B /* MailComposerPresenterMessageUI.swift in Sources */, - 0E197C6823C4A47A0074015B /* MailComposerPresenter.swift in Sources */, - 0E6BADA023856A01003A2D4C /* MenuTablePresentTransitionAnimation.swift in Sources */, - 0EF4E31126823F3D00D83CC7 /* RuuviCoreError+LocalizedError.swift in Sources */, - 663155EB2667F40C005B90A6 /* UpdateFirmwareModuleInput.swift in Sources */, - 0E6BADA123856A01003A2D4C /* WebTagSettingsViewInput.swift in Sources */, - 66718A57266A685700A380F8 /* DfuFlashViewOutput.swift in Sources */, - 0E6BADA223856A01003A2D4C /* WelcomeRouterInput.swift in Sources */, - A907A1D92460376600041F6E /* TagChartViewModel.swift in Sources */, - 0E6BADA423856A01003A2D4C /* MenuModuleOutput.swift in Sources */, - 0E6BADA723856A01003A2D4C /* Localizable.swift in Sources */, - 0E197C6323C352380074015B /* TagSettingsAlertDescriptionCell.swift in Sources */, - 0E6BADA823856A01003A2D4C /* LocationPickerAppleInitializer.swift in Sources */, - 0E6BADA923856A01003A2D4C /* TagChartsPresenter.swift in Sources */, - 66BC44B22657AED400A03253 /* OffsetCorrectionViewOutput.swift in Sources */, - 0E6BADAA23856A01003A2D4C /* DefaultsList.swift in Sources */, - A90E16A624606B2000631E6C /* TagChartsInteractorOutput.swift in Sources */, - A9E5995A2557345200F9E5CC /* ShareEmailInputTableViewCell.swift in Sources */, - A91D02F32511207200694733 /* SelectionTableInitializer.swift in Sources */, - 0E6BADAC23856A01003A2D4C /* WelcomePresenter.swift in Sources */, - 0E6BADAE23856A01003A2D4C /* CardsViewOutput.swift in Sources */, - 0E6BADAF23856A01003A2D4C /* DefaultsSwitchTableViewCell.swift in Sources */, - 0E6BADB023856A01003A2D4C /* DefaultsViewInput.swift in Sources */, - 0E92A9862686371F00187E4F /* DateValueFormatter.swift in Sources */, - 0E6BADB123856A01003A2D4C /* LocationPickerRouter.swift in Sources */, - 66718A48266A685700A380F8 /* DfuFlashPresenter.swift in Sources */, - 0E6BADB223856A01003A2D4C /* WebTagSettingsModuleInput.swift in Sources */, - 66718A6E266BD0E800A380F8 /* Color+Ruuvi.swift in Sources */, - 0E6BADB323856A01003A2D4C /* MenuTableConfigurator.swift in Sources */, - 0EAD33F02399273E00EC5BAA /* HeartbeatViewModel.swift in Sources */, - 660EB29E266928E6000FD22B /* UIViewController+Alert.swift in Sources */, - 66718A4E266A685700A380F8 /* DfuLogTableViewCell.swift in Sources */, - 0E6BADB723856A01003A2D4C /* DefaultsStepperTableViewCell.swift in Sources */, - 0E2AFFA2266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift in Sources */, - 0E6BADBA23856A01003A2D4C /* SettingsRouter.swift in Sources */, - 0EE49B9B23B877CF003012C2 /* WebTagSettingsAlertControlsCell.swift in Sources */, - 0EA92FDD2387E734008F1558 /* TagSettingsAlertsHeaderFooterView.swift in Sources */, - 660EB25D2669278E000FD22B /* DfuDevicesScannerInitializer.swift in Sources */, - A9B57440253B993200DB7353 /* SignInConfigurator.swift in Sources */, - 0E6BADBD23856A01003A2D4C /* SwipeDownToDismissNavigationController.swift in Sources */, - 0E6BADBE23856A01003A2D4C /* DefaultsRouterInput.swift in Sources */, - 0E6BADBF23856A01003A2D4C /* AboutPresenter.swift in Sources */, - A9B57452253B994900DB7353 /* SignInViewModel.swift in Sources */, - 0EB66B432686058F00375BCC /* FeatureToggle.swift in Sources */, - A964648C247BAE6B0001D55D /* AdvancedRouter.swift in Sources */, - 0EA796732664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift in Sources */, - 0E6BADC023856A01003A2D4C /* TagChartsPresentTransitionAnimation.swift in Sources */, - 0E6BADC123856A01003A2D4C /* TagSettingsViewModel.swift in Sources */, - A9B5744E253B994900DB7353 /* SignInViewController.swift in Sources */, - 0E6BADC223856A01003A2D4C /* CardsPresenter.swift in Sources */, - 0E6BADC323856A01003A2D4C /* DiscoverWebTagsInfoHeaderFooterView.swift in Sources */, - 0EA796872664B84D002BA25D /* RuuviReactorError+LocalizedError.swift in Sources */, - A9BD38BC24F6108300904BBE /* Humidity+Offset.swift in Sources */, - 0E6BADC623856A01003A2D4C /* Observable.swift in Sources */, - 0E6BADC723856A01003A2D4C /* ForegroundTableViewController.swift in Sources */, - 0E6BADCA23856A01003A2D4C /* TagSettingsViewOutput.swift in Sources */, - 0E6BADCB23856A01003A2D4C /* ForegroundViewModel.swift in Sources */, - 0E6BADCC23856A01003A2D4C /* CardsViewModel.swift in Sources */, - 0E6BADCD23856A01003A2D4C /* UIApplication+ViewController.swift in Sources */, - 0E05014026860099007060C4 /* RuuviDaemonError+LocalizedError.swift in Sources */, - 0E6BADCE23856A01003A2D4C /* WebTagSettingsTableConfigurator.swift in Sources */, - A98D3F1D256CBD610066588B /* SharePresenter.swift in Sources */, - 0EB66B3D2686058F00375BCC /* FallbackFeatureToggleProvider.swift in Sources */, - 0EE36E9D269749DF0021B746 /* View+Any.swift in Sources */, - A9E599632557346600F9E5CC /* ShareSendButtonTableViewCell.swift in Sources */, - 0E6BADD223856A01003A2D4C /* TagSettingsMoreInfoHeaderFooterView.swift in Sources */, - 0E6BADD423856A01003A2D4C /* PermissionPresenterAlert.swift in Sources */, - A98D3F18256CBD610066588B /* ShareRouterInput.swift in Sources */, - 0E6BADD623856A01003A2D4C /* MainRouter.swift in Sources */, - 0E6BADD723856A01003A2D4C /* TagChartsScrollViewController.swift in Sources */, - 0E6BADD923856A01003A2D4C /* PhotoPickerPresenterSheet.swift in Sources */, - 0E6BADDA23856A01003A2D4C /* AboutConfigurator.swift in Sources */, - 0E6BADDB23856A01003A2D4C /* AboutViewInput.swift in Sources */, - A964646E247BAE6B0001D55D /* AdvancedStepperTableViewCell.swift in Sources */, - 0E6BADDC23856A01003A2D4C /* TagChartsViewInput.swift in Sources */, - 0E6BADDD23856A01003A2D4C /* LanguageTableViewController.swift in Sources */, - 0E6BADDE23856A01003A2D4C /* DefaultsViewController.swift in Sources */, - 0E79F28D244328D50048BF86 /* DiscoverAddWithMACTableViewCell.swift in Sources */, - A91D02F02511207200694733 /* SelectionTableConfigurator.swift in Sources */, - 0E6BADE023856A01003A2D4C /* DefaultsViewModel.swift in Sources */, - 0E92A9842686370000187E4F /* RUError.swift in Sources */, - 0E6BADE123856A01003A2D4C /* TagChartsScrollConfigurator.swift in Sources */, - 66718A42266A685700A380F8 /* DfuFlashModuleInput.swift in Sources */, - 66BC44B52657AED400A03253 /* OffsetCorrectionRouter.swift in Sources */, - 0E6BADE323856A01003A2D4C /* LanguageViewOutput.swift in Sources */, - 660EB26C2669278E000FD22B /* DfuDeviceTableViewCell.swift in Sources */, - 0E6BADE423856A01003A2D4C /* DefaultsConfigurator.swift in Sources */, - 0E6BADE523856A01003A2D4C /* MenuRouter.swift in Sources */, - 0E6BADE623856A01003A2D4C /* ForegroundRouterInput.swift in Sources */, - 66BC449D2657AED400A03253 /* OffsetCorrectionConfigurator.swift in Sources */, - 0EAD33E72399273E00EC5BAA /* HeartbeatConfigurator.swift in Sources */, - 0EA796832664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift in Sources */, - 0EA7968F2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift in Sources */, - 0E6BADEA23856A01003A2D4C /* DefaultsInitializer.swift in Sources */, - A9E5996C255734A000F9E5CC /* ShareEmailTableViewCell.swift in Sources */, - 0EE36EA6269749DF0021B746 /* LatestRelease.swift in Sources */, - 0E6BADEC23856A01003A2D4C /* MainInitializer.swift in Sources */, - 663155E22667F40C005B90A6 /* UpdateFirmwareConfigurator.swift in Sources */, - 0E6BADEE23856A01003A2D4C /* ForegroundSwitchTableViewCell.swift in Sources */, - 0E6BADF023856A01003A2D4C /* MenuTableInitializer.swift in Sources */, - 66BC44B82657AED400A03253 /* OffsetCorrectionRouterInput.swift in Sources */, - 0EE36EA0269749DF0021B746 /* ProgressBar.swift in Sources */, - 0E6BADF123856A01003A2D4C /* LocationPickerViewOutput.swift in Sources */, - 0EE49B9723B74775003012C2 /* WebTagSettingsAlertHeaderCell.swift in Sources */, - 0E6BADF223856A01003A2D4C /* WebTagSettingsTableViewController.swift in Sources */, - 0E62298726A7FB4E0041DCDD /* AppRouter.swift in Sources */, - 0E6BADF323856A01003A2D4C /* WelcomeRouter.swift in Sources */, - A93CDCD125659BA600018C6C /* AlertPresenter.swift in Sources */, - 0EE36EA4269749DF0021B746 /* DFUInteractorInput.swift in Sources */, - 0EB66B442686058F00375BCC /* InfoProviderImpl.swift in Sources */, - A9646489247BAE6B0001D55D /* AdvancedRouterInput.swift in Sources */, - 66718A45266A685700A380F8 /* DfuFlashModuleOutput.swift in Sources */, - 663155EE2667F40C005B90A6 /* UpdateFirmwareAppleViewController.swift in Sources */, - 0EAD33EE2399273E00EC5BAA /* HeartbeatTableViewController.swift in Sources */, - A93CDCAD25657C1D00018C6C /* MenuViewModel.swift in Sources */, - 0E6BADF823856A01003A2D4C /* TagSettingsRouter.swift in Sources */, - 0EB66B422686058F00375BCC /* FeatureToggleService.swift in Sources */, - 0E6BADF923856A01003A2D4C /* DiscoverDeviceTableViewCell.swift in Sources */, - 0E92A982268636F700187E4F /* Language+Localization.swift in Sources */, - 66718A67266A6CA700A380F8 /* DfuFilePickerPresenter.swift in Sources */, - 660EB2662669278E000FD22B /* DfuDevicesScannerModuleOutput.swift in Sources */, - 0E6BADFA23856A01003A2D4C /* AboutInitializer.swift in Sources */, - 0E6BADFB23856A01003A2D4C /* ForegroundEnvironmentObject.swift in Sources */, - 0E92A97C268636F700187E4F /* ExportHeadersProvider.swift in Sources */, - 0E6BADFC23856A01003A2D4C /* MenuTableEmbededViewController.swift in Sources */, - 663155E82667F40C005B90A6 /* UpdateFirmwareModuleOutput.swift in Sources */, - 0EB66B3F2686058F00375BCC /* LocalFeatureToggleProvider.swift in Sources */, - A98D3F00256CBD400066588B /* ShareModuleInput.swift in Sources */, - A949A83D24707FDE006B7F4F /* LocalizedCache.swift in Sources */, - 0EB66B412686058F00375BCC /* RemoteConfigService.swift in Sources */, - 0EAD33EB2399273E00EC5BAA /* HeartbeatRouter.swift in Sources */, - 0E6BADFE23856A01003A2D4C /* TagChartsDismissTransitionAnimation.swift in Sources */, - 0E6BADFF23856A01003A2D4C /* Date+Ruuvi.swift in Sources */, - 66718A60266A685700A380F8 /* DfuFlashRouterInput.swift in Sources */, - A98D3F19256CBD610066588B /* ShareViewInput.swift in Sources */, - 0EE36EA7269749DF0021B746 /* DFUModuleFactory.swift in Sources */, - 0E6BAE0323856A01003A2D4C /* CardsScrollViewController.swift in Sources */, - A980573A25807118000D03AB /* AboutViewModel.swift in Sources */, - 663155F12667F40C005B90A6 /* UpdateFirmwareViewOutput.swift in Sources */, - 0E05015A26860375007060C4 /* UniversalLinkCoordinator.swift in Sources */, - 660EB25A2669278E000FD22B /* DfuDevicesScannerConfigurator.swift in Sources */, - 0EE36EA3269749DF0021B746 /* DFUUIView.swift in Sources */, - 0E6BAE0423856A01003A2D4C /* LanguagePresenter.swift in Sources */, - A9A67BFC24C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift in Sources */, - 660EB2632669278E000FD22B /* DfuDevicesScannerModuleInput.swift in Sources */, - A964647A247BAE6B0001D55D /* AdvancedViewModel.swift in Sources */, - 0EB66B3E2686058F00375BCC /* FirebaseFeatureToggleProvider.swift in Sources */, - A9646486247BAE6B0001D55D /* AdvancedPresenter.swift in Sources */, - 0E6BAE0623856A01003A2D4C /* TagSettingsTableViewController.swift in Sources */, - 0E6BAE0823856A01003A2D4C /* LocationPickerModuleInput.swift in Sources */, - 0E92A97B268636F700187E4F /* TemperatureUnit+Localization.swift in Sources */, - A9B5744B253B994900DB7353 /* SignInRouterInput.swift in Sources */, - A976CA8024A928C20099BDC1 /* AdvancedDisclosureTableViewCell.swift in Sources */, - A90E16992460504C00631E6C /* TagChartModuleOutput.swift in Sources */, - A91D031C25113EAA00694733 /* UnitPressure+Extension.swift in Sources */, - 0E6BAE0D23856A01003A2D4C /* SettingsTableViewController.swift in Sources */, - 0EF4E31826823F6100D83CC7 /* DiscoverRuuviTagViewModel.swift in Sources */, - 0EAD33EA2399273E00EC5BAA /* HeartbeatRouterInput.swift in Sources */, - A98BC877250E4265001CEFDC /* Double+Round.swift in Sources */, - 0EF4E31226823F3D00D83CC7 /* RuuviVirtualError+LocalizedError.swift in Sources */, - A9646483247BAE6B0001D55D /* AdvancedModuleInput.swift in Sources */, - 0EAD33ED2399273E00EC5BAA /* HeartbeatEnvironmentObject.swift in Sources */, - 0E05015826860375007060C4 /* AppStateService.swift in Sources */, - 0E6BAE0F23856A01003A2D4C /* SwipeDownToDismissTransitionAnimation.swift in Sources */, - A9E6774A25A33081000B75A3 /* String+Characters.swift in Sources */, - 0E6BAE1223856A01003A2D4C /* SettingsRouterInput.swift in Sources */, - 0EAD33F12399273E00EC5BAA /* HeartbeatViewOutput.swift in Sources */, - A91D02FF2511207300694733 /* SelectionTableViewCell.swift in Sources */, - 0EB66B452686058F00375BCC /* InfoProvider.swift in Sources */, - 0E6BAE1323856A01003A2D4C /* ForegroundStepperTableViewCell.swift in Sources */, - 0E6BAE1423856A01003A2D4C /* MenuTableTransitionManager.swift in Sources */, - 0E6BAE1523856A01003A2D4C /* TagChartsViewOutput.swift in Sources */, - 0E6BAE1623856A01003A2D4C /* DefaultsRouter.swift in Sources */, - 0E6BAE1723856A01003A2D4C /* ForegroundViewInput.swift in Sources */, - 0E6BAE1823856A01003A2D4C /* WebTagSettingsRouterInput.swift in Sources */, - 0EA7968B2664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift in Sources */, - 660EB27E2669278E000FD22B /* DfuDevicesScannerRouterInput.swift in Sources */, - A98D3F16256CBD610066588B /* ShareConfigurator.swift in Sources */, - 0E6BAE1D23856A01003A2D4C /* LocalizationService.swift in Sources */, - 663155E52667F40C005B90A6 /* UpdateFirmwarePresenter.swift in Sources */, - 0E6BAE1E23856A01003A2D4C /* RURangeSeekSlider.swift in Sources */, - A91D02FC2511207300694733 /* SelectionViewInput.swift in Sources */, - 0E6BAE1F23856A01003A2D4C /* CardsModuleInput.swift in Sources */, - 0E6BAE2023856A01003A2D4C /* LanguageRouterInput.swift in Sources */, - 0E6BAE2323856A01003A2D4C /* ForegroundViewOutput.swift in Sources */, - 66BC44AC2657AED400A03253 /* OffsetCorrectionViewInput.swift in Sources */, - 0E1B2F38239DF0120060C469 /* TagSettingsAlertControlsCell.swift in Sources */, - 0E6BAE2423856A01003A2D4C /* LanguageModuleInput.swift in Sources */, - 0E6BAE2523856A01003A2D4C /* PresentationAssembly.swift in Sources */, - 0E6BAE2623856A01003A2D4C /* DiscoverWebTagTableViewCell.swift in Sources */, - 0E6BAE2723856A01003A2D4C /* AboutModuleInput.swift in Sources */, - 0E6BAE2823856A01003A2D4C /* WelcomeViewOutput.swift in Sources */, - 0EAD33E82399273E00EC5BAA /* HeartbeatModuleInput.swift in Sources */, - A9B5744D253B994900DB7353 /* SignInViewInput.swift in Sources */, - A9B57453253B994900DB7353 /* SignInInitializer.swift in Sources */, - 0E6BAE2923856A01003A2D4C /* MainNavigationDelegate.swift in Sources */, - 0E6BAE2D23856A01003A2D4C /* WebTagSettingsTableInitializer.swift in Sources */, - 66BC44AF2657AED400A03253 /* OffsetCorrectionViewModel.swift in Sources */, - 0E6BAE2E23856A01003A2D4C /* MenuRouterInput.swift in Sources */, - 0E6BAE2F23856A01003A2D4C /* LanguageRouter.swift in Sources */, - 66718A4B266A685700A380F8 /* DfuFlashAppleViewController.swift in Sources */, - 0EE98A7B26493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift in Sources */, - 0EE36E99269749DF0021B746 /* DFUModuleInput.swift in Sources */, - 0E6BAE3123856A01003A2D4C /* TagChartsModuleInput.swift in Sources */, - 0E6BAE3223856A01003A2D4C /* Double+Temperature.swift in Sources */, - 660EB2782669278E000FD22B /* DfuDevicesScannerViewOutput.swift in Sources */, - 0E6BAE3623856A01003A2D4C /* ActivityPresenter.swift in Sources */, - 0E6BAE3723856A01003A2D4C /* MenuViewOutput.swift in Sources */, - 0E6BAE3823856A01003A2D4C /* DiscoverViewInput.swift in Sources */, - 0EAD33E92399273E00EC5BAA /* HeartbeatPresenter.swift in Sources */, - 66718A51266A685700A380F8 /* DfuFlashViewModel.swift in Sources */, - 0E6BAE3923856A01003A2D4C /* LocationPickerAppleViewController.swift in Sources */, - 0E6BAE3A23856A01003A2D4C /* TagSettingsTableConfigurator.swift in Sources */, - 66BC44A32657AED400A03253 /* OffsetCorrectionPresenter.swift in Sources */, - 0E6BAE3C23856A01003A2D4C /* SwipeDownToDismissTransitioningDelegate.swift in Sources */, - 0E6BAE3D23856A01003A2D4C /* MenuViewInput.swift in Sources */, - 0E6BAE3E23856A01003A2D4C /* ActivitySpinnerView.swift in Sources */, - 0E6BAE4023856A01003A2D4C /* ActivityPresenterRuuviLogo.swift in Sources */, - 0EAD33F22399273E00EC5BAA /* HeartbeatViewController.swift in Sources */, - 0E6BAE4123856A01003A2D4C /* AboutViewController.swift in Sources */, - A98D3F1E256CBD610066588B /* ShareModuleOutput.swift in Sources */, - A98D3F1A256CBD610066588B /* ShareViewModel.swift in Sources */, - 0E6BAE4223856A01003A2D4C /* DiscoverRouterInput.swift in Sources */, - 0E6BAE4423856A01003A2D4C /* DefaultsEnvironmentObject.swift in Sources */, - 0E6BAE4623856A01003A2D4C /* ViewInput.swift in Sources */, - 0E6BAE4723856A01003A2D4C /* UserDefaults+Optional.swift in Sources */, - 0E6BAE4823856A01003A2D4C /* TagChartsRouterInput.swift in Sources */, - 0E6BAE4923856A01003A2D4C /* CardsViewInput.swift in Sources */, - 0E6BAE4A23856A01003A2D4C /* DiscoverPresenter.swift in Sources */, - 0E6BAE4B23856A01003A2D4C /* LanguageViewInput.swift in Sources */, - 0E6BAE4C23856A01003A2D4C /* AboutRouter.swift in Sources */, - 0E6BAE4E23856A01003A2D4C /* TagChartsRouter.swift in Sources */, - 66718A6A266A6CA700A380F8 /* DfuFilePickerPresenterSheet.swift in Sources */, - 0E6BAE4F23856A01003A2D4C /* DiscoverTableInitializer.swift in Sources */, - 0E6BAE5023856A01003A2D4C /* DiscoverViewOutput.swift in Sources */, - 0E05015B26860375007060C4 /* UniversalLinkRouterImpl.swift in Sources */, - 0E6BAE5123856A01003A2D4C /* DiscoverRouter.swift in Sources */, - A93052BA242BFCF900FB62B1 /* TagChartViewOutput.swift in Sources */, - 0E6BAE5223856A01003A2D4C /* WelcomeModuleInput.swift in Sources */, - 0E05015926860375007060C4 /* UniversalLinkCoordinatormpl.swift in Sources */, - 0E6BAE5323856A01003A2D4C /* PhotoPickerPresenter.swift in Sources */, - 0E6BAE5423856A01003A2D4C /* LocationPickerPresenter.swift in Sources */, - 66BC44A02657AED400A03253 /* OffsetCorrectionModuleOutput.swift in Sources */, - 0EE36E9A269749DF0021B746 /* DFUPresenter.swift in Sources */, - 0E6BAE5723856A01003A2D4C /* DefaultsModuleInput.swift in Sources */, - 0E6BAE5A23856A01003A2D4C /* TagSettingsPresenter.swift in Sources */, - 0E6BAE5B23856A01003A2D4C /* TagChartsModuleOutput.swift in Sources */, - 0E92A981268636F700187E4F /* MeasurementType.swift in Sources */, - A91D03052511207300694733 /* SelectionViewOutput.swift in Sources */, - 0E6BAE5D23856A01003A2D4C /* SwipeDownToDismissInteractiveTransition.swift in Sources */, - 0E05015C26860375007060C4 /* UniversalLinkRouter.swift in Sources */, - 0E6BAE5E23856A01003A2D4C /* TagSettingsRouterInput.swift in Sources */, - 0E6BAE5F23856A01003A2D4C /* NSObject+Observable.swift in Sources */, - 0E6BAE6023856A01003A2D4C /* TagSettingsModuleInput.swift in Sources */, - 0E6BAE6223856A01003A2D4C /* LocationPickerAppleConfigurator.swift in Sources */, - 0E6BAE6323856A01003A2D4C /* AppAssembly.swift in Sources */, - 0E6BAE6523856A01003A2D4C /* MenuTableDismissTransitionAnimation.swift in Sources */, - 0E6BAE6623856A01003A2D4C /* DiscoverModuleInput.swift in Sources */, - 0E6BAE6823856A01003A2D4C /* SettingsTableConfigurator.swift in Sources */, - 0E6BAE6A23856A01003A2D4C /* LanguageTableInitializer.swift in Sources */, - A964647D247BAE6B0001D55D /* AdvancedConfigurator.swift in Sources */, - 0EE36E98269749DF0021B746 /* FirmwareRepository.swift in Sources */, - 0E6BAE6B23856A01003A2D4C /* LocationPickerModuleOutput.swift in Sources */, - 0E6BAE6C23856A01003A2D4C /* DiscoverTableConfigurator.swift in Sources */, - 0E6BAE6E23856A01003A2D4C /* LocationPickerViewInput.swift in Sources */, - 0EE36E9B269749DF0021B746 /* Publishers+System.swift in Sources */, - 0E6BAE6F23856A01003A2D4C /* SettingsTableInitializer.swift in Sources */, - 0E6BAE7023856A01003A2D4C /* TagChartsTransitionManager.swift in Sources */, - 0E6BAE7123856A01003A2D4C /* ActivityRuuviLogoViewController.swift in Sources */, - 0E6BAE7223856A01003A2D4C /* TagChartsScrollInitializer.swift in Sources */, - A907BB1324AE620E009DA3DB /* UIWindow+Orientation.swift in Sources */, - A90E169E24606ABF00631E6C /* TagChartsInteractor.swift in Sources */, - 0EAD33EF2399273E00EC5BAA /* HeartbeatViewInput.swift in Sources */, - 0E6BAE7323856A01003A2D4C /* ForegroundConfigurator.swift in Sources */, - 0E6BAE7423856A01003A2D4C /* AppDelegate.swift in Sources */, - 0EB66B3C2686058F00375BCC /* FeatureToggleProvider.swift in Sources */, - 0EA796772664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift in Sources */, - 0E92A97F268636F700187E4F /* VirtualLocation+Localization.swift in Sources */, - 0E6BAE7523856A01003A2D4C /* TagSettingsTableInitializer.swift in Sources */, - 66718A5D266A685700A380F8 /* DfuFlashRouter.swift in Sources */, - 0E6BAE7B23856A01003A2D4C /* WebTagSettingsViewModel.swift in Sources */, - 0E6BAE7C23856A01003A2D4C /* MainConfigurator.swift in Sources */, - A90E16AB24609B9B00631E6C /* TagChartAssembler.swift in Sources */, - 0E6BAE7D23856A01003A2D4C /* WebTagSettingsPresenter.swift in Sources */, - 0E6BAE7E23856A01003A2D4C /* MenuModuleInput.swift in Sources */, - 0E6BAE8023856A01003A2D4C /* CardsScrollInitializer.swift in Sources */, - 0E6BAE8123856A01003A2D4C /* DefaultsTableViewController.swift in Sources */, - 660EB2692669278E000FD22B /* DfuNoDeviceTableViewCell.swift in Sources */, - 0E6BAE8423856A01003A2D4C /* MenuTableTransitioningDelegate.swift in Sources */, - 0E6BAE8523856A01003A2D4C /* ErrorPresenter.swift in Sources */, - 0E6BAE8623856A01003A2D4C /* LanguageTableViewCell.swift in Sources */, - A98D3F1C256CBD610066588B /* ShareViewController.swift in Sources */, - 0E62298626A7FB4E0041DCDD /* OnboardRouter.swift in Sources */, - 0E31B04423BBA37C00660412 /* WebTagSettingsAlertsHeaderFooterView.swift in Sources */, - A91D0313251123B400694733 /* SelectionModuleOutput.swift in Sources */, - 0E6BAE8B23856A01003A2D4C /* ForegroundRow.swift in Sources */, - 0E92A980268636F700187E4F /* HumidityUnit+Localization.swift in Sources */, - 0E6BAE8C23856A01003A2D4C /* SettingsViewOutput.swift in Sources */, - 66718A54266A685700A380F8 /* DfuFlashViewInput.swift in Sources */, - 660EB2812669278E000FD22B /* DfuDevicesScannerRouter.swift in Sources */, - 0E6BAE8D23856A01003A2D4C /* ForegroundPresenter.swift in Sources */, - A9B57454253B994900DB7353 /* SignInViewOutput.swift in Sources */, - 0E6BAE8E23856A01003A2D4C /* DiscoverNoDevicesTableViewCell.swift in Sources */, - 0EAD33D62399272000EC5BAA /* DiscoverModuleOutput.swift in Sources */, - 0E6BAE8F23856A01003A2D4C /* SettingsModuleInput.swift in Sources */, - 0EB66B402686058F00375BCC /* FirebaseRemoteConfigService.swift in Sources */, - 0E6BAE9023856A01003A2D4C /* CardsScrollConfigurator.swift in Sources */, - 0E6BAE9323856A01003A2D4C /* WebTagSettingsViewOutput.swift in Sources */, - 0E05015726860375007060C4 /* AppStateServiceImpl.swift in Sources */, - 0E6BAE9423856A01003A2D4C /* CardsRouter.swift in Sources */, - 0E6BAE9523856A01003A2D4C /* WelcomeViewController.swift in Sources */, - 0E92A97D268636F700187E4F /* HeartbeatDaemonTitles.swift in Sources */, - 0EF4E35226831A0C00D83CC7 /* DfuFirmware+Log.swift in Sources */, - A9646468247BAE6B0001D55D /* AdvancedViewInput.swift in Sources */, - 0EE36EA1269749DF0021B746 /* Feedback.swift in Sources */, - 0E6BAE9623856A01003A2D4C /* CardsRouterInput.swift in Sources */, - 0E6BAE9723856A01003A2D4C /* WelcomeInitializer.swift in Sources */, - A92E3C65242644B800D981D5 /* TagChartViewInput.swift in Sources */, - 0E05015E26860386007060C4 /* ChartFilterOperation.swift in Sources */, - 0E1B2F34239DEF120060C469 /* TagSettingsAlertHeaderCell.swift in Sources */, - A9F4471824B79959001E63AF /* TagSettingsModuleOutput.swift in Sources */, - A90E169124604F7400631E6C /* TagChartPresenter.swift in Sources */, - A907A1D5245F7C6600041F6E /* ProgressBarView.swift in Sources */, - 0E6BAE9923856A01003A2D4C /* SettingsViewInput.swift in Sources */, - 0E6BAE9C23856A01003A2D4C /* CardsRouterDelegate.swift in Sources */, - A90E169524604FD100631E6C /* TagChartModuleInput.swift in Sources */, - A9646477247BAE6B0001D55D /* AdvancedViewOutput.swift in Sources */, - 0E6BAE9F23856A01003A2D4C /* ErrorPresenterAlert.swift in Sources */, - 0EE36EAA269749F20021B746 /* RuuviColor.swift in Sources */, - A91D03022511207300694733 /* SelectionTableViewController.swift in Sources */, - 0E6BAEA023856A01003A2D4C /* ForegroundViewController.swift in Sources */, - 0EE36EA5269749DF0021B746 /* DFUInteractor.swift in Sources */, - 0E6BAEA223856A01003A2D4C /* ForegroundInitializer.swift in Sources */, - A9646471247BAE6B0001D55D /* AdvancedSwitchTableViewCell.swift in Sources */, - A98D3F17256CBD610066588B /* ShareInitializer.swift in Sources */, - A91D02F62511207300694733 /* SelectionPresenter.swift in Sources */, - 0EE36E9E269749DF0021B746 /* Spinner.swift in Sources */, - 0EF4E31926823F6100D83CC7 /* DiscoverVirtualTagViewModel.swift in Sources */, - 0E290A872660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - 0E53A3F3232DFC6200ACED49 /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 0E53A3F2232DFC6200ACED49 /* en */, - 0E53A3F4232DFC6400ACED49 /* ru */, - 0E53A3F5232DFC6500ACED49 /* fi */, - 64A2DAE324310B2900DE6699 /* sv */, - 310159B92644864C00A5E8E8 /* fr */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; - 0EEB20C922B7A7200015F9E0 /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 0EEB20C822B7A7200015F9E0 /* en */, - 0E9D0AAF231E9BD800C6BDA7 /* ru */, - 0EBAF0832320120F0025A191 /* fi */, - 64A2DAE224310B2900DE6699 /* sv */, - 310159B82644864400A5E8E8 /* fr */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - 64333D2C20B0C45900CDF4B6 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 64333D2D20B0C45900CDF4B6 /* Base */, - 310159B7264484D700A5E8E8 /* fr */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 64333D3120B0C45A00CDF4B6 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 64333D3220B0C45A00CDF4B6 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 0E6BAECC23856A01003A2D4C /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = station/station.entitlements; - CODE_SIGN_IDENTITY = "iPhone Distribution"; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 23; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; - DEVELOPMENT_ASSET_PATHS = ""; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - INFOPLIST_FILE = "$(SRCROOT)/station/Resources/Plists/MacInfo.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 0.7; - OTHER_LDFLAGS = ( - "$(inherited)", - "-ObjC", - "-l\"c++\"", - "-l\"sqlite3\"", - "-l\"z\"", - "-framework", - "\"UIKit\"", - "-weak_framework", - "\"UserNotifications\"", - "-weak_framework", - SwiftUI, - ); - OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D DEVELOPMENT"; - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.station; - PRODUCT_NAME = "Ruuvi Station"; - PROVISIONING_PROFILE = ""; - PROVISIONING_PROFILE_SPECIFIER = "match AdHoc com.ruuvi.station"; - "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "MacCatalyst Ruuvi Station Developer Id"; - SUPPORTED_PLATFORMS = macosx; - SUPPORTS_MACCATALYST = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 0E6BAECD23856A01003A2D4C /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = station/station.entitlements; - CODE_SIGN_IDENTITY = "iPhone Distribution"; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 23; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES; - DEVELOPMENT_ASSET_PATHS = ""; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - INFOPLIST_FILE = "$(SRCROOT)/station/Resources/Plists/MacInfo.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 10.15; - MARKETING_VERSION = 0.7; - OTHER_LDFLAGS = ( - "$(inherited)", - "-ObjC", - "-l\"c++\"", - "-l\"sqlite3\"", - "-l\"z\"", - "-framework", - "\"UIKit\"", - "-weak_framework", - "\"UserNotifications\"", - "-weak_framework", - SwiftUI, - ); - OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS"; - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.station; - PRODUCT_NAME = "Ruuvi Station"; - PROVISIONING_PROFILE = ""; - PROVISIONING_PROFILE_SPECIFIER = "match AdHoc com.ruuvi.station"; - "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "MacCatalyst Ruuvi Station Developer Id"; - SUPPORTED_PLATFORMS = macosx; - SUPPORTS_MACCATALYST = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 64333D4B20B0C45B00CDF4B6 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 64333D4C20B0C45B00CDF4B6 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 0E6BAECB23856A01003A2D4C /* Build configuration list for PBXNativeTarget "station" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 0E6BAECC23856A01003A2D4C /* Debug */, - 0E6BAECD23856A01003A2D4C /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 64333D2020B0C45900CDF4B6 /* Build configuration list for PBXProject "macOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 64333D4B20B0C45B00CDF4B6 /* Debug */, - 64333D4C20B0C45B00CDF4B6 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - 0EBE42CF267CA725002888EC /* XCRemoteSwiftPackageReference "Localize-Swift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/marmelroy/Localize-Swift"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 3.2.0; - }; - }; - 0EBE42D2267CA889002888EC /* XCRemoteSwiftPackageReference "BTKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ruuvi/BTKit"; - requirement = { - kind = upToNextMinorVersion; - minimumVersion = 0.4.3; - }; - }; - 0EE1125A267BC327008DA8D9 /* XCRemoteSwiftPackageReference "LightRoute" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/rinat-enikeev/LightRoute"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.2.2; - }; - }; - 0EE11260267BC395008DA8D9 /* XCRemoteSwiftPackageReference "Swinject" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/Swinject/Swinject"; - requirement = { - kind = upToNextMinorVersion; - minimumVersion = 2.6.2; - }; - }; - 0EE11263267BC3CC008DA8D9 /* XCRemoteSwiftPackageReference "IOS-Pods-DFU-Library" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/NordicSemiconductor/IOS-Pods-DFU-Library"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 4.10.3; - }; - }; - 0EE11266267BC477008DA8D9 /* XCRemoteSwiftPackageReference "RangeSeekSlider" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/rinat-enikeev/RangeSeekSlider"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.8.2; - }; - }; - 0EE11269267BC4A7008DA8D9 /* XCRemoteSwiftPackageReference "GestureInstructions" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/rinat-enikeev/GestureInstructions"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 0.0.2; - }; - }; - 0EE1126C267BC5D6008DA8D9 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/firebase/firebase-ios-sdk"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 8.2.0; - }; - }; - 0EE11273267BC751008DA8D9 /* XCRemoteSwiftPackageReference "SwinjectPropertyLoader" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/rinat-enikeev/SwinjectPropertyLoader"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.0.2; - }; - }; - 0EE11279267BC7E2008DA8D9 /* XCRemoteSwiftPackageReference "RxSwift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ReactiveX/RxSwift"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 6.2.0; - }; - }; - 0EE36EBC269F06CA0021B746 /* XCRemoteSwiftPackageReference "Charts" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/danielgindi/Charts"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 4.0.1; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 0E00C5002685BA1D009B3C24 /* RuuviServiceExport */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceExport; - }; - 0E00C5022685BA1D009B3C24 /* RuuviServiceMeasurement */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceMeasurement; - }; - 0E050142268601F5007060C4 /* RuuviDaemonBackground */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemonBackground; - }; - 0E050144268601F5007060C4 /* RuuviDaemonOperation */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemonOperation; - }; - 0E050146268601F6007060C4 /* RuuviDaemonRuuviTag */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemonRuuviTag; - }; - 0E050148268601F6007060C4 /* RuuviDaemonVirtualTag */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemonVirtualTag; - }; - 0E11D211267E1310002D0686 /* FirebaseInAppMessaging-Beta */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE1126C267BC5D6008DA8D9 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = "FirebaseInAppMessaging-Beta"; - }; - 0E11D213267E1317002D0686 /* FirebaseMessaging */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE1126C267BC5D6008DA8D9 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseMessaging; - }; - 0E25135A2684A1FD004A522A /* RuuviNotification */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviNotification; - }; - 0E25135C2684A1FD004A522A /* RuuviNotificationLocal */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviNotificationLocal; - }; - 0E2513702684D09B004A522A /* RuuviNotifier */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviNotifier; - }; - 0E2513722684D09B004A522A /* RuuviNotifierImpl */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviNotifierImpl; - }; - 0E5BF778267BCCB900EBF2D6 /* RuuviCoreImage */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCoreImage; - }; - 0E62298926A7FB860041DCDD /* RuuviOnboard */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviOnboard; - }; - 0E92A9892686373900187E4F /* RuuviServiceGATT */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceGATT; - }; - 0EB8B91C2683525900FE130E /* RuuviMigration */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviMigration; - }; - 0EB8B91E2683525900FE130E /* RuuviMigrationImpl */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviMigrationImpl; - }; - 0EB8B93B26837B6900FE130E /* RuuviCoreDiff */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCoreDiff; - }; - 0EB8B93D26837B6900FE130E /* RuuviCorePermission */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCorePermission; - }; - 0EB8B93F26837B6A00FE130E /* RuuviCorePN */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCorePN; - }; - 0EB97864267C769E0032CC05 /* RuuviPersistenceRealm */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviPersistenceRealm; - }; - 0EB97866267C769E0032CC05 /* RuuviPersistenceSQLite */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviPersistenceSQLite; - }; - 0EB97868267C7B640032CC05 /* RuuviDaemonCloudSync */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemonCloudSync; - }; - 0EB9786A267C7B6C0032CC05 /* RuuviStorageCoordinator */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviStorageCoordinator; - }; - 0EB9786C267C85BE0032CC05 /* RuuviPoolCoordinator */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviPoolCoordinator; - }; - 0EBE42C6267C8A97002888EC /* RuuviReactorImpl */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviReactorImpl; - }; - 0EBE42C8267C8A9B002888EC /* RuuviRepositoryCoordinator */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviRepositoryCoordinator; - }; - 0EBE42CA267C8AA1002888EC /* RuuviUserCoordinator */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviUserCoordinator; - }; - 0EBE42D0267CA726002888EC /* Localize_Swift */ = { - isa = XCSwiftPackageProductDependency; - package = 0EBE42CF267CA725002888EC /* XCRemoteSwiftPackageReference "Localize-Swift" */; - productName = Localize_Swift; - }; - 0EBE42D3267CA889002888EC /* BTKit */ = { - isa = XCSwiftPackageProductDependency; - package = 0EBE42D2267CA889002888EC /* XCRemoteSwiftPackageReference "BTKit" */; - productName = BTKit; - }; - 0EE11234267BBDC1008DA8D9 /* RuuviCloud */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCloud; - }; - 0EE11236267BBDC1008DA8D9 /* RuuviCloudApi */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCloudApi; - }; - 0EE11238267BBDC1008DA8D9 /* RuuviCloudPure */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCloudPure; - }; - 0EE1123A267BBDC1008DA8D9 /* RuuviContext */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviContext; - }; - 0EE1123C267BBDC1008DA8D9 /* RuuviCore */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCore; - }; - 0EE11240267BBDC1008DA8D9 /* RuuviLocal */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviLocal; - }; - 0EE11242267BBDC1008DA8D9 /* RuuviLocalUserDefaults */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviLocalUserDefaults; - }; - 0EE11244267BBDC1008DA8D9 /* RuuviOntology */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviOntology; - }; - 0EE11246267BBDC1008DA8D9 /* RuuviPersistence */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviPersistence; - }; - 0EE11248267BBDC1008DA8D9 /* RuuviPool */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviPool; - }; - 0EE1124C267BBDC1008DA8D9 /* RuuviRepository */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviRepository; - }; - 0EE1124E267BBDC1008DA8D9 /* RuuviService */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviService; - }; - 0EE11250267BBDC1008DA8D9 /* RuuviStorage */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviStorage; - }; - 0EE11252267BBDC1008DA8D9 /* RuuviUser */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviUser; - }; - 0EE1125B267BC327008DA8D9 /* LightRoute */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE1125A267BC327008DA8D9 /* XCRemoteSwiftPackageReference "LightRoute" */; - productName = LightRoute; - }; - 0EE1125E267BC34A008DA8D9 /* RuuviReactor */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviReactor; - }; - 0EE11261267BC395008DA8D9 /* Swinject */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE11260267BC395008DA8D9 /* XCRemoteSwiftPackageReference "Swinject" */; - productName = Swinject; - }; - 0EE11264267BC3CC008DA8D9 /* NordicDFU */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE11263267BC3CC008DA8D9 /* XCRemoteSwiftPackageReference "IOS-Pods-DFU-Library" */; - productName = NordicDFU; - }; - 0EE11267267BC477008DA8D9 /* RangeSeekSlider */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE11266267BC477008DA8D9 /* XCRemoteSwiftPackageReference "RangeSeekSlider" */; - productName = RangeSeekSlider; - }; - 0EE1126A267BC4A7008DA8D9 /* GestureInstructions */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE11269267BC4A7008DA8D9 /* XCRemoteSwiftPackageReference "GestureInstructions" */; - productName = GestureInstructions; - }; - 0EE1126F267BC5D6008DA8D9 /* FirebaseRemoteConfig */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE1126C267BC5D6008DA8D9 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseRemoteConfig; - }; - 0EE11271267BC5D6008DA8D9 /* FirebaseCrashlytics */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE1126C267BC5D6008DA8D9 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; - productName = FirebaseCrashlytics; - }; - 0EE11274267BC751008DA8D9 /* SwinjectPropertyLoader */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE11273267BC751008DA8D9 /* XCRemoteSwiftPackageReference "SwinjectPropertyLoader" */; - productName = SwinjectPropertyLoader; - }; - 0EE11277267BC7A3008DA8D9 /* RuuviDaemon */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDaemon; - }; - 0EE1127A267BC7E3008DA8D9 /* RxSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE11279267BC7E2008DA8D9 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxSwift; - }; - 0EE36EBD269F06CA0021B746 /* Charts */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE36EBC269F06CA0021B746 /* XCRemoteSwiftPackageReference "Charts" */; - productName = Charts; - }; - 0EF00EFE267C6A930082AA8D /* RuuviContextRealm */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviContextRealm; - }; - 0EF00F00267C6A960082AA8D /* RuuviContextSQLite */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviContextSQLite; - }; - 0EF00F02267C6B160082AA8D /* RuuviServiceFactory */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviServiceFactory; - }; - 0EF4E31C2682403500D83CC7 /* RuuviCoreLocation */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviCoreLocation; - }; - 0EF4E31E2682403500D83CC7 /* RuuviLocation */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviLocation; - }; - 0EF4E3202682403500D83CC7 /* RuuviLocationService */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviLocationService; - }; - 0EF4E3222682403500D83CC7 /* RuuviVirtual */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtual; - }; - 0EF4E3242682403500D83CC7 /* RuuviVirtualModel */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualModel; - }; - 0EF4E3262682403500D83CC7 /* RuuviVirtualOWM */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualOWM; - }; - 0EF4E3282682403500D83CC7 /* RuuviVirtualPersistence */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualPersistence; - }; - 0EF4E32A2682403500D83CC7 /* RuuviVirtualReactor */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualReactor; - }; - 0EF4E32C2682403500D83CC7 /* RuuviVirtualRepository */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualRepository; - }; - 0EF4E32E2682403500D83CC7 /* RuuviVirtualService */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualService; - }; - 0EF4E3302682403500D83CC7 /* RuuviVirtualStorage */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviVirtualStorage; - }; - 0EF4E35626831B1100D83CC7 /* RuuviDFU */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDFU; - }; - 0EF4E35826831B1100D83CC7 /* RuuviDFUImpl */ = { - isa = XCSwiftPackageProductDependency; - productName = RuuviDFUImpl; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 64333D1D20B0C45900CDF4B6 /* Project object */; -} diff --git a/macOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/macOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100755 index 919434a62..000000000 --- a/macOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/macOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/macOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100755 index 18d981003..000000000 --- a/macOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/macOS.xcodeproj/xcshareddata/xcschemes/station.xcscheme b/macOS.xcodeproj/xcshareddata/xcschemes/station.xcscheme deleted file mode 100755 index 53c63d2d6..000000000 --- a/macOS.xcodeproj/xcshareddata/xcschemes/station.xcscheme +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 23cf255d9d21520c3f78ad1ca7088490317cbfe4 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 25 Nov 2023 10:39:37 +0200 Subject: [PATCH 10/84] Remove ActivityRuuviLogo Storyboard (#1726) * Remove ActivityRuuviLogo Storyboard Motivation: start migrating ot code only * remove duplicated image --- .../ActivityPresenterRuuviLogo.swift | 6 +- .../ActivityRuuviLogoViewController.swift | 52 ++++++++++++- .../Resources/ActivityRuuviLogo.storyboard | 69 ------------------ project_frameworks.yml | 1 + .../Contents.json | 12 --- .../web-ruuvi-eye-nega.png | Bin 31969 -> 0 bytes 6 files changed, 50 insertions(+), 90 deletions(-) delete mode 100644 Common/RuuviPresenters/Sources/RuuviPresenters/Resources/ActivityRuuviLogo.storyboard delete mode 100644 station/Resources/Images/Assets.xcassets/ruuvi_logo_for_activity_presenter.imageset/Contents.json delete mode 100644 station/Resources/Images/Assets.xcassets/ruuvi_logo_for_activity_presenter.imageset/web-ruuvi-eye-nega.png diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift index a22c198e4..340e07d42 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift @@ -20,11 +20,7 @@ public final class ActivityPresenterRuuviLogo: ActivityPresenter { weak var appWindow: UIWindow? public init() { - // swiftlint:disable force_cast - hudViewController = UIStoryboard.named("ActivityRuuviLogo", for: Self.self) - .instantiateViewController(withIdentifier: "ActivityRuuviLogoViewController") - as! ActivityRuuviLogoViewController - // swiftlint:enable force_cast + hudViewController = ActivityRuuviLogoViewController() window.windowLevel = .normal hudViewController.view.translatesAutoresizingMaskIntoConstraints = false window.rootViewController = hudViewController diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityRuuviLogoViewController.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityRuuviLogoViewController.swift index ab6699bf6..c50eab597 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityRuuviLogoViewController.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityRuuviLogoViewController.swift @@ -4,10 +4,20 @@ public final class ActivityRuuviLogoViewController: UIViewController { var statusBarStyle = UIStatusBarStyle.default var statusBarHidden = false - @IBOutlet weak var spinnerView: ActivitySpinnerView! - @IBOutlet weak var logoImageView: UIImageView! - @IBOutlet weak var messageLabel: UILabel! - + private var logoImageView = UIImageView() + var spinnerView = ActivitySpinnerView() + var messageLabel = UILabel() + + public init() { + super.init(nibName: nil, bundle: nil) + setupView() + } + + @available(*, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + public override func viewDidLoad() { super.viewDidLoad() logoImageView.tintColor = UIColor.white @@ -29,4 +39,38 @@ public final class ActivityRuuviLogoViewController: UIViewController { } return statusBarHidden } + + private func setupView() { + view.backgroundColor = UIColor(white: 0, alpha: 0.8) + + logoImageView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(logoImageView) + NSLayoutConstraint.activate([ + logoImageView.widthAnchor.constraint(equalToConstant: 64), + logoImageView.heightAnchor.constraint(equalToConstant: 64), + logoImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor), + logoImageView.centerYAnchor.constraint(equalTo: view.centerYAnchor), + ]) + + logoImageView.image = UIImage.named("ruuvi_logo_for_activity_presenter", for: Self.self) + + spinnerView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(spinnerView) + NSLayoutConstraint.activate([ + spinnerView.widthAnchor.constraint(equalToConstant: 80), + spinnerView.heightAnchor.constraint(equalToConstant: 80), + spinnerView.centerXAnchor.constraint(equalTo: logoImageView.centerXAnchor), + spinnerView.centerYAnchor.constraint(equalTo: logoImageView.centerYAnchor), + ]) + + messageLabel.numberOfLines = 0 + messageLabel.textAlignment = .center + messageLabel.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(messageLabel) + NSLayoutConstraint.activate([ + messageLabel.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16), + view.safeAreaLayoutGuide.trailingAnchor.constraint(equalTo: messageLabel.trailingAnchor, constant: 16), + messageLabel.topAnchor.constraint(equalTo: spinnerView.bottomAnchor, constant: 16), + ]) + } } diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/ActivityRuuviLogo.storyboard b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/ActivityRuuviLogo.storyboard deleted file mode 100644 index f88418340..000000000 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/ActivityRuuviLogo.storyboard +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/project_frameworks.yml b/project_frameworks.yml index 91234f0de..d4c52eec8 100644 --- a/project_frameworks.yml +++ b/project_frameworks.yml @@ -195,6 +195,7 @@ targets: - package: LightRoute - package: Swinject - package: RangeSeekSlider + - package: NordicDFU - package: GestureInstructions - package: Firebase product: FirebaseMessaging diff --git a/station/Resources/Images/Assets.xcassets/ruuvi_logo_for_activity_presenter.imageset/Contents.json b/station/Resources/Images/Assets.xcassets/ruuvi_logo_for_activity_presenter.imageset/Contents.json deleted file mode 100644 index 22de1297c..000000000 --- a/station/Resources/Images/Assets.xcassets/ruuvi_logo_for_activity_presenter.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "web-ruuvi-eye-nega.png" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/station/Resources/Images/Assets.xcassets/ruuvi_logo_for_activity_presenter.imageset/web-ruuvi-eye-nega.png b/station/Resources/Images/Assets.xcassets/ruuvi_logo_for_activity_presenter.imageset/web-ruuvi-eye-nega.png deleted file mode 100644 index 8fa085fb9a2460c2a633979bcdfd405ed12611e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31969 zcmbTe2{_d2`#=8HoJ^->RN8H&WJx3;W9<+bSwfNQvSp1CVHkCa7Wrf?>)5qeT4Y~N zlv6S^_B~3BH5p|8-OtoH*XQ@YzW?plb#>zXe%{Y=Kll2&@B7@+*VWv#e$RRg!!~K1 zQa8Xb925Qyuj7O#sn(U9@Xzlar_Os}*amL&mjjDS*o9$h_c|GwkWF+>6K&mHC9E&H z+t^9?x_ZE93{zC`^{}>ewj=Mgv2$>8QxcpktrXnrbWusrSVrfFj)$6^qthurPdh_D zT_amRXIuG;f-1^;6@7^?fvX+adatjmi<=kGS4ogPFA;u5k0k~7vWJkJl>|?q1^1fh z=3B$GXel9E0?J`z6C67HT3l2Y>W@{&i6N*+CW7)BiSy6Q%@ z_C4(8wf~(tB&8&d zpd+ydUbOvpoQJok3w!a4wvu)(cCL1AWG@&i_3u~@M|ZNjm!tdt&D8(C{@)e=((35^ zyT<>x7gyJRm+&H=yaLDgMUek-w3pFU4?9T%J1=){Pg}c_S74j_(P=!0YMyr1WOq*^ zcXyY6E=vEOE$>xRLl+~zS479!*2xW>L-fDCvQxJv+bId65r>Z)KYT>WNJ^e~_~GYJ9rue)_E-PMp;E-7$NsmWz&97I$=3g`gD=_=?cF_Ht>M&8uGS8Ak{)gj zf_wj^B~i`Y#oZGYhTTd3_j4^ZHGNNadnXro;boxt$6l?IYO+%Dva*MdN=UJ{tD{5I za`PfvyV=@lsVfNrg(RGuE)uPe$jeGuTgx4`v6iwue9XpH_OSI)IjO@(j><~g%g7u% zDrIBy&-d!?w%&*j{`vmm|IhFBJe@!etzG_)=Rwkm7>Ibv$qTOb>M!{*w7dN4Cl{x^ zY@Q)n+ag&|60}83V0TgQ*JG#uV+#D7*2mEfCjEcli=V^1-0jIe)}D4J9DrK?-@?kFXWoYa319Cxowa%3=-{5k27;#uL&Z8zz6 zFWotJdOG1w!NHAhgT6MHj-H<^RTlW&y5WOgTVdmadHUphY|!(s4(Qc+$fhqet)m$hYciSy>zj|LFf> zs{hz(fwoGFLEOk?eoW*KEj&%ulg>SEnY*-{s~xB}BlEf1X~`hK&}n&wN}zQ($03q ze-!&>Xl<#8Q8ZwM(6fe9w|;z6eWelLdy0o;AZ^P1!Jn74?FQkfrDs?mvtxIc;wa$A!K z%l1;r2`}|Jx(G*1qR7-Z!}lpWGXHSG?^;J9s@97P9@&h3%N7#iqYa!J7p;_w^4w)) zxaIQEF?gy7Pp@@m<>f_v*LWwc+IRkLc+6}^gf(U&0B_cGYPWOMglM;GzR%zg%iKLa zI3=3FeKHdB(1E#=-^&Yxo)cBs9Fvbr^b#~(?9hAg9LGW*>b;zc5eVgqeHI?2joS!( z5c^hvN}#ETFtN3R2|&^>mYe+Rf}ih5ld-exsH-qJy0MC8z~Jz6X-RR%zdm|}7L>Ry zq=AE#5J70fjV})#dJ~X-aR+siqehKD2xSa22R0(#vLQ4ZNpHJC%{{~5AfA%KbDl=O z-Ghl_wWRQ&>u&JT_5(>a>3`tJeY|_ULe)*!fOB(&#Q2kbqbt;z2e-L4EZTI4V9R=1 z_@dju^e;*CZE8~Z_NUxirfT7=H@q;`VIjUxTjhuDJ8qxO)2LB@CyvP!?8a7u{9=luPJOMmJ;z>M^_q84jH%c1 z*zGfn;NU1Pejm5wGW4RJklCK|JTTRRK-Ga=ynipRr|x_SZ5>a1%TxdL`y8J6<)-&bN$g3{}&wh`2iOc`p&>DtpArTwf&h@ymzrAE7Ynt_1 zpl}=iurWN3^`zrd&(ek8ALO9j-0`{kx$*_s^;Md%H_K;zyi|S#{@ENHMO_PjyG}k_ zy@uPmQXU&TeX{0$6vL>Ww~A`W2)5}A`738kPC)eGTC6kfW86~#$pqXkeVE*9+%xbv zFDG7gH7>06;<7LL0FIJ$*+2o?evC)=PrTnLEqsZ@km8n{ck}8U2e5qWJ0HbH8^lIc zQ4BrR&)s4NPVN<8Z4pD2)=iQ&aq4NPRdgpUwS$&J~IJFeNG_X zj3Br?@FZXYFLu2r=KoG2=DWR@$IO~wjw((OW>wr^LT%bvI#;yL8Z7$Rt}S|*QTKMz zIgDz&GjQ0l^%z zvZj$Ui0ddMExdB3IXyWvG*8oc4Th0hjnsLyM0K{)Ias@e_=js2E=b6hiX>-CEz&t?SL~|;y|ZP6_%4YJEs@)O2$(mp zozS;>*a^Xqkz(Iz{J4DcgaV#=;+xCMgQIugzN0mqmK3-O6%mJf}2m~;{_vo52TF;xva=p0Y)M-aB(_i|HrcJfaH=BHh|mmZZQ z!MCPJR)}xGjDGciY2-BGUrfwR*3@w35$yblJ|iVueis27zV`WJXI_QLalFTF5|NcM z%UZhOafBCZ!>6Vls_;Mc_dM)#{5ucw1ygY(lx}lfC@bY=Wbg<)g*8S&N z7$!Te{xWj}sIKZN%4`%u3>ZC)vx@{SYqoiLd*Rk=d0Gs7b1h+7UA>GKtx4ev4;9vF zNqLcbhz}b%Fr*ma6?jnaAUfN~xW0OV6PGZRAf**TcqcEHT2NMgM)r41wSiAdRLPw9 zTXS#(fv>T`bo?Ph9>dmO(x{>2UbtJ9yGUY!JnNq)5ncZC zqy@urht-Q7Z<1Bl3fbf+K$uf!@?sdpMb@;gFCI3ZalD7Gb>C3;-}1@7ujRu&nZ8Z) zURZ2GZyuyq?-@+sIyvf5#6Gc@gBaW*NCItAlR;xJ;!(4#&w--R`G`5NR zggkNVqbTnNzOJ$lQ?E%Mob>QM$n;nnQ;5UJ^+qNugxHMqY9VoVJT`pmP5u&}@>@?I zlQ-Y5VAQ1Dw_3l?39lcbR@g)kT;+#wTc-Xn=_O!|&ccEN`|A2mXoVozRN-E7{k1!w{D3XZ;8-XAQ20idV>%nAU>vPYX}b9NSH=9PLC6UGIIWA+^%dkIjgV`KHiSI87Y?j-NhS2N|nBw0nojHzoc`!I(#CUw|Cxs{@ zz9eP}W1m&|X~v_3*{zwy~lTj?WyU8yLCPA znAPtpV29wa&X`*R)B@*bu)#hN|i#8hL8Q^P7QM(FlAO>Q@6 zG&A=ICFbhG@w4Sm!Ve7QarA;CCA;Y|iO81$_jAN*n>Uf9m1T?e#~GEXTPwmO|A{Vu zYS_$NCzPmT2%qm2gi)$m4u)vdk98*#!FlO80&`&!+GiZ9qsX%Aum$Q9gXWISLW$n! z6Dyr<-mT*$436v_Xk6=J1=QTbCiPG_;@BjFV9JC1dP+e;% z4y`o|YdIS*ip9_zMADg|$5G_mQ|R;D_GE)NIPOY%x)+#mHnXW_9oBe~Ew^Ea##MYR ztnU3!X~f9Yr_@isa@V^Sene}?wsY+=`yTbZ?pUYNg`&vH=&q?rabcld1|(3*jl$wS zLqneQ5cYG6J>jj4x%;o>k=anMY1pu^0m)4j^^%4&bJ3=scbk2LE(jW;873qnIPj3M zPo&`hrK&(LD&cPH@4%X>=W7i~T+xIR@&}nX_Sq}EM8GgJH%Hk7;LI(|)gcMe4oJuZ>VAg7Yo`Dw#r`Js29t3W+qMUUS&CjRIZPq@ziT$obz zCBbqXBGY551ExON;XCOkxI~$_bPDz+<+T)sQ44r(g~oPWIJX;%Ddh@Hm`?H73A|=> zRyu=xfw`HS9HESL8s{X6qN&@r`DAlpbv@2*E#|<0ss+Vr6zoBI+k+>q7)FcfPO-2h z`GpN8G_a5DO^$!kG4jrHF7A?LK`VQ2!|RP-v_wT%sL2lrzdq{>^69X@|I#Z{1BP=Z zrKOXtdoc61b#3Bp_mr42&qof-u?+>4-%mD!brJS+Gs1#<+)lzl(54I=1dN6WSG4^J z&vZTEwt|Oh=JwKv+e}B!~`xo8iuOWQ>NECthR&S=F z7-|`6`BDd&+gmK&e)mLztlB5vY;jq8?Zb3qegFCQ7u!Q%s9DDfIKj-#Ps6qRWR$p( zG8t4c%N5;(w!$kL32GmeczH-nt~Q? zgoehul`wBo7H7vNE)rNj_GI-hkjBx!fOa#ax6GWAX`@cU~A<>`lmp`mzz0FMKL1JlW? zOZ1N)Kjy66zs64Sp@H8k^156dtvuj{hxuH5nDW;z?;`7iR)&IB=8P>VGs`}`SB1;x zzs6q}HK|Z=wX>--_@c7d(LfmQc;Qetq&!#r%)Io$*H4N7z3x!ZgVeY4Bngtk94Fa@%h2sy^F@lyp3xtbHNZdOtDH%U9dp~-RRoLq{%E()KpI5W9 z^2eJTAh~-QS;DG5(}1+79rEdY6iYbrt$QpHnKCKypT&hE!a(Br(;Qn*$Oedb7sV@K%lD@W-|5)#1}kqpo%XD;bg$ zW}kR;Na~I>@Bef|uweFw)+CY*q%Y(#S{uLr*t52zpq2Sj(h#li?c29;bKPDI1J}8f zj}LedhacIKn6DW7euxN_H@uunNk&3SDqdL_9pc>~*M2i3q+xj>Z*`#y&&9uVQu|BF zXp)Yo(s|-<0tSr5Q~m-A4?}mMfaJZrA8YtgbqH7Ac_Mz<*4Ot(xBJRh_mxS+A2r{7 zhu1GQErv$)YQha_)&!%S9cv=z+6M$Iv0^J&8A1Nv-w6kG{QkXh%N^?=zrLbeGG^Mj z*vPf*9tTG0p9@-@bI^961=Z8(6O@(tp~({99UrrxXvI@Q(HLlp}xc@^X7zCRua z82q>cWV)lNIdHi8pJqJ;+@9B_a7< zXf+rW)w2&Wo18y?{+tywITt9&ANZrcJmZDxiTcoX_aHy_hv{=Bi!aqd#kcnNhX|~M zFm~?}fAQjlf8}gJ-gx;$$!N@;u(zU%ZM*fu8qNLa2g*Y_+j0_bg-)TZn(o-KBj%NB z*A97yISa!N?^kBrDWexQ`Q%GmO=ycIityR!KS-ZzMRv5RB<$Wjx8?W76`q-70%sSD z<#8{&?40)TxcB!j@9deU8~01T#NT64wfw?g=3VfL=D=JUKYaMmT`$+?Vo9Xffufs0 zTf{ecb5`AoVo=~l)(Dm3J5{`i0=iy!s*cmKJz4Z5C4UDdug9Y(1|x4}B(Gw=XEM-d zv4XOAC6>&o$c)=(^ItqmEW2T_2z@O zdcWAUr7$DPe!~#Nz2$Yt!F85|Xqls{(A}L5>X$S`b$+%jDeh8cl-nV`R5~wj8@LTq z9(EiMbbSt22}~h#n%o&29OP?ISzR&*9ePJ2?eZlyTOAyxYOuYRkq-yT?})?xCyEfc z&1yBagC-nmzQ14dRk#0Sc^KooRivA?sEl?<_Wnqggwrb7Db-^mmMzrw?95q*hNSZ8 zs$g8$cvqpEdB4V+a($wz`NMRd6ZGOOTPm(%REf)cJl;~rjvbp@tXy4uL3o&!`coyP zx<#=hAkMlKssW};-$B7=LQx4Mp^!`%{>?6N{fn{kYH^>*{Mn;(8vVO4egDci|4L)x z8uEwl-@o5O0)KURrmcZb$&Y2kRLm#Dl>0o;^24A1O2EnoG5L}A7ZYzk8!NwlnxRmq zcORpL96We1E<;*X?!i+-sgN$5HnHkJxmsskch4;Xrt}4q=e+TbxV`bTXwNyKI-dxW z?>}Dr;i1!TOI3S2pWD?HBQcUl#Q9kxRwy1yT4Yvpsf;zMFWk4Aig3Sxs>t`J<4QE1QKK9QKU~8^0Yta=jY!7W0s|TbWDhQ z`0(MOM7*F)s?y&VuSc=!ukI7nAcbJm6LXDfToipGE{Z%m)}i2DJQ!n1^!@g!`St79 z2290`W!2-s2YIZD7dauURj;W-K445)^(EbFS$Zb36(>jwoL>?&Q@!IBQM6TcJ5j+W zDJe10dqC!8SXh|M>Tvjq$VB;EuLe_muH)zNkt}Zn64qRVd#}>~Wb^Brot6nAi8q3$T}aG# zjD3&QwJfs|rsqM`gLU|ET)Ve_Bhi8lS}wl+PUJ#PT^U=ieKP_uue-keuw^9k@7N%EhmE-0pWp^J80M%JXh%Eyxsc z^I?zeKp-c+#=G~PA>xhhUmqOi@X4~g9uc?+Vm85nTVS!M1*OO?#>B>M_im>xFV0oY zIt0x+gnj&Y#zC>s>BUFWS%8i-`<{0%i$NX)QNc6tvs~b30g?k%EFP);%y_qjwn$+; zS=jKEw`#Q|VnWL!V-GRvdc+cvF?8%~p{IEl_-@N_biuz#PXU2&VzxY$&VY;QpV*YVMGM1e`H8s@);${BeanoAv@e41D{)`B`s`qD8 zHwTRYc2;uv0&}Cj+#&y#tgNhtX!;+AcipwP84-AEwwG-wu=we&%H^(PkwlIW$E#Pb z*1j(v$#|iE^|Sm?mUhUnoUF6C;6G{;i}&gAZaX}fV7_my`B6p1fZPrj!enPbU37>G zpiQ|K;}0jKxj#tHi||T9@x!IhP01^)3$VLH^D^JdbB7DNziVrT^DCVtZitrIdhTe@ zpAjo(kP_eXOp>oea;R(und6D>;^~)agY7i6@nF%E^i?x|$r@i!MXLCYSVFlp=&H69 zPnT;>e(_4osp&&)^bqbIKq|+yLwfyLA2luge{$9J_di3RP(~Ds4cFv2w?Qb|Q9<$d z3Jk1(Ti+Omh!-?17c~74?o{P~ZH|4KcW5^l^OKvFJm+Sko%N7ALVl+-*ZsnTh}$Sw z*VjRvYOIf9d6@8G&7H`pGJxlgqZL{Nkl#geNI6>3%b!ko8f-Dqt9-)aIp`dkKeCu^ zWm6h;t|>?A`p$=Z7R?ADg^1WSYJ)%Jh;EtO7IXLl9g)e0$$MlN`C;YX-yeGB-lx3k z|HbsDB@nT;iY*1e`36LYIP11t^GRSJbu&a;KA-NXTeh|L5+xFERLq@bVi_ARYPnk$ zf8|%kc5U|QzFZp=MaN!#Nhk~)ced>EN1iC-{IE0k`1m`V!(MH_m%1ByB@+PNxGxzv zb!WEfkL0V&jM#%$Cc3ZsSzB8_BJWseRn=|6yXpD)-wsq3)Id0qpJ+z#;w!w^U&`LO z{V9+WVeIpB+APcr0T_fDEUlu1O9P25aTW0L0KJiDc;3cs5;M-2} zy18HAUxzbfc+tZ`j~jvT>;L`hMm$`RiSz;mqJw|`?ER^Yjkkw`MVV4GVcZ(*aPngJ z&|8uN)@l!oF!e}}GBVC&Iyq?N4~$+vsv{6;tJ^g5%+j?m2=LlP`T2{WD#B*HjKOQ z%4L2I4l(mi-d!o+$G61WMArg=s@971T5L)CH>~yT@00rGAzT6#P46bvYf?(|nw-ty zZ1~sP_%O%P#fegPkka;|7Y+?#BkIion=gz;@avNC*tvPVRi?`FAIyzaUyD-1vgePL zzYc2Znt+bI9k>p%L7p82=_`V}=fp=Lr~W{~g*67*YF-fMWqqV{2}@=B8C44h%ES z%I137sng_qmOaw>vN5r_jdVuk%2+!SIP;O|rc3ZD&3@GrqtdA3NZvtE*E0gXCAM zPO&lyjI)^6DiI}O`4;>4@1F*$mfNK&A0b2&^3O+0GS5T`Z2~~RM|1?&KZ?N0eX?l` zp>oQH6?LS--neu;AM68qy!TyTX1OOOB`F&d@#X-->TRRvi$+T@t#1=Bm#W@!|31k? z4w3z!6YnWZ{P;7~!Z|uA)A&_-Vb*ZSdbm|gOyf*m`Tfx2`p2tpo_&=b0$alJPu%t! zKl@7Z-1GFpSP5RlciGtxJhlw%F}3nKcY6U`Ycr-ex!V_FW9DX_Gw&k!bFO0=>m6Xe zkvo=41FgWIEC2E8?Q}dQApwymSd3aqIhh)keMu|ti;4@tC#!5G$WoqpRJeVn)9FhB zcpxTu@1t3>5jXC$@u5BEMMpBc8ZSrld^-pCeS-_tiY>GOtl%TJC(ICDoxyj?T|cXl z!M;89yE{S4V$IC}1xy+>J7*bO?0;L=*P;w_SZ@c7f%#@R&SlNw?-(V}s zp7aZq-)>0$snG14vehBstWBaZeLmoL3m-PTx2`96W)}h_`d_cD>wV%LL~?pe4t>I0 z)bjJ!dW{Si?9?m7&o!WcOa;I%f`9vukackE}F=XT__4#KJ1sdhHGRI z%OG?npS$nSlRTKVD}o=ur$(X4vT6Dv@N3H}hy)?xNhTx*eVLnMn_`hN*=ttH3D|$}yLazO@9`^*TzYkBr0y>d%NW-1=L|gD z?-QkER#PEyG&N%3JMmS;A?COc9?#}f6K?#wv#qCC)^lT}5&VR^AZTLt$k)hQ?#wGc zOT>@1`e^qqK1;taLcqu^zy;v=V9gCirP`j)6lnOj_-uJYDk%k>zqJ?Q zS2H5+NIQ7WK1DG(liTAnV-wQjK}jpkwO(-F6ivsDAn>LAnQfN#(5KskD8J7(S>W01 zeBI&^^1?|7JAC>bgsI@JsOdcn+$_fR6o zUO~a3vXx?wj-8CSg}H$Lwo%3iyYWecf5OrQ>AcYAt;o|%GDKnCU3xLJ>%8rm;0t!NcgBUR?n@$euVyvL@<*(D5zG32*e1+sW-%w%{@;KDhQcei+$UI94Clg zt4x03uYOBmalM;`w6T89X}Z@ zmBzF=4y;IAxDHm_9R~lu+Ke1x8eoIjQv?p=Ny#hG%)m1?h$1*(#0o==&If z)gQI{(f4ncmI6K_(3&A1dLM8+w~70jPLlA!o`1|h5;kd#uir#VK=(- ze{ltRbg?l3UYr}G;Xmet_~fMf_$Ml3Ri;bx$*Wg^i})hFdi_?H=j619X#P*$mda}t zHuGU3Zos_$%#Bzg)IVR1J=Aeqp)m*VGme<&5B0m`(RtYIbASiQU?n=k3C(nbaY2yj z8bz1-bR{#&USYX07r8wsXr;bhsa^dc;0{vRxGDGI=mvbrRHNHrpVdpTNgJ?yd&!C) z1C{9I;mT=+N<-pn+UWZolWx(hTM|k;F{}EOq1B~i6hP80Ag%e+JFCUw|CSFYFQoAG zMJBNkoy0&1aH!hD2^+7aq@)ycDgUt2Wb)$1P}rcWoX-;p^C@y;R_0@xcuqt>LK7=> zVuXb&mC_25FY)D70=gj6l&7Psdu1tJm>MYk-^|mZR$lnPV9)p$^nps_4Tm+@(>lxL z7RzN%pj3H2GJ5wl`Q;6XwbVUMeQvE%e21Bk-A@eQ$Eq~IG5P>Wfv&XQH{KOk`h+h$ z%yxdHXaw?i>%^q=3kICnwmEQ*vt9tRung!|!TFTpE5DtS<_~mq5KR5}4z1WmPgKxr z0MPnyB90boK+*>LV9_3LQR7H*ddAH)(te@vxAmugO*OC-Py-kGzaS{ zWk=Ta2oryZLrzm3`N5E8*m~qYV>*(VwihZD&NCEB2m+YZev5#qH$kBFXxo}tHV26_ zw0q-VN+i{5PGu$GvHUGM z^kd}@Zs{tf8`kx3k%yt6gJ(9(J>c^=V>h-CT+Td6zG&%}MJibYr9J?t>dHtgc&@{E zuwi{mU*+O6yf(5w-;XFz%-z5NM*@*82Ibaa;6r`&>zb>Q@01s)WE?Aah(j`Exbe00&!E4SfXv!X_r}!_@wlq1VAW-Wfyrd5ZuQKRkaT@=emtZ zPOJ9(jklDT+Dbyx(~bda>rktvezzo0zg5kE`+QvoB2MC5CoJ1 zQph(soYwzN^4FR^ZaCD#@wZ+`l@K zj3^iQtuSb@un>Yo{k2>wOZiX4{4Yu`GUOny`0Q5O8qB5hW16PkU;>Qb&|hn4Xc%_m z#*GYyJZDXfhGo&ih>Cu>wb<~VlL12t7a(TMhT_In_rU3R&{Lc>H|H|keG>x!Gu!43 zbqD`Yzn4Vy-nC~>+~TL}TuU7tIG&zZw+I4e#E`3;uYU+Mf6Vs3p4ryw#?qzMfo~O7 z=B8F(QT}_N=l(pj+-P29ARUbHsGPEL;KI`Uw7>SyE)447lFTRX$P%@Z+dqw>@*`xz zw?laFFfp-5L0Vecm{^OoH&(F1VpvK%0eo0hCgn3v-;Wz;%@5u#N>b16?{p;>FM^tK z`BH#k@%>fDsrA~ThnL43RJ?B3&5fTHt->}(G2eyx4Iq< zD(N`nxvW`uJNk~G#8?jb3yUYHh*CbB0{cy`ZC$YZ~ZEK%R!fU2ZFxJ zMBdXccae5)C3$sdRg^DfqO~B=s$7WDBisb=UMshr;?yK4mF5=Y@cz8~OHZFANm{sT zS+-SkV6x7j?%l3jx#AAUt@mubd*F-nM76N6p#;s=g*VO;%<+(Wc`95`=|Y*WvrIY+ zieX~qNBHUw?hNT>Gus@?q9m<_ni5-})oYYnL1C6SsHX`Di?Skrb|lX$Bm1mX(o9dw z{iy;7)To2>S@}22>P5xUpkz20O4U1ty`^89+7_-AME!gv4H1*yB?x)I z;$bgMzW2(6IaB_Uk;@rM5U$?t0!2p1cSl)XPdY(#&G3Hz*)jPR7g_UL9oB6`MK@UD z7G0eK`%$FHfA!1VYlOz2!0(aCcVp@Lnvi;WLRon%v}`KLiM8KFD&SX&8B=ycQ5K8E zDrU%Ea$LHUT-JJE`7wJK6bIDD(y^*&B%Z#d>47;B6Bj}EeMW#LN;K<%(yD4A(U#(+S{`Zb0}w z-$pxQE#E#!H!P_!H_Av~F3_`>8JR!QP#IJ3E<88g~ z03SxckDt>USTHFW9a((_Zu(#3A&dYZ8w3mmI$bc#N1R}3@gDaE#4a9 zF{_6Ps+6VADl2Jc&m_ut7IRrRMFe)hU70*VZg5>U#|T9B-oK=kQPhpkGhzsr?0`zU zbpUh57k=QQS*(1~TloU!`_h-^a*xd)r7v=cLCrKkC+*J2%t20L_-W-*UFFgn7;|yS zQ{Z&$q7@jA(@h-IO%K2;@L3!$oP=x}mHtaWq?^a@zKLQCX9$!r4p7QU&qDxhYGPut z@Oo#3K9LhMx3Too3^SX!P6CKQYH@BdXc_`a5Mdd6OTQtr3HyTZXcpiIlCLpr#&fLw zSrdvcUV!+N)K#$V?I~vA1iB)7EA%PP@j!;S2XNR@h|UAwIRUvGU~(lWF1a#;mniHm z{}?HPsk$E96Lx1kvC0bK_(T|eC^7AzhQxB!AZektVjcF0#7IHFqJc3Y`JQ{A}tDliq z_I2$^QsqR1-o3e_8!>$)b}7TJn-LjZ>|0&20Wpz!z91K?%c%8-%gs(ej!_)slAZv~ z-YZZRSermC*8CXhGc#pq`k^6Fkizr=-1tg_0=8v~l$_k$JGfq(fEjm*!_2UxHvqTT zqGT637Am}Dg`>6ZcYDXzK1(EW_vuO)NJ78|-nX6<9j^o&W$6xz?k!mPpopgMAqFdnV+%dM?-U zC40amqf?bDZL4B@DTKGife7#hG>m5!GJgy1wO_;XmTbJW+*zO`^dWMqvM+-$TLI3^ zjj!dX!Y=$`bySPX6YbSolAmv7x$t%D{QR4dhzS+IF;tOe0W4InoH8}=rYGYCrtg|p zxw0_N*e&LEad2l$DXt2G+Rotv!eu`91}9LRBy=5(18h{6A#G%4JGc`>XXECzd{nm| zQ{h3121K#$)MH6JHTMUuv2|CtZkOesvexP|1UAgyf)3_} z66+ z!97dD`MrVqMm3Ld18^$~j0^7N8Mba_`(J}V=>N`Mri7UpR_kX@I4o!$yqCg&48C$MSB4fiT$hKK7 z7FhZ_U%ArS>xF%?MayVH4b~MusBb})RE2Q%;TWi=>A@Jx(`2ssp1y;%E5@2=CrfHaq-0jjU4(;|dWMP3&Cq_-D8S2$uToWjn#>nau)!{LLp?50_RvtMib^%7 zeFBGkUI%+%sw&VQw@U%R0>g;&w{+fISNAJ*Cr@qZ&eTm2!h`Z;GPIcViN z)I?O4%M5jkB>s-kwgE=G0U7#(!oohMb#>oPLe;DUWuYlKa5N=^f8kT*Qtax{3g*0YGiQO)ASx9V)BSD&ffhN`HoplzCFM< z?7vgeqFYH`z8Hvg6!N2aqT|~=9vW2a@3tmD*dr<^$diFniZU1(o<2uftf{G4wZ0m# z8%0Aafa9AkfIC=cnGhepn0~z%v&v6AemV6jpjO~1XU9c#_K6;1s!Dp7q+5QSXV(L> z>uuRZs|busHtJSzKo@x^uk8Cob8~Z085C+B@_)~P1x{G53|huKy<(;!#3z#4CA7SL zviKzgIn(T#TeOj9;0zuPEb;e7+{Tt4P)C!J6*H|D)ZkHg0VuG>@A`H;h`G2k; zU^p}sycvrh2-hF{x16~zXmy$A^cxPU+ZhI$Gx=`lEi~tu=!lAQ=w{uD`ftwd7d*Ff zVS6%w93fx}Uu1Ak78txT4jTKXw0mKCDE=A_%K*Rvnov*v1pZe!v1~~piW(|K&O4O2 zW|!ixj5GA7p>ilt+t6kTDJ|t^28^BBH&K>VS)A!`Clmc7?t}N6O!A*NFP_MOL75@Y zG#0|R>^8wDXotXv!%&;#`En6i7|8VqpCc_8z1v)6)$z*pf*AXYZ{@vTAEe`y=H5sK zUUmkQ5+jF9&d9omK^rP8TG0;~njt7O&*TAE3fjh5)8%XA9fZGeC`Cr(kf6CJ-PEn! zRWu_rg0Ky_UCoh~ilrVcZ+fl-H>swk<^`As)_7htBLfcN29y)q{@+JDkBZO1#}y%9VERLd@litwTnKMe^fWi*RF!0l4~ zc`dNwUEuRX$;6b`_QrwGas`8BUF%{FuUdf7hT>A=K#G%A@+K<(KlKq9O?q~sXEBhu z(Hm^X8<(zE_3ywZm+AK}-4t)S9IvgtVAEiO;U<42>0ybDeO=yfGlZ61?r*D7UFaTC zmODoTN+q&CF<<5ZU+T?RXMwXO`|55^j?0b-7_WY1MD&iC6R4s6{r&74$d|9k>WX^P zQu$1nPh{jKkDJGOh_c>*pFnv=zPa8xcO|T;Cpgut8a!l5uH|S#coeH;XEu&??Fm#I zJf3_3T&>UCcsAM~&UAUPj*nNaEAjx=|Cj)gVmk;7cuXS$w%kuqr|D^y^7}Pk5bd7MCxkXg8$BScI($dl{K>GnIjm($&$tp(e0}!T}X{mHA^I`&> zP=f*yay8k01k zhvRy}ScPc4w#p~65AC>c84fdQ+gb7L#yIjS&>~~YH60%VRKqjAl)yw{1_E*t=3nDK z)#)(ypKc1~_Ywp8%xvW1f;4Q38}xHaLRkA5<)E;9W$0n>D+IE|m#_o$c=J0P9=lP0 z0HmOxcWDU4VByGzobnVXGtlzk+uCRdsgO^n&?P+$$5G`5#|D*sGp>I=C}{IM-U&O$ zc9W;x@+|M;!u0nM!n&eD3`n(-%b%hTGVhp&t?{^p+As*=5C{@N-nw?8&pRTL3@%-f z{=I7OxFQrl5PA0$I@Q-vzL6qX>)^mjU%ws4s3RVZ-CxtAc1X@$2K&atp5Y$AZhb52 zOmMfoGxW@6KNW>SM~C#5DfOMNAQ1xmMZe!9)8 zx&~`pMGXf)$Zoql%R5DWTJBer@l`GI)Zd_PqzARCpqOWxjhPG|TAc@M36M6d=q5@* z-$WtPETA?cUmIK^IT~$|Rgmion7#+G16K4rXg)UR{2o5O9supmW<24oA?HLWLq&HY z;WrPNHglgI1A2$R0`!$arLf}!RDvBb>L^0(4u>e;FV*$z7r%;M{{x)R<#UMGX1%EE zqyw!v1<2SrEuYs4jb4@ujM$YNbXO7$yZ?xv?QBuL3ahjf^J32bR!U;jx<$#=!AgX` zU9NvZ`EKgZsNFvhfUm}$-lBj$U9Jse-7A80bs0lAkEo?5T7QMOsmioH7P?4-#x(oN zo@{4@I!pS5=YQc7sj2`jTd`GH$dt*OS?esyYztVYngz9vKgYi80I1NERKndGoP^xz zi718v1Tff3WC+Kh`ZADJFYlitc|;4p5W`-)8Ww+0(z+8+%dDu}`OQ?fd`S?sAjO5@ zv^Ll>?gc=TPb~g=B{&qIEcjM#H>Z{PKiP2Y$55$Lg)ky$NlBY^^nehy1RzJS?RuT z*IuwAUkfT6bs|~NY@sghCc#y;fO-q~*!6cD*pckO8RMWCu!$p9hu13EjKh8N^5eIC zkIoCQgNhEQ%brPIoeq)!7$CEC;l`*a)4B5tq0vcCdHxH;ff&rdAG9=e0YM&LO)DFb zW0h-z!$fRdT%IyV3htRqhdIGlhNBG}jk_zScq*s3kjQV`(?w9oEC%r0OUqq=U#@gT z9E+cu$qVYy^MC@$53j1}CZj2rw>Xzwb3I9)9}GR7PglhFF8{2gjrPW<{J*M(ZuB5H z2IaU+D}9w<|EqKg_U?4OSnRJ} z)3K?7VAZ6dsaeQQOF||R>ZrnC)J&&_#mkQo$_0P5agb}$!j=6fNY=f*Kt)?hB&KM@ z@m&3Q^A~Y6EH^a%j`T)^&?MMRDX3_kczt6-srFFz{f|)$*yYQQT7J+fr2l|DV7etQ za0a2P>BaZ2@jok$s7RTa!4kitUK5m!$GoS$MCzH2^vWCZP*Svr`sV?d?NWjyHPrY) z(@7Wr+`W(?H0)7us1C_-&rFw-n=+-|D_UJybU+?ScF8Y-U$VcHCfWV%ughDY5mm@FH^gP>>D&=T^)q+cnsUG764GNZ1zvEIZ#OxJ|!|81|F+j4*UhoChdzqc;q zlPh?*)BRPtf+9g=0(H7Tc?Yxz$=@yfEZY((SK3WEAh<(zdLy+SA-iB&FBC~b(v0$} z)B$$^uiy-L{FOAx-eyQ&PhRknZot}~BC`|Y#DP8SgNBSH5QgRtWA^L)YQDynYJ#R? zan!v8i#K_pZ{b`T`DWb1&M_SE3`6hAr`=fmbN9ZA9;7>v7RkO10dfK;_5$<#7qUI! za^?&`_v0y?s=`Zcs|%KWkkP_uV)uCEpF?JEPaI4n>+R7EiBRw;$OGpw9%wv)YW>Ub zzqL4KNGf!l-Ir)G!RBnPCCw%st%_f*zFCR7SH-E!b?d5ZuC1d%|g3@B`| zjF&7ZHM+4p%;y6gcs2F{jQbJ%Tkd;VK#ZWP#ATKC%Dt~Q0jlE=wAC06UcA@i4wv5Z zM9rS`C?X?Ip`cso^;s9yWZ$K!T2#M=HRhR_cfqoL`od5V4gK_J8tGiX28#y=?LxqZ zeR@<@wlx4?DISpgM%0F_Fts<5OpBQSkmDheyM?grA?DI8kMQ0u?A<7HZwb>?=C<1Z zj}L{Wd0BiV#~GC~D$L~T>av{_Who-D#2Y+aD3k_Qac8diXxt-R<)=+TJrt&DpNGhL zOjVoY#Qb?V_u@tzxh94^=fK!|O|YanWZ!$cVAvLfU5!KZRQ?2X2C5;uGJkl^VPAjP1aIghoAwaL*7tBu^_d zA9C61m9%s{@BW7X#- zHFdmMBL&-g9;9nR`j+x_WpNUE8G%pQR-i*BoBSs+e&nrMsf?Dpdd)*OMV_A|W4Emh zmcM#SS@48Z|a@Nt^Q7-e)BkjvxK|up>v1RoDP0YqybG@24Jn zkcnh+r{I8oVG>uqMJ5w;??0*bgxV%0VFS{f_vgQQIwRQ(*nsq4;)4f{sG7Xd)vb_O zk~`Cr3$CP~C%rhn0dJBAAwIigLNA(w+IjTk)}Ahg>=(lVvY0Knb1%m54G`-xJW=d z<&o!^1T|G(x?GV;leZUK{qkmC;VP{K{5Mkj3z`QRw_S)!MlJ!g?ybPTu<$R9I7|B9 z$@{Y-+s2K!jr}7cPML(t`{g_94*(9*g2sKb1mSbm()|VrX&En2i!%gsL)#m20q>ym zzs(@d*=28GeQbuTwL#-};`Vvq@_Buu(pZgB^w}k<_Y0H^63s3Mh=WQHbG>6! zeHm%DIvVxYI<@}yrSd}_k#lOU#j}9RA*gm_zmkAu1Ptk~#F6JGTzIxx3;AzeM+I;r zwh(41GAmZAMJe^IWT;~+-o*joLa6)|E)Q+17VxbOF@+MrnY&6Pua@qZgLbG0{`nxmicY41A=Y>gJGYP2e2k_L}n?wC%qiSJO7X6 z0`z8cVaSAMW`VGG3&9eRb)VUu{c^rRahpGP%J^u=#2~IH;A81J-jdm$Xu2vwbyKY- zW}ywYC(R_dypG6#^Jqx$!n%-OmUDGcz2hm(fC$ii;v>R8M$V>gmCp60jMXGgEppdR zUhdpmVL53Zr^#VG37^i3SWZZ3VpXo+N?luQSS1w8FHSNtm6Q?}8W`MYSQ9;)6 zIULZP*H>uK&ioqFtnFf)9N%y#1uY_@P2Qio9nC9jF;MPoMt1XNDcwZUKQhuogo8cy za_j!p(u1k1aX?~B%o20nvXdY+=IKXX$p7$Sru4CV6`U@sGxe7?NwFv24~iphtErzzfso zG_5Fab;Q}7mZ-TY_sV2iA2aQ7=Q%IGK!3@;)rGL2!uP3il;`V(9oWzt-?hy;dr`vY z`VkF2+6sGE-X_8s`eZU*P#utWdZ?8?+&+`F4Vci7Zxb#UWMl4)90z51yms#5x(I~E z*uy80NS=ecZ_*$^=AAotQbOBi3GW6B??4n67araSfUB~8H<9eS zBZI;1!Q^(BYeeU^E84$R?6T+vB-%>g3G4JGvaLSPat3v)3qUP^Z(piO10#GCwqr(a&{JBG>qV2il1`|^M@5^ksmXi z5_bR2Wh?1Q zpLJ~4+Gb=`EP{Klrw+9Iv!&a$>J)Q++N%FiMQmi+mAX1K%(ss}jD@ti3FW#XP`6gmAF4O2%B7_jF9?D4aZ8+q(?_ZA;W{>r{zE$yB(AfM7rt!9&4NJb5S12A$gl4V1qHcT>H*g>H#{>B z8cm%`3{%e~VwlJ}09M~(7a-1Fh?nu!oHq^{JyJ57d@qS}43E-PzLd>$;_xd-H;kw^ z&swypw%JHV-$hT%*v#PDhmv3=wxEVymy5OFikB_Q1P?83(fZMb^$w|cPwRyO@KEPu z@c2|t?e67PaR?bIiSdtM?e8@G4A&jl=0^^b#N<1+(Q!#;-wwwbVnU6d=v=N?83tfH z+0%!6o}QnVDlI5j;m{R2$Mz$ZGWMUc@&cI4o@}zXh<1wWMH-VZg*vux(iKQ?*f*A0 zYcB{tX$=piX<|wW>3cricR2K`7Zxy#HxdIbBe1xX5wt2IZI!uq`uk^W$}x+CI$DL_ z?q;n(N`quwCmE-;`c4;|1;x%${xAHwm4wm#H=(AHMjl&$A+VkhSjYQB2CE>vgHfsZ zPmU_zt9>y-?M+vMdath>8EhZ)&;?)fA9iA>%j}#>iDoZ5I`Zp$E4$~pKZK>*w_it| z68!BtG2|LgXOGCwHb&J}*3M-mTj9X}c}y_1!1siy2A0Bv@IZ)}arW806ybhuIqqUE zS=UvRFLPkiz?}Y&RarO={OgDx1`NDPOM(Oym%w$j^Rn`H%{ZvS%h(Y76Sa63(#{Xs z$vT!fK)q5B<=ypY9QDX+VISx5i?}pI>4{>%VL&5J%27_KWH<+Y%S>wOU+rq!fXQ4J za$}0mbs~Lp1O&Tw;)vZ?vnn&YX_(hEdGtT>74+2D11^)hUXrReCeN&D=JgtwM}!C7 zMJCSW5V1tR`o4WioC|KdT2HiNGx}FC={`?NCUG6tz7**wlNOYv4@ny&j$=yJ=K8J9nLAod{ut;YYrjNm&S*|FzmcDkTB_XiAjg5X+)8rwo>ph5R3E*q&b?V1D zKW1OM5P4q=qKoIGu7xLmCB;~`D)Y>kTJrVUx%a(hAbTIkf*w;imYd?I{@|lhvGa4K88&1N8GvSKLDQkT{v4N|(-0&<+iKU3Pbk%Q z@EjkM5ACI1HWH!{0aM`r^x9lx43>!Pv=$;bheBBd?$^x!rxnwDO~N>XB+f?(kls3< z$=h%+H!Op(jZ2~`wdB(9F9%`ERA_o;Y#PI6;j|!4#o5`RbF?`a;dtv8Ri=*v8|PCy z{=!2h9%`=fJV`kCRnuGM8+3NR@DF<`!tmaac-78XJx-L;b*GI{Lv0@O4hE)YJ{u{x zwWiB){;7JATT7aN1RhYqWK{L zXEP*8s#}0sIGwk1#-t8@;m#8LfU)`VHF__$JaH$-zuU+96(*GQKUBfCJnwi1m!TYJ zn@sQI^<4b<3o=`1%&jCOG46f$3EX_9V{+`PnZEov886D8BqoT<@ZvuMjILa0^ZJJ$aVL@mTSX<#Gx9^D z7d6r87Ysx1wyvoGqHL~$W3^G`{IR8*pNZYpC3pbb_Fp6_65J+*87t1o&T~&K=`J%1c8Zp$$&3=DKhgY706rfsB+ci5{Kd1qw3hGh+gtK;|@I5$hJ$ zH7@dq7ZgI$L@3V>z3G{4I}qVs%(^>q7=CH4+4PiBpWy}_+#^&QKJQ4t9=`FGcz&ZW zHV+NHuODFvIc&(us5oOqwSsJ(*l<$jd6TzPy*Ez(Jrm<&-k{yq$K_EB4|1CVz)@j7 zImsXn@e(=e5U6#yMHU=H{-bX>R%Z^D(N|=nn^Gl~aQ=Ss#JUjpvce?p%$R$b;4rLF zONKnHHPbB)H`4bYs{x6r7G$JBM#kxcJgu*wwf=QbIT;|RL*CQX#_K0amjJqT@~LxiiQ-t69jOCcOJ%- z2imQ2RZ?NcH3bM2wGH(=f-W@Ke`NCgDO>^%lw?3>vOhD+q|6$NM-o{O`mPxqus)yGWyl) z>q_IH_w9ufIfRC}q59tGdDDb{LyaaBQ590xC6W=EI2miE6@9M^N1`~8(w3BD9giEKew$d|BG zMTsXm3i}rd-#HDmi6F@HfAZ)UGnHn`Vo8X#5>cDNua^tIp7yQOA!$N=-6t@rR%V&c`JSI>s;gqhCCBiV71#&|;zTAf;&Whg2t8sx&OpvbReLx z`S#Q~a?*4l6HqwX+N|M~dQ8J_Py`BF5Ym*|Z-|*y^&m?X`BiT#v=OjD<2(Y@KhhQL zXn2o|CQQPjQ#H=-3^(bS^{ep>BK-_!Na0RR#MrY?SO98h_avIozl^vF6XWd@qoXl7 zFH{JdNK?^$#;Xf$^RNS@_CJIqNMerb7-1^D$^?y)+*uJjMJTO#p;i~K*i;8UA!=mh zZQnhCn+M6kgy|m(iO|y0+Vu0Z^=mNbiy#8@*DTk=`xE_TJ-oD)!Ffb1BqwJP6w!5M z(!-(*>3$JP;F}`{xa}EHeqqHm^9Zp38e>1H@Ho)FmD-P3l`^#2$P_k`SsMEgW~30H zs$lSGQYlI7Or*>2|F{$#pU5pLVSylMAmPbID#~w~PpdQ37w3Ye0RyO{c6ll%-M0Q{ zB%W+MUB7f>CzRvN&9$E9?4|0UR?bVhVt=WxewtnFkL3^@l?uZd=H?Z30JRGIg#QSj zEmh&&9?sc&VQUD>I2rQi3)Q*>CmO@^D-L+>P~)?If$z7$mj0K0GnwEN(W6ge2|r1PrL42BaWok(B{!f8Bop zw-5p5oWPEwG;o&03)5Ka&hXGSrL_Iu!@d zW5vWUaF@eCz{lQRHQlM!O0+SoEfpQ;8V94mP3_n97Z<%uyWQxc6x0sE#7mbX-4p47)744syt-D+U=wSq zV@i@E2dy~vtnGlRHxW=A9BUga{cePNIFn*R9lekhCHmRqC+XA!n4I$76X3r_cYUbd zL1J%OTW~DHo1MN@f2B_C>G}hnP^tBqPQ*baBUdU7r!vGJ(ok4JqxwRGp*C&l5{sjC zbG`P-=iUvRwq*Tk#shZ3X8dV_>*~9p>~gK$*TR3pLe{3 z{=7O(Jihkv;XIg@(Fw3SQ-fb!Pb7A|iap?$1&5_)sBmag;n3`c<5d&is!Hni39?ACg@%;$6B4NAwy<(Po6V(ae4P%ohed}V@!y`sKODnR=hjCP z%jSqR5HpD+Ui-Ip0u2f`Y43++BQ%B8P70E z5c`ZK$P+7do50I?!rpWvEcSZJXB{d%z_@v*@-WmvkLPa=7wE8^j*?7Cep>; z>M)Z#jogE};O^#g`^5OjEP@G5faX~0ruX{?UCDaDt!+Vmz+l@5j{E_6fWzvgEb9~G z7T#-sr0_QKiW|ge6E@xR%*BHX26<$$uUNWtX-Hp2-r`mu1HXcHq41U9>u|HaxLe$K zV)vgHT0AYyGw%$a7`%{xP;?%Rru__zZebw?V30V!d@v+igg7?aeLi-sp4qBH!#s#$ z?Zp4|bOCS4GJ&ybObj>Kp|R$%l_;+OgX-70k~+41$JfKAk7vs57$6eF> z&ReT#B1znjhyMpyy(#@6{D+3it28y%c+%T*v0W|G_(2*i@G30rU0S#_+VyLT#dU}a zcXoEZ+IcH#(-v-n`;Nc9CM$(}c*Hc@FwypU?~-!^w1#Ks0KWc5dLvMh8-^=f`}%00 zr@}2Ue@=S6*dLLG#t_Cdd;A)%B*i(PKPhP+WMZzgz3Rg5)<&ZJV?B7@C>$iuarcmZi;P z8q0!p-i{@85=g};femUBKq)&lX{MA^ztIdZrl}s@E*bv~uP#)YLGwC1+yss(1i7Km zzf|K53NaY2v4uqRRh#Osaw>7nF2-zZohS^OYBrm_k)sHyw2e8n{V*>qxWqHsLT^Uwu!uy!Bqn zu+sdP0-$;R*7);3EYIzcl_*FeUlW@a5ru*zq$0_ruhQprO6kOewX&w#TQ?YFWOY| z#Z}_Y+TdGqZl@BsFXlqi{aP9{-8pziD&7IXbSCA-(fBjeDol;&=S}1s!CpdYVJ|3!X#v3)I{MgK*v;Gjb;uJ_i^(7#SLI71PqJ36KO+1M$-oz>+b3{|zP>F4_T4diJo47v!5s=^aXNbf?~QQT7qq95`$>M{MJBCRy_ZE#0aAG>uzUuTCkE9b2-^7~CJs8{Jg8NZ)Y z0r5npgQ^=wb&&I1aMR{#@ zMpwT*idk5zk}4X8L(Rp8K;GTZld|&JRfNy3K-FF9BdzAYx$c5m@~Fa$CtQr%QIc9Q zc6AmXt(xtI3LG~bMqj4VvzaklDo?FPe5p#@(cE6cA&6CD^Y}m!hG+*{GLJ^02uUtv zWOlcv(p4>rjN$H&e}02TAYHaK8jYBxoJfkR6d9uymWh>jnB>L*iS+CV#vP;0FF=I% zT39^f@j=^ywKlU+=Oy_q2V2-bGJpY{?RAQ(}6vIzG&XMWo_+NMSvTkYQ3aB z?jPqDsYzM?MT^j}bCg`PcOnR|9hH>rqXVTVF5BryDl%06T{R?mv9Veya! zkx0`hZzV-w%COfKlEF}Y|GNcWS5#5=$$UlDW27dEI4JYKqVnEmJ9yvo%s;%Q?TR;q@+)KYia_TS0=kB_YY=Vzy*-@LXjH`d4l3Ygh{V z?%-Ed%3BjG@vE(~q()ZvrB+asLoQvnX?RgjwE@cWFi7CFu8yt%^y=L8-J0Ibp!de)u-0$e5oEZD^@I473;sRY_7KxhMy;x=r~tt^iZU<;JAr3kUxd3B zuW2m7Rdbf~c6=cCYv-k_CbkRsHs`K`{=87OM4%uHHD?L_Ltb$1x{vQl!F0TDW_n8R zfCG~X+Nyn}MS_h15!#T#MD{~;sUDpJ%Fd!>3`wCl!5x(9$u1L;G`I0O9OipQPoQMc zB2X8EPGBD>?>iN~3vm+V(a{+G>N?jXWSMyw9RC%GIu5kST)%divt@JYv~H@tXuhJl zax%#%$lmf~K<-l8@Zkop8$PmbXD|VwO$|8)GbLge)M9V-&FNy%Nl7Nh^_?WB{KtE< zV{%FLqgPP1ODMLpuvbftliELD<0$Gp1jj6=VXh^rSyA*8_e9iY za61-Tquz~;N^RMBZ>2bA_@^&p*p}JDnIcr(ZMh8JBbP%Zjy;;MD7KcIr&mcyt;fGV z(||EkJP{7e(5d8O6z>{JV%>EGm$LrE?Lh^xn67~(TssS-nZlIaL$U`PMX9pbli|pe zjY|8=Z3bA?6le@dV3J-RIY9N~G=}R%B5kk7tY${}cg#cijzougV!}C1n@(@gM@C+P z8-ZeBPxLl}#qOc4T%ag%oUs_xzFTQq>Ltz6Zv*fU@T>ES&v0QlhG5e*yqzD2QjBjB zt}r~o?(j^x31#$ktNU0vi2jXN=Z8*rTGo&&QWQ&nHa3lQd(HxW(VxgvB;DM$QN zbhY930h?EO5=BCdHR)GEnz#BG%iuL#8NT)DY2w7uG8O_ z2mdpAm)fsIMVrJen~uhUMdZ9k>-dC+p3EG#8OyIZJV%8Sk!l!P8_Rya@O8M}jFdj= zz+E||#e2ME*G;Jw#S>4k(|5}ZWty2@+b&D#CeKE3K;|P69aJx5Y^#gwV;1`>A{r@q zsUWw+f(6Z{EzBOziX}QsG0c~Ew!^}b5S^9>h_u}G5)?syb^>~9hSbQP!3`ood{dO` zL)8cLm5pMR`HyduyweC{_MF}6R4L(u5?VzL*%wPNTu1%hsAN&=TlO9f{GnxU&3uXt z{+H9WVg3i#GaL3OY5gV2RhBK`zo+`p<-J8W#?Y(-`>1r(vbhwWU8UeQh8l|N>|Ti| z7mN5%iXdhApDUISzl7A=QU!`hhQRou>U-nqJFZbP@biLO6$jAmTyp(Q{=vzw&CXDfua?hSP)=6toDSJT|QI) z({Qw1n+8gLBJL3pd#;kqlN!!8Dg5h<L*Y4;pdNl997iUP<$e=w>GHAov?c<(xV6d?5#~XPsUz+ z+yv9a4P!6*U03{eDE0L9-O(RIHh<0G z>rpCrsUUiI?g6yzHtMqmUt6o}ku*Dl_a?J6EcofVzeRc$fg2os$3uwHsy`n7<3a1! z>h+_8>8J9q>rv5|ARGC9-XO;Gpi04!l%|l7jIoiO+2#2s^e948n=JpjuEVUer0esd z)klV&^za&oUD4YQ(Gi*{QL#LUsdOWJPB@hJ&NB?U)SBwZK0H54n7(I?XR%^`Vf>b% zzISDr(cTmak| Date: Sat, 25 Nov 2023 12:32:56 +0200 Subject: [PATCH 11/84] Xcodegen tool installation if needed (#1727) Added script to install xcodegen, so `make` works even without `brew install xcodegen` --- .gitignore | 3 ++ Makefile | 20 +++++++++---- scripts/install/install_xcodegen.sh | 45 +++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 5 deletions(-) create mode 100755 scripts/install/install_xcodegen.sh diff --git a/.gitignore b/.gitignore index f39b6266c..8930e926b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# Tools +.tools + # Generated spm.xcodeproj frameworks.xcodeproj diff --git a/Makefile b/Makefile index 4cb8c6ce5..b957c10ad 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,23 @@ +.PHONY: installed_xcodegen + # generates xcodeproj for frameworks build configuration -xcodeproj_with_frameworks: - xcodegen -s project_frameworks.yml +xcodeproj_with_frameworks: installed_xcodegen + .tools/xcodegen/bin/xcodegen -s project_frameworks.yml + +# install xcodegen +installed_xcodegen: .tools/xcodegen/bin/xcodegen + +# install xcodegen if not installed +.tools/xcodegen/bin/xcodegen: scripts/install/install_xcodegen.sh + scripts/install/install_xcodegen.sh + touch $@ # generates xcodeproj for swift package manager build configuration -xcodeproj_with_spm: - xcodegen -s project_spm.yml +xcodeproj_with_spm: installed_xcodegen + .tools/xcodegen/bin/xcodegen -s project_spm.yml # builds station target with frameworks build configuration for iOS -build_with_frameworks: +build_with_frameworks: d=$$(date +%s)\ ; xcodebuild -project frameworks.xcodeproj -scheme station -configuration Release -sdk iphoneos17.0 build\ && echo "Build took $$(($$(date +%s)-d)) seconds" diff --git a/scripts/install/install_xcodegen.sh b/scripts/install/install_xcodegen.sh new file mode 100755 index 000000000..d3fc3cf3e --- /dev/null +++ b/scripts/install/install_xcodegen.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +# immediately exit if any command has a non-zero exit status +set -e + +OUTPUT_DIR=".tools/xcodegen" + +EXPECTED_XCODEGEN_HASH="2566750f11478c88c2c114a120d7d7fc" + +# check if xcodegen is already installed by hashing all files in the output directory +if [ -d "$OUTPUT_DIR" ] && [ "$(find "$OUTPUT_DIR" -type f -exec md5 {} \; | md5)" = $EXPECTED_XCODEGEN_HASH ]; then + echo "xcodegen is already installed" + exit 0 +fi + +# remove the output directory if it exists +if [ -d "$OUTPUT_DIR" ]; then + rm -rf "$OUTPUT_DIR" +fi + +# create the output directory +mkdir -p "$OUTPUT_DIR" + +# download the latest release of xcodegen +curl -L "https://github.com/yonaskolb/XcodeGen/releases/download/2.38.0/xcodegen.zip" -o ".tools/xcodegen.zip" + +# unzip the downloaded file +unzip ".tools/xcodegen.zip" -d ".tools" + +# remove the downloaded file +rm ".tools/xcodegen.zip" + +# echo the hash of downloaded xcodegen +echo "$(md5 .tools/xcodegen)" + +# if the hash of downloaded xcodegen is not the expected value, exit with an error +INSTALLED_XCODEGEN_HASH="$(find "$OUTPUT_DIR" -type f -exec md5 {} \; | md5)" +if [ "$INSTALLED_XCODEGEN_HASH" != "$EXPECTED_XCODEGEN_HASH" ]; then + echo "xcodegen failed to install" + echo "Expected hash: $EXPECTED_XCODEGEN_HASH" + echo "Actual hash: $INSTALLED_XCODEGEN_HASH" + exit 1 +else + echo "No xcodegen install needed" +fi \ No newline at end of file From 287ab8dabb390ae90fe98681a43136b8264d6fd4 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 25 Nov 2023 14:39:48 +0200 Subject: [PATCH 12/84] Xcodegen for Widget target (#1728) * Xcodegen for Widget target Implements xcodeproj gen for Widget * fixes for widget * attempt to fix widgets * add i18n to widget --- project_frameworks.yml | 14 ++++++- project_spm.yml | 38 ++++++++++++++++- ruuvi-widgets/Assembly/WidgetAssembly.swift | 7 ++++ ruuvi-widgets/Info.plist | 20 +++++++++ widget_frameworks.yml | 45 +++++++++++++++++++++ widget_spm.yml | 44 ++++++++++++++++++++ 6 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 widget_frameworks.yml create mode 100644 widget_spm.yml diff --git a/project_frameworks.yml b/project_frameworks.yml index d4c52eec8..497d63c94 100644 --- a/project_frameworks.yml +++ b/project_frameworks.yml @@ -181,6 +181,7 @@ include: - Modules/RuuviDiscover/target.yml - Modules/RuuviLocationPicker/target.yml - Modules/RuuviOnboard/target.yml +- widget_frameworks.yml targets: station: @@ -188,7 +189,11 @@ targets: platform: iOS sources: - path: station + - path: ruuvi_widgets.entitlements + - path: station_intents.entitlements + - path: pnservice.entitlements dependencies: + - target: "station.widgets" - package: BTKit - package: Charts - package: GRDB @@ -201,6 +206,7 @@ targets: product: FirebaseMessaging - package: Firebase product: FirebaseRemoteConfig + - package: KeychainAccess - package: Humidity - package: Future - package: Realm @@ -266,4 +272,10 @@ targets: MERGED_BINARY_TYPE: "manual" TARGETED_DEVICE_FAMILY: 1,2 SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true - CODE_SIGN_ENTITLEMENTS: station/station.entitlements \ No newline at end of file + CODE_SIGN_ENTITLEMENTS: station/station.entitlements + +schemes: + station: + build: + targets: + station: all \ No newline at end of file diff --git a/project_spm.yml b/project_spm.yml index f3a2cb3b3..220fad1a0 100644 --- a/project_spm.yml +++ b/project_spm.yml @@ -41,6 +41,24 @@ packages: GestureInstructions: url: https://github.com/rinat-enikeev/GestureInstructions from: 0.0.2 + KeychainAccess: + url: https://github.com/kishikawakatsumi/KeychainAccess + from: 4.2.1 + Realm: + url: https://github.com/realm/realm-cocoa + from: 10.8.0 + GRDB: + url: https://github.com/groue/GRDB.swift + from: 4.14.0 + Humidity: + url: https://github.com/rinat-enikeev/Humidity + from: 0.1.5 + Future: + url: https://github.com/kean/Future + from: 1.3.0 + NordicDFU: + url: https://github.com/NordicSemiconductor/IOS-Pods-DFU-Library + from: 4.10.3 RuuviAnalytics: path: Packages/RuuviAnalytics RuuviCloud: @@ -90,13 +108,20 @@ packages: RuuviOnboard: path: Modules/RuuviOnboard +include: +- widget_spm.yml + targets: station: type: application platform: iOS sources: - path: station + - path: ruuvi_widgets.entitlements + - path: station_intents.entitlements + - path: pnservice.entitlements dependencies: + - target: "station.widgets" - package: BTKit - package: Charts - package: LightRoute @@ -107,6 +132,11 @@ targets: product: FirebaseMessaging - package: Firebase product: FirebaseRemoteConfig + - package: KeychainAccess + - package: Realm + - package: Realm + product: RealmSwift + - package: NordicDFU - package: RuuviAnalytics - package: RuuviAnalytics product: RuuviAnalyticsImpl @@ -237,4 +267,10 @@ targets: base: TARGETED_DEVICE_FAMILY: 1,2 SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true - CODE_SIGN_ENTITLEMENTS: station/station.entitlements \ No newline at end of file + CODE_SIGN_ENTITLEMENTS: station/station.entitlements + +schemes: + station: + build: + targets: + station: all \ No newline at end of file diff --git a/ruuvi-widgets/Assembly/WidgetAssembly.swift b/ruuvi-widgets/Assembly/WidgetAssembly.swift index e12908f1f..036fec8d1 100644 --- a/ruuvi-widgets/Assembly/WidgetAssembly.swift +++ b/ruuvi-widgets/Assembly/WidgetAssembly.swift @@ -1,6 +1,13 @@ +import Foundation import Swinject import RuuviCloud import RuuviUser +#if canImport(RuuviCloudPure) +import RuuviCloudPure +#endif +#if canImport(RuuviUserCoordinator) +import RuuviUserCoordinator +#endif final class WidgetAssembly { static let shared = WidgetAssembly() diff --git a/ruuvi-widgets/Info.plist b/ruuvi-widgets/Info.plist index ae0a6e076..df44555c2 100644 --- a/ruuvi-widgets/Info.plist +++ b/ruuvi-widgets/Info.plist @@ -2,11 +2,31 @@ + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Ruuvi Station + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + $(CURRENT_PROJECT_VERSION) NSExtension NSExtensionPointIdentifier com.apple.widgetkit-extension + NSHumanReadableCopyright + Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. UIAppFonts Oswald-Bold.ttf diff --git a/widget_frameworks.yml b/widget_frameworks.yml new file mode 100644 index 000000000..11d0db815 --- /dev/null +++ b/widget_frameworks.yml @@ -0,0 +1,45 @@ +targets: + station.widgets: + type: app-extension + platform: iOS + info: + path: ruuvi-widgets/Info.plist + properties: + NSExtension: + NSExtensionPointIdentifier: com.apple.widgetkit-extension + UIAppFonts: [Oswald-Bold.ttf,Oswald-ExtraLight.ttf,Muli-Regular.ttf,Muli-Bold.ttf,Montserrat-Bold.ttf,Montserrat-Regular.ttf] + CFBundleDisplayName: Ruuvi Station + CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString: $(MARKETING_VERSION) + CFBundleVersion: $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright: Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. + settings: + base: + CODE_SIGN_ENTITLEMENTS: ruuvi_widgets.entitlements + sources: + - path: ruuvi-widgets + - path: station/Resources/Strings/ + dependencies: + - package: Swinject + - package: BTKit + - package: Future + - package: GRDB + - package: Humidity + - package: Realm + - package: KeychainAccess + - package: Realm + product: RealmSwift + - target: RuuviUser + embed: true + - target: RuuviCloud + embed: true + - target: RuuviOntology + embed: true + - target: RuuviPool + embed: true + - target: RuuviLocal + embed: true + - target: RuuviPersistence + embed: true + - target: RuuviContext + embed: true \ No newline at end of file diff --git a/widget_spm.yml b/widget_spm.yml new file mode 100644 index 000000000..da11337dc --- /dev/null +++ b/widget_spm.yml @@ -0,0 +1,44 @@ +targets: + station.widgets: + type: app-extension + platform: iOS + info: + path: ruuvi-widgets/Info.plist + properties: + NSExtension: + NSExtensionPointIdentifier: com.apple.widgetkit-extension + UIAppFonts: [Oswald-Bold.ttf,Oswald-ExtraLight.ttf,Muli-Regular.ttf,Muli-Bold.ttf,Montserrat-Bold.ttf,Montserrat-Regular.ttf] + CFBundleDisplayName: Ruuvi Station + CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString: $(MARKETING_VERSION) + CFBundleVersion: $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright: Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. + settings: + base: + CODE_SIGN_ENTITLEMENTS: ruuvi_widgets.entitlements + sources: + - path: ruuvi-widgets + - path: station/Resources/Strings/ + dependencies: + - package: Swinject + - package: BTKit + - package: Future + - package: GRDB + - package: Humidity + - package: Realm + - package: KeychainAccess + - package: Realm + product: RealmSwift + - package: RuuviUser + - package: RuuviUser + product: RuuviUserCoordinator + - package: RuuviCloud + - package: RuuviCloud + product: RuuviCloudPure + - package: RuuviCloud + product: RuuviCloudApi + - package: RuuviOntology + - package: RuuviPool + - package: RuuviLocal + - package: RuuviPersistence + - package: RuuviContext \ No newline at end of file From 4840a0766af64771e5a96488b8985280388f1f9c Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 25 Nov 2023 19:27:39 +0200 Subject: [PATCH 13/84] Intents and PNService targets from xcodegen (#1729) * Add PNService to xcodegen * Add intents to xcodegen * Load Keystore PostBuild script (#1730) * Load Keystore PostBuild script Only on Archive for Release configuration loads secrects * add build script --- .gitignore | 1 - intents/Info.plist | 20 +++++++++++++ intents_frameworks.yml | 51 ++++++++++++++++++++++++++++++++++ intents_spm.yml | 50 +++++++++++++++++++++++++++++++++ pnservice.yml | 22 +++++++++++++++ pnservice/Info.plist | 20 +++++++++++++ project_frameworks.yml | 13 ++++++++- project_spm.yml | 13 ++++++++- scripts/build/load_keystore.sh | 16 +++++++++++ 9 files changed, 203 insertions(+), 3 deletions(-) create mode 100644 intents_frameworks.yml create mode 100644 intents_spm.yml create mode 100644 pnservice.yml create mode 100644 scripts/build/load_keystore.sh diff --git a/.gitignore b/.gitignore index 8930e926b..c27536ba3 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,6 @@ station/Classes/Networking/Assembly/Networking.plist # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore ## Build generated -build/ DerivedData/ ## Various settings diff --git a/intents/Info.plist b/intents/Info.plist index 792273965..cde80a610 100644 --- a/intents/Info.plist +++ b/intents/Info.plist @@ -2,6 +2,24 @@ + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Ruuvi Station + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + $(CURRENT_PROJECT_VERSION) NSExtension NSExtensionAttributes @@ -20,5 +38,7 @@ NSExtensionPrincipalClass $(PRODUCT_MODULE_NAME).IntentHandler + NSHumanReadableCopyright + Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. diff --git a/intents_frameworks.yml b/intents_frameworks.yml new file mode 100644 index 000000000..689e042be --- /dev/null +++ b/intents_frameworks.yml @@ -0,0 +1,51 @@ +targets: + station.intents: + type: app-extension + platform: iOS + info: + path: intents/Info.plist + properties: + NSExtension: + NSExtensionAttributes: + IntentsRestrictedWhileLocked: [] + IntentsRestrictedWhileProtectedDataUnavailable: [] + IntentsSupported: [RuuviTagSelectionIntent] + NSExtensionPointIdentifier: com.apple.intents-service + NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).IntentHandler + CFBundleDisplayName: Ruuvi Station + CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString: $(MARKETING_VERSION) + CFBundleVersion: $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright: Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. + settings: + base: + CODE_SIGN_ENTITLEMENTS: station_intents.entitlements + sources: + - path: intents + - path: ruuvi-widgets + excludes: + - Info.plist + dependencies: + - package: Swinject + - package: BTKit + - package: Future + - package: GRDB + - package: Humidity + - package: Realm + - package: KeychainAccess + - package: Realm + product: RealmSwift + - target: RuuviUser + embed: true + - target: RuuviCloud + embed: true + - target: RuuviOntology + embed: true + - target: RuuviPool + embed: true + - target: RuuviLocal + embed: true + - target: RuuviPersistence + embed: true + - target: RuuviContext + embed: true \ No newline at end of file diff --git a/intents_spm.yml b/intents_spm.yml new file mode 100644 index 000000000..e7db6f0cf --- /dev/null +++ b/intents_spm.yml @@ -0,0 +1,50 @@ +targets: + station.intents: + type: app-extension + platform: iOS + info: + path: intents/Info.plist + properties: + NSExtension: + NSExtensionAttributes: + IntentsRestrictedWhileLocked: [] + IntentsRestrictedWhileProtectedDataUnavailable: [] + IntentsSupported: [RuuviTagSelectionIntent] + NSExtensionPointIdentifier: com.apple.intents-service + NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).IntentHandler + CFBundleDisplayName: Ruuvi Station + CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString: $(MARKETING_VERSION) + CFBundleVersion: $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright: Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. + settings: + base: + CODE_SIGN_ENTITLEMENTS: station_intents.entitlements + sources: + - path: intents + - path: ruuvi-widgets + excludes: + - Info.plist + dependencies: + - package: Swinject + - package: BTKit + - package: Future + - package: GRDB + - package: Humidity + - package: Realm + - package: KeychainAccess + - package: Realm + product: RealmSwift + - package: RuuviUser + - package: RuuviUser + product: RuuviUserCoordinator + - package: RuuviCloud + - package: RuuviCloud + product: RuuviCloudPure + - package: RuuviCloud + product: RuuviCloudApi + - package: RuuviOntology + - package: RuuviPool + - package: RuuviLocal + - package: RuuviPersistence + - package: RuuviContext \ No newline at end of file diff --git a/pnservice.yml b/pnservice.yml new file mode 100644 index 000000000..acfbb15df --- /dev/null +++ b/pnservice.yml @@ -0,0 +1,22 @@ +targets: + station.pnservice: + type: app-extension + platform: iOS + info: + path: pnservice/Info.plist + properties: + NSExtension: + NSExtensionPointIdentifier: com.apple.usernotifications.service + NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).NotificationService + CFBundleDisplayName: Ruuvi Station + CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString: $(MARKETING_VERSION) + CFBundleVersion: $(CURRENT_PROJECT_VERSION) + NSHumanReadableCopyright: Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. + settings: + base: + CODE_SIGN_ENTITLEMENTS: pnservice.entitlements + sources: + - path: pnservice + - path: station/Resources/Strings/ + - path: station/Resources/Sounds/ \ No newline at end of file diff --git a/pnservice/Info.plist b/pnservice/Info.plist index 57421ebf9..1383832e9 100644 --- a/pnservice/Info.plist +++ b/pnservice/Info.plist @@ -2,6 +2,24 @@ + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Ruuvi Station + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + $(CURRENT_PROJECT_VERSION) NSExtension NSExtensionPointIdentifier @@ -9,5 +27,7 @@ NSExtensionPrincipalClass $(PRODUCT_MODULE_NAME).NotificationService + NSHumanReadableCopyright + Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. diff --git a/project_frameworks.yml b/project_frameworks.yml index 497d63c94..ef1cdc8e8 100644 --- a/project_frameworks.yml +++ b/project_frameworks.yml @@ -182,6 +182,8 @@ include: - Modules/RuuviLocationPicker/target.yml - Modules/RuuviOnboard/target.yml - widget_frameworks.yml +- pnservice.yml +- intents_frameworks.yml targets: station: @@ -194,6 +196,8 @@ targets: - path: pnservice.entitlements dependencies: - target: "station.widgets" + - target: "station.intents" + - target: "station.pnservice" - package: BTKit - package: Charts - package: GRDB @@ -273,7 +277,14 @@ targets: TARGETED_DEVICE_FAMILY: 1,2 SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true CODE_SIGN_ENTITLEMENTS: station/station.entitlements - + postBuildScripts: + - path: scripts/build/load_keystore.sh + name: Load Keystore + inputFiles: + - $(SRCROOT)/station/Classes/Networking/Assembly/Networking.plist + - $(SRCROOT)/station/Resources/Plists/GoogleService-Info.plist + runOnlyWhenInstalling: true + basedOnDependencyAnalysis: false schemes: station: build: diff --git a/project_spm.yml b/project_spm.yml index 220fad1a0..4cd698505 100644 --- a/project_spm.yml +++ b/project_spm.yml @@ -110,6 +110,8 @@ packages: include: - widget_spm.yml +- pnservice.yml +- intents_spm.yml targets: station: @@ -122,6 +124,8 @@ targets: - path: pnservice.entitlements dependencies: - target: "station.widgets" + - target: "station.intents" + - target: "station.pnservice" - package: BTKit - package: Charts - package: LightRoute @@ -268,7 +272,14 @@ targets: TARGETED_DEVICE_FAMILY: 1,2 SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true CODE_SIGN_ENTITLEMENTS: station/station.entitlements - + postBuildScripts: + - path: scripts/build/load_keystore.sh + name: Load Keystore + inputFiles: + - $(SRCROOT)/station/Classes/Networking/Assembly/Networking.plist + - $(SRCROOT)/station/Resources/Plists/GoogleService-Info.plist + runOnlyWhenInstalling: true + basedOnDependencyAnalysis: false schemes: station: build: diff --git a/scripts/build/load_keystore.sh b/scripts/build/load_keystore.sh new file mode 100644 index 000000000..105299f57 --- /dev/null +++ b/scripts/build/load_keystore.sh @@ -0,0 +1,16 @@ +if [ "${CONFIGURATION}" = "Release" ]; then + BUILD_APP_DIR=${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME} + git clone git@github.com:ruuvi/com.ruuvi.station.ios.keystore.git + if [ $? -eq 0 ]; then + /bin/cp -rf com.ruuvi.station.ios.keystore/GoogleService-Info.plist "$BUILD_APP_DIR/GoogleService-Info.plist" + /bin/cp -rf com.ruuvi.station.ios.keystore/Networking.plist "$BUILD_APP_DIR/Networking.plist" + rm -rf com.ruuvi.station.ios.keystore + else + if grep -q "{ set your API key here }" $SCRIPT_INPUT_FILE_0; then + echo "warning: Missing OpenWeatherMap API key. In order to make Virtual Sensors work please obtain API key on https://openweathermap.org and put into station/Classes/Networking/Assembly/Networking.plist" + fi + if grep -q "1:925543306936:ios:84f5fda343c52e7671c64d" $SCRIPT_INPUT_FILE_1; then + echo "warning: Demo GoogleServices credentials. If you want to use your own GoogleServices credentials, please replace the station/Resources/Plists/GoogleService-Info.plist file" + fi + fi +fi \ No newline at end of file From 8a1c973f7cc3d44b255604bb94760146f321a36d Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 25 Nov 2023 20:46:32 +0200 Subject: [PATCH 14/84] Implement localization swiftgen step (#1731) * Implement localization swiftgen step For generated project * isntall swiftgen also on spm * phony for swiftgen --- Makefile | 13 ++++++--- pnservice.yml | 1 + project_frameworks.yml | 12 +++++++++ project_spm.yml | 12 +++++++++ scripts/build/generate_l10n.sh | 10 +++++++ scripts/install/install_swiftgen.sh | 42 +++++++++++++++++++++++++++++ scripts/install/install_xcodegen.sh | 3 --- widget_frameworks.yml | 1 + 8 files changed, 88 insertions(+), 6 deletions(-) create mode 100755 scripts/build/generate_l10n.sh create mode 100755 scripts/install/install_swiftgen.sh diff --git a/Makefile b/Makefile index b957c10ad..176718ac7 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,16 @@ -.PHONY: installed_xcodegen +.PHONY: installed_xcodegen installed_swiftgen # generates xcodeproj for frameworks build configuration -xcodeproj_with_frameworks: installed_xcodegen +xcodeproj_with_frameworks: installed_xcodegen installed_swiftgen .tools/xcodegen/bin/xcodegen -s project_frameworks.yml +# install swiftgen +installed_swiftgen: .tools/swiftgen/bin/swiftgen + +.tools/swiftgen/bin/swiftgen: scripts/install/install_swiftgen.sh + scripts/install/install_swiftgen.sh + touch $@ + # install xcodegen installed_xcodegen: .tools/xcodegen/bin/xcodegen @@ -13,7 +20,7 @@ installed_xcodegen: .tools/xcodegen/bin/xcodegen touch $@ # generates xcodeproj for swift package manager build configuration -xcodeproj_with_spm: installed_xcodegen +xcodeproj_with_spm: installed_xcodegen installed_swiftgen .tools/xcodegen/bin/xcodegen -s project_spm.yml # builds station target with frameworks build configuration for iOS diff --git a/pnservice.yml b/pnservice.yml index acfbb15df..cfde6c951 100644 --- a/pnservice.yml +++ b/pnservice.yml @@ -18,5 +18,6 @@ targets: CODE_SIGN_ENTITLEMENTS: pnservice.entitlements sources: - path: pnservice + resources: - path: station/Resources/Strings/ - path: station/Resources/Sounds/ \ No newline at end of file diff --git a/project_frameworks.yml b/project_frameworks.yml index ef1cdc8e8..4a1bfa55d 100644 --- a/project_frameworks.yml +++ b/project_frameworks.yml @@ -277,6 +277,18 @@ targets: TARGETED_DEVICE_FAMILY: 1,2 SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true CODE_SIGN_ENTITLEMENTS: station/station.entitlements + preBuildScripts: + - path: scripts/build/generate_l10n.sh + name: Generate L10N + inputFiles: + - $(SRCROOT)/station.localization/station.localization.json + outputFiles: + - $(SRCROOT)/station/Resources/Strings/en.lproj/Localizable.strings + - $(SRCROOT)/station/Resources/Strings/sv.lproj/Localizable.strings + - $(SRCROOT)/station/Resources/Strings/ru.lproj/Localizable.strings + - $(SRCROOT)/station/Resources/Strings/fi.lproj/Localizable.strings + - $(SRCROOT)/station/Resources/Strings/fr.lproj/Localizable.strings + - $(SRCROOT)/station/Resources/Strings/de.lproj/Localizable.strings postBuildScripts: - path: scripts/build/load_keystore.sh name: Load Keystore diff --git a/project_spm.yml b/project_spm.yml index 4cd698505..3f97153c6 100644 --- a/project_spm.yml +++ b/project_spm.yml @@ -272,6 +272,18 @@ targets: TARGETED_DEVICE_FAMILY: 1,2 SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true CODE_SIGN_ENTITLEMENTS: station/station.entitlements + preBuildScripts: + - path: scripts/build/generate_l10n.sh + name: Generate L10N + inputFiles: + - $(SRCROOT)/station.localization/station.localization.json + outputFiles: + - $(SRCROOT)/station/Resources/Strings/en.lproj/Localizable.strings + - $(SRCROOT)/station/Resources/Strings/sv.lproj/Localizable.strings + - $(SRCROOT)/station/Resources/Strings/ru.lproj/Localizable.strings + - $(SRCROOT)/station/Resources/Strings/fi.lproj/Localizable.strings + - $(SRCROOT)/station/Resources/Strings/fr.lproj/Localizable.strings + - $(SRCROOT)/station/Resources/Strings/de.lproj/Localizable.strings postBuildScripts: - path: scripts/build/load_keystore.sh name: Load Keystore diff --git a/scripts/build/generate_l10n.sh b/scripts/build/generate_l10n.sh new file mode 100755 index 000000000..55a53e187 --- /dev/null +++ b/scripts/build/generate_l10n.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# if ./tools/swiftgen/bin/swiftgen not exists, install it +if [ ! -f "$PROJECT_DIR"/.tools/swiftgen/bin/swiftgen ]; then + echo "Installing swiftgen..." + "$PROJECT_DIR"/scripts/install/install_swiftgen.sh +fi + +# execute swiftgen +"$PROJECT_DIR"/.tools/swiftgen/bin/swiftgen \ No newline at end of file diff --git a/scripts/install/install_swiftgen.sh b/scripts/install/install_swiftgen.sh new file mode 100755 index 000000000..2a332f061 --- /dev/null +++ b/scripts/install/install_swiftgen.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +set -e + +OUTPUT_DIR=".tools/swiftgen" + + +EXPECTED_SWIFTGEN_HASH="6cd7a4c789050045970291a23d5232fe" + +# check if swiftgen is already installed by hashing all files in the output directory +if [ -d "$OUTPUT_DIR" ] && [ "$(find "$OUTPUT_DIR" -type f -exec md5 {} \; | md5)" = $EXPECTED_SWIFTGEN_HASH ]; then + echo "swiftgen is already installed" + exit 0 +fi + +# remove the output directory if it exists +if [ -d "$OUTPUT_DIR" ]; then + rm -rf "$OUTPUT_DIR" +fi + +# create the output directory +mkdir -p "$OUTPUT_DIR" + +# download the latest release of swiftgen +curl -L "https://github.com/SwiftGen/SwiftGen/releases/download/6.6.2/swiftgen-6.6.2.zip" -o ".tools/swiftgen.zip" + +# unzip the downloaded file +unzip ".tools/swiftgen.zip" -d ".tools/swiftgen" + +# remove the downloaded file +rm ".tools/swiftgen.zip" + +# if the hash of downloaded swiftgen is not the expected value, exit with an error +INSTALLED_SWIFTGEN_HASH="$(find "$OUTPUT_DIR" -type f -exec md5 {} \; | md5)" +if [ "$INSTALLED_SWIFTGEN_HASH" != "$EXPECTED_SWIFTGEN_HASH" ]; then + echo "swiftgen failed to install" + echo "Expected hash: $EXPECTED_SWIFTGEN_HASH" + echo "Actual hash: $INSTALLED_SWIFTGEN_HASH" + exit 1 +else + echo "No swiftgen install needed" +fi \ No newline at end of file diff --git a/scripts/install/install_xcodegen.sh b/scripts/install/install_xcodegen.sh index d3fc3cf3e..d756d604b 100755 --- a/scripts/install/install_xcodegen.sh +++ b/scripts/install/install_xcodegen.sh @@ -30,9 +30,6 @@ unzip ".tools/xcodegen.zip" -d ".tools" # remove the downloaded file rm ".tools/xcodegen.zip" -# echo the hash of downloaded xcodegen -echo "$(md5 .tools/xcodegen)" - # if the hash of downloaded xcodegen is not the expected value, exit with an error INSTALLED_XCODEGEN_HASH="$(find "$OUTPUT_DIR" -type f -exec md5 {} \; | md5)" if [ "$INSTALLED_XCODEGEN_HASH" != "$EXPECTED_XCODEGEN_HASH" ]; then diff --git a/widget_frameworks.yml b/widget_frameworks.yml index 11d0db815..7c054bba8 100644 --- a/widget_frameworks.yml +++ b/widget_frameworks.yml @@ -18,6 +18,7 @@ targets: CODE_SIGN_ENTITLEMENTS: ruuvi_widgets.entitlements sources: - path: ruuvi-widgets + resources: - path: station/Resources/Strings/ dependencies: - package: Swinject From 985b81a1f343353d1c5ae83de346bf7c0865e9f2 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 25 Nov 2023 20:52:56 +0200 Subject: [PATCH 15/84] Fix SPM build (#1732) Cycle fixed. --- widget_spm.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/widget_spm.yml b/widget_spm.yml index da11337dc..e3d205171 100644 --- a/widget_spm.yml +++ b/widget_spm.yml @@ -18,6 +18,7 @@ targets: CODE_SIGN_ENTITLEMENTS: ruuvi_widgets.entitlements sources: - path: ruuvi-widgets + resources: - path: station/Resources/Strings/ dependencies: - package: Swinject From 9241d744831371a09c3285382318d51737a0f6ff Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 25 Nov 2023 21:06:46 +0200 Subject: [PATCH 16/84] Update README with xcodegen instructions (#1733) * Update README with xcodegen instructions Updates README * fixes * add cd --- README.md | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 8aeb50755..739d9aad4 100644 --- a/README.md +++ b/README.md @@ -47,15 +47,30 @@ Ruuvi Station is an open-source iOS app [available](https://itunes.apple.com/us/ ## How to use -1. Clone the repo with the recursive parameter ```git clone --recursive https://github.com/ruuvi/com.ruuvi.station.ios.git``` -2. ```cd``` into repo and run: ```pod install --repo-update``` -3. Open ```station.xcworkspace``` -4. Configure Signing -Optional: -5. Obtain [OpenWeatherMap](https://openweathermap.org) API Key and put it into ```/station/Classes/Networking/Assembly/Networking.plist``` -6. Setup your [Firebase](https://firebase.google.com) project and replace ```station/Resources/Plists/GoogleService-Info.plist``` - -Build and Run on your device! +1. Clone the repo with the recursive parameter +```zsh +git clone --recursive https://github.com/ruuvi/com.ruuvi.station.ios.git +cd com.ruuvi.station.ios +``` + +2. Make and open the `frameworks.xcodeproj` +```zsh +make +xed frameworks.xcodeproj +``` + +3. Configure Signing + +4. Build and Run on your device! + +
+Optionally + +1. Obtain [OpenWeatherMap](https://openweathermap.org) API Key and put it into ```/station/Classes/Networking/Assembly/Networking.plist``` + +2. Setup your [Firebase](https://firebase.google.com) project and replace ```station/Resources/Plists/GoogleService-Info.plist``` + +
## Get in touch From 55c881aa11c4887353a9ad54e270efdc0e483939 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sun, 26 Nov 2023 18:52:25 +0200 Subject: [PATCH 17/84] FLEX support for spm/framework project (#1735) Implements support for FLEX in DEBUG for spm/framworks --- project_frameworks.yml | 7 +++++++ project_spm.yml | 7 +++++++ station.xcodeproj/project.pbxproj | 20 +++++++++---------- station/Classes/Application/AppDelegate.swift | 6 +++--- .../Assembly/PresentationAssembly.swift | 4 ++-- ...ift => FeatureTogglesViewController.swift} | 10 +++++----- .../Module/Router/SettingsRouter.swift | 2 +- station/Extensions/UIWindow+Shake.swift | 2 +- 8 files changed, 36 insertions(+), 22 deletions(-) rename station/Classes/Presentation/FLEX/{FLEXFeatureTogglesViewController.swift => FeatureTogglesViewController.swift} (95%) diff --git a/project_frameworks.yml b/project_frameworks.yml index 4a1bfa55d..8105e90c7 100644 --- a/project_frameworks.yml +++ b/project_frameworks.yml @@ -154,6 +154,9 @@ packages: GRDB: url: https://github.com/groue/GRDB.swift from: 4.14.0 + FLEX: + url: https://github.com/FLEXTool/FLEX.git + from: 5.22.10 include: - Packages/RuuviAnalytics/target.yml @@ -216,6 +219,7 @@ targets: - package: Realm - package: Realm product: RealmSwift + - package: FLEX - target: RuuviAnalytics - target: RuuviCloud - target: RuuviContext @@ -277,6 +281,9 @@ targets: TARGETED_DEVICE_FAMILY: 1,2 SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true CODE_SIGN_ENTITLEMENTS: station/station.entitlements + configs: + Release: + EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" preBuildScripts: - path: scripts/build/generate_l10n.sh name: Generate L10N diff --git a/project_spm.yml b/project_spm.yml index 3f97153c6..98c942b9a 100644 --- a/project_spm.yml +++ b/project_spm.yml @@ -59,6 +59,9 @@ packages: NordicDFU: url: https://github.com/NordicSemiconductor/IOS-Pods-DFU-Library from: 4.10.3 + FLEX: + url: https://github.com/FLEXTool/FLEX.git + from: 5.22.10 RuuviAnalytics: path: Packages/RuuviAnalytics RuuviCloud: @@ -141,6 +144,7 @@ targets: - package: Realm product: RealmSwift - package: NordicDFU + - package: FLEX - package: RuuviAnalytics - package: RuuviAnalytics product: RuuviAnalyticsImpl @@ -272,6 +276,9 @@ targets: TARGETED_DEVICE_FAMILY: 1,2 SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true CODE_SIGN_ENTITLEMENTS: station/station.entitlements + configs: + Release: + EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" preBuildScripts: - path: scripts/build/generate_l10n.sh name: Generate L10N diff --git a/station.xcodeproj/project.pbxproj b/station.xcodeproj/project.pbxproj index cf07bfbff..675ecda24 100644 --- a/station.xcodeproj/project.pbxproj +++ b/station.xcodeproj/project.pbxproj @@ -352,6 +352,8 @@ 0EC50F5422CCBBE800172EEB /* NSObject+Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5322CCBBE800172EEB /* NSObject+Observable.swift */; }; 0EC50F5622CCE46D00172EEB /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5522CCE46D00172EEB /* Optional.swift */; }; 0EC50F5922CF621000172EEB /* PhotoPickerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5822CF621000172EEB /* PhotoPickerPresenter.swift */; }; + 0ECA196A2B138C3A00BEE4DB /* FeatureTogglesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECA19692B138C3A00BEE4DB /* FeatureTogglesViewController.swift */; }; + 0ECA196B2B138C3A00BEE4DB /* FeatureTogglesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECA19692B138C3A00BEE4DB /* FeatureTogglesViewController.swift */; }; 0ECDF1B52313D65500A09ACA /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0ECDF1B42313D65500A09ACA /* GoogleService-Info.plist */; }; 0EE36E3F26957E010021B746 /* DFUInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E3E26957E000021B746 /* DFUInteractorInput.swift */; }; 0EE36E4026957E010021B746 /* DFUInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E3E26957E000021B746 /* DFUInteractorInput.swift */; }; @@ -361,8 +363,6 @@ 0EE36EB1269DC71B0021B746 /* Algorithms in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE36EB0269DC71B0021B746 /* Algorithms */; }; 0EE36EB4269DC7D90021B746 /* Charts in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE36EB3269DC7D90021B746 /* Charts */; }; 0EE36EB6269DC7E40021B746 /* Charts in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE36EB5269DC7E40021B746 /* Charts */; }; - 0EE98A7926493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE98A7826493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift */; }; - 0EE98A7A26493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE98A7826493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift */; }; 0EEB20C622B7915C0015F9E0 /* CardsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20C522B7915C0015F9E0 /* CardsViewModel.swift */; }; 0EEB20C722B7A7200015F9E0 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20C922B7A7200015F9E0 /* Localizable.strings */; }; 0EEB20CB22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20CA22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift */; }; @@ -1363,13 +1363,13 @@ 0EC50F5322CCBBE800172EEB /* NSObject+Observable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSObject+Observable.swift"; sourceTree = ""; }; 0EC50F5522CCE46D00172EEB /* Optional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Optional.swift; sourceTree = ""; }; 0EC50F5822CF621000172EEB /* PhotoPickerPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPickerPresenter.swift; sourceTree = ""; }; + 0ECA19692B138C3A00BEE4DB /* FeatureTogglesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureTogglesViewController.swift; sourceTree = ""; }; 0ECDF1B42313D65500A09ACA /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 0ECDF1B62313D7DA00A09ACA /* station.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = station.entitlements; sourceTree = ""; }; 0EE36E3E26957E000021B746 /* DFUInteractorInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DFUInteractorInput.swift; sourceTree = ""; }; 0EE36E4126957E200021B746 /* LatestRelease.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatestRelease.swift; sourceTree = ""; }; 0EE49BB123B8C40D003012C2 /* MacInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = MacInfo.plist; sourceTree = ""; }; 0EE49BB223B8C40D003012C2 /* DevInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = DevInfo.plist; sourceTree = ""; }; - 0EE98A7826493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FLEXFeatureTogglesViewController.swift; sourceTree = ""; }; 0EEB20C522B7915C0015F9E0 /* CardsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsViewModel.swift; sourceTree = ""; }; 0EEB20C822B7A7200015F9E0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 0EEB20CA22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableEmbededViewController.swift; sourceTree = ""; }; @@ -2860,7 +2860,7 @@ 0EE98A772649386000AAB3ED /* FLEX */ = { isa = PBXGroup; children = ( - 0EE98A7826493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift */, + 0ECA19692B138C3A00BEE4DB /* FeatureTogglesViewController.swift */, ); path = FLEX; sourceTree = ""; @@ -4895,7 +4895,7 @@ mainGroup = 64333D1C20B0C45900CDF4B6; packageReferences = ( 0EE36EAD269DC70E0021B746 /* XCRemoteSwiftPackageReference "swift-algorithms" */, - 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts.git" */, + 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts" */, ); productRefGroup = 64333D2620B0C45900CDF4B6 /* Products */; projectDirPath = ""; @@ -5396,7 +5396,6 @@ 0E8BD2DA238566AB008B31EF /* MenuModuleOutput.swift in Sources */, E1198A3629BA76CB002245CF /* ASSelectionViewInput.swift in Sources */, 0E3CA70D267365B1000D9B25 /* Debouncer.swift in Sources */, - 0EE98A7A26493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift in Sources */, E116707A29634363002DF7BF /* BackgroundSelectionViewOutput.swift in Sources */, 66BC449C2657AED400A03253 /* OffsetCorrectionConfigurator.swift in Sources */, E10E18BB297D67FC002C78C3 /* RuuviCloudViewOutput.swift in Sources */, @@ -5756,6 +5755,7 @@ 0E197C7A23C5CCBC0074015B /* InfoProviderImpl.swift in Sources */, 0E8BD3CA238566AB008B31EF /* CardsRouter.swift in Sources */, E10E18BE297D68EB002C78C3 /* RuuviCloudModuleInput.swift in Sources */, + 0ECA196B2B138C3A00BEE4DB /* FeatureTogglesViewController.swift in Sources */, E10E18C2297DD0CA002C78C3 /* RuuviCloudTableViewCell.swift in Sources */, E1198A2D29BA769A002245CF /* ASSelectionTableViewController.swift in Sources */, A9646488247BAE6B0001D55D /* ChartSettingsRouterInput.swift in Sources */, @@ -5874,6 +5874,7 @@ A92A66BD2450C640002918E7 /* UITableViewCell+ReusableView.swift in Sources */, A93CDCDE25659BF600018C6C /* AlertPresenterImpl.swift in Sources */, E1B57FEE29859CC900B441FB /* DevicesModuleInput.swift in Sources */, + 0ECA196A2B138C3A00BEE4DB /* FeatureTogglesViewController.swift in Sources */, 0E1C1E0F22B4049F0032F6CA /* MenuTablePresentationController.swift in Sources */, 340BE39B27B54FEC006D6C34 /* String+Email.swift in Sources */, E116707929634363002DF7BF /* BackgroundSelectionViewOutput.swift in Sources */, @@ -6185,7 +6186,6 @@ 0EE36E4226957E200021B746 /* LatestRelease.swift in Sources */, 0E02ABCB2379483A00ED4629 /* Double+Temperature.swift in Sources */, 0EB48D8B2619D5AC008E0D2D /* FeatureToggleService.swift in Sources */, - 0EE98A7926493C5000AAB3ED /* FLEXFeatureTogglesViewController.swift in Sources */, E1198A3229BA76C1002245CF /* ASSelectionViewOutput.swift in Sources */, E19691882A06E03300DC360E /* PushAlertSoundSelectionViewOutput.swift in Sources */, 0E5C302822D0B1C600B52E39 /* AppStateServiceImpl.swift in Sources */, @@ -7130,7 +7130,7 @@ minimumVersion = 1.0.0; }; }; - 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts.git" */ = { + 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/danielgindi/Charts.git"; requirement = { @@ -7153,12 +7153,12 @@ }; 0EE36EB3269DC7D90021B746 /* Charts */ = { isa = XCSwiftPackageProductDependency; - package = 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts.git" */; + package = 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts" */; productName = Charts; }; 0EE36EB5269DC7E40021B746 /* Charts */ = { isa = XCSwiftPackageProductDependency; - package = 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts.git" */; + package = 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts" */; productName = Charts; }; /* End XCSwiftPackageProductDependency section */ diff --git a/station/Classes/Application/AppDelegate.swift b/station/Classes/Application/AppDelegate.swift index c5254467c..4e8d6c67a 100644 --- a/station/Classes/Application/AppDelegate.swift +++ b/station/Classes/Application/AppDelegate.swift @@ -1,7 +1,7 @@ import UIKit import FirebaseCore import FirebaseMessaging -#if canImport(FLEX) +#if DEBUG && canImport(FLEX) import FLEX #endif import UserNotifications @@ -62,10 +62,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { cloudNotificationService = r.resolve(RuuviServiceCloudNotification.self) - #if canImport(FLEX) + #if DEBUG && canImport(FLEX) FLEXManager.shared.registerGlobalEntry( withName: "Feature Toggles", - viewControllerFutureBlock: { r.resolve(FLEXFeatureTogglesViewController.self) ?? UIViewController() + viewControllerFutureBlock: { r.resolve(FeatureTogglesViewController.self) ?? UIViewController() } ) #endif diff --git a/station/Classes/Presentation/Assembly/PresentationAssembly.swift b/station/Classes/Presentation/Assembly/PresentationAssembly.swift index 9496db421..e4d2aef23 100644 --- a/station/Classes/Presentation/Assembly/PresentationAssembly.swift +++ b/station/Classes/Presentation/Assembly/PresentationAssembly.swift @@ -19,8 +19,8 @@ class PresentationAssembly: Assembly { return presenter } - container.register(FLEXFeatureTogglesViewController.self) { r in - let controller = FLEXFeatureTogglesViewController() + container.register(FeatureTogglesViewController.self) { r in + let controller = FeatureTogglesViewController() controller.featureToggleService = r.resolve(FeatureToggleService.self) return controller } diff --git a/station/Classes/Presentation/FLEX/FLEXFeatureTogglesViewController.swift b/station/Classes/Presentation/FLEX/FeatureTogglesViewController.swift similarity index 95% rename from station/Classes/Presentation/FLEX/FLEXFeatureTogglesViewController.swift rename to station/Classes/Presentation/FLEX/FeatureTogglesViewController.swift index 3c6345204..aefad6bb5 100644 --- a/station/Classes/Presentation/FLEX/FLEXFeatureTogglesViewController.swift +++ b/station/Classes/Presentation/FLEX/FeatureTogglesViewController.swift @@ -1,6 +1,6 @@ import UIKit -final class FLEXFeatureTogglesViewController: UITableViewController { +final class FeatureTogglesViewController: UITableViewController { var featureToggleService: FeatureToggleService! init() { @@ -78,7 +78,7 @@ final class FLEXFeatureTogglesViewController: UITableViewController { } // MARK: - UITableViewDelegate -extension FLEXFeatureTogglesViewController { +extension FeatureTogglesViewController { override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) guard self.sourceSwitch.isOn else { return } @@ -93,7 +93,7 @@ extension FLEXFeatureTogglesViewController { } // MARK: - UITableViewDataSource -extension FLEXFeatureTogglesViewController { +extension FeatureTogglesViewController { override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.features.count } @@ -116,7 +116,7 @@ extension FLEXFeatureTogglesViewController { } // MARK: - Helpers -extension FLEXFeatureTogglesViewController { +extension FeatureTogglesViewController { private static func title(for feature: Feature) -> String { switch feature { case .legacyFirmwareUpdatePopup: @@ -126,7 +126,7 @@ extension FLEXFeatureTogglesViewController { } // MARK: - Factory -extension FLEXFeatureTogglesViewController { +extension FeatureTogglesViewController { private static func makeSourceLabel() -> UILabel { let label = UILabel() label.text = "Use local feature toggles" diff --git a/station/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouter.swift b/station/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouter.swift index b4d92da96..0d2f9f941 100644 --- a/station/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouter.swift +++ b/station/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouter.swift @@ -54,7 +54,7 @@ class SettingsRouter: SettingsRouterInput { func openFeatureToggles() { let r = AppAssembly.shared.assembler.resolver - if let viewController = r.resolve(FLEXFeatureTogglesViewController.self) { + if let viewController = r.resolve(FeatureTogglesViewController.self) { transitionHandler.navigationController?.pushViewController( viewController, animated: true diff --git a/station/Extensions/UIWindow+Shake.swift b/station/Extensions/UIWindow+Shake.swift index d64986bfc..bb7368d39 100644 --- a/station/Extensions/UIWindow+Shake.swift +++ b/station/Extensions/UIWindow+Shake.swift @@ -1,5 +1,5 @@ import UIKit -#if canImport(FLEX) +#if DEBUG && canImport(FLEX) import FLEX extension UIWindow { From cd810a51649e59d75ac80634a18e1a96e3012a33 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sun, 26 Nov 2023 18:53:19 +0200 Subject: [PATCH 18/84] Remove Virtual Tags (#1734) * Remove RuuviVirtual Removes virtual sensors code * remove RuuviLocation[Picker] * fix spm * fix pods * fix spm --- Modules/RuuviDiscover/Package.swift | 2 - Modules/RuuviDiscover/RuuviDiscover.podspec | 1 - .../Contents.json | 23 - .../webtag-current.png | Bin 1671 -> 0 bytes .../webtag-current@2x.png | Bin 1908 -> 0 bytes .../webtag-current@3x.png | Bin 2195 -> 0 bytes .../icon-webtag-map.imageset/Contents.json | 23 - .../icon-webtag-map.imageset/webtag-map.png | Bin 1783 -> 0 bytes .../webtag-map@2x.png | Bin 2168 -> 0 bytes .../webtag-map@3x.png | Bin 2574 -> 0 bytes .../Sources/RuuviDiscover/RuuviDiscover.swift | 6 - .../RuuviDiscover/RuuviDiscoverFactory.swift | 9 - .../VMP/Presenter/DiscoverPresenter.swift | 32 -- .../VMP/View/DiscoverViewInput.swift | 1 - .../Table/DiscoverTableViewController.swift | 8 - Modules/RuuviDiscover/target.yml | 1 - Modules/RuuviLocationPicker/.gitignore | 7 - Modules/RuuviLocationPicker/Info.plist | 22 - Modules/RuuviLocationPicker/Package.swift | 40 -- Modules/RuuviLocationPicker/README.md | 3 - .../RuuviLocationPicker.podspec | 35 -- .../Resources/LocationPicker.storyboard | 85 --- .../Contents.json | 6 - .../dismiss-modal-icon.imageset/Contents.json | 26 - .../dismiss-modal-icon.imageset/down.png | Bin 319 -> 0 bytes .../dismiss-modal-icon.imageset/down@2x.png | Bin 494 -> 0 bytes .../dismiss-modal-icon.imageset/down@3x.png | Bin 609 -> 0 bytes .../Contents.json | 26 - .../location-picker-pin-icon.png | Bin 577 -> 0 bytes .../location-picker-pin-icon@2x.png | Bin 1136 -> 0 bytes .../location-picker-pin-icon@3x.png | Bin 1739 -> 0 bytes .../de.lproj/RuuviLocationPicker.strings | 2 - .../en.lproj/RuuviLocationPicker.strings | 2 - .../fi.lproj/RuuviLocationPicker.strings | 2 - .../fr.lproj/RuuviLocationPicker.strings | 2 - .../ru.lproj/RuuviLocationPicker.strings | 2 - .../sv.lproj/RuuviLocationPicker.strings | 2 - .../RuuviLocationPicker.swift | 13 - .../RuuviLocationPickerFactory.swift | 44 -- .../Util/RuuviBundleUtils.swift | 88 --- .../Presenter/LocationPickerPresenter.swift | 112 ---- .../LocationPickerAppleViewController.swift | 149 ----- .../VMP/View/LocationPickerViewInput.swift | 8 - .../VMP/View/LocationPickerViewOutput.swift | 11 - .../RuuviLocationPickerTests.swift | 7 - Modules/RuuviLocationPicker/target.yml | 12 - Packages/RuuviAnalytics/Package.swift | 2 - .../RuuviAnalytics/RuuviAnalytics.podspec | 1 - .../RuuviAnalyticsImpl.swift | 12 - Packages/RuuviAnalytics/target.yml | 1 - Packages/RuuviDaemon/Package.swift | 13 - Packages/RuuviDaemon/RuuviDaemon.podspec | 11 - .../RuuviDaemon/BackgroundTaskService.swift | 6 - .../Sources/RuuviDaemon/PullWebDaemon.swift | 7 - .../RuuviDaemon/RuuviDaemonError.swift | 2 - .../RuuviDaemon/VirtualTagDaemon.swift | 14 - .../BackgroundProcessServiceiOS13.swift | 5 +- .../BackgroundTaskServiceiOS13.swift | 63 -- .../Data/DataPruningOperationsManager.swift | 23 - .../Data/WebTagDataPruningOperation.swift | 31 - .../CurrentWebTagRefreshDataOperation.swift | 42 -- .../WebTag/WebTagOperationsManager.swift | 64 --- .../WebTag/WebTagRefreshDataOperation.swift | 47 -- .../RuuviTagHeartbeatDaemonBTKit.swift | 5 +- .../PullWeb/PullWebDaemonOperations.swift | 71 --- .../RuuviDaemonVirtualTag/UserDefault.swift | 21 - .../WebTag/VirtualTagDaemonImpl.swift | 216 ------- Packages/RuuviDaemon/target.yml | 1 - .../RuuviLocal/RuuviLocalSettings.swift | 4 - .../RuuviLocalSettingsUserDefaults.swift | 23 - Packages/RuuviLocation/.gitignore | 7 - Packages/RuuviLocation/Info.plist | 22 - Packages/RuuviLocation/Package.swift | 43 -- Packages/RuuviLocation/README.md | 3 - Packages/RuuviLocation/RuuviLocation.podspec | 34 -- .../RuuviLocation/RuuviLocationError.swift | 6 - .../RuuviLocation/RuuviLocationService.swift | 14 - .../LocationPersistence/KeyedArchiver.swift | 19 - .../LocationAppleClass.swift | 48 -- .../LocationPersistence.swift | 8 - .../LocationPersistenceImpl.swift | 56 -- .../RuuviLocationServiceApple.swift | 92 --- .../RuuviLocationTests.swift | 7 - Packages/RuuviLocation/target.yml | 8 - Packages/RuuviMigration/Package.swift | 3 - .../RuuviMigration/RuuviMigration.podspec | 1 - .../MigrationManagerAlertService.swift | 77 --- .../RuuviMigrationFactoryImpl.swift | 5 - .../RuuviMigrationFixRHAlerts.swift | 1 - .../toVIPER/MigrationManagerToVIPER.swift | 18 +- Packages/RuuviMigration/target.yml | 1 - Packages/RuuviNotification/Package.swift | 2 - .../RuuviNotification.podspec | 1 - .../RuuviNotificationLocalImpl.swift | 33 +- Packages/RuuviNotification/target.yml | 1 - Packages/RuuviNotifier/Package.swift | 3 - Packages/RuuviNotifier/RuuviNotifier.podspec | 1 - .../Sources/RuuviNotifier/RuuviNotifier.swift | 2 - .../RuuviNotifierImpl+Process.swift | 36 -- Packages/RuuviNotifier/target.yml | 1 - .../Sensor/VirtualTag/VirtualLocation.swift | 6 - .../Sensor/VirtualTag/VirtualProvider.swift | 9 - .../Sensor/VirtualTag/VirtualSensor.swift | 11 - .../Sensor/VirtualTag/VirtualTagSensor.swift | 65 --- .../VirtualTag/VirtualTagSensorRecord.swift | 85 --- .../RuuviService/RuuviServiceAlert.swift | 56 -- .../RuuviServiceSensorProperties.swift | 13 - .../RuuviServiceAlertImpl.swift | 216 ------- .../RuuviServiceSensorPropertiesImpl.swift | 32 -- Packages/RuuviVirtual/.gitignore | 7 - Packages/RuuviVirtual/Info.plist | 22 - Packages/RuuviVirtual/Package.swift | 134 ----- Packages/RuuviVirtual/README.md | 3 - Packages/RuuviVirtual/RuuviVirtual.podspec | 78 --- .../Sources/RuuviVirtual/VirtualData.swift | 38 -- .../Sources/RuuviVirtual/VirtualError.swift | 55 -- .../RuuviVirtual/VirtualPersistence.swift | 62 -- .../RuuviVirtual/VirtualProviderService.swift | 48 -- .../Sources/RuuviVirtual/VirtualReactor.swift | 33 -- .../RuuviVirtual/VirtualRepository.swift | 10 - .../Sources/RuuviVirtual/VirtualService.swift | 58 -- .../Sources/RuuviVirtual/VirtualStorage.swift | 11 - .../RuuviVirtualModel/WebTagDataRealm.swift | 41 -- .../WebTagRealm+VirtualTagSensor.swift | 12 - .../RuuviVirtualModel/WebTagRealm.swift | 78 --- .../RuuviVirtualOWM/OpenWeatherMapAPI.swift | 16 - .../OpenWeatherMapAPIURLSession.swift | 80 --- .../VirtualPersistenceRealm.swift | 296 ---------- .../VirtualTagLastRecordSubjectCombine.swift | 50 -- .../Combine/VirtualTagSubjectCombine.swift | 55 -- .../VirtualReactorImpl.swift | 73 --- .../VirtualRepositoryCoordinator.swift | 26 - .../VirtualProviderServiceImpl.swift | 180 ------ .../VirtualServiceImpl.swift | 140 ----- .../VirtualStorageCoordinator.swift | 48 -- .../RuuviVirtualTests/RuuviVirtualTests.swift | 7 - Packages/RuuviVirtual/target.yml | 16 - Podfile | 11 - Podfile.lock | 97 +--- project_frameworks.yml | 8 +- project_spm.yml | 27 +- station.xcodeproj/project.pbxproj | 256 --------- station/Classes/Application/AppAssembly.swift | 182 ------ .../AppState/Impl/AppStateServiceImpl.swift | 17 - .../BackgroundSelectionModuleFactory.swift | 8 +- .../BackgroundSelectionPresenter.swift | 21 +- .../Assembly/CardsViewModuleFactory.swift | 2 - .../Cards/Presenter/CardsModuleInput.swift | 1 - .../Cards/Presenter/CardsPresenter.swift | 184 +----- .../Dashboard/Cards/Router/CardsRouter.swift | 14 - .../Cards/Router/CardsRouterInput.swift | 5 - .../Dashboard/Cards/View/CardsViewInput.swift | 1 - .../Dashboard/Cards/View/CardsViewModel.swift | 43 -- .../Cards/View/UI/CardsLargeImageCell.swift | 10 - .../Cards/View/UI/CardsViewController.swift | 12 - .../Presenter/TagChartsViewPresenter.swift | 1 - .../Charts/View/TagChartsViewModel.swift | 9 - .../Assembly/DashboardModuleFactory.swift | 3 - .../Home/Presenter/DashboardPresenter.swift | 203 +------ .../Home/Router/DashboardRouter.swift | 33 +- .../Home/Router/DashboardRouterInput.swift | 41 +- .../Home/View/DashboardImageCell.swift | 9 - .../Home/View/DashboardPlainCell.swift | 9 - .../Home/View/DashboardViewController.swift | 8 - .../Home/View/DashboardViewInput.swift | 1 - .../LocationPickerAppleConfigurator.swift | 25 - .../LocationPickerAppleInitializer.swift | 10 - .../LocationPicker/LocationPicker.storyboard | 106 ---- .../Presenter/LocationPickerModuleInput.swift | 12 - .../LocationPickerModuleOutput.swift | 6 - .../Presenter/LocationPickerPresenter.swift | 105 ---- .../Router/LocationPickerRouter.swift | 11 - .../Router/LocationPickerRouterInput.swift | 11 - .../LocationPickerAppleViewController.swift | 148 ----- .../View/LocationPickerViewInput.swift | 6 - .../View/LocationPickerViewOutput.swift | 11 - .../Module/Presenter/SettingsPresenter.swift | 1 - .../Presenter/DefaultsPresenter.swift | 14 - .../Presenter/TagSettingsPresenter.swift | 7 - .../Router/TagSettingsRouter.swift | 2 +- .../WebTagSettingsTableConfigurator.swift | 30 - .../WebTagSettingsTableInitializer.swift | 10 - .../Presenter/WebTagSettingsModuleInput.swift | 9 - .../Presenter/WebTagSettingsPresenter.swift | 541 ------------------ .../Router/WebTagSettingsRouter.swift | 39 -- .../Router/WebTagSettingsRouterInput.swift | 9 - .../WebTagSettingsTableViewController.swift | 231 -------- .../View/WebTagSettingsViewInput.swift | 10 - .../View/WebTagSettingsViewModel.swift | 41 -- .../View/WebTagSettingsViewOutput.swift | 15 - .../WebTagSettings/WebTagSettings.storyboard | 287 ---------- station/Classes/Routers/DiscoverRouter.swift | 40 -- station/Extensions/Errors/RUError.swift | 13 - .../RuuviDaemonError+LocalizedError.swift | 3 - .../RuuviVirtualError+LocalizedError.swift | 78 --- .../VirtualLocation+Localization.swift | 13 - .../Contents.json | 23 - .../webtag-current.png | Bin 1671 -> 0 bytes .../webtag-current@2x.png | Bin 1908 -> 0 bytes .../webtag-current@3x.png | Bin 2195 -> 0 bytes .../icon-webtag-map.imageset/Contents.json | 23 - .../icon-webtag-map.imageset/webtag-map.png | Bin 1783 -> 0 bytes .../webtag-map@2x.png | Bin 2168 -> 0 bytes .../webtag-map@3x.png | Bin 2574 -> 0 bytes station/Resources/Plists/DevInfo.plist | 1 - station/Resources/Plists/Info.plist | 1 - station/Resources/Plists/MacInfo.plist | 1 - 207 files changed, 49 insertions(+), 7280 deletions(-) delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-current.imageset/Contents.json delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-current.imageset/webtag-current.png delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-current.imageset/webtag-current@2x.png delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-current.imageset/webtag-current@3x.png delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-map.imageset/Contents.json delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-map.imageset/webtag-map.png delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-map.imageset/webtag-map@2x.png delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-map.imageset/webtag-map@3x.png delete mode 100644 Modules/RuuviLocationPicker/.gitignore delete mode 100644 Modules/RuuviLocationPicker/Info.plist delete mode 100644 Modules/RuuviLocationPicker/Package.swift delete mode 100644 Modules/RuuviLocationPicker/README.md delete mode 100644 Modules/RuuviLocationPicker/RuuviLocationPicker.podspec delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/LocationPicker.storyboard delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/Contents.json delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/dismiss-modal-icon.imageset/Contents.json delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/dismiss-modal-icon.imageset/down.png delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/dismiss-modal-icon.imageset/down@2x.png delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/dismiss-modal-icon.imageset/down@3x.png delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/location-picker-pin-icon.imageset/Contents.json delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon.png delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@2x.png delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@3x.png delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/de.lproj/RuuviLocationPicker.strings delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/en.lproj/RuuviLocationPicker.strings delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/fi.lproj/RuuviLocationPicker.strings delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/fr.lproj/RuuviLocationPicker.strings delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/ru.lproj/RuuviLocationPicker.strings delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/sv.lproj/RuuviLocationPicker.strings delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/RuuviLocationPicker.swift delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/RuuviLocationPickerFactory.swift delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Util/RuuviBundleUtils.swift delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/Presenter/LocationPickerPresenter.swift delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/View/Apple/LocationPickerAppleViewController.swift delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/View/LocationPickerViewInput.swift delete mode 100644 Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/View/LocationPickerViewOutput.swift delete mode 100644 Modules/RuuviLocationPicker/Tests/RuuviLocationPickerTests/RuuviLocationPickerTests.swift delete mode 100644 Modules/RuuviLocationPicker/target.yml delete mode 100644 Packages/RuuviDaemon/Sources/RuuviDaemon/BackgroundTaskService.swift delete mode 100644 Packages/RuuviDaemon/Sources/RuuviDaemon/PullWebDaemon.swift delete mode 100644 Packages/RuuviDaemon/Sources/RuuviDaemon/VirtualTagDaemon.swift delete mode 100644 Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundTaskServiceiOS13.swift delete mode 100644 Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/WebTagDataPruningOperation.swift delete mode 100644 Packages/RuuviDaemon/Sources/RuuviDaemonOperation/WebTag/CurrentWebTagRefreshDataOperation.swift delete mode 100644 Packages/RuuviDaemon/Sources/RuuviDaemonOperation/WebTag/WebTagOperationsManager.swift delete mode 100644 Packages/RuuviDaemon/Sources/RuuviDaemonOperation/WebTag/WebTagRefreshDataOperation.swift delete mode 100644 Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/PullWeb/PullWebDaemonOperations.swift delete mode 100644 Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/UserDefault.swift delete mode 100644 Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/WebTag/VirtualTagDaemonImpl.swift delete mode 100644 Packages/RuuviLocation/.gitignore delete mode 100644 Packages/RuuviLocation/Info.plist delete mode 100644 Packages/RuuviLocation/Package.swift delete mode 100644 Packages/RuuviLocation/README.md delete mode 100644 Packages/RuuviLocation/RuuviLocation.podspec delete mode 100644 Packages/RuuviLocation/Sources/RuuviLocation/RuuviLocationError.swift delete mode 100644 Packages/RuuviLocation/Sources/RuuviLocation/RuuviLocationService.swift delete mode 100644 Packages/RuuviLocation/Sources/RuuviLocationService/LocationPersistence/KeyedArchiver.swift delete mode 100644 Packages/RuuviLocation/Sources/RuuviLocationService/LocationPersistence/LocationAppleClass.swift delete mode 100644 Packages/RuuviLocation/Sources/RuuviLocationService/LocationPersistence/LocationPersistence.swift delete mode 100644 Packages/RuuviLocation/Sources/RuuviLocationService/LocationPersistence/LocationPersistenceImpl.swift delete mode 100644 Packages/RuuviLocation/Sources/RuuviLocationService/RuuviLocationServiceApple.swift delete mode 100644 Packages/RuuviLocation/Tests/RuuviLocationTests/RuuviLocationTests.swift delete mode 100644 Packages/RuuviLocation/target.yml delete mode 100644 Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualLocation.swift delete mode 100644 Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualProvider.swift delete mode 100644 Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualSensor.swift delete mode 100644 Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualTagSensor.swift delete mode 100644 Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualTagSensorRecord.swift delete mode 100644 Packages/RuuviVirtual/.gitignore delete mode 100644 Packages/RuuviVirtual/Info.plist delete mode 100644 Packages/RuuviVirtual/Package.swift delete mode 100644 Packages/RuuviVirtual/README.md delete mode 100644 Packages/RuuviVirtual/RuuviVirtual.podspec delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualData.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualError.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualPersistence.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualProviderService.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualReactor.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualRepository.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualService.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualStorage.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtualModel/WebTagDataRealm.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtualModel/WebTagRealm+VirtualTagSensor.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtualModel/WebTagRealm.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtualOWM/OpenWeatherMapAPI.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtualOWM/URLSession/OpenWeatherMapAPIURLSession.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtualPersistence/VirtualPersistenceRealm.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagLastRecordSubjectCombine.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagSubjectCombine.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtualReactor/VirtualReactorImpl.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtualRepository/VirtualRepositoryCoordinator.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtualService/VirtualProviderServiceImpl.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtualService/VirtualServiceImpl.swift delete mode 100644 Packages/RuuviVirtual/Sources/RuuviVirtualStorage/VirtualStorageCoordinator.swift delete mode 100644 Packages/RuuviVirtual/Tests/RuuviVirtualTests/RuuviVirtualTests.swift delete mode 100644 Packages/RuuviVirtual/target.yml delete mode 100644 station/Classes/Presentation/Modules/LocationPicker/Assembly/Apple/LocationPickerAppleConfigurator.swift delete mode 100644 station/Classes/Presentation/Modules/LocationPicker/Assembly/Apple/LocationPickerAppleInitializer.swift delete mode 100644 station/Classes/Presentation/Modules/LocationPicker/LocationPicker.storyboard delete mode 100644 station/Classes/Presentation/Modules/LocationPicker/Presenter/LocationPickerModuleInput.swift delete mode 100644 station/Classes/Presentation/Modules/LocationPicker/Presenter/LocationPickerModuleOutput.swift delete mode 100644 station/Classes/Presentation/Modules/LocationPicker/Presenter/LocationPickerPresenter.swift delete mode 100644 station/Classes/Presentation/Modules/LocationPicker/Router/LocationPickerRouter.swift delete mode 100644 station/Classes/Presentation/Modules/LocationPicker/Router/LocationPickerRouterInput.swift delete mode 100644 station/Classes/Presentation/Modules/LocationPicker/View/Apple/LocationPickerAppleViewController.swift delete mode 100644 station/Classes/Presentation/Modules/LocationPicker/View/LocationPickerViewInput.swift delete mode 100644 station/Classes/Presentation/Modules/LocationPicker/View/LocationPickerViewOutput.swift delete mode 100644 station/Classes/Presentation/Modules/WebTagSettings/Assembly/Table/WebTagSettingsTableConfigurator.swift delete mode 100644 station/Classes/Presentation/Modules/WebTagSettings/Assembly/Table/WebTagSettingsTableInitializer.swift delete mode 100644 station/Classes/Presentation/Modules/WebTagSettings/Presenter/WebTagSettingsModuleInput.swift delete mode 100644 station/Classes/Presentation/Modules/WebTagSettings/Presenter/WebTagSettingsPresenter.swift delete mode 100644 station/Classes/Presentation/Modules/WebTagSettings/Router/WebTagSettingsRouter.swift delete mode 100644 station/Classes/Presentation/Modules/WebTagSettings/Router/WebTagSettingsRouterInput.swift delete mode 100644 station/Classes/Presentation/Modules/WebTagSettings/View/Table/WebTagSettingsTableViewController.swift delete mode 100644 station/Classes/Presentation/Modules/WebTagSettings/View/WebTagSettingsViewInput.swift delete mode 100644 station/Classes/Presentation/Modules/WebTagSettings/View/WebTagSettingsViewModel.swift delete mode 100644 station/Classes/Presentation/Modules/WebTagSettings/View/WebTagSettingsViewOutput.swift delete mode 100644 station/Classes/Presentation/Modules/WebTagSettings/WebTagSettings.storyboard delete mode 100644 station/Extensions/Errors/RuuviVirtualError+LocalizedError.swift delete mode 100644 station/Extensions/VirtualLocation+Localization.swift delete mode 100644 station/Resources/Images/Assets.xcassets/icon-webtag-current.imageset/Contents.json delete mode 100644 station/Resources/Images/Assets.xcassets/icon-webtag-current.imageset/webtag-current.png delete mode 100644 station/Resources/Images/Assets.xcassets/icon-webtag-current.imageset/webtag-current@2x.png delete mode 100644 station/Resources/Images/Assets.xcassets/icon-webtag-current.imageset/webtag-current@3x.png delete mode 100644 station/Resources/Images/Assets.xcassets/icon-webtag-map.imageset/Contents.json delete mode 100644 station/Resources/Images/Assets.xcassets/icon-webtag-map.imageset/webtag-map.png delete mode 100644 station/Resources/Images/Assets.xcassets/icon-webtag-map.imageset/webtag-map@2x.png delete mode 100644 station/Resources/Images/Assets.xcassets/icon-webtag-map.imageset/webtag-map@3x.png diff --git a/Modules/RuuviDiscover/Package.swift b/Modules/RuuviDiscover/Package.swift index 2ef691a3a..2e4f4431d 100644 --- a/Modules/RuuviDiscover/Package.swift +++ b/Modules/RuuviDiscover/Package.swift @@ -18,7 +18,6 @@ let package = Package( .package(path: "../../Packages/RuuviReactor"), .package(path: "../../Packages/RuuviLocal"), .package(path: "../../Packages/RuuviService"), - .package(path: "../../Packages/RuuviVirtual"), .package(path: "../../Common/RuuviPresenters"), .package(path: "../../Common/RuuviLocalization"), .package(url: "https://github.com/ruuvi/BTKit", .upToNextMinor(from: "0.4.3")), @@ -32,7 +31,6 @@ let package = Package( "RuuviReactor", "RuuviLocal", "RuuviService", - "RuuviVirtual", "RuuviPresenters", "BTKit", "RuuviLocalization" diff --git a/Modules/RuuviDiscover/RuuviDiscover.podspec b/Modules/RuuviDiscover/RuuviDiscover.podspec index cc3b626dc..a6c247f57 100644 --- a/Modules/RuuviDiscover/RuuviDiscover.podspec +++ b/Modules/RuuviDiscover/RuuviDiscover.podspec @@ -25,7 +25,6 @@ Pod::Spec.new do |s| ss.dependency 'RuuviReactor' ss.dependency 'RuuviLocal' ss.dependency 'RuuviService' - ss.dependency 'RuuviVirtual' ss.dependency 'RuuviCore' ss.dependency 'RuuviLocalization' ss.dependency 'RuuviPresenters' diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-current.imageset/Contents.json b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-current.imageset/Contents.json deleted file mode 100644 index 7943e737a..000000000 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-current.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "filename" : "webtag-current.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "filename" : "webtag-current@2x.png", - "idiom" : "universal", - "scale" : "2x" - }, - { - "filename" : "webtag-current@3x.png", - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-current.imageset/webtag-current.png b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-current.imageset/webtag-current.png deleted file mode 100644 index bd088bd02a4489bea311bc29bbab1dae985ce62a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1671 zcmbVNYiJx*6rLpJ(I$~fYl)#HCIu^AhU&I~2wnJHORsNK8BojHIBbmT%Zr>6}Eu7vQls%}`_!;!cIBe$OD8 zl!nQOX(KY|6KI*^gJiGha!34mvT-%pk=3R|-k6^umhF5ALi zVQSKKEx<6@Y}S_z_)L3(;Y3knSU=}IE@#sU!=LD#es zrkSoB)NsXRG7|9)MkKo>C~JnN02v>Q2%IPgwBN@S-IXK|HyjrlGKxpT6poNj(-gpSsQ?!WakPqhA274acFnz;3UUhm21Y(+lk2YVfpHXzE zJW6Y1F=qgjy;=xUvX=x%p~}&%d zk{IUCI*V)T%De){y~7(;n->14wmoFvUT5Q`cJCuEtrA2{YdqSY2tE1C?CsO@>@1Mv7qom;kUZEycI%rx;WJkO6FIhi;xcY6EM{VTcU7hgW}OZ53q z`YdAlw^T#J;?w-H`qkOx3lFT$ZLlvCo?E)5@aV<)rp1OK^;Dhp&KL9Dw|3MBJy+*s z0*rTj_wAZts-H>lQ}R;Z0;3AG9k+eG^5f&qSgie?XZN1(YgA9sR#)Q_2Y=dBd+deJ zy9&uGhaX(p_I_aB?5^#5XRh`)uI`YOht3qXy~!>7{OX5az73ABnU%{sE(zq}<3ck3 zSQl-aA3u>_WKORgv)&+P-z(g)d8M%b_mdx7TwC%fKa91-^zLQ;sn?I*bUFE2+o5{n Xo3R5Yq|uMPUqyUyDEi94_``ny=UOEV diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-current.imageset/webtag-current@2x.png b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-current.imageset/webtag-current@2x.png deleted file mode 100644 index b0320dab62ae60f9ddf330a841d9589330de5f5b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1908 zcmbVNeNYr-7++9B3`Q=H{K#4t{DiyRz2&}kI0f$bxEYQJjstX(_ICGRzif&|O*u~a!J~MLTa4!OLj2Wrc*)h9d zVH>!T7Ll!NDRa;*jkJkD7A=Hx10*2uvN8n+ydIxK2Fyr=mjq*F8b#m;L~b-A`HDff z#$FCvc#(y58oipvb9Au5q`~z>j>(h_Ycbr2Vn!4v)VQ9^!APwZj$R0`CNgfa!deuy z1-{HkgDeXqiu(P2ji1o)Vm*qROePf5qFSvQAk@a)Qk9K3HL- zTzr#kMu4ZI61+l;)+a^71OkQzC;`Pam?9|xWat=9Xc9dU;|z_m9@fkHWC>vL7*=TD zWnOCF|AsoY{D1)vTDv`FfhzmN`uP`)Vc32>m9CrIkX`!G41G3syJ@(cGbEsE*x4|fK{2}cR}!u^qy7QiA|v^ zM-7%adqe5#T2wnj312;KJQ63qXx%Y=_;k_sR!hp!=c;;-U~4XTCrlr=XfD>c#zl8t zJQMo)bof>=y!@$O67~_#e3x1mUf$O=l63D}>QGi(^Y=*pld3y2ho|bQ!ZSVyZJ5UO z4kV3-kq_H{!#0_AA{k4MpHFC6S{fhjJVp2P#d~s_-s?%Lc|GNXb6*>hO{QqS$y%^= zzGeR#DF^blsBUCl8k+TK9O1PdN}HPW`PQm~f%us#2(HiP&y=^k4V@1S65;cwT(=z6 zs%wPmS~WzSb|p_7X}k0ie(|HXmRdI_lv)=*(fZSyPj{?sbN(K;d*pcbfRDbs_x8y& zcgQf_zJK$v?8D6&moxWF>v!)B4E+!PF~X4i{AR&S`55IsMv zF0W83v^_*Iyhls3dY}68ZU82#bMo646V7LJzbQ(fWCE^rGA|n?HtqH7?%C#;Yu?62u zs7sQ36o&czeyv}p<%Lp=FdB^*PGTgffe4LQ;g#rs#w*5;YOn&45jda3@m@sMNSE+s zk_m;L4pZ>>LTbI@NSI*2umJ7D2rVvC8UnIR24rz=8a^6 z!tr6Kjb}M$#UG)`6i!gYZ=o=6SX!e05zI1_lNUTRWX*Z#Qh@oqr6>}LC1v5=yZ{YD z?{v4XXIdClxFP1IFG4cYEPBGI*K0^EG32hzMrC?MiS{xe(`rItgtQ#TQU-&O zPA<{uHM(Ry&?FLuWQ~ypq(+wnoFxR%u}+2@mACRtnVbis^6Y<<&k;CShqU{D>yfKd zP9Q3S6XDTTjMUE(uwrE9=8&PBp=d^~1ry51NdQ=MWSRTl5g1nMcLAvMZ}MUoCh|_n zPYYmSDU8;?OFj%Tz~s^$CWHN+=g{75Wj+dry+fXcnihNswLRd4y-t8lO+WF;=?aBv zdZu+@o~!2UjswCM_{7CIrm&h-H8nNLF?DsZQ>T7EX<+w9=?SL};pfgdYMzG|T^M;} z#f9)URs4r7FUW4=O0-x^aa9eS!$-zPcOb!F#NE`0x$scpf? zh?Xz?x(_lgow~cj_1yZ7c=USg%GQUKb@vy&Y4p_X8a%yA9OyBA{L8DcYH6$9h%j)}8ZIIZk-WwYRJd*&Wv((|*>|0-m|IZ%)(cIj-FI*Peg-wPz!Y ziPg>Y;A7==PG#4(YsTVC*p{3{8+Og+#(!?^wS+5Qipt>d>`N z*MLc%n_qk{O*vJEp-0LoQqx?wztLi%#lAPQm9-QUfoAuS?1GB$t zuf=<&efdolsakv^=xFTkd?9k*k4KAB4y+%nNNG+`UK_j>yzjkIqIVtp`pV$yhwIT+ z@!+Rqw7$}FI5+?150iUh=U#107h^UST-j}lsa8EdX2y}5Q#UM=e;YE>vaJUfIck3e DUMC^t diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-map.imageset/Contents.json b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-map.imageset/Contents.json deleted file mode 100644 index 433d4434d..000000000 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-map.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "filename" : "webtag-map.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "filename" : "webtag-map@2x.png", - "idiom" : "universal", - "scale" : "2x" - }, - { - "filename" : "webtag-map@3x.png", - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-map.imageset/webtag-map.png b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-map.imageset/webtag-map.png deleted file mode 100644 index 8a8d282d2ca696c605ec5b3ef27c8133d4b9d5ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1783 zcmbVNdu$VR9B+-Fpp%D-@(?`^hHP-XyRPke=L&4SZEZ%&=o+_)AlJKJyR*FqcQ@K? z5{53rC4-oOf+&zEGlIHckm&?7bWv2$;52B4k3U?LNyZjLFd*RX+O8P}UtDr`zx(|@ z-^b_sy4DJRS=PiE6HO*lme<1s;5*y6Zyyhzn_6dO!Pf-EQ=^$ocie5_`D+AszWPidu+R3DSuZPMplgNC#~rXsZ=TUnsPu@?ko_l%{RLFBe*? z>k5tI@p#-4&$q~G1Sctq!U-#GwPFx~Y4wuMCNN2xGpd0B8m9`1F31vMXkarS? z<=AMVDn?yK+-@T=6f)n(a)M;=$Q>gE7*+=^)IeYa1@jgpDB4QG>@6VdG(n`GKA9K7 z^<$tUff3FiSwIscZMR(qg>}QTI{U9+o}9EoptzkUohiCdo{_maqYg&p`Tr@uOch`svay@iV|1rcK(t5D zU~22r{Zk3nq*pNkN!AR_az-z>P|hdP z_1}sQhYWC|byH;Uzw%6;jcM~yIGi2EGBdQ`M`r8+3C=nd4z=HU&g7U(=5=1CDCpdD zaO)dtUeV;zNx8R9ZDmT)MH`sX&bEQ&iRQxMxl^Zix97o~P6k~wvuN4&rJogdNZ;-4 z@89|T*)P}UyMDR6D{}0@_$7TmJ%9G}loJ=Sx0{D&_nUX_Ikvm0D{^Ee@xcBwO%Dey zX4f`OCz_(udOo_E?VtCioO7`IO1XIjzuz@7TX^B>(Tle|gDg1pS{~6C3mw{WK4s+*{l9h0c|Q)bHENb`1RZwDiGye(b~c^EIEgYpW+57nkL%3^X4| z?0#J6U&X8|FRPL^U1Hnr+SnUD()i$D{u1BEYuh(>eSPPBd$;WvdFQS*(|G;Ycj=fKa2p8j21>t5e*%X0+>p7M0hKf5pV&gOTYjeat8@{eza54VVc zeY)=dqWOgP^DRTO<_{jfa=xJJ2eiZ5?|t;`dCcV}JYTi+qLnQxa$8z@SM^m%*RCC{ yGVeOqctqOp>&xbc?!RQ7+;ZqpXn@K{p6og;%p88 diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-map.imageset/webtag-map@2x.png b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-webtag-map.imageset/webtag-map@2x.png deleted file mode 100644 index 942e74577f7037250fe1fc4a2ac997630393a01a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2168 zcmbVO3sBQ$951K{C_0}gZkh!+-Jngf_cC{1zAxYR`~Ls`@Bg~2 z)W=Nq^7QePNF-j`Xic0jPY{Q@oA54tQE3$>4<>pxCy|Ww7l(^B&aX`(=?74TL_SeB z10!gw3^&rLq|9Mu1hhmlDcr%}L^{a>sic{*sle7_RUkkaRbWD}4%RVhGL4GPX33e^ zF$N+#oj{FXco;Crfe8YvB##3QtHs7)4i(rb7ZcXvHUt8l5I$W6Mu-Z5M4cW`(<})D z%al?A2?_>6P#L0B1fggkAcv7q2o8l1g%nX@K`)# znl;e0r6*AO9+LsJS_}*dOwi#3WfOV4*XtIk!Ff^ziU=u;3UM>Qs1P>{Q3Sxj7z}qo zb+nN(W%Yt0uoMn8AR!nm$KY3?Lf#m09{*Rck-$teYsCfDlodCV5MwigfYXk5$4NYWt`mJ(Y>-zKxfWiI3d=83M9lNAdO)6Huc6H=n`vBBL$)VkQZGr zjyCajoFya7g17!#@<9RvNG#nhGSFXncAoVr^B%a+JH(~4X$c?Bwny58UdIYeEy$2{ zTq1FOq18kf5|_8E-@4!dJn*BcCdFH$5)%_gr7-xdl$$BHZjQYbc4jQjR4{PGy%_)u zS5&|jZ_PDJO-y6(v4G0(f_Kh6_pL2?xbfLD`?|dRhj|AFB@^E~9{S)#QfhJQ*~`O@ zA31vt+`rBKz_UT}>B;6iw@{ZNwsL>Lzm``KYDOyT}EkGUGXH>6?wM)TXnYw#B&!6w*t#0gDO{6 zwLL*c8iw82cXdrQotPkNuEp7XfJK$~!t63UC)AYnOTXga%6=PFlq|Zhb=lBGcFI$!0=y^E)cOds- z!yaX7YtjRBC+|r3g$vuBKG}3}Ztm3FRp~{Wg1k5HzUOn;<5Z4$@vvm5Ikl{*eyBMh zXWF$QpAU9~oQSX0XUG zR-Zu`DLRAtH=>8P|3LxcTDg2!$1mEV)eftmjgc!D8bc2GMKrC*)e}%6K~vcVoQPb( znCb6eqemqM0y9zu1x0Dz25R10lL3ju5f~8=Ajfc0=im|e&M88Q83{4yK(JvE6E_7c zV&aA(f>|&hh2b|)Ii)7ka^Ha>FdG&skPsC97bufAYRriJSFjpK(lt%rj7Fq=wm`6Qkzo1{n_plcXBuzycneN-#JcA7}GYIRdtbE99`#2q6N8s6%*&kWn-kHdIRC*^WGT zdtUv2o=-54OdVpHUoFQ`osI-TV@R3_ZSGM0BoWJpW*QP0%o!BJ9kn0^aYqsmYH($p-@2{N9>^(t@&}&EcA5pdZocr^7NBwxHXU-FH*UT-a(mPan=LSZ zZXOcA`c2Uui^lF3df1%@ii{_uQs>1vOYRoO0hAj!Z&|3_a)df z;RDYaAFE}IDpNjoK0E$9s_@7s^%cfHX^(%=x-wt>jdSme>uWNBow4Nu=K?rRy?}SC z+eEBm)!r@UsXKcV7an+kH=WvjJ7{6ThInhu;{E40N!8h@Moa(UZ;y{JyWxJt<52Ol zzH;@Iv8^Y!ocXExcC0cgXhBUTD`81-f(w$iyQIw0z;EH#&+<2iJpU>?Wj)+0-+yyv zg;nBQx2xoNe88tuRaHHu_laYd^l4RgGs;Iio6|){W*+s@WiAD5x{gB$S0lb@o8P2T z+G}E!<@8Q9S-hGT6j72{blqd$S}&u4w@viW-}M&2S$MUzdgjsJyB_EbJkMDsbc(Y~ zY_RdI9)93~yrRdm|EP+{TIap1CE|oWbfM`<-=(SAyKUAHvD4(0cTU;u_Tu>`ItpU* zmb8cbz_(wr{Oz9Arh5J5wul)@f%i{$&K`^DKDFa&TIRz&#|!iB?cP*7;ozhAJTK^c z(~-sLxNnVMAO{*#>Rpc4;{}fqU2Ls>jQO_uMAxBdpO)7qwt7AgsLJyj{cg|Qaj|J% z?aOt<+~xBA@lW;U@XgiNeOlZ`U{^xEn`R5mJ}_-bAW7a>&$jGo2RHWL?>jh+{o?bO zDUGqSG6LBPs*%5FGQO``>IsA`y6g2)Q(d(;`S^r8tuf0|oLy7r-ktiHeVkwZ*Hw{$ zWM$t-%cA;6Nl!+x4p=*Bu4$I#=gV97mmd54=2xms&C%4_l>C*F@@1_t2f_0GefGBe z?1m0*(8XFsO`;nyX^qFZtl9xWGP&g3)#+7H8*X>)K5Fnc`#ro|T)^Mhq5W8tw1%)$LiK zUSYvhk;U`y=!o;SuakL|n+ujq>G1intl!hzS?}j@a^2zWd67!W+ZLMs=jit9r=v`y zUbZyk&M4P9(44oetMSZ=@%Lut6!&)G$8LOlc~|mASFbkP>Bv6}^ zt_|PTlkr(w_}Z~?C113(Z@p7Ls{h5VweO$n_Pe|4`MSMM4N0ectDRq5j4Zw~8R#03 nu>bzG{=D4&NBz?W+MZ6VY3}X&A-pNh@y8~MjF%pqld|UT=o;pO diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscover.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscover.swift index 2b70c5c2b..f6279d2aa 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscover.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscover.swift @@ -5,16 +5,10 @@ public protocol RuuviDiscover: AnyObject { var viewController: UIViewController { get } var router: AnyObject? { get set } var output: RuuviDiscoverOutput? { get set } - - func onDidPick(location: Location) } public protocol RuuviDiscoverOutput: AnyObject { func ruuviDiscoverWantsClose(_ ruuviDiscover: RuuviDiscover) func ruuvi(discover: RuuviDiscover, didAdd ruuviTag: AnyRuuviTagSensor) func ruuvi(discover: RuuviDiscover, didSelectFromNFC ruuviTag: RuuviTagSensor) - // Will be deprecated in near future. Currently retained to support already - // added web tags. - func ruuviDiscoverWantsPickLocation(_ ruuviDiscover: RuuviDiscover) - func ruuvi(discover: RuuviDiscover, didAdd virtualSensor: AnyVirtualTagSensor) } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscoverFactory.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscoverFactory.swift index 024f35b2d..ca100e6e8 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscoverFactory.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscoverFactory.swift @@ -4,15 +4,12 @@ import RuuviContext import RuuviReactor import RuuviLocal import RuuviService -import RuuviVirtual import RuuviCore import RuuviPresenters public struct RuuviDiscoverDependencies { - var virtualReactor: VirtualReactor var errorPresenter: ErrorPresenter var activityPresenter: ActivityPresenter - var virtualService: VirtualService var permissionsManager: RuuviCorePermission var permissionPresenter: PermissionPresenter var foreground: BTForeground @@ -20,20 +17,16 @@ public struct RuuviDiscoverDependencies { var ruuviOwnershipService: RuuviServiceOwnership public init( - virtualReactor: VirtualReactor, errorPresenter: ErrorPresenter, activityPresenter: ActivityPresenter, - virtualService: VirtualService, permissionsManager: RuuviCorePermission, permissionPresenter: PermissionPresenter, foreground: BTForeground, ruuviReactor: RuuviReactor, ruuviOwnershipService: RuuviServiceOwnership ) { - self.virtualReactor = virtualReactor self.errorPresenter = errorPresenter self.activityPresenter = activityPresenter - self.virtualService = virtualService self.permissionsManager = permissionsManager self.permissionPresenter = permissionPresenter self.foreground = foreground @@ -47,10 +40,8 @@ public final class RuuviDiscoverFactory { public func create(dependencies: RuuviDiscoverDependencies) -> RuuviDiscover { let presenter = DiscoverPresenter() - presenter.virtualReactor = dependencies.virtualReactor presenter.errorPresenter = dependencies.errorPresenter presenter.activityPresenter = dependencies.activityPresenter - presenter.virtualService = dependencies.virtualService presenter.permissionsManager = dependencies.permissionsManager presenter.permissionPresenter = dependencies.permissionPresenter presenter.foreground = dependencies.foreground diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift index 9575786e3..1e5d70a25 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift @@ -8,7 +8,6 @@ import RuuviContext import RuuviReactor import RuuviLocal import RuuviService -import RuuviVirtual import RuuviCore import RuuviPresenters import CoreBluetooth @@ -31,10 +30,8 @@ class DiscoverPresenter: NSObject, RuuviDiscover { var router: AnyObject? weak var output: RuuviDiscoverOutput? - var virtualReactor: VirtualReactor! var errorPresenter: ErrorPresenter! var activityPresenter: ActivityPresenter! - var virtualService: VirtualService! var foreground: BTForeground! var permissionsManager: RuuviCorePermission! var permissionPresenter: PermissionPresenter! @@ -264,18 +261,6 @@ extension DiscoverPresenter: DiscoverViewOutput { } } - extension DiscoverPresenter { - func onDidPick(location: Location) { - virtualService.add(provider: .openWeatherMap, location: location) - .on(success: { [weak self] virtualSensor in - guard let sSelf = self else { return } - sSelf.output?.ruuvi(discover: sSelf, didAdd: virtualSensor) - }, failure: { [weak self] error in - self?.errorPresenter.present(error: error) - }) - } - } - // MARK: - Private extension DiscoverPresenter { private func startObservingPersistedRuuviSensors() { @@ -459,21 +444,4 @@ extension DiscoverPresenter { return string.replacingOccurrences(of: "\0", with: "") } } - -extension DiscoverPresenter { - // Will be deprecated in near future. Currently retained to support already - // added web tags. - private func persistWebTag(with provider: VirtualProvider) { - let operation = virtualService.add( - provider: provider, - name: "Test Virtual Sensor" - ) - operation.on(success: { [weak self] virtualSensor in - guard let sSelf = self else { return } - sSelf.output?.ruuvi(discover: sSelf, didAdd: virtualSensor) - }, failure: { [weak self] error in - self?.errorPresenter.present(error: error) - }) - } -} // swiftlint:enable file_length diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift index 0e963004c..25208efa7 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift @@ -1,7 +1,6 @@ import Foundation import UIKit import RuuviOntology -import RuuviVirtual import RuuviLocalization protocol DiscoverViewInput: UIViewController, Localizable { diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift index 68d4f0964..510ac8f5c 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift @@ -1,7 +1,6 @@ import UIKit import BTKit import RuuviOntology -import RuuviVirtual import RuuviLocalization import CoreNFC @@ -68,13 +67,6 @@ extension DiscoverTableViewController: DiscoverViewInput { present(alertVC, animated: true) } - func showWebTagInfoDialog() { - let message = "DiscoverTable.WebTagsInfoDialog.message".localized(for: Self.self) - let alertVC = UIAlertController(title: nil, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "OK".localized(for: Self.self), style: .cancel, handler: nil)) - present(alertVC, animated: true) - } - func startNFCSession() { session?.invalidate() session = nil diff --git a/Modules/RuuviDiscover/target.yml b/Modules/RuuviDiscover/target.yml index f27df5352..ef4adc1a1 100644 --- a/Modules/RuuviDiscover/target.yml +++ b/Modules/RuuviDiscover/target.yml @@ -11,6 +11,5 @@ targets: - target: RuuviReactor - target: RuuviLocal - target: RuuviService - - target: RuuviVirtual - target: RuuviPresenters - target: RuuviLocalization diff --git a/Modules/RuuviLocationPicker/.gitignore b/Modules/RuuviLocationPicker/.gitignore deleted file mode 100644 index bb460e7be..000000000 --- a/Modules/RuuviLocationPicker/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.DS_Store -/.build -/Packages -/*.xcodeproj -xcuserdata/ -DerivedData/ -.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata diff --git a/Modules/RuuviLocationPicker/Info.plist b/Modules/RuuviLocationPicker/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Modules/RuuviLocationPicker/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Modules/RuuviLocationPicker/Package.swift b/Modules/RuuviLocationPicker/Package.swift deleted file mode 100644 index 1568ed6d5..000000000 --- a/Modules/RuuviLocationPicker/Package.swift +++ /dev/null @@ -1,40 +0,0 @@ -// swift-tools-version:5.9 -// The swift-tools-version declares the minimum version of Swift required to build this package. - -import PackageDescription - -let package = Package( - name: "RuuviLocationPicker", - defaultLocalization: "en", - platforms: [.macOS(.v10_15), .iOS(.v13)], - products: [ - // Products define the executables and libraries a package produces, and make them visible to other packages. - .library( - name: "RuuviLocationPicker", - targets: ["RuuviLocationPicker"]) - ], - dependencies: [ - .package(path: "../../Packages/RuuviOntology"), - .package(path: "../../Common/RuuviPresenters"), - .package(path: "../../Common/RuuviLocalization"), - .package(path: "../../Packages/RuuviCore"), - .package(path: "../../Packages/RuuviLocation"), - ], - targets: [ - // Targets are the basic building blocks of a package. A target can define a module or a test suite. - // Targets can depend on other targets in this package, and on products in packages this package depends on. - .target( - name: "RuuviLocationPicker", - dependencies: [ - "RuuviOntology", - "RuuviPresenters", - "RuuviCore", - "RuuviLocation", - "RuuviLocalization" - ] - ), - .testTarget( - name: "RuuviLocationPickerTests", - dependencies: ["RuuviLocationPicker"]) - ] -) diff --git a/Modules/RuuviLocationPicker/README.md b/Modules/RuuviLocationPicker/README.md deleted file mode 100644 index cb6fceb00..000000000 --- a/Modules/RuuviLocationPicker/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# RuuviLocationPicker - -A description of this package. diff --git a/Modules/RuuviLocationPicker/RuuviLocationPicker.podspec b/Modules/RuuviLocationPicker/RuuviLocationPicker.podspec deleted file mode 100644 index 891da1752..000000000 --- a/Modules/RuuviLocationPicker/RuuviLocationPicker.podspec +++ /dev/null @@ -1,35 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviLocationPicker' - s.version = '0.0.1' - s.summary = 'Ruuvi LocationPicker' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'RuuviLocationPicker' - - s.subspec 'RuuviLocationPicker' do |ss| - ss.source_files = 'Sources/RuuviLocationPicker/**/*.{h,m,swift}', 'Sources/RuuviLocationPicker/*.{h,m,swift}' - ss.resource_bundles = { - 'RuuviLocationPicker' => ['Sources/**/Resources/**/*'] - } - - ss.dependency 'RuuviCore' - ss.dependency 'RuuviLocation' - ss.dependency 'RuuviPresenters' - ss.dependency 'RuuviLocalization' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end - - - diff --git a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/LocationPicker.storyboard b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/LocationPicker.storyboard deleted file mode 100644 index 61da29ba2..000000000 --- a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/LocationPicker.storyboard +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/Contents.json b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/dismiss-modal-icon.imageset/Contents.json b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/dismiss-modal-icon.imageset/Contents.json deleted file mode 100644 index a51b7b7d2..000000000 --- a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/dismiss-modal-icon.imageset/Contents.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "images" : [ - { - "filename" : "down.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "filename" : "down@2x.png", - "idiom" : "universal", - "scale" : "2x" - }, - { - "filename" : "down@3x.png", - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "template" - } -} diff --git a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/dismiss-modal-icon.imageset/down.png b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/dismiss-modal-icon.imageset/down.png deleted file mode 100644 index 266f1f852a52b1432a282b36ef3d7e3d94035b6e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 319 zcmeAS@N?(olHy`uVBq!ia0vp^f*{Pn1|+R>-G2co&H|6fVg?3oVGw3ym^DWND9BhG zwn`WqgefAiwT zMuSRb+a_}czXzf=P0D$@c3LrC)UIIqBNw#j$g)(^8qbGIJ?m@N_xz1tGDS{WQt?R4 zRli9p(dT~3UN|P!@wnpouDtqVnX}vi7+)kXKfJ`V-&U;j(ZzdfR;@~wXyd-(?eJQG zL+-}zmkcqpf_m%2L|pGFeR-)cDV*i!zW-}p|H@+i;=w-m0&B18h7=LkJvyg1b7ss> zx?yxrm37j_@77Q6I_iE9mUPmxdXPQme8QG)sk1B+&axMig5938{zopr0Qtyz;{X5v diff --git a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/dismiss-modal-icon.imageset/down@2x.png b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/dismiss-modal-icon.imageset/down@2x.png deleted file mode 100644 index acba77b2e97e2065f671a5e118140b41343a74e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 494 zcmVO2o64a6O6=99@}6d9NZc1=G@lGD(?y~r zGNepb2}CMB*tQ)`r_&8gKbUpcGd^_rmNZ}(#zR*LgmN}Kl0sJ(Hr&C6?^VBnf8qf7 zJsVGwF-o7mv1YT$^cusvaqIVwc3oEqs+-lsR8fa@@ul$ zY>K^JZ$ej)xi;Q*X0usiI2=y*=c)b4#@JPW_}eJ(I^OB$+D7yFytofi5s+OM1p&gF z0k0u@VE7kEGo($2A?O==iF@b>1Qjxw%&U1q^W-{jClp=cAPWc@Ef$N0c_Qwf*)Nex z&K7d;p4shO1IPt}lzDJTkShdf^8gFPLMh>Uh#^np2tn%5$t1raK=^&yadUXQ!=F>9 zBdMr?BtSkPNJkCqE;$B`C^~>YOQlkQPRut1>9|3F(&_XuP&SoH4Nd`tfFNZvsaC6H zSF06n(6|Lp*Xwn$-|xr4gF%oL2KfMmgdlA@vD@uVT`oC>v_e9VH3ppv+CpLpM%x3psWc1_88OF5h_fksR^`L1$xj@qY##Iuqm*f^NvM@p#EHDQI4ZecP!v>C00000NkvXXu0mjfGgkQK diff --git a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/location-picker-pin-icon.imageset/Contents.json b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/location-picker-pin-icon.imageset/Contents.json deleted file mode 100644 index 1c1f0e55a..000000000 --- a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/location-picker-pin-icon.imageset/Contents.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "images" : [ - { - "filename" : "location-picker-pin-icon.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "filename" : "location-picker-pin-icon@2x.png", - "idiom" : "universal", - "scale" : "2x" - }, - { - "filename" : "location-picker-pin-icon@3x.png", - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "template" - } -} diff --git a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon.png b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon.png deleted file mode 100644 index eb68628fad54e5be82176bc11ebd152d72c907e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 577 zcmV-H0>1r;P)P000>X1^@s6#OZ}&00001b5ch_0Itp) z=>Px$`$dhW{1z#em0xEfnDl)_+j}z=B>07Bo5GI zJmi@AxLHTk=ksYSOoY8@u+Y^|-~jMGD4WJ94il;WO4PIsj3~u8W;OUU4$({MQyeC8 zN)v%cv1<@`VfM#|`Cb_3iH~_J6>(j+h{9*S0DixKd%*QQ6YyP1DpIXhU1aRZ3Mr45 z*@f>>j$)|@OTrD>hWVfcJchsW7Np<9CPu$0jY{F%Gj z&yDQFPjnn-9@t_&1TJvc3w|uh_AFwWri1xUL7?7hwWfO+QPx(DoI2^RA>e5SUqSIK@`3p4HqFOf_Tvc4{egl3r8d|_7)bVGnF<`Qz$C_At{0u z+9) z9bpibhU+?0U3WZj+z@36roz!OG+&L}(R{$v~M78K%vfq<^K)RI-+^wJSxN z2#(r)aMUb|1iB&uzm5!Vo}8TQpg;9VMmn3h%@rRuX4UEq)kCFGkDV0)?#F}fp4ARy z)-WDKkc%L7*Q(?6$w!BH;YRzBM7Sw8l+tcCpp9MRgZ1=^)WLBQFVEEubf2&j^v zc_>|FY^xt5A}E=sAXBmexzPt^9`EyZ&ls*NBO<8#Pe6OlMRX>70_^W55Jp5Qj&7Ma zl+D44+?45MI-||b0CAKiQU80{*hvc#FR{rFm|{3t5!&>wtqKz22+I)>Jh(@sNKxr7&H%N?QZyaJ+rmdqD zVNUT7JBNVEY^>21V0%HsUTEqHk?HB_S**y2(2GEU1l-1Ixbp4S6(STTg1U%BNeg1G z6T@~f5C{y_DGUX!5sAm+%ZTBGN*q*%xQg^wK1ircv9&S&WXeOv=guX3UEhT=>)`1v zvSF0t9n08p*R>U4k*uz+o<_pouyJh*-F!Bib$n#k;<`>`Zf@=e%H{|h)qSJ@i8cKD zQmIs~HV~&{S4)cplgVVVC^34Ata?6x!~pivdfb|Q>q3MGVZY2;_X|jjfW$RM*6r5h zlc{nHc=sM?YHFendS&!aDNpnay$pC6@G|h diff --git a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@3x.png b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Resources/RuuviLocationPicker.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@3x.png deleted file mode 100644 index cb9815a48d74054e85aae9d26132f554f8fa5ba3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1739 zcmV;+1~mDJP)002t}1^@s6I8J)%00001b5ch_0Itp) z=>Px*g-Jv~RCodHn_FmHMHt7kNh-l;5DH3@tn@)8S`ERFn^?qvC~8&eTcBdS(}E}n zUQkfPheAt5XzGI+(P9zogGL1(RIEbonl^^k#)p+At*M6ETu75NiN9(0gm^M%cV_a< zZoqTkFlWB`F8}%O+|HcYf`a&p8HgE(8HgE(8HgE(8HgE(8OSpOi9E+IYHDh_eQ|Md z3pj4zE>9#9<>c3sj**^1rtTBu+dDcse&TtaJ1rHD8d1L6d zlkV;6>N;v_C#9EDvg+#Ul0`*DZvuWBBo(?=0{tlHYzbzH3w^@JGekRu3tZ*FdGM_*sxT&PGi z>y@lcn>JlhR#x^kh&PL();s%ge0==g!NI{veevq0&f|tb=mbO^Kra_WDL9+c@w_#F zB7;ghsW3*pMb~@M$=KbfsG4wtM(mPjH*Lm}HU_qR2qTOQ~H{sND+93`}_NChlfaiVq~Qw^hZY06wsw^;br%Wnwpxc zG{s9IRj%}u{*ut(0sTG$HDeV~vH<6@o!eYeQgW2{zwLYpx_miul~;0Aj=Xt!naMLP z>su2&QysB)LluxQrKY&J_!raQVLd9RmJyC5c)uG!hy8~HqTJjky$ z6(tKW30`>BxOMevfeG0E!TaP!0Y6JFM7tqgX&j56EqTx512{gF4lhlXV(XwZNEd(X zXnf*gm&r!D8>(2UE2c=VRhc|pgLJ{0rDKb?EC4R@tL~QuYU7XiUJi=*Agh2?vsyfQ zJ9ChQxHF@pqaS6_aVqvgR(jR^z7wL=8|_P_QdT^17<0}AJPT&DEp8_=-!3veV@+7VJReLi#3-4t0_V)fp_wc&z!v8KBvDIFh z9Zi?Cy_2QFuzT=2$yxO*eL>Vo{O^(WtMey*;7b>TV~f+tWO9bGdvxWil zjLdV=vJ?{5Kl^9}CyY=TD&emSqQqaAqr&HmEOkbm$~_YW#6f<6cfhBy6FDJc5 RuuviLocationPicker { - let presenter = LocationPickerPresenter() - presenter.locationService = dependencies.locationService - presenter.activityPresenter = dependencies.activityPresenter - presenter.errorPresenter = dependencies.errorPresenter - presenter.permissionsManager = dependencies.permissionsManager - presenter.permissionPresenter = dependencies.permissionPresenter - presenter.locationManager = dependencies.locationManager - return presenter - } -} diff --git a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Util/RuuviBundleUtils.swift b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Util/RuuviBundleUtils.swift deleted file mode 100644 index be1ad1013..000000000 --- a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/Util/RuuviBundleUtils.swift +++ /dev/null @@ -1,88 +0,0 @@ -import Foundation -import UIKit - -extension Bundle { - public static func pod(_ clazz: AnyClass) -> Bundle { - if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { - if let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), let bundle = Bundle(url: bundleURL) { - return bundle - } else if let bundleURL = Bundle(for: clazz).resourceURL, let bundle = Bundle(url: bundleURL) { - return bundle - } else { - assertionFailure() - return Bundle.main - } - } else { - assertionFailure() - return Bundle.main - } - } -} - -extension UIImage { - public static func named(_ name: String, for clazz: AnyClass) -> UIImage? { - #if SWIFT_PACKAGE - return UIImage(named: name, in: Bundle.module, compatibleWith: nil) - #else - return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) - #endif - } -} - -extension String { - public func localized(for clazz: AnyClass) -> String { - let bundle: Bundle - #if SWIFT_PACKAGE - bundle = Bundle.module - #else - bundle = Bundle.pod(clazz) - #endif - if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { - if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), - let bundle = Bundle(path: path) { - return bundle.localizedString(forKey: self, value: nil, table: module) - } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), - let bundle = Bundle(path: path) { - return bundle.localizedString(forKey: self, value: nil, table: module) - } else { - assertionFailure() - return self - } - } else { - assertionFailure() - return self - } - } - - private func currentLanguage() -> String { - if let preferred = Bundle.main.preferredLocalizations.first { - return preferred - } else { - return "Base" - } - } -} - -extension UIStoryboard { - public static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { - let bundle: Bundle - #if SWIFT_PACKAGE - bundle = Bundle.module - #else - bundle = Bundle.pod(clazz) - #endif - return UIStoryboard(name: name, bundle: bundle) - } -} - -extension UINib { - public static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { - let bundle: Bundle - #if SWIFT_PACKAGE - bundle = Bundle.module - #else - bundle = Bundle.pod(clazz) - #endif - return UINib(nibName: nibName, bundle: bundle) - } -} diff --git a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/Presenter/LocationPickerPresenter.swift b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/Presenter/LocationPickerPresenter.swift deleted file mode 100644 index 6cdd21793..000000000 --- a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/Presenter/LocationPickerPresenter.swift +++ /dev/null @@ -1,112 +0,0 @@ -import Foundation -import CoreLocation -import RuuviLocation -import RuuviCore -import RuuviPresenters -import UIKit - -class LocationPickerPresenter: RuuviLocationPicker { - var viewController: UIViewController { - if let view = view { - return view - } else { - let storyboard = UIStoryboard.named("LocationPicker", for: Self.self) - // swiftlint:disable:next force_cast - let view = storyboard.instantiateInitialViewController() as! LocationPickerAppleViewController - view.output = self - self.view = view - return view - } - } - - var router: AnyObject? - weak var output: RuuviLocationPickerOutput? - - private weak var view: LocationPickerViewInput! - var locationService: RuuviLocationService! - var activityPresenter: ActivityPresenter! - var errorPresenter: ErrorPresenter! - var permissionsManager: RuuviCorePermission! - var permissionPresenter: PermissionPresenter! - var locationManager: RuuviCoreLocation! - - private var isLoading: Bool = false { - didSet { - if isLoading != oldValue { - if isLoading { - activityPresenter.increment() - } else { - activityPresenter.decrement() - } - } - } - } -} - -extension LocationPickerPresenter: LocationPickerViewOutput { - func viewDidTriggerCancel() { - output?.ruuviLocationPickerWantsClose(self) - } - - func viewDidTriggerDismiss() { - output?.ruuviLocationPickerWantsClose(self) - } - - func viewDidTriggerDone() { - if let location = view.selectedLocation { - output?.ruuvi(locationPicker: self, didPick: location) - } else { - assert(false) - } - } - - func viewDidEnterSearchQuery(_ query: String) { - let search = locationService.search(query: query) - isLoading = true - search.on(success: { [weak self] (locations) in - self?.view.selectedLocation = locations.first - }, failure: { [weak self] (error) in - self?.errorPresenter.present(error: error) - }, completion: { - self.isLoading = false - }) - } - - func viewDidLongPressOnMap(at coordinate: CLLocationCoordinate2D) { - let reverseGeoCode = locationService.reverseGeocode(coordinate: coordinate) - reverseGeoCode.on(success: { [weak self] (locations) in - self?.view.selectedLocation = locations.last - }, failure: { [weak self] (error) in - self?.errorPresenter.present(error: error) - }) - } - - func viewDidTriggerCurrentLocation() { - if !permissionsManager.isLocationPermissionGranted { - permissionsManager.requestLocationPermission { [weak self] (granted) in - if granted { - self?.obtainCurrentLocation() - } else { - self?.permissionPresenter.presentNoLocationPermission() - } - } - } else { - obtainCurrentLocation() - } - } - - private func obtainCurrentLocation() { - let op = locationManager.getCurrentLocation() - op.on(success: { [weak self] (location) in - let reverseGeoCode = self?.locationService.reverseGeocode(coordinate: location.coordinate) - reverseGeoCode?.on(success: { (locations) in - self?.view.selectedLocation = locations.last - }, failure: { (error) in - self?.errorPresenter.present(error: error) - }) - }, failure: { [weak self] (error) in - self?.errorPresenter.present(error: error) - }) - } - -} diff --git a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/View/Apple/LocationPickerAppleViewController.swift b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/View/Apple/LocationPickerAppleViewController.swift deleted file mode 100644 index f10ad97a7..000000000 --- a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/View/Apple/LocationPickerAppleViewController.swift +++ /dev/null @@ -1,149 +0,0 @@ -import UIKit -import MapKit -import RuuviOntology -import RuuviLocalization - -class LocationPickerAppleViewController: UIViewController { - var output: LocationPickerViewOutput! - - @IBOutlet weak var mapView: MKMapView! - @IBOutlet var doneBarButtonItem: UIBarButtonItem! - @IBOutlet var cancelBarButtonItem: UIBarButtonItem! - - var selectedLocation: Location? { - didSet { - updateUISelectedLocation() - } - } - - private var searchBar: UISearchBar! - private let annotationViewReuseIdentifier = "LocationPickerMKAnnotationViewReuseIdentifier" -} - -// MARK: - LocationPickerViewInput -extension LocationPickerAppleViewController: LocationPickerViewInput { - func localize() { - doneBarButtonItem.title = "Done".localized(for: Self.self) - cancelBarButtonItem.title = "Cancel".localized(for: Self.self) - } -} - -// MARK: - IBActions -extension LocationPickerAppleViewController { - @IBAction func doneBarButtonItemAction(_ sender: Any) { - output.viewDidTriggerDone() - } - - @IBAction func cancelBarButtonItemAction(_ sender: Any) { - output.viewDidTriggerCancel() - } - - @IBAction func dismissBarButtonItemAction(_ sender: Any) { - output.viewDidTriggerDismiss() - } - - @IBAction func pinBarButtonItemAction(_ sender: Any) { - output.viewDidTriggerCurrentLocation() - } - - @objc func mapViewLongPressHandler(_ gr: UIGestureRecognizer) { - if gr.state == .began { - let point = gr.location(in: mapView) - let coordinate = mapView.convert(point, toCoordinateFrom: mapView) - output.viewDidLongPressOnMap(at: coordinate) - } - } - - @objc func mapViewTapHandler(_ gr: UIGestureRecognizer) { - searchBar.resignFirstResponder() - } -} - -// MARK: - View lifecycle -extension LocationPickerAppleViewController { - override func viewDidLoad() { - super.viewDidLoad() - setupLocalization() - configureViews() - updateUI() - } -} - -// MARK: - MKMapViewDelegate -extension LocationPickerAppleViewController: MKMapViewDelegate { - func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { - if let view = mapView.dequeueReusableAnnotationView(withIdentifier: annotationViewReuseIdentifier) { - return view - } else { - let view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotationViewReuseIdentifier) - view.canShowCallout = true - view.animatesDrop = true - return view - } - } - - func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) { - searchBar.resignFirstResponder() - } -} - -// MARK: - UISearchBarDelegate -extension LocationPickerAppleViewController: UISearchBarDelegate { - func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { - searchBar.resignFirstResponder() - if let query = searchBar.text { - output.viewDidEnterSearchQuery(query) - } - } -} - -// MARK: - View configuration -extension LocationPickerAppleViewController { - private func configureViews() { - if #available(iOS 13, *) { - let appearance = navigationController?.navigationBar.standardAppearance.copy() - navigationItem.standardAppearance = appearance - } - - searchBar = UISearchBar(frame: .zero) - searchBar.backgroundColor = .systemBackground - searchBar.searchTextField.leftView?.tintColor = .secondaryLabel - searchBar.delegate = self - navigationItem.titleView = searchBar - - let gr = UILongPressGestureRecognizer(target: self, - action: - #selector(LocationPickerAppleViewController.mapViewLongPressHandler(_:))) - gr.minimumPressDuration = 0.3 - mapView.addGestureRecognizer(gr) - - let tr = UITapGestureRecognizer(target: self, - action: #selector(LocationPickerAppleViewController.mapViewTapHandler(_:))) - mapView.addGestureRecognizer(tr) - } -} - -// MARK: - Update UI -extension LocationPickerAppleViewController { - private func updateUI() { - updateUISelectedLocation() - } - - private func updateUISelectedLocation() { - if isViewLoaded { - mapView.removeAnnotations(mapView.annotations) - if let location = selectedLocation { - let annotation = MKPointAnnotation() - annotation.coordinate = location.coordinate - annotation.title = location.cityCommaCountry - mapView.addAnnotation(annotation) - mapView.centerCoordinate = location.coordinate - mapView.selectAnnotation(annotation, animated: true) - searchBar.text = location.cityCommaCountry - navigationItem.rightBarButtonItems = [doneBarButtonItem] - } else { - navigationItem.rightBarButtonItems = [cancelBarButtonItem] - } - } - } -} diff --git a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/View/LocationPickerViewInput.swift b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/View/LocationPickerViewInput.swift deleted file mode 100644 index 023ad90c6..000000000 --- a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/View/LocationPickerViewInput.swift +++ /dev/null @@ -1,8 +0,0 @@ -import Foundation -import UIKit -import RuuviOntology -import RuuviLocalization - -protocol LocationPickerViewInput: UIViewController, Localizable { - var selectedLocation: Location? { get set } -} diff --git a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/View/LocationPickerViewOutput.swift b/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/View/LocationPickerViewOutput.swift deleted file mode 100644 index fc0ab1b8d..000000000 --- a/Modules/RuuviLocationPicker/Sources/RuuviLocationPicker/VMP/View/LocationPickerViewOutput.swift +++ /dev/null @@ -1,11 +0,0 @@ -import Foundation -import CoreLocation - -protocol LocationPickerViewOutput { - func viewDidTriggerDone() - func viewDidTriggerCancel() - func viewDidTriggerDismiss() - func viewDidEnterSearchQuery(_ query: String) - func viewDidLongPressOnMap(at coordinate: CLLocationCoordinate2D) - func viewDidTriggerCurrentLocation() -} diff --git a/Modules/RuuviLocationPicker/Tests/RuuviLocationPickerTests/RuuviLocationPickerTests.swift b/Modules/RuuviLocationPicker/Tests/RuuviLocationPickerTests/RuuviLocationPickerTests.swift deleted file mode 100644 index 2387c7142..000000000 --- a/Modules/RuuviLocationPicker/Tests/RuuviLocationPickerTests/RuuviLocationPickerTests.swift +++ /dev/null @@ -1,7 +0,0 @@ -import XCTest -@testable import RuuviLocationPicker - -final class RuuviLocationPickerTests: XCTestCase { - func testExample() { - } -} diff --git a/Modules/RuuviLocationPicker/target.yml b/Modules/RuuviLocationPicker/target.yml deleted file mode 100644 index 7b7afe921..000000000 --- a/Modules/RuuviLocationPicker/target.yml +++ /dev/null @@ -1,12 +0,0 @@ ---- -targets: - RuuviLocationPicker: - templates: - - Module - dependencies: - - package: Future - - target: RuuviOntology - - target: RuuviPresenters - - target: RuuviLocalization - - target: RuuviCore - - target: RuuviLocation diff --git a/Packages/RuuviAnalytics/Package.swift b/Packages/RuuviAnalytics/Package.swift index e64cd5710..34f1f2d03 100644 --- a/Packages/RuuviAnalytics/Package.swift +++ b/Packages/RuuviAnalytics/Package.swift @@ -19,7 +19,6 @@ let package = Package( .package(path: "../RuuviStorage"), .package(path: "../RuuviLocal"), .package(path: "../RuuviOntology"), - .package(path: "../RuuviVirtual"), .package(path: "../RuuviUser"), .package(path: "../RuuviService") ], @@ -35,7 +34,6 @@ let package = Package( "RuuviLocal", "RuuviStorage", "RuuviOntology", - "RuuviVirtual", "RuuviUser", "RuuviService" ]), diff --git a/Packages/RuuviAnalytics/RuuviAnalytics.podspec b/Packages/RuuviAnalytics/RuuviAnalytics.podspec index 9a30fb4ed..33464bc93 100644 --- a/Packages/RuuviAnalytics/RuuviAnalytics.podspec +++ b/Packages/RuuviAnalytics/RuuviAnalytics.podspec @@ -25,7 +25,6 @@ Pod::Spec.new do |s| ss.dependency 'RuuviAnalytics/Contract' ss.dependency 'RuuviStorage' ss.dependency 'RuuviLocal' - ss.dependency 'RuuviVirtual' ss.dependency 'RuuviUser' ss.dependency 'RuuviService/Alert' end diff --git a/Packages/RuuviAnalytics/Sources/RuuviAnalyticsImpl/RuuviAnalyticsImpl.swift b/Packages/RuuviAnalytics/Sources/RuuviAnalyticsImpl/RuuviAnalyticsImpl.swift index fa6bfbe18..13d15b369 100644 --- a/Packages/RuuviAnalytics/Sources/RuuviAnalyticsImpl/RuuviAnalyticsImpl.swift +++ b/Packages/RuuviAnalytics/Sources/RuuviAnalyticsImpl/RuuviAnalyticsImpl.swift @@ -6,7 +6,6 @@ import RuuviAnalytics import RuuviOntology import RuuviStorage import RuuviLocal -import RuuviVirtual import RuuviUser import RuuviService @@ -20,8 +19,6 @@ public final class RuuviAnalyticsImpl: RuuviAnalytics { case claimedTags(Int) // Quantity of offline tags[only local tags](if greater that 10, then "10+") case offlineTags(Int) - // Quantity of virtual tags(if greater that 10, then "10+") - case virtualTags(Int) // Quantity of tags using data format 2 case df2_tags(Int) // Quantity of tags using data format 3 @@ -77,8 +74,6 @@ public final class RuuviAnalyticsImpl: RuuviAnalytics { return "claimed_tags" case .offlineTags: return "offline_tags" - case .virtualTags: - return "virtual_tags" case .df2_tags: return "use_df2" case .df3_tags: @@ -129,20 +124,17 @@ public final class RuuviAnalyticsImpl: RuuviAnalytics { private let ruuviUser: RuuviUser private let ruuviStorage: RuuviStorage - private let virtualPersistence: VirtualPersistence private let settings: RuuviLocalSettings private let alertService: RuuviServiceAlert public init( ruuviUser: RuuviUser, ruuviStorage: RuuviStorage, - virtualPersistence: VirtualPersistence, settings: RuuviLocalSettings, alertService: RuuviServiceAlert ) { self.ruuviUser = ruuviUser self.ruuviStorage = ruuviStorage - self.virtualPersistence = virtualPersistence self.settings = settings self.alertService = alertService } @@ -179,9 +171,6 @@ public final class RuuviAnalyticsImpl: RuuviAnalytics { ruuviStorage.getOfflineTagsCount().on(success: { count in self.set(.offlineTags(count)) }) - virtualPersistence.readAll().on(success: { tags in - self.set(.virtualTags(tags.count)) - }) set(.backgroundScanEnabled(settings.saveHeartbeats)) set(.backgroundScanInterval(settings.saveHeartbeatsIntervalMinutes * 60)) set(.dashboardEnabled(false)) @@ -206,7 +195,6 @@ public final class RuuviAnalyticsImpl: RuuviAnalytics { case .addedTags(let count), .claimedTags(let count), .offlineTags(let count), - .virtualTags(let count), .df2_tags(let count), .df3_tags(let count), .df4_tags(let count), diff --git a/Packages/RuuviAnalytics/target.yml b/Packages/RuuviAnalytics/target.yml index a9773bfb5..43153def0 100644 --- a/Packages/RuuviAnalytics/target.yml +++ b/Packages/RuuviAnalytics/target.yml @@ -12,6 +12,5 @@ targets: - target: RuuviStorage - target: RuuviLocal - target: RuuviOntology - - target: RuuviVirtual - target: RuuviUser - target: RuuviService diff --git a/Packages/RuuviDaemon/Package.swift b/Packages/RuuviDaemon/Package.swift index 0a82c26d4..e7525a35d 100644 --- a/Packages/RuuviDaemon/Package.swift +++ b/Packages/RuuviDaemon/Package.swift @@ -22,15 +22,11 @@ let package = Package( .library( name: "RuuviDaemonRuuviTag", targets: ["RuuviDaemonRuuviTag"]), - .library( - name: "RuuviDaemonVirtualTag", - targets: ["RuuviDaemonVirtualTag"]) ], dependencies: [ .package(path: "../RuuviOntology"), .package(path: "../RuuviLocal"), .package(path: "../RuuviService"), - .package(path: "../RuuviVirtual"), .package(path: "../RuuviStorage"), .package(path: "../RuuviReactor"), .package(path: "../RuuviPool"), @@ -45,7 +41,6 @@ let package = Package( dependencies: [ "RuuviLocal", "RuuviService", - "RuuviVirtual", "RuuviStorage", "RuuviReactor", "RuuviPool", @@ -68,7 +63,6 @@ let package = Package( "RuuviDaemon", "RuuviNotifier", "RuuviOntology", - "RuuviVirtual" ] ), .target( @@ -78,13 +72,6 @@ let package = Package( "RuuviDaemonOperation" ] ), - .target( - name: "RuuviDaemonVirtualTag", - dependencies: [ - "RuuviDaemon", - "RuuviDaemonOperation" - ] - ), .target( name: "RuuviDaemonRuuviTag", dependencies: [ diff --git a/Packages/RuuviDaemon/RuuviDaemon.podspec b/Packages/RuuviDaemon/RuuviDaemon.podspec index a0a2d277c..42cdde703 100644 --- a/Packages/RuuviDaemon/RuuviDaemon.podspec +++ b/Packages/RuuviDaemon/RuuviDaemon.podspec @@ -42,7 +42,6 @@ Pod::Spec.new do |s| ss.dependency 'RuuviStorage' ss.dependency 'RuuviLocal' ss.dependency 'RuuviPool' - ss.dependency 'RuuviVirtual' ss.dependency 'RuuviOntology' ss.dependency 'RuuviNotifier' ss.dependency 'FutureX' @@ -63,16 +62,6 @@ Pod::Spec.new do |s| ss.dependency 'RuuviNotifier' end - s.subspec 'VirtualTag' do |ss| - ss.source_files = 'Sources/RuuviDaemonVirtualTag/**/*.{h,m,swift}', 'Sources/RuuviDaemonVirtualTag/*.{h,m,swift}' - ss.dependency 'RuuviDaemon/Contract' - ss.dependency 'BTKit' - ss.dependency 'RuuviLocal' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviVirtual' - ss.dependency 'RuuviNotifier' - end - s.test_spec 'Tests' do |test_spec| test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' end diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemon/BackgroundTaskService.swift b/Packages/RuuviDaemon/Sources/RuuviDaemon/BackgroundTaskService.swift deleted file mode 100644 index 4acc5e311..000000000 --- a/Packages/RuuviDaemon/Sources/RuuviDaemon/BackgroundTaskService.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation - -public protocol BackgroundTaskService { - func register() - func schedule() -} diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemon/PullWebDaemon.swift b/Packages/RuuviDaemon/Sources/RuuviDaemon/PullWebDaemon.swift deleted file mode 100644 index 692308224..000000000 --- a/Packages/RuuviDaemon/Sources/RuuviDaemon/PullWebDaemon.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation - -public protocol PullWebDaemon { - func start() - func stop() - func wakeUp() -} diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviDaemonError.swift b/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviDaemonError.swift index 1dccd1242..3250c5f8e 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviDaemonError.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviDaemonError.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviVirtual import RuuviStorage import RuuviReactor import RuuviPool @@ -7,7 +6,6 @@ import RuuviPersistence import BTKit public enum RuuviDaemonError: Error { - case virtualStorage(VirtualStorageError) case ruuviStorage(RuuviStorageError) case ruuviReactor(RuuviReactorError) case ruuviPool(RuuviPoolError) diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemon/VirtualTagDaemon.swift b/Packages/RuuviDaemon/Sources/RuuviDaemon/VirtualTagDaemon.swift deleted file mode 100644 index 0ce57e2c0..000000000 --- a/Packages/RuuviDaemon/Sources/RuuviDaemon/VirtualTagDaemon.swift +++ /dev/null @@ -1,14 +0,0 @@ -import Foundation - -extension Notification.Name { - public static let WebTagDaemonDidFail = Notification.Name("WebTagDaemonDidFail") -} - -public enum WebTagDaemonDidFailKey: String { - case error = "RuuviDaemonError" // RuuviDaemonError -} - -public protocol VirtualTagDaemon { - func start() - func stop() -} diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift index 83d6e204e..2886731e3 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift @@ -40,9 +40,8 @@ public final class BackgroundProcessServiceiOS13: BackgroundProcessService { schedule() let ruuviTags = dataPruningOperationsManager.ruuviTagPruningOperations() - let virtualTags = dataPruningOperationsManager.webTagPruningOperations() - Future.zip(ruuviTags, virtualTags).on(success: { (ruuviTagOperations, virtualTagsOperations) in - let operations = ruuviTagOperations + virtualTagsOperations + ruuviTags.on(success: { ruuviTagOperations in + let operations = ruuviTagOperations if operations.count > 0 { let queue = OperationQueue() queue.maxConcurrentOperationCount = 1 diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundTaskServiceiOS13.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundTaskServiceiOS13.swift deleted file mode 100644 index 05ed831ac..000000000 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundTaskServiceiOS13.swift +++ /dev/null @@ -1,63 +0,0 @@ -import Foundation -import BackgroundTasks -import RuuviDaemon -#if canImport(RuuviDaemonOperation) -import RuuviDaemonOperation -#endif - - -@available(iOS 13, *) -public final class BackgroundTaskServiceiOS13: BackgroundTaskService { - private let webTagOperationsManager: WebTagOperationsManager - - private let networkTagRefresh = "com.ruuvi.station.BackgroundTaskServiceiOS13.webTagRefresh" - - public init(webTagOperationsManager: WebTagOperationsManager) { - self.webTagOperationsManager = webTagOperationsManager - } - - public func register() { - BGTaskScheduler.shared.register(forTaskWithIdentifier: networkTagRefresh, using: nil) { task in - if let bgTask = task as? BGAppRefreshTask { - self.handleWebTagRefresh(task: bgTask) - } else { - fatalError() - } - } - } - - public func schedule() { - let request = BGAppRefreshTaskRequest(identifier: networkTagRefresh) - request.earliestBeginDate = Date(timeIntervalSinceNow: 5 * 60) - do { - try BGTaskScheduler.shared.submit(request) - } catch { - print("Could not schedule app refresh: \(error)") - } - } - - private func handleWebTagRefresh(task: BGAppRefreshTask) { - schedule() - webTagOperationsManager.alertsPullOperations() - .on(success: { [weak self] operations in - self?.enqueueOperations(operations, task: task) - }) - } - - private func enqueueOperations(_ operations: [Operation], task: BGAppRefreshTask) { - if operations.count > 0 { - let queue = OperationQueue() - queue.maxConcurrentOperationCount = 1 - let lastOperation = operations.last! - lastOperation.completionBlock = { - task.setTaskCompleted(success: !lastOperation.isCancelled) - } - queue.addOperations(operations, waitUntilFinished: false) - task.expirationHandler = { - queue.cancelAllOperations() - } - } else { - task.setTaskCompleted(success: true) - } - } -} diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/DataPruningOperationsManager.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/DataPruningOperationsManager.swift index 667bab2aa..1552f81bb 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/DataPruningOperationsManager.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/DataPruningOperationsManager.swift @@ -3,46 +3,23 @@ import Future import RuuviStorage import RuuviLocal import RuuviPool -import RuuviVirtual import RuuviDaemon public final class DataPruningOperationsManager { private let settings: RuuviLocalSettings - private let virtualStorage: VirtualStorage - private let virtualRepository: VirtualRepository private let ruuviStorage: RuuviStorage private let ruuviPool: RuuviPool public init( settings: RuuviLocalSettings, - virtualStorage: VirtualStorage, - virtualRepository: VirtualRepository, ruuviStorage: RuuviStorage, ruuviPool: RuuviPool ) { self.settings = settings - self.virtualStorage = virtualStorage - self.virtualRepository = virtualRepository self.ruuviStorage = ruuviStorage self.ruuviPool = ruuviPool } - public func webTagPruningOperations() -> Future<[Operation], RuuviDaemonError> { - let promise = Promise<[Operation], RuuviDaemonError>() - virtualStorage.readAll().on(success: { [weak self] virtualTags in - guard let sSelf = self else { return } - let ops = virtualTags.map({ - WebTagDataPruningOperation(id: $0.id, - virtualTagTank: sSelf.virtualRepository, - settings: sSelf.settings) - }) - promise.succeed(value: ops) - }, failure: { error in - promise.fail(error: .virtualStorage(error)) - }) - return promise.future - } - public func ruuviTagPruningOperations() -> Future<[Operation], RuuviDaemonError> { let promise = Promise<[Operation], RuuviDaemonError>() ruuviStorage.readAll().on(success: { [weak self] ruuviTags in diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/WebTagDataPruningOperation.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/WebTagDataPruningOperation.swift deleted file mode 100644 index 328101f5b..000000000 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/WebTagDataPruningOperation.swift +++ /dev/null @@ -1,31 +0,0 @@ -import Foundation -import RuuviLocal -import RuuviVirtual - -class WebTagDataPruningOperation: AsyncOperation { - private var id: String - private var settings: RuuviLocalSettings - private var virtualTagTank: VirtualRepository - - init( - id: String, - virtualTagTank: VirtualRepository, - settings: RuuviLocalSettings - ) { - self.id = id - self.virtualTagTank = virtualTagTank - self.settings = settings - } - - override func main() { - let offset = settings.dataPruningOffsetHours - let date = Calendar.current.date(byAdding: .hour, - value: -offset, - to: Date()) ?? Date() - virtualTagTank.deleteAllRecords(id, before: date).on(failure: { error in - print(error.localizedDescription) - }, completion: { - self.state = .finished - }) - } -} diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/WebTag/CurrentWebTagRefreshDataOperation.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/WebTag/CurrentWebTagRefreshDataOperation.swift deleted file mode 100644 index 9ba31e48a..000000000 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/WebTag/CurrentWebTagRefreshDataOperation.swift +++ /dev/null @@ -1,42 +0,0 @@ -import Foundation -import RuuviOntology -import RuuviVirtual -import RuuviNotifier - -class CurrentWebTagRefreshDataOperation: AsyncOperation { - private var sensor: VirtualSensor - private var provider: VirtualProvider - private var weatherProviderService: VirtualProviderService - private var alertService: RuuviNotifier - private var webTagPersistence: VirtualPersistence! - - init(sensor: VirtualSensor, - provider: VirtualProvider, - weatherProviderService: VirtualProviderService, - alertService: RuuviNotifier, - webTagPersistence: VirtualPersistence) { - self.sensor = sensor - self.provider = provider - self.weatherProviderService = weatherProviderService - self.alertService = alertService - self.webTagPersistence = webTagPersistence - } - - override func main() { - weatherProviderService.loadCurrentLocationData(from: provider).on(success: { [weak self] response in - guard let sSelf = self else { return } - sSelf.alertService.process(data: response.1, for: sSelf.sensor) - let persist = sSelf.webTagPersistence.persist(currentLocation: response.0, data: response.1) - persist.on(success: { [weak sSelf] _ in - sSelf?.state = .finished - }, failure: { [weak sSelf] error in - print(error.localizedDescription) - sSelf?.state = .finished - }) - }, failure: { [weak self] error in - print(error.localizedDescription) - self?.state = .finished - }) - } - -} diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/WebTag/WebTagOperationsManager.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/WebTag/WebTagOperationsManager.swift deleted file mode 100644 index 18bc216d4..000000000 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/WebTag/WebTagOperationsManager.swift +++ /dev/null @@ -1,64 +0,0 @@ -import Foundation -import Future -import RuuviService -import RuuviVirtual -import RuuviNotifier -import RuuviDaemon - -public final class WebTagOperationsManager { - private let virtualProviderService: VirtualProviderService - private let alertService: RuuviServiceAlert - private let ruuviNotifier: RuuviNotifier - private let virtualStorage: VirtualStorage - private let virtualPersistence: VirtualPersistence - - public init( - virtualProviderService: VirtualProviderService, - alertService: RuuviServiceAlert, - alertHandler: RuuviNotifier, - virtualStorage: VirtualStorage, - virtualPersistence: VirtualPersistence - ) { - self.virtualProviderService = virtualProviderService - self.alertService = alertService - self.ruuviNotifier = alertHandler - self.virtualStorage = virtualStorage - self.virtualPersistence = virtualPersistence - } - - public func alertsPullOperations() -> Future<[Operation], RuuviDaemonError> { - let promise = Promise<[Operation], RuuviDaemonError>() - virtualStorage.readAll().on(success: { [weak self] virtualTags in - guard let sSelf = self else { return } - var operations = [Operation]() - virtualTags.forEach { virtualTag in - if sSelf.alertService.hasRegistrations(for: virtualTag) { - if let location = virtualTag.loc { - let operation = WebTagRefreshDataOperation( - sensor: virtualTag, - location: location, - provider: virtualTag.provider, - weatherProviderService: sSelf.virtualProviderService, - alertService: sSelf.ruuviNotifier, - webTagPersistence: sSelf.virtualPersistence - ) - operations.append(operation) - } else { - let operation = CurrentWebTagRefreshDataOperation( - sensor: virtualTag, - provider: virtualTag.provider, - weatherProviderService: sSelf.virtualProviderService, - alertService: sSelf.ruuviNotifier, - webTagPersistence: sSelf.virtualPersistence - ) - operations.append(operation) - } - } - } - promise.succeed(value: operations) - }, failure: { error in - promise.fail(error: .virtualStorage(error)) - }) - return promise.future - } -} diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/WebTag/WebTagRefreshDataOperation.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/WebTag/WebTagRefreshDataOperation.swift deleted file mode 100644 index 0b926feab..000000000 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/WebTag/WebTagRefreshDataOperation.swift +++ /dev/null @@ -1,47 +0,0 @@ -import Foundation -import CoreLocation -import RuuviOntology -import RuuviVirtual -import RuuviNotifier - -class WebTagRefreshDataOperation: AsyncOperation { - private var sensor: VirtualSensor - private var location: Location - private var provider: VirtualProvider - private var weatherProviderService: VirtualProviderService - private var alertService: RuuviNotifier - private var webTagPersistence: VirtualPersistence! - - init(sensor: VirtualSensor, - location: Location, - provider: VirtualProvider, - weatherProviderService: VirtualProviderService, - alertService: RuuviNotifier, - webTagPersistence: VirtualPersistence) { - self.sensor = sensor - self.location = location - self.provider = provider - self.weatherProviderService = weatherProviderService - self.alertService = alertService - self.webTagPersistence = webTagPersistence - } - - override func main() { - weatherProviderService.loadData(coordinate: location.coordinate, provider: provider).on(success: { - [weak self] data in - guard let sSelf = self else { return } - sSelf.alertService.process(data: data, for: sSelf.sensor) - let persist = sSelf.webTagPersistence.persist(location: sSelf.location, data: data) - persist.on(success: { [weak sSelf] _ in - sSelf?.state = .finished - }, failure: { [weak sSelf] error in - print(error.localizedDescription) - sSelf?.state = .finished - }) - }, failure: { [weak self] error in - print(error.localizedDescription) - self?.state = .finished - }) - } - -} diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Heartbeat/RuuviTagHeartbeatDaemonBTKit.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Heartbeat/RuuviTagHeartbeatDaemonBTKit.swift index e0e8b3d05..aba8db255 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Heartbeat/RuuviTagHeartbeatDaemonBTKit.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Heartbeat/RuuviTagHeartbeatDaemonBTKit.swift @@ -9,6 +9,7 @@ import RuuviService import RuuviNotification import RuuviNotifier import RuuviDaemon + // swiftlint:disable file_length public final class RuuviTagHeartbeatDaemonBTKit: RuuviDaemonWorker, RuuviTagHeartbeatDaemon { private let background: BTBackground @@ -20,7 +21,6 @@ public final class RuuviTagHeartbeatDaemonBTKit: RuuviDaemonWorker, RuuviTagHear private let alertService: RuuviServiceAlert private let alertHandler: RuuviNotifier private let settings: RuuviLocalSettings - private let pullWebDaemon: PullWebDaemon private let titles: RuuviTagHeartbeatDaemonTitles private var ruuviTags = [AnyRuuviTagSensor]() @@ -46,7 +46,6 @@ public final class RuuviTagHeartbeatDaemonBTKit: RuuviDaemonWorker, RuuviTagHear alertService: RuuviServiceAlert, alertHandler: RuuviNotifier, settings: RuuviLocalSettings, - pullWebDaemon: PullWebDaemon, titles: RuuviTagHeartbeatDaemonTitles ) { self.background = background @@ -58,7 +57,6 @@ public final class RuuviTagHeartbeatDaemonBTKit: RuuviDaemonWorker, RuuviTagHear self.alertService = alertService self.alertHandler = alertHandler self.settings = settings - self.pullWebDaemon = pullWebDaemon self.titles = titles super.init() connectionAddedToken = NotificationCenter @@ -202,7 +200,6 @@ extension RuuviTagHeartbeatDaemonBTKit { private func heartbeatHandler() -> ((RuuviTagHeartbeatDaemonBTKit, BTDevice) -> Void)? { return { observer, device in - observer.pullWebDaemon.wakeUp() if let ruuviTag = device.ruuvi?.tag { var sensorSettings: SensorSettings? if let ruuviTagSensor = observer.ruuviTags diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/PullWeb/PullWebDaemonOperations.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/PullWeb/PullWebDaemonOperations.swift deleted file mode 100644 index b1a54e875..000000000 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/PullWeb/PullWebDaemonOperations.swift +++ /dev/null @@ -1,71 +0,0 @@ -import Foundation -import RuuviLocal -import RuuviDaemon -#if canImport(RuuviDaemonOperation) -import RuuviDaemonOperation -#endif - -public final class PullWebDaemonOperations: RuuviDaemonWorker, PullWebDaemon { - private let settings: RuuviLocalSettings - private let webTagOperationsManager: WebTagOperationsManager - - public init( - settings: RuuviLocalSettings, - webTagOperationsManager: WebTagOperationsManager - ) { - self.settings = settings - self.webTagOperationsManager = webTagOperationsManager - } - - @UserDefault("PullWebDaemonOperations.webTagLastPullDate", defaultValue: Date()) - private var webTagLastPullDate: Date - private var pullTimer: Timer? - - @objc public func wakeUp() { - if needsToPullWebTagData() { - pullWebTagData() - webTagLastPullDate = Date() - } - } - - public func start() { - start { [weak self] in - guard let sSelf = self else { return } - let timer = Timer.scheduledTimer(timeInterval: 60, - target: sSelf, - selector: #selector(PullWebDaemonOperations.wakeUp), - userInfo: nil, - repeats: true) - RunLoop.current.add(timer, forMode: .common) - sSelf.pullTimer = timer - } - } - - public func stop() { - perform(#selector(PullWebDaemonOperations.stopDaemon), - on: thread, - with: nil, - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) - } - - @objc private func stopDaemon() { - pullTimer?.invalidate() - stopWork() - } - - private func needsToPullWebTagData() -> Bool { - let elapsed = Int(Date().timeIntervalSince(webTagLastPullDate)) - return elapsed > settings.webPullIntervalMinutes * 60 - } - - private func pullWebTagData() { - webTagOperationsManager.alertsPullOperations() - .on(success: { operations in - let queue = OperationQueue() - queue.maxConcurrentOperationCount = 1 - queue.addOperations(operations, waitUntilFinished: false) - }) - } - -} diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/UserDefault.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/UserDefault.swift deleted file mode 100644 index 3ef972d50..000000000 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/UserDefault.swift +++ /dev/null @@ -1,21 +0,0 @@ -import Foundation - -@propertyWrapper -struct UserDefault { - let key: String - let defaultValue: T - - init(_ key: String, defaultValue: T) { - self.key = key - self.defaultValue = defaultValue - } - - var wrappedValue: T { - get { - return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue - } - set { - UserDefaults.standard.set(newValue, forKey: key) - } - } -} diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/WebTag/VirtualTagDaemonImpl.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/WebTag/VirtualTagDaemonImpl.swift deleted file mode 100644 index a9cd59c15..000000000 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonVirtualTag/WebTag/VirtualTagDaemonImpl.swift +++ /dev/null @@ -1,216 +0,0 @@ -import Foundation -import CoreLocation -import RuuviLocal -import RuuviOntology -import RuuviVirtual -import RuuviNotifier -import RuuviDaemon - -public final class VirtualTagDaemonImpl: RuuviDaemonWorker, VirtualTagDaemon { - private let virtualService: VirtualService - private let settings: RuuviLocalSettings - private let virtualPersistence: VirtualPersistence - private let alertService: RuuviNotifier - private let virtualReactor: VirtualReactor - - private var token: VirtualReactorToken? - private var wsTokens = [VirtualToken]() - private var virtualTags = [AnyVirtualTagSensor]() - private var isOnToken: NSObjectProtocol? - private var intervalToken: NSObjectProtocol? - - private var pullInterval: TimeInterval { - return TimeInterval(settings.webTagDaemonIntervalMinutes * 60) - } - - deinit { - autoreleasepool { - wsTokens.forEach({ $0.invalidate() }) - wsTokens.removeAll() - token?.invalidate() - if let isOnToken = isOnToken { - NotificationCenter.default.removeObserver(isOnToken) - } - if let intervalToken = intervalToken { - NotificationCenter.default.removeObserver(intervalToken) - } - } - } - - public init( - virtualService: VirtualService, - settings: RuuviLocalSettings, - virtualPersistence: VirtualPersistence, - alertService: RuuviNotifier, - virtualReactor: VirtualReactor - ) { - self.virtualService = virtualService - self.settings = settings - self.virtualPersistence = virtualPersistence - self.alertService = alertService - self.virtualReactor = virtualReactor - super.init() - isOnToken = NotificationCenter - .default - .addObserver(forName: .isWebTagDaemonOnDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - guard let sSelf = self else { return } - if sSelf.settings.isWebTagDaemonOn { - sSelf.start() - } else { - sSelf.stop() - } - }) - } - - public func start() { - start { [weak self] in - self?.stopDaemon() - self?.token?.invalidate() - self?.token = self?.virtualReactor.observe({ [weak self] change in - switch change { - case .initial(let sensors): - self?.virtualTags = sensors - self?.restartPulling(fire: true) - case .insert(let sensor): - self?.virtualTags.append(sensor) - self?.restartPulling(fire: true) - case .delete(let sensor): - self?.virtualTags.removeAll(where: { $0.id == sensor.id }) - self?.restartPulling(fire: true) - case .update(let sensor): - if let index = self?.virtualTags.firstIndex(of: sensor) { - self?.virtualTags[index] = sensor - } - self?.restartPulling(fire: true) - case .error(let error): - print(error.localizedDescription) - } - }) - - self?.intervalToken = NotificationCenter - .default - .addObserver(forName: .WebTagDaemonIntervalDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - guard let sSelf = self else { return } - sSelf.perform(#selector(VirtualTagDaemonImpl.restartPulling(fire:)), - on: sSelf.thread, - with: false, - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) - }) - } - } - - public func stop() { - perform(#selector(VirtualTagDaemonImpl.stopDaemon), - on: thread, - with: nil, - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) - stopWork() - } - - @objc private func stopDaemon() { - autoreleasepool { - wsTokens.forEach({ $0.invalidate() }) - wsTokens.removeAll() - token?.invalidate() - token = nil - if let intervalToken = intervalToken { - NotificationCenter.default.removeObserver(intervalToken) - } - } - } - - @objc private func restartPulling(fire: Bool) { - wsTokens.forEach({ $0.invalidate() }) - wsTokens.removeAll() - - restartPullingCurrentLocation(virtualTags: virtualTags, fire: fire) - restartPullingFixedLocations(virtualTags: virtualTags, fire: fire) - } - - private func restartPullingFixedLocations( - virtualTags: [AnyVirtualTagSensor], - fire: Bool - ) { - let virtualTagsWithLocation = virtualTags.filter({ $0.loc != nil }) - for virtualTag in virtualTagsWithLocation { - guard let location = virtualTag.loc else { return } - wsTokens.append( - virtualService.observeData( - self, - coordinate: location.coordinate, - provider: virtualTag.provider, - interval: pullInterval, - fire: fire, - closure: { (observer, data, error) in - if let data = data { - observer.virtualPersistence.persist( - location: location, - data: data - ) - observer.alertService.process( - data: data, - for: virtualTag - ) - } else if let error = error { - observer.post(error: error) - } - } - ) - ) - } - } - - private func restartPullingCurrentLocation( - virtualTags: [AnyVirtualTagSensor], - fire: Bool - ) { - let virtualTagsWithoutLocation = virtualTags.filter({ $0.loc == nil }) - for provider in VirtualProvider.allCases { - // swiftlint:disable:next for_where - if virtualTagsWithoutLocation.contains(where: { $0.provider == provider }) { - wsTokens.append( - virtualService.observeCurrentLocationData( - self, - provider: provider, - interval: pullInterval, - fire: fire, - closure: { (observer, data, location, error) in - if let data = data, let location = location { - observer.virtualPersistence.persist( - currentLocation: location, - data: data - ) - virtualTagsWithoutLocation.forEach({ - observer.alertService.process( - data: data, - for: $0 - ) - }) - } else if let error = error { - observer.post(error: error) - } - } - ) - ) - } - } - } - - private func post(error: Error) { - DispatchQueue.main.async { - NotificationCenter - .default - .post(name: .WebTagDaemonDidFail, - object: nil, - userInfo: [WebTagDaemonDidFailKey.error: error]) - } - } -} diff --git a/Packages/RuuviDaemon/target.yml b/Packages/RuuviDaemon/target.yml index 9eef05048..57e3fcd05 100644 --- a/Packages/RuuviDaemon/target.yml +++ b/Packages/RuuviDaemon/target.yml @@ -10,7 +10,6 @@ targets: - target: RuuviOntology - target: RuuviLocal - target: RuuviService - - target: RuuviVirtual - target: RuuviStorage - target: RuuviReactor - target: RuuviPool diff --git a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift index fb74760bd..e359b793a 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift @@ -10,8 +10,6 @@ extension Notification.Name { public static let PressureUnitAccuracyChange = Notification.Name("Settings.PressureUnitAccuracyChange") public static let LanguageDidChange = Notification.Name("LanguageDidChange") public static let isAdvertisementDaemonOnDidChange = Notification.Name("isAdvertisementDaemonOnDidChange") - public static let isWebTagDaemonOnDidChange = Notification.Name("isWebTagDaemonOnDidChange") - public static let WebTagDaemonIntervalDidChange = Notification.Name("WebTagDaemonIntervalDidChange") public static let DownsampleOnDidChange = Notification.Name("DownsampleOnDidChange") public static let ChartDurationHourDidChange = Notification.Name("ChartDurationHourDidChange") public static let ChartDrawDotsOnDidChange = Notification.Name("ChartDrawDotsOnDidChange") @@ -57,8 +55,6 @@ public protocol RuuviLocalSettings { var cloudProfileLanguageCode: String? { get set } var isAdvertisementDaemonOn: Bool { get set } var advertisementDaemonIntervalMinutes: Int { get set } - var isWebTagDaemonOn: Bool { get set } - var webTagDaemonIntervalMinutes: Int { get set } var connectionTimeout: TimeInterval { get set } var serviceTimeout: TimeInterval { get set } var cardsSwipeHintWasShown: Bool { get set } diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift index b4027c3ec..e573bd897 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift @@ -251,29 +251,6 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { } } - @UserDefault("SettingsUserDegaults.isWebTagDaemonOn", defaultValue: true) - var isWebTagDaemonOn: Bool { - didSet { - NotificationCenter - .default - .post(name: .isWebTagDaemonOnDidChange, - object: self, - userInfo: nil) - } - } - - @UserDefault("SettingsUserDegaults.webTagDaemonIntervalMinutes", defaultValue: 60) - var webTagDaemonIntervalMinutes: Int { - - didSet { - NotificationCenter - .default - .post(name: .WebTagDaemonIntervalDidChange, - object: self, - userInfo: nil) - } - } - @UserDefault("SettingsUserDegaults.connectionTimeout", defaultValue: 30) var connectionTimeout: TimeInterval diff --git a/Packages/RuuviLocation/.gitignore b/Packages/RuuviLocation/.gitignore deleted file mode 100644 index bb460e7be..000000000 --- a/Packages/RuuviLocation/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.DS_Store -/.build -/Packages -/*.xcodeproj -xcuserdata/ -DerivedData/ -.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata diff --git a/Packages/RuuviLocation/Info.plist b/Packages/RuuviLocation/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviLocation/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviLocation/Package.swift b/Packages/RuuviLocation/Package.swift deleted file mode 100644 index 1247afef7..000000000 --- a/Packages/RuuviLocation/Package.swift +++ /dev/null @@ -1,43 +0,0 @@ -// swift-tools-version:5.9 -// The swift-tools-version declares the minimum version of Swift required to build this package. - -import PackageDescription - -let package = Package( - name: "RuuviLocation", - platforms: [.macOS(.v10_15), .iOS(.v13)], - products: [ - .library( - name: "RuuviLocation", - targets: ["RuuviLocation"] - ), - .library( - name: "RuuviLocationService", - targets: ["RuuviLocationService"] - ) - ], - dependencies: [ - .package(url: "https://github.com/kean/Future", .exact("1.3.0")), - .package(path: "../RuuviOntology") - ], - targets: [ - .target( - name: "RuuviLocation", - dependencies: [ - "Future", - "RuuviOntology" - ] - ), - .target( - name: "RuuviLocationService", - dependencies: [ - "RuuviLocation", - "Future", - "RuuviOntology" - ] - ), - .testTarget( - name: "RuuviLocationTests", - dependencies: ["RuuviLocation"]) - ] -) diff --git a/Packages/RuuviLocation/README.md b/Packages/RuuviLocation/README.md deleted file mode 100644 index a552b56e6..000000000 --- a/Packages/RuuviLocation/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# RuuviLocation - -A description of this package. diff --git a/Packages/RuuviLocation/RuuviLocation.podspec b/Packages/RuuviLocation/RuuviLocation.podspec deleted file mode 100644 index 91a8d0a70..000000000 --- a/Packages/RuuviLocation/RuuviLocation.podspec +++ /dev/null @@ -1,34 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviLocation' - s.version = '0.0.1' - s.summary = 'Ruuvi Location' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviLocation/**/*.{h,m,swift}', 'Sources/RuuviLocation/*.{h,m,swift}' - ss.dependency 'FutureX' - ss.dependency 'RuuviOntology' - end - - s.subspec 'Service' do |ss| - ss.source_files = 'Sources/RuuviLocationService/**/*.{h,m,swift}', 'Sources/RuuviLocationService/*.{h,m,swift}' - ss.dependency 'RuuviLocation/Contract' - ss.dependency 'RuuviOntology' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end - - diff --git a/Packages/RuuviLocation/Sources/RuuviLocation/RuuviLocationError.swift b/Packages/RuuviLocation/Sources/RuuviLocation/RuuviLocationError.swift deleted file mode 100644 index cb2d7faa5..000000000 --- a/Packages/RuuviLocation/Sources/RuuviLocation/RuuviLocationError.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation - -public enum RuuviLocationError: Error { - case map(Error) - case callbackErrorAndResultAreNil -} diff --git a/Packages/RuuviLocation/Sources/RuuviLocation/RuuviLocationService.swift b/Packages/RuuviLocation/Sources/RuuviLocation/RuuviLocationService.swift deleted file mode 100644 index 4dfd3eb7a..000000000 --- a/Packages/RuuviLocation/Sources/RuuviLocation/RuuviLocationService.swift +++ /dev/null @@ -1,14 +0,0 @@ -import Foundation -import Future -import CoreLocation -import RuuviOntology - -public protocol RuuviLocationService { - func search( - query: String - ) -> Future<[Location], RuuviLocationError> - - func reverseGeocode( - coordinate: CLLocationCoordinate2D - ) -> Future<[Location], RuuviLocationError> -} diff --git a/Packages/RuuviLocation/Sources/RuuviLocationService/LocationPersistence/KeyedArchiver.swift b/Packages/RuuviLocation/Sources/RuuviLocationService/LocationPersistence/KeyedArchiver.swift deleted file mode 100644 index 4109fe47d..000000000 --- a/Packages/RuuviLocation/Sources/RuuviLocationService/LocationPersistence/KeyedArchiver.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Foundation - -struct KeyedArchiver { - public static func archive(object: Any) -> Data? { - if #available(iOS 12.0, *) { - return try? NSKeyedArchiver.archivedData(withRootObject: object, requiringSecureCoding: false) - } else { - return NSKeyedArchiver.archivedData(withRootObject: object) - } - } - - public static func unarchive(_ data: Data, with type: T.Type) -> T? { - if #available(iOS 12.0, *) { - return try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? T - } else { - return NSKeyedUnarchiver.unarchiveObject(with: data) as? T - } - } -} diff --git a/Packages/RuuviLocation/Sources/RuuviLocationService/LocationPersistence/LocationAppleClass.swift b/Packages/RuuviLocation/Sources/RuuviLocationService/LocationPersistence/LocationAppleClass.swift deleted file mode 100644 index 1afb2dfae..000000000 --- a/Packages/RuuviLocation/Sources/RuuviLocationService/LocationPersistence/LocationAppleClass.swift +++ /dev/null @@ -1,48 +0,0 @@ -import Foundation -import CoreLocation -import RuuviOntology - -class LocationAppleClass: NSObject, NSCoding { - var city: String? - var state: String? - var country: String? - var latitude: Double - var longitude: Double - - init(location: Location) { - city = location.city - state = location.state - country = location.country - latitude = location.coordinate.latitude - longitude = location.coordinate.longitude - } - - required init?(coder: NSCoder) { - city = coder.decodeObject(forKey: "city") as? String - state = coder.decodeObject(forKey: "state") as? String - country = coder.decodeObject(forKey: "country") as? String - latitude = coder.decodeDouble(forKey: "latitude") - longitude = coder.decodeDouble(forKey: "longitude") - } - - func encode(with coder: NSCoder) { - coder.encode(city, forKey: "city") - coder.encode(state, forKey: "state") - coder.encode(country, forKey: "country") - coder.encode(latitude, forKey: "latitude") - coder.encode(longitude, forKey: "longitude") - } -} -extension LocationAppleClass: Location { - var coordinate: CLLocationCoordinate2D { - return CLLocationCoordinate2D(latitude: latitude, - longitude: longitude) - } - - var asStruct: LocationApple { - return LocationApple(city: city, - state: state, - country: country, - coordinate: coordinate) - } -} diff --git a/Packages/RuuviLocation/Sources/RuuviLocationService/LocationPersistence/LocationPersistence.swift b/Packages/RuuviLocation/Sources/RuuviLocationService/LocationPersistence/LocationPersistence.swift deleted file mode 100644 index 54e7b583e..000000000 --- a/Packages/RuuviLocation/Sources/RuuviLocationService/LocationPersistence/LocationPersistence.swift +++ /dev/null @@ -1,8 +0,0 @@ -import Foundation -import CoreLocation -import RuuviOntology - -protocol LocationPersistence { - func locations(for coordinate: CLLocationCoordinate2D) -> [Location]? - func setLocations(_ locations: [Location], for coordinate: CLLocationCoordinate2D) -} diff --git a/Packages/RuuviLocation/Sources/RuuviLocationService/LocationPersistence/LocationPersistenceImpl.swift b/Packages/RuuviLocation/Sources/RuuviLocationService/LocationPersistence/LocationPersistenceImpl.swift deleted file mode 100644 index fcbc40634..000000000 --- a/Packages/RuuviLocation/Sources/RuuviLocationService/LocationPersistence/LocationPersistenceImpl.swift +++ /dev/null @@ -1,56 +0,0 @@ -import Foundation -import CoreLocation -import RuuviOntology - -fileprivate extension Location { - var asClass: LocationAppleClass { - return LocationAppleClass(location: self) - } -} - -final class LocationPersistenceImpl: LocationPersistence { - private let regionsKey: String = "LocationPersistence.regions" - private let regionKey: String = "LocationPersistence.region." - - func locations(for coordinate: CLLocationCoordinate2D) -> [Location]? { - guard let region = regions.first(where: {$0.contains(coordinate)}) else { - return nil - } - let key = regionKey + region.identifier - guard let data = UserDefaults.standard.data(forKey: key), - let locations = KeyedArchiver.unarchive(data, with: [LocationAppleClass].self) else { - return nil - } - return locations.map({ $0.asStruct }) - } - - func setLocations(_ locations: [Location], for coordinate: CLLocationCoordinate2D) { - let region: CLCircularRegion - if let existedRegion = regions.first(where: {$0.contains(coordinate)}) { - region = existedRegion - } else { - region = CLCircularRegion(center: coordinate, radius: 1000.0, identifier: UUID().uuidString) - regions.append(region) - } - let key = regionKey + region.identifier - let array = NSArray(array: locations.map({$0.asClass})) - let data: Data? = KeyedArchiver.archive(object: array) - UserDefaults.standard.set(data, forKey: key) - } -} -// MARK: - Private -extension LocationPersistenceImpl { - private var regions: [CLCircularRegion] { - get { - guard let data = UserDefaults.standard.data(forKey: regionsKey), - let regionsPersisted = KeyedArchiver.unarchive(data, with: [CLCircularRegion].self) else { - return [] - } - return regionsPersisted - } - set { - let data = KeyedArchiver.archive(object: newValue) - UserDefaults.standard.set(data, forKey: regionsKey) - } - } -} diff --git a/Packages/RuuviLocation/Sources/RuuviLocationService/RuuviLocationServiceApple.swift b/Packages/RuuviLocation/Sources/RuuviLocationService/RuuviLocationServiceApple.swift deleted file mode 100644 index 64065bb17..000000000 --- a/Packages/RuuviLocation/Sources/RuuviLocationService/RuuviLocationServiceApple.swift +++ /dev/null @@ -1,92 +0,0 @@ -import Foundation -import MapKit -import Future -import RuuviOntology -import RuuviLocation - -struct LocationApple: Location { - var city: String? - var state: String? - var country: String? - var coordinate: CLLocationCoordinate2D -} - -public final class RuuviLocationServiceApple: RuuviLocationService { - private let locationPersistence = LocationPersistenceImpl() - - public init() {} - - public func search(query: String) -> Future<[Location], RuuviLocationError> { - let promise = Promise<[Location], RuuviLocationError>() - let request = MKLocalSearch.Request() - request.naturalLanguageQuery = query - let search = MKLocalSearch(request: request) - search.start { (response, error) in - guard let response = response else { - if let error = error { - promise.fail(error: .map(error)) - } else { - promise.fail(error: .callbackErrorAndResultAreNil) - } - return - } - var locations = [LocationApple]() - for item in response.mapItems { - locations.append( - LocationApple( - city: item.placemark.locality, - state: item.placemark.administrativeArea, - country: item.placemark.country, - coordinate: item.placemark.coordinate - ) - ) - } - promise.succeed(value: locations) - } - return promise.future - } - - public func reverseGeocode( - coordinate: CLLocationCoordinate2D - ) -> Future<[Location], RuuviLocationError> { - if let locations = locationPersistence.locations(for: coordinate) { - let promise = Promise<[Location], RuuviLocationError>() - promise.succeed(value: locations) - return promise.future - } else { - return getReverseGeocodeLocation(coordinate: coordinate).future - } - } -} -// MARK: - Private -extension RuuviLocationServiceApple { - private func getReverseGeocodeLocation( - coordinate: CLLocationCoordinate2D - ) -> Promise<[Location], RuuviLocationError> { - let promise = Promise<[Location], RuuviLocationError>() - let location = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude) - let geoCoder = CLGeocoder() - let handler: CLGeocodeCompletionHandler = { [weak self] (placemarks, error) in - guard let placemarks = placemarks else { - if let error = error { - promise.fail(error: .map(error)) - } else { - promise.fail(error: .callbackErrorAndResultAreNil) - } - return - } - - var locations = [LocationApple]() - for placemark in placemarks { - locations.append(LocationApple(city: placemark.locality, - state: placemark.administrativeArea, - country: placemark.country, - coordinate: placemark.location?.coordinate ?? coordinate)) - } - self?.locationPersistence.setLocations(locations, for: coordinate) - promise.succeed(value: locations) - } - geoCoder.reverseGeocodeLocation(location, completionHandler: handler) - return promise - } -} diff --git a/Packages/RuuviLocation/Tests/RuuviLocationTests/RuuviLocationTests.swift b/Packages/RuuviLocation/Tests/RuuviLocationTests/RuuviLocationTests.swift deleted file mode 100644 index b31bead8e..000000000 --- a/Packages/RuuviLocation/Tests/RuuviLocationTests/RuuviLocationTests.swift +++ /dev/null @@ -1,7 +0,0 @@ -import XCTest -@testable import RuuviLocation - -final class RuuviLocationTests: XCTestCase { - func testExample() { - } -} diff --git a/Packages/RuuviLocation/target.yml b/Packages/RuuviLocation/target.yml deleted file mode 100644 index ffe473a34..000000000 --- a/Packages/RuuviLocation/target.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -targets: - RuuviLocation: - templates: - - Framework - dependencies: - - package: Future - - target: RuuviOntology diff --git a/Packages/RuuviMigration/Package.swift b/Packages/RuuviMigration/Package.swift index ee361f28f..2021332b6 100644 --- a/Packages/RuuviMigration/Package.swift +++ b/Packages/RuuviMigration/Package.swift @@ -19,7 +19,6 @@ let package = Package( .package(path: "../RuuviLocal"), .package(path: "../RuuviPool"), .package(path: "../RuuviContext"), - .package(path: "../RuuviVirtual"), .package(path: "../RuuviStorage"), .package(path: "../RuuviService") ], @@ -34,11 +33,9 @@ let package = Package( "RuuviLocal", "RuuviPool", "RuuviContext", - "RuuviVirtual", "RuuviStorage", "RuuviService", .product(name: "RuuviOntologyRealm", package: "RuuviOntology"), - .product(name: "RuuviVirtualModel", package: "RuuviVirtual") ]), .testTarget( name: "RuuviMigrationTests", diff --git a/Packages/RuuviMigration/RuuviMigration.podspec b/Packages/RuuviMigration/RuuviMigration.podspec index a14f08b13..6a57b4df6 100644 --- a/Packages/RuuviMigration/RuuviMigration.podspec +++ b/Packages/RuuviMigration/RuuviMigration.podspec @@ -25,7 +25,6 @@ Pod::Spec.new do |s| ss.dependency 'RuuviStorage' ss.dependency 'RuuviLocal' ss.dependency 'RuuviService' - ss.dependency 'RuuviVirtual' end s.test_spec 'Tests' do |test_spec| diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/AlertService/MigrationManagerAlertService.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/AlertService/MigrationManagerAlertService.swift index c6f9f2505..71fb0945a 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/AlertService/MigrationManagerAlertService.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/AlertService/MigrationManagerAlertService.swift @@ -4,20 +4,16 @@ import RuuviOntology import RuuviContext import RuuviStorage import RuuviService -import RuuviVirtual import RuuviMigration final class MigrationManagerAlertService: RuuviMigration { - private let virtualStorage: VirtualStorage private let ruuviStorage: RuuviStorage private let ruuviAlertService: RuuviServiceAlert init( - virtualStorage: VirtualStorage, ruuviStorage: RuuviStorage, ruuviAlertService: RuuviServiceAlert ) { - self.virtualStorage = virtualStorage self.ruuviStorage = ruuviStorage self.ruuviAlertService = ruuviAlertService } @@ -79,18 +75,6 @@ extension MigrationManagerAlertService { private func migrateTo1Version(completion: @escaping ((Bool) -> Void)) { let group = DispatchGroup() group.enter() - fetchVirtualSensors { virtualSensors in - self.queue.async { - virtualSensors.forEach { virtualSensor in - group.enter() - self.migrateTo1Version(element: virtualSensor, completion: { - group.leave() - }) - } - group.leave() - } - } - group.enter() fetchRuuviSensors { ruuviTagSensors in self.queue.async { ruuviTagSensors.forEach({ element in @@ -148,67 +132,6 @@ extension MigrationManagerAlertService { completion() } - private func migrateTo1Version(element: (VirtualSensor, Temperature?), completion: @escaping (() -> Void)) { - let id = element.0.id - if prefs.bool(forKey: Keys.Ver1.relativeHumidityAlertIsOnUDKeyPrefix + id), - let lower = prefs.optionalDouble(forKey: Keys.Ver1.relativeHumidityLowerBoundUDKeyPrefix + id), - let upper = prefs.optionalDouble(forKey: Keys.Ver1.relativeHumidityUpperBoundUDKeyPrefix + id), - let temperature = element.1 { - prefs.set(false, forKey: Keys.Ver1.relativeHumidityAlertIsOnUDKeyPrefix + id) - let lowerHumidity: Humidity = Humidity(value: lower / 100, - unit: .relative(temperature: temperature)) - let upperHumidity: Humidity = Humidity(value: upper / 100, - unit: .relative(temperature: temperature)) - ruuviAlertService.register(type: .humidity(lower: lowerHumidity, upper: upperHumidity), - for: element.0) - } else if prefs.bool(forKey: Keys.Ver1.absoluteHumidityAlertIsOnUDKeyPrefix + id), - let lower = prefs.optionalDouble(forKey: Keys.Ver1.absoluteHumidityLowerBoundUDKeyPrefix + id), - let upper = prefs.optionalDouble(forKey: Keys.Ver1.absoluteHumidityUpperBoundUDKeyPrefix + id) { - prefs.set(false, forKey: Keys.Ver1.absoluteHumidityAlertIsOnUDKeyPrefix + id) - let lowerHumidity: Humidity = Humidity(value: lower, - unit: .absolute) - let upperHumidity: Humidity = Humidity(value: upper, - unit: .absolute) - ruuviAlertService.register(type: .humidity(lower: lowerHumidity, - upper: upperHumidity), - for: element.0) - } else { - debugPrint("do nothing") - } - - // pick one description, relative preffered - let humidityDescription = prefs.string(forKey: Keys.Ver1.relativeHumidityAlertDescriptionUDKeyPrefix + id) - ?? prefs.string(forKey: Keys.Ver1.absoluteHumidityAlertDescriptionUDKeyPrefix + id) - ruuviAlertService.setHumidity(description: humidityDescription, for: element.0) - - completion() - } - - private func fetchVirtualSensors(completion: @escaping ([(VirtualSensor, Temperature?)]) -> Void) { - - queue.async { - let group = DispatchGroup() - group.enter() - var result = [(VirtualSensor, Temperature?)]() - self.virtualStorage.readAll().on(success: {sensors in - sensors.forEach({ sensor in - group.enter() - self.virtualStorage.readLast(sensor) - .on(success: { record in - result.append((sensor, record?.temperature)) - group.leave() - }) - }) - group.leave() - }, failure: { _ in - group.leave() - }) - group.notify(queue: .main, execute: { - completion(result) - }) - } - } - private func fetchRuuviSensors(completion: @escaping ([(RuuviTagSensor, Temperature?)]) -> Void) { queue.async { let group = DispatchGroup() diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift index 56ba86d50..0c86313ba 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift @@ -1,7 +1,6 @@ import RuuviLocal import RuuviPool import RuuviContext -import RuuviVirtual import RuuviStorage import RuuviService import RuuviMigration @@ -11,7 +10,6 @@ public final class RuuviMigrationFactoryImpl: RuuviMigrationFactory { private let idPersistence: RuuviLocalIDs private let realmContext: RealmContext private let ruuviPool: RuuviPool - private let virtualStorage: VirtualStorage private let ruuviStorage: RuuviStorage private let ruuviAlertService: RuuviServiceAlert private let ruuviOffsetCalibrationService: RuuviServiceOffsetCalibration @@ -21,7 +19,6 @@ public final class RuuviMigrationFactoryImpl: RuuviMigrationFactory { idPersistence: RuuviLocalIDs, realmContext: RealmContext, ruuviPool: RuuviPool, - virtualStorage: VirtualStorage, ruuviStorage: RuuviStorage, ruuviAlertService: RuuviServiceAlert, ruuviOffsetCalibrationService: RuuviServiceOffsetCalibration @@ -30,7 +27,6 @@ public final class RuuviMigrationFactoryImpl: RuuviMigrationFactory { self.idPersistence = idPersistence self.realmContext = realmContext self.ruuviPool = ruuviPool - self.virtualStorage = virtualStorage self.ruuviStorage = ruuviStorage self.ruuviAlertService = ruuviAlertService self.ruuviOffsetCalibrationService = ruuviOffsetCalibrationService @@ -43,7 +39,6 @@ public final class RuuviMigrationFactoryImpl: RuuviMigrationFactory { ruuviPool: ruuviPool ) let toAlertService = MigrationManagerAlertService( - virtualStorage: virtualStorage, ruuviStorage: ruuviStorage, ruuviAlertService: ruuviAlertService ) diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/fixRHAlerts/RuuviMigrationFixRHAlerts.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/fixRHAlerts/RuuviMigrationFixRHAlerts.swift index 190dd1187..b2862d9f7 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/fixRHAlerts/RuuviMigrationFixRHAlerts.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/fixRHAlerts/RuuviMigrationFixRHAlerts.swift @@ -3,7 +3,6 @@ import UIKit import RuuviLocal import RuuviPool import RuuviContext -import RuuviVirtual import RuuviStorage import RuuviService import RuuviMigration diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift index 48738865d..e993d663e 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift @@ -2,14 +2,10 @@ import RealmSwift import Foundation import RuuviOntology import RuuviLocal -import RuuviVirtual import RuuviMigration #if canImport(RuuviOntologyRealm) import RuuviOntologyRealm #endif -#if canImport(RuuviVirtualModel) -import RuuviVirtualModel -#endif public final class MigrationManagerToVIPER: RuuviMigration { private let localImages: RuuviLocalImages @@ -34,7 +30,7 @@ public final class MigrationManagerToVIPER: RuuviMigration { } else if oldSchemaVersion < 4 { self?.from3to4(migration) } else if oldSchemaVersion < 8 { - self?.deleteRuuviTagAndWebTagData(migration) + self?.deleteRuuviTagData(migration) } }, shouldCompactOnLaunch: { totalBytes, usedBytes in let fiveHundredMegabytes = 500 * 1024 * 1024 @@ -139,19 +135,11 @@ public final class MigrationManagerToVIPER: RuuviMigration { } private func from3to4(_ migration: Migration) { - migration.enumerateObjects(ofType: WebTagRealm.className(), { (oldObject, newObject) in - if let location = oldObject?["location"] as? WebTagLocationRealm, let city = location.city { - newObject?["name"] = city - } else { - newObject?["name"] = "" - } - }) - deleteRuuviTagAndWebTagData(migration) + deleteRuuviTagData(migration) } - private func deleteRuuviTagAndWebTagData(_ migration: Migration) { + private func deleteRuuviTagData(_ migration: Migration) { migration.deleteData(forType: RuuviTagDataRealm.className()) - migration.deleteData(forType: WebTagDataRealm.className()) } private func real(_ name: String, _ mac: String, _ uuid: String) -> String { diff --git a/Packages/RuuviMigration/target.yml b/Packages/RuuviMigration/target.yml index 73dc72843..232783118 100644 --- a/Packages/RuuviMigration/target.yml +++ b/Packages/RuuviMigration/target.yml @@ -13,6 +13,5 @@ targets: - target: RuuviLocal - target: RuuviPool - target: RuuviContext - - target: RuuviVirtual - target: RuuviStorage - target: RuuviService diff --git a/Packages/RuuviNotification/Package.swift b/Packages/RuuviNotification/Package.swift index 43240e514..b3ca8eac8 100644 --- a/Packages/RuuviNotification/Package.swift +++ b/Packages/RuuviNotification/Package.swift @@ -19,7 +19,6 @@ let package = Package( .package(path: "../RuuviStorage"), .package(path: "../RuuviLocal"), .package(path: "../RuuviService"), - .package(path: "../RuuviVirtual") ], targets: [ .target( @@ -29,7 +28,6 @@ let package = Package( name: "RuuviNotificationLocal", dependencies: [ "RuuviNotification", - "RuuviVirtual", "RuuviService", "RuuviLocal", "RuuviStorage", diff --git a/Packages/RuuviNotification/RuuviNotification.podspec b/Packages/RuuviNotification/RuuviNotification.podspec index 9e9e44856..60275aca6 100644 --- a/Packages/RuuviNotification/RuuviNotification.podspec +++ b/Packages/RuuviNotification/RuuviNotification.podspec @@ -25,7 +25,6 @@ Pod::Spec.new do |s| ss.dependency 'RuuviStorage' ss.dependency 'RuuviLocal' ss.dependency 'RuuviService' - ss.dependency 'RuuviVirtual' end s.test_spec 'Tests' do |test_spec| diff --git a/Packages/RuuviNotification/Sources/RuuviNotificationLocal/RuuviNotificationLocalImpl.swift b/Packages/RuuviNotification/Sources/RuuviNotificationLocal/RuuviNotificationLocalImpl.swift index b8c9cb4d2..cf4d877a3 100644 --- a/Packages/RuuviNotification/Sources/RuuviNotificationLocal/RuuviNotificationLocalImpl.swift +++ b/Packages/RuuviNotification/Sources/RuuviNotificationLocal/RuuviNotificationLocalImpl.swift @@ -6,7 +6,6 @@ import RuuviOntology import RuuviStorage import RuuviLocal import RuuviService -import RuuviVirtual import RuuviNotification struct LocalAlertCategory { @@ -24,7 +23,6 @@ enum BlastNotificationType: String { public final class RuuviNotificationLocalImpl: NSObject, RuuviNotificationLocal { private let ruuviStorage: RuuviStorage - private let virtualTagTrunk: VirtualStorage private let idPersistence: RuuviLocalIDs private let settings: RuuviLocalSettings private let ruuviAlertService: RuuviServiceAlert @@ -33,13 +31,11 @@ public final class RuuviNotificationLocalImpl: NSObject, RuuviNotificationLocal public init( ruuviStorage: RuuviStorage, - virtualTagTrunk: VirtualStorage, idPersistence: RuuviLocalIDs, settings: RuuviLocalSettings, ruuviAlertService: RuuviServiceAlert ) { self.ruuviStorage = ruuviStorage - self.virtualTagTrunk = virtualTagTrunk self.idPersistence = idPersistence self.settings = settings self.ruuviAlertService = ruuviAlertService @@ -341,13 +337,6 @@ extension RuuviNotificationLocalImpl { content: content, trigger: trigger) UNUserNotificationCenter.current().add(request, withCompletionHandler: nil) }) - virtualTagTrunk.readOne(id(for: uuid)).on(success: { virtualTag in - content.subtitle = virtualTag.name - let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.1, repeats: false) - let request = UNNotificationRequest(identifier: uuid + type.rawValue, - content: content, trigger: trigger) - UNUserNotificationCenter.current().add(request, withCompletionHandler: nil) - }) switch reason { case .low: @@ -420,18 +409,14 @@ extension RuuviNotificationLocalImpl { if let userInfo = notification.userInfo, let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType { - let virtualSensor = userInfo[RuuviServiceAlertDidChangeKey.virtualSensor] as? VirtualSensor let physicalSensor = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor var isOn = false - if let virtualSensor = virtualSensor { - isOn = self?.ruuviAlertService.isOn(type: type, for: virtualSensor) ?? false - } if let physicalSensor = physicalSensor { isOn = self?.ruuviAlertService.isOn(type: type, for: physicalSensor) ?? false } - if let uuid = physicalSensor?.luid?.value ?? physicalSensor?.macId?.value ?? virtualSensor?.id { + if let uuid = physicalSensor?.luid?.value ?? physicalSensor?.macId?.value { switch type { case .temperature: self?.lowTemperatureAlerts[uuid] = nil @@ -555,8 +540,6 @@ extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { sharedTo: [] ) ruuviAlertService.unregister(type: Self.alertType(from: type), ruuviTag: ruuviTag) - let virtualSensor = VirtualSensorStruct(id: uuid) - ruuviAlertService.unregister(type: Self.alertType(from: type), for: virtualSensor) case lowHigh.mute: mute(type: type, uuid: uuid) default: @@ -585,8 +568,6 @@ extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { sharedTo: [] ) ruuviAlertService.unregister(type: Self.alertType(from: type), ruuviTag: ruuviTag) - let virtualSensor = VirtualSensorStruct(id: uuid) - ruuviAlertService.unregister(type: Self.alertType(from: type), for: virtualSensor) case blast.mute: mute(type: type, uuid: uuid) default: @@ -639,12 +620,6 @@ extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { for: ruuviTag, till: date ) - let virtualSensor = VirtualSensorStruct(id: uuid) - ruuviAlertService.mute( - type: Self.alertType(from: type), - for: virtualSensor, - till: date - ) } private func mute(type: BlastNotificationType, uuid: String) { @@ -672,12 +647,6 @@ extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { for: ruuviTag, till: date ) - let virtualSensor = VirtualSensorStruct(id: uuid) - ruuviAlertService.mute( - type: Self.alertType(from: type), - for: virtualSensor, - till: date - ) } private func muteOffset() -> Date? { diff --git a/Packages/RuuviNotification/target.yml b/Packages/RuuviNotification/target.yml index 22122bfea..c16aefe28 100644 --- a/Packages/RuuviNotification/target.yml +++ b/Packages/RuuviNotification/target.yml @@ -8,6 +8,5 @@ targets: - package: Humidity - target: RuuviOntology - target: RuuviLocal - - target: RuuviVirtual - target: RuuviStorage - target: RuuviService diff --git a/Packages/RuuviNotifier/Package.swift b/Packages/RuuviNotifier/Package.swift index ccfa633a0..2ea7431fe 100644 --- a/Packages/RuuviNotifier/Package.swift +++ b/Packages/RuuviNotifier/Package.swift @@ -16,7 +16,6 @@ let package = Package( ], dependencies: [ .package(path: "../RuuviOntology"), - .package(path: "../RuuviVirtual"), .package(path: "../RuuviService"), .package(path: "../RuuviNotification") ], @@ -25,14 +24,12 @@ let package = Package( name: "RuuviNotifier", dependencies: [ "RuuviOntology", - "RuuviVirtual" ]), .target( name: "RuuviNotifierImpl", dependencies: [ "RuuviNotifier", "RuuviOntology", - "RuuviVirtual", "RuuviService", "RuuviNotification" ]), diff --git a/Packages/RuuviNotifier/RuuviNotifier.podspec b/Packages/RuuviNotifier/RuuviNotifier.podspec index f5114f8df..6fe2436df 100644 --- a/Packages/RuuviNotifier/RuuviNotifier.podspec +++ b/Packages/RuuviNotifier/RuuviNotifier.podspec @@ -22,7 +22,6 @@ Pod::Spec.new do |s| ss.source_files = 'Sources/RuuviNotifierImpl/**/*.{h,m,swift}', 'Sources/RuuviNotifierImpl/*.{h,m,swift}' ss.dependency 'RuuviNotifier/Contract' ss.dependency 'RuuviOntology' - ss.dependency 'RuuviVirtual' ss.dependency 'RuuviNotification' end diff --git a/Packages/RuuviNotifier/Sources/RuuviNotifier/RuuviNotifier.swift b/Packages/RuuviNotifier/Sources/RuuviNotifier/RuuviNotifier.swift index a81f1559d..7c86af062 100644 --- a/Packages/RuuviNotifier/Sources/RuuviNotifier/RuuviNotifier.swift +++ b/Packages/RuuviNotifier/Sources/RuuviNotifier/RuuviNotifier.swift @@ -1,10 +1,8 @@ import Foundation import RuuviOntology -import RuuviVirtual public protocol RuuviNotifier { func process(record ruuviTag: RuuviTagSensorRecord, trigger: Bool) - func process(data: VirtualData, for sensor: VirtualSensor) func processNetwork(record: RuuviTagSensorRecord, trigger: Bool, for identifier: MACIdentifier) func subscribe(_ observer: T, to uuid: String) diff --git a/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl+Process.swift b/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl+Process.swift index f71ae834e..70555af3e 100644 --- a/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl+Process.swift +++ b/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl+Process.swift @@ -1,7 +1,6 @@ // swiftlint:disable file_length import Foundation import RuuviOntology -import RuuviVirtual import RuuviNotifier // MARK: - Process Physical Sensors @@ -73,41 +72,6 @@ extension RuuviNotifierImpl { } } -// MARK: - Process Virtual Sensors -extension RuuviNotifierImpl { - public func process(data: VirtualData, for sensor: VirtualSensor) { - var isTriggered = false - AlertType.allCases.forEach { (type) in - switch type { - case .temperature: - isTriggered = process(temperature: data.temperature, - alertType: type, - identifier: sensor.id.luid) - || isTriggered - case .relativeHumidity: - let isRelativeHumidity = process( - relativeHumidity: data.humidity, - temperature: data.temperature, - alertType: type, - identifier: sensor.id.luid - ) - isTriggered = isTriggered || isRelativeHumidity - || isTriggered - case .pressure: - isTriggered = process(pressure: data.pressure, - alertType: type, - identifier: sensor.id.luid) - default: - break - } - } - - if ruuviAlertService.hasRegistrations(for: sensor) { - notify(uuid: sensor.id, isTriggered: isTriggered) - } - } - -} // MARK: - Process Network Sensors extension RuuviNotifierImpl { // swiftlint:disable:next function_body_length diff --git a/Packages/RuuviNotifier/target.yml b/Packages/RuuviNotifier/target.yml index 9ce902537..be981bd4d 100644 --- a/Packages/RuuviNotifier/target.yml +++ b/Packages/RuuviNotifier/target.yml @@ -7,5 +7,4 @@ targets: - package: Humidity - target: RuuviOntology - target: RuuviNotification - - target: RuuviVirtual - target: RuuviService diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualLocation.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualLocation.swift deleted file mode 100644 index a52e94c9d..000000000 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualLocation.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation - -public enum VirtualLocation { - case current - case manual -} diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualProvider.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualProvider.swift deleted file mode 100644 index 8248a8aca..000000000 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualProvider.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Foundation - -public protocol HasVirtualProvider { - var provider: VirtualProvider { get } -} - -public enum VirtualProvider: String, CaseIterable { - case openWeatherMap -} diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualSensor.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualSensor.swift deleted file mode 100644 index 146257f1e..000000000 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualSensor.swift +++ /dev/null @@ -1,11 +0,0 @@ -import Foundation - -public protocol VirtualSensor: Sensor {} - -public struct VirtualSensorStruct: VirtualSensor { - public var id: String - - public init(id: String) { - self.id = id - } -} diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualTagSensor.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualTagSensor.swift deleted file mode 100644 index fcfdf65ad..000000000 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualTagSensor.swift +++ /dev/null @@ -1,65 +0,0 @@ -import Foundation - -public protocol VirtualTagSensor: VirtualSensor, Nameable, Locateable, HasVirtualProvider { } - -extension VirtualTagSensor { - public var any: AnyVirtualTagSensor { - return AnyVirtualTagSensor(object: self) - } - - public var `struct`: VirtualTagSensorStruct { - return VirtualTagSensorStruct( - id: id, - name: name, - loc: loc, - provider: provider - ) - } -} - -public struct VirtualTagSensorStruct: VirtualTagSensor { - public var id: String - public var name: String - public var loc: Location? - public var provider: VirtualProvider - - public init( - id: String, - name: String, - loc: Location?, - provider: VirtualProvider - ) { - self.id = id - self.name = name - self.loc = loc - self.provider = provider - } -} - -public struct AnyVirtualTagSensor: VirtualTagSensor, Equatable, Hashable { - var object: VirtualTagSensor - - public var id: String { - return object.id - } - - public var name: String { - return object.name - } - - public var loc: Location? { - return object.loc - } - - public var provider: VirtualProvider { - return object.provider - } - - public static func == (lhs: AnyVirtualTagSensor, rhs: AnyVirtualTagSensor) -> Bool { - return lhs.id == rhs.id - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(id) - } -} diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualTagSensorRecord.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualTagSensorRecord.swift deleted file mode 100644 index de63aee2c..000000000 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/VirtualTag/VirtualTagSensorRecord.swift +++ /dev/null @@ -1,85 +0,0 @@ -import Foundation - -public protocol VirtualTagSensorRecord: Sensor { - var sensorId: String { get } - var date: Date { get } - var temperature: Temperature? { get } - var humidity: Humidity? { get } - var pressure: Pressure? { get } - var location: Location? { get } -} - -extension VirtualTagSensorRecord { - public var id: String { - return sensorId + "\(date.timeIntervalSince1970)" - } - - public var any: AnyVirtualTagSensorRecord { - return AnyVirtualTagSensorRecord(object: self) - } -} - -public struct VirtualTagSensorRecordStruct: VirtualTagSensorRecord { - public var sensorId: String - public var date: Date - public var temperature: Temperature? - public var humidity: Humidity? - public var pressure: Pressure? - public var location: Location? - - public init( - sensorId: String, - date: Date, - temperature: Temperature?, - humidity: Humidity?, - pressure: Pressure?, - location: Location? - ) { - self.sensorId = sensorId - self.date = date - self.temperature = temperature - self.humidity = humidity - self.pressure = pressure - self.location = location - } -} - -public struct AnyVirtualTagSensorRecord: VirtualTagSensorRecord, Equatable, Hashable { - private var object: VirtualTagSensorRecord - - public init(object: VirtualTagSensorRecord) { - self.object = object - } - - public var sensorId: String { - return object.sensorId - } - - public var date: Date { - return object.date - } - - public var temperature: Temperature? { - return object.temperature - } - - public var humidity: Humidity? { - return object.humidity - } - - public var pressure: Pressure? { - return object.pressure - } - - public var location: Location? { - return object.location - } - - public static func == (lhs: AnyVirtualTagSensorRecord, rhs: AnyVirtualTagSensorRecord) -> Bool { - return lhs.id == rhs.id - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(id) - } -} diff --git a/Packages/RuuviService/Sources/RuuviService/RuuviServiceAlert.swift b/Packages/RuuviService/Sources/RuuviService/RuuviServiceAlert.swift index 96f6495ff..80372ac00 100644 --- a/Packages/RuuviService/Sources/RuuviService/RuuviServiceAlert.swift +++ b/Packages/RuuviService/Sources/RuuviService/RuuviServiceAlert.swift @@ -10,13 +10,11 @@ extension Notification.Name { public enum RuuviServiceAlertDidChangeKey: String { case physicalSensor - case virtualSensor case type } public protocol RuuviServiceAlert: RuuviServiceAlertRuuviTag, RuuviServiceAlertPhysicalSensor, - RuuviServiceAlertVirtualSensor, RuuviServiceAlertCloud, RuuviServiceAlertDeprecated {} @@ -150,57 +148,3 @@ public protocol RuuviServiceAlertPhysicalSensor { func setMovement(counter: Int?, for sensor: PhysicalSensor) func movementDescription(for sensor: PhysicalSensor) -> String? } - -public protocol RuuviServiceAlertVirtualSensor { - // virtual sensor - func hasRegistrations(for sensor: VirtualSensor) -> Bool - func isOn(type: AlertType, for sensor: VirtualSensor) -> Bool - func alert(for sensor: VirtualSensor, of type: AlertType) -> AlertType? - func register(type: AlertType, for sensor: VirtualSensor) - func unregister(type: AlertType, for sensor: VirtualSensor) - func mute(type: AlertType, for sensor: VirtualSensor, till date: Date) - func unmute(type: AlertType, for sensor: VirtualSensor) - func mutedTill(type: AlertType, for sensor: VirtualSensor) -> Date? - - /// temperature (celsius) - func lowerCelsius(for sensor: VirtualSensor) -> Double? - func setLower(celsius: Double?, for sensor: VirtualSensor) - func upperCelsius(for sensor: VirtualSensor) -> Double? - func setUpper(celsius: Double?, for sensor: VirtualSensor) - func temperatureDescription(for sensor: VirtualSensor) -> String? - func setTemperature(description: String?, for sensor: VirtualSensor) - - /// relative humidity (fraction of one) - func lowerRelativeHumidity(for sensor: VirtualSensor) -> Double? - func setLower(relativeHumidity: Double?, for sensor: VirtualSensor) - func upperRelativeHumidity(for sensor: VirtualSensor) -> Double? - func setUpper(relativeHumidity: Double?, for sensor: VirtualSensor) - func relativeHumidityDescription(for sensor: VirtualSensor) -> String? - func setRelativeHumidity(description: String?, for sensor: VirtualSensor) - - /// humidity (unitHumidity) - func lowerHumidity(for sensor: VirtualSensor) -> Humidity? - func setLower(humidity: Humidity?, for sensor: VirtualSensor) - func upperHumidity(for sensor: VirtualSensor) -> Humidity? - func setUpper(humidity: Humidity?, for sensor: VirtualSensor) - func humidityDescription(for sensor: VirtualSensor) -> String? - func setHumidity(description: String?, for sensor: VirtualSensor) - - /// pressure (hPa) - func lowerPressure(for sensor: VirtualSensor) -> Double? - func setLower(pressure: Double?, for sensor: VirtualSensor) - func upperPressure(for sensor: VirtualSensor) -> Double? - func setUpper(pressure: Double?, for sensor: VirtualSensor) - func pressureDescription(for sensor: VirtualSensor) -> String? - func setPressure(description: String?, for sensor: VirtualSensor) - - /// connection - func connectionDescription(for sensor: VirtualSensor) -> String? - func setConnection(description: String?, for sensor: VirtualSensor) - - /// movement - func movementCounter(for sensor: VirtualSensor) -> Int? - func setMovement(counter: Int?, for sensor: VirtualSensor) - func movementDescription(for sensor: VirtualSensor) -> String? - func setMovement(description: String?, for sensor: VirtualSensor) -} diff --git a/Packages/RuuviService/Sources/RuuviService/RuuviServiceSensorProperties.swift b/Packages/RuuviService/Sources/RuuviService/RuuviServiceSensorProperties.swift index 14e658156..3b9ced0ee 100644 --- a/Packages/RuuviService/Sources/RuuviService/RuuviServiceSensorProperties.swift +++ b/Packages/RuuviService/Sources/RuuviService/RuuviServiceSensorProperties.swift @@ -18,25 +18,12 @@ public protocol RuuviServiceSensorProperties { maxSize: CGSize ) -> Future - @discardableResult - func set( - image: UIImage, - for sensor: VirtualSensor - ) -> Future - - @discardableResult - func setNextDefaultBackground(for sensor: VirtualSensor) -> Future - @discardableResult func setNextDefaultBackground(for sensor: RuuviTagSensor) -> Future func getImage(for sensor: RuuviTagSensor) -> Future - func getImage(for sensor: VirtualSensor) -> Future - func removeImage(for sensor: RuuviTagSensor) - - func removeImage(for sensor: VirtualSensor) } extension RuuviServiceSensorProperties { diff --git a/Packages/RuuviService/Sources/RuuviServiceAlert/RuuviServiceAlertImpl.swift b/Packages/RuuviService/Sources/RuuviServiceAlert/RuuviServiceAlertImpl.swift index 2deb6c774..0d90c8dec 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAlert/RuuviServiceAlertImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAlert/RuuviServiceAlertImpl.swift @@ -694,43 +694,6 @@ public final class RuuviServiceAlertImpl: RuuviServiceAlert { } } - // Virtual Sensor - public func hasRegistrations(for sensor: VirtualSensor) -> Bool { - return AlertType.allCases.contains(where: { isOn(type: $0, for: sensor) }) - } - - public func isOn(type: AlertType, for sensor: VirtualSensor) -> Bool { - return alert(for: sensor, of: type) != nil - } - - public func alert(for sensor: VirtualSensor, of type: AlertType) -> AlertType? { - return alertPersistence.alert(for: sensor.id, of: type) - } - - public func mutedTill(type: AlertType, for sensor: VirtualSensor) -> Date? { - alertPersistence.mutedTill(type: type, for: sensor.id) - } - - public func register(type: AlertType, for sensor: VirtualSensor) { - alertPersistence.register(type: type, for: sensor.id) - postAlertDidChange(with: sensor, of: type) - } - - public func unregister(type: AlertType, for sensor: VirtualSensor) { - alertPersistence.unregister(type: type, for: sensor.id) - postAlertDidChange(with: sensor, of: type) - } - - public func mute(type: AlertType, for sensor: VirtualSensor, till date: Date) { - alertPersistence.mute(type: type, for: sensor.id, till: date) - postAlertDidChange(with: sensor, of: type) - } - - public func unmute(type: AlertType, for sensor: VirtualSensor) { - alertPersistence.unmute(type: type, for: sensor.id) - postAlertDidChange(with: sensor, of: type) - } - // UUID func hasRegistrations(for uuid: String) -> Bool { return AlertType.allCases.contains(where: { isOn(type: $0, for: uuid) }) @@ -761,19 +724,6 @@ public final class RuuviServiceAlertImpl: RuuviServiceAlert { ) } - private func postAlertDidChange(with sensor: VirtualSensor, of type: AlertType) { - NotificationCenter - .default - .post( - name: .RuuviServiceAlertDidChange, - object: nil, - userInfo: [ - RuuviServiceAlertDidChangeKey.virtualSensor: sensor, - RuuviServiceAlertDidChangeKey.type: type - ] - ) - } - private func postAlertTriggerDidChange(with sensor: PhysicalSensor, of type: AlertType) { NotificationCenter .default @@ -883,39 +833,6 @@ extension RuuviServiceAlertImpl { } } - public func lowerCelsius(for sensor: VirtualSensor) -> Double? { - return alertPersistence.lowerCelsius(for: sensor.id) - } - - public func setLower(celsius: Double?, for sensor: VirtualSensor) { - alertPersistence.setLower(celsius: celsius, for: sensor.id) - if let l = celsius, let u = upperCelsius(for: sensor) { - postAlertDidChange(with: sensor, of: .temperature(lower: l, upper: u)) - } - } - - public func upperCelsius(for sensor: VirtualSensor) -> Double? { - return alertPersistence.upperCelsius(for: sensor.id) - } - - public func setUpper(celsius: Double?, for sensor: VirtualSensor) { - alertPersistence.setUpper(celsius: celsius, for: sensor.id) - if let u = celsius, let l = lowerCelsius(for: sensor) { - postAlertDidChange(with: sensor, of: .temperature(lower: l, upper: u)) - } - } - - public func temperatureDescription(for sensor: VirtualSensor) -> String? { - return alertPersistence.temperatureDescription(for: sensor.id) - } - - public func setTemperature(description: String?, for sensor: VirtualSensor) { - alertPersistence.setTemperature(description: description, for: sensor.id) - if let l = lowerCelsius(for: sensor), let u = upperCelsius(for: sensor) { - postAlertDidChange(with: sensor, of: .temperature(lower: l, upper: u)) - } - } - public func lowerCelsius(for uuid: String) -> Double? { return alertPersistence.lowerCelsius(for: uuid) } @@ -1022,39 +939,6 @@ extension RuuviServiceAlertImpl { } } - public func lowerRelativeHumidity(for sensor: VirtualSensor) -> Double? { - return alertPersistence.lowerRelativeHumidity(for: sensor.id) - } - - public func setLower(relativeHumidity: Double?, for sensor: VirtualSensor) { - alertPersistence.setLower(relativeHumidity: relativeHumidity, for: sensor.id) - if let l = relativeHumidity, let u = upperRelativeHumidity(for: sensor) { - postAlertDidChange(with: sensor, of: .relativeHumidity(lower: l, upper: u)) - } - } - - public func upperRelativeHumidity(for sensor: VirtualSensor) -> Double? { - return alertPersistence.upperRelativeHumidity(for: sensor.id) - } - - public func setUpper(relativeHumidity: Double?, for sensor: VirtualSensor) { - alertPersistence.setUpper(relativeHumidity: relativeHumidity, for: sensor.id) - if let u = relativeHumidity, let l = lowerRelativeHumidity(for: sensor) { - postAlertDidChange(with: sensor, of: .relativeHumidity(lower: l, upper: u)) - } - } - - public func relativeHumidityDescription(for sensor: VirtualSensor) -> String? { - return alertPersistence.relativeHumidityDescription(for: sensor.id) - } - - public func setRelativeHumidity(description: String?, for sensor: VirtualSensor) { - alertPersistence.setRelativeHumidity(description: description, for: sensor.id) - if let l = lowerRelativeHumidity(for: sensor), let u = upperRelativeHumidity(for: sensor) { - postAlertDidChange(with: sensor, of: .relativeHumidity(lower: l, upper: u)) - } - } - public func lowerRelativeHumidity(for uuid: String) -> Double? { return alertPersistence.lowerRelativeHumidity(for: uuid) } @@ -1162,40 +1046,6 @@ extension RuuviServiceAlertImpl { } } - public func lowerHumidity(for sensor: VirtualSensor) -> Humidity? { - return alertPersistence.lowerHumidity(for: sensor.id) - } - - public func setLower(humidity: Humidity?, for sensor: VirtualSensor) { - alertPersistence.setLower(humidity: humidity, for: sensor.id) - if let l = humidity, let u = upperHumidity(for: sensor) { - postAlertDidChange(with: sensor, of: .humidity(lower: l, upper: u)) - } - } - - public func upperHumidity(for sensor: VirtualSensor) -> Humidity? { - return alertPersistence.upperHumidity(for: sensor.id) - } - - public func setUpper(humidity: Humidity?, for sensor: VirtualSensor) { - alertPersistence.setUpper(humidity: humidity, for: sensor.id) - if let u = humidity, let l = lowerHumidity(for: sensor) { - postAlertDidChange(with: sensor, of: .humidity(lower: l, upper: u)) - } - } - - public func humidityDescription(for sensor: VirtualSensor) -> String? { - return alertPersistence.humidityDescription(for: sensor.id) - } - - public func setHumidity(description: String?, for sensor: VirtualSensor) { - alertPersistence.setHumidity(description: description, for: sensor.id) - if let l = lowerHumidity(for: sensor), - let u = upperHumidity(for: sensor) { - postAlertDidChange(with: sensor, of: .humidity(lower: l, upper: u)) - } - } - public func lowerHumidity(for uuid: String) -> Humidity? { return alertPersistence.lowerHumidity(for: uuid) } @@ -1304,39 +1154,6 @@ extension RuuviServiceAlertImpl { } } - public func lowerPressure(for sensor: VirtualSensor) -> Double? { - return alertPersistence.lowerPressure(for: sensor.id) - } - - public func setLower(pressure: Double?, for sensor: VirtualSensor) { - alertPersistence.setLower(pressure: pressure, for: sensor.id) - if let l = pressure, let u = upperPressure(for: sensor) { - postAlertDidChange(with: sensor, of: .pressure(lower: l, upper: u)) - } - } - - public func upperPressure(for sensor: VirtualSensor) -> Double? { - return alertPersistence.upperPressure(for: sensor.id) - } - - public func setUpper(pressure: Double?, for sensor: VirtualSensor) { - alertPersistence.setUpper(pressure: pressure, for: sensor.id) - if let u = pressure, let l = lowerPressure(for: sensor) { - postAlertDidChange(with: sensor, of: .pressure(lower: l, upper: u)) - } - } - - public func pressureDescription(for sensor: VirtualSensor) -> String? { - return alertPersistence.pressureDescription(for: sensor.id) - } - - public func setPressure(description: String?, for sensor: VirtualSensor) { - alertPersistence.setPressure(description: description, for: sensor.id) - if let l = lowerPressure(for: sensor), let u = upperPressure(for: sensor) { - postAlertDidChange(with: sensor, of: .pressure(lower: l, upper: u)) - } - } - public func lowerPressure(for uuid: String) -> Double? { return alertPersistence.lowerPressure(for: uuid) } @@ -1488,15 +1305,6 @@ extension RuuviServiceAlertImpl { postAlertDidChange(with: sensor, of: .connection) } - public func connectionDescription(for sensor: VirtualSensor) -> String? { - return alertPersistence.connectionDescription(for: sensor.id) - } - - public func setConnection(description: String?, for sensor: VirtualSensor) { - alertPersistence.setConnection(description: description, for: sensor.id) - postAlertDidChange(with: sensor, of: .connection) - } - public func connectionDescription(for uuid: String) -> String? { return alertPersistence.connectionDescription(for: uuid) } @@ -1531,10 +1339,6 @@ extension RuuviServiceAlertImpl { } } - public func cloudConnectionDescription(for sensor: VirtualSensor) -> String? { - return alertPersistence.cloudConnectionDescription(for: sensor.id) - } - public func setCloudConnection(unseenDuration: Double?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setCloudConnection(unseenDuration: unseenDuration, for: luid.value) @@ -1627,26 +1431,6 @@ extension RuuviServiceAlertImpl { } } - public func movementCounter(for sensor: VirtualSensor) -> Int? { - return alertPersistence.movementCounter(for: sensor.id) - } - - public func setMovement(counter: Int?, for sensor: VirtualSensor) { - alertPersistence.setMovement(counter: counter, for: sensor.id) - // no need to post an update, this is not user initiated action - } - - public func movementDescription(for sensor: VirtualSensor) -> String? { - return alertPersistence.movementDescription(for: sensor.id) - } - - public func setMovement(description: String?, for sensor: VirtualSensor) { - alertPersistence.setMovement(description: description, for: sensor.id) - if let c = movementCounter(for: sensor) { - postAlertDidChange(with: sensor, of: .movement(last: c)) - } - } - public func movementCounter(for uuid: String) -> Int? { return alertPersistence.movementCounter(for: uuid) } diff --git a/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift b/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift index 24771ff6a..b1803d881 100644 --- a/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift @@ -53,28 +53,6 @@ public final class RuuviServiceSensorPropertiesImpl: RuuviServiceSensorPropertie return promise.future } - public func set( - image: UIImage, - for sensor: VirtualSensor - ) -> Future { - let promise = Promise() - localImages.setCustomBackground( - image: image, - for: sensor.id.luid - ).on(success: { url in - promise.succeed(value: url) - }, failure: { error in - promise.fail(error: .ruuviLocal(error)) - }) - return promise.future - } - - public func setNextDefaultBackground(for sensor: VirtualSensor) -> Future { - let luid = sensor.id.luid - let macId: MACIdentifier? = nil - return setNextDefaultBackground(luid: luid, macId: macId) - } - public func setNextDefaultBackground(for sensor: RuuviTagSensor) -> Future { let luid = sensor.luid let macId = sensor.macId @@ -181,12 +159,6 @@ public final class RuuviServiceSensorPropertiesImpl: RuuviServiceSensorPropertie return promise.future } - public func getImage(for sensor: VirtualSensor) -> Future { - let luid = sensor.id.luid - let macId: MACIdentifier? = nil - return getImage(luid: luid, macId: macId) - } - public func getImage(for sensor: RuuviTagSensor) -> Future { return getImage(luid: sensor.luid, macId: sensor.macId) } @@ -204,10 +176,6 @@ public final class RuuviServiceSensorPropertiesImpl: RuuviServiceSensorPropertie } } - public func removeImage(for sensor: VirtualSensor) { - localImages.deleteCustomBackground(for: sensor.id.luid) - } - @discardableResult private func resetCloudImage(for sensor: RuuviTagSensor) -> Future { let promise = Promise() diff --git a/Packages/RuuviVirtual/.gitignore b/Packages/RuuviVirtual/.gitignore deleted file mode 100644 index bb460e7be..000000000 --- a/Packages/RuuviVirtual/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.DS_Store -/.build -/Packages -/*.xcodeproj -xcuserdata/ -DerivedData/ -.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata diff --git a/Packages/RuuviVirtual/Info.plist b/Packages/RuuviVirtual/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviVirtual/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviVirtual/Package.swift b/Packages/RuuviVirtual/Package.swift deleted file mode 100644 index 22e43eeed..000000000 --- a/Packages/RuuviVirtual/Package.swift +++ /dev/null @@ -1,134 +0,0 @@ -// swift-tools-version:5.9 -// The swift-tools-version declares the minimum version of Swift required to build this package. - -import PackageDescription - -let package = Package( - name: "RuuviVirtual", - platforms: [.macOS(.v10_15), .iOS(.v13)], - products: [ - .library( - name: "RuuviVirtual", - targets: ["RuuviVirtual"] - ), - .library( - name: "RuuviVirtualModel", - targets: ["RuuviVirtualModel"] - ), - .library( - name: "RuuviVirtualOWM", - targets: ["RuuviVirtualOWM"] - ), - .library( - name: "RuuviVirtualPersistence", - targets: ["RuuviVirtualPersistence"] - ), - .library( - name: "RuuviVirtualReactor", - targets: ["RuuviVirtualReactor"] - ), - .library( - name: "RuuviVirtualRepository", - targets: ["RuuviVirtualRepository"] - ), - .library( - name: "RuuviVirtualService", - targets: ["RuuviVirtualService"] - ), - .library( - name: "RuuviVirtualStorage", - targets: ["RuuviVirtualStorage"] - ) - ], - dependencies: [ - .package(path: "../RuuviOntology"), - .package(path: "../RuuviCore"), - .package(path: "../RuuviLocation"), - .package(path: "../RuuviContext"), - .package(path: "../RuuviLocal"), - .package(url: "https://github.com/kean/Future", .exact("1.3.0")), - .package(name: "Realm", url: "https://github.com/realm/realm-cocoa", .upToNextMajor(from: "10.8.0")) - ], - targets: [ - .target( - name: "RuuviVirtual", - dependencies: [ - "RuuviOntology", - "RuuviCore", - "RuuviLocation", - "Future" - ] - ), - .target( - name: "RuuviVirtualModel", - dependencies: [ - "RuuviOntology", - "RuuviVirtual", - "Future", - .product(name: "RealmSwift", package: "Realm") - ] - ), - .target( - name: "RuuviVirtualOWM", - dependencies: [ - "RuuviOntology", - "RuuviVirtual", - "Future" - ] - ), - .target( - name: "RuuviVirtualPersistence", - dependencies: [ - "RuuviOntology", - "RuuviVirtual", - "RuuviContext", - "RuuviLocal", - "Future", - "RuuviVirtualModel", - .product(name: "RealmSwift", package: "Realm") - ] - ), - .target( - name: "RuuviVirtualReactor", - dependencies: [ - "RuuviOntology", - "RuuviContext", - "RuuviVirtual", - "RuuviVirtualModel", - "Future", - .product(name: "RealmSwift", package: "Realm") - ] - ), - .target( - name: "RuuviVirtualRepository", - dependencies: [ - "RuuviOntology", - "RuuviVirtual", - "Future" - ] - ), - .target( - name: "RuuviVirtualService", - dependencies: [ - "RuuviOntology", - "RuuviVirtual", - "RuuviVirtualOWM", - "RuuviLocation", - "RuuviLocal", - "RuuviCore", - "Future" - ] - ), - .target( - name: "RuuviVirtualStorage", - dependencies: [ - "RuuviOntology", - "RuuviVirtual", - "Future" - ] - ), - .testTarget( - name: "RuuviVirtualTests", - dependencies: ["RuuviVirtual"]) - ] -) diff --git a/Packages/RuuviVirtual/README.md b/Packages/RuuviVirtual/README.md deleted file mode 100644 index e084cb7ec..000000000 --- a/Packages/RuuviVirtual/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# RuuviVirtual - -A description of this package. diff --git a/Packages/RuuviVirtual/RuuviVirtual.podspec b/Packages/RuuviVirtual/RuuviVirtual.podspec deleted file mode 100644 index ea9fa1074..000000000 --- a/Packages/RuuviVirtual/RuuviVirtual.podspec +++ /dev/null @@ -1,78 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviVirtual' - s.version = '0.0.1' - s.summary = 'Ruuvi Virtual' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviVirtual/**/*.{h,m,swift}', 'Sources/RuuviVirtual/*.{h,m,swift}' - ss.dependency 'FutureX' - ss.dependency 'RuuviOntology' - end - - s.subspec 'Model' do |ss| - ss.source_files = 'Sources/RuuviVirtualModel/**/*.{h,m,swift}', 'Sources/RuuviVirtualModel/*.{h,m,swift}' - ss.dependency 'RuuviVirtual/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'FutureX' - ss.dependency 'RealmSwift' - end - - s.subspec 'Persistence' do |ss| - ss.source_files = 'Sources/RuuviVirtualPersistence/**/*.{h,m,swift}', 'Sources/RuuviVirtualPersistence/*.{h,m,swift}' - ss.dependency 'RuuviVirtual/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviLocal' - ss.dependency 'RuuviContext/Realm' - ss.dependency 'RealmSwift' - end - - s.subspec 'Storage' do |ss| - ss.source_files = 'Sources/RuuviVirtualStorage/**/*.{h,m,swift}', 'Sources/RuuviVirtualStorage/*.{h,m,swift}' - ss.dependency 'RuuviVirtual/Contract' - ss.dependency 'RuuviOntology' - end - - s.subspec 'Repository' do |ss| - ss.source_files = 'Sources/RuuviVirtualRepository/**/*.{h,m,swift}', 'Sources/RuuviVirtualRepository/*.{h,m,swift}' - ss.dependency 'RuuviVirtual/Contract' - ss.dependency 'RuuviOntology' - end - - s.subspec 'Reactor' do |ss| - ss.source_files = 'Sources/RuuviVirtualReactor/**/*.{h,m,swift}', 'Sources/RuuviVirtualReactor/*.{h,m,swift}' - ss.dependency 'RuuviVirtual/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviContext/Realm' - end - - s.subspec 'Service' do |ss| - ss.source_files = 'Sources/RuuviVirtualService/**/*.{h,m,swift}', 'Sources/RuuviVirtualService/*.{h,m,swift}' - ss.dependency 'RuuviVirtual/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviVirtual/OWM' - ss.dependency 'RuuviLocation/Service' - ss.dependency 'RuuviCore/Location' - end - - s.subspec 'OWM' do |ss| - ss.source_files = 'Sources/RuuviVirtualOWM/**/*.{h,m,swift}', 'Sources/RuuviVirtualOWM/*.{h,m,swift}' - ss.dependency 'RuuviVirtual/Contract' - ss.dependency 'FutureX' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end - diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualData.swift b/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualData.swift deleted file mode 100644 index 01a54b7f6..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualData.swift +++ /dev/null @@ -1,38 +0,0 @@ -import Foundation -import RuuviOntology - -public struct VirtualData { - public var celsius: Double? - public var relativeHumidity: Double? - public var hPa: Double? - - public init( - celsius: Double?, - relativeHumidity: Double?, - hPa: Double? - ) { - self.celsius = celsius - self.relativeHumidity = relativeHumidity - self.hPa = hPa - } -} - -extension VirtualData { - public var temperature: Temperature? { - return Temperature(celsius, unit: .celsius) - } - - public var humidity: Humidity? { - guard let relative = relativeHumidity else { - return nil - } - return Humidity( - relative: relative / 100.0, - temperature: temperature - ) - } - - public var pressure: Pressure? { - return Pressure(hPa, unit: .hectopascals) - } -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualError.swift b/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualError.swift deleted file mode 100644 index b50bc81d1..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualError.swift +++ /dev/null @@ -1,55 +0,0 @@ -import Foundation -import RuuviCore -import RuuviLocation - -public enum VirtualReactorError: Error { - case virtualPersistence(VirtualPersistenceError) -} - -public enum VirtualPersistenceError: Error { - case persistence(Error) - case failedToFindVirtualTag -} - -public enum VirtualRepositoryError: Error { - case virtualPersistence(VirtualPersistenceError) -} - -public enum VirtualStorageError: Error { - case virtualPersistence(VirtualPersistenceError) -} - -public enum VirtualServiceError: Error { - case ruuviCore(RuuviCoreError) - case ruuviLocation(RuuviLocationError) - case virtualPersistence(VirtualPersistenceError) - case openWeatherMap(OWMError) - case failedToReverseGeocodeCoordinate - case callerDeinitedDuringOperation -} - -public enum OWMError: Error, Equatable { - case networking(Error) - case missingOpenWeatherMapAPIKey - case failedToParseOpenWeatherMapResponse - case apiLimitExceeded - case invalidApiKey - case notAHttpResponse - - public static func == (lhs: OWMError, rhs: OWMError) -> Bool { - switch (lhs, rhs) { - case (.missingOpenWeatherMapAPIKey, .missingOpenWeatherMapAPIKey): - return true - case (.failedToParseOpenWeatherMapResponse, .failedToParseOpenWeatherMapResponse): - return true - case (.apiLimitExceeded, .apiLimitExceeded): - return true - case (.invalidApiKey, .invalidApiKey): - return true - case (.notAHttpResponse, .notAHttpResponse): - return true - default: - return false - } - } -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualPersistence.swift b/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualPersistence.swift deleted file mode 100644 index b76b00316..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualPersistence.swift +++ /dev/null @@ -1,62 +0,0 @@ -import Foundation -import Future -import CoreLocation -import RuuviOntology - -public protocol VirtualPersistence { - var isCurrentLocationVirtualTagExists: Bool { get } - - func readAll() -> Future<[AnyVirtualTagSensor], VirtualPersistenceError> - - func readLast( - _ virtualTag: VirtualTagSensor - ) -> Future - - func readOne( - _ id: String - ) -> Future - - func deleteAllRecords( - _ ruuviTagId: String, - before date: Date - ) -> Future - - func persist( - provider: VirtualProvider, - name: String - ) -> Future - - func persist( - provider: VirtualProvider, - location: Location - ) -> Future - - func remove(sensor: VirtualSensor) -> Future - - func update( - name: String, - of sensor: VirtualSensor - ) -> Future - - func update( - location: Location, - of sensor: VirtualSensor - ) -> Future - - func clearLocation( - of sensor: VirtualSensor, - name: String - ) -> Future - - @discardableResult - func persist( - currentLocation: Location, - data: VirtualData - ) -> Future - - @discardableResult - func persist( - location: Location, - data: VirtualData - ) -> Future -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualProviderService.swift b/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualProviderService.swift deleted file mode 100644 index f46a7eec4..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualProviderService.swift +++ /dev/null @@ -1,48 +0,0 @@ -import Foundation -import Future -import CoreLocation -import RuuviOntology - -public protocol VirtualProviderService { - func loadData( - coordinate: CLLocationCoordinate2D, - provider: VirtualProvider - ) -> Future - - func loadCurrentLocationData( - from provider: VirtualProvider - ) -> Future<(Location, VirtualData), VirtualServiceError> - - @discardableResult - func observeCurrentLocationData( - _ observer: T, - provider: VirtualProvider, - interval: TimeInterval, - fire: Bool, - closure: @escaping (T, VirtualData?, Location?, VirtualServiceError?) -> Void - ) -> VirtualToken - - // swiftlint:disable function_parameter_count - @discardableResult - func observeData( - _ observer: T, - coordinate: CLLocationCoordinate2D, - provider: VirtualProvider, - interval: TimeInterval, - fire: Bool, - closure: @escaping (T, VirtualData?, VirtualServiceError?) -> Void - ) -> VirtualToken - // swiftlint:enable function_parameter_count -} - -public final class VirtualToken { - private let cancellationClosure: () -> Void - - public init(cancellationClosure: @escaping () -> Void) { - self.cancellationClosure = cancellationClosure - } - - public func invalidate() { - cancellationClosure() - } -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualReactor.swift b/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualReactor.swift deleted file mode 100644 index 521291978..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualReactor.swift +++ /dev/null @@ -1,33 +0,0 @@ -import Foundation -import RuuviOntology - -public protocol VirtualReactor { - func observe( - _ block: @escaping (VirtualReactorChange) -> Void - ) -> VirtualReactorToken - - func observeLast( - _ virtualTag: VirtualTagSensor, - _ block: @escaping (VirtualReactorChange) -> Void - ) -> VirtualReactorToken -} - -public enum VirtualReactorChange { - case initial([Type]) - case insert(Type) - case delete(Type) - case update(Type) - case error(VirtualReactorError) -} - -public final class VirtualReactorToken { - private let cancellationClosure: () -> Void - - public init(cancellationClosure: @escaping () -> Void) { - self.cancellationClosure = cancellationClosure - } - - public func invalidate() { - cancellationClosure() - } -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualRepository.swift b/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualRepository.swift deleted file mode 100644 index bb6d3d1d2..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualRepository.swift +++ /dev/null @@ -1,10 +0,0 @@ -import Foundation -import Future - -public protocol VirtualRepository { - @discardableResult - func deleteAllRecords( - _ id: String, - before date: Date - ) -> Future -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualService.swift b/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualService.swift deleted file mode 100644 index 79f2d3abe..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualService.swift +++ /dev/null @@ -1,58 +0,0 @@ -import Foundation -import Future -import CoreLocation -import RuuviOntology - -public protocol VirtualService { - var isCurrentLocationVirtualTagExists: Bool { get } - - func add( - provider: VirtualProvider, - name: String - ) -> Future - - func add( - provider: VirtualProvider, - location: Location - ) -> Future - - func remove( - sensor: VirtualSensor - ) -> Future - - func update( - name: String, - of sensor: VirtualSensor - ) -> Future - - func update( - location: Location, - of sensor: VirtualSensor - ) -> Future - - func clearLocation( - of sensor: VirtualSensor, - name: String - ) -> Future - - // swiftlint:disable function_parameter_count - @discardableResult - func observeData( - _ observer: T, - coordinate: CLLocationCoordinate2D, - provider: VirtualProvider, - interval: TimeInterval, - fire: Bool, - closure: @escaping (T, VirtualData?, VirtualServiceError?) -> Void - ) -> VirtualToken - // swiftlint:enable function_parameter_count - - @discardableResult - func observeCurrentLocationData( - _ observer: T, - provider: VirtualProvider, - interval: TimeInterval, - fire: Bool, - closure: @escaping (T, VirtualData?, Location?, VirtualServiceError?) -> Void - ) -> VirtualToken -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualStorage.swift b/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualStorage.swift deleted file mode 100644 index c17742291..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtual/VirtualStorage.swift +++ /dev/null @@ -1,11 +0,0 @@ -import Foundation -import Future -import RuuviOntology - -public protocol VirtualStorage { - func readOne(_ id: String) -> Future - func readAll() -> Future<[AnyVirtualTagSensor], VirtualStorageError> - func readLast( - _ virtualTag: VirtualTagSensor - ) -> Future -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualModel/WebTagDataRealm.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualModel/WebTagDataRealm.swift deleted file mode 100644 index b347c4dcf..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualModel/WebTagDataRealm.swift +++ /dev/null @@ -1,41 +0,0 @@ -import RealmSwift -import Foundation -import RuuviOntology -import RuuviVirtual - -public final class WebTagDataRealm: Object { - @objc public dynamic var webTag: WebTagRealm? - @objc public dynamic var date: Date = Date() - @objc public dynamic var location: WebTagLocationRealm? - - public let celsius = RealmProperty() - public let humidity = RealmProperty() - public let pressure = RealmProperty() - - public convenience init(webTag: WebTagRealm, data: VirtualData) { - self.init() - self.webTag = webTag - self.celsius.value = data.celsius - self.humidity.value = data.humidity?.value - self.pressure.value = data.hPa - } -} - -extension WebTagDataRealm { - public var record: VirtualTagSensorRecord? { - guard let id = webTag?.id else { - return nil - } - let t = Temperature(celsius.value) - let h = Humidity(relative: humidity.value, temperature: t) - let p = Pressure(pressure.value) - return VirtualTagSensorRecordStruct( - sensorId: id, - date: date, - temperature: t, - humidity: h, - pressure: p, - location: location?.location - ) - } -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualModel/WebTagRealm+VirtualTagSensor.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualModel/WebTagRealm+VirtualTagSensor.swift deleted file mode 100644 index 7faf22263..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualModel/WebTagRealm+VirtualTagSensor.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Foundation -import RuuviOntology - -extension WebTagRealm: VirtualTagSensor { - public var loc: Location? { - return location?.location - } - - public var id: String { - return uuid - } -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualModel/WebTagRealm.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualModel/WebTagRealm.swift deleted file mode 100644 index 064932e4b..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualModel/WebTagRealm.swift +++ /dev/null @@ -1,78 +0,0 @@ -import RealmSwift -import CoreLocation -import RuuviOntology - -public final class WebTagRealm: Object { - @objc public dynamic var name: String = "" - @objc public dynamic var uuid: String = "" - @objc dynamic var providerString: String = VirtualProvider.openWeatherMap.rawValue - @objc public dynamic var location: WebTagLocationRealm? - - public let data = LinkingObjects(fromType: WebTagDataRealm.self, property: "webTag") - - public var provider: VirtualProvider { - if let provider = VirtualProvider(rawValue: providerString) { - return provider - } else { - return .openWeatherMap - } - } - - override public static func primaryKey() -> String { - return "uuid" - } - - public convenience init(uuid: String, provider: VirtualProvider) { - self.init() - self.uuid = uuid - self.providerString = provider.rawValue - } -} - -public final class WebTagLocationRealm: Object { - let webTags = LinkingObjects(fromType: WebTagRealm.self, property: "location") - - @objc public dynamic var city: String? - @objc public dynamic var state: String? - @objc public dynamic var country: String? - @objc public dynamic var latitude: Double = 0 - @objc public dynamic var longitude: Double = 0 - @objc public dynamic var compoundKey: String = UUID().uuidString - - override public static func primaryKey() -> String? { - return "compoundKey" - } - - public convenience init(location: Location) { - self.init() - city = location.city - state = location.state - country = location.country - latitude = location.coordinate.latitude - longitude = location.coordinate.longitude - compoundKey = "\(latitude)" + "\(longitude)" - } -} - -extension WebTagLocationRealm { - public var location: Location { - let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) - return LocationWebTag(city: city, - state: state, - country: country, - coordinate: coordinate) - } -} - -private struct LocationWebTag: Location { - var city: String? - var state: String? - var country: String? - var coordinate: CLLocationCoordinate2D -} - -extension WebTagRealm { - public var lastRecord: VirtualTagSensorRecord? { - return data.last?.record - } -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualOWM/OpenWeatherMapAPI.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualOWM/OpenWeatherMapAPI.swift deleted file mode 100644 index 263fd7e55..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualOWM/OpenWeatherMapAPI.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Foundation -import Future -import RuuviVirtual - -public protocol OpenWeatherMapAPI { - func loadCurrent( - longitude: Double, - latitude: Double - ) -> Future -} - -public struct OWMData { - public var kelvin: Double? - public var humidity: Double? // in % - public var pressure: Double? // in hPa -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualOWM/URLSession/OpenWeatherMapAPIURLSession.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualOWM/URLSession/OpenWeatherMapAPIURLSession.swift deleted file mode 100644 index 673029fcb..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualOWM/URLSession/OpenWeatherMapAPIURLSession.swift +++ /dev/null @@ -1,80 +0,0 @@ -import Foundation -import Future -import RuuviVirtual - -public final class OpenWeatherMapAPIURLSession: OpenWeatherMapAPI { - private let apiKey: String - - public init(apiKey: String) { - self.apiKey = apiKey - } - - public func loadCurrent( - longitude: Double, - latitude: Double - ) -> Future { - let promise = Promise() - if let url = currentWeatherUrl(latitude: latitude, longitude: longitude) { - var request = URLRequest(url: url) - request.httpMethod = "GET" - - let task = URLSession.shared.dataTask(with: request) { (data, response, error) in - if let error = error { - promise.fail(error: .networking(error)) - } else { - if let httpResponse = response as? HTTPURLResponse { - let status = httpResponse.statusCode - if status == 429 { - promise.fail(error: OWMError.apiLimitExceeded) - } else if status == 401 { - promise.fail(error: OWMError.invalidApiKey) - } else { - if let data = data { - do { - guard let json = try JSONSerialization.jsonObject(with: - data, options: []) as? [String: Any] else { - promise.fail(error: OWMError.failedToParseOpenWeatherMapResponse) - return - } - guard let main = json["main"] as? [String: Any] else { - promise.fail(error: OWMError.failedToParseOpenWeatherMapResponse) - return - } - let kelvin = main["temp"] as? Double - let humidity = main["humidity"] as? Double - let pressure = main["pressure"] as? Double - let data = OWMData(kelvin: kelvin, humidity: humidity, pressure: pressure) - promise.succeed(value: data) - } catch let error { - promise.fail(error: .networking(error)) - } - } else { - promise.fail(error: OWMError.failedToParseOpenWeatherMapResponse) - } - } - } else { - promise.fail(error: OWMError.notAHttpResponse) - } - } - } - task.resume() - } else { - promise.fail(error: .missingOpenWeatherMapAPIKey) - } - return promise.future - } - - private func currentWeatherUrl(latitude: Double, longitude: Double) -> URL? { - var urlComponents = URLComponents() - urlComponents.scheme = "https" - urlComponents.host = "api.openweathermap.org" - urlComponents.path = "/data/2.5/weather" - - let latitudeQuery = URLQueryItem(name: "lat", value: "\(latitude)") - let longitudeQuery = URLQueryItem(name: "lon", value: "\(longitude)") - let apiKeyQuery = URLQueryItem(name: "APPID", value: apiKey) - urlComponents.queryItems = [latitudeQuery, longitudeQuery, apiKeyQuery] - - return urlComponents.url - } -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualPersistence/VirtualPersistenceRealm.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualPersistence/VirtualPersistenceRealm.swift deleted file mode 100644 index dbee56a90..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualPersistence/VirtualPersistenceRealm.swift +++ /dev/null @@ -1,296 +0,0 @@ -import RealmSwift -import Future -import CoreLocation -import RuuviOntology -import RuuviContext -import RuuviLocal -import RuuviVirtual -#if canImport(RuuviVirtualModel) -import RuuviVirtualModel -#endif - -// swiftlint:disable:next type_body_length -public final class VirtualPersistenceRealm: VirtualPersistence { - private let context: RealmContext - private var settings: RuuviLocalSettings - - public init(context: RealmContext, settings: RuuviLocalSettings) { - self.context = context - self.settings = settings - } - - public var isCurrentLocationVirtualTagExists: Bool { - return context.main.objects(WebTagRealm.self) - .filter("location == nil").count > 0 - } - - public func readLast( - _ virtualTag: VirtualTagSensor - ) -> Future { - let promise = Promise() - context.bgWorker.enqueue { - let lastRecord = self.context.bg.objects(WebTagDataRealm.self) - .filter("webTag.uuid == %@", virtualTag.id) - .sorted(byKeyPath: "date", ascending: false) - .first - promise.succeed(value: lastRecord?.record?.any) - } - return promise.future - } - - public func readAll() -> Future<[AnyVirtualTagSensor], VirtualPersistenceError> { - let promise = Promise<[AnyVirtualTagSensor], VirtualPersistenceError>() - context.bgWorker.enqueue { - let realmEntities = self.context.bg.objects(WebTagRealm.self) - let result: [AnyVirtualTagSensor] = realmEntities.map { webTagRealm in - return VirtualTagSensorStruct( - id: webTagRealm.uuid, - name: webTagRealm.name, - loc: webTagRealm.loc, - provider: webTagRealm.provider - ).any - } - promise.succeed(value: result) - } - return promise.future - } - - public func readOne(_ id: String) -> Future { - let promise = Promise() - context.bgWorker.enqueue { - if let webTagRealm = self.context.bg.object(ofType: WebTagRealm.self, forPrimaryKey: id) { - let result = VirtualTagSensorStruct( - id: webTagRealm.id, - name: webTagRealm.name, - loc: webTagRealm.loc, - provider: webTagRealm.provider - ).any - promise.succeed(value: result) - } else { - promise.fail(error: .failedToFindVirtualTag) - } - } - return promise.future - } - - public func deleteAllRecords(_ ruuviTagId: String, before date: Date) -> Future { - let promise = Promise() - context.bgWorker.enqueue { - do { - let data = self.context.bg.objects(WebTagDataRealm.self) - .filter("webTag.uuid == %@ AND date < %@", ruuviTagId, date) - try self.context.bg.write { - self.context.bg.delete(data) - } - promise.succeed(value: true) - } catch { - promise.fail(error: .persistence(error)) - } - } - return promise.future - } - - public func clearLocation( - of sensor: VirtualSensor, - name: String - ) -> Future { - let promise = Promise() - let webTagId = sensor.id - context.bgWorker.enqueue { - do { - if let webTag = self.context.bg.object(ofType: WebTagRealm.self, forPrimaryKey: webTagId) { - try self.context.bg.write { - if let oldLocation = webTag.location { - self.context.bg.delete(oldLocation) - } - webTag.location = nil - webTag.name = name - } - promise.succeed(value: true) - } else { - promise.fail(error: .failedToFindVirtualTag) - } - } catch { - promise.fail(error: .persistence(error)) - } - } - return promise.future - } - - public func update( - location: Location, - of sensor: VirtualSensor - ) -> Future { - let promise = Promise() - let webTagId = sensor.id - context.bgWorker.enqueue { - do { - if let webTag = self.context.bg.object(ofType: WebTagRealm.self, forPrimaryKey: webTagId) { - try self.context.bg.write { - if let oldLocation = webTag.location { - self.context.bg.delete(oldLocation) - } - let newLocation = WebTagLocationRealm(location: location) - self.context.bg.add(newLocation, update: .all) - webTag.location = newLocation - webTag.name = location.city ?? location.country ?? "" - } - promise.succeed(value: true) - } else { - promise.fail(error: .failedToFindVirtualTag) - } - } catch { - promise.fail(error: .persistence(error)) - } - } - return promise.future - } - - public func persist( - provider: VirtualProvider, - location: Location - ) -> Future { - let promise = Promise() - context.bgWorker.enqueue { - let uuid = UUID().uuidString - let webTag = WebTagRealm(uuid: uuid, provider: provider) - webTag.name = location.city ?? location.country ?? "" - let webTagLocation = WebTagLocationRealm(location: location) - do { - try self.context.bg.write { - self.context.bg.add(webTag, update: .all) - self.context.bg.add(webTagLocation, update: .modified) - webTag.location = webTagLocation - } - promise.succeed(value: webTag.struct.any) - } catch { - promise.fail(error: .persistence(error)) - } - } - return promise.future - } - - public func persist( - provider: VirtualProvider, - name: String - ) -> Future { - let promise = Promise() - context.bgWorker.enqueue { - let uuid = UUID().uuidString - let webTag = WebTagRealm(uuid: uuid, provider: provider) - webTag.name = name - do { - try self.context.bg.write { - self.context.bg.add(webTag, update: .all) - } - promise.succeed(value: webTag.struct.any) - } catch { - promise.fail(error: .persistence(error)) - } - } - return promise.future - } - - public func remove(sensor: VirtualSensor) -> Future { - let promise = Promise() - let sensorId = sensor.id - context.bgWorker.enqueue { - do { - if let webTag = self.context.bg.object( - ofType: WebTagRealm.self, - forPrimaryKey: sensorId - ) { - try self.context.bg.write { - self.context.bg.delete(webTag) - } - promise.succeed(value: true) - } else { - promise.fail(error: .failedToFindVirtualTag) - } - } catch { - promise.fail(error: .persistence(error)) - } - } - return promise.future - } - - public func update( - name: String, - of sensor: VirtualSensor - ) -> Future { - let promise = Promise() - let webTagId = sensor.id - context.bgWorker.enqueue { - do { - if let webTag = self.context.bg.object(ofType: WebTagRealm.self, forPrimaryKey: webTagId) { - try self.context.bg.write { - webTag.name = name - } - promise.succeed(value: true) - } else { - promise.fail(error: .failedToFindVirtualTag) - } - } catch { - promise.fail(error: .persistence(error)) - } - } - return promise.future - } - - @discardableResult - public func persist(currentLocation: Location, data: VirtualData) -> Future { - let promise = Promise() - context.bgWorker.enqueue { - let currentLocationWebTags = self.context.bg.objects(WebTagRealm.self).filter("location == nil") - do { - try currentLocationWebTags.forEach({ (webTag) in - if !webTag.isInvalidated { - let tagData = WebTagDataRealm(webTag: webTag, data: data) - let location = WebTagLocationRealm(location: currentLocation) - try self.context.bg.write { - if !webTag.isInvalidated { - self.context.bg.add(location, update: .modified) - tagData.location = location - self.context.bg.add(tagData) - } - } - } - }) - promise.succeed(value: data) - } catch { - promise.fail(error: .persistence(error)) - } - } - return promise.future - } - - @discardableResult - public func persist(location: Location, data: VirtualData) -> Future { - let promise = Promise() - context.bgWorker.enqueue { - let webTags = self.context.bg.objects(WebTagRealm.self) - .filter("location != nil AND location.latitude == %@ AND location.longitude == %@", - location.coordinate.latitude, - location.coordinate.longitude) - do { - try webTags.forEach({ (webTag) in - if !webTag.isInvalidated { - let tagData = WebTagDataRealm(webTag: webTag, data: data) - let location = WebTagLocationRealm(location: location) - try self.context.bg.write { - if !webTag.isInvalidated { - self.context.bg.add(location, update: .modified) - tagData.location = location - self.context.bg.add(tagData) - } - } - } - }) - promise.succeed(value: data) - } catch { - promise.fail(error: .persistence(error)) - } - } - return promise.future - } -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagLastRecordSubjectCombine.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagLastRecordSubjectCombine.swift deleted file mode 100644 index 3759a8a52..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagLastRecordSubjectCombine.swift +++ /dev/null @@ -1,50 +0,0 @@ -import Foundation -import Combine -import RuuviContext -import RuuviOntology -import RealmSwift -#if canImport(RuuviVirtualModel) -import RuuviVirtualModel -#endif - -final class VirtualTagLastRecordSubjectCombine { - var isServing: Bool = false - - private let realm: RealmContext - private let id: String - - let subject = PassthroughSubject() - - private var virtualSensorDataRealmToken: NotificationToken? - - deinit { - virtualSensorDataRealmToken?.invalidate() - } - - init( - id: String, - realm: RealmContext - ) { - self.realm = realm - self.id = id - } - - func start() { - self.isServing = true - - let results = self.realm.main.objects(WebTagDataRealm.self) - .filter("webTag.uuid == %@", id) - .sorted(byKeyPath: "date") - self.virtualSensorDataRealmToken = results.observe { [weak self] (change) in - guard let sSelf = self else { return } - switch change { - case .update(let records, _, _, _): - if let lastRecord = records.last?.record { - sSelf.subject.send(lastRecord.any) - } - default: - break - } - } - } -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagSubjectCombine.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagSubjectCombine.swift deleted file mode 100644 index 43389f047..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/Combine/VirtualTagSubjectCombine.swift +++ /dev/null @@ -1,55 +0,0 @@ -import Foundation -import Combine -import RealmSwift -import RuuviOntology -import RuuviContext -#if canImport(RuuviVirtualModel) -import RuuviVirtualModel -#endif - -class VirtualTagSubjectCombine { - var realm: RealmContext - - let insertSubject = PassthroughSubject() - let updateSubject = PassthroughSubject() - let deleteSubject = PassthroughSubject() - - private var webTagsRealmToken: NotificationToken? - private var webTagRealmCache = [AnyVirtualTagSensor]() - - deinit { - webTagsRealmToken?.invalidate() - } - - init(realm: RealmContext) { - self.realm = realm - DispatchQueue.main.async { [weak self] in - guard let sSelf = self else { return } - let results = sSelf.realm.main.objects(WebTagRealm.self) - sSelf.webTagRealmCache = results.map({ $0.struct.any }) - sSelf.webTagsRealmToken = results.observe { [weak self] (change) in - guard let sSelf = self else { return } - switch change { - case .update(let webTags, let deletions, let insertions, let modifications): - for del in deletions { - sSelf.deleteSubject.send(sSelf.webTagRealmCache[del].struct.any) - } - sSelf.webTagRealmCache = sSelf.webTagRealmCache - .enumerated() - .filter { !deletions.contains($0.offset) } - .map { $0.element } - for ins in insertions { - sSelf.insertSubject.send(webTags[ins].struct.any) - sSelf.webTagRealmCache.insert(webTags[ins].struct.any, at: ins) - } - for mod in modifications { - sSelf.updateSubject.send(webTags[mod].struct.any) - sSelf.webTagRealmCache[mod] = webTags[mod].struct.any - } - default: - break - } - } - } - } -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/VirtualReactorImpl.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/VirtualReactorImpl.swift deleted file mode 100644 index ed85728ff..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualReactor/VirtualReactorImpl.swift +++ /dev/null @@ -1,73 +0,0 @@ -import Foundation -import Future -import RuuviOntology -import RuuviContext -import RuuviVirtual - -public final class VirtualReactorImpl: VirtualReactor { - private let context: RealmContext - private let persistence: VirtualPersistence - private lazy var entityCombine = VirtualTagSubjectCombine(realm: context) - private lazy var lastRecordCombines = [String: VirtualTagLastRecordSubjectCombine]() - - public init(context: RealmContext, persistence: VirtualPersistence) { - self.context = context - self.persistence = persistence - } - - public func observe( - _ block: @escaping (VirtualReactorChange) -> Void - ) -> VirtualReactorToken { - let realmOperation = persistence.readAll() - realmOperation.on(success: { realmEntities in - block(.initial(realmEntities)) - }, failure: { error in - block(.error(.virtualPersistence(error))) - }) - let insert = entityCombine.insertSubject.sink { value in - block(.insert(value)) - } - let update = entityCombine.updateSubject.sink { value in - block(.update(value)) - } - let delete = entityCombine.deleteSubject.sink { value in - block(.delete(value)) - } - return VirtualReactorToken { - insert.cancel() - update.cancel() - delete.cancel() - } - } - - public func observeLast( - _ virtualTag: VirtualTagSensor, - _ block: @escaping (VirtualReactorChange) -> Void - ) -> VirtualReactorToken { - let realmOperation = persistence.readLast(virtualTag) - realmOperation.on(success: { record in - block(.update(record?.any)) - }) - var recordCombine: VirtualTagLastRecordSubjectCombine - if let combine = lastRecordCombines[virtualTag.id] { - recordCombine = combine - } else { - let combine = VirtualTagLastRecordSubjectCombine( - id: virtualTag.id, - realm: context - ) - lastRecordCombines[virtualTag.id] = combine - recordCombine = combine - } - let cancellable = recordCombine.subject.sink { (record) in - block(.update(record)) - } - if !recordCombine.isServing { - recordCombine.start() - } - return VirtualReactorToken { - cancellable.cancel() - } - } - -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualRepository/VirtualRepositoryCoordinator.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualRepository/VirtualRepositoryCoordinator.swift deleted file mode 100644 index 10117060c..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualRepository/VirtualRepositoryCoordinator.swift +++ /dev/null @@ -1,26 +0,0 @@ -import Foundation -import Future -import RuuviVirtual - -public final class VirtualRepositoryCoordinator: VirtualRepository { - private let peristence: VirtualPersistence - - public init(persistence: VirtualPersistence) { - self.peristence = persistence - } - - @discardableResult - public func deleteAllRecords( - _ id: String, - before date: Date - ) -> Future { - let promise = Promise() - peristence.deleteAllRecords(id, before: date) - .on(success: { success in - promise.succeed(value: success) - }, failure: { error in - promise.fail(error: .virtualPersistence(error)) - }) - return promise.future - } -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualService/VirtualProviderServiceImpl.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualService/VirtualProviderServiceImpl.swift deleted file mode 100644 index f0fce8c50..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualService/VirtualProviderServiceImpl.swift +++ /dev/null @@ -1,180 +0,0 @@ -import Foundation -import Future -import CoreLocation -import RuuviVirtual -import RuuviOntology -import RuuviLocation -import RuuviCore -#if canImport(RuuviVirtualOWM) -import RuuviVirtualOWM -#endif - -public final class VirtualProviderServiceImpl: VirtualProviderService { - private let owmApi: OpenWeatherMapAPI - private let locationManager: RuuviCoreLocation - private let locationService: RuuviLocationService - - public init( - owmApi: OpenWeatherMapAPI, - ruuviCoreLocation: RuuviCoreLocation, - ruuviLocationService: RuuviLocationService - ) { - self.owmApi = owmApi - self.locationManager = ruuviCoreLocation - self.locationService = ruuviLocationService - } - - @discardableResult - // swiftlint:disable:next function_parameter_count - public func observeData( - _ observer: T, - coordinate: CLLocationCoordinate2D, - provider: VirtualProvider, - interval: TimeInterval, - fire: Bool, - closure: @escaping (T, VirtualData?, VirtualServiceError?) -> Void - ) -> VirtualToken { - let timer = Timer.scheduledTimer(withTimeInterval: interval, - repeats: true) { [weak self, weak observer] timer in - guard let observer = observer else { - timer.invalidate() - return - } - if let operation = self?.loadData(coordinate: coordinate, provider: provider) { - operation.on(success: { data in - if timer.isValid { - closure(observer, data, nil) - } - }, failure: { (error) in - if timer.isValid { - closure(observer, nil, error) - } - }) - } else { - timer.invalidate() - } - } - - if fire { - timer.fire() - } - - return VirtualToken { - timer.invalidate() - } - } - - @discardableResult - public func observeCurrentLocationData( - _ observer: T, - provider: VirtualProvider, - interval: TimeInterval, - fire: Bool, - closure: @escaping (T, VirtualData?, Location?, VirtualServiceError?) -> Void - ) -> VirtualToken { - - let timer = Timer.scheduledTimer(withTimeInterval: interval, - repeats: true) { [weak self, weak observer] timer in - guard let observer = observer else { - timer.invalidate() - return - } - if let operation = self?.loadCurrentLocationData(from: provider) { - operation.on(success: { result in - if timer.isValid { - closure(observer, result.1, result.0, nil) - } - }, failure: { (error) in - if timer.isValid { - closure(observer, nil, nil, error) - } - }) - } else { - timer.invalidate() - } - } - - if fire { - timer.fire() - } - - return VirtualToken { - timer.invalidate() - } - } - - public func loadCurrentLocationData( - from provider: VirtualProvider - ) -> Future<(Location, VirtualData), VirtualServiceError> { - let promise = Promise<(Location, VirtualData), VirtualServiceError>() - let coordinate = locationManager.getCurrentLocation() - coordinate.on(success: { [weak self] (coordinate) in - self?.loadCurrentLocationData( - for: coordinate, - provider: provider, - with: promise - ) - }, failure: { (error) in - promise.fail(error: .ruuviCore(error)) - }) - return promise.future - } - - private func loadCurrentLocationData( - for coordinate: CLLocation, - provider: VirtualProvider, - with promise: Promise<(Location, VirtualData), VirtualServiceError> - ) { - let location = locationService.reverseGeocode(coordinate: coordinate.coordinate) - location.on(success: { [weak self] locations in - guard let location = locations.last else { - promise.fail(error: .failedToReverseGeocodeCoordinate) - return - } - - guard let op = self?.loadData(coordinate: location.coordinate, provider: provider) else { - promise.fail(error: .callerDeinitedDuringOperation) - return - } - - op.on(success: { (data) in - promise.succeed(value: (location, data)) - }, failure: { (error) in - promise.fail(error: error) - }) - - }, failure: { (error) in - promise.fail(error: .ruuviLocation(error)) - }) - } - - public func loadData( - coordinate: CLLocationCoordinate2D, - provider: VirtualProvider - ) -> Future { - let promise = Promise() - switch provider { - case .openWeatherMap: - let api = self.owmApi.loadCurrent( - longitude: coordinate.longitude, - latitude: coordinate.latitude - ) - api.on(success: { data in - var celsius: Double? - if let kelvin = data.kelvin { - celsius = kelvin - 273.15 - } - let result = VirtualData( - celsius: celsius, - relativeHumidity: data.humidity, - hPa: data.pressure - ) - promise.succeed(value: result) - }, failure: { (error) in - promise.fail(error: .openWeatherMap(error)) - }) - } - return promise.future - } - -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualService/VirtualServiceImpl.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualService/VirtualServiceImpl.swift deleted file mode 100644 index 817fe7227..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualService/VirtualServiceImpl.swift +++ /dev/null @@ -1,140 +0,0 @@ -import Foundation -import Future -import CoreLocation -import RuuviLocal -import RuuviVirtual -import RuuviOntology - -public final class VirtualServiceImpl: VirtualService { - private let ruuviLocalImages: RuuviLocalImages - private let virtualPersistence: VirtualPersistence - private let weatherProviderService: VirtualProviderService - - public init( - ruuviLocalImages: RuuviLocalImages, - virtualPersistence: VirtualPersistence, - virtualProviderService: VirtualProviderService - ) { - self.ruuviLocalImages = ruuviLocalImages - self.virtualPersistence = virtualPersistence - self.weatherProviderService = virtualProviderService - } - - public var isCurrentLocationVirtualTagExists: Bool { - return virtualPersistence.isCurrentLocationVirtualTagExists - } - - public func add(provider: VirtualProvider, location: Location) -> Future { - let promise = Promise() - virtualPersistence.persist( - provider: provider, - location: location - ).on(success: { virtualSensor in - promise.succeed(value: virtualSensor) - }, failure: { error in - promise.fail(error: .virtualPersistence(error)) - }) - return promise.future - } - - public func add( - provider: VirtualProvider, - name: String - ) -> Future { - let promise = Promise() - virtualPersistence.persist( - provider: provider, - name: name - ).on(success: { virtualSensor in - promise.succeed(value: virtualSensor) - }, failure: { error in - promise.fail(error: .virtualPersistence(error)) - }) - return promise.future - } - - public func remove(sensor: VirtualSensor) -> Future { - ruuviLocalImages.deleteCustomBackground(for: sensor.id.luid) - let promise = Promise() - virtualPersistence.remove(sensor: sensor) - .on(success: { success in - promise.succeed(value: success) - }, failure: { error in - promise.fail(error: .virtualPersistence(error)) - }) - return promise.future - } - - public func update(name: String, of sensor: VirtualSensor) -> Future { - let promise = Promise() - virtualPersistence.update(name: name, of: sensor) - .on(success: { success in - promise.succeed(value: success) - }, failure: { error in - promise.fail(error: .virtualPersistence(error)) - }) - return promise.future - } - - public func update(location: Location, of sensor: VirtualSensor) -> Future { - let promise = Promise() - virtualPersistence.update( - location: location, - of: sensor - ).on(success: { success in - promise.succeed(value: success) - }, failure: { error in - promise.fail(error: .virtualPersistence(error)) - }) - return promise.future - } - - public func clearLocation(of sensor: VirtualSensor, name: String) -> Future { - let promise = Promise() - virtualPersistence.clearLocation( - of: sensor, - name: name - ).on(success: { success in - promise.succeed(value: success) - }, failure: { error in - promise.fail(error: .virtualPersistence(error)) - }) - return promise.future - } - - @discardableResult - public func observeCurrentLocationData( - _ observer: T, - provider: VirtualProvider, - interval: TimeInterval, - fire: Bool = true, - closure: @escaping (T, VirtualData?, Location?, VirtualServiceError?) -> Void - ) -> VirtualToken { - return weatherProviderService.observeCurrentLocationData( - observer, - provider: provider, - interval: interval, - fire: fire, - closure: closure - ) - } - - @discardableResult - public func observeData( - _ observer: T, - coordinate: CLLocationCoordinate2D, - provider: VirtualProvider, - interval: TimeInterval, - fire: Bool = true, - closure: @escaping (T, VirtualData?, VirtualServiceError?) -> Void - ) -> VirtualToken { - return weatherProviderService.observeData( - observer, - coordinate: coordinate, - provider: provider, - interval: interval, - fire: fire, - closure: closure - ) - } -} diff --git a/Packages/RuuviVirtual/Sources/RuuviVirtualStorage/VirtualStorageCoordinator.swift b/Packages/RuuviVirtual/Sources/RuuviVirtualStorage/VirtualStorageCoordinator.swift deleted file mode 100644 index 1ed8df835..000000000 --- a/Packages/RuuviVirtual/Sources/RuuviVirtualStorage/VirtualStorageCoordinator.swift +++ /dev/null @@ -1,48 +0,0 @@ -import Foundation -import Future -import RuuviOntology -import RuuviVirtual - -public final class VirtualStorageCoordinator: VirtualStorage { - private let persistence: VirtualPersistence - - public init(persistence: VirtualPersistence) { - self.persistence = persistence - } - - public func readLast( - _ virtualTag: VirtualTagSensor - ) -> Future { - let promise = Promise() - persistence.readLast(virtualTag) - .on(success: { record in - promise.succeed(value: record) - }, failure: { error in - promise.fail(error: .virtualPersistence(error)) - }) - return promise.future - } - - public func readAll() -> Future<[AnyVirtualTagSensor], VirtualStorageError> { - let promise = Promise<[AnyVirtualTagSensor], VirtualStorageError>() - persistence.readAll() - .on(success: { sensors in - promise.succeed(value: sensors) - }, failure: { error in - promise.fail(error: .virtualPersistence(error)) - }) - return promise.future - } - - public func readOne(_ id: String) -> Future { - let promise = Promise() - persistence.readOne(id) - .on(success: { sensor in - promise.succeed(value: sensor) - }, failure: { error in - promise.fail(error: .virtualPersistence(error)) - }) - return promise.future - } - -} diff --git a/Packages/RuuviVirtual/Tests/RuuviVirtualTests/RuuviVirtualTests.swift b/Packages/RuuviVirtual/Tests/RuuviVirtualTests/RuuviVirtualTests.swift deleted file mode 100644 index 1c689c04a..000000000 --- a/Packages/RuuviVirtual/Tests/RuuviVirtualTests/RuuviVirtualTests.swift +++ /dev/null @@ -1,7 +0,0 @@ -import XCTest -@testable import RuuviVirtual - -final class RuuviVirtualTests: XCTestCase { - func testExample() { - } -} diff --git a/Packages/RuuviVirtual/target.yml b/Packages/RuuviVirtual/target.yml deleted file mode 100644 index 4fcc035a4..000000000 --- a/Packages/RuuviVirtual/target.yml +++ /dev/null @@ -1,16 +0,0 @@ ---- -targets: - RuuviVirtual: - templates: - - Framework - dependencies: - - package: Humidity - - package: Future - - package: Realm - - package: Realm - product: RealmSwift - - target: RuuviOntology - - target: RuuviCore - - target: RuuviLocation - - target: RuuviContext - - target: RuuviLocal diff --git a/Podfile b/Podfile index 66d6016f0..1b94e8bec 100644 --- a/Podfile +++ b/Podfile @@ -35,7 +35,6 @@ def shared_pods # modules pod 'RuuviDiscover', :path => 'Modules/RuuviDiscover/RuuviDiscover.podspec', :testspecs => ['Tests'] pod 'RuuviOnboard', :path => 'Modules/RuuviOnboard/RuuviOnboard.podspec', :testspecs => ['Tests'] - pod 'RuuviLocationPicker', :path => 'Modules/RuuviLocationPicker/RuuviLocationPicker.podspec', :testspecs => ['Tests'] # packages pod 'RuuviAnalytics', :path => 'Packages/RuuviAnalytics/RuuviAnalytics.podspec', :testspecs => ['Tests'] pod 'RuuviAnalytics/Impl', :path => 'Packages/RuuviAnalytics/RuuviAnalytics.podspec' @@ -58,8 +57,6 @@ def shared_pods pod 'RuuviDaemon/VirtualTag', :path => 'Packages/RuuviDaemon/RuuviDaemon.podspec' pod 'RuuviDaemon/Background', :path => 'Packages/RuuviDaemon/RuuviDaemon.podspec' pod 'RuuviLocal/UserDefaults', :path => 'Packages/RuuviLocal/RuuviLocal.podspec' - pod 'RuuviLocation', :path => 'Packages/RuuviLocation/RuuviLocation.podspec', :testspecs => ['Tests'] - pod 'RuuviLocation/Service', :path => 'Packages/RuuviLocation/RuuviLocation.podspec' pod 'RuuviNotification', :path => 'Packages/RuuviNotification/RuuviNotification.podspec', :testspecs => ['Tests'] pod 'RuuviNotification/Local', :path => 'Packages/RuuviNotification/RuuviNotification.podspec' pod 'RuuviNotifier', :path => 'Packages/RuuviNotifier/RuuviNotifier.podspec', :testspecs => ['Tests'] @@ -91,14 +88,6 @@ def shared_pods pod 'RuuviRepository/Coordinator', :path => 'Packages/RuuviRepository/RuuviRepository.podspec' pod 'RuuviUser', :path => 'Packages/RuuviUser/RuuviUser.podspec', :testspecs => ['Tests'] pod 'RuuviUser/Coordinator', :path => 'Packages/RuuviUser/RuuviUser.podspec' - pod 'RuuviVirtual', :path => 'Packages/RuuviVirtual/RuuviVirtual.podspec', :testspecs => ['Tests'] - pod 'RuuviVirtual/Storage', :path => 'Packages/RuuviVirtual/RuuviVirtual.podspec' - pod 'RuuviVirtual/Reactor', :path => 'Packages/RuuviVirtual/RuuviVirtual.podspec' - pod 'RuuviVirtual/Persistence', :path => 'Packages/RuuviVirtual/RuuviVirtual.podspec' - pod 'RuuviVirtual/Model', :path => 'Packages/RuuviVirtual/RuuviVirtual.podspec' - pod 'RuuviVirtual/Repository', :path => 'Packages/RuuviVirtual/RuuviVirtual.podspec' - pod 'RuuviVirtual/Service', :path => 'Packages/RuuviVirtual/RuuviVirtual.podspec' - pod 'RuuviVirtual/OWM', :path => 'Packages/RuuviVirtual/RuuviVirtual.podspec' pod 'Swinject' pod 'SwiftGen', '~> 6.0' pod 'KeychainAccess' diff --git a/Podfile.lock b/Podfile.lock index 4d5399629..c55c2f9cc 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -172,7 +172,6 @@ PODS: - RuuviService/Alert - RuuviStorage - RuuviUser - - RuuviVirtual - RuuviAnalytics/Tests (0.0.3) - RuuviCloud (0.1.0): - RuuviCloud/Contract (= 0.1.0) @@ -244,7 +243,6 @@ PODS: - RuuviOntology - RuuviPool - RuuviStorage - - RuuviVirtual - RuuviDaemon/RuuviTag (0.0.1): - BTKit - RuuviDaemon/Contract @@ -264,7 +262,6 @@ PODS: - RuuviLocal - RuuviNotifier - RuuviOntology - - RuuviVirtual - RuuviDaemon/Worker (0.0.1) - RuuviDFU (0.0.1): - RuuviDFU/Contract (= 0.0.1) @@ -283,7 +280,6 @@ PODS: - RuuviPresenters - RuuviReactor - RuuviService - - RuuviVirtual - RuuviDiscover/Tests (0.0.2) - RuuviLocal (0.0.3): - RuuviLocal/Contract (= 0.0.3) @@ -298,23 +294,6 @@ PODS: - RuuviLocalization/RuuviLocalization (= 0.0.1) - RuuviLocalization/RuuviLocalization (0.0.1) - RuuviLocalization/Tests (0.0.1) - - RuuviLocation (0.0.1): - - RuuviLocation/Contract (= 0.0.1) - - RuuviLocation/Contract (0.0.1): - - FutureX - - RuuviOntology - - RuuviLocation/Service (0.0.1): - - RuuviLocation/Contract - - RuuviOntology - - RuuviLocation/Tests (0.0.1) - - RuuviLocationPicker (0.0.1): - - RuuviLocationPicker/RuuviLocationPicker (= 0.0.1) - - RuuviLocationPicker/RuuviLocationPicker (0.0.1): - - RuuviCore - - RuuviLocalization - - RuuviLocation - - RuuviPresenters - - RuuviLocationPicker/Tests (0.0.1) - RuuviMigration (0.0.1): - RuuviMigration/Contract (= 0.0.1) - RuuviMigration/Contract (0.0.1) @@ -324,7 +303,6 @@ PODS: - RuuviOntology - RuuviService - RuuviStorage - - RuuviVirtual - RuuviMigration/Tests (0.0.1) - RuuviNotification (0.0.2): - RuuviNotification/Contract (= 0.0.2) @@ -335,7 +313,6 @@ PODS: - RuuviOntology - RuuviService - RuuviStorage - - RuuviVirtual - RuuviNotification/Tests (0.0.2) - RuuviNotifier (0.0.1): - RuuviNotifier/Contract (= 0.0.1) @@ -344,7 +321,6 @@ PODS: - RuuviNotification - RuuviNotifier/Contract - RuuviOntology - - RuuviVirtual - RuuviNotifier/Tests (0.0.1) - RuuviOnboard (0.0.4): - RuuviOnboard/RuuviOnboard (= 0.0.4) @@ -544,42 +520,6 @@ PODS: - KeychainAccess - RuuviUser/Contract - RuuviUser/Tests (0.0.1) - - RuuviVirtual (0.0.1): - - RuuviVirtual/Contract (= 0.0.1) - - RuuviVirtual/Contract (0.0.1): - - FutureX - - RuuviOntology - - RuuviVirtual/Model (0.0.1): - - FutureX - - RealmSwift - - RuuviOntology - - RuuviVirtual/Contract - - RuuviVirtual/OWM (0.0.1): - - FutureX - - RuuviVirtual/Contract - - RuuviVirtual/Persistence (0.0.1): - - RealmSwift - - RuuviContext/Realm - - RuuviLocal - - RuuviOntology - - RuuviVirtual/Contract - - RuuviVirtual/Reactor (0.0.1): - - RuuviContext/Realm - - RuuviOntology - - RuuviVirtual/Contract - - RuuviVirtual/Repository (0.0.1): - - RuuviOntology - - RuuviVirtual/Contract - - RuuviVirtual/Service (0.0.1): - - RuuviCore/Location - - RuuviLocation/Service - - RuuviOntology - - RuuviVirtual/Contract - - RuuviVirtual/OWM - - RuuviVirtual/Storage (0.0.1): - - RuuviOntology - - RuuviVirtual/Contract - - RuuviVirtual/Tests (0.0.1) - SwiftGen (6.6.2) - Swinject (2.8.3) - ZIPFoundation (0.9.11) @@ -636,11 +576,6 @@ DEPENDENCIES: - RuuviLocal/UserDefaults (from `Packages/RuuviLocal/RuuviLocal.podspec`) - RuuviLocalization (from `Common/RuuviLocalization/RuuviLocalization.podspec`) - RuuviLocalization/Tests (from `Common/RuuviLocalization/RuuviLocalization.podspec`) - - RuuviLocation (from `Packages/RuuviLocation/RuuviLocation.podspec`) - - RuuviLocation/Service (from `Packages/RuuviLocation/RuuviLocation.podspec`) - - RuuviLocation/Tests (from `Packages/RuuviLocation/RuuviLocation.podspec`) - - RuuviLocationPicker (from `Modules/RuuviLocationPicker/RuuviLocationPicker.podspec`) - - RuuviLocationPicker/Tests (from `Modules/RuuviLocationPicker/RuuviLocationPicker.podspec`) - RuuviMigration (from `Packages/RuuviMigration/RuuviMigration.podspec`) - RuuviMigration/Impl (from `Packages/RuuviMigration/RuuviMigration.podspec`) - RuuviMigration/Tests (from `Packages/RuuviMigration/RuuviMigration.podspec`) @@ -690,15 +625,6 @@ DEPENDENCIES: - RuuviUser (from `Packages/RuuviUser/RuuviUser.podspec`) - RuuviUser/Coordinator (from `Packages/RuuviUser/RuuviUser.podspec`) - RuuviUser/Tests (from `Packages/RuuviUser/RuuviUser.podspec`) - - RuuviVirtual (from `Packages/RuuviVirtual/RuuviVirtual.podspec`) - - RuuviVirtual/Model (from `Packages/RuuviVirtual/RuuviVirtual.podspec`) - - RuuviVirtual/OWM (from `Packages/RuuviVirtual/RuuviVirtual.podspec`) - - RuuviVirtual/Persistence (from `Packages/RuuviVirtual/RuuviVirtual.podspec`) - - RuuviVirtual/Reactor (from `Packages/RuuviVirtual/RuuviVirtual.podspec`) - - RuuviVirtual/Repository (from `Packages/RuuviVirtual/RuuviVirtual.podspec`) - - RuuviVirtual/Service (from `Packages/RuuviVirtual/RuuviVirtual.podspec`) - - RuuviVirtual/Storage (from `Packages/RuuviVirtual/RuuviVirtual.podspec`) - - RuuviVirtual/Tests (from `Packages/RuuviVirtual/RuuviVirtual.podspec`) - SwiftGen (~> 6.0) - Swinject @@ -764,10 +690,6 @@ EXTERNAL SOURCES: :path: Packages/RuuviLocal/RuuviLocal.podspec RuuviLocalization: :path: Common/RuuviLocalization/RuuviLocalization.podspec - RuuviLocation: - :path: Packages/RuuviLocation/RuuviLocation.podspec - RuuviLocationPicker: - :path: Modules/RuuviLocationPicker/RuuviLocationPicker.podspec RuuviMigration: :path: Packages/RuuviMigration/RuuviMigration.podspec RuuviNotification: @@ -794,8 +716,6 @@ EXTERNAL SOURCES: :path: Packages/RuuviStorage/RuuviStorage.podspec RuuviUser: :path: Packages/RuuviUser/RuuviUser.podspec - RuuviVirtual: - :path: Packages/RuuviVirtual/RuuviVirtual.podspec CHECKOUT OPTIONS: BTKit: @@ -845,20 +765,18 @@ SPEC CHECKSUMS: RangeSeekSlider: 0c26866bb2f59eea808d486ec3b990bcfae1b938 Realm: d4f810e161fa2c2c589b9860b6eb09238deacd73 RealmSwift: cef9946f09f2333a8f2ac8bac4f8de52fb9f5ac3 - RuuviAnalytics: 1442f702d42ca8a7c4000394a534cd54bf5fd67a + RuuviAnalytics: 57b1793c6d12cce0f0232179625962e7ee5d8eb3 RuuviCloud: f488ad2791dea1cee92b648e96e3eca20f5465b6 RuuviContext: 3c3a03e1791189e57d35252cac2448b30cb5c8c4 RuuviCore: c42d46fd24adec33663aa61a7b73430b448a56e4 - RuuviDaemon: 029c2bcced7d9fdfc3aa32d452701a7d1306f293 + RuuviDaemon: 49929276bac8f6d1a73c31326bdebbf29ac513ac RuuviDFU: f032417ccbb62cbaa35d62918cdb51b420010c78 - RuuviDiscover: 6b710fc2c5124dba67807aec126c99d1d6e723c3 + RuuviDiscover: b5c4f470541f50ad68e785542f7839ba067c5614 RuuviLocal: 5d711ed6933bbea2c958bd805186bbde012bc4e3 RuuviLocalization: 04e829bac8113cc8edb49c22a243da88b8383210 - RuuviLocation: 39860779e7ea8330ef0c9bbddc0d6088687767d8 - RuuviLocationPicker: ec6fb89f5b0a5ff85d00036a2847e0ffac3b9076 - RuuviMigration: e2d397eba79436eef6e8b982b1e188a5f6426a2e - RuuviNotification: 4907402a0962abd2513dc511ade32ee6a05da6a1 - RuuviNotifier: 2fdb2579b48c2ff5ad28ae5d651b01831e8b1b90 + RuuviMigration: 9db6edb260c58fedfc816bb8561d3f070113bdba + RuuviNotification: 9985612f76fd661cf26473518e503c3ac224c928 + RuuviNotifier: c417691a212ca07ab4fae7095cb9e0bc25e19084 RuuviOnboard: c9c5556007c56b4491df3ad8e1ef9c3c57ebbd34 RuuviOntology: 174c688dc2083e7afe1d98d941c9db0fd6c7a063 RuuviPersistence: 0be00598293866c79a94636247e9365b2a2e3da5 @@ -869,11 +787,10 @@ SPEC CHECKSUMS: RuuviService: 87d15c3b9758850079b91a7823f4de41e7b90cac RuuviStorage: b7f0d9e11fdc0bb73317b70464cc04e8b5b5d6d7 RuuviUser: 7222200bae9f4a7d1309f0b77013890d764b3c28 - RuuviVirtual: ac6530563120c022842cc2f2ff9e8c1237f36eb6 SwiftGen: 1366a7f71aeef49954ca5a63ba4bef6b0f24138c Swinject: 893c9a543000ac2f10ee4cbaf0933c6992c935d5 ZIPFoundation: b1f0de4eed33e74a676f76e12559ab6b75990197 -PODFILE CHECKSUM: 678248a5443826612f8c9f943ea15daf54e24fe5 +PODFILE CHECKSUM: b310e01f364c17dd00c1de3d944fa2a1ad2776b8 COCOAPODS: 1.12.1 diff --git a/project_frameworks.yml b/project_frameworks.yml index 8105e90c7..be3f9989f 100644 --- a/project_frameworks.yml +++ b/project_frameworks.yml @@ -165,7 +165,6 @@ include: - Packages/RuuviCore/target.yml - Packages/RuuviDaemon/target.yml - Packages/RuuviDFU/target.yml -- Packages/RuuviLocation/target.yml - Packages/RuuviLocal/target.yml - Packages/RuuviMigration/target.yml - Packages/RuuviNotification/target.yml @@ -178,11 +177,9 @@ include: - Packages/RuuviService/target.yml - Packages/RuuviStorage/target.yml - Packages/RuuviUser/target.yml -- Packages/RuuviVirtual/target.yml - Common/RuuviPresenters/target.yml - Common/RuuviLocalization/target.yml - Modules/RuuviDiscover/target.yml -- Modules/RuuviLocationPicker/target.yml - Modules/RuuviOnboard/target.yml - widget_frameworks.yml - pnservice.yml @@ -226,7 +223,6 @@ targets: - target: RuuviCore - target: RuuviDaemon - target: RuuviDFU - - target: RuuviLocation - target: RuuviLocal - target: RuuviMigration - target: RuuviNotification @@ -239,10 +235,8 @@ targets: - target: RuuviService - target: RuuviStorage - target: RuuviUser - - target: RuuviVirtual - target: RuuviPresenters - target: RuuviDiscover - - target: RuuviLocationPicker - target: RuuviOnboard - target: RuuviLocalization info: @@ -254,7 +248,7 @@ targets: CFBundleVersion: $(CURRENT_PROJECT_VERSION) UISupportedInterfaceOrientations: [UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight, UIInterfaceOrientationPortrait] UILaunchStoryboardName: LaunchScreen - BGTaskSchedulerPermittedIdentifiers: [com.ruuvi.station.BackgroundTaskServiceiOS13.webTagRefresh, com.ruuvi.station.BackgroundProcessServiceiOS13.dataPruning] + BGTaskSchedulerPermittedIdentifiers: [com.ruuvi.station.BackgroundProcessServiceiOS13.dataPruning] FirebaseMessagingAutoInitEnabled: false LSApplicationQueriesSchemes: [https, http, mailto] LSRequiresIPhoneOS: true diff --git a/project_spm.yml b/project_spm.yml index 98c942b9a..d441074a9 100644 --- a/project_spm.yml +++ b/project_spm.yml @@ -74,8 +74,6 @@ packages: path: Packages/RuuviDaemon RuuviDFU: path: Packages/RuuviDFU - RuuviLocation: - path: Packages/RuuviLocation RuuviLocal: path: Packages/RuuviLocal RuuviMigration: @@ -100,14 +98,10 @@ packages: path: Packages/RuuviStorage RuuviUser: path: Packages/RuuviUser - RuuviVirtual: - path: Packages/RuuviVirtual RuuviPresenters: path: Common/RuuviPresenters RuuviDiscover: path: Modules/RuuviDiscover - RuuviLocationPicker: - path: Modules/RuuviLocationPicker RuuviOnboard: path: Modules/RuuviOnboard @@ -168,8 +162,6 @@ targets: - package: RuuviDaemon - package: RuuviDaemon product: RuuviDaemonBackground - - package: RuuviDaemon - product: RuuviDaemonVirtualTag - package: RuuviDaemon product: RuuviDaemonRuuviTag - package: RuuviDaemon @@ -177,9 +169,6 @@ targets: - package: RuuviDFU - package: RuuviDFU product: RuuviDFUImpl - - package: RuuviLocation - - package: RuuviLocation - product: RuuviLocationService - package: RuuviLocal - package: RuuviLocal product: RuuviLocalUserDefaults @@ -224,22 +213,8 @@ targets: - package: RuuviUser - package: RuuviUser product: RuuviUserCoordinator - - package: RuuviVirtual - - package: RuuviVirtual - product: RuuviVirtualOWM - - package: RuuviVirtual - product: RuuviVirtualPersistence - - package: RuuviVirtual - product: RuuviVirtualReactor - - package: RuuviVirtual - product: RuuviVirtualRepository - - package: RuuviVirtual - product: RuuviVirtualStorage - - package: RuuviVirtual - product: RuuviVirtualService - package: RuuviPresenters - package: RuuviDiscover - - package: RuuviLocationPicker - package: RuuviOnboard info: path: station/Resources/Plists/Info.plist @@ -250,7 +225,7 @@ targets: CFBundleVersion: $(CURRENT_PROJECT_VERSION) UISupportedInterfaceOrientations: [UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight, UIInterfaceOrientationPortrait] UILaunchStoryboardName: LaunchScreen - BGTaskSchedulerPermittedIdentifiers: [com.ruuvi.station.BackgroundTaskServiceiOS13.webTagRefresh, com.ruuvi.station.BackgroundProcessServiceiOS13.dataPruning] + BGTaskSchedulerPermittedIdentifiers: [com.ruuvi.station.BackgroundProcessServiceiOS13.dataPruning] FirebaseMessagingAutoInitEnabled: false LSApplicationQueriesSchemes: [https, http, mailto] LSRequiresIPhoneOS: true diff --git a/station.xcodeproj/project.pbxproj b/station.xcodeproj/project.pbxproj index 675ecda24..73b94ee71 100644 --- a/station.xcodeproj/project.pbxproj +++ b/station.xcodeproj/project.pbxproj @@ -14,36 +14,10 @@ 0E00C5092685D82B009B3C24 /* RuuviDaemonError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E00C5072685D82B009B3C24 /* RuuviDaemonError+LocalizedError.swift */; }; 0E02ABBA237598C600ED4629 /* RURangeSeekSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E02ABB9237598C600ED4629 /* RURangeSeekSlider.swift */; }; 0E02ABCB2379483A00ED4629 /* Double+Temperature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E02ABCA2379483A00ED4629 /* Double+Temperature.swift */; }; - 0E046F2722F04A0300BD4E9C /* WebTagSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E046F2622F04A0300BD4E9C /* WebTagSettings.storyboard */; }; - 0E046F2922F0561B00BD4E9C /* WebTagSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2822F0561B00BD4E9C /* WebTagSettingsViewInput.swift */; }; - 0E046F2B22F0563100BD4E9C /* WebTagSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2A22F0563100BD4E9C /* WebTagSettingsViewOutput.swift */; }; - 0E046F2E22F0569000BD4E9C /* WebTagSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2D22F0569000BD4E9C /* WebTagSettingsTableViewController.swift */; }; - 0E046F3022F057CC00BD4E9C /* WebTagSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2F22F057CC00BD4E9C /* WebTagSettingsRouterInput.swift */; }; - 0E046F3222F057DD00BD4E9C /* WebTagSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3122F057DD00BD4E9C /* WebTagSettingsRouter.swift */; }; - 0E046F3422F057FC00BD4E9C /* WebTagSettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3322F057FC00BD4E9C /* WebTagSettingsModuleInput.swift */; }; - 0E046F3622F0581E00BD4E9C /* WebTagSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3522F0581E00BD4E9C /* WebTagSettingsPresenter.swift */; }; - 0E046F3B22F05AA800BD4E9C /* WebTagSettingsTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3A22F05AA800BD4E9C /* WebTagSettingsTableInitializer.swift */; }; - 0E046F3D22F05B0900BD4E9C /* WebTagSettingsTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3C22F05B0900BD4E9C /* WebTagSettingsTableConfigurator.swift */; }; - 0E046F3F22F0702D00BD4E9C /* WebTagSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3E22F0702D00BD4E9C /* WebTagSettingsViewModel.swift */; }; - 0E046F4622F17EF400BD4E9C /* LocationPicker.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E046F4522F17EF400BD4E9C /* LocationPicker.storyboard */; }; - 0E046F4822F181DA00BD4E9C /* LocationPickerViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4722F181DA00BD4E9C /* LocationPickerViewInput.swift */; }; - 0E046F4A22F1820400BD4E9C /* LocationPickerViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4922F1820400BD4E9C /* LocationPickerViewOutput.swift */; }; - 0E046F4D22F1823C00BD4E9C /* LocationPickerAppleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4C22F1823C00BD4E9C /* LocationPickerAppleViewController.swift */; }; - 0E046F4F22F1827800BD4E9C /* LocationPickerRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4E22F1827800BD4E9C /* LocationPickerRouterInput.swift */; }; - 0E046F5122F1828900BD4E9C /* LocationPickerRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5022F1828900BD4E9C /* LocationPickerRouter.swift */; }; - 0E046F5322F182AB00BD4E9C /* LocationPickerModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5222F182AB00BD4E9C /* LocationPickerModuleInput.swift */; }; - 0E046F5522F182BF00BD4E9C /* LocationPickerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5422F182BF00BD4E9C /* LocationPickerPresenter.swift */; }; - 0E046F5822F182F500BD4E9C /* LocationPickerAppleInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5722F182F500BD4E9C /* LocationPickerAppleInitializer.swift */; }; - 0E046F5A22F1832600BD4E9C /* LocationPickerAppleConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5922F1832600BD4E9C /* LocationPickerAppleConfigurator.swift */; }; - 0E046F6222F193B300BD4E9C /* LocationPickerModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F6122F193B300BD4E9C /* LocationPickerModuleOutput.swift */; }; 0E0501212685E895007060C4 /* HeartbeatDaemonTitles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0501202685E895007060C4 /* HeartbeatDaemonTitles.swift */; }; 0E0501222685E895007060C4 /* HeartbeatDaemonTitles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0501202685E895007060C4 /* HeartbeatDaemonTitles.swift */; }; 0E09672522AE897000E85F48 /* CALayer+IB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E09672422AE897000E85F48 /* CALayer+IB.swift */; }; 0E0A381923616AC3003A0364 /* UserDefaults+Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0A381823616AC3003A0364 /* UserDefaults+Optional.swift */; }; - 0E11D223267F2EC0002D0686 /* VirtualLocation+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E11D222267F2EC0002D0686 /* VirtualLocation+Localization.swift */; }; - 0E11D224267F2EC0002D0686 /* VirtualLocation+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E11D222267F2EC0002D0686 /* VirtualLocation+Localization.swift */; }; - 0E11D226267F3100002D0686 /* RuuviVirtualError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E11D225267F3100002D0686 /* RuuviVirtualError+LocalizedError.swift */; }; - 0E11D227267F3100002D0686 /* RuuviVirtualError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E11D225267F3100002D0686 /* RuuviVirtualError+LocalizedError.swift */; }; 0E197C6623C4A47A0074015B /* MailComposerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C6523C4A47A0074015B /* MailComposerPresenter.swift */; }; 0E197C6723C4A47A0074015B /* MailComposerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C6523C4A47A0074015B /* MailComposerPresenter.swift */; }; 0E197C6B23C4A52A0074015B /* MailComposerPresenterMessageUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C6A23C4A52A0074015B /* MailComposerPresenterMessageUI.swift */; }; @@ -147,22 +121,16 @@ 0E8BD2C1238566AB008B31EF /* MenuTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF722B3FF480032F6CA /* MenuTableViewController.swift */; }; 0E8BD2C2238566AB008B31EF /* AboutRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F822B7D28C0015F9E0 /* AboutRouterInput.swift */; }; 0E8BD2C6238566AB008B31EF /* AboutViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F422B7D1A40015F9E0 /* AboutViewOutput.swift */; }; - 0E8BD2CD238566AB008B31EF /* LocationPickerRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4E22F1827800BD4E9C /* LocationPickerRouterInput.swift */; }; 0E8BD2CE238566AB008B31EF /* Language+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF064232002A00025A191 /* Language+Localization.swift */; }; - 0E8BD2D0238566AB008B31EF /* WebTagSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3122F057DD00BD4E9C /* WebTagSettingsRouter.swift */; }; 0E8BD2D1238566AB008B31EF /* DefaultsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10192384615400A9CBA6 /* DefaultsPresenter.swift */; }; 0E8BD2D4238566AB008B31EF /* SettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E222B7C8C10015F9E0 /* SettingsPresenter.swift */; }; 0E8BD2D6238566AB008B31EF /* MenuTablePresentTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0A22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift */; }; - 0E8BD2D7238566AB008B31EF /* WebTagSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2822F0561B00BD4E9C /* WebTagSettingsViewInput.swift */; }; 0E8BD2DA238566AB008B31EF /* MenuModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20CC22B7BD6C0015F9E0 /* MenuModuleOutput.swift */; }; 0E8BD2DD238566AB008B31EF /* Localizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A46222AF959E006CB87C /* Localizable.swift */; }; - 0E8BD2DE238566AB008B31EF /* LocationPickerAppleInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5722F182F500BD4E9C /* LocationPickerAppleInitializer.swift */; }; 0E8BD2E0238566AB008B31EF /* DefaultsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10212384637F00A9CBA6 /* DefaultsList.swift */; }; 0E8BD2E4238566AB008B31EF /* CardsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DD422B3BF3A0032F6CA /* CardsViewOutput.swift */; }; 0E8BD2E5238566AB008B31EF /* DefaultsSwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A102423846CEB00A9CBA6 /* DefaultsSwitchTableViewCell.swift */; }; 0E8BD2E6238566AB008B31EF /* DefaultsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100B23845F7100A9CBA6 /* DefaultsViewInput.swift */; }; - 0E8BD2E7238566AB008B31EF /* LocationPickerRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5022F1828900BD4E9C /* LocationPickerRouter.swift */; }; - 0E8BD2E8238566AB008B31EF /* WebTagSettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3322F057FC00BD4E9C /* WebTagSettingsModuleInput.swift */; }; 0E8BD2E9238566AB008B31EF /* MenuTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0422B400890032F6CA /* MenuTableConfigurator.swift */; }; 0E8BD2ED238566AB008B31EF /* DefaultsStepperTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8BD2AA23851CF2008B31EF /* DefaultsStepperTableViewCell.swift */; }; 0E8BD2F0238566AB008B31EF /* SettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20DE22B7C8790015F9E0 /* SettingsRouter.swift */; }; @@ -173,7 +141,6 @@ 0E8BD300238566AB008B31EF /* TagSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863222CBB0250026C7A5 /* TagSettingsViewOutput.swift */; }; 0E8BD302238566AB008B31EF /* CardsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20C522B7915C0015F9E0 /* CardsViewModel.swift */; }; 0E8BD303238566AB008B31EF /* UIApplication+ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DBA22B3919F0032F6CA /* UIApplication+ViewController.swift */; }; - 0E8BD304238566AB008B31EF /* WebTagSettingsTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3C22F05B0900BD4E9C /* WebTagSettingsTableConfigurator.swift */; }; 0E8BD30F238566AB008B31EF /* PhotoPickerPresenterSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C300A22CF629100B52E39 /* PhotoPickerPresenterSheet.swift */; }; 0E8BD310238566AB008B31EF /* AboutConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB210222B7D3210015F9E0 /* AboutConfigurator.swift */; }; 0E8BD311238566AB008B31EF /* AboutViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F222B7D1900015F9E0 /* AboutViewInput.swift */; }; @@ -184,29 +151,23 @@ 0E8BD31B238566AB008B31EF /* MenuRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFB22B3FFD90032F6CA /* MenuRouter.swift */; }; 0E8BD320238566AB008B31EF /* DefaultsInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A101B2384618700A9CBA6 /* DefaultsInitializer.swift */; }; 0E8BD326238566AB008B31EF /* MenuTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0222B400590032F6CA /* MenuTableInitializer.swift */; }; - 0E8BD327238566AB008B31EF /* LocationPickerViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4922F1820400BD4E9C /* LocationPickerViewOutput.swift */; }; - 0E8BD328238566AB008B31EF /* WebTagSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2D22F0569000BD4E9C /* WebTagSettingsTableViewController.swift */; }; 0E8BD330238566AB008B31EF /* AboutInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB210022B7D2F50015F9E0 /* AboutInitializer.swift */; }; 0E8BD332238566AB008B31EF /* MenuTableEmbededViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20CA22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift */; }; 0E8BD335238566AB008B31EF /* Date+Ruuvi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF5B72A22D62CD900D9D14A /* Date+Ruuvi.swift */; }; - 0E8BD33E238566AB008B31EF /* LocationPickerModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5222F182AB00BD4E9C /* LocationPickerModuleInput.swift */; }; 0E8BD343238566AB008B31EF /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D222B7C7AC0015F9E0 /* SettingsTableViewController.swift */; }; 0E8BD345238566AB008B31EF /* SwipeDownToDismissTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6122CC93EB00BC6D64 /* SwipeDownToDismissTransitionAnimation.swift */; }; 0E8BD348238566AB008B31EF /* SettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20DC22B7C8650015F9E0 /* SettingsRouterInput.swift */; }; 0E8BD34A238566AB008B31EF /* MenuTableTransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215922BA28860015F9E0 /* MenuTableTransitionManager.swift */; }; 0E8BD34C238566AB008B31EF /* DefaultsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10132384610400A9CBA6 /* DefaultsRouter.swift */; }; - 0E8BD34E238566AB008B31EF /* WebTagSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2F22F057CC00BD4E9C /* WebTagSettingsRouterInput.swift */; }; 0E8BD353238566AB008B31EF /* LocalizationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9D0AB0231EBEFD00C6BDA7 /* LocalizationService.swift */; }; 0E8BD354238566AB008B31EF /* RURangeSeekSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E02ABB9237598C600ED4629 /* RURangeSeekSlider.swift */; }; 0E8BD355238566AB008B31EF /* CardsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DDC22B3C2160032F6CA /* CardsModuleInput.swift */; }; 0E8BD35B238566AB008B31EF /* PresentationAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DBD22B3921E0032F6CA /* PresentationAssembly.swift */; }; 0E8BD35D238566AB008B31EF /* AboutModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FC22B7D2C90015F9E0 /* AboutModuleInput.swift */; }; - 0E8BD363238566AB008B31EF /* WebTagSettingsTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3A22F05AA800BD4E9C /* WebTagSettingsTableInitializer.swift */; }; 0E8BD364238566AB008B31EF /* MenuRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF922B3FFBF0032F6CA /* MenuRouterInput.swift */; }; 0E8BD368238566AB008B31EF /* Double+Temperature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E02ABCA2379483A00ED4629 /* Double+Temperature.swift */; }; 0E8BD36B238566AB008B31EF /* AppStateServiceImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C302722D0B1C600B52E39 /* AppStateServiceImpl.swift */; }; 0E8BD36D238566AB008B31EF /* MenuViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF422B3FF1D0032F6CA /* MenuViewOutput.swift */; }; - 0E8BD36F238566AB008B31EF /* LocationPickerAppleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4C22F1823C00BD4E9C /* LocationPickerAppleViewController.swift */; }; 0E8BD372238566AB008B31EF /* SwipeDownToDismissTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA5F22CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift */; }; 0E8BD373238566AB008B31EF /* MenuViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF222B3FEFF0032F6CA /* MenuViewInput.swift */; }; 0E8BD377238566AB008B31EF /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F622B7D2090015F9E0 /* AboutViewController.swift */; }; @@ -216,29 +177,22 @@ 0E8BD37F238566AB008B31EF /* CardsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DD222B3BF180032F6CA /* CardsViewInput.swift */; }; 0E8BD382238566AB008B31EF /* AboutRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FA22B7D2990015F9E0 /* AboutRouter.swift */; }; 0E8BD389238566AB008B31EF /* PhotoPickerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5822CF621000172EEB /* PhotoPickerPresenter.swift */; }; - 0E8BD38A238566AB008B31EF /* LocationPickerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5422F182BF00BD4E9C /* LocationPickerPresenter.swift */; }; 0E8BD38D238566AB008B31EF /* DefaultsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10172384613E00A9CBA6 /* DefaultsModuleInput.swift */; }; 0E8BD392238566AB008B31EF /* HumidityUnit+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF5B75322DE153A00D9D14A /* HumidityUnit+Localization.swift */; }; 0E8BD393238566AB008B31EF /* SwipeDownToDismissInteractiveTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6322CC943900BC6D64 /* SwipeDownToDismissInteractiveTransition.swift */; }; 0E8BD395238566AB008B31EF /* NSObject+Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5322CCBBE800172EEB /* NSObject+Observable.swift */; }; - 0E8BD398238566AB008B31EF /* LocationPickerAppleConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F5922F1832600BD4E9C /* LocationPickerAppleConfigurator.swift */; }; 0E8BD399238566AB008B31EF /* AppAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DA722B387A00032F6CA /* AppAssembly.swift */; }; 0E8BD39A238566AB008B31EF /* AppStateService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C302422D0B19600B52E39 /* AppStateService.swift */; }; 0E8BD39B238566AB008B31EF /* MenuTableDismissTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0C22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift */; }; 0E8BD39E238566AB008B31EF /* SettingsTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E722B7C92C0015F9E0 /* SettingsTableConfigurator.swift */; }; - 0E8BD3A1238566AB008B31EF /* LocationPickerModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F6122F193B300BD4E9C /* LocationPickerModuleOutput.swift */; }; - 0E8BD3A4238566AB008B31EF /* LocationPickerViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F4722F181DA00BD4E9C /* LocationPickerViewInput.swift */; }; 0E8BD3A5238566AB008B31EF /* SettingsTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E522B7C8F20015F9E0 /* SettingsTableInitializer.swift */; }; 0E8BD3AA238566AB008B31EF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64333D2820B0C45900CDF4B6 /* AppDelegate.swift */; }; 0E8BD3AD238566AB008B31EF /* RUError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1D9F22B36C100032F6CA /* RUError.swift */; }; - 0E8BD3B1238566AB008B31EF /* WebTagSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3E22F0702D00BD4E9C /* WebTagSettingsViewModel.swift */; }; - 0E8BD3B3238566AB008B31EF /* WebTagSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F3522F0581E00BD4E9C /* WebTagSettingsPresenter.swift */; }; 0E8BD3B4238566AB008B31EF /* MenuModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFD22B3FFFC0032F6CA /* MenuModuleInput.swift */; }; 0E8BD3B7238566AB008B31EF /* DefaultsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10112384605A00A9CBA6 /* DefaultsTableViewController.swift */; }; 0E8BD3BA238566AB008B31EF /* MenuTableTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0822B4024E0032F6CA /* MenuTableTransitioningDelegate.swift */; }; 0E8BD3C2238566AB008B31EF /* SettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D722B7C8060015F9E0 /* SettingsViewOutput.swift */; }; 0E8BD3C5238566AB008B31EF /* SettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E022B7C8A90015F9E0 /* SettingsModuleInput.swift */; }; - 0E8BD3C9238566AB008B31EF /* WebTagSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E046F2A22F0563100BD4E9C /* WebTagSettingsViewOutput.swift */; }; 0E8BD3CA238566AB008B31EF /* CardsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE322B3C2710032F6CA /* CardsRouter.swift */; }; 0E8BD3CC238566AB008B31EF /* CardsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE122B3C25F0032F6CA /* CardsRouterInput.swift */; }; 0E8BD3CF238566AB008B31EF /* SettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D522B7C7E70015F9E0 /* SettingsViewInput.swift */; }; @@ -247,7 +201,6 @@ 0E8BD3E0238566AB008B31EF /* About.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20EE22B7D1580015F9E0 /* About.storyboard */; }; 0E8BD3E1238566AB008B31EF /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0ECDF1B42313D65500A09ACA /* GoogleService-Info.plist */; }; 0E8BD3E3238566AB008B31EF /* Networking.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0E9F97B422EC44930015ADE2 /* Networking.plist */; }; - 0E8BD3E5238566AB008B31EF /* LocationPicker.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E046F4522F17EF400BD4E9C /* LocationPicker.storyboard */; }; 0E8BD3E6238566AB008B31EF /* Defaults.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E8A100123845E5100A9CBA6 /* Defaults.storyboard */; }; 0E8BD3E8238566AB008B31EF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 64333D3120B0C45A00CDF4B6 /* LaunchScreen.storyboard */; }; 0E8BD3EA238566AB008B31EF /* Oswald-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6486970F20E042E000CCD7C1 /* Oswald-Bold.ttf */; }; @@ -260,7 +213,6 @@ 0E8BD3FA238566AB008B31EF /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20D022B7C6F30015F9E0 /* Settings.storyboard */; }; 0E8BD3FB238566AB008B31EF /* Muli-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 64678190225D02CE0072856A /* Muli-Bold.ttf */; }; 0E8BD3FD238566AB008B31EF /* Montserrat-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 643C651E21C38F490037BE5B /* Montserrat-Bold.ttf */; }; - 0E8BD3FE238566AB008B31EF /* WebTagSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E046F2622F04A0300BD4E9C /* WebTagSettings.storyboard */; }; 0E97D79B268C881300FE9D5B /* DFUModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E97D79A268C881300FE9D5B /* DFUModuleInput.swift */; }; 0E97D79C268C881300FE9D5B /* DFUModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E97D79A268C881300FE9D5B /* DFUModuleInput.swift */; }; 0E97D79E268C884500FE9D5B /* DFUPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E97D79D268C884500FE9D5B /* DFUPresenter.swift */; }; @@ -1206,33 +1158,9 @@ 0E00C5072685D82B009B3C24 /* RuuviDaemonError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviDaemonError+LocalizedError.swift"; sourceTree = ""; }; 0E02ABB9237598C600ED4629 /* RURangeSeekSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RURangeSeekSlider.swift; sourceTree = ""; }; 0E02ABCA2379483A00ED4629 /* Double+Temperature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+Temperature.swift"; sourceTree = ""; }; - 0E046F2622F04A0300BD4E9C /* WebTagSettings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = WebTagSettings.storyboard; sourceTree = ""; }; - 0E046F2822F0561B00BD4E9C /* WebTagSettingsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsViewInput.swift; sourceTree = ""; }; - 0E046F2A22F0563100BD4E9C /* WebTagSettingsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsViewOutput.swift; sourceTree = ""; }; - 0E046F2D22F0569000BD4E9C /* WebTagSettingsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsTableViewController.swift; sourceTree = ""; }; - 0E046F2F22F057CC00BD4E9C /* WebTagSettingsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsRouterInput.swift; sourceTree = ""; }; - 0E046F3122F057DD00BD4E9C /* WebTagSettingsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsRouter.swift; sourceTree = ""; }; - 0E046F3322F057FC00BD4E9C /* WebTagSettingsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsModuleInput.swift; sourceTree = ""; }; - 0E046F3522F0581E00BD4E9C /* WebTagSettingsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsPresenter.swift; sourceTree = ""; }; - 0E046F3A22F05AA800BD4E9C /* WebTagSettingsTableInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsTableInitializer.swift; sourceTree = ""; }; - 0E046F3C22F05B0900BD4E9C /* WebTagSettingsTableConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsTableConfigurator.swift; sourceTree = ""; }; - 0E046F3E22F0702D00BD4E9C /* WebTagSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebTagSettingsViewModel.swift; sourceTree = ""; }; - 0E046F4522F17EF400BD4E9C /* LocationPicker.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LocationPicker.storyboard; sourceTree = ""; }; - 0E046F4722F181DA00BD4E9C /* LocationPickerViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerViewInput.swift; sourceTree = ""; }; - 0E046F4922F1820400BD4E9C /* LocationPickerViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerViewOutput.swift; sourceTree = ""; }; - 0E046F4C22F1823C00BD4E9C /* LocationPickerAppleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerAppleViewController.swift; sourceTree = ""; }; - 0E046F4E22F1827800BD4E9C /* LocationPickerRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerRouterInput.swift; sourceTree = ""; }; - 0E046F5022F1828900BD4E9C /* LocationPickerRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerRouter.swift; sourceTree = ""; }; - 0E046F5222F182AB00BD4E9C /* LocationPickerModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerModuleInput.swift; sourceTree = ""; }; - 0E046F5422F182BF00BD4E9C /* LocationPickerPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerPresenter.swift; sourceTree = ""; }; - 0E046F5722F182F500BD4E9C /* LocationPickerAppleInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerAppleInitializer.swift; sourceTree = ""; }; - 0E046F5922F1832600BD4E9C /* LocationPickerAppleConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerAppleConfigurator.swift; sourceTree = ""; }; - 0E046F6122F193B300BD4E9C /* LocationPickerModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerModuleOutput.swift; sourceTree = ""; }; 0E0501202685E895007060C4 /* HeartbeatDaemonTitles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatDaemonTitles.swift; sourceTree = ""; }; 0E09672422AE897000E85F48 /* CALayer+IB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CALayer+IB.swift"; sourceTree = ""; }; 0E0A381823616AC3003A0364 /* UserDefaults+Optional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Optional.swift"; sourceTree = ""; }; - 0E11D222267F2EC0002D0686 /* VirtualLocation+Localization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VirtualLocation+Localization.swift"; sourceTree = ""; }; - 0E11D225267F3100002D0686 /* RuuviVirtualError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviVirtualError+LocalizedError.swift"; sourceTree = ""; }; 0E197C6523C4A47A0074015B /* MailComposerPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailComposerPresenter.swift; sourceTree = ""; }; 0E197C6A23C4A52A0074015B /* MailComposerPresenterMessageUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailComposerPresenterMessageUI.swift; sourceTree = ""; }; 0E197C6E23C4A7D00074015B /* Presentation.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Presentation.plist; sourceTree = ""; }; @@ -1894,63 +1822,6 @@ path = RangeSeekSlider; sourceTree = ""; }; - 0E046F2022F049C500BD4E9C /* WebTagSettings */ = { - isa = PBXGroup; - children = ( - 0E046F2622F04A0300BD4E9C /* WebTagSettings.storyboard */, - 0E046F2522F049F000BD4E9C /* Assembly */, - 0E046F2322F049E200BD4E9C /* Presenter */, - 0E046F2222F049DE00BD4E9C /* Router */, - 0E046F2122F049D900BD4E9C /* View */, - ); - path = WebTagSettings; - sourceTree = ""; - }; - 0E046F2122F049D900BD4E9C /* View */ = { - isa = PBXGroup; - children = ( - 0E046F2C22F0563E00BD4E9C /* Table */, - 0E046F3E22F0702D00BD4E9C /* WebTagSettingsViewModel.swift */, - 0E046F2822F0561B00BD4E9C /* WebTagSettingsViewInput.swift */, - 0E046F2A22F0563100BD4E9C /* WebTagSettingsViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E046F2222F049DE00BD4E9C /* Router */ = { - isa = PBXGroup; - children = ( - 0E046F2F22F057CC00BD4E9C /* WebTagSettingsRouterInput.swift */, - 0E046F3122F057DD00BD4E9C /* WebTagSettingsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E046F2322F049E200BD4E9C /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E046F3322F057FC00BD4E9C /* WebTagSettingsModuleInput.swift */, - 0E046F3522F0581E00BD4E9C /* WebTagSettingsPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E046F2522F049F000BD4E9C /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E046F3922F05A9300BD4E9C /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E046F2C22F0563E00BD4E9C /* Table */ = { - isa = PBXGroup; - children = ( - 0E046F2D22F0569000BD4E9C /* WebTagSettingsTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; 0E046F3722F0585E00BD4E9C /* Transitions */ = { isa = PBXGroup; children = ( @@ -1970,81 +1841,6 @@ path = SwipeDownToDismiss; sourceTree = ""; }; - 0E046F3922F05A9300BD4E9C /* Table */ = { - isa = PBXGroup; - children = ( - 0E046F3A22F05AA800BD4E9C /* WebTagSettingsTableInitializer.swift */, - 0E046F3C22F05B0900BD4E9C /* WebTagSettingsTableConfigurator.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E046F4022F17EC600BD4E9C /* LocationPicker */ = { - isa = PBXGroup; - children = ( - 0E046F4522F17EF400BD4E9C /* LocationPicker.storyboard */, - 0E046F4422F17EE100BD4E9C /* Assembly */, - 0E046F4322F17EDC00BD4E9C /* Presenter */, - 0E046F4222F17ED700BD4E9C /* Router */, - 0E046F4122F17ED300BD4E9C /* View */, - ); - path = LocationPicker; - sourceTree = ""; - }; - 0E046F4122F17ED300BD4E9C /* View */ = { - isa = PBXGroup; - children = ( - 0E046F4B22F1821000BD4E9C /* Apple */, - 0E046F4722F181DA00BD4E9C /* LocationPickerViewInput.swift */, - 0E046F4922F1820400BD4E9C /* LocationPickerViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E046F4222F17ED700BD4E9C /* Router */ = { - isa = PBXGroup; - children = ( - 0E046F4E22F1827800BD4E9C /* LocationPickerRouterInput.swift */, - 0E046F5022F1828900BD4E9C /* LocationPickerRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E046F4322F17EDC00BD4E9C /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E046F5222F182AB00BD4E9C /* LocationPickerModuleInput.swift */, - 0E046F6122F193B300BD4E9C /* LocationPickerModuleOutput.swift */, - 0E046F5422F182BF00BD4E9C /* LocationPickerPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E046F4422F17EE100BD4E9C /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E046F5622F182E600BD4E9C /* Apple */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E046F4B22F1821000BD4E9C /* Apple */ = { - isa = PBXGroup; - children = ( - 0E046F4C22F1823C00BD4E9C /* LocationPickerAppleViewController.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 0E046F5622F182E600BD4E9C /* Apple */ = { - isa = PBXGroup; - children = ( - 0E046F5722F182F500BD4E9C /* LocationPickerAppleInitializer.swift */, - 0E046F5922F1832600BD4E9C /* LocationPickerAppleConfigurator.swift */, - ); - path = Apple; - sourceTree = ""; - }; 0E09671522AE74CB00E85F48 /* Application */ = { isa = PBXGroup; children = ( @@ -2139,11 +1935,9 @@ E16B8F3A28D108970025B92D /* My Ruuvi */, 0EEB20E922B7D1350015F9E0 /* About */, 0E1C1DCE22B3BDAE0032F6CA /* Dashboard */, - 0E046F4022F17EC600BD4E9C /* LocationPicker */, 0E1C1DEB22B3FDB40032F6CA /* Menu */, 0EEB20CE22B7C6DA0015F9E0 /* Settings */, 0EF2862522CBAF280026C7A5 /* TagSettings */, - 0E046F2022F049C500BD4E9C /* WebTagSettings */, 71A3760FF84549A5FB45C805 /* SignIn */, DB47D7C8D6149FEA8DD05FDC /* Share */, ); @@ -2172,7 +1966,6 @@ 0EF4E33F26824EF500D83CC7 /* DfuFirmware+Log.swift */, 0E02ABCA2379483A00ED4629 /* Double+Temperature.swift */, 0EF5B75322DE153A00D9D14A /* HumidityUnit+Localization.swift */, - 0E11D222267F2EC0002D0686 /* VirtualLocation+Localization.swift */, 0EBAF064232002A00025A191 /* Language+Localization.swift */, 340BE39A27B54FEB006D6C34 /* String+Email.swift */, E1395BE9294F6C2A00C403C6 /* String+Localization.swift */, @@ -2695,7 +2488,6 @@ 0EA796882664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift */, 0EA7968C2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift */, 0E2AFF9F266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift */, - 0E11D225267F3100002D0686 /* RuuviVirtualError+LocalizedError.swift */, 0EA7AB792680A68200C137AD /* RuuviCoreError+LocalizedError.swift */, 0EF4E33C26824ABD00D83CC7 /* RuuviDFUError+LocalizedError.swift */, ); @@ -4924,7 +4716,6 @@ 66BC44962657AED400A03253 /* OffsetCorrection.storyboard in Resources */, 0E8BD3E3238566AB008B31EF /* Networking.plist in Resources */, 340BE39F27B56129006D6C34 /* ruuvi_logo_splash.png in Resources */, - 0E8BD3E5238566AB008B31EF /* LocationPicker.storyboard in Resources */, 0E8BD3E6238566AB008B31EF /* Defaults.storyboard in Resources */, 0E8BD3E8238566AB008B31EF /* LaunchScreen.storyboard in Resources */, 0E8BD3EA238566AB008B31EF /* Oswald-Bold.ttf in Resources */, @@ -4951,7 +4742,6 @@ 0E8BD3FB238566AB008B31EF /* Muli-Bold.ttf in Resources */, 0E197C8223C5CDBE0074015B /* iOSDeviceModelMapping.plist in Resources */, 0E8BD3FD238566AB008B31EF /* Montserrat-Bold.ttf in Resources */, - 0E8BD3FE238566AB008B31EF /* WebTagSettings.storyboard in Resources */, E1BAC13B2A7598F000EA820E /* Muli-ExtraBold.ttf in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4990,7 +4780,6 @@ 66BC44952657AED400A03253 /* OffsetCorrection.storyboard in Resources */, 0E9F97B522EC44930015ADE2 /* Networking.plist in Resources */, 340BE39E27B56129006D6C34 /* ruuvi_logo_splash.png in Resources */, - 0E046F4622F17EF400BD4E9C /* LocationPicker.storyboard in Resources */, 0E8A100223845E5100A9CBA6 /* Defaults.storyboard in Resources */, 64333D3320B0C45A00CDF4B6 /* LaunchScreen.storyboard in Resources */, 6486971020E0436A00CCD7C1 /* Oswald-Bold.ttf in Resources */, @@ -5017,7 +4806,6 @@ 64678191225D03300072856A /* Muli-Bold.ttf in Resources */, 0E197C8123C5CDBE0074015B /* iOSDeviceModelMapping.plist in Resources */, 643C651F21C38F490037BE5B /* Montserrat-Bold.ttf in Resources */, - 0E046F2722F04A0300BD4E9C /* WebTagSettings.storyboard in Resources */, E1BAC13A2A7598F000EA820E /* Muli-ExtraBold.ttf in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -5363,7 +5151,6 @@ 0EAD33D82399273D00EC5BAA /* HeartbeatInitializer.swift in Sources */, E1CE5E4329FC39D000391109 /* DefaultsModuleOutput.swift in Sources */, E1B7B5382AE98B72009D747E /* SensorRemovalModuleInput.swift in Sources */, - 0E8BD2CD238566AB008B31EF /* LocationPickerRouterInput.swift in Sources */, E19EAF98299E6083005827E4 /* SignInBenefitsRouterInput.swift in Sources */, E186AB2C2844A273004926FC /* RuuviWidgetsConfiguration.intentdefinition in Sources */, 0EA511B9261F3C2C00EE5D5E /* LocalFeatureToggleProvider.swift in Sources */, @@ -5374,7 +5161,6 @@ A91D02FE2511207300694733 /* SelectionTableViewCell.swift in Sources */, 0E8BD2CE238566AB008B31EF /* Language+Localization.swift in Sources */, A91D02F82511207300694733 /* SelectionModuleInput.swift in Sources */, - 0E8BD2D0238566AB008B31EF /* WebTagSettingsRouter.swift in Sources */, E19691512A06DCA400DC360E /* NotificationsSettingsModuleFactory.swift in Sources */, E10E18AF297D6672002C78C3 /* RuuviCloudPresenter.swift in Sources */, E19EAF76299AE3B0005827E4 /* SignInView.swift in Sources */, @@ -5392,7 +5178,6 @@ A9FC79002579675100F94604 /* UniversalLinkRouter.swift in Sources */, E1ED426A28FF253B00302179 /* TagChartsViewModel.swift in Sources */, 0E8BD2D6238566AB008B31EF /* MenuTablePresentTransitionAnimation.swift in Sources */, - 0E8BD2D7238566AB008B31EF /* WebTagSettingsViewInput.swift in Sources */, 0E8BD2DA238566AB008B31EF /* MenuModuleOutput.swift in Sources */, E1198A3629BA76CB002245CF /* ASSelectionViewInput.swift in Sources */, 0E3CA70D267365B1000D9B25 /* Debouncer.swift in Sources */, @@ -5405,7 +5190,6 @@ 0E97D7A9268C922C00FE9D5B /* DFUInteractor.swift in Sources */, E19691572A06DCBB00DC360E /* NotificationsSettingsRouter.swift in Sources */, 0EE36E4026957E010021B746 /* DFUInteractorInput.swift in Sources */, - 0E8BD2DE238566AB008B31EF /* LocationPickerAppleInitializer.swift in Sources */, E19EAF79299AE5EA005827E4 /* SignInVerifyView.swift in Sources */, E168B4B72886AF1200D6B5C6 /* UnitSettingsType.swift in Sources */, E1B5800929859EDE00B441FB /* DevicesInteractorInput.swift in Sources */, @@ -5423,10 +5207,8 @@ A9FC79182579678D00F94604 /* UniversalLinkCoordinatormpl.swift in Sources */, E1E102EF28F348B700815508 /* TagChartsHelper.swift in Sources */, 0E8BD2E6238566AB008B31EF /* DefaultsViewInput.swift in Sources */, - 0E8BD2E7238566AB008B31EF /* LocationPickerRouter.swift in Sources */, E191F1EA2968B6B100F1FEA6 /* TagSettingsViewController.swift in Sources */, E1167083296346D5002DF7BF /* BackgroundSelectionModuleInput.swift in Sources */, - 0E8BD2E8238566AB008B31EF /* WebTagSettingsModuleInput.swift in Sources */, 0E8BD2E9238566AB008B31EF /* MenuTableConfigurator.swift in Sources */, 0EAD33E22399273D00EC5BAA /* HeartbeatViewModel.swift in Sources */, E1597A6629608CF300DFB70B /* GlobalHelpers.swift in Sources */, @@ -5464,7 +5246,6 @@ E19EAFA5299E6211005827E4 /* SignInBenefitsModuleOutput.swift in Sources */, E10E18732978AF3D002C78C3 /* TagSettingsViewModel.swift in Sources */, 0E8BD303238566AB008B31EF /* UIApplication+ViewController.swift in Sources */, - 0E8BD304238566AB008B31EF /* WebTagSettingsTableConfigurator.swift in Sources */, A92E3C6C2426767E00D981D5 /* MeasurementType.swift in Sources */, E1198A3329BA76C1002245CF /* ASSelectionViewOutput.swift in Sources */, E1ED426F28FF261D00302179 /* CustomYAxisRenderer.swift in Sources */, @@ -5510,10 +5291,8 @@ 0E2AFFA1266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift in Sources */, 0E8BD326238566AB008B31EF /* MenuTableInitializer.swift in Sources */, E1CD78052878302C00F1F0EB /* UnitSettingsViewOutput.swift in Sources */, - 0E8BD327238566AB008B31EF /* LocationPickerViewOutput.swift in Sources */, E1CA28AF29201F34009E4423 /* RUAlertExpandButton.swift in Sources */, E19EAFAB299E62C0005827E4 /* SignInBenefitsViewOutput.swift in Sources */, - 0E8BD328238566AB008B31EF /* WebTagSettingsTableViewController.swift in Sources */, E191F222296A00CE00F1FEA6 /* TagSettingsFooterCell.swift in Sources */, 66BC44A52657AED400A03253 /* OffsetCorrectionModuleInput.swift in Sources */, A9E5994B2557341F00F9E5CC /* ShareDescriptionTableViewCell.swift in Sources */, @@ -5547,7 +5326,6 @@ 0EA796862664B84D002BA25D /* RuuviReactorError+LocalizedError.swift in Sources */, 0EF4E34126824EF500D83CC7 /* DfuFirmware+Log.swift in Sources */, 0EB8ED37268F685500C6B0FA /* URLSession+downloadTaskPublisher.swift in Sources */, - 0E8BD33E238566AB008B31EF /* LocationPickerModuleInput.swift in Sources */, E11FDA6E29A2A3C6003ADA7B /* DefaultsPlainTableViewCell.swift in Sources */, E191F20A2969E11F00F1FEA6 /* TagSettingsRouterInput.swift in Sources */, E1CD77FF28782F9900F1F0EB /* UnitSettingsModuleOutput.swift in Sources */, @@ -5589,7 +5367,6 @@ E1B7B5402AEAD61A009D747E /* SensorRemovalModuleOutput.swift in Sources */, 0E2513602684AEAD004A522A /* RuuviNotifierTitlesImpl.swift in Sources */, E1B5800F2986AE0800B441FB /* RuuviContextMenuButton.swift in Sources */, - 0E8BD34E238566AB008B31EF /* WebTagSettingsRouterInput.swift in Sources */, A91D03072511207300694733 /* SelectionRouter.swift in Sources */, 0E8BD353238566AB008B31EF /* LocalizationService.swift in Sources */, 3490A4C427D9F2C80032BBAB /* UINavigationController.swift in Sources */, @@ -5619,7 +5396,6 @@ 340BE39127B54F37006D6C34 /* OwnerViewInput.swift in Sources */, E1E3C33A298EC9DC00A59CB8 /* DashboardModuleFactory.swift in Sources */, E1198A0929BA68B6002245CF /* AppearanceSettingsRouterInput.swift in Sources */, - 0E8BD363238566AB008B31EF /* WebTagSettingsTableInitializer.swift in Sources */, 0E8BD364238566AB008B31EF /* MenuRouterInput.swift in Sources */, 0EA796822664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift in Sources */, E1CD77F928782F2200F1F0EB /* UnitSettingsPresenter.swift in Sources */, @@ -5641,7 +5417,6 @@ E1198A1F29BA6B7E002245CF /* AppearanceSettingsModuleInput.swift in Sources */, 0E8BD36D238566AB008B31EF /* MenuViewOutput.swift in Sources */, 0EAD33DB2399273D00EC5BAA /* HeartbeatPresenter.swift in Sources */, - 0E8BD36F238566AB008B31EF /* LocationPickerAppleViewController.swift in Sources */, 0E8BD372238566AB008B31EF /* SwipeDownToDismissTransitioningDelegate.swift in Sources */, E19EAF95299E6038005827E4 /* SignInBenefitsModuleFactory.swift in Sources */, 0E8BD373238566AB008B31EF /* MenuViewInput.swift in Sources */, @@ -5652,7 +5427,6 @@ 0EAD33E42399273D00EC5BAA /* HeartbeatViewController.swift in Sources */, E191F20D2969E14600F1FEA6 /* TagSettingsRouter.swift in Sources */, 0E8BD377238566AB008B31EF /* AboutViewController.swift in Sources */, - 0E11D224267F2EC0002D0686 /* VirtualLocation+Localization.swift in Sources */, E16B8F5B28D113EA0025B92D /* MyRuuviAccountRouter.swift in Sources */, 66BC44A22657AED400A03253 /* OffsetCorrectionPresenter.swift in Sources */, 66BC44AE2657AED400A03253 /* OffsetCorrectionViewModel.swift in Sources */, @@ -5667,7 +5441,6 @@ A964647F247BAE6B0001D55D /* ChartSettingsInitializer.swift in Sources */, A93CDCD025659BA600018C6C /* AlertPresenter.swift in Sources */, 0E8BD389238566AB008B31EF /* PhotoPickerPresenter.swift in Sources */, - 0E8BD38A238566AB008B31EF /* LocationPickerPresenter.swift in Sources */, E1597A692960944600DFB70B /* DashboardCellDelegate.swift in Sources */, 0E00C4F22684D97B009B3C24 /* ExportHeadersProvider.swift in Sources */, E18D04BE28E8B397008EF5EC /* TagChartsViewInteractorInput.swift in Sources */, @@ -5687,7 +5460,6 @@ E1E3C337298D858D00A59CB8 /* TagChartsModuleFactory.swift in Sources */, 0E00C5092685D82B009B3C24 /* RuuviDaemonError+LocalizedError.swift in Sources */, 0EF4E33E26824ABD00D83CC7 /* RuuviDFUError+LocalizedError.swift in Sources */, - 0E8BD398238566AB008B31EF /* LocationPickerAppleConfigurator.swift in Sources */, E191F2102969E1C300F1FEA6 /* TagSettingsPresenter.swift in Sources */, 0E8BD399238566AB008B31EF /* AppAssembly.swift in Sources */, E16051ED285CBA57003FCA70 /* FileManager+Date.swift in Sources */, @@ -5698,12 +5470,10 @@ 0E8BD39B238566AB008B31EF /* MenuTableDismissTransitionAnimation.swift in Sources */, E1AB90682A0EB1AD00543F61 /* SensorForceClaimRouter.swift in Sources */, 0E8BD39E238566AB008B31EF /* SettingsTableConfigurator.swift in Sources */, - 0E8BD3A1238566AB008B31EF /* LocationPickerModuleOutput.swift in Sources */, E18D04A628E8A5A3008EF5EC /* TagChartsViewConfigurator.swift in Sources */, E116709029635B53002DF7BF /* BackgroundSelectionUploadProgressView.swift in Sources */, 0EB8ED4026916D1700C6B0FA /* LargeButtonStyle.swift in Sources */, E1E1475D28E85EE700832B8C /* UIImageView+Init.swift in Sources */, - 0E8BD3A4238566AB008B31EF /* LocationPickerViewInput.swift in Sources */, 0E8BD3A5238566AB008B31EF /* SettingsTableInitializer.swift in Sources */, 0EA7967E2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift in Sources */, 0EAD33E12399273D00EC5BAA /* HeartbeatViewInput.swift in Sources */, @@ -5726,11 +5496,9 @@ 0E8BD3AD238566AB008B31EF /* RUError.swift in Sources */, E1597A5D295E24D400DFB70B /* RuuviAssets.swift in Sources */, A964647C247BAE6B0001D55D /* ChartSettingsConfigurator.swift in Sources */, - 0E8BD3B1238566AB008B31EF /* WebTagSettingsViewModel.swift in Sources */, 0EB8ED22268EFF6400C6B0FA /* Feedback.swift in Sources */, 0E97D79F268C884500FE9D5B /* DFUPresenter.swift in Sources */, 0E0501222685E895007060C4 /* HeartbeatDaemonTitles.swift in Sources */, - 0E8BD3B3238566AB008B31EF /* WebTagSettingsPresenter.swift in Sources */, E1CE4C782959DF01005C023F /* DashboardIndicatorView.swift in Sources */, E1ED427328FF261D00302179 /* CustomXAxisRenderer.swift in Sources */, 0E2B339F26A2BCBE00366B01 /* OnboardRouter.swift in Sources */, @@ -5747,11 +5515,9 @@ 0E8BD3C2238566AB008B31EF /* SettingsViewOutput.swift in Sources */, 0E290A862660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift in Sources */, A9646476247BAE6B0001D55D /* ChartSettingsViewOutput.swift in Sources */, - 0E11D227267F3100002D0686 /* RuuviVirtualError+LocalizedError.swift in Sources */, E191F1ED2968BCF300F1FEA6 /* TagSettingsBasicCell.swift in Sources */, 0E8BD3C5238566AB008B31EF /* SettingsModuleInput.swift in Sources */, 0EB48DA42619D7EE008E0D2D /* FirebaseFeatureToggleProvider.swift in Sources */, - 0E8BD3C9238566AB008B31EF /* WebTagSettingsViewOutput.swift in Sources */, 0E197C7A23C5CCBC0074015B /* InfoProviderImpl.swift in Sources */, 0E8BD3CA238566AB008B31EF /* CardsRouter.swift in Sources */, E10E18BE297D68EB002C78C3 /* RuuviCloudModuleInput.swift in Sources */, @@ -5914,7 +5680,6 @@ E1597A46295CD5E400DFB70B /* DashboardModuleInput.swift in Sources */, E16B8F4E28D113230025B92D /* MyRuuviAccountInitializer.swift in Sources */, A976CA7E24A928C20099BDC1 /* ChartSettingsDisclosureTableViewCell.swift in Sources */, - 0E046F4F22F1827800BD4E9C /* LocationPickerRouterInput.swift in Sources */, E19EAF7B299BF94C005827E4 /* SignInBenefitsViewController.swift in Sources */, 0E9E775A238CCE5F006D7013 /* String+Replace.swift in Sources */, E19EAFB0299EB46D005827E4 /* NoSensorView.swift in Sources */, @@ -5925,7 +5690,6 @@ 66BC44982657AED400A03253 /* OffsetCorrectionAppleInitializer.swift in Sources */, E1B7B53F2AEAD61A009D747E /* SensorRemovalModuleOutput.swift in Sources */, 0E84BF592397F3C600A37E1A /* HeartbeatViewModel.swift in Sources */, - 0E046F3222F057DD00BD4E9C /* WebTagSettingsRouter.swift in Sources */, 0EB8ED472692018000C6B0FA /* RuuviColor.swift in Sources */, E1597A4F295CD67900DFB70B /* DashboardInteractor.swift in Sources */, E16B8F4828D10E7A0025B92D /* MyRuuviAccountViewModel.swift in Sources */, @@ -5959,7 +5723,6 @@ 0E1C1E0B22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift in Sources */, E1CD780C287830B100F1F0EB /* UnitSettingsRouter.swift in Sources */, E1B57FF729859CEC00B441FB /* DevicesTableViewCell.swift in Sources */, - 0E046F2922F0561B00BD4E9C /* WebTagSettingsViewInput.swift in Sources */, 0E0501212685E895007060C4 /* HeartbeatDaemonTitles.swift in Sources */, 0EEB20CD22B7BD6C0015F9E0 /* MenuModuleOutput.swift in Sources */, 0E70A46322AF959E006CB87C /* Localizable.swift in Sources */, @@ -5968,7 +5731,6 @@ E1CD78012878302100F1F0EB /* UnitSettingsViewInput.swift in Sources */, E1198A1129BA6910002245CF /* AppearanceSettingsPresenter.swift in Sources */, 0EA511B8261F3C2C00EE5D5E /* LocalFeatureToggleProvider.swift in Sources */, - 0E046F5822F182F500BD4E9C /* LocationPickerAppleInitializer.swift in Sources */, A9E599582557345200F9E5CC /* ShareEmailInputTableViewCell.swift in Sources */, A91D02F12511207200694733 /* SelectionTableInitializer.swift in Sources */, E1B20C8A2926D2FC0023D739 /* Double+Extension.swift in Sources */, @@ -5987,8 +5749,6 @@ E19EAF72299ADB2F005827E4 /* UIButton+Extension.swift in Sources */, E1AB905E2A0EB0D000543F61 /* SensorForceClaimModuleFactory.swift in Sources */, 66718A6C266BD0E800A380F8 /* Color+Ruuvi.swift in Sources */, - 0E046F5122F1828900BD4E9C /* LocationPickerRouter.swift in Sources */, - 0E046F3422F057FC00BD4E9C /* WebTagSettingsModuleInput.swift in Sources */, E116708F29635B53002DF7BF /* BackgroundSelectionUploadProgressView.swift in Sources */, E1972BE129587615000E2AEC /* CardsLargeImageCell.swift in Sources */, 660EB29C266928E6000FD22B /* UIViewController+Alert.swift in Sources */, @@ -6032,7 +5792,6 @@ 0E1C1DBB22B3919F0032F6CA /* UIApplication+ViewController.swift in Sources */, E1CE5E4229FC39D000391109 /* DefaultsModuleOutput.swift in Sources */, E1D0238B29EB02C600EC0FFD /* RuuviUISwitch.swift in Sources */, - 0E046F3D22F05B0900BD4E9C /* WebTagSettingsTableConfigurator.swift in Sources */, A9E599612557346600F9E5CC /* ShareSendButtonTableViewCell.swift in Sources */, 0EF4E33D26824ABD00D83CC7 /* RuuviDFUError+LocalizedError.swift in Sources */, E1198A1E29BA6B7E002245CF /* AppearanceSettingsModuleInput.swift in Sources */, @@ -6074,10 +5833,8 @@ 0E8A101C2384618700A9CBA6 /* DefaultsInitializer.swift in Sources */, A9E5996A255734A000F9E5CC /* ShareEmailTableViewCell.swift in Sources */, 0E1C1E0322B400590032F6CA /* MenuTableInitializer.swift in Sources */, - 0E046F4A22F1820400BD4E9C /* LocationPickerViewOutput.swift in Sources */, 66BC44B62657AED400A03253 /* OffsetCorrectionRouterInput.swift in Sources */, A92E3C4C24261CF900D981D5 /* MeasurementType.swift in Sources */, - 0E046F2E22F0569000BD4E9C /* WebTagSettingsTableViewController.swift in Sources */, A9FC78E92579671B00F94604 /* UniversalLinkCoordinator.swift in Sources */, A93CDCCF25659BA600018C6C /* AlertPresenter.swift in Sources */, E1597A2D295B6E6B00DFB70B /* UIFont+Extension.swift in Sources */, @@ -6122,7 +5879,6 @@ E19EAFA7299E62A7005827E4 /* SignInBenefitsViewInput.swift in Sources */, E196917E2A06E03300DC360E /* PushAlertSoundSelectionPresenter.swift in Sources */, E1B5800129859D2300B441FB /* DevicesViewOutput.swift in Sources */, - 0E046F5322F182AB00BD4E9C /* LocationPickerModuleInput.swift in Sources */, A91D031A25113EAA00694733 /* UnitPressure+Extension.swift in Sources */, 0EB48E06261B1095008E0D2D /* FirebaseRemoteConfigService.swift in Sources */, 0EEB20D322B7C7AC0015F9E0 /* SettingsTableViewController.swift in Sources */, @@ -6141,7 +5897,6 @@ 340BE39627B54F38006D6C34 /* OwnerRouter.swift in Sources */, E18D04AF28E8A747008EF5EC /* TagChartsViewModuleOutput.swift in Sources */, 0E8A10142384610400A9CBA6 /* DefaultsRouter.swift in Sources */, - 0E046F3022F057CC00BD4E9C /* WebTagSettingsRouterInput.swift in Sources */, 0E197C7423C5C7A20074015B /* InfoProvider.swift in Sources */, E19EAF9E299E610A005827E4 /* SignInBenefitsPresenter.swift in Sources */, 340BE38C27B54F37006D6C34 /* OwnerPresenter.swift in Sources */, @@ -6178,7 +5933,6 @@ E16B8F5A28D113EA0025B92D /* MyRuuviAccountRouter.swift in Sources */, A9B57443253B994700DB7353 /* SignInViewInput.swift in Sources */, E1B20C872926CDE10023D739 /* UITextField+Extension.swift in Sources */, - 0E046F3B22F05AA800BD4E9C /* WebTagSettingsTableInitializer.swift in Sources */, E19EAF75299AE3B0005827E4 /* SignInView.swift in Sources */, 0E1C1DFA22B3FFBF0032F6CA /* MenuRouterInput.swift in Sources */, E1B7B5282AE98A37009D747E /* SensorRemovalViewController.swift in Sources */, @@ -6190,7 +5944,6 @@ E19691882A06E03300DC360E /* PushAlertSoundSelectionViewOutput.swift in Sources */, 0E5C302822D0B1C600B52E39 /* AppStateServiceImpl.swift in Sources */, 0E1C1DF522B3FF1D0032F6CA /* MenuViewOutput.swift in Sources */, - 0E046F4D22F1823C00BD4E9C /* LocationPickerAppleViewController.swift in Sources */, E18D04AC28E8A737008EF5EC /* TagChartsViewModuleInput.swift in Sources */, 0EB8ED1E268EFF4200C6B0FA /* Publishers+System.swift in Sources */, 0E53DA6022CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift in Sources */, @@ -6224,7 +5977,6 @@ 0E84BF6D239802CA00A37E1A /* HeartbeatPresenter.swift in Sources */, 0EC50F5922CF621000172EEB /* PhotoPickerPresenter.swift in Sources */, E1CA28AE29201F34009E4423 /* RUAlertExpandButton.swift in Sources */, - 0E046F5522F182BF00BD4E9C /* LocationPickerPresenter.swift in Sources */, 0E8A10182384613E00A9CBA6 /* DefaultsModuleInput.swift in Sources */, 66BC449E2657AED400A03253 /* OffsetCorrectionModuleOutput.swift in Sources */, 0EB8ED21268EFF6400C6B0FA /* Feedback.swift in Sources */, @@ -6241,7 +5993,6 @@ 0EC50F5422CCBBE800172EEB /* NSObject+Observable.swift in Sources */, E18D04A528E8A5A3008EF5EC /* TagChartsViewConfigurator.swift in Sources */, E1B7B5242AE989ED009D747E /* SensorRemovalModuleFactory.swift in Sources */, - 0E046F5A22F1832600BD4E9C /* LocationPickerAppleConfigurator.swift in Sources */, 0E1C1DA822B387A00032F6CA /* AppAssembly.swift in Sources */, 0E5C302522D0B19600B52E39 /* AppStateService.swift in Sources */, 0E1C1E0D22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift in Sources */, @@ -6253,14 +6004,11 @@ E1198A0B29BA68BE002245CF /* AppearanceSettingsRouter.swift in Sources */, E191F1FE2969D6C900F1FEA6 /* TagSettingsPlainCell.swift in Sources */, E1E102EE28F348B700815508 /* TagChartsHelper.swift in Sources */, - 0E11D223267F2EC0002D0686 /* VirtualLocation+Localization.swift in Sources */, E191F1E92968B6B100F1FEA6 /* TagSettingsViewController.swift in Sources */, E1E6C215296C9CB100B3D037 /* Int+Extension.swift in Sources */, A9FC790E2579676E00F94604 /* UniversalLinkRouterImpl.swift in Sources */, - 0E046F6222F193B300BD4E9C /* LocationPickerModuleOutput.swift in Sources */, A964647B247BAE6B0001D55D /* ChartSettingsConfigurator.swift in Sources */, E1597A55295CD6E300DFB70B /* DashboardViewOutput.swift in Sources */, - 0E046F4822F181DA00BD4E9C /* LocationPickerViewInput.swift in Sources */, E1597A33295CC4F900DFB70B /* LowBatteryView.swift in Sources */, 0EEB20E622B7C8F20015F9E0 /* SettingsTableInitializer.swift in Sources */, E1198A1529BA6A06002245CF /* AppearanceSettingsViewOutput.swift in Sources */, @@ -6273,16 +6021,13 @@ E1B7B5372AE98B72009D747E /* SensorRemovalModuleInput.swift in Sources */, E18D04D428F1D52A008EF5EC /* TagChartsViewOutput.swift in Sources */, 0E1C1DA022B36C100032F6CA /* RUError.swift in Sources */, - 0E046F3F22F0702D00BD4E9C /* WebTagSettingsViewModel.swift in Sources */, 0E97D7A8268C922C00FE9D5B /* DFUInteractor.swift in Sources */, E10E18AE297D6672002C78C3 /* RuuviCloudPresenter.swift in Sources */, 340BE38E27B54F37006D6C34 /* OwnerModuleInput.swift in Sources */, - 0E046F3622F0581E00BD4E9C /* WebTagSettingsPresenter.swift in Sources */, 0E1C1DFE22B3FFFC0032F6CA /* MenuModuleInput.swift in Sources */, 0E8A10122384605A00A9CBA6 /* DefaultsTableViewController.swift in Sources */, 0E1C1E0922B4024E0032F6CA /* MenuTableTransitioningDelegate.swift in Sources */, E1198A2129BA6EC6002245CF /* RuuviTheme+Extension.swift in Sources */, - 0E11D226267F3100002D0686 /* RuuviVirtualError+LocalizedError.swift in Sources */, A98D3F12256CBD600066588B /* ShareViewController.swift in Sources */, 0EEB20D822B7C8060015F9E0 /* SettingsViewOutput.swift in Sources */, A91D0311251123B400694733 /* SelectionModuleOutput.swift in Sources */, @@ -6298,7 +6043,6 @@ E1B57FF129859CD400B441FB /* DevicesPresenter.swift in Sources */, 0E84BF652397F9DC00A37E1A /* HeartbeatTableViewController.swift in Sources */, E11FDA6D29A2A3C2003ADA7B /* DefaultsPlainTableViewCell.swift in Sources */, - 0E046F2B22F0563100BD4E9C /* WebTagSettingsViewOutput.swift in Sources */, E1198A2F29BA76A8002245CF /* ASSelectionTableViewCell.swift in Sources */, E18D04C428E9DF77008EF5EC /* TagChartsView.swift in Sources */, 0EB48D6F2619D50A008E0D2D /* FeatureToggle.swift in Sources */, diff --git a/station/Classes/Application/AppAssembly.swift b/station/Classes/Application/AppAssembly.swift index ab7a21350..7a73e36cd 100644 --- a/station/Classes/Application/AppAssembly.swift +++ b/station/Classes/Application/AppAssembly.swift @@ -5,7 +5,6 @@ import BTKit import RuuviLocal import RuuviPool import RuuviContext -import RuuviVirtual import RuuviStorage import RuuviService import RuuviDFU @@ -18,17 +17,12 @@ import RuuviDaemon import RuuviNotifier import RuuviNotification import RuuviRepository -import RuuviLocation import RuuviCore import RuuviDiscover import RuuviPresenters -import RuuviLocationPicker #if canImport(RuuviCloudPure) import RuuviCloudPure #endif -#if canImport(RuuviVirtualOWM) -import RuuviVirtualOWM -#endif #if canImport(RuuviContextRealm) import RuuviContextRealm #endif @@ -62,18 +56,6 @@ import RuuviDFUImpl #if canImport(RuuviMigrationImpl) import RuuviMigrationImpl #endif -#if canImport(RuuviVirtualPersistence) -import RuuviVirtualPersistence -#endif -#if canImport(RuuviVirtualReactor) -import RuuviVirtualReactor -#endif -#if canImport(RuuviVirtualRepository) -import RuuviVirtualRepository -#endif -#if canImport(RuuviVirtualStorage) -import RuuviVirtualStorage -#endif #if canImport(RuuviDaemonOperation) import RuuviDaemonOperation #endif @@ -83,9 +65,6 @@ import RuuviDaemonBackground #if canImport(RuuviDaemonRuuviTag) import RuuviDaemonRuuviTag #endif -#if canImport(RuuviDaemonVirtualTag) -import RuuviDaemonVirtualTag -#endif #if canImport(RuuviServiceGATT) import RuuviServiceGATT #endif @@ -116,15 +95,6 @@ import RuuviUserCoordinator #if canImport(RuuviCoreLocation) import RuuviCoreLocation #endif -#if canImport(RuuviLocationService) -import RuuviLocationService -#endif -#if canImport(RuuviVirtualOWM) -import RuuviVirtualOWM -#endif -#if canImport(RuuviVirtualService) -import RuuviVirtualService -#endif #if canImport(RuuviNotificationLocal) import RuuviNotificationLocal #endif @@ -134,9 +104,6 @@ import RuuviCoreImage #if canImport(RuuviCoreLocation) import RuuviCoreLocation #endif -#if canImport(RuuviLocationService) -import RuuviLocationService -#endif #if canImport(RuuviCorePN) import RuuviCorePN #endif @@ -163,7 +130,6 @@ final class AppAssembly { PersistenceAssembly(), PresentationAssembly(), DfuAssembly(), - VirtualAssembly() ]) } } @@ -189,7 +155,6 @@ private final class MigrationAssembly: Assembly { let idPersistence = r.resolve(RuuviLocalIDs.self)! let realmContext = r.resolve(RealmContext.self)! let ruuviPool = r.resolve(RuuviPool.self)! - let virtualStorage = r.resolve(VirtualStorage.self)! let ruuviStorage = r.resolve(RuuviStorage.self)! let ruuviAlertService = r.resolve(RuuviServiceAlert.self)! let ruuviOffsetCalibrationService = r.resolve(RuuviServiceOffsetCalibration.self)! @@ -198,7 +163,6 @@ private final class MigrationAssembly: Assembly { idPersistence: idPersistence, realmContext: realmContext, ruuviPool: ruuviPool, - virtualStorage: virtualStorage, ruuviStorage: ruuviStorage, ruuviAlertService: ruuviAlertService, ruuviOffsetCalibrationService: ruuviOffsetCalibrationService @@ -326,12 +290,6 @@ private final class PersistenceAssembly: Assembly { private final class NetworkingAssembly: Assembly { func assemble(container: Container) { - container.register(OpenWeatherMapAPI.self) { _ in - let apiKey: String = AppAssemblyConstants.openWeatherMapApiKey - let api = OpenWeatherMapAPIURLSession(apiKey: apiKey) - return api - } - let appGroupDefaults = UserDefaults( suiteName: AppGroupConstants.appGroupSuiteIdentifier ) @@ -359,32 +317,6 @@ private final class NetworkingAssembly: Assembly { } } -private final class VirtualAssembly: Assembly { - func assemble(container: Container) { - container.register(VirtualPersistence.self) { r in - let context = r.resolve(RealmContext.self)! - let settings = r.resolve(RuuviLocalSettings.self)! - return VirtualPersistenceRealm(context: context, settings: settings) - } - - container.register(VirtualReactor.self) { r in - let context = r.resolve(RealmContext.self)! - let persistence = r.resolve(VirtualPersistence.self)! - return VirtualReactorImpl(context: context, persistence: persistence) - }.inObjectScope(.container) - - container.register(VirtualRepository.self) { r in - let persistence = r.resolve(VirtualPersistence.self)! - return VirtualRepositoryCoordinator(persistence: persistence) - } - - container.register(VirtualStorage.self) { r in - let persistence = r.resolve(VirtualPersistence.self)! - return VirtualStorageCoordinator(persistence: persistence) - } - } -} - private final class DaemonAssembly: Assembly { // swiftlint:disable:next function_body_length func assemble(container: Container) { @@ -396,40 +328,18 @@ private final class DaemonAssembly: Assembly { return service }.inObjectScope(.container) - container.register(BackgroundTaskService.self) { r in - let webTagOperationsManager = r.resolve(WebTagOperationsManager.self)! - let service = BackgroundTaskServiceiOS13( - webTagOperationsManager: webTagOperationsManager - ) - return service - }.inObjectScope(.container) - container.register(DataPruningOperationsManager.self) { r in let settings = r.resolve(RuuviLocalSettings.self)! let ruuviStorage = r.resolve(RuuviStorage.self)! - let virtualStorage = r.resolve(VirtualStorage.self)! - let virtualRepository = r.resolve(VirtualRepository.self)! let ruuviPool = r.resolve(RuuviPool.self)! let manager = DataPruningOperationsManager( settings: settings, - virtualStorage: virtualStorage, - virtualRepository: virtualRepository, ruuviStorage: ruuviStorage, ruuviPool: ruuviPool ) return manager } - container.register(PullWebDaemon.self) { r in - let settings = r.resolve(RuuviLocalSettings.self)! - let webTagOperationsManager = r.resolve(WebTagOperationsManager.self)! - let daemon = PullWebDaemonOperations( - settings: settings, - webTagOperationsManager: webTagOperationsManager - ) - return daemon - }.inObjectScope(.container) - container.register(RuuviTagAdvertisementDaemon.self) { r in let settings = r.resolve(RuuviLocalSettings.self)! let foreground = r.resolve(BTForeground.self)! @@ -456,7 +366,6 @@ private final class DaemonAssembly: Assembly { let alertHandler = r.resolve(RuuviNotifier.self)! let alertService = r.resolve(RuuviServiceAlert.self)! let settings = r.resolve(RuuviLocalSettings.self)! - let pullWebDaemon = r.resolve(PullWebDaemon.self)! let daemon = RuuviTagHeartbeatDaemonBTKit( background: background, localNotificationsManager: localNotificationsManager, @@ -467,7 +376,6 @@ private final class DaemonAssembly: Assembly { alertService: alertService, alertHandler: alertHandler, settings: settings, - pullWebDaemon: pullWebDaemon, titles: HeartbeatDaemonTitles() ) return daemon @@ -490,38 +398,6 @@ private final class DaemonAssembly: Assembly { ) return daemon }.inObjectScope(.container) - - container.register(VirtualTagDaemon.self) { r in - let virtualService = r.resolve(VirtualService.self)! - let settings = r.resolve(RuuviLocalSettings.self)! - let virtualPersistence = r.resolve(VirtualPersistence.self)! - let alertService = r.resolve(RuuviNotifier.self)! - let virtualReactor = r.resolve(VirtualReactor.self)! - let daemon = VirtualTagDaemonImpl( - virtualService: virtualService, - settings: settings, - virtualPersistence: virtualPersistence, - alertService: alertService, - virtualReactor: virtualReactor - ) - return daemon - }.inObjectScope(.container) - - container.register(WebTagOperationsManager.self) { r in - let alertService = r.resolve(RuuviServiceAlert.self)! - let ruuviNotifier = r.resolve(RuuviNotifier.self)! - let virtualProviderService = r.resolve(VirtualProviderService.self)! - let virtualStorage = r.resolve(VirtualStorage.self)! - let virtualPersistence = r.resolve(VirtualPersistence.self)! - let manager = WebTagOperationsManager( - virtualProviderService: virtualProviderService, - alertService: alertService, - alertHandler: ruuviNotifier, - virtualStorage: virtualStorage, - virtualPersistence: virtualPersistence - ) - return manager - } } } @@ -548,12 +424,9 @@ private final class BusinessAssembly: Assembly { service.settings = r.resolve(RuuviLocalSettings.self) service.advertisementDaemon = r.resolve(RuuviTagAdvertisementDaemon.self) service.propertiesDaemon = r.resolve(RuuviTagPropertiesDaemon.self) - service.webTagDaemon = r.resolve(VirtualTagDaemon.self) service.cloudSyncDaemon = r.resolve(RuuviDaemonCloudSync.self) service.heartbeatDaemon = r.resolve(RuuviTagHeartbeatDaemon.self) service.ruuviUser = r.resolve(RuuviUser.self) - service.pullWebDaemon = r.resolve(PullWebDaemon.self) - service.backgroundTaskService = r.resolve(BackgroundTaskService.self) service.backgroundProcessService = r.resolve(BackgroundProcessService.self) #if canImport(RuuviAnalytics) service.userPropertiesService = r.resolve(RuuviAnalytics.self) @@ -610,11 +483,6 @@ private final class BusinessAssembly: Assembly { return provider }.inObjectScope(.container) - container.register(RuuviLocationService.self) { _ in - let service = RuuviLocationServiceApple() - return service - } - container.register(RemoteConfigService.self) { _ in let service = FirebaseRemoteConfigService() return service @@ -785,40 +653,15 @@ private final class BusinessAssembly: Assembly { return factory.createUser() }.inObjectScope(.container) - container.register(VirtualProviderService.self) { r in - let owmApi = r.resolve(OpenWeatherMapAPI.self)! - let locationManager = r.resolve(RuuviCoreLocation.self)! - let locationService = r.resolve(RuuviLocationService.self)! - let service = VirtualProviderServiceImpl( - owmApi: owmApi, - ruuviCoreLocation: locationManager, - ruuviLocationService: locationService - ) - return service - } - - container.register(VirtualService.self) { r in - let virtualPersistence = r.resolve(VirtualPersistence.self)! - let weatherProviderService = r.resolve(VirtualProviderService.self)! - let ruuviLocalImages = r.resolve(RuuviLocalImages.self)! - let service = VirtualServiceImpl( - ruuviLocalImages: ruuviLocalImages, - virtualPersistence: virtualPersistence, - virtualProviderService: weatherProviderService - ) - return service - } #if canImport(RuuviAnalytics) container.register(RuuviAnalytics.self) { r in let ruuviUser = r.resolve(RuuviUser.self)! let ruuviStorage = r.resolve(RuuviStorage.self)! - let virtualPersistence = r.resolve(VirtualPersistence.self)! let settings = r.resolve(RuuviLocalSettings.self)! let alertService = r.resolve(RuuviServiceAlert.self)! let service = RuuviAnalyticsImpl( ruuviUser: ruuviUser, ruuviStorage: ruuviStorage, - virtualPersistence: virtualPersistence, settings: settings, alertService: alertService ) @@ -871,12 +714,10 @@ private final class CoreAssembly: Assembly { container.register(RuuviNotificationLocal.self) { r in let settings = r.resolve(RuuviLocalSettings.self)! let ruuviStorage = r.resolve(RuuviStorage.self)! - let virtualTagTrunk = r.resolve(VirtualStorage.self)! let idPersistence = r.resolve(RuuviLocalIDs.self)! let ruuviAlertService = r.resolve(RuuviServiceAlert.self)! let manager = RuuviNotificationLocalImpl( ruuviStorage: ruuviStorage, - virtualTagTrunk: virtualTagTrunk, idPersistence: idPersistence, settings: settings, ruuviAlertService: ruuviAlertService @@ -919,10 +760,8 @@ private final class CoreAssembly: Assembly { private final class ModulesAssembly: Assembly { func assemble(container: Container) { container.register(RuuviDiscover.self) { r in - let virtualReactor = r.resolve(VirtualReactor.self)! let errorPresenter = r.resolve(ErrorPresenter.self)! let activityPresenter = r.resolve(ActivityPresenter.self)! - let virtualService = r.resolve(VirtualService.self)! let permissionsManager = r.resolve(RuuviCorePermission.self)! let permissionPresenter = r.resolve(PermissionPresenter.self)! let foreground = r.resolve(BTForeground.self)! @@ -931,10 +770,8 @@ private final class ModulesAssembly: Assembly { let factory = RuuviDiscoverFactory() let dependencies = RuuviDiscoverDependencies( - virtualReactor: virtualReactor, errorPresenter: errorPresenter, activityPresenter: activityPresenter, - virtualService: virtualService, permissionsManager: permissionsManager, permissionPresenter: permissionPresenter, foreground: foreground, @@ -943,25 +780,6 @@ private final class ModulesAssembly: Assembly { ) return factory.create(dependencies: dependencies) } - - container.register(RuuviLocationPicker.self) { r in - let locationService = r.resolve(RuuviLocationService.self)! - let activityPresenter = r.resolve(ActivityPresenter.self)! - let errorPresenter = r.resolve(ErrorPresenter.self)! - let permissionsManager = r.resolve(RuuviCorePermission.self)! - let permissionPresenter = r.resolve(PermissionPresenter.self)! - let locationManager = r.resolve(RuuviCoreLocation.self)! - let dependencies = RuuviLocationPickerDependencies( - locationService: locationService, - activityPresenter: activityPresenter, - errorPresenter: errorPresenter, - permissionsManager: permissionsManager, - permissionPresenter: permissionPresenter, - locationManager: locationManager - ) - let factory = RuuviLocationPickerFactory() - return factory.create(dependencies: dependencies) - } } } diff --git a/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift b/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift index e9537f0c3..e6ca74f8b 100644 --- a/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift +++ b/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift @@ -12,28 +12,22 @@ import WidgetKit class AppStateServiceImpl: AppStateService { var advertisementDaemon: RuuviTagAdvertisementDaemon! - var backgroundTaskService: BackgroundTaskService! var backgroundProcessService: BackgroundProcessService! var heartbeatDaemon: RuuviTagHeartbeatDaemon! var ruuviUser: RuuviUser! var propertiesDaemon: RuuviTagPropertiesDaemon! - var pullWebDaemon: PullWebDaemon! var cloudSyncDaemon: RuuviDaemonCloudSync! var settings: RuuviLocalSettings! #if canImport(RuuviAnalytics) var userPropertiesService: RuuviAnalytics! #endif var universalLinkCoordinator: UniversalLinkCoordinator! - var webTagDaemon: VirtualTagDaemon! func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) { if settings.isAdvertisementDaemonOn { advertisementDaemon.start() } - if settings.isWebTagDaemonOn { - webTagDaemon.start() - } if ruuviUser.isAuthorized { cloudSyncDaemon.start() @@ -45,8 +39,6 @@ class AppStateServiceImpl: AppStateService { } heartbeatDaemon.start() propertiesDaemon.start() - pullWebDaemon.start() - backgroundTaskService.register() backgroundProcessService.register() settings.appIsOnForeground = true observeWidgetKind() @@ -70,16 +62,11 @@ class AppStateServiceImpl: AppStateService { if settings.isAdvertisementDaemonOn { advertisementDaemon.stop() } - if settings.isWebTagDaemonOn { - webTagDaemon.stop() - } if ruuviUser.isAuthorized { cloudSyncDaemon.stop() WidgetCenter.shared.reloadTimelines(ofKind: AppAssemblyConstants.simpleWidgetKindId) } propertiesDaemon.stop() - pullWebDaemon.stop() - backgroundTaskService.schedule() backgroundProcessService.schedule() settings.appIsOnForeground = false } @@ -88,14 +75,10 @@ class AppStateServiceImpl: AppStateService { if settings.isAdvertisementDaemonOn { advertisementDaemon.start() } - if settings.isWebTagDaemonOn { - webTagDaemon.start() - } if ruuviUser.isAuthorized { cloudSyncDaemon.start() } propertiesDaemon.start() - pullWebDaemon.start() settings.appIsOnForeground = true } diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/Assembly/BackgroundSelectionModuleFactory.swift b/station/Classes/Presentation/Modules/Dashboard/Background/Assembly/BackgroundSelectionModuleFactory.swift index 046786cdf..879058d93 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/Assembly/BackgroundSelectionModuleFactory.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/Assembly/BackgroundSelectionModuleFactory.swift @@ -5,17 +5,15 @@ import RuuviPresenters import RuuviLocal protocol BackgroundSelectionModuleFactory { - func create(for ruuviTag: RuuviTagSensor?, - virtualTag: VirtualTagSensor?) -> BackgroundSelectionModuleInput + func create(for ruuviTag: RuuviTagSensor?) -> BackgroundSelectionModuleInput } final class BackgroundSelectionModuleFactoryImpl: BackgroundSelectionModuleFactory { - func create(for ruuviTag: RuuviTagSensor?, - virtualTag: VirtualTagSensor?) -> BackgroundSelectionModuleInput { + func create(for ruuviTag: RuuviTagSensor?) -> BackgroundSelectionModuleInput { let r = AppAssembly.shared.assembler.resolver let presenter = BackgroundSelectionPresenter( - ruuviTag: ruuviTag, virtualSensor: virtualTag + ruuviTag: ruuviTag ) presenter.photoPickerPresenter = r.resolve(PhotoPickerPresenter.self) presenter.ruuviSensorPropertiesService = r.resolve(RuuviServiceSensorProperties.self) diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift index 888abb86d..702ad1901 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift @@ -20,7 +20,6 @@ final class BackgroundSelectionPresenter: BackgroundSelectionModuleInput { } private weak var weakView: UIViewController? private let ruuviTag: RuuviTagSensor? - private let virtualSensor: VirtualTagSensor? private var viewModel: BackgroundSelectionViewModel! { didSet { prepareDefaultImages() @@ -41,10 +40,8 @@ final class BackgroundSelectionPresenter: BackgroundSelectionModuleInput { var ruuviLocalImages: RuuviLocalImages! var errorPresenter: ErrorPresenter! - init(ruuviTag: RuuviTagSensor?, - virtualSensor: VirtualTagSensor?) { + init(ruuviTag: RuuviTagSensor?) { self.ruuviTag = ruuviTag - self.virtualSensor = virtualSensor // swiftlint:disable:next inert_defer defer { self.viewModel = BackgroundSelectionViewModel() } @@ -68,8 +65,6 @@ extension BackgroundSelectionPresenter: BackgroundSelectionViewOutput { if let photo = model.image { if let ruuviTag = ruuviTag { performPhotoUpload(with: photo, ruuviTag: ruuviTag) - } else if let virtualSensor = virtualSensor { - performPhotoUpload(with: photo, virtualSensor: virtualSensor) } } } @@ -164,8 +159,6 @@ extension BackgroundSelectionPresenter: PhotoPickerPresenterDelegate { func photoPicker(presenter: PhotoPickerPresenter, didPick photo: UIImage) { if let ruuviTag = ruuviTag { performPhotoUpload(with: photo, ruuviTag: ruuviTag) - } else if let virtualSensor = virtualSensor { - performPhotoUpload(with: photo, virtualSensor: virtualSensor) } } @@ -182,16 +175,4 @@ extension BackgroundSelectionPresenter: PhotoPickerPresenterDelegate { self?.errorPresenter.present(error: error) }) } - - private func performPhotoUpload(with photo: UIImage, virtualSensor: VirtualTagSensor) { - ruuviSensorPropertiesService.set(image: photo, for: virtualSensor) - .on(success: { [weak self] _ in - self?.viewModel.background.value = photo - if let weakView = self?.weakView as? BackgroundSelectionViewController { - weakView.viewShouldDismiss() - } - }, failure: { [weak self] error in - self?.errorPresenter.present(error: error) - }) - } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Assembly/CardsViewModuleFactory.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Assembly/CardsViewModuleFactory.swift index e1c322abd..1773de5e5 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Assembly/CardsViewModuleFactory.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Assembly/CardsViewModuleFactory.swift @@ -5,7 +5,6 @@ import RuuviStorage import RuuviReactor import RuuviLocal import RuuviService -import RuuviVirtual import RuuviCore import RuuviNotifier import RuuviPresenters @@ -41,7 +40,6 @@ final class CardsViewModuleFactoryImpl: CardsViewModuleFactory { presenter.ruuviSensorPropertiesService = r.resolve(RuuviServiceSensorProperties.self) presenter.localSyncState = r.resolve(RuuviLocalSyncState.self) presenter.ruuviStorage = r.resolve(RuuviStorage.self) - presenter.virtualReactor = r.resolve(VirtualReactor.self) presenter.permissionPresenter = r.resolve(PermissionPresenter.self) presenter.permissionsManager = r.resolve(RuuviCorePermission.self) diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleInput.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleInput.swift index 604e2ce3b..95ec86d4f 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleInput.swift @@ -4,7 +4,6 @@ import RuuviOntology protocol CardsModuleInput: AnyObject { func configure(viewModels: [CardsViewModel], ruuviTagSensors: [AnyRuuviTagSensor], - virtualSensors: [AnyVirtualTagSensor], sensorSettings: [SensorSettings]) func configure(scrollTo: CardsViewModel?, openChart: Bool) diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift index 02f83e92c..368708bd7 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift @@ -7,7 +7,6 @@ import RuuviStorage import RuuviReactor import RuuviLocal import RuuviService -import RuuviVirtual import RuuviNotification import RuuviNotifier import RuuviPresenters @@ -31,16 +30,12 @@ class CardsPresenter { var ruuviSensorPropertiesService: RuuviServiceSensorProperties! var localSyncState: RuuviLocalSyncState! var ruuviStorage: RuuviStorage! - var virtualReactor: VirtualReactor! var permissionPresenter: PermissionPresenter! var permissionsManager: RuuviCorePermission! // MARK: - PRIVATE VARIABLES /// Collection of the sensor private var ruuviTags = [AnyRuuviTagSensor]() - /// Collection of virtual sensors - private var virtualSensors = [AnyVirtualTagSensor]() - /// Collection of virtual sensors private var sensorSettings = [SensorSettings]() /// Collection of the card view model. private var viewModels: [CardsViewModel] = [] { @@ -73,16 +68,13 @@ class CardsPresenter { // MARK: - OBSERVERS private var ruuviTagToken: RuuviReactorToken? - private var virtualSensorsToken: VirtualReactorToken? private var ruuviTagObserveLastRecordTokens = [RuuviReactorToken]() - private var virtualSensorsDataTokens = [VirtualReactorToken]() private var advertisementTokens = [ObservationToken]() private var heartbeatTokens = [ObservationToken]() private var sensorSettingsTokens = [RuuviReactorToken]() private var stateToken: ObservationToken? private var backgroundToken: NSObjectProtocol? private var alertDidChangeToken: NSObjectProtocol? - private var webTagDaemonFailureToken: NSObjectProtocol? private var ruuviTagAdvertisementDaemonFailureToken: NSObjectProtocol? private var ruuviTagPropertiesDaemonFailureToken: NSObjectProtocol? private var ruuviTagHeartbeatDaemonFailureToken: NSObjectProtocol? @@ -107,14 +99,13 @@ class CardsPresenter { // MARK: - CardsModuleInput extension CardsPresenter: CardsModuleInput { - func configure(viewModels: [CardsViewModel], - ruuviTagSensors: [AnyRuuviTagSensor], - virtualSensors: [AnyVirtualTagSensor], - sensorSettings: [SensorSettings] + func configure( + viewModels: [CardsViewModel], + ruuviTagSensors: [AnyRuuviTagSensor], + sensorSettings: [SensorSettings] ) { self.viewModels = viewModels self.ruuviTags = ruuviTagSensors - self.virtualSensors = virtualSensors self.sensorSettings = sensorSettings } @@ -133,13 +124,10 @@ extension CardsPresenter: CardsModuleInput { extension CardsPresenter { private func startObservingVisibleTag() { startObservingRuuviTags() - startObservingWebTags() observeSensorSettings() observeRuuviTagBTMesurements() startListeningLatestRecords() - startObservingVirtualSensorData() startListeningToRuuviTagsAlertStatus() - startListeningToWebTagsAlertStatus() startObservingAlertChanges() startObservingBackgroundChanges() startObservingDaemonsErrors() @@ -179,58 +167,6 @@ extension CardsPresenter { startObservingVisibleTag() } - // swiftlint:disable:next cyclomatic_complexity - private func startObservingWebTags() { - virtualSensorsToken?.invalidate() - virtualSensorsToken = virtualReactor.observe { [weak self] change in - guard let sSelf = self else { return } - switch change { - case .delete(let sensor): - sSelf.virtualSensors.removeAll(where: { $0.id == sensor.id }) - sSelf.syncViewModels() - - // If a sensor is deleted, and there's no more sensor take - // user to dashboard. - guard sSelf.viewModels.count > 0 else { - sSelf.viewShouldDismiss() - return - } - - if let first = sSelf.viewModels.first { - sSelf.updateVisibleCard(from: first, triggerScroll: true) - sSelf.view?.scroll(to: sSelf.visibleViewModelIndex) - } - case .update(let sensor): - if let index = sSelf.virtualSensors - .firstIndex( - where: { - $0.id == sensor.id - }) { - sSelf.virtualSensors[index] = sensor - sSelf.syncViewModels() - if let viewModel = sSelf.viewModels.first(where: { - $0.id.value == sensor.id - }) { - sSelf.notifyUpdate(for: viewModel) - } - } - case .insert(let sensor): - sSelf.virtualSensors.append(sensor) - sSelf.syncViewModels() - if let viewModel = sSelf.viewModels.first(where: { - $0.id.value == sensor.id - }) { - sSelf.updateVisibleCard(from: viewModel, - triggerScroll: true) - sSelf.view?.scroll(to: sSelf.visibleViewModelIndex) - } - case .error(let error): - sSelf.errorPresenter.present(error: error) - default: break - } - } - } - // swiftlint:disable:next cyclomatic_complexity function_body_length private func startObservingRuuviTags() { ruuviTagToken?.invalidate() @@ -327,26 +263,6 @@ extension CardsPresenter { } } - private func startObservingVirtualSensorData() { - virtualSensorsDataTokens.forEach({ $0.invalidate() }) - virtualSensorsDataTokens.removeAll() - virtualSensors.forEach { virtualSensor in - virtualSensorsDataTokens - .append(virtualReactor.observeLast(virtualSensor, { [weak self] changes in - if case .update(let anyRecord) = changes, - let viewModel = self?.viewModels - .first(where: { $0.id.value == anyRecord?.sensorId }), - let record = anyRecord { - let previousDate = viewModel.date.value ?? Date.distantPast - if previousDate <= record.date { - viewModel.update(record) - self?.notifyUpdate(for: viewModel) - } - } - })) - } - } - private func startListeningToRuuviTagsAlertStatus() { ruuviTags.forEach({ (ruuviTag) in if ruuviTag.isCloud { @@ -363,10 +279,6 @@ extension CardsPresenter { }) } - private func startListeningToWebTagsAlertStatus() { - virtualSensors.forEach({ alertHandler.subscribe(self, to: $0.id) }) - } - // swiftlint:disable:next function_body_length private func startObservingAlertChanges() { alertDidChangeToken?.invalidate() @@ -399,26 +311,6 @@ extension CardsPresenter { self?.notifyUpdate(for: viewModel) }) } - if let virtualSensor - = userInfo[RuuviServiceAlertDidChangeKey.virtualSensor] as? VirtualSensor, - let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType { - sSelf.viewModels.filter({ - ($0.id.value != nil && ($0.id.value == virtualSensor.id)) - }).forEach({ (viewModel) in - if sSelf.alertService.hasRegistrations(for: virtualSensor) { - viewModel.alertState.value = .registered - } else { - viewModel.alertState.value = .empty - } - self?.updateIsOnState(of: type, - for: virtualSensor.id, - viewModel: viewModel) - self?.updateMutedTill(of: type, - for: virtualSensor.id, - viewModel: viewModel) - self?.notifyUpdate(for: viewModel) - }) - } } }) } @@ -596,7 +488,6 @@ extension CardsPresenter { .first(where: { $0.luid != nil && $0.luid?.any == luid?.any }) ?? sSelf.ruuviTags .first(where: { $0.macId != nil && $0.macId?.any == macId?.any }) - let webTag = sSelf.virtualSensors.first(where: { $0.id == luid?.value }) if let ruuviTag = ruuviTag { sSelf.ruuviSensorPropertiesService.getImage(for: ruuviTag) .on(success: { image in @@ -606,15 +497,6 @@ extension CardsPresenter { self?.errorPresenter.present(error: error) }) } - if let webTag = webTag { - sSelf.ruuviSensorPropertiesService.getImage(for: webTag) - .on(success: { image in - viewModel.background.value = image - self?.view?.changeCardBackground(of: viewModel, to: image) - }, failure: { [weak sSelf] error in - sSelf?.errorPresenter.present(error: error) - }) - } } } } @@ -622,38 +504,6 @@ extension CardsPresenter { // swiftlint:disable:next cyclomatic_complexity function_body_length func startObservingDaemonsErrors() { - webTagDaemonFailureToken?.invalidate() - webTagDaemonFailureToken = NotificationCenter - .default - .addObserver(forName: .WebTagDaemonDidFail, - object: nil, - queue: .main) { [weak self] notification in - if let userInfo = notification.userInfo, - let error = userInfo[WebTagDaemonDidFailKey.error] as? RUError { - if case .core(let coreError) = error, coreError == .locationPermissionDenied { - self?.permissionPresenter.presentNoLocationPermission() - } else if case .core(let coreError) = error, coreError == .locationPermissionNotDetermined { - self?.permissionsManager.requestLocationPermission { [weak self] (granted) in - if !granted { - self?.permissionPresenter.presentNoLocationPermission() - } - } - } else if case .virtualService(let serviceError) = error, - case .openWeatherMap(let owmError) = serviceError, - owmError == OWMError.apiLimitExceeded { - self?.view?.showWebTagAPILimitExceededError() - } else if case .map(let mapError) = error { - let nsError = mapError as NSError - if nsError.code == 2, nsError.domain == "kCLErrorDomain" { - self?.view?.showReverseGeocodingFailed() - } else { - self?.errorPresenter.present(error: error) - } - } else { - self?.errorPresenter.present(error: error) - } - } - } ruuviTagAdvertisementDaemonFailureToken?.invalidate() ruuviTagAdvertisementDaemonFailureToken = NotificationCenter .default @@ -796,23 +646,8 @@ extension CardsPresenter { return viewModel }) - let virtualViewModels = virtualSensors.compactMap({ virtualSensor -> CardsViewModel in - let viewModel = CardsViewModel(virtualSensor) - ruuviSensorPropertiesService.getImage(for: virtualSensor) - .on(success: { [weak self] image in - viewModel.background.value = image - self?.view?.changeCardBackground(of: viewModel, to: image) - }, failure: { [weak self] error in - self?.errorPresenter.present(error: error) - }) - viewModel.alertState.value = alertService - .hasRegistrations(for: virtualSensor) ? .registered : .empty - viewModel.isConnected.value = false - notifyUpdate(for: viewModel) - return viewModel - }) - viewModels = reorder(ruuviViewModels + virtualViewModels) + viewModels = reorder(ruuviViewModels) guard viewModels.count > 0 else { output?.cardsViewDidDismiss(module: self) @@ -886,16 +721,13 @@ extension CardsPresenter { private func shutdownModule() { ruuviTagToken?.invalidate() - virtualSensorsToken?.invalidate() ruuviTagObserveLastRecordTokens.forEach({ $0.invalidate() }) - virtualSensorsDataTokens.forEach({ $0.invalidate() }) advertisementTokens.forEach({ $0.invalidate() }) heartbeatTokens.forEach({ $0.invalidate() }) sensorSettingsTokens.forEach({ $0.invalidate() }) stateToken?.invalidate() backgroundToken?.invalidate() alertDidChangeToken?.invalidate() - webTagDaemonFailureToken?.invalidate() ruuviTagAdvertisementDaemonFailureToken?.invalidate() ruuviTagPropertiesDaemonFailureToken?.invalidate() ruuviTagHeartbeatDaemonFailureToken?.invalidate() @@ -955,12 +787,6 @@ extension CardsPresenter: CardsViewOutput { } else { openTagSettingsScreens(viewModel: viewModel) } - } else if viewModel.type == .web, - let webTag = virtualSensors.first(where: { $0.id == viewModel.id.value }) { - router.openVirtualSensorSettings( - sensor: webTag, - temperature: viewModel.temperature.value - ) } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift index d328f7747..1f383728b 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift @@ -3,7 +3,6 @@ import Foundation import UIKit import RuuviOntology import RuuviLocal -import RuuviVirtual class CardsRouter: NSObject, CardsRouterInput { weak var transitionHandler: UIViewController? @@ -35,19 +34,6 @@ class CardsRouter: NSObject, CardsRouterInput { } } - func openVirtualSensorSettings( - sensor: VirtualTagSensor, - temperature: Temperature? - ) { - let factory = StoryboardFactory(storyboardName: "WebTagSettings") - try? transitionHandler? - .forStoryboard(factory: factory, to: WebTagSettingsModuleInput.self) - .to(preferred: .navigation(style: .push)) - .then({ (module) -> Any? in - module.configure(sensor: sensor, temperature: temperature) - }) - } - func openUpdateFirmware(ruuviTag: RuuviTagSensor) { let factory: DFUModuleFactory = DFUModuleFactoryImpl() let module = factory.create(for: ruuviTag) diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouterInput.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouterInput.swift index dbc42d937..b1db28171 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouterInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouterInput.swift @@ -1,6 +1,5 @@ import Foundation import RuuviOntology -import RuuviVirtual protocol CardsRouterInput { func openUpdateFirmware(ruuviTag: RuuviTagSensor) @@ -10,9 +9,5 @@ protocol CardsRouterInput { sensorSettings: SensorSettings?, output: TagSettingsModuleOutput ) - func openVirtualSensorSettings( - sensor: VirtualTagSensor, - temperature: Temperature? - ) func dismiss() } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift index 1e3660fd4..2e434a2a9 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift @@ -10,7 +10,6 @@ protocol CardsViewInput: ViewInput { func changeCardBackground(of viewModel: CardsViewModel, to image: UIImage?) func scroll(to index: Int) func showBluetoothDisabled(userDeclined: Bool) - func showWebTagAPILimitExceededError() func showKeepConnectionDialogChart(for viewModel: CardsViewModel) func showKeepConnectionDialogSettings(for viewModel: CardsViewModel) func showFirmwareUpdateDialog(for viewModel: CardsViewModel) diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift index be26f79c6..d3d02a34c 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift @@ -3,11 +3,9 @@ import BTKit import Humidity import RuuviOntology import RuuviLocal -import RuuviVirtual enum CardType { case ruuvi - case web } struct CardsViewModel { @@ -31,7 +29,6 @@ struct CardsViewModel { var currentLocation: Observable = Observable() var animateRSSI: Observable = Observable() var isConnectable: Observable = Observable() - var provider: VirtualProvider? var isConnected: Observable = Observable() var isCloud: Observable = Observable() var isOwner: Observable = Observable() @@ -77,46 +74,6 @@ struct CardsViewModel { private let batteryStatusProvider = RuuviTagBatteryStatusProvider() - init(_ virtualSensor: VirtualTagSensor) { - type = .web - id.value = virtualSensor.id - luid.value = virtualSensor.id.luid.any - name.value = virtualSensor.name - // TODO: @rinat fetch one -// temperature.value = virtualSensor.lastRecord?.temperature -// humidity.value = virtualSensor.lastRecord?.humidity -// pressure.value = virtualSensor.lastRecord?.pressure - isConnectable.value = false - isConnected.value = false - isCloud.value = false - isOwner.value = true -// date.value = virtualSensor.data.last?.date -// location.value = virtualSensor.location?.location - provider = virtualSensor.provider - source.value = .weatherProvider - } - - func update(_ record: VirtualTagSensorRecord) { - temperature.value = record.temperature - humidity.value = record.humidity - pressure.value = record.pressure - isConnectable.value = false - isConnected.value = false - isCloud.value = false - isOwner.value = true - currentLocation.value = record.location - date.value = record.date - } - - func update(_ wpsData: VirtualData, current: Location?) { - isConnectable.value = false - temperature.value = wpsData.temperature - humidity.value = wpsData.humidity - pressure.value = wpsData.pressure - currentLocation.value = current - date.value = Date() - } - init(_ ruuviTag: RuuviTagSensor) { type = .ruuvi id.value = ruuviTag.id diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift index cc22e0c3c..4a66a21d0 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift @@ -276,16 +276,6 @@ extension CardsLargeImageCell { } else { hideMovementView(hide: true) } - case .web: - let location = viewModel.location - if let location = location.value { - movementView.setValue(with: location.city ?? location.country) - } else if let currentLocation = viewModel.currentLocation.value { - movementView.setValue(with: currentLocation.description) - } else { - movementView.setValue(with: "N/A".localized()) - } - movementView.setIcon(with: RuuviAssets.locationImage) } // Ago diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift index 19781df5b..151b9435c 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift @@ -541,14 +541,6 @@ extension CardsViewController: CardsViewInput { // No op. } - func showWebTagAPILimitExceededError() { - let title = "Cards.WebTagAPILimitExcededError.Alert.title".localized() - let message = "Cards.WebTagAPILimitExcededError.Alert.message".localized() - let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) - present(alertVC, animated: true) - } - func showBluetoothDisabled(userDeclined: Bool) { let title = "Cards.BluetoothDisabledAlert.title".localized() let message = "Cards.BluetoothDisabledAlert.message".localized() @@ -804,10 +796,6 @@ extension CardsViewController { alertButton.isHidden = !viewModel.isConnected.value.bound alertButtonHidden.isUserInteractionEnabled = viewModel.isConnected.value.bound } - case .web: - // Hide alert bell for virtual tags - alertButton.isHidden = true - alertButtonHidden.isUserInteractionEnabled = false } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift index 239e9287c..b6f9cd155 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift @@ -9,7 +9,6 @@ import RuuviStorage import RuuviReactor import RuuviLocal import RuuviService -import RuuviVirtual import RuuviNotification import RuuviNotifier import RuuviPresenters diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift index 97130403f..9232c84f0 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift @@ -5,7 +5,6 @@ import RuuviOntology enum TagChartsType { case ruuvi - case virtual } struct TagChartsViewModel { @@ -24,14 +23,6 @@ struct TagChartsViewModel { self.type = type } - init(_ virtualSensor: VirtualTagSensor) { - type = .virtual - uuid.value = virtualSensor.id - name.value = virtualSensor.name - isConnectable.value = false - isCloud.value = false - } - init(_ ruuviTag: RuuviTagSensor) { type = .ruuvi uuid.value = ruuviTag.luid?.value diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift index e0bda19d4..b91170ece 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift @@ -5,7 +5,6 @@ import RuuviStorage import RuuviReactor import RuuviLocal import RuuviService -import RuuviVirtual import RuuviCore import RuuviNotifier import RuuviPresenters @@ -36,7 +35,6 @@ final class DashboardModuleFactoryImpl: DashboardModuleFactory { presenter.settings = r.resolve(RuuviLocalSettings.self) presenter.foreground = r.resolve(BTForeground.self) presenter.background = r.resolve(BTBackground.self) - presenter.webTagService = r.resolve(VirtualService.self) presenter.permissionPresenter = r.resolve(PermissionPresenter.self) presenter.pushNotificationsManager = r.resolve(RuuviCorePN.self) presenter.permissionsManager = r.resolve(RuuviCorePermission.self) @@ -49,7 +47,6 @@ final class DashboardModuleFactoryImpl: DashboardModuleFactory { presenter.infoProvider = r.resolve(InfoProvider.self) presenter.ruuviReactor = r.resolve(RuuviReactor.self) presenter.ruuviStorage = r.resolve(RuuviStorage.self) - presenter.virtualReactor = r.resolve(VirtualReactor.self) presenter.measurementService = r.resolve(RuuviServiceMeasurement.self) presenter.localSyncState = r.resolve(RuuviLocalSyncState.self) presenter.ruuviSensorPropertiesService = r.resolve(RuuviServiceSensorProperties.self) diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift index 8af7da595..57d041a42 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift @@ -8,7 +8,6 @@ import RuuviStorage import RuuviReactor import RuuviLocal import RuuviService -import RuuviVirtual import RuuviCore import RuuviNotification import RuuviNotifier @@ -29,7 +28,6 @@ class DashboardPresenter: DashboardModuleInput { var settings: RuuviLocalSettings! var foreground: BTForeground! var background: BTBackground! - var webTagService: VirtualService! var permissionPresenter: PermissionPresenter! var pushNotificationsManager: RuuviCorePN! var permissionsManager: RuuviCorePermission! @@ -42,7 +40,6 @@ class DashboardPresenter: DashboardModuleInput { var infoProvider: InfoProvider! var ruuviReactor: RuuviReactor! var ruuviStorage: RuuviStorage! - var virtualReactor: VirtualReactor! var measurementService: RuuviServiceMeasurement! var localSyncState: RuuviLocalSyncState! var ruuviSensorPropertiesService: RuuviServiceSensorProperties! @@ -56,13 +53,10 @@ class DashboardPresenter: DashboardModuleInput { var cloudNotificationService: RuuviServiceCloudNotification! private var ruuviTagToken: RuuviReactorToken? private var ruuviTagObserveLastRecordTokens = [RuuviReactorToken]() - private var virtualSensorsToken: VirtualReactorToken? - private var virtualSensorsDataTokens = [VirtualReactorToken]() private var advertisementTokens = [ObservationToken]() private var heartbeatTokens = [ObservationToken]() private var sensorSettingsTokens = [RuuviReactorToken]() private var backgroundToken: NSObjectProtocol? - private var webTagDaemonFailureToken: NSObjectProtocol? private var ruuviTagAdvertisementDaemonFailureToken: NSObjectProtocol? private var ruuviTagPropertiesDaemonFailureToken: NSObjectProtocol? private var ruuviTagHeartbeatDaemonFailureToken: NSObjectProtocol? @@ -90,11 +84,6 @@ class DashboardPresenter: DashboardModuleInput { private var dashboardTapActionTypeToken: NSObjectProtocol? private var cloudSyncSuccessStateToken: NSObjectProtocol? private var cloudSyncFailStateToken: NSObjectProtocol? - private var virtualSensors = [AnyVirtualTagSensor]() { - didSet { - startListeningToWebTagsAlertStatus() - } - } private var ruuviTags = [AnyRuuviTagSensor]() private var sensorSettingsList = [SensorSettings]() private var viewModels: [CardsViewModel] = [] { @@ -103,7 +92,6 @@ class DashboardPresenter: DashboardModuleInput { } } private var didLoadInitialRuuviTags = false - private var didLoadInitialWebTags = false private let appGroupDefaults = UserDefaults( suiteName: AppGroupConstants.appGroupSuiteIdentifier ) @@ -113,15 +101,12 @@ class DashboardPresenter: DashboardModuleInput { deinit { ruuviTagToken?.invalidate() - virtualSensorsToken?.invalidate() ruuviTagObserveLastRecordTokens.forEach({ $0.invalidate() }) advertisementTokens.forEach({ $0.invalidate() }) heartbeatTokens.forEach({ $0.invalidate() }) - virtualSensorsDataTokens.forEach({ $0.invalidate() }) sensorSettingsTokens.forEach({ $0.invalidate() }) stateToken?.invalidate() backgroundToken?.invalidate() - webTagDaemonFailureToken?.invalidate() ruuviTagAdvertisementDaemonFailureToken?.invalidate() ruuviTagHeartbeatDaemonFailureToken?.invalidate() ruuviTagReadLogsOperationFailureToken?.invalidate() @@ -160,7 +145,6 @@ class DashboardPresenter: DashboardModuleInput { extension DashboardPresenter: DashboardViewOutput { func viewDidLoad() { startObservingRuuviTags() - startObservingWebTags() startObservingBackgroundChanges() startObservingDaemonsErrors() startObservingConnectionPersistenceNotifications() @@ -215,12 +199,6 @@ extension DashboardPresenter: DashboardViewOutput { } else { openTagSettingsScreens(viewModel: viewModel) } - } else if viewModel.type == .web, - let webTag = virtualSensors.first(where: { $0.id == viewModel.id.value }) { - router.openVirtualSensorSettings( - sensor: webTag, - temperature: viewModel.temperature.value - ) } } @@ -263,9 +241,6 @@ extension DashboardPresenter: DashboardViewOutput { if let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) { router.openBackgroundSelectionView(ruuviTag: ruuviTagSensor) } - } else if viewModel.type == .web, - let webTag = virtualSensors.first(where: { $0.id == viewModel.id.value }) { - router.openBackgroundSelectionView(virtualSensor: webTag) } } @@ -445,7 +420,6 @@ extension DashboardPresenter: DiscoverRouterDelegate { }) { self.router.openCardImageView(with: viewModels, ruuviTagSensors: ruuviTags, - virtualSensors: virtualSensors, sensorSettings: sensorSettingsList, scrollTo: viewModel, showCharts: false, @@ -600,25 +574,9 @@ extension DashboardPresenter { return viewModel }) - let virtualViewModels = virtualSensors.compactMap({ virtualSensor -> CardsViewModel in - let viewModel = CardsViewModel(virtualSensor) - ruuviSensorPropertiesService.getImage(for: virtualSensor) - .on(success: { [weak self] image in - viewModel.background.value = image - self?.notifyViewModelUpdate(for: viewModel) - }, failure: { [weak self] error in - self?.errorPresenter.present(error: error) - }) - viewModel.alertState.value = alertService - .hasRegistrations(for: virtualSensor) ? .registered : .empty - viewModel.isConnected.value = false - notifyViewModelUpdate(for: viewModel) - return viewModel - }) - let vms = reorder(ruuviViewModels + virtualViewModels) - if didLoadInitialRuuviTags - && didLoadInitialWebTags { + let vms = reorder(ruuviViewModels) + if didLoadInitialRuuviTags{ view?.showNoSensorsAddedMessage(show: vms.isEmpty) askAppStoreReview(with: vms.count) } @@ -626,8 +584,7 @@ extension DashboardPresenter { self.viewModels = vms } - private func syncViewModel(ruuviTagSensor: RuuviTagSensor?, - virtualSensor: VirtualTagSensor?) { + private func syncViewModel(ruuviTagSensor: RuuviTagSensor?) { if let ruuviTag = ruuviTagSensor { let viewModel = CardsViewModel(ruuviTag) ruuviSensorPropertiesService.getImage(for: ruuviTag) @@ -662,22 +619,6 @@ extension DashboardPresenter { viewModels.append(viewModel) viewModels = reorder(viewModels) } - - if let virtualSensor = virtualSensor { - let viewModel = CardsViewModel(virtualSensor) - ruuviSensorPropertiesService.getImage(for: virtualSensor) - .on(success: { [weak self] image in - viewModel.background.value = image - self?.notifyViewModelUpdate(for: viewModel) - }, failure: { [weak self] error in - self?.errorPresenter.present(error: error) - }) - viewModel.alertState.value = alertService.hasRegistrations(for: virtualSensor) ? .registered : .empty - viewModel.isConnected.value = false - - viewModels.append(viewModel) - viewModels = reorder(viewModels) - } } private func processAlert(record: RuuviTagSensorRecord, @@ -974,68 +915,6 @@ extension DashboardPresenter { } } - private func restartObservingVirtualSensorsData() { - virtualSensorsDataTokens.forEach({ $0.invalidate() }) - virtualSensorsDataTokens.removeAll() - virtualSensors.forEach { virtualSensor in - virtualSensorsDataTokens - .append(virtualReactor.observeLast(virtualSensor, { [weak self] changes in - if case .update(let anyRecord) = changes, - let viewModel = self?.viewModels - .first(where: { $0.id.value == anyRecord?.sensorId }), - let record = anyRecord { - let previousDate = viewModel.date.value ?? Date.distantPast - if previousDate <= record.date { - viewModel.update(record) - self?.notifyViewModelUpdate(for: viewModel) - } - } - })) - } - } - - private func startObservingWebTags() { - virtualSensorsToken?.invalidate() - virtualSensorsToken = virtualReactor.observe { [weak self] change in - guard let sSelf = self else { return } - switch change { - case .initial(let sensors): - sSelf.didLoadInitialWebTags = true - sSelf.virtualSensors = sensors - sSelf.restartObservingVirtualSensorsData() - case .delete(let sensor): - sSelf.virtualSensors.removeAll(where: { $0.id == sensor.id }) - sSelf.syncViewModels() - sSelf.restartObservingVirtualSensorsData() - case .update(let sensor): - if let index = sSelf.virtualSensors - .firstIndex( - where: { - $0.id == sensor.id - }) { - sSelf.virtualSensors[index] = sensor - sSelf.syncViewModels() - sSelf.restartObservingVirtualSensorsData() - } - case .insert(let sensor): - sSelf.virtualSensors.append(sensor) - sSelf.syncViewModel(ruuviTagSensor: nil, - virtualSensor: sensor) - if let viewModel = sSelf.viewModels.first(where: { - $0.id.value == sensor.id - }) { - sSelf.router.openVirtualSensorSettings( - sensor: sensor, - temperature: viewModel.temperature.value - ) - } - sSelf.restartObservingVirtualSensorsData() - case .error(let error): - sSelf.errorPresenter.present(error: error) - } - } - } - // swiftlint:disable:next function_body_length cyclomatic_complexity private func startObservingRuuviTags() { ruuviTagToken?.invalidate() @@ -1049,7 +928,6 @@ extension DashboardPresenter { sSelf.syncViewModels() sSelf.startListeningToRuuviTagsAlertStatus() sSelf.observeRuuviTags() - sSelf.startObservingWebTags() sSelf.restartObservingRuuviTagLastRecords() sSelf.syncHasCloudSensorToAppGroupContainer(with: ruuviTags) case .insert(let sensor): @@ -1062,13 +940,11 @@ extension DashboardPresenter { // Avoid triggering the method when big changes is happening // such as login. if !sSelf.settings.isSyncing { - sSelf.syncViewModel(ruuviTagSensor: sensor, - virtualSensor: nil) + sSelf.syncViewModel(ruuviTagSensor: sensor) } sSelf.startListeningToRuuviTagsAlertStatus() sSelf.observeRuuviTags() - sSelf.startObservingWebTags() if !sSelf.settings.isSyncing, let viewModel = sSelf.viewModels.first(where: { return ($0.luid.value != nil && $0.luid.value == sensor.luid?.any) @@ -1095,7 +971,6 @@ extension DashboardPresenter { sSelf.syncViewModels() sSelf.startListeningToRuuviTagsAlertStatus() sSelf.observeRuuviTags() - sSelf.startObservingWebTags() sSelf.restartObservingRuuviTagLastRecords() sSelf.syncHasCloudSensorToAppGroupContainer(with: sSelf.ruuviTags) case .error(let error): @@ -1112,7 +987,6 @@ extension DashboardPresenter { sSelf.syncViewModels() sSelf.restartObserveRuuviTagAdvertisements() } - sSelf.startObservingWebTags() sSelf.syncHasCloudSensorToAppGroupContainer(with: sSelf.ruuviTags) } } @@ -1138,7 +1012,6 @@ extension DashboardPresenter { .first(where: { $0.luid != nil && $0.luid?.any == luid?.any }) ?? sSelf.ruuviTags .first(where: { $0.macId != nil && $0.macId?.any == macId?.any }) - let webTag = sSelf.virtualSensors.first(where: { $0.id == luid?.value }) if let ruuviTag = ruuviTag { sSelf.ruuviSensorPropertiesService.getImage(for: ruuviTag) .on(success: { image in @@ -1148,15 +1021,6 @@ extension DashboardPresenter { self?.errorPresenter.present(error: error) }) } - if let webTag = webTag { - sSelf.ruuviSensorPropertiesService.getImage(for: webTag) - .on(success: { image in - viewModel.background.value = image - self?.notifyViewModelUpdate(for: viewModel) - }, failure: { [weak sSelf] error in - sSelf?.errorPresenter.present(error: error) - }) - } } } } @@ -1164,38 +1028,6 @@ extension DashboardPresenter { // swiftlint:disable:next cyclomatic_complexity function_body_length func startObservingDaemonsErrors() { - webTagDaemonFailureToken?.invalidate() - webTagDaemonFailureToken = NotificationCenter - .default - .addObserver(forName: .WebTagDaemonDidFail, - object: nil, - queue: .main) { [weak self] notification in - if let userInfo = notification.userInfo, - let error = userInfo[WebTagDaemonDidFailKey.error] as? RUError { - if case .core(let coreError) = error, coreError == .locationPermissionDenied { - self?.permissionPresenter.presentNoLocationPermission() - } else if case .core(let coreError) = error, coreError == .locationPermissionNotDetermined { - self?.permissionsManager.requestLocationPermission { [weak self] (granted) in - if !granted { - self?.permissionPresenter.presentNoLocationPermission() - } - } - } else if case .virtualService(let serviceError) = error, - case .openWeatherMap(let owmError) = serviceError, - owmError == OWMError.apiLimitExceeded { - self?.view?.showWebTagAPILimitExceededError() - } else if case .map(let mapError) = error { - let nsError = mapError as NSError - if nsError.code == 2, nsError.domain == "kCLErrorDomain" { - self?.view?.showReverseGeocodingFailed() - } else { - self?.errorPresenter.present(error: error) - } - } else { - self?.errorPresenter.present(error: error) - } - } - } ruuviTagAdvertisementDaemonFailureToken?.invalidate() ruuviTagAdvertisementDaemonFailureToken = NotificationCenter .default @@ -1345,27 +1177,6 @@ extension DashboardPresenter { sSelf.triggerAlertsIfNeeded() }) } - if let virtualSensor - = userInfo[RuuviServiceAlertDidChangeKey.virtualSensor] as? VirtualSensor, - let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType { - sSelf.viewModels.filter({ - ($0.id.value != nil && ($0.id.value == virtualSensor.id)) - }).forEach({ (viewModel) in - if sSelf.alertService.hasRegistrations(for: virtualSensor) { - viewModel.alertState.value = .registered - sSelf.notifyViewModelUpdate(for: viewModel) - } else { - viewModel.alertState.value = .empty - sSelf.notifyViewModelUpdate(for: viewModel) - } - sSelf.updateIsOnState(of: type, - for: virtualSensor.id, - viewModel: viewModel) - sSelf.updateMutedTill(of: type, - for: virtualSensor.id, - viewModel: viewModel) - }) - } } }) } @@ -1386,10 +1197,6 @@ extension DashboardPresenter { }) } - private func startListeningToWebTagsAlertStatus() { - virtualSensors.forEach({ alertHandler.subscribe(self, to: $0.id) }) - } - private func openTagSettingsScreens(viewModel: CardsViewModel) { if let ruuviTag = ruuviTags.first(where: { $0.id == viewModel.id.value }) { self.router.openTagSettings( @@ -1409,7 +1216,6 @@ extension DashboardPresenter { self.router.openTagSettings( with: viewModels, ruuviTagSensors: ruuviTags, - virtualSensors: virtualSensors, sensorSettings: sensorSettingsList, scrollTo: viewModel, ruuviTag: ruuviTag, @@ -1427,7 +1233,6 @@ extension DashboardPresenter { private func openCardView(viewModel: CardsViewModel, showCharts: Bool) { router.openCardImageView(with: viewModels, ruuviTagSensors: ruuviTags, - virtualSensors: virtualSensors, sensorSettings: sensorSettingsList, scrollTo: viewModel, showCharts: showCharts, diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift index 52e8cee21..1eb974e2a 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift @@ -3,7 +3,6 @@ import Foundation import UIKit import RuuviOntology import RuuviLocal -import RuuviVirtual class DashboardRouter: NSObject, DashboardRouterInput { weak var transitionHandler: UIViewController! @@ -111,24 +110,9 @@ class DashboardRouter: NSObject, DashboardRouterInput { sensorSettings: sensorSettings) } } - - func openVirtualSensorSettings( - sensor: VirtualTagSensor, - temperature: Temperature? - ) { - let factory = StoryboardFactory(storyboardName: "WebTagSettings") - try! transitionHandler - .forStoryboard(factory: factory, to: WebTagSettingsModuleInput.self) - .to(preferred: .navigation(style: .push)) - .then({ (module) -> Any? in - module.configure(sensor: sensor, temperature: temperature) - }) - } - // swiftlint:disable:next function_parameter_count func openCardImageView(with viewModels: [CardsViewModel], ruuviTagSensors: [AnyRuuviTagSensor], - virtualSensors: [AnyVirtualTagSensor], sensorSettings: [SensorSettings], scrollTo: CardsViewModel?, showCharts: Bool, @@ -158,7 +142,6 @@ class DashboardRouter: NSObject, DashboardRouterInput { cards.configure(output: output) cards.configure(viewModels: viewModels, ruuviTagSensors: ruuviTagSensors, - virtualSensors: virtualSensors, sensorSettings: sensorSettings) cards.configure(scrollTo: scrollTo, openChart: showCharts) @@ -168,7 +151,6 @@ class DashboardRouter: NSObject, DashboardRouterInput { // swiftlint:disable:next function_parameter_count func openTagSettings(with viewModels: [CardsViewModel], ruuviTagSensors: [AnyRuuviTagSensor], - virtualSensors: [AnyVirtualTagSensor], sensorSettings: [SensorSettings], scrollTo: CardsViewModel?, ruuviTag: RuuviTagSensor, @@ -187,7 +169,6 @@ class DashboardRouter: NSObject, DashboardRouterInput { cardsPresenter.configure(output: output) cardsPresenter.configure(viewModels: viewModels, ruuviTagSensors: ruuviTagSensors, - virtualSensors: virtualSensors, sensorSettings: sensorSettings) cardsPresenter.configure(scrollTo: scrollTo, openChart: false) @@ -231,7 +212,7 @@ class DashboardRouter: NSObject, DashboardRouterInput { func openBackgroundSelectionView(ruuviTag: RuuviTagSensor) { let factory: BackgroundSelectionModuleFactory = BackgroundSelectionModuleFactoryImpl() - let module = factory.create(for: ruuviTag, virtualTag: nil) + let module = factory.create(for: ruuviTag) self.backgroundSelectionModule = module transitionHandler .navigationController? @@ -242,18 +223,6 @@ class DashboardRouter: NSObject, DashboardRouterInput { } - func openBackgroundSelectionView(virtualSensor: VirtualTagSensor) { - let factory: BackgroundSelectionModuleFactory = BackgroundSelectionModuleFactoryImpl() - let module = factory.create(for: nil, virtualTag: virtualSensor) - self.backgroundSelectionModule = module - transitionHandler - .navigationController? - .pushViewController( - module.viewController, - animated: true - ) - } - func openShare(for sensor: RuuviTagSensor) { let restorationId = "ShareViewController" let factory = StoryboardFactory(storyboardName: "Share", bundle: .main, restorationId: restorationId) diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouterInput.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouterInput.swift index 61c22ad5c..cc11093d6 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouterInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouterInput.swift @@ -1,6 +1,5 @@ import Foundation import RuuviOntology -import RuuviVirtual protocol DashboardRouterInput { func openMenu(output: MenuModuleOutput) @@ -12,39 +11,35 @@ protocol DashboardRouterInput { func openRuuviProductsPageFromMenu() func openSignIn(output: SignInBenefitsModuleOutput) // swiftlint:disable:next function_parameter_count - func openCardImageView(with viewModels: [CardsViewModel], - ruuviTagSensors: [AnyRuuviTagSensor], - virtualSensors: [AnyVirtualTagSensor], - sensorSettings: [SensorSettings], - scrollTo: CardsViewModel?, - showCharts: Bool, - output: CardsModuleOutput) + func openCardImageView( + with viewModels: [CardsViewModel], + ruuviTagSensors: [AnyRuuviTagSensor], + sensorSettings: [SensorSettings], + scrollTo: CardsViewModel?, + showCharts: Bool, + output: CardsModuleOutput + ) func openTagSettings( ruuviTag: RuuviTagSensor, latestMeasurement: RuuviTagSensorRecord?, sensorSettings: SensorSettings?, output: TagSettingsModuleOutput ) - func openVirtualSensorSettings( - sensor: VirtualTagSensor, - temperature: Temperature? - ) - // swiftlint:disable function_parameter_count /// Used for only when a new sensor is added. - func openTagSettings(with viewModels: [CardsViewModel], - ruuviTagSensors: [AnyRuuviTagSensor], - virtualSensors: [AnyVirtualTagSensor], - sensorSettings: [SensorSettings], - scrollTo: CardsViewModel?, - ruuviTag: RuuviTagSensor, - latestMeasurement: RuuviTagSensorRecord?, - sensorSetting: SensorSettings?, - output: CardsModuleOutput) + func openTagSettings( + with viewModels: [CardsViewModel], + ruuviTagSensors: [AnyRuuviTagSensor], + sensorSettings: [SensorSettings], + scrollTo: CardsViewModel?, + ruuviTag: RuuviTagSensor, + latestMeasurement: RuuviTagSensorRecord?, + sensorSetting: SensorSettings?, + output: CardsModuleOutput + ) // swiftlint:enable function_parameter_count func openUpdateFirmware(ruuviTag: RuuviTagSensor) func openBackgroundSelectionView(ruuviTag: RuuviTagSensor) - func openBackgroundSelectionView(virtualSensor: VirtualTagSensor) func openMyRuuviAccount() func openShare(for sensor: RuuviTagSensor) } diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift index 55f89b892..8f766435a 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift @@ -368,15 +368,6 @@ extension DashboardImageCell { } else { hideMovementView(hide: true) } - case .web: - let location = viewModel.location - if let location = location.value { - movementView.setValue(with: location.city ?? location.country) - } else if let currentLocation = viewModel.currentLocation.value { - movementView.setValue(with: currentLocation.description) - } else { - movementView.setValue(with: "N/A".localized()) - } } // Ago diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift index 9730a82ae..ea899d16a 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift @@ -325,15 +325,6 @@ extension DashboardPlainCell { } else { hideMovementView(hide: true) } - case .web: - let location = viewModel.location - if let location = location.value { - movementView.setValue(with: location.city ?? location.country) - } else if let currentLocation = viewModel.currentLocation.value { - movementView.setValue(with: currentLocation.description) - } else { - movementView.setValue(with: "N/A".localized()) - } } // Ago diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift index 55769bc37..1894a379f 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift @@ -621,14 +621,6 @@ extension DashboardViewController: DashboardViewInput { // No op. } - func showWebTagAPILimitExceededError() { - let title = "Cards.WebTagAPILimitExcededError.Alert.title".localized() - let message = "Cards.WebTagAPILimitExcededError.Alert.message".localized() - let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) - present(alertVC, animated: true) - } - func showBluetoothDisabled(userDeclined: Bool) { let title = "Cards.BluetoothDisabledAlert.title".localized() let message = "Cards.BluetoothDisabledAlert.message".localized() diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift index ff92d738a..e622a2939 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift @@ -10,7 +10,6 @@ protocol DashboardViewInput: ViewInput { func applyUpdate(to viewModel: CardsViewModel) func showNoSensorsAddedMessage(show: Bool) func showBluetoothDisabled(userDeclined: Bool) - func showWebTagAPILimitExceededError() func showKeepConnectionDialogChart(for viewModel: CardsViewModel) func showKeepConnectionDialogSettings(for viewModel: CardsViewModel) func showReverseGeocodingFailed() diff --git a/station/Classes/Presentation/Modules/LocationPicker/Assembly/Apple/LocationPickerAppleConfigurator.swift b/station/Classes/Presentation/Modules/LocationPicker/Assembly/Apple/LocationPickerAppleConfigurator.swift deleted file mode 100644 index 67003986d..000000000 --- a/station/Classes/Presentation/Modules/LocationPicker/Assembly/Apple/LocationPickerAppleConfigurator.swift +++ /dev/null @@ -1,25 +0,0 @@ -import UIKit -import RuuviCore -import RuuviLocation -import RuuviPresenters - -class LocationPickerAppleConfigurator { - func configure(view: LocationPickerAppleViewController) { - let r = AppAssembly.shared.assembler.resolver - - let router = LocationPickerRouter() - router.transitionHandler = view - - let presenter = LocationPickerPresenter() - presenter.view = view - presenter.router = router - presenter.locationService = r.resolve(RuuviLocationService.self) - presenter.activityPresenter = r.resolve(ActivityPresenter.self) - presenter.errorPresenter = r.resolve(ErrorPresenter.self) - presenter.permissionsManager = r.resolve(RuuviCorePermission.self) - presenter.permissionPresenter = r.resolve(PermissionPresenter.self) - presenter.locationManager = r.resolve(RuuviCoreLocation.self) - - view.output = presenter - } -} diff --git a/station/Classes/Presentation/Modules/LocationPicker/Assembly/Apple/LocationPickerAppleInitializer.swift b/station/Classes/Presentation/Modules/LocationPicker/Assembly/Apple/LocationPickerAppleInitializer.swift deleted file mode 100644 index eb3c2ed72..000000000 --- a/station/Classes/Presentation/Modules/LocationPicker/Assembly/Apple/LocationPickerAppleInitializer.swift +++ /dev/null @@ -1,10 +0,0 @@ -import UIKit - -class LocationPickerAppleInitializer: NSObject { - @IBOutlet weak var viewController: LocationPickerAppleViewController! - - override func awakeFromNib() { - super.awakeFromNib() - LocationPickerAppleConfigurator().configure(view: viewController) - } -} diff --git a/station/Classes/Presentation/Modules/LocationPicker/LocationPicker.storyboard b/station/Classes/Presentation/Modules/LocationPicker/LocationPicker.storyboard deleted file mode 100644 index 00658367e..000000000 --- a/station/Classes/Presentation/Modules/LocationPicker/LocationPicker.storyboard +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/station/Classes/Presentation/Modules/LocationPicker/Presenter/LocationPickerModuleInput.swift b/station/Classes/Presentation/Modules/LocationPicker/Presenter/LocationPickerModuleInput.swift deleted file mode 100644 index ec38a35b4..000000000 --- a/station/Classes/Presentation/Modules/LocationPicker/Presenter/LocationPickerModuleInput.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Foundation - -protocol LocationPickerModuleInput: AnyObject { - func configure(output: LocationPickerModuleOutput) - func dismiss(completion: (() -> Void)?) -} - -extension LocationPickerModuleInput { - func dismiss() { - dismiss(completion: nil) - } -} diff --git a/station/Classes/Presentation/Modules/LocationPicker/Presenter/LocationPickerModuleOutput.swift b/station/Classes/Presentation/Modules/LocationPicker/Presenter/LocationPickerModuleOutput.swift deleted file mode 100644 index dafd67825..000000000 --- a/station/Classes/Presentation/Modules/LocationPicker/Presenter/LocationPickerModuleOutput.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation -import RuuviOntology - -protocol LocationPickerModuleOutput: AnyObject { - func locationPicker(module: LocationPickerModuleInput, didPick location: Location) -} diff --git a/station/Classes/Presentation/Modules/LocationPicker/Presenter/LocationPickerPresenter.swift b/station/Classes/Presentation/Modules/LocationPicker/Presenter/LocationPickerPresenter.swift deleted file mode 100644 index fe8bcf28c..000000000 --- a/station/Classes/Presentation/Modules/LocationPicker/Presenter/LocationPickerPresenter.swift +++ /dev/null @@ -1,105 +0,0 @@ -import Foundation -import CoreLocation -import RuuviLocation -import RuuviCore -import RuuviPresenters - -class LocationPickerPresenter: LocationPickerModuleInput { - weak var view: LocationPickerViewInput! - var router: LocationPickerRouterInput! - var locationService: RuuviLocationService! - var activityPresenter: ActivityPresenter! - var errorPresenter: ErrorPresenter! - var permissionsManager: RuuviCorePermission! - var permissionPresenter: PermissionPresenter! - var locationManager: RuuviCoreLocation! - - private var isLoading: Bool = false { - didSet { - if isLoading != oldValue { - if isLoading { - activityPresenter.increment() - } else { - activityPresenter.decrement() - } - } - } - } - private weak var output: LocationPickerModuleOutput? - - func configure(output: LocationPickerModuleOutput) { - self.output = output - } - - func dismiss(completion: (() -> Void)?) { - router.dismiss(completion: completion) - } -} - -extension LocationPickerPresenter: LocationPickerViewOutput { - func viewDidTriggerCancel() { - router.dismiss() - } - - func viewDidTriggerDismiss() { - router.dismiss() - } - - func viewDidTriggerDone() { - if let location = view.selectedLocation { - output?.locationPicker(module: self, didPick: location) - } else { - assert(false) - } - } - - func viewDidEnterSearchQuery(_ query: String) { - let search = locationService.search(query: query) - isLoading = true - search.on(success: { [weak self] (locations) in - self?.view.selectedLocation = locations.first - }, failure: { [weak self] (error) in - self?.errorPresenter.present(error: error) - }, completion: { - self.isLoading = false - }) - } - - func viewDidLongPressOnMap(at coordinate: CLLocationCoordinate2D) { - let reverseGeoCode = locationService.reverseGeocode(coordinate: coordinate) - reverseGeoCode.on(success: { [weak self] (locations) in - self?.view.selectedLocation = locations.last - }, failure: { [weak self] (error) in - self?.errorPresenter.present(error: error) - }) - } - - func viewDidTriggerCurrentLocation() { - if !permissionsManager.isLocationPermissionGranted { - permissionsManager.requestLocationPermission { [weak self] (granted) in - if granted { - self?.obtainCurrentLocation() - } else { - self?.permissionPresenter.presentNoLocationPermission() - } - } - } else { - obtainCurrentLocation() - } - } - - private func obtainCurrentLocation() { - let op = locationManager.getCurrentLocation() - op.on(success: { [weak self] (location) in - let reverseGeoCode = self?.locationService.reverseGeocode(coordinate: location.coordinate) - reverseGeoCode?.on(success: { (locations) in - self?.view.selectedLocation = locations.last - }, failure: { (error) in - self?.errorPresenter.present(error: error) - }) - }, failure: { [weak self] (error) in - self?.errorPresenter.present(error: error) - }) - } - -} diff --git a/station/Classes/Presentation/Modules/LocationPicker/Router/LocationPickerRouter.swift b/station/Classes/Presentation/Modules/LocationPicker/Router/LocationPickerRouter.swift deleted file mode 100644 index bf0054abd..000000000 --- a/station/Classes/Presentation/Modules/LocationPicker/Router/LocationPickerRouter.swift +++ /dev/null @@ -1,11 +0,0 @@ -import LightRoute -import UIKit - -class LocationPickerRouter: LocationPickerRouterInput { - weak var transitionHandler: UIViewController! - - func dismiss(completion: (() -> Void)?) { - transitionHandler.dismiss(animated: true, completion: completion) - } - -} diff --git a/station/Classes/Presentation/Modules/LocationPicker/Router/LocationPickerRouterInput.swift b/station/Classes/Presentation/Modules/LocationPicker/Router/LocationPickerRouterInput.swift deleted file mode 100644 index 2a57a786c..000000000 --- a/station/Classes/Presentation/Modules/LocationPicker/Router/LocationPickerRouterInput.swift +++ /dev/null @@ -1,11 +0,0 @@ -import Foundation - -protocol LocationPickerRouterInput { - func dismiss(completion: (() -> Void)?) -} - -extension LocationPickerRouterInput { - func dismiss() { - dismiss(completion: nil) - } -} diff --git a/station/Classes/Presentation/Modules/LocationPicker/View/Apple/LocationPickerAppleViewController.swift b/station/Classes/Presentation/Modules/LocationPicker/View/Apple/LocationPickerAppleViewController.swift deleted file mode 100644 index 17d4d1a39..000000000 --- a/station/Classes/Presentation/Modules/LocationPicker/View/Apple/LocationPickerAppleViewController.swift +++ /dev/null @@ -1,148 +0,0 @@ -import UIKit -import MapKit -import RuuviOntology - -class LocationPickerAppleViewController: UIViewController { - var output: LocationPickerViewOutput! - - @IBOutlet weak var mapView: MKMapView! - @IBOutlet var doneBarButtonItem: UIBarButtonItem! - @IBOutlet var cancelBarButtonItem: UIBarButtonItem! - - var selectedLocation: Location? { - didSet { - updateUISelectedLocation() - } - } - - private var searchBar: UISearchBar! - private let annotationViewReuseIdentifier = "LocationPickerMKAnnotationViewReuseIdentifier" -} - -// MARK: - LocationPickerViewInput -extension LocationPickerAppleViewController: LocationPickerViewInput { - func localize() { - doneBarButtonItem.title = "Done".localized() - cancelBarButtonItem.title = "Cancel".localized() - } -} - -// MARK: - IBActions -extension LocationPickerAppleViewController { - @IBAction func doneBarButtonItemAction(_ sender: Any) { - output.viewDidTriggerDone() - } - - @IBAction func cancelBarButtonItemAction(_ sender: Any) { - output.viewDidTriggerCancel() - } - - @IBAction func dismissBarButtonItemAction(_ sender: Any) { - output.viewDidTriggerDismiss() - } - - @IBAction func pinBarButtonItemAction(_ sender: Any) { - output.viewDidTriggerCurrentLocation() - } - - @objc func mapViewLongPressHandler(_ gr: UIGestureRecognizer) { - if gr.state == .began { - let point = gr.location(in: mapView) - let coordinate = mapView.convert(point, toCoordinateFrom: mapView) - output.viewDidLongPressOnMap(at: coordinate) - } - } - - @objc func mapViewTapHandler(_ gr: UIGestureRecognizer) { - searchBar.resignFirstResponder() - } -} - -// MARK: - View lifecycle -extension LocationPickerAppleViewController { - override func viewDidLoad() { - super.viewDidLoad() - setupLocalization() - configureViews() - updateUI() - } -} - -// MARK: - MKMapViewDelegate -extension LocationPickerAppleViewController: MKMapViewDelegate { - func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? { - if let view = mapView.dequeueReusableAnnotationView(withIdentifier: annotationViewReuseIdentifier) { - return view - } else { - let view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotationViewReuseIdentifier) - view.canShowCallout = true - view.animatesDrop = true - return view - } - } - - func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) { - searchBar.resignFirstResponder() - } -} - -// MARK: - UISearchBarDelegate -extension LocationPickerAppleViewController: UISearchBarDelegate { - func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { - searchBar.resignFirstResponder() - if let query = searchBar.text { - output.viewDidEnterSearchQuery(query) - } - } -} - -// MARK: - View configuration -extension LocationPickerAppleViewController { - private func configureViews() { - if #available(iOS 13, *) { - let appearance = navigationController?.navigationBar.standardAppearance.copy() - navigationItem.standardAppearance = appearance - } - - searchBar = UISearchBar(frame: .zero) - searchBar.backgroundColor = .systemBackground - searchBar.searchTextField.leftView?.tintColor = .secondaryLabel - searchBar.delegate = self - navigationItem.titleView = searchBar - - let gr = UILongPressGestureRecognizer(target: self, - action: - #selector(LocationPickerAppleViewController.mapViewLongPressHandler(_:))) - gr.minimumPressDuration = 0.3 - mapView.addGestureRecognizer(gr) - - let tr = UITapGestureRecognizer(target: self, - action: #selector(LocationPickerAppleViewController.mapViewTapHandler(_:))) - mapView.addGestureRecognizer(tr) - } -} - -// MARK: - Update UI -extension LocationPickerAppleViewController { - private func updateUI() { - updateUISelectedLocation() - } - - private func updateUISelectedLocation() { - if isViewLoaded { - mapView.removeAnnotations(mapView.annotations) - if let location = selectedLocation { - let annotation = MKPointAnnotation() - annotation.coordinate = location.coordinate - annotation.title = location.cityCommaCountry - mapView.addAnnotation(annotation) - mapView.centerCoordinate = location.coordinate - mapView.selectAnnotation(annotation, animated: true) - searchBar.text = location.cityCommaCountry - navigationItem.rightBarButtonItems = [doneBarButtonItem] - } else { - navigationItem.rightBarButtonItems = [cancelBarButtonItem] - } - } - } -} diff --git a/station/Classes/Presentation/Modules/LocationPicker/View/LocationPickerViewInput.swift b/station/Classes/Presentation/Modules/LocationPicker/View/LocationPickerViewInput.swift deleted file mode 100644 index 562bc50ff..000000000 --- a/station/Classes/Presentation/Modules/LocationPicker/View/LocationPickerViewInput.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation -import RuuviOntology - -protocol LocationPickerViewInput: ViewInput { - var selectedLocation: Location? { get set } -} diff --git a/station/Classes/Presentation/Modules/LocationPicker/View/LocationPickerViewOutput.swift b/station/Classes/Presentation/Modules/LocationPicker/View/LocationPickerViewOutput.swift deleted file mode 100644 index fc0ab1b8d..000000000 --- a/station/Classes/Presentation/Modules/LocationPicker/View/LocationPickerViewOutput.swift +++ /dev/null @@ -1,11 +0,0 @@ -import Foundation -import CoreLocation - -protocol LocationPickerViewOutput { - func viewDidTriggerDone() - func viewDidTriggerCancel() - func viewDidTriggerDismiss() - func viewDidEnterSearchQuery(_ query: String) - func viewDidLongPressOnMap(at coordinate: CLLocationCoordinate2D) - func viewDidTriggerCurrentLocation() -} diff --git a/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift index ef97ad6d3..ff9d608a3 100644 --- a/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift @@ -4,7 +4,6 @@ import RuuviContext import RuuviReactor import RuuviLocal import RuuviService -import RuuviVirtual import RuuviPresenters import RuuviUser import RuuviStorage diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift index d7e4a1649..7fa156aa7 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift @@ -26,7 +26,6 @@ class DefaultsPresenter: NSObject, DefaultsModuleInput { buildChartIntervalSeconds(), buildChartDurationHours(), saveAdvertisementsInterval(), - buildSaveAndLoadFromWebIntervalMinutues(), buildAskForReviewFirstTime(), buildAskForReviewLater(), buildDashboardCardTapAction(), @@ -197,19 +196,6 @@ extension DefaultsPresenter { return advertisementInterval } - private func buildSaveAndLoadFromWebIntervalMinutues() -> DefaultsViewModel { - let webSaveAndLoadInterval = DefaultsViewModel() - webSaveAndLoadInterval.title = "ForegroundRow.webTags.title".localized() - webSaveAndLoadInterval.integer.value = settings.webTagDaemonIntervalMinutes - webSaveAndLoadInterval.unit = .minutes - webSaveAndLoadInterval.type.value = .stepper - - bind(webSaveAndLoadInterval.integer, fire: false) { observer, interval in - observer.settings.webTagDaemonIntervalMinutes = interval.bound - } - return webSaveAndLoadInterval - } - private func buildAskForReviewFirstTime() -> DefaultsViewModel { let askForReviewAtLaunch = DefaultsViewModel() askForReviewAtLaunch.title = "Defaults.AppLaunchRequiredForReview.Count.title".localized() diff --git a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift index 9ce720982..788205a2f 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift @@ -1101,13 +1101,6 @@ extension TagSettingsPresenter { self?.updateMutedTill(of: type, for: physicalSensor.id) self?.syncAlerts(of: type) } - if let virtualSensor - = userInfo[RuuviServiceAlertDidChangeKey.virtualSensor] as? VirtualSensor, - virtualSensor.id == self?.viewModel.uuid.value, - let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType { - self?.updateIsOnState(of: type, for: virtualSensor.id) - self?.updateMutedTill(of: type, for: virtualSensor.id) - } } }) } diff --git a/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift b/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift index d02abd2d9..38952a1c6 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift @@ -21,7 +21,7 @@ class TagSettingsRouter: NSObject, TagSettingsRouterInput { func openBackgroundSelectionView(ruuviTag: RuuviTagSensor) { let factory: BackgroundSelectionModuleFactory = BackgroundSelectionModuleFactoryImpl() - let module = factory.create(for: ruuviTag, virtualTag: nil) + let module = factory.create(for: ruuviTag) self.backgroundSelectionModule = module transitionHandler .navigationController? diff --git a/station/Classes/Presentation/Modules/WebTagSettings/Assembly/Table/WebTagSettingsTableConfigurator.swift b/station/Classes/Presentation/Modules/WebTagSettings/Assembly/Table/WebTagSettingsTableConfigurator.swift deleted file mode 100644 index fdad1eb54..000000000 --- a/station/Classes/Presentation/Modules/WebTagSettings/Assembly/Table/WebTagSettingsTableConfigurator.swift +++ /dev/null @@ -1,30 +0,0 @@ -import Foundation -import RuuviLocal -import RuuviService -import RuuviVirtual -import RuuviCore -import RuuviPresenters - -class WebTagSettingsTableConfigurator { - func configure(view: WebTagSettingsTableViewController) { - let r = AppAssembly.shared.assembler.resolver - - let router = WebTagSettingsRouter() - router.transitionHandler = view - - let presenter = WebTagSettingsPresenter() - presenter.view = view - presenter.router = router - presenter.virtualReactor = r.resolve(VirtualReactor.self) - presenter.errorPresenter = r.resolve(ErrorPresenter.self) - presenter.webTagService = r.resolve(VirtualService.self) - presenter.settings = r.resolve(RuuviLocalSettings.self) - presenter.alertService = r.resolve(RuuviServiceAlert.self) - presenter.pushNotificationsManager = r.resolve(RuuviCorePN.self) - presenter.permissionsManager = r.resolve(RuuviCorePermission.self) - presenter.permissionPresenter = r.resolve(PermissionPresenter.self) - presenter.ruuviSensorPropertiesService = r.resolve(RuuviServiceSensorProperties.self) - - view.output = presenter - } -} diff --git a/station/Classes/Presentation/Modules/WebTagSettings/Assembly/Table/WebTagSettingsTableInitializer.swift b/station/Classes/Presentation/Modules/WebTagSettings/Assembly/Table/WebTagSettingsTableInitializer.swift deleted file mode 100644 index ac3de6eb9..000000000 --- a/station/Classes/Presentation/Modules/WebTagSettings/Assembly/Table/WebTagSettingsTableInitializer.swift +++ /dev/null @@ -1,10 +0,0 @@ -import UIKit - -class WebTagSettingsTableInitializer: NSObject { - @IBOutlet weak var viewController: WebTagSettingsTableViewController! - - override func awakeFromNib() { - super.awakeFromNib() - WebTagSettingsTableConfigurator().configure(view: viewController) - } -} diff --git a/station/Classes/Presentation/Modules/WebTagSettings/Presenter/WebTagSettingsModuleInput.swift b/station/Classes/Presentation/Modules/WebTagSettings/Presenter/WebTagSettingsModuleInput.swift deleted file mode 100644 index c76cfcdbb..000000000 --- a/station/Classes/Presentation/Modules/WebTagSettings/Presenter/WebTagSettingsModuleInput.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Foundation -import RuuviOntology - -protocol WebTagSettingsModuleInput: AnyObject { - func configure( - sensor: VirtualTagSensor, - temperature: Temperature? - ) -} diff --git a/station/Classes/Presentation/Modules/WebTagSettings/Presenter/WebTagSettingsPresenter.swift b/station/Classes/Presentation/Modules/WebTagSettings/Presenter/WebTagSettingsPresenter.swift deleted file mode 100644 index 0984eca9b..000000000 --- a/station/Classes/Presentation/Modules/WebTagSettings/Presenter/WebTagSettingsPresenter.swift +++ /dev/null @@ -1,541 +0,0 @@ -// swiftlint:disable file_length -import UIKit -import CoreLocation -import Humidity -import RuuviOntology -import RuuviLocal -import RuuviService -import RuuviVirtual -import RuuviCore -import RuuviPresenters - -class WebTagSettingsPresenter: NSObject, WebTagSettingsModuleInput { - weak var view: WebTagSettingsViewInput! - var virtualReactor: VirtualReactor! - var router: WebTagSettingsRouterInput! - var errorPresenter: ErrorPresenter! - var webTagService: VirtualService! - var settings: RuuviLocalSettings! - var alertService: RuuviServiceAlert! - var pushNotificationsManager: RuuviCorePN! - var permissionsManager: RuuviCorePermission! - var permissionPresenter: PermissionPresenter! - var ruuviSensorPropertiesService: RuuviServiceSensorProperties! - - private var temperature: Temperature? { - didSet { - view.viewModel.temperature.value = temperature - } - } - private var mutedTillTimer: Timer? - private var virtualReactorToken: VirtualReactorToken? - private var temperatureUnitToken: NSObjectProtocol? - private var humidityUnitToken: NSObjectProtocol? - private var pressureUnitToken: NSObjectProtocol? - private var appDidBecomeActiveToken: NSObjectProtocol? - private var alertDidChangeToken: NSObjectProtocol? - private var virtualSensor: VirtualTagSensor! { - didSet { - syncViewModel() - bindViewModel(to: virtualSensor) - } - } - - deinit { - mutedTillTimer?.invalidate() - virtualReactorToken?.invalidate() - temperatureUnitToken?.invalidate() - appDidBecomeActiveToken?.invalidate() - humidityUnitToken?.invalidate() - pressureUnitToken?.invalidate() - alertDidChangeToken?.invalidate() - } - - func configure( - sensor: VirtualTagSensor, - temperature: Temperature? - ) { - self.virtualSensor = sensor - self.temperature = temperature - startObservingWebTag() - startObservingSettingsChanges() - startObservingApplicationState() - startObservingAlertChanges() - startMutedTillTimer() - } -} - -// MARK: - WebTagSettingsViewOutput -extension WebTagSettingsPresenter: WebTagSettingsViewOutput { - func viewWillAppear() { - checkPushNotificationsStatus() - syncViewModel() - } - - func viewDidAskToDismiss() { - router.dismiss() - } - - func viewDidTriggerChangeBackground() { - router.openBackgroundSelectionView(virtualSensor: virtualSensor) - } - - func viewDidChangeTag(name: String) { - let defaultName = virtualSensor.loc == nil - ? VirtualLocation.current.title - : VirtualLocation.manual.title - let finalName = name.isEmpty ? defaultName : name - let operation = webTagService.update(name: finalName, of: virtualSensor) - operation.on(failure: { [weak self] (error) in - self?.errorPresenter.present(error: error) - }) - } - - func viewDidAskToRemoveWebTag() { - view.showTagRemovalConfirmationDialog() - } - - func viewDidConfirmTagRemoval() { - let operation = webTagService.remove(sensor: virtualSensor) - operation.on(success: { [weak self] _ in - self?.router.dismiss() - }, failure: { [weak self] (error) in - self?.errorPresenter.present(error: error) - }) - } - - func viewDidAskToSelectLocation() { - router.openLocationPicker(output: self) - } - - func viewDidAskToClearLocation() { - view.showClearLocationConfirmationDialog() - } - - func viewDidConfirmToClearLocation() { - let operation = webTagService.clearLocation( - of: virtualSensor, - name: VirtualLocation.current.title - ) - operation.on(failure: { [weak self] (error) in - self?.errorPresenter.present(error: error) - }) - } - - func viewDidTapOnAlertsDisabledView() { - let isPN = view.viewModel.isPushNotificationsEnabled.value ?? false - let isFixed = view.viewModel.location.value != nil - let isLA = view.viewModel.isLocationAuthorizedAlways.value ?? false - - if isFixed { - if !isPN { - permissionPresenter.presentNoPushNotificationsPermission() - } - } else { - if !isPN && !isLA { - view.showBothNoPNPermissionAndNoLocationPermission() - } else if !isLA { - permissionPresenter.presentNoLocationPermission() - } else if !isPN { - permissionPresenter.presentNoPushNotificationsPermission() - } - } - } - - func viewDidAskToOpenSettings() { - router.openSettings() - } -} - -// MARK: - Observations -extension WebTagSettingsPresenter { - private func startObservingSettingsChanges() { - temperatureUnitToken = NotificationCenter - .default - .addObserver(forName: .TemperatureUnitDidChange, - object: nil, - queue: .main) { [weak self] _ in - self?.view.viewModel.temperatureUnit.value = self?.settings.temperatureUnit - } - humidityUnitToken = NotificationCenter - .default - .addObserver(forName: .HumidityUnitDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.view.viewModel.humidityUnit.value = self?.settings.humidityUnit - }) - pressureUnitToken = NotificationCenter - .default - .addObserver(forName: .PressureUnitDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.view.viewModel.pressureUnit.value = self?.settings.pressureUnit - }) - } -} - -// MARK: - LocationPickerModuleOutput -extension WebTagSettingsPresenter: LocationPickerModuleOutput { - func locationPicker(module: LocationPickerModuleInput, didPick location: Location) { - let operation = webTagService.update(location: location, of: virtualSensor) - operation.on(failure: { [weak self] error in - self?.errorPresenter.present(error: error) - }) - module.dismiss() - } -} - -// MARK: - Private -extension WebTagSettingsPresenter { - private func startMutedTillTimer() { - self.mutedTillTimer = Timer - .scheduledTimer( - withTimeInterval: 5, - repeats: true - ) { [weak self] timer in - guard let sSelf = self else { timer.invalidate(); return } - sSelf.reloadMutedTill() - } - } - - private func bindViewModel(to webTag: VirtualTagSensor) { - bindTemperatureAlert(webTag) - bindHumidityAlert(webTag) - bindPressureAlert(webTag) - } - - private func bindTemperatureAlert(_ sensor: VirtualTagSensor) { - let temperatureLower = view.viewModel.temperatureLowerBound - let temperatureUpper = view.viewModel.temperatureUpperBound - bind(view.viewModel.isTemperatureAlertOn, fire: false) { - [weak temperatureLower, - weak temperatureUpper] observer, isOn in - if let l = temperatureLower?.value?.converted(to: .celsius).value, - let u = temperatureUpper?.value?.converted(to: .celsius).value { - let type: AlertType = .temperature(lower: l, upper: u) - let currentState = observer.alertService.isOn(type: type, for: sensor) - if currentState != isOn.bound { - if isOn.bound { - observer.alertService.register(type: type, for: sensor) - } else { - observer.alertService.unregister(type: type, for: sensor) - } - observer.alertService.unmute(type: type, for: sensor) - } - } - } - bind(view.viewModel.temperatureLowerBound, fire: false) { observer, lower in - if let l = lower?.converted(to: .celsius).value { - observer.alertService.setLower(celsius: l, for: sensor) - } - } - bind(view.viewModel.temperatureUpperBound, fire: false) { observer, upper in - if let u = upper?.converted(to: .celsius).value { - observer.alertService.setUpper(celsius: u, for: sensor) - } - } - bind(view.viewModel.temperatureAlertDescription, fire: false) {observer, temperatureAlertDescription in - observer.alertService.setTemperature(description: temperatureAlertDescription, for: sensor) - } - } - - private func bindHumidityAlert(_ sensor: VirtualTagSensor) { - let humidityLower = view.viewModel.humidityLowerBound - let humidityUpper = view.viewModel.humidityUpperBound - bind(view.viewModel.isHumidityAlertOn, fire: false) { - [weak humidityLower, weak humidityUpper] observer, isOn in - if let l = humidityLower?.value, - let u = humidityUpper?.value { - let type: AlertType = .humidity(lower: l, upper: u) - let currentState = observer.alertService.isOn( - type: type, - for: sensor.id - ) - if currentState != isOn.bound { - if isOn.bound { - observer.alertService.register(type: type, for: sensor) - } else { - observer.alertService.unregister(type: type, for: sensor) - } - observer.alertService.unmute(type: type, for: sensor) - } - } - } - bind(view.viewModel.humidityLowerBound, fire: false) { observer, lower in - observer.alertService.setLower(humidity: lower, for: sensor) - } - bind(view.viewModel.humidityUpperBound, fire: false) { observer, upper in - observer.alertService.setUpper(humidity: upper, for: sensor) - } - bind(view.viewModel.humidityAlertDescription, fire: false) { - observer, humidityAlertDescription in - observer.alertService.setHumidity(description: humidityAlertDescription, for: sensor) - } - } - - private func bindPressureAlert(_ webTag: VirtualTagSensor) { - let pressureLower = view.viewModel.pressureLowerBound - let pressureUpper = view.viewModel.pressureUpperBound - bind(view.viewModel.isPressureAlertOn, fire: false) { - [weak pressureLower, weak pressureUpper] observer, isOn in - if let l = pressureLower?.value?.converted(to: .hectopascals).value, - let u = pressureUpper?.value?.converted(to: .hectopascals).value { - let type: AlertType = .pressure(lower: l, upper: u) - let currentState = observer.alertService.isOn( - type: type, - for: webTag.id - ) - if currentState != isOn.bound { - if isOn.bound { - observer.alertService.register(type: type, for: webTag) - } else { - observer.alertService.unregister(type: type, for: webTag) - } - observer.alertService.unmute(type: type, for: webTag) - } - } - } - - bind(view.viewModel.pressureLowerBound, fire: false) { observer, lower in - if let l = lower?.converted(to: .hectopascals).value { - observer.alertService.setLower(pressure: l, for: webTag) - } - } - - bind(view.viewModel.pressureUpperBound, fire: false) { observer, upper in - if let u = upper?.converted(to: .hectopascals).value { - observer.alertService.setUpper(pressure: u, for: webTag) - } - } - - bind(view.viewModel.pressureAlertDescription, fire: false) { observer, pressureAlertDescription in - observer.alertService.setPressure(description: pressureAlertDescription, for: webTag) - } - } - - private func startObservingWebTag() { - virtualReactorToken?.invalidate() - let id = virtualSensor.id - virtualReactorToken = virtualReactor.observe { [weak self] change in - switch change { - case .delete(let sensor): - if sensor.id == id { - self?.router.dismiss() - } - case .update(let sensor): - if sensor.id == id { - self?.virtualSensor = sensor - self?.syncViewModel() - } - case .error(let error): - self?.errorPresenter.present(error: error) - default: - break - } - } - } - - private func startObservingApplicationState() { - appDidBecomeActiveToken = NotificationCenter - .default - .addObserver(forName: UIApplication.didBecomeActiveNotification, - object: nil, - queue: .main, - using: { [weak self] (_) in - self?.checkPushNotificationsStatus() - self?.view.viewModel.isLocationAuthorizedAlways.value - = self?.permissionsManager.locationAuthorizationStatus == .authorizedAlways - }) - } - - // swiftlint:disable:next function_body_length - private func syncViewModel() { - ruuviSensorPropertiesService.getImage(for: virtualSensor) - .on(success: { [weak self] image in - self?.view.viewModel.background.value = image - }, failure: { [weak self] error in - self?.errorPresenter.present(error: error) - }) - view.viewModel.isLocationAuthorizedAlways.value - = permissionsManager.locationAuthorizationStatus == .authorizedAlways - view.viewModel.temperatureUnit.value = settings.temperatureUnit - view.viewModel.humidityUnit.value = settings.humidityUnit - view.viewModel.pressureUnit.value = settings.pressureUnit - if virtualSensor.name == VirtualLocation.manual.title { - view.viewModel.name.value = nil - } else { - view.viewModel.name.value = virtualSensor.name - } - - view.viewModel.uuid.value = virtualSensor.id - view.viewModel.location.value = virtualSensor.loc - - view.isNameChangedEnabled = view.viewModel.location.value != nil - - view.viewModel.temperatureAlertDescription.value - = alertService.temperatureDescription(for: virtualSensor.id) - view.viewModel.humidityAlertDescription.value - = alertService.humidityDescription(for: virtualSensor.id) - view.viewModel.pressureAlertDescription.value - = alertService.pressureDescription(for: virtualSensor.id) - - let temperatureAlertType: AlertType = .temperature(lower: 0, upper: 0) - if case .temperature(let lower, let upper) = alertService.alert( - for: virtualSensor.id, - of: temperatureAlertType - ) { - view.viewModel.isTemperatureAlertOn.value = true - view.viewModel.temperatureLowerBound.value = Temperature(lower, unit: .celsius) - view.viewModel.temperatureUpperBound.value = Temperature(upper, unit: .celsius) - } else { - view.viewModel.isTemperatureAlertOn.value = false - if let celsiusLower = alertService.lowerCelsius(for: virtualSensor.id) { - view.viewModel.temperatureLowerBound.value = Temperature(celsiusLower, unit: .celsius) - } - if let celsiusUpper = alertService.upperCelsius(for: virtualSensor.id) { - view.viewModel.temperatureUpperBound.value = Temperature(celsiusUpper, unit: .celsius) - } - } - view.viewModel.temperatureAlertMutedTill.value - = alertService.mutedTill(type: temperatureAlertType, for: virtualSensor.id) - - let humidityAlertType: AlertType = .humidity(lower: .init(value: 0, unit: .absolute), - upper: .init(value: 0, unit: .absolute)) - if case .humidity(let lower, let upper) - = alertService.alert(for: virtualSensor.id, of: humidityAlertType) { - view.viewModel.isHumidityAlertOn.value = true - view.viewModel.humidityLowerBound.value = lower - view.viewModel.humidityUpperBound.value = upper - } else { - view.viewModel.isHumidityAlertOn.value = false - if let humidityLower = alertService.lowerHumidity(for: virtualSensor.id) { - view.viewModel.humidityLowerBound.value = humidityLower - } - if let humidityUpper = alertService.upperHumidity(for: virtualSensor.id) { - view.viewModel.humidityUpperBound.value = humidityUpper - } - } - view.viewModel.humidityAlertMutedTill.value = alertService.mutedTill( - type: humidityAlertType, - for: virtualSensor.id - ) - - let pressureAlertType: AlertType = .pressure(lower: 0, upper: 0) - if case .pressure(let lower, let upper) = alertService.alert(for: virtualSensor.id, of: pressureAlertType) { - view.viewModel.isPressureAlertOn.value = true - view.viewModel.pressureLowerBound.value = Pressure(lower, unit: .hectopascals) - view.viewModel.pressureUpperBound.value = Pressure(upper, unit: .hectopascals) - } else { - view.viewModel.isPressureAlertOn.value = false - if let pressureLowerBound = alertService.lowerPressure(for: virtualSensor.id) { - view.viewModel.pressureLowerBound.value = Pressure(pressureLowerBound, unit: .hectopascals) - } - if let pressureUpperBound = alertService.upperPressure(for: virtualSensor.id) { - view.viewModel.pressureUpperBound.value = Pressure(pressureUpperBound, unit: .hectopascals) - } - } - view.viewModel.pressureAlertMutedTill.value = alertService.mutedTill( - type: pressureAlertType, - for: virtualSensor.id - ) - - reloadMutedTill() - } - - private func checkPushNotificationsStatus() { - pushNotificationsManager.getRemoteNotificationsAuthorizationStatus { [weak self] (status) in - switch status { - case .notDetermined: - self?.pushNotificationsManager.registerForRemoteNotifications() - case .authorized: - self?.view.viewModel.isPushNotificationsEnabled.value = true - case .denied: - self?.view.viewModel.isPushNotificationsEnabled.value = false - } - } - } - - private func startObservingAlertChanges() { - alertDidChangeToken = NotificationCenter - .default - .addObserver(forName: .RuuviServiceAlertDidChange, - object: nil, - queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let virtualSensor = userInfo[RuuviServiceAlertDidChangeKey.virtualSensor] as? VirtualSensor, - virtualSensor.id == self?.view.viewModel.uuid.value, - let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType { - self?.updateIsOnState(of: type, for: virtualSensor.id) - self?.updateMutedTill(of: type, for: virtualSensor.id) - } - }) - } - - private func updateIsOnState(of type: AlertType, for uuid: String) { - var observable: Observable? - switch type { - case .temperature: - observable = view.viewModel.isTemperatureAlertOn - case .relativeHumidity: - observable = view.viewModel.isRelativeHumidityAlertOn - case .humidity: - observable = view.viewModel.isHumidityAlertOn - case .pressure: - observable = view.viewModel.isPressureAlertOn - case .connection, .cloudConnection, .movement, .signal: - observable = nil - } - - if let observable = observable { - let isOn = alertService.isOn(type: type, for: uuid) - if isOn != observable.value { - observable.value = isOn - } - } - } - - private func reloadMutedTill() { - if let mutedTill = view.viewModel.temperatureAlertMutedTill.value, - mutedTill < Date() { - view.viewModel.temperatureAlertMutedTill.value = nil - } - - if let mutedTill = view.viewModel.humidityAlertMutedTill.value, - mutedTill < Date() { - view.viewModel.humidityAlertMutedTill.value = nil - } - - if let mutedTill = view.viewModel.pressureAlertMutedTill.value, - mutedTill < Date() { - view.viewModel.pressureAlertMutedTill.value = nil - } - - } - - private func updateMutedTill(of type: AlertType, for uuid: String) { - var observable: Observable? - switch type { - case .temperature: - observable = view.viewModel.temperatureAlertMutedTill - case .relativeHumidity: - observable = view.viewModel.relativeHumidityAlertMutedTill - case .humidity: - observable = view.viewModel.humidityAlertMutedTill - case .pressure: - observable = view.viewModel.pressureAlertMutedTill - case .connection, .cloudConnection, .movement, .signal: - observable = nil - } - - if let observable = observable { - let date = alertService.mutedTill(type: type, for: uuid) - if date != observable.value { - observable.value = date - } - } - } -} -// swiftlint:enable file_length diff --git a/station/Classes/Presentation/Modules/WebTagSettings/Router/WebTagSettingsRouter.swift b/station/Classes/Presentation/Modules/WebTagSettings/Router/WebTagSettingsRouter.swift deleted file mode 100644 index 4bef48efb..000000000 --- a/station/Classes/Presentation/Modules/WebTagSettings/Router/WebTagSettingsRouter.swift +++ /dev/null @@ -1,39 +0,0 @@ -import UIKit -import LightRoute -import RuuviOntology - -class WebTagSettingsRouter: WebTagSettingsRouterInput { - weak var transitionHandler: UIViewController! - private var backgroundSelectionModule: BackgroundSelectionModuleInput? - - func dismiss() { - try! transitionHandler.closeCurrentModule().perform() - } - - func openLocationPicker(output: LocationPickerModuleOutput) { - let factory = StoryboardFactory(storyboardName: "LocationPicker") - try! transitionHandler - .forStoryboard(factory: factory, to: LocationPickerModuleInput.self) - .then({ (module) -> Any? in - module.configure(output: output) - }) - } - - func openSettings() { - if let settingsUrl = URL(string: UIApplication.openSettingsURLString) { - UIApplication.shared.open(settingsUrl, options: [:]) - } - } - - func openBackgroundSelectionView(virtualSensor: VirtualTagSensor) { - let factory: BackgroundSelectionModuleFactory = BackgroundSelectionModuleFactoryImpl() - let module = factory.create(for: nil, virtualTag: virtualSensor) - self.backgroundSelectionModule = module - transitionHandler - .navigationController? - .pushViewController( - module.viewController, - animated: true - ) - } -} diff --git a/station/Classes/Presentation/Modules/WebTagSettings/Router/WebTagSettingsRouterInput.swift b/station/Classes/Presentation/Modules/WebTagSettings/Router/WebTagSettingsRouterInput.swift deleted file mode 100644 index dafbadb85..000000000 --- a/station/Classes/Presentation/Modules/WebTagSettings/Router/WebTagSettingsRouterInput.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Foundation -import RuuviOntology - -protocol WebTagSettingsRouterInput { - func dismiss() - func openLocationPicker(output: LocationPickerModuleOutput) - func openSettings() - func openBackgroundSelectionView(virtualSensor: VirtualTagSensor) -} diff --git a/station/Classes/Presentation/Modules/WebTagSettings/View/Table/WebTagSettingsTableViewController.swift b/station/Classes/Presentation/Modules/WebTagSettings/View/Table/WebTagSettingsTableViewController.swift deleted file mode 100644 index 8b7530ac6..000000000 --- a/station/Classes/Presentation/Modules/WebTagSettings/View/Table/WebTagSettingsTableViewController.swift +++ /dev/null @@ -1,231 +0,0 @@ -import UIKit -import RuuviOntology - -private enum WebTagSettingsTableSection: Int { - case name = 0 - case moreInfo = 2 - - static func section(for sectionIndex: Int) -> WebTagSettingsTableSection { - return WebTagSettingsTableSection(rawValue: sectionIndex) ?? .name - } -} - -class WebTagSettingsTableViewController: UITableViewController { - var output: WebTagSettingsViewOutput! - - @IBOutlet weak var backgroundImageContainer: UIView! - @IBOutlet weak var backgroundImageView: UIImageView! - @IBOutlet weak var tagNameCell: UITableViewCell! - @IBOutlet weak var locationCell: UITableViewCell! - @IBOutlet weak var locationValueLabel: UILabel! - @IBOutlet weak var clearLocationButton: UIButton! - @IBOutlet weak var clearLocationButtonWidth: NSLayoutConstraint! - @IBOutlet weak var backgroundImageLabel: UILabel! - @IBOutlet weak var tagNameTitleLabel: UILabel! - @IBOutlet weak var tagNameValueLabel: UILabel! - @IBOutlet weak var removeThisWebTagButton: UIButton! - @IBOutlet weak var locationTitleLabel: UILabel! - - var isNameChangedEnabled: Bool = true - var viewModel = WebTagSettingsViewModel() { - didSet { - bindViewModel() - } - } - - private let alertsSectionHeaderReuseIdentifier = "WebTagSettingsAlertsHeaderFooterView" - private let alertOffString = "WebTagSettings.Alerts.Off" - /// The limit for the tag name is 32 characters - private let tagNameCharaterLimit: Int = 32 -} - -// MARK: - WebTagSettingsViewInput -extension WebTagSettingsTableViewController: WebTagSettingsViewInput { - - func localize() { - navigationItem.title = "WebTagSettings.navigationItem.title".localized() - backgroundImageLabel.text = "change_background_image".localized() - tagNameTitleLabel.text = "WebTagSettings.Label.TagName.text".localized() - locationTitleLabel.text = "WebTagSettings.Label.Location.text".localized() - removeThisWebTagButton.setTitle("WebTagSettings.Button.Remove.title".localized().capitalized, for: .normal) - tableView.reloadData() - } - - func showTagRemovalConfirmationDialog() { - let title = "WebTagSettings.confirmTagRemovalDialog.title".localized() - let message = "WebTagSettings.confirmTagRemovalDialog.message".localized() - let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: "Confirm".localized(), - style: .destructive, - handler: { [weak self] _ in - self?.output.viewDidConfirmTagRemoval() - })) - controller.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil)) - present(controller, animated: true) - } - - func showClearLocationConfirmationDialog() { - let title = "WebTagSettings.confirmClearLocationDialog.title".localized() - let message = "WebTagSettings.confirmClearLocationDialog.message".localized() - let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: "Confirm".localized(), - style: .destructive, - handler: { [weak self] _ in - self?.output.viewDidConfirmToClearLocation() - })) - controller.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil)) - present(controller, animated: true) - } - - func showBothNoPNPermissionAndNoLocationPermission() { - let message - = "WebTagSettings.AlertsAreDisabled.Dialog.BothNoPNPermissionAndNoLocationPermission.message".localized() - let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) - let actionTitle = "WebTagSettings.AlertsAreDisabled.Dialog.Settings.title".localized() - controller.addAction(UIAlertAction(title: actionTitle, style: .default, handler: { [weak self] _ in - self?.output.viewDidAskToOpenSettings() - })) - controller.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil)) - present(controller, animated: true) - } -} - -// MARK: - IBActions -extension WebTagSettingsTableViewController { - @IBAction func dismissBarButtonItemAction(_ sender: Any) { - output.viewDidAskToDismiss() - } - - @IBAction func selectBackgroundButtonTouchUpInside(_ sender: UIButton) { - output.viewDidTriggerChangeBackground() - } - - @IBAction func removeThisWebTagButtonTouchUpInside(_ sender: Any) { - output.viewDidAskToRemoveWebTag() - } - - @IBAction func clearLocationButtonTouchUpInside(_ sender: Any) { - output.viewDidAskToClearLocation() - } -} - -// MARK: - View lifecycle -extension WebTagSettingsTableViewController { - override func viewDidLoad() { - super.viewDidLoad() - addGestureRecognizerOnUploadBackgroundContainerView() - setupLocalization() - bindViewModel() - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - output.viewWillAppear() - } -} - -extension WebTagSettingsTableViewController { - private func addGestureRecognizerOnUploadBackgroundContainerView() { - let tap = UITapGestureRecognizer( - target: self, - action: #selector(Self.backgroundContainerViewTapHandler(_:)) - ) - backgroundImageContainer.addGestureRecognizer(tap) - } - - @objc - private func backgroundContainerViewTapHandler(_ sender: Any) { - output.viewDidTriggerChangeBackground() - } -} - -// MARK: - UITableViewDelegate -extension WebTagSettingsTableViewController { - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - tableView.deselectRow(at: indexPath, animated: false) - guard let cell = tableView.cellForRow(at: indexPath) else { - return - } - switch cell { - case tagNameCell: - guard isNameChangedEnabled else { return } - showSensorNameRenameDialog(name: viewModel.name.value) - case locationCell: - output.viewDidAskToSelectLocation() - default: - break - } - } - - override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - return 44 - } -} - -// MARK: - UITextFieldDelegate -extension WebTagSettingsTableViewController: UITextFieldDelegate { - func textFieldShouldReturn(_ textField: UITextField) -> Bool { - textField.resignFirstResponder() - return false - } - - func textField(_ textField: UITextField, shouldChangeCharactersIn - range: NSRange, - replacementString string: String) -> Bool { - guard let text = textField.text else { - return true - } - let limit = text.utf16.count + string.utf16.count - range.length - if limit <= tagNameCharaterLimit { - return true - } else { - return false - } - } -} - -// MARK: - Sensor name rename dialog -extension WebTagSettingsTableViewController { - private func showSensorNameRenameDialog(name: String?) { - var textField = UITextField() - let alert = UIAlertController(title: "TagSettings.tagNameTitleLabel.text".localized(), - message: "TagSettings.tagNameTitleLabel.rename.text".localized(), - preferredStyle: .alert) - alert.addTextField { alertTextField in - alertTextField.delegate = self - alertTextField.text = name - textField = alertTextField - } - let action = UIAlertAction(title: "OK".localized(), style: .default) { [weak self] _ in - guard let name = textField.text, !name.isEmpty else { return } - self?.output.viewDidChangeTag(name: name) - } - let cancelAction = UIAlertAction(title: "Cancel".localized(), style: .cancel) - alert.addAction(action) - alert.addAction(cancelAction) - present(alert, animated: true, completion: nil) - } -} - -// MARK: - Bindings -extension WebTagSettingsTableViewController { - - private func bindViewModel() { - backgroundImageView.bind(viewModel.background) { $0.image = $1 } - tagNameValueLabel.bind(viewModel.name) { $0.text = $1?.trimmingCharacters(in: .whitespacesAndNewlines) } - let clearButton = clearLocationButton - let clearWidth = clearLocationButtonWidth - locationValueLabel.bind(viewModel.location, block: { [weak clearButton, weak clearWidth] label, location in - label.text = location?.cityCommaCountry ?? "WebTagSettings.Location.Current".localized() - clearButton?.isHidden = location == nil - clearWidth?.constant = location == nil ? 0 : 36 - }) - - tableView.bind(viewModel.isLocationAuthorizedAlways) { tableView, _ in - tableView.reloadData() - } - tableView.bind(viewModel.location) { tableView, _ in - tableView.reloadData() - } - } -} diff --git a/station/Classes/Presentation/Modules/WebTagSettings/View/WebTagSettingsViewInput.swift b/station/Classes/Presentation/Modules/WebTagSettings/View/WebTagSettingsViewInput.swift deleted file mode 100644 index 50b39332b..000000000 --- a/station/Classes/Presentation/Modules/WebTagSettings/View/WebTagSettingsViewInput.swift +++ /dev/null @@ -1,10 +0,0 @@ -import Foundation - -protocol WebTagSettingsViewInput: ViewInput { - var viewModel: WebTagSettingsViewModel { get set } - var isNameChangedEnabled: Bool { get set } - - func showTagRemovalConfirmationDialog() - func showClearLocationConfirmationDialog() - func showBothNoPNPermissionAndNoLocationPermission() -} diff --git a/station/Classes/Presentation/Modules/WebTagSettings/View/WebTagSettingsViewModel.swift b/station/Classes/Presentation/Modules/WebTagSettings/View/WebTagSettingsViewModel.swift deleted file mode 100644 index 6978f5520..000000000 --- a/station/Classes/Presentation/Modules/WebTagSettings/View/WebTagSettingsViewModel.swift +++ /dev/null @@ -1,41 +0,0 @@ -import UIKit -import RuuviOntology - -struct WebTagSettingsViewModel { - let background: Observable = Observable() - let name: Observable = Observable() - let uuid: Observable = Observable() - let location: Observable = Observable() - let temperature: Observable = Observable() - - let isLocationAuthorizedAlways: Observable = Observable(false) - let isPushNotificationsEnabled: Observable = Observable() - - let temperatureUnit: Observable = Observable() - let humidityUnit: Observable = Observable() - let pressureUnit: Observable = Observable() - - let isTemperatureAlertOn: Observable = Observable(false) - let temperatureAlertMutedTill: Observable = Observable(nil) - let temperatureLowerBound: Observable = Observable() - let temperatureUpperBound: Observable = Observable() - let temperatureAlertDescription: Observable = Observable() - - let isRelativeHumidityAlertOn: Observable = Observable(false) - let relativeHumidityAlertMutedTill: Observable = Observable(nil) - let relativeHumidityLowerBound: Observable = Observable() - let relativeHumidityUpperBound: Observable = Observable() - let relativeHumidityAlertDescription: Observable = Observable() - - let isHumidityAlertOn: Observable = Observable(false) - let humidityAlertMutedTill: Observable = Observable(nil) - let humidityLowerBound: Observable = Observable(.init(value: 0, unit: .absolute)) - let humidityUpperBound: Observable = Observable(.init(value: 40, unit: .absolute)) - let humidityAlertDescription: Observable = Observable() - - let isPressureAlertOn: Observable = Observable(false) - let pressureAlertMutedTill: Observable = Observable(nil) - let pressureLowerBound: Observable = Observable() - let pressureUpperBound: Observable = Observable() - let pressureAlertDescription: Observable = Observable() -} diff --git a/station/Classes/Presentation/Modules/WebTagSettings/View/WebTagSettingsViewOutput.swift b/station/Classes/Presentation/Modules/WebTagSettings/View/WebTagSettingsViewOutput.swift deleted file mode 100644 index a6c553574..000000000 --- a/station/Classes/Presentation/Modules/WebTagSettings/View/WebTagSettingsViewOutput.swift +++ /dev/null @@ -1,15 +0,0 @@ -import UIKit - -protocol WebTagSettingsViewOutput { - func viewWillAppear() - func viewDidAskToDismiss() - func viewDidTriggerChangeBackground() - func viewDidChangeTag(name: String) - func viewDidAskToRemoveWebTag() - func viewDidConfirmTagRemoval() - func viewDidAskToSelectLocation() - func viewDidAskToClearLocation() - func viewDidConfirmToClearLocation() - func viewDidTapOnAlertsDisabledView() - func viewDidAskToOpenSettings() -} diff --git a/station/Classes/Presentation/Modules/WebTagSettings/WebTagSettings.storyboard b/station/Classes/Presentation/Modules/WebTagSettings/WebTagSettings.storyboard deleted file mode 100644 index 4f82888a7..000000000 --- a/station/Classes/Presentation/Modules/WebTagSettings/WebTagSettings.storyboard +++ /dev/null @@ -1,287 +0,0 @@ - - - - - - - - - - - - - Muli-Bold - - - Muli-Regular - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/station/Classes/Routers/DiscoverRouter.swift b/station/Classes/Routers/DiscoverRouter.swift index 609206040..f017b590f 100644 --- a/station/Classes/Routers/DiscoverRouter.swift +++ b/station/Classes/Routers/DiscoverRouter.swift @@ -2,7 +2,6 @@ import Foundation import RuuviDiscover import RuuviOntology import BTKit -import RuuviLocationPicker import UIKit protocol DiscoverRouterDelegate: AnyObject { @@ -33,32 +32,6 @@ final class DiscoverRouter { } } private weak var weakDiscover: RuuviDiscover? - - private var locationPicker: RuuviLocationPicker { - if let locationPicker = self.weakLocationPicker { - return locationPicker - } else { - let r = AppAssembly.shared.assembler.resolver - let locationPicker = r.resolve(RuuviLocationPicker.self)! - locationPicker.router = self - locationPicker.output = self - self.weakLocationPicker = locationPicker - return locationPicker - } - } - private weak var weakLocationPicker: RuuviLocationPicker? -} - -extension DiscoverRouter: RuuviLocationPickerOutput { - func ruuviLocationPickerWantsClose(_ ruuviLocationPicker: RuuviLocationPicker) { - ruuviLocationPicker.viewController.dismiss(animated: true) - } - - func ruuvi(locationPicker: RuuviLocationPicker, didPick location: Location) { - locationPicker.viewController.dismiss(animated: true) { [weak self] in - self?.discover.onDidPick(location: location) - } - } } extension DiscoverRouter: RuuviDiscoverOutput { @@ -74,16 +47,3 @@ extension DiscoverRouter: RuuviDiscoverOutput { delegate?.discoverRouterWantsCloseWithRuuviTagNavigation(self, ruuviTag: ruuviTag) } } - -extension DiscoverRouter { - // Will be deprecated in near future. Currently retained to support already - // added web tags. - func ruuviDiscoverWantsPickLocation(_ ruuviDiscover: RuuviDiscover) { - let navigation = UINavigationController(rootViewController: locationPicker.viewController) - viewController.present(navigation, animated: true) - } - - func ruuvi(discover: RuuviDiscover, didAdd virtualSensor: AnyVirtualTagSensor) { - delegate?.discoverRouterWantsClose(self) - } -} diff --git a/station/Extensions/Errors/RUError.swift b/station/Extensions/Errors/RUError.swift index 861d0f9f0..468a3a073 100644 --- a/station/Extensions/Errors/RUError.swift +++ b/station/Extensions/Errors/RUError.swift @@ -5,13 +5,9 @@ import RuuviPersistence import RuuviPool import RuuviLocal import RuuviService -import RuuviVirtual import RuuviDFU enum RUError: Error { - case virtualService(VirtualServiceError) - case virtualStorage(VirtualStorageError) - case virtualPersistence(VirtualPersistenceError) case ruuviLocal(RuuviLocalError) case ruuviPool(RuuviPoolError) case ruuviStorage(RuuviStorageError) @@ -34,12 +30,6 @@ enum RUError: Error { extension RUError: LocalizedError { public var errorDescription: String? { switch self { - case .virtualService(let error): - return error.localizedDescription - case .virtualPersistence(let error): - return error.localizedDescription - case .virtualStorage(let error): - return error.localizedDescription case .ruuviLocal(let error): return error.localizedDescription case .ruuviPool(let error): @@ -152,7 +142,6 @@ enum UnexpectedError: Error { case callerDeinitedDuringOperation case failedToReverseGeocodeCoordinate case failedToFindRuuviTag - case failedToFindVirtualTag case failedToFindLogsForTheTag case viewModelUUIDIsNil case attemptToReadDataFromRealmWithoutLUID @@ -180,8 +169,6 @@ extension UnexpectedError: LocalizedError { return "UnexpectedError.viewModelUUIDIsNil".localized() case .attemptToReadDataFromRealmWithoutLUID: return "UnexpectedError.attemptToReadDataFromRealmWithoutLUID".localized() - case .failedToFindVirtualTag: - return "UnexpectedError.failedToFindVirtualTag".localized() case .failedToConstructURL: return "UnexpectedError.failedToConstructURL".localized() case .notAHttpResponse: diff --git a/station/Extensions/Errors/RuuviDaemonError+LocalizedError.swift b/station/Extensions/Errors/RuuviDaemonError+LocalizedError.swift index 88515f8a3..1c986e28e 100644 --- a/station/Extensions/Errors/RuuviDaemonError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviDaemonError+LocalizedError.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviVirtual import RuuviStorage import RuuviReactor import RuuviPool @@ -20,8 +19,6 @@ extension RuuviDaemonError: LocalizedError { return error.errorDescription case .ruuviStorage(let error): return error.errorDescription - case .virtualStorage(let error): - return error.errorDescription } } } diff --git a/station/Extensions/Errors/RuuviVirtualError+LocalizedError.swift b/station/Extensions/Errors/RuuviVirtualError+LocalizedError.swift deleted file mode 100644 index f74a4fd33..000000000 --- a/station/Extensions/Errors/RuuviVirtualError+LocalizedError.swift +++ /dev/null @@ -1,78 +0,0 @@ -import Foundation -import RuuviVirtual - -extension VirtualReactorError: LocalizedError { - public var errorDescription: String? { - switch self { - case .virtualPersistence(let error): - return error.localizedDescription - } - } -} - -extension VirtualPersistenceError: LocalizedError { - public var errorDescription: String? { - switch self { - case .persistence(let error): - return error.localizedDescription - case .failedToFindVirtualTag: - return "UnexpectedError.failedToFindVirtualTag".localized() - } - } -} - -extension VirtualRepositoryError: LocalizedError { - public var errorDescription: String? { - switch self { - case .virtualPersistence(let error): - return error.localizedDescription - } - } -} - -extension VirtualStorageError: LocalizedError { - public var errorDescription: String? { - switch self { - case .virtualPersistence(let error): - return error.localizedDescription - } - } -} - -extension VirtualServiceError: LocalizedError { - public var errorDescription: String? { - switch self { - case .virtualPersistence(let error): - return error.localizedDescription - case .ruuviCore(let error): - return error.localizedDescription - case .ruuviLocation(let error): - return error.localizedDescription - case .openWeatherMap(let error): - return error.localizedDescription - case .failedToReverseGeocodeCoordinate: - return "UnexpectedError.failedToReverseGeocodeCoordinate".localized() - case .callerDeinitedDuringOperation: - return "UnexpectedError.callerDeinitedDuringOperation".localized() - } - } -} - -extension OWMError: LocalizedError { - public var errorDescription: String? { - switch self { - case .failedToParseOpenWeatherMapResponse: - return "OWMError.failedToParseOpenWeatherMapResponse".localized() - case .apiLimitExceeded: - return "OWMError.apiLimitExceeded".localized() - case .notAHttpResponse: - return "OWMError.notAHttpResponse".localized() - case .invalidApiKey: - return "OWMError.invalidApiKey".localized() - case .networking(let error): - return error.localizedDescription - case .missingOpenWeatherMapAPIKey: - return "ExpectedError.missingOpenWeatherMapAPIKey".localized() - } - } -} diff --git a/station/Extensions/VirtualLocation+Localization.swift b/station/Extensions/VirtualLocation+Localization.swift deleted file mode 100644 index 5165c5238..000000000 --- a/station/Extensions/VirtualLocation+Localization.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Foundation -import RuuviOntology - -extension VirtualLocation { - var title: String { - switch self { - case .current: - return "WebTagLocationSource.current".localized() - case .manual: - return "WebTagLocationSource.manual".localized() - } - } -} diff --git a/station/Resources/Images/Assets.xcassets/icon-webtag-current.imageset/Contents.json b/station/Resources/Images/Assets.xcassets/icon-webtag-current.imageset/Contents.json deleted file mode 100644 index bd8acf2aa..000000000 --- a/station/Resources/Images/Assets.xcassets/icon-webtag-current.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "webtag-current.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "webtag-current@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "webtag-current@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/station/Resources/Images/Assets.xcassets/icon-webtag-current.imageset/webtag-current.png b/station/Resources/Images/Assets.xcassets/icon-webtag-current.imageset/webtag-current.png deleted file mode 100644 index bd088bd02a4489bea311bc29bbab1dae985ce62a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1671 zcmbVNYiJx*6rLpJ(I$~fYl)#HCIu^AhU&I~2wnJHORsNK8BojHIBbmT%Zr>6}Eu7vQls%}`_!;!cIBe$OD8 zl!nQOX(KY|6KI*^gJiGha!34mvT-%pk=3R|-k6^umhF5ALi zVQSKKEx<6@Y}S_z_)L3(;Y3knSU=}IE@#sU!=LD#es zrkSoB)NsXRG7|9)MkKo>C~JnN02v>Q2%IPgwBN@S-IXK|HyjrlGKxpT6poNj(-gpSsQ?!WakPqhA274acFnz;3UUhm21Y(+lk2YVfpHXzE zJW6Y1F=qgjy;=xUvX=x%p~}&%d zk{IUCI*V)T%De){y~7(;n->14wmoFvUT5Q`cJCuEtrA2{YdqSY2tE1C?CsO@>@1Mv7qom;kUZEycI%rx;WJkO6FIhi;xcY6EM{VTcU7hgW}OZ53q z`YdAlw^T#J;?w-H`qkOx3lFT$ZLlvCo?E)5@aV<)rp1OK^;Dhp&KL9Dw|3MBJy+*s z0*rTj_wAZts-H>lQ}R;Z0;3AG9k+eG^5f&qSgie?XZN1(YgA9sR#)Q_2Y=dBd+deJ zy9&uGhaX(p_I_aB?5^#5XRh`)uI`YOht3qXy~!>7{OX5az73ABnU%{sE(zq}<3ck3 zSQl-aA3u>_WKORgv)&+P-z(g)d8M%b_mdx7TwC%fKa91-^zLQ;sn?I*bUFE2+o5{n Xo3R5Yq|uMPUqyUyDEi94_``ny=UOEV diff --git a/station/Resources/Images/Assets.xcassets/icon-webtag-current.imageset/webtag-current@2x.png b/station/Resources/Images/Assets.xcassets/icon-webtag-current.imageset/webtag-current@2x.png deleted file mode 100644 index b0320dab62ae60f9ddf330a841d9589330de5f5b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1908 zcmbVNeNYr-7++9B3`Q=H{K#4t{DiyRz2&}kI0f$bxEYQJjstX(_ICGRzif&|O*u~a!J~MLTa4!OLj2Wrc*)h9d zVH>!T7Ll!NDRa;*jkJkD7A=Hx10*2uvN8n+ydIxK2Fyr=mjq*F8b#m;L~b-A`HDff z#$FCvc#(y58oipvb9Au5q`~z>j>(h_Ycbr2Vn!4v)VQ9^!APwZj$R0`CNgfa!deuy z1-{HkgDeXqiu(P2ji1o)Vm*qROePf5qFSvQAk@a)Qk9K3HL- zTzr#kMu4ZI61+l;)+a^71OkQzC;`Pam?9|xWat=9Xc9dU;|z_m9@fkHWC>vL7*=TD zWnOCF|AsoY{D1)vTDv`FfhzmN`uP`)Vc32>m9CrIkX`!G41G3syJ@(cGbEsE*x4|fK{2}cR}!u^qy7QiA|v^ zM-7%adqe5#T2wnj312;KJQ63qXx%Y=_;k_sR!hp!=c;;-U~4XTCrlr=XfD>c#zl8t zJQMo)bof>=y!@$O67~_#e3x1mUf$O=l63D}>QGi(^Y=*pld3y2ho|bQ!ZSVyZJ5UO z4kV3-kq_H{!#0_AA{k4MpHFC6S{fhjJVp2P#d~s_-s?%Lc|GNXb6*>hO{QqS$y%^= zzGeR#DF^blsBUCl8k+TK9O1PdN}HPW`PQm~f%us#2(HiP&y=^k4V@1S65;cwT(=z6 zs%wPmS~WzSb|p_7X}k0ie(|HXmRdI_lv)=*(fZSyPj{?sbN(K;d*pcbfRDbs_x8y& zcgQf_zJK$v?8D6&moxWF>v!)B4E+!PF~X4i{AR&S`55IsMv zF0W83v^_*Iyhls3dY}68ZU82#bMo646V7LJzbQ(fWCE^rGA|n?HtqH7?%C#;Yu?62u zs7sQ36o&czeyv}p<%Lp=FdB^*PGTgffe4LQ;g#rs#w*5;YOn&45jda3@m@sMNSE+s zk_m;L4pZ>>LTbI@NSI*2umJ7D2rVvC8UnIR24rz=8a^6 z!tr6Kjb}M$#UG)`6i!gYZ=o=6SX!e05zI1_lNUTRWX*Z#Qh@oqr6>}LC1v5=yZ{YD z?{v4XXIdClxFP1IFG4cYEPBGI*K0^EG32hzMrC?MiS{xe(`rItgtQ#TQU-&O zPA<{uHM(Ry&?FLuWQ~ypq(+wnoFxR%u}+2@mACRtnVbis^6Y<<&k;CShqU{D>yfKd zP9Q3S6XDTTjMUE(uwrE9=8&PBp=d^~1ry51NdQ=MWSRTl5g1nMcLAvMZ}MUoCh|_n zPYYmSDU8;?OFj%Tz~s^$CWHN+=g{75Wj+dry+fXcnihNswLRd4y-t8lO+WF;=?aBv zdZu+@o~!2UjswCM_{7CIrm&h-H8nNLF?DsZQ>T7EX<+w9=?SL};pfgdYMzG|T^M;} z#f9)URs4r7FUW4=O0-x^aa9eS!$-zPcOb!F#NE`0x$scpf? zh?Xz?x(_lgow~cj_1yZ7c=USg%GQUKb@vy&Y4p_X8a%yA9OyBA{L8DcYH6$9h%j)}8ZIIZk-WwYRJd*&Wv((|*>|0-m|IZ%)(cIj-FI*Peg-wPz!Y ziPg>Y;A7==PG#4(YsTVC*p{3{8+Og+#(!?^wS+5Qipt>d>`N z*MLc%n_qk{O*vJEp-0LoQqx?wztLi%#lAPQm9-QUfoAuS?1GB$t zuf=<&efdolsakv^=xFTkd?9k*k4KAB4y+%nNNG+`UK_j>yzjkIqIVtp`pV$yhwIT+ z@!+Rqw7$}FI5+?150iUh=U#107h^UST-j}lsa8EdX2y}5Q#UM=e;YE>vaJUfIck3e DUMC^t diff --git a/station/Resources/Images/Assets.xcassets/icon-webtag-map.imageset/Contents.json b/station/Resources/Images/Assets.xcassets/icon-webtag-map.imageset/Contents.json deleted file mode 100644 index ee9ce2e9f..000000000 --- a/station/Resources/Images/Assets.xcassets/icon-webtag-map.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "webtag-map.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "webtag-map@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "webtag-map@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/station/Resources/Images/Assets.xcassets/icon-webtag-map.imageset/webtag-map.png b/station/Resources/Images/Assets.xcassets/icon-webtag-map.imageset/webtag-map.png deleted file mode 100644 index 8a8d282d2ca696c605ec5b3ef27c8133d4b9d5ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1783 zcmbVNdu$VR9B+-Fpp%D-@(?`^hHP-XyRPke=L&4SZEZ%&=o+_)AlJKJyR*FqcQ@K? z5{53rC4-oOf+&zEGlIHckm&?7bWv2$;52B4k3U?LNyZjLFd*RX+O8P}UtDr`zx(|@ z-^b_sy4DJRS=PiE6HO*lme<1s;5*y6Zyyhzn_6dO!Pf-EQ=^$ocie5_`D+AszWPidu+R3DSuZPMplgNC#~rXsZ=TUnsPu@?ko_l%{RLFBe*? z>k5tI@p#-4&$q~G1Sctq!U-#GwPFx~Y4wuMCNN2xGpd0B8m9`1F31vMXkarS? z<=AMVDn?yK+-@T=6f)n(a)M;=$Q>gE7*+=^)IeYa1@jgpDB4QG>@6VdG(n`GKA9K7 z^<$tUff3FiSwIscZMR(qg>}QTI{U9+o}9EoptzkUohiCdo{_maqYg&p`Tr@uOch`svay@iV|1rcK(t5D zU~22r{Zk3nq*pNkN!AR_az-z>P|hdP z_1}sQhYWC|byH;Uzw%6;jcM~yIGi2EGBdQ`M`r8+3C=nd4z=HU&g7U(=5=1CDCpdD zaO)dtUeV;zNx8R9ZDmT)MH`sX&bEQ&iRQxMxl^Zix97o~P6k~wvuN4&rJogdNZ;-4 z@89|T*)P}UyMDR6D{}0@_$7TmJ%9G}loJ=Sx0{D&_nUX_Ikvm0D{^Ee@xcBwO%Dey zX4f`OCz_(udOo_E?VtCioO7`IO1XIjzuz@7TX^B>(Tle|gDg1pS{~6C3mw{WK4s+*{l9h0c|Q)bHENb`1RZwDiGye(b~c^EIEgYpW+57nkL%3^X4| z?0#J6U&X8|FRPL^U1Hnr+SnUD()i$D{u1BEYuh(>eSPPBd$;WvdFQS*(|G;Ycj=fKa2p8j21>t5e*%X0+>p7M0hKf5pV&gOTYjeat8@{eza54VVc zeY)=dqWOgP^DRTO<_{jfa=xJJ2eiZ5?|t;`dCcV}JYTi+qLnQxa$8z@SM^m%*RCC{ yGVeOqctqOp>&xbc?!RQ7+;ZqpXn@K{p6og;%p88 diff --git a/station/Resources/Images/Assets.xcassets/icon-webtag-map.imageset/webtag-map@2x.png b/station/Resources/Images/Assets.xcassets/icon-webtag-map.imageset/webtag-map@2x.png deleted file mode 100644 index 942e74577f7037250fe1fc4a2ac997630393a01a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2168 zcmbVO3sBQ$951K{C_0}gZkh!+-Jngf_cC{1zAxYR`~Ls`@Bg~2 z)W=Nq^7QePNF-j`Xic0jPY{Q@oA54tQE3$>4<>pxCy|Ww7l(^B&aX`(=?74TL_SeB z10!gw3^&rLq|9Mu1hhmlDcr%}L^{a>sic{*sle7_RUkkaRbWD}4%RVhGL4GPX33e^ zF$N+#oj{FXco;Crfe8YvB##3QtHs7)4i(rb7ZcXvHUt8l5I$W6Mu-Z5M4cW`(<})D z%al?A2?_>6P#L0B1fggkAcv7q2o8l1g%nX@K`)# znl;e0r6*AO9+LsJS_}*dOwi#3WfOV4*XtIk!Ff^ziU=u;3UM>Qs1P>{Q3Sxj7z}qo zb+nN(W%Yt0uoMn8AR!nm$KY3?Lf#m09{*Rck-$teYsCfDlodCV5MwigfYXk5$4NYWt`mJ(Y>-zKxfWiI3d=83M9lNAdO)6Huc6H=n`vBBL$)VkQZGr zjyCajoFya7g17!#@<9RvNG#nhGSFXncAoVr^B%a+JH(~4X$c?Bwny58UdIYeEy$2{ zTq1FOq18kf5|_8E-@4!dJn*BcCdFH$5)%_gr7-xdl$$BHZjQYbc4jQjR4{PGy%_)u zS5&|jZ_PDJO-y6(v4G0(f_Kh6_pL2?xbfLD`?|dRhj|AFB@^E~9{S)#QfhJQ*~`O@ zA31vt+`rBKz_UT}>B;6iw@{ZNwsL>Lzm``KYDOyT}EkGUGXH>6?wM)TXnYw#B&!6w*t#0gDO{6 zwLL*c8iw82cXdrQotPkNuEp7XfJK$~!t63UC)AYnOTXga%6=PFlq|Zhb=lBGcFI$!0=y^E)cOds- z!yaX7YtjRBC+|r3g$vuBKG}3}Ztm3FRp~{Wg1k5HzUOn;<5Z4$@vvm5Ikl{*eyBMh zXWF$QpAU9~oQSX0XUG zR-Zu`DLRAtH=>8P|3LxcTDg2!$1mEV)eftmjgc!D8bc2GMKrC*)e}%6K~vcVoQPb( znCb6eqemqM0y9zu1x0Dz25R10lL3ju5f~8=Ajfc0=im|e&M88Q83{4yK(JvE6E_7c zV&aA(f>|&hh2b|)Ii)7ka^Ha>FdG&skPsC97bufAYRriJSFjpK(lt%rj7Fq=wm`6Qkzo1{n_plcXBuzycneN-#JcA7}GYIRdtbE99`#2q6N8s6%*&kWn-kHdIRC*^WGT zdtUv2o=-54OdVpHUoFQ`osI-TV@R3_ZSGM0BoWJpW*QP0%o!BJ9kn0^aYqsmYH($p-@2{N9>^(t@&}&EcA5pdZocr^7NBwxHXU-FH*UT-a(mPan=LSZ zZXOcA`c2Uui^lF3df1%@ii{_uQs>1vOYRoO0hAj!Z&|3_a)df z;RDYaAFE}IDpNjoK0E$9s_@7s^%cfHX^(%=x-wt>jdSme>uWNBow4Nu=K?rRy?}SC z+eEBm)!r@UsXKcV7an+kH=WvjJ7{6ThInhu;{E40N!8h@Moa(UZ;y{JyWxJt<52Ol zzH;@Iv8^Y!ocXExcC0cgXhBUTD`81-f(w$iyQIw0z;EH#&+<2iJpU>?Wj)+0-+yyv zg;nBQx2xoNe88tuRaHHu_laYd^l4RgGs;Iio6|){W*+s@WiAD5x{gB$S0lb@o8P2T z+G}E!<@8Q9S-hGT6j72{blqd$S}&u4w@viW-}M&2S$MUzdgjsJyB_EbJkMDsbc(Y~ zY_RdI9)93~yrRdm|EP+{TIap1CE|oWbfM`<-=(SAyKUAHvD4(0cTU;u_Tu>`ItpU* zmb8cbz_(wr{Oz9Arh5J5wul)@f%i{$&K`^DKDFa&TIRz&#|!iB?cP*7;ozhAJTK^c z(~-sLxNnVMAO{*#>Rpc4;{}fqU2Ls>jQO_uMAxBdpO)7qwt7AgsLJyj{cg|Qaj|J% z?aOt<+~xBA@lW;U@XgiNeOlZ`U{^xEn`R5mJ}_-bAW7a>&$jGo2RHWL?>jh+{o?bO zDUGqSG6LBPs*%5FGQO``>IsA`y6g2)Q(d(;`S^r8tuf0|oLy7r-ktiHeVkwZ*Hw{$ zWM$t-%cA;6Nl!+x4p=*Bu4$I#=gV97mmd54=2xms&C%4_l>C*F@@1_t2f_0GefGBe z?1m0*(8XFsO`;nyX^qFZtl9xWGP&g3)#+7H8*X>)K5Fnc`#ro|T)^Mhq5W8tw1%)$LiK zUSYvhk;U`y=!o;SuakL|n+ujq>G1intl!hzS?}j@a^2zWd67!W+ZLMs=jit9r=v`y zUbZyk&M4P9(44oetMSZ=@%Lut6!&)G$8LOlc~|mASFbkP>Bv6}^ zt_|PTlkr(w_}Z~?C113(Z@p7Ls{h5VweO$n_Pe|4`MSMM4N0ectDRq5j4Zw~8R#03 nu>bzG{=D4&NBz?W+MZ6VY3}X&A-pNh@y8~MjF%pqld|UT=o;pO diff --git a/station/Resources/Plists/DevInfo.plist b/station/Resources/Plists/DevInfo.plist index 58b39fda6..6b2d8142c 100644 --- a/station/Resources/Plists/DevInfo.plist +++ b/station/Resources/Plists/DevInfo.plist @@ -4,7 +4,6 @@ BGTaskSchedulerPermittedIdentifiers - com.ruuvi.station.BackgroundTaskServiceiOS13.webTagRefresh com.ruuvi.station.BackgroundProcessServiceiOS13.dataPruning CFBundleDevelopmentRegion diff --git a/station/Resources/Plists/Info.plist b/station/Resources/Plists/Info.plist index 46055a497..d46075408 100644 --- a/station/Resources/Plists/Info.plist +++ b/station/Resources/Plists/Info.plist @@ -4,7 +4,6 @@ BGTaskSchedulerPermittedIdentifiers - com.ruuvi.station.BackgroundTaskServiceiOS13.webTagRefresh com.ruuvi.station.BackgroundProcessServiceiOS13.dataPruning CFBundleDevelopmentRegion diff --git a/station/Resources/Plists/MacInfo.plist b/station/Resources/Plists/MacInfo.plist index 9d584bb65..09b80806d 100644 --- a/station/Resources/Plists/MacInfo.plist +++ b/station/Resources/Plists/MacInfo.plist @@ -4,7 +4,6 @@ BGTaskSchedulerPermittedIdentifiers - com.ruuvi.station.BackgroundTaskServiceiOS13.webTagRefresh com.ruuvi.station.BackgroundProcessServiceiOS13.dataPruning CFBundleDevelopmentRegion From 2237a64d3416439cdc2b5b8b804ff41ced765b0a Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Fri, 1 Dec 2023 23:39:07 +0200 Subject: [PATCH 19/84] Fill the iOS device model mapping PLIST (#1742) * Fill the iOS device model mapping PLIST Fills missing models in device model mapping plist * use old names --- .../Plists/iOSDeviceModelMapping.plist | 170 +++++++++++------- 1 file changed, 107 insertions(+), 63 deletions(-) diff --git a/station/Resources/Plists/iOSDeviceModelMapping.plist b/station/Resources/Plists/iOSDeviceModelMapping.plist index 62cba5a2a..bf43bdef7 100644 --- a/station/Resources/Plists/iOSDeviceModelMapping.plist +++ b/station/Resources/Plists/iOSDeviceModelMapping.plist @@ -48,10 +48,10 @@ iPhone 5S iPhone6,2 iPhone 5S - iPhone7,2 - iPhone 6 iPhone7,1 iPhone 6 Plus + iPhone7,2 + iPhone 6 iPhone8,1 iPhone 6S iPhone8,2 @@ -68,14 +68,14 @@ iPhone 7 Plus iPhone10,1 iPhone 8 - iPhone10,4 - iPhone 8 iPhone10,2 iPhone 8 Plus - iPhone10,5 - iPhone 8 Plus iPhone10,3 iPhone X + iPhone10,4 + iPhone 8 + iPhone10,5 + iPhone 8 Plus iPhone10,6 iPhone X iPhone11,2 @@ -94,8 +94,6 @@ iPhone 11 Pro Max iPhone12,8 iPhone SE 2nd Gen - iPhone14,6 - iPhone SE 3rd Gen iPhone13,1 iPhone 12 Mini iPhone13,2 @@ -104,22 +102,32 @@ iPhone 12 Pro iPhone13,4 iPhone 12 Pro Max - iPhone14,4 - iPhone 13 mini - iPhone14,5 - iPhone 13 - iPhone14,2 - iPhone 13 Pro - iPhone14,3 - iPhone 13 Pro Max - iPhone14,7 - iPhone 14 - iPhone14,8 - iPhone 14 Plus - iPhone15,2 - iPhone 14 Pro - iPhone15,3 - iPhone 14 Pro Max + iPhone14,2 + iPhone 13 Pro + iPhone14,3 + iPhone 13 Pro Max + iPhone14,4 + iPhone 13 mini + iPhone14,5 + iPhone 13 + iPhone14,6 + iPhone SE 3rd Gen + iPhone14,7 + iPhone 14 + iPhone14,8 + iPhone 14 Plus + iPhone15,2 + iPhone 14 Pro + iPhone15,3 + iPhone 14 Pro Max + iPhone15,4 + iPhone 15 + iPhone15,5 + iPhone 15 Plus + iPhone16,1 + iPhone 15 Pro + iPhone16,2 + iPhone 15 Pro Max iPad1,1 iPad iPad1,2 @@ -138,48 +146,24 @@ iPad 3rd Gen iPad3,3 iPad 3rd Gen + iPad2,5 + iPad Mini 1st Gen + iPad2,6 + iPad Mini 1st Gen + iPad2,7 + iPad Mini 1st Gen iPad3,4 iPad 4th Gen iPad3,5 iPad 4th Gen iPad3,6 iPad 4th Gen - iPad6,11 - iPad 5th Gen - iPad6,12 - iPad 5th Gen - iPad7,5 - iPad 6th Gen - iPad7,6 - iPad 6th Gen - iPad7,11 - iPad 7th Gen - iPad7,12 - iPad 7th Gen - iPad11,6 - iPad 8th Gen - iPad11,7 - iPad 8th Gen - iPad12,1 - iPad 7th Gen - iPad12,2 - iPad 9th Gen - iPad13,18 - iPad 10th Gen - iPad13,19 - iPad 10th Gen iPad4,1 iPad Air iPad4,2 iPad Air iPad4,3 iPad Air - iPad2,5 - iPad Mini 1st Gen - iPad2,6 - iPad Mini 1st Gen - iPad2,7 - iPad Mini 1st Gen iPad4,4 iPad Mini 2nd Gen iPad4,5 @@ -252,10 +236,26 @@ iPad Pro 12.9 inch 4th Gen (WiFi) iPad8,12 iPad Pro 12.9 inch 4th Gen (WiFi+Cellular) + iPad11,1 + iPad mini 5th Gen (WiFi) + iPad11,2 + iPad mini 5th Gen + iPad11,3 + iPad Air 3rd Gen (WiFi) + iPad11,4 + iPad Air 3rd Gen iPad11,6 iPad 8th Gen (WiFi) iPad11,7 iPad 8th Gen (WiFi+Cellular) + iPad12,1 + iPad 7th Gen + iPad12,2 + iPad 9th Gen + iPad14,1 + iPad mini 6th Gen (WiFi) + iPad14,2 + iPad mini 6th Gen (WiFi+Cellular) iPad13,1 iPad air 4th Gen (WiFi) iPad13,2 @@ -276,14 +276,22 @@ iPad Pro 12.9 inch 5th Gen iPad13,11 iPad Pro 12.9 inch 5th Gen - iPad11,1 - iPad mini 5th Gen (WiFi) - iPad11,2 - iPad mini 5th Gen - iPad11,3 - iPad Air 3rd Gen (WiFi) - iPad11,4 - iPad Air 3rd Gen + iPad13,16 + iPad Air 5th Gen (WiFi) + iPad13,17 + iPad Air 5th Gen (WiFi+Cellular) + iPad13,18 + iPad 10th Gen + iPad13,19 + iPad 10th Gen + iPad14,3 + iPad Pro 11 inch 4th Gen + iPad14,4 + iPad Pro 11 inch 4th Gen + iPad14,5 + iPad Pro 12.9 inch 6th Gen + iPad14,6 + iPad Pro 12.9 inch 6th Gen Watch1,1 Apple Watch 38mm case Watch1,2 @@ -336,5 +344,41 @@ Apple Watch Series 6 40mm case (GPS+Cellular) Watch6,4 Apple Watch Series 6 44mm case (GPS+Cellular) + Watch6,6 + Apple Watch Series 7 41mm case (GPS) + Watch6,7 + Apple Watch Series 7 45mm case (GPS) + Watch6,8 + Apple Watch Series 7 41mm case (GPS+Cellular) + Watch6,9 + Apple Watch Series 7 45mm case (GPS+Cellular) + Watch6,10 + Apple Watch SE 40mm case (GPS) + Watch6,11 + Apple Watch SE 44mm case (GPS) + Watch6,12 + Apple Watch SE 40mm case (GPS+Cellular) + Watch6,13 + Apple Watch SE 44mm case (GPS+Cellular) + Watch6,14 + Apple Watch Series 8 41mm case (GPS) + Watch6,15 + Apple Watch Series 8 45mm case (GPS) + Watch6,16 + Apple Watch Series 8 41mm case (GPS+Cellular) + Watch6,17 + Apple Watch Series 8 45mm case (GPS+Cellular) + Watch6,18 + Apple Watch Ultra + Watch7,1 + Apple Watch Series 9 41mm case (GPS) + Watch7,2 + Apple Watch Series 9 45mm case (GPS) + Watch7,3 + Apple Watch Series 9 41mm case (GPS+Cellular) + Watch7,4 + Apple Watch Series 9 45mm case (GPS+Cellular) + Watch7,5 + Apple Watch Ultra 2 -
+ \ No newline at end of file From c4d5040c15bfb7761df340cf8987e60c833c90fc Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Fri, 1 Dec 2023 23:39:26 +0200 Subject: [PATCH 20/84] Remove outdated files (#1743) Removes files not necessary for the repo --- .gitmodules | 3 - Podfile.patch | 63 ------------------ Rambafile | 35 ---------- Templates/swifty_vm_viper | 1 - station/Resources/Plists/MacInfo.plist | 89 -------------------------- 5 files changed, 191 deletions(-) delete mode 100644 Podfile.patch delete mode 100644 Rambafile delete mode 160000 Templates/swifty_vm_viper delete mode 100644 station/Resources/Plists/MacInfo.plist diff --git a/.gitmodules b/.gitmodules index 465a3cc83..636ef8862 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "station.localization"] path = station.localization url = git@github.com:ruuvi/station.localization.git -[submodule "Templates/swifty_vm_viper"] - path = Templates/swifty_vm_viper - url = git@github.com:viikufa/swifty_vm_viper.git diff --git a/Podfile.patch b/Podfile.patch deleted file mode 100644 index bae22ed69..000000000 --- a/Podfile.patch +++ /dev/null @@ -1,63 +0,0 @@ -diff --git a/Podfile b/Podfile -index e278ef7e..591a4137 100644 ---- a/Podfile -+++ b/Podfile -@@ -5,6 +5,13 @@ inhibit_all_warnings! - - install! 'cocoapods', :disable_input_output_paths => true - -+def ruuvi_ontology -+ pod 'RuuviOntology', :path => 'Packages/RuuviOntology/RuuviOntology.podspec' -+ pod 'RuuviOntology/Contract', :path => 'Packages/RuuviOntology/RuuviOntology.podspec' -+ pod 'RuuviOntology/SQLite', :path => 'Packages/RuuviOntology/RuuviOntology.podspec' -+ pod 'RuuviOntology/Realm', :path => 'Packages/RuuviOntology/RuuviOntology.podspec' -+end -+ - def shared_pods - pod 'BTKit', '~> 0.4.1' - pod 'Firebase' -@@ -34,7 +41,6 @@ def shared_pods - # packages - pod 'RuuviAnalytics', :path => 'Packages/RuuviAnalytics/RuuviAnalytics.podspec', :testspecs => ['Tests'] - pod 'RuuviAnalytics/Impl', :path => 'Packages/RuuviAnalytics/RuuviAnalytics.podspec' -- pod 'RuuviOntology', :path => 'Packages/RuuviOntology/RuuviOntology.podspec' - pod 'RuuviContext', :path => 'Packages/RuuviContext/RuuviContext.podspec' - pod 'RuuviCore', :path => 'Packages/RuuviCore/RuuviCore.podspec', :testspecs => ['Tests'] - pod 'RuuviCore/Image', :path => 'Packages/RuuviCore/RuuviCore.podspec' -@@ -101,7 +107,6 @@ end - - def widget_pods - pod 'Swinject' -- pod 'RuuviOntology', :path => 'Packages/RuuviOntology/RuuviOntology.podspec' - pod 'BTKit', '~> 0.4.1' - pod 'FutureX' - pod 'GRDB.swift', '~> 4.14.0' -@@ -118,23 +123,28 @@ def widget_pods - end - - target 'station' do -+ ruuvi_ontology - shared_pods - end - - target 'station_dev' do -+ ruuvi_ontology - shared_pods - pod 'FLEX', :configurations => ['Debug'] - end - - target 'station_widgets' do -+ ruuvi_ontology - widget_pods - end - - target 'station_intents' do -+ ruuvi_ontology - widget_pods - end - - target 'stationTests' do -+ ruuvi_ontology - shared_pods - pod 'Nimble' - pod 'Quick' diff --git a/Rambafile b/Rambafile deleted file mode 100644 index 43df0861e..000000000 --- a/Rambafile +++ /dev/null @@ -1,35 +0,0 @@ -### Headers settings -company: Ruuvi Innovations Oy. BSD-3-Clause. - -### Xcode project settings -project_name: com.ruuvi.station.ios -xcodeproj_path: station.xcodeproj - -### Code generation settings section -# The main project target name -project_target: station_dev - -# The file path for new modules -project_file_path: station/Classes/Presentation/Modules - -# The Xcode group path to new modules -project_group_path: station/Classes/Presentation/Modules - -### Tests generation settings section -# The tests target name -test_target: station - -# The file path for new tests -test_file_path: stationTests - -# The Xcode group path to new tests -test_group_path: stationTests - -### Dependencies settings section -podfile_path: Podfile - -### Templates -templates: -- {name: swifty_vm_viper, git: 'https://github.com/viikufa/swifty_vm_viper.git'} -#- {name: remote_template_name, git: 'https://github.com/igrekde/remote_template'} -#- {name: swifty_viper} diff --git a/Templates/swifty_vm_viper b/Templates/swifty_vm_viper deleted file mode 160000 index 1e4c0e148..000000000 --- a/Templates/swifty_vm_viper +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1e4c0e14858405c7c65e9b8b8fdf9f7a1e5ca89d diff --git a/station/Resources/Plists/MacInfo.plist b/station/Resources/Plists/MacInfo.plist deleted file mode 100644 index 09b80806d..000000000 --- a/station/Resources/Plists/MacInfo.plist +++ /dev/null @@ -1,89 +0,0 @@ - - - - - BGTaskSchedulerPermittedIdentifiers - - com.ruuvi.station.BackgroundProcessServiceiOS13.dataPruning - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Ruuvi Station - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - LSApplicationCategoryType - public.app-category.weather - LSRequiresIPhoneOS - - NSBluetoothAlwaysUsageDescription - The app uses Bluetooth LE to read data from RuuviTag sensors. - NSBluetoothPeripheralUsageDescription - The app uses Bluetooth LE to read data from RuuviTag sensors. - NSCameraUsageDescription - Ruuvi Station needs to access your camera in order to be able to capture photos and use them as tag background. - NSLocationAlwaysAndWhenInUseUsageDescription - Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. - NSLocationAlwaysUsageDescription - Ruuvi Station needs to access your location while being in background in order to pull data for Virtual Sensors for your current location and display alerts. - NSLocationUsageDescription - Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. - NSLocationWhenInUseUsageDescription - Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. - NSPhotoLibraryUsageDescription - Ruuvi Station needs to access your camera roll to enable selecting the background for the tag. - UIAppFonts - - Oswald-Bold.ttf - Oswald-ExtraLight.ttf - Muli-Regular.ttf - Muli-Bold.ttf - Montserrat-Bold.ttf - Montserrat-Regular.ttf - - UIBackgroundModes - - bluetooth-central - fetch - processing - remote-notification - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UIStatusBarStyle - UIStatusBarStyleLightContent - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - - From 710490f37e1aed31187b789ab3649a8d7a1cb291 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Fri, 1 Dec 2023 23:39:52 +0200 Subject: [PATCH 21/84] Use [framworks] xcodeproj to build the app (#1737) * Use [framworks] xcodeproj to build the app Implements workflow for firebase distribution of the app built from frameworks.xcodeproj use test trigger make project try to copy provisioning profiles xcode destination try station uuid auto signing build configs * run on macos 13 * use xcode 15 * remove Beta build configuration * use date as build number * use different key for cache * remove trigger on push to branch and uncomment uploading logic --- .github/workflows/firebase_frameworks.yml | 102 ++++++++++++++++++++++ intents_frameworks.yml | 10 +++ intents_spm.yml | 10 +++ pnservice.yml | 10 +++ project_frameworks.yml | 16 +++- project_spm.yml | 16 +++- widget_frameworks.yml | 10 +++ widget_spm.yml | 10 +++ 8 files changed, 180 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/firebase_frameworks.yml diff --git a/.github/workflows/firebase_frameworks.yml b/.github/workflows/firebase_frameworks.yml new file mode 100644 index 000000000..d9f47182b --- /dev/null +++ b/.github/workflows/firebase_frameworks.yml @@ -0,0 +1,102 @@ +name: Deploy to Firebase [frameworks] + +on: + workflow_dispatch: + +jobs: + build: + runs-on: macos-13 + + steps: + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '15' + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup SSH + uses: webfactory/ssh-agent@v0.8.0 + with: + ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + + - name: Remove existing localisation directory + run: rm -rf ${{ github.workspace }}/station.localization + + - name: Clone localisation submodule + run: git clone -b master https://github.com/ruuvi/station.localization.git ${{ github.workspace }}/station.localization + + - name: Install the Apple certificate and provisioning profiles + env: + BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} + P12_PASSWORD: ${{ secrets.P12_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + run: | + CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 + KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db + + echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode > $CERTIFICATE_PATH + + security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + security set-keychain-settings -lut 21600 $KEYCHAIN_PATH + security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH + + security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH + security list-keychain -d user -s $KEYCHAIN_PATH + + mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles + echo -n "${{ secrets.MAIN_APP_ADHOC_PROVISION_PROFILE_BASE64 }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/match_AdHoc_com.ruuvi.station.mobileprovision + echo -n "${{ secrets.WIDGETS_APP_ADHOC_PROVISION_PROFILE_BASE64 }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/match_AdHoc_com.ruuvi.station.widgets.mobileprovision + echo -n "${{ secrets.INTENTS_APP_ADHOC_PROVISION_PROFILE_BASE64 }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/match_AdHoc_com.ruuvi.station.intents.mobileprovision + echo -n "${{ secrets.PNSERVICE_APP_ADHOC_PROVISION_PROFILE_BASE64 }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/match_AdHoc_com.ruuvi.station.pnservice.mobileprovision + + - name: Increment build number + run: | + buildNumber=$(date '+%y%m%d%H%M') + /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" ${{ github.workspace }}/station/Resources/Plists/Info.plist + + - name: Make xcodeproj + run: | + make xcodeproj_with_frameworks + + - name: SPM Cache + uses: actions/cache@v2 + with: + path: ~/Library/Developer/Xcode/DerivedData/frameworks*/SourcePackages/ + key: ${{ runner.os }}-frameworks-${{ hashFiles('frameworks.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }} + restore-keys: | + ${{ runner.os }}-frameworks- + + - name: Build app + run: | + xcodebuild -project frameworks.xcodeproj -scheme station -configuration Alpha -archivePath ./Build/Station_Dev.xcarchive archive -allowProvisioningUpdates + - name: Export IPA + env: + EXPORT_PLIST: ${{ secrets.ADHOC_EXPORT_OPTIONS }} + run: | + EXPORT_PLIST_PATH=${{ runner.temp }}/ExportOptions.plist + echo -n "$EXPORT_PLIST" | base64 --decode > $EXPORT_PLIST_PATH + xcodebuild -exportArchive -archivePath ./Build/Station_Dev.xcarchive -exportOptionsPlist $EXPORT_PLIST_PATH -exportPath ${{ runner.temp }}/export + + - name: Distribute to Firebase + run: | + curl -sL https://firebase.tools | bash + firebase appdistribution:distribute ${{ runner.temp }}/export/*.ipa \ + --app ${{ secrets.GOOGLE_APP_ID }} \ + --token ${{ secrets.FIREBASE_REFRESH_TOKEN }} \ + --groups ${{ secrets.ALPHA_TESTERS_GROUP }} \ + --release-notes "Features, enhancements and bug fixes." + + - name: Zip dSYM files + run: | + find ${{ runner.temp }}/export -name '*.dSYM' | xargs -I \{\} zip -r \{\}.zip \{\} + + - name: Upload dSYM to Firebase + run: | + find ${{ runner.temp }}/export -name '*.dSYM.zip' | xargs -I \{\} firebase crashlytics:upload-symbols --app ${{ secrets.GOOGLE_APP_ID }} -g \{\} + + - name: Clean up keychain and provisioning profiles + if: ${{ always() }} + run: | + security delete-keychain $RUNNER_TEMP/app-signing.keychain-db + rm -rf ~/Library/MobileDevice/Provisioning\ Profiles/* diff --git a/intents_frameworks.yml b/intents_frameworks.yml index 689e042be..158d18292 100644 --- a/intents_frameworks.yml +++ b/intents_frameworks.yml @@ -20,6 +20,16 @@ targets: settings: base: CODE_SIGN_ENTITLEMENTS: station_intents.entitlements + configs: + Alpha: + CODE_SIGN_IDENTITY: "iPhone Distribution" + PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.intents" + Debug: + CODE_SIGN_STYLE: Automatic + Release: + EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" + CODE_SIGN_IDENTITY: "iPhone Distribution" + PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.intents" sources: - path: intents - path: ruuvi-widgets diff --git a/intents_spm.yml b/intents_spm.yml index e7db6f0cf..76f3f7a88 100644 --- a/intents_spm.yml +++ b/intents_spm.yml @@ -20,6 +20,16 @@ targets: settings: base: CODE_SIGN_ENTITLEMENTS: station_intents.entitlements + configs: + Alpha: + CODE_SIGN_IDENTITY: "iPhone Distribution" + PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.intents" + Debug: + CODE_SIGN_STYLE: Automatic + Release: + EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" + CODE_SIGN_IDENTITY: "iPhone Distribution" + PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.intents" sources: - path: intents - path: ruuvi-widgets diff --git a/pnservice.yml b/pnservice.yml index cfde6c951..d6db014fc 100644 --- a/pnservice.yml +++ b/pnservice.yml @@ -16,6 +16,16 @@ targets: settings: base: CODE_SIGN_ENTITLEMENTS: pnservice.entitlements + configs: + Alpha: + CODE_SIGN_IDENTITY: "iPhone Distribution" + PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.pnservice" + Debug: + CODE_SIGN_STYLE: Automatic + Release: + EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" + CODE_SIGN_IDENTITY: "iPhone Distribution" + PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.pnservice" sources: - path: pnservice resources: diff --git a/project_frameworks.yml b/project_frameworks.yml index be3f9989f..b3e650b3c 100644 --- a/project_frameworks.yml +++ b/project_frameworks.yml @@ -7,8 +7,8 @@ attributes: settings: base: - CURRENT_PROJECT_VERSION: 420 - MARKETING_VERSION: "2.5.0" + CURRENT_PROJECT_VERSION: 1 + MARKETING_VERSION: "2.5.2" DEVELOPMENT_TEAM: *DEVELOPMENT_TEAM name: *APP_NAME @@ -185,6 +185,11 @@ include: - pnservice.yml - intents_frameworks.yml +configs: + Alpha: debug + Debug: debug + Release: release + targets: station: type: application @@ -276,8 +281,15 @@ targets: SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true CODE_SIGN_ENTITLEMENTS: station/station.entitlements configs: + Alpha: + CODE_SIGN_IDENTITY: "iPhone Distribution" + PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station" + Debug: + CODE_SIGN_STYLE: Automatic Release: EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" + CODE_SIGN_IDENTITY: "iPhone Distribution" + PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station" preBuildScripts: - path: scripts/build/generate_l10n.sh name: Generate L10N diff --git a/project_spm.yml b/project_spm.yml index d441074a9..40feb95d8 100644 --- a/project_spm.yml +++ b/project_spm.yml @@ -7,8 +7,8 @@ attributes: settings: base: - CURRENT_PROJECT_VERSION: 420 - MARKETING_VERSION: "2.5.0" + CURRENT_PROJECT_VERSION: 1 + MARKETING_VERSION: "2.5.2" DEVELOPMENT_TEAM: *DEVELOPMENT_TEAM name: *APP_NAME @@ -110,6 +110,11 @@ include: - pnservice.yml - intents_spm.yml +configs: + Alpha: debug + Debug: debug + Release: release + targets: station: type: application @@ -252,8 +257,15 @@ targets: SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true CODE_SIGN_ENTITLEMENTS: station/station.entitlements configs: + Alpha: + CODE_SIGN_IDENTITY: "iPhone Distribution" + PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station" + Debug: + CODE_SIGN_STYLE: Automatic Release: EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" + CODE_SIGN_IDENTITY: "iPhone Distribution" + PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station" preBuildScripts: - path: scripts/build/generate_l10n.sh name: Generate L10N diff --git a/widget_frameworks.yml b/widget_frameworks.yml index 7c054bba8..fd1f025cd 100644 --- a/widget_frameworks.yml +++ b/widget_frameworks.yml @@ -16,6 +16,16 @@ targets: settings: base: CODE_SIGN_ENTITLEMENTS: ruuvi_widgets.entitlements + configs: + Alpha: + CODE_SIGN_IDENTITY: "iPhone Distribution" + PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.widgets" + Debug: + CODE_SIGN_STYLE: Automatic + Release: + CODE_SIGN_IDENTITY: "iPhone Distribution" + PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.widgets" + EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" sources: - path: ruuvi-widgets resources: diff --git a/widget_spm.yml b/widget_spm.yml index e3d205171..e0ce7d15a 100644 --- a/widget_spm.yml +++ b/widget_spm.yml @@ -16,6 +16,16 @@ targets: settings: base: CODE_SIGN_ENTITLEMENTS: ruuvi_widgets.entitlements + configs: + Alpha: + CODE_SIGN_IDENTITY: "iPhone Distribution" + PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.widgets" + Debug: + CODE_SIGN_STYLE: Automatic + Release: + CODE_SIGN_IDENTITY: "iPhone Distribution" + PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.widgets" + EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" sources: - path: ruuvi-widgets resources: From f977f49be107d43a8be75e467707c824f3668451 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 2 Dec 2023 13:58:28 +0200 Subject: [PATCH 22/84] Add ChangeLog to firebase [frameworks] workflow (#1744) Adds a changelog to Firebase Distribution deploy. --- .github/workflows/firebase_frameworks.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/firebase_frameworks.yml b/.github/workflows/firebase_frameworks.yml index d9f47182b..e39a05eb3 100644 --- a/.github/workflows/firebase_frameworks.yml +++ b/.github/workflows/firebase_frameworks.yml @@ -78,6 +78,10 @@ jobs: echo -n "$EXPORT_PLIST" | base64 --decode > $EXPORT_PLIST_PATH xcodebuild -exportArchive -archivePath ./Build/Station_Dev.xcarchive -exportOptionsPlist $EXPORT_PLIST_PATH -exportPath ${{ runner.temp }}/export + - name: Build Changelog + id: build_changelog + uses: mikepenz/release-changelog-builder-action@v4.1.0 + - name: Distribute to Firebase run: | curl -sL https://firebase.tools | bash @@ -85,7 +89,7 @@ jobs: --app ${{ secrets.GOOGLE_APP_ID }} \ --token ${{ secrets.FIREBASE_REFRESH_TOKEN }} \ --groups ${{ secrets.ALPHA_TESTERS_GROUP }} \ - --release-notes "Features, enhancements and bug fixes." + --release-notes ${{ steps.build_changelog.outputs.changelog }} - name: Zip dSYM files run: | From 7a919875b21fcf2246d54e662d8707f59032334f Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sun, 3 Dec 2023 22:24:15 +0200 Subject: [PATCH 23/84] Feature: upgrade firmware option on NFC scan of df3 tag (#1746) * Feature: upgrade firmware option on NFC scan of df3 tag Implemenbts RuuviFirmware Module and uses it in RuuviDiscover to enable firmware upgrade from add a sensor page * add l10n * green color * remove read fw step * solve presenter deallocated issue --- .../Resources/de.lproj/RuuviDiscover.strings | 1 + .../Resources/en.lproj/RuuviDiscover.strings | 3 + .../Resources/fi.lproj/RuuviDiscover.strings | 1 + .../Resources/fr.lproj/RuuviDiscover.strings | 1 + .../Resources/ru.lproj/RuuviDiscover.strings | 1 + .../Resources/sv.lproj/RuuviDiscover.strings | 1 + .../RuuviDiscover/RuuviDiscoverFactory.swift | 7 +- .../VMP/Presenter/DiscoverPresenter.swift | 19 + .../VMP/View/DiscoverViewInput.swift | 1 + .../VMP/View/DiscoverViewOutput.swift | 1 + .../Table/DiscoverTableViewController.swift | 8 + Modules/RuuviDiscover/target.yml | 1 + Modules/RuuviFirmware/.gitignore | 8 + Modules/RuuviFirmware/Info.plist | 22 + Modules/RuuviFirmware/Package.swift | 23 + Modules/RuuviFirmware/RuuviFirmware.podspec | 38 ++ .../RuuviFirmware}/Common/Feedback.swift | 10 +- .../Common/LargeButtonStyle.swift | 10 +- .../RuuviFirmware}/Common/ProgressBar.swift | 8 +- .../RuuviFirmware/Common/RuuvoBoardView.swift | 33 ++ .../RuuviFirmware/Common/Spinner.swift | 26 ++ .../Extensions/Publishers+System.swift | 3 +- .../URLSession+downloadTaskPublisher.swift | 0 .../RuuviFirmware/Extensions/View+Any.swift | 5 + .../RuuviFirmware/FirmwareInteractor.swift | 187 ++++++++ .../RuuviFirmware/FirmwarePresenter.swift | 51 ++ .../Model/GitHubRelease+URL.swift | 43 ++ .../RuuviFirmware/Model/GitHubRelease.swift | 22 + .../Repository}/FirmwareRepository.swift | 12 +- .../RuuviFirmware/Resources/Muli-Bold.ttf | Bin 0 -> 89796 bytes .../RuuviFirmware/Resources/Muli-Regular.ttf | Bin 0 -> 90300 bytes .../RuuviFirmware.xcassets/Contents.json | 6 + .../RuuviMenuTextColor.colorset/Contents.json | 38 ++ .../RuuviTextColor.colorset/Contents.json | 38 ++ .../RuuviTintColor.colorset/Contents.json | 20 + .../Contents.json | 0 .../ruuvitag-b8-and-older-button-location.png | Bin .../Resources/de.lproj/RuuviFirmware.strings | 20 + .../Resources/en.lproj/RuuviFirmware.strings | 20 + .../Resources/fi.lproj/RuuviFirmware.strings | 20 + .../Resources/fr.lproj/RuuviFirmware.strings | 20 + .../Resources/ru.lproj/RuuviFirmware.strings | 20 + .../Resources/sv.lproj/RuuviFirmware.strings | 20 + .../Sources/RuuviFirmware/RuuviFirmware.swift | 11 + .../RuuviFirmware/RuuviFirmwareBuilder.swift | 37 ++ .../RuuviFirmware/SwiftUI/FirmwareView.swift | 438 ++++++++++++++++++ .../SwiftUI/FirmwareViewModel.swift | 410 ++++++++++++++++ .../RuuviFirmware/Util/RuuviBundleUtils.swift | 88 ++++ .../RuuviFirmware/Util/RuuviColor.swift | 8 + .../RuuviFirmwareTests.swift | 12 + Modules/RuuviFirmware/target.yml | 11 + project_frameworks.yml | 2 + station/Classes/Application/AppAssembly.swift | 4 +- .../Submodules/DFU/Common/Spinner.swift | 21 - .../Submodules/DFU/Extensions/View+Any.swift | 15 - .../DFU/Interactor/DFUInteractor.swift | 1 + .../Submodules/DFU/View/DFUViewModel.swift | 1 + .../DFU/View/SwiftUI/DFUUIView.swift | 29 +- .../RuuviTintColor.colorset/Contents.json | 4 +- 59 files changed, 1778 insertions(+), 82 deletions(-) create mode 100644 Modules/RuuviFirmware/.gitignore create mode 100644 Modules/RuuviFirmware/Info.plist create mode 100644 Modules/RuuviFirmware/Package.swift create mode 100644 Modules/RuuviFirmware/RuuviFirmware.podspec rename {station/Classes/Presentation/Modules/TagSettings/Submodules/DFU => Modules/RuuviFirmware/Sources/RuuviFirmware}/Common/Feedback.swift (57%) rename {station/Classes/Presentation/Modules/TagSettings/Submodules/DFU => Modules/RuuviFirmware/Sources/RuuviFirmware}/Common/LargeButtonStyle.swift (62%) rename {station/Classes/Presentation/Modules/TagSettings/Submodules/DFU => Modules/RuuviFirmware/Sources/RuuviFirmware}/Common/ProgressBar.swift (83%) create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Common/RuuvoBoardView.swift create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Common/Spinner.swift rename {station/Classes/Presentation/Modules/TagSettings/Submodules/DFU => Modules/RuuviFirmware/Sources/RuuviFirmware}/Extensions/Publishers+System.swift (95%) rename {station/Classes/Presentation/Modules/TagSettings/Submodules/DFU => Modules/RuuviFirmware/Sources/RuuviFirmware}/Extensions/URLSession+downloadTaskPublisher.swift (100%) create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/View+Any.swift create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Model/GitHubRelease+URL.swift create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Model/GitHubRelease.swift rename {station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/FirmwareRepository => Modules/RuuviFirmware/Sources/RuuviFirmware/Repository}/FirmwareRepository.swift (85%) create mode 100755 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/Muli-Bold.ttf create mode 100755 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/Muli-Regular.ttf create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/Contents.json create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviMenuTextColor.colorset/Contents.json create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviTextColor.colorset/Contents.json create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviTintColor.colorset/Contents.json rename {station/Resources/Images/Assets.xcassets => Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets}/ruuvitag-b8-and-older-button-location.imageset/Contents.json (100%) rename {station/Resources/Images/Assets.xcassets => Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets}/ruuvitag-b8-and-older-button-location.imageset/ruuvitag-b8-and-older-button-location.png (100%) create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/de.lproj/RuuviFirmware.strings create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/en.lproj/RuuviFirmware.strings create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/fi.lproj/RuuviFirmware.strings create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/fr.lproj/RuuviFirmware.strings create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/ru.lproj/RuuviFirmware.strings create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/sv.lproj/RuuviFirmware.strings create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmware.swift create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmwareBuilder.swift create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift create mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviColor.swift create mode 100644 Modules/RuuviFirmware/Tests/RuuviFirmwareTests/RuuviFirmwareTests.swift create mode 100644 Modules/RuuviFirmware/target.yml delete mode 100644 station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Common/Spinner.swift delete mode 100644 station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Extensions/View+Any.swift diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/de.lproj/RuuviDiscover.strings b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/de.lproj/RuuviDiscover.strings index ecafd1f99..d98b8cfdb 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/de.lproj/RuuviDiscover.strings +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/de.lproj/RuuviDiscover.strings @@ -28,3 +28,4 @@ "add_sensor_nfc_df3_error" = "Dieser Sensor kann aufgrund der alten Firmware nicht mit NFC hinzugefügt werden. Bitte fügen Sie den Sensor über Bluetooth hinzu und aktualisieren Sie die Firmware."; "add_sensor_description" = "Auf dieser Seite werden Ruuvi-Sensoren in der Nähe angezeigt, die der App noch nicht hinzugefügt wurden. Tippen Sie auf einen Sensor, um ihn hinzuzufügen."; "add_sensor_via_nfc" = "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone."; +"upgrade_firmware" = "Firmware Update"; diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/en.lproj/RuuviDiscover.strings b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/en.lproj/RuuviDiscover.strings index c6b4a9904..5e1a9399f 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/en.lproj/RuuviDiscover.strings +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/en.lproj/RuuviDiscover.strings @@ -28,3 +28,6 @@ "add_sensor_nfc_df3_error" = "This tag cannot be added with NFC due to old firmware. Please add the tag with Bluetooth and update firmware."; "add_sensor_description" = "This page shows nearby Ruuvi sensors not yet added to the app. Tap a sensor to add it."; "add_sensor_via_nfc" = "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone."; +"upgrade_firmware" = "Firmware Update"; + + diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/fi.lproj/RuuviDiscover.strings b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/fi.lproj/RuuviDiscover.strings index 9e63aa475..378a06592 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/fi.lproj/RuuviDiscover.strings +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/fi.lproj/RuuviDiscover.strings @@ -28,3 +28,4 @@ "add_sensor_nfc_df3_error" = "Vanha laiteohjelmisto ei salli anturin lisäämistä NFC:llä. Lisää anturi Bluetooth-yhteydellä ja päivitä laiteohjelmisto."; "add_sensor_description" = "Tällä sivulla näet lähelläsi olevat Ruuvi-anturit, joita ei ole vielä lisätty sovellukseen. Lisää listattu anturi napauttamalla."; "add_sensor_via_nfc" = "Voit vaihtoehtoisesti lisätä anturin sovellukseen NFC:llä napauttamalla Lisää NFC:llä painiketta ja koskettamalla sitä."; +"upgrade_firmware" = "Laiteohjelmiston päivitys"; diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/fr.lproj/RuuviDiscover.strings b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/fr.lproj/RuuviDiscover.strings index eaa1e9af4..0365f333a 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/fr.lproj/RuuviDiscover.strings +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/fr.lproj/RuuviDiscover.strings @@ -28,3 +28,4 @@ "add_sensor_nfc_df3_error" = "Ce capteur ne peut pas être ajouté avec NFC en raison d'un ancien firmware. Veuillez ajouter le capteur avec Bluetooth et mettre à jour le firmware."; "add_sensor_description" = "Cette page montre les capteurs Ruuvi à proximité qui n'ont pas encore été ajoutés à l'application. Appuyez sur un capteur pour l'ajouter."; "add_sensor_via_nfc" = "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone."; +"upgrade_firmware" = "Mise à jour du firmware"; diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/ru.lproj/RuuviDiscover.strings b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/ru.lproj/RuuviDiscover.strings index 78c812c9a..dba31af33 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/ru.lproj/RuuviDiscover.strings +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/ru.lproj/RuuviDiscover.strings @@ -28,3 +28,4 @@ "add_sensor_nfc_df3_error" = "This sensor cannot be added with NFC due to old firmware. Please add the sensor with Bluetooth and update firmware."; "add_sensor_description" = "Здесь показаны датчики Ruuvi, которые еще не были добавлены в приложение. Нажмите на сенсор, чтобы добавить его."; "add_sensor_via_nfc" = "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone."; +"upgrade_firmware" = "Обновление Прошивки"; diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/sv.lproj/RuuviDiscover.strings b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/sv.lproj/RuuviDiscover.strings index e17c35df6..779a30301 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/sv.lproj/RuuviDiscover.strings +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/sv.lproj/RuuviDiscover.strings @@ -28,3 +28,4 @@ "add_sensor_nfc_df3_error" = "Denna sensor kan inte läggas till med NFC på grund av gammal firmware. Lägg till sensorn med Bluetooth och uppdatera firmware."; "add_sensor_description" = "Den här sidan visar närliggande Ruuvi-sensorer som ännu inte har lagts till i appen. Tryck på en sensor för att lägga till den."; "add_sensor_via_nfc" = "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone."; +"upgrade_firmware" = "Firmware Uppdatering"; diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscoverFactory.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscoverFactory.swift index ca100e6e8..7f1276e32 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscoverFactory.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscoverFactory.swift @@ -6,6 +6,7 @@ import RuuviLocal import RuuviService import RuuviCore import RuuviPresenters +import RuuviFirmware public struct RuuviDiscoverDependencies { var errorPresenter: ErrorPresenter @@ -15,6 +16,7 @@ public struct RuuviDiscoverDependencies { var foreground: BTForeground var ruuviReactor: RuuviReactor var ruuviOwnershipService: RuuviServiceOwnership + var firmwareBuilder: RuuviFirmwareBuilder public init( errorPresenter: ErrorPresenter, @@ -23,7 +25,8 @@ public struct RuuviDiscoverDependencies { permissionPresenter: PermissionPresenter, foreground: BTForeground, ruuviReactor: RuuviReactor, - ruuviOwnershipService: RuuviServiceOwnership + ruuviOwnershipService: RuuviServiceOwnership, + firmwareBuilder: RuuviFirmwareBuilder ) { self.errorPresenter = errorPresenter self.activityPresenter = activityPresenter @@ -32,6 +35,7 @@ public struct RuuviDiscoverDependencies { self.foreground = foreground self.ruuviReactor = ruuviReactor self.ruuviOwnershipService = ruuviOwnershipService + self.firmwareBuilder = firmwareBuilder } } @@ -47,6 +51,7 @@ public final class RuuviDiscoverFactory { presenter.foreground = dependencies.foreground presenter.ruuviReactor = dependencies.ruuviReactor presenter.ruuviOwnershipService = dependencies.ruuviOwnershipService + presenter.firmwareBuilder = dependencies.firmwareBuilder return presenter } } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift index 1e5d70a25..9932bc2e6 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift @@ -10,6 +10,7 @@ import RuuviLocal import RuuviService import RuuviCore import RuuviPresenters +import RuuviFirmware import CoreBluetooth import CoreNFC @@ -37,6 +38,7 @@ class DiscoverPresenter: NSObject, RuuviDiscover { var permissionPresenter: PermissionPresenter! var ruuviReactor: RuuviReactor! var ruuviOwnershipService: RuuviServiceOwnership! + var firmwareBuilder: RuuviFirmwareBuilder! private weak var view: DiscoverViewInput? private var accessQueue = DispatchQueue( @@ -190,6 +192,7 @@ extension DiscoverPresenter: DiscoverViewOutput { message: message, showAddSensor: false, showGoToSensor: true, + showUpgradeFirmware: false, isDF3: false ) return @@ -208,6 +211,7 @@ extension DiscoverPresenter: DiscoverViewOutput { message: message, showAddSensor: true, showGoToSensor: false, + showUpgradeFirmware: false, isDF3: false ) return @@ -227,6 +231,7 @@ extension DiscoverPresenter: DiscoverViewOutput { message: message, showAddSensor: false, showGoToSensor: false, + showUpgradeFirmware: true, isDF3: nfcSensor?.firmwareVersion == "2.5.9" ) } @@ -252,6 +257,13 @@ extension DiscoverPresenter: DiscoverViewOutput { } } + func viewDidAskToUpgradeFirmware(of sensor: NFCSensor?) { + guard let sensor else { return } + let firmwareModule = firmwareBuilder.build(uuid: sensor.id, currentFirmware: sensor.firmwareVersion) + firmwareModule.output = self + viewController.present(firmwareModule.viewController, animated: true) + } + func viewDidACopyMacAddress(of sensor: NFCSensor?) { UIPasteboard.general.string = sensor?.macId } @@ -261,6 +273,13 @@ extension DiscoverPresenter: DiscoverViewOutput { } } +// MARK: - RuuviFirmwareOutput +extension DiscoverPresenter: RuuviFirmwareOutput { + func ruuviFirmwareSuccessfullyUpgraded(_ ruuviDiscover: RuuviFirmware) { + ruuviDiscover.viewController.dismiss(animated: true) + } +} + // MARK: - Private extension DiscoverPresenter { private func startObservingPersistedRuuviSensors() { diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift index 25208efa7..a858dbc3c 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift @@ -16,6 +16,7 @@ protocol DiscoverViewInput: UIViewController, Localizable { message: String, showAddSensor: Bool, showGoToSensor: Bool, + showUpgradeFirmware: Bool, isDF3: Bool ) } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewOutput.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewOutput.swift index 4b94dfa19..dbf1c0bde 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewOutput.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewOutput.swift @@ -16,4 +16,5 @@ protocol DiscoverViewOutput { func viewDidGoToSensor(with sensor: NFCSensor?) func viewDidACopyMacAddress(of sensor: NFCSensor?) func viewDidACopySecret(of sensor: NFCSensor?) + func viewDidAskToUpgradeFirmware(of sensor: NFCSensor?) } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift index 510ac8f5c..0c8018804 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift @@ -89,6 +89,7 @@ extension DiscoverTableViewController: DiscoverViewInput { message: String, showAddSensor: Bool, showGoToSensor: Bool, + showUpgradeFirmware: Bool, isDF3: Bool ) { let title = "sensor_details".localized(for: Self.self) @@ -140,6 +141,13 @@ extension DiscoverTableViewController: DiscoverViewInput { self?.output.viewDidGoToSensor(with: tag) })) } + + if showUpgradeFirmware { + alertVC.addAction(UIAlertAction(title: "upgrade_firmware".localized(for: Self.self), + style: .default, handler: { [weak self] _ in + self?.output.viewDidAskToUpgradeFirmware(of: tag) + })) + } alertVC.addAction(UIAlertAction(title: "close".localized(for: Self.self), style: .cancel, handler: nil)) present(alertVC, animated: true) diff --git a/Modules/RuuviDiscover/target.yml b/Modules/RuuviDiscover/target.yml index ef4adc1a1..70b917c73 100644 --- a/Modules/RuuviDiscover/target.yml +++ b/Modules/RuuviDiscover/target.yml @@ -13,3 +13,4 @@ targets: - target: RuuviService - target: RuuviPresenters - target: RuuviLocalization + - target: RuuviFirmware diff --git a/Modules/RuuviFirmware/.gitignore b/Modules/RuuviFirmware/.gitignore new file mode 100644 index 000000000..0023a5340 --- /dev/null +++ b/Modules/RuuviFirmware/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +/.build +/Packages +xcuserdata/ +DerivedData/ +.swiftpm/configuration/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/Modules/RuuviFirmware/Info.plist b/Modules/RuuviFirmware/Info.plist new file mode 100644 index 000000000..0f6add7d8 --- /dev/null +++ b/Modules/RuuviFirmware/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + 1 + + diff --git a/Modules/RuuviFirmware/Package.swift b/Modules/RuuviFirmware/Package.swift new file mode 100644 index 000000000..51672539a --- /dev/null +++ b/Modules/RuuviFirmware/Package.swift @@ -0,0 +1,23 @@ +// swift-tools-version: 5.9 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "RuuviFirmware", + products: [ + // Products define the executables and libraries a package produces, making them visible to other packages. + .library( + name: "RuuviFirmware", + targets: ["RuuviFirmware"]), + ], + targets: [ + // Targets are the basic building blocks of a package, defining a module or a test suite. + // Targets can depend on other targets in this package and products from dependencies. + .target( + name: "RuuviFirmware"), + .testTarget( + name: "RuuviFirmwareTests", + dependencies: ["RuuviFirmware"]), + ] +) diff --git a/Modules/RuuviFirmware/RuuviFirmware.podspec b/Modules/RuuviFirmware/RuuviFirmware.podspec new file mode 100644 index 000000000..a6c247f57 --- /dev/null +++ b/Modules/RuuviFirmware/RuuviFirmware.podspec @@ -0,0 +1,38 @@ +Pod::Spec.new do |s| + s.name = 'RuuviDiscover' + s.version = '0.0.2' + s.summary = 'Ruuvi Discover' + s.homepage = 'https://ruuvi.com' + s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } + s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } + s.platform = :ios, '10.0' + s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } + s.frameworks = 'Foundation' + s.requires_arc = true + s.ios.deployment_target = '10.0' + s.swift_version = '5.0' + + s.default_subspecs = 'RuuviDiscover' + + s.subspec 'RuuviDiscover' do |ss| + ss.source_files = 'Sources/RuuviDiscover/**/*.{h,m,swift}', 'Sources/RuuviDiscover/*.{h,m,swift}' + ss.resource_bundles = { + 'RuuviDiscover' => ['Sources/**/Resources/**/*'] + } + + ss.dependency 'BTKit' + ss.dependency 'RuuviContext' + ss.dependency 'RuuviReactor' + ss.dependency 'RuuviLocal' + ss.dependency 'RuuviService' + ss.dependency 'RuuviCore' + ss.dependency 'RuuviLocalization' + ss.dependency 'RuuviPresenters' + end + + s.test_spec 'Tests' do |test_spec| + test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' + end +end + + diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Common/Feedback.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/Feedback.swift similarity index 57% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Common/Feedback.swift rename to Modules/RuuviFirmware/Sources/RuuviFirmware/Common/Feedback.swift index d431a302d..0e0210211 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Common/Feedback.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/Feedback.swift @@ -1,11 +1,13 @@ -import Foundation import Combine -struct Feedback { - let run: (AnyPublisher) -> AnyPublisher +public struct Feedback { + public let run: (AnyPublisher) -> AnyPublisher + public init(run: @escaping (AnyPublisher) -> AnyPublisher) { + self.run = run + } } -extension Feedback { +public extension Feedback { init( effects: @escaping (State) -> Effect ) where Effect.Output == Event, Effect.Failure == Never { diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Common/LargeButtonStyle.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/LargeButtonStyle.swift similarity index 62% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Common/LargeButtonStyle.swift rename to Modules/RuuviFirmware/Sources/RuuviFirmware/Common/LargeButtonStyle.swift index 5ca5e7852..dd588a7ee 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Common/LargeButtonStyle.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/LargeButtonStyle.swift @@ -1,11 +1,17 @@ import SwiftUI -struct LargeButtonStyle: ButtonStyle { +public struct LargeButtonStyle: ButtonStyle { let backgroundColor: Color let foregroundColor: Color let isDisabled: Bool - func makeBody(configuration: Self.Configuration) -> some View { + public init(backgroundColor: Color, foregroundColor: Color, isDisabled: Bool) { + self.backgroundColor = backgroundColor + self.foregroundColor = foregroundColor + self.isDisabled = isDisabled + } + + public func makeBody(configuration: Self.Configuration) -> some View { let currentForegroundColor = isDisabled || configuration.isPressed ? foregroundColor.opacity(0.3) diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Common/ProgressBar.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/ProgressBar.swift similarity index 83% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Common/ProgressBar.swift rename to Modules/RuuviFirmware/Sources/RuuviFirmware/Common/ProgressBar.swift index 76082e654..73d02ad03 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Common/ProgressBar.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/ProgressBar.swift @@ -1,9 +1,13 @@ import SwiftUI -struct ProgressBar: View { +public struct ProgressBar: View { @Binding var value: Double + + public init(value: Binding) { + self._value = value + } - var body: some View { + public var body: some View { GeometryReader { geometry in ZStack(alignment: .leading) { Rectangle() diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/RuuvoBoardView.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/RuuvoBoardView.swift new file mode 100644 index 000000000..b2aaddaf2 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/RuuvoBoardView.swift @@ -0,0 +1,33 @@ +import SwiftUI + +public struct RuuviBoardView: View { + @State private var isPortrait = false + private let boardImageName = "ruuvitag-b8-and-older-button-location" + public init() {} + + public var body: some View { + HStack { + if isPortrait { + Image(boardImageName, bundle: .pod(RuuviFirmwareDummyClass.self)) + .resizable() + .aspectRatio(contentMode: .fit) + } else { + Spacer() + Image(boardImageName, bundle: .pod(RuuviFirmwareDummyClass.self)) + .resizable() + .aspectRatio(contentMode: .fit) + .scaledToFit() + .frame(width: 300, height: 147) + Spacer() + } + } + .padding() + .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in + guard let scene = UIApplication.shared.windows.first?.windowScene else { return } + self.isPortrait = scene.interfaceOrientation.isPortrait + } + } +} + +private class RuuviFirmwareDummyClass { +} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/Spinner.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/Spinner.swift new file mode 100644 index 000000000..c4c70e6b6 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/Spinner.swift @@ -0,0 +1,26 @@ +import SwiftUI +import UIKit + +public struct Spinner: UIViewRepresentable { + public let isAnimating: Bool + public let style: UIActivityIndicatorView.Style + + public init(isAnimating: Bool, style: UIActivityIndicatorView.Style) { + self.isAnimating = isAnimating + self.style = style + } + + public func makeUIView(context: Context) -> UIActivityIndicatorView { + let spinner = UIActivityIndicatorView(style: style) + spinner.hidesWhenStopped = true + return spinner + } + + public func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) { + if isAnimating { + uiView.startAnimating() + } else { + uiView.stopAnimating() + } + } +} diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Extensions/Publishers+System.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/Publishers+System.swift similarity index 95% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Extensions/Publishers+System.swift rename to Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/Publishers+System.swift index 27c14f9b5..45d5a6cb5 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Extensions/Publishers+System.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/Publishers+System.swift @@ -1,7 +1,6 @@ -import Foundation import Combine -extension Publishers { +public extension Publishers { static func system( initial: State, reduce: @escaping (State, Event) -> State, diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Extensions/URLSession+downloadTaskPublisher.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/URLSession+downloadTaskPublisher.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Extensions/URLSession+downloadTaskPublisher.swift rename to Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/URLSession+downloadTaskPublisher.swift diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/View+Any.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/View+Any.swift new file mode 100644 index 000000000..8dc5c4f36 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/View+Any.swift @@ -0,0 +1,5 @@ +import SwiftUI + +public extension View { + func eraseToAnyView() -> AnyView { AnyView(self) } +} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift new file mode 100644 index 000000000..5f767ef98 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift @@ -0,0 +1,187 @@ +import BTKit +import Combine +import Foundation +import RuuviDFU + +struct CurrentRelease { + var version: String +} + +enum FirmwareDownloadResponse { + case progress(Progress) + case response(appUrl: URL, fullUrl: URL) +} + +enum FirmwareError: Error { + case failedToGetFirmwareName + case failedToConstructFirmwareFromFile +} + +final class FirmwareInteractor { + private let background: BTBackground + private let firmwareRepository: FirmwareRepository + private let ruuviDFU: RuuviDFU + + init( + background: BTBackground, + ruuviDFU: RuuviDFU, + firmwareRepository: FirmwareRepository + ) { + self.background = background + self.ruuviDFU = ruuviDFU + self.firmwareRepository = firmwareRepository + } + + func loadLatestGitHubRelease() -> AnyPublisher { + let urlString = "https://api.github.com/repos/ruuvi/ruuvi.firmware.c/releases/latest" + guard let url = URL(string: urlString) else { + return Fail(error: URLError(.badURL)).eraseToAnyPublisher() + } + return + URLSession.shared.dataTaskPublisher(for: url) + .map { $0.data } + .decode(type: GitHubRelease.self, decoder: JSONDecoder()) + .catch { error in Fail(error: error)} + .receive(on: RunLoop.main) + .eraseToAnyPublisher() + } + + func serveCurrentRelease(uuid: String) -> Future { + return Future { [weak self] promise in + guard let self else { return } + self.background.services.gatt.firmwareRevision( + for: self, + uuid: uuid, + options: [.connectionTimeout(15)] + ) { _, result in + switch result { + case .success(let version): + let currentRelease = CurrentRelease(version: version) + promise(.success(currentRelease)) + case .failure(let error): + promise(.failure(error)) + } + } + } + } + + func read(release: GitHubRelease) -> AnyPublisher<(appUrl: URL, fullUrl: URL), Error> { + guard let fullName = release.defaultFullZipName else { + return Fail<(appUrl: URL, fullUrl: URL), Error>( + error: FirmwareError.failedToGetFirmwareName + ).eraseToAnyPublisher() + } + guard let appName = release.defaultAppZipName else { + return Fail<(appUrl: URL, fullUrl: URL), Error>( + error: FirmwareError.failedToGetFirmwareName + ).eraseToAnyPublisher() + } + let app = firmwareRepository.read(name: appName) + let full = firmwareRepository.read(name: fullName) + return app + .combineLatest(full) + .map { app, full in + return (appUrl: app, fullUrl: full) + }.eraseToAnyPublisher() + } + + func download(release: GitHubRelease) -> AnyPublisher { + guard let fullName = release.defaultFullZipName, + let fullUrl = release.defaultFullZipUrl else { + return Fail(error: URLError(.badURL)).eraseToAnyPublisher() + } + guard let appName = release.defaultAppZipName, + let appUrl = release.defaultAppZipUrl else { + return Fail(error: URLError(.badURL)).eraseToAnyPublisher() + } + let progress = Progress(totalUnitCount: 2) + let full = download(url: fullUrl, name: fullName, progress: progress) + let app = download(url: appUrl, name: appName, progress: progress) + return app + .combineLatest(full) + .map({ app, full in + switch (app, full) { + case let (.progress(appProgress), .progress): + return .progress(appProgress) + case let (.progress(appProgress), .response): + return .progress(appProgress) + case let (.response, .progress(fullProgress)): + return .progress(fullProgress) + case let (.response(appUrl), .response(fullUrl)): + return .response(appUrl: appUrl, fullUrl: fullUrl) + } + }).eraseToAnyPublisher() + } + + private func download(url: URL, name: String, progress: Progress) -> AnyPublisher { + return URLSession.shared + .downloadTaskPublisher(for: url, progress: progress) + .catch { error in Fail(error: error) } + .map({ [weak self] response in + guard let sSelf = self else { return response } + switch response { + case .response(let fileUrl): + if let movedUrl = try? sSelf.firmwareRepository.save( + name: name, + fileUrl: fileUrl + ) { + return .response(fileUrl: movedUrl) + } else { + return response + } + case .progress: + return response + } + + }) + .receive(on: RunLoop.main) + .eraseToAnyPublisher() + } + + func listen() -> Future { + return Future { [weak self] promise in + guard let self else { return } + self.ruuviDFU.scan(self) { _, device in + promise(.success(device.uuid)) + } + } + } + + func observeLost(uuid: String) -> Future { + return Future { [weak self] promise in + guard let self else { return } + self.ruuviDFU.lost(self, closure: { _, device in + if device.uuid == uuid { + promise(.success(uuid)) + } + }) + } + } + + func flash( + uuid: String, + latestRelease: GitHubRelease, + currentRelease: CurrentRelease?, + appUrl: URL, + fullUrl: URL + ) -> AnyPublisher { + + let firmwareUrl: URL + if let currentRelease = currentRelease { + let currentMajor = currentRelease.version.drop(while: { !$0.isNumber }).prefix(while: { $0 != "." }) + let latestMajor = latestRelease.version.drop(while: { !$0.isNumber }).prefix(while: { $0 != "." }) + if currentMajor == latestMajor { + firmwareUrl = appUrl + } else { + firmwareUrl = fullUrl + } + } else { + firmwareUrl = fullUrl + } + + guard let firmware = ruuviDFU.firmwareFromUrl(url: firmwareUrl) else { + return Fail(error: FirmwareError.failedToConstructFirmwareFromFile).eraseToAnyPublisher() + } + return ruuviDFU.flashFirmware(uuid: uuid, with: firmware).eraseToAnyPublisher() + } +} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift new file mode 100644 index 000000000..670f11841 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift @@ -0,0 +1,51 @@ +import BTKit +import RuuviDFU +import SwiftUI +import UIKit + +final class FirmwarePresenter: RuuviFirmware { + weak var output: RuuviFirmwareOutput? + var router: AnyObject? + + var viewController: UIViewController { + if let view = self.weakView { + return view + } else { + let viewModel = FirmwareViewModel( + uuid: uuid, + currentFirmware: currentFirmware, + interactor: interactor + ) + viewModel.output = self + let view = UIHostingController(rootView: FirmwareView(viewModel: viewModel)) + self.weakView = view + return view + } + } + private weak var weakView: UIViewController? + private let interactor: FirmwareInteractor + private let uuid: String + private let currentFirmware: String? + + init( + uuid: String, + currentFirmware: String?, + background: BTBackground, + ruuviDFU: RuuviDFU, + firmwareRepository: FirmwareRepository + ) { + self.uuid = uuid + self.currentFirmware = currentFirmware + self.interactor = FirmwareInteractor( + background: background, + ruuviDFU: ruuviDFU, + firmwareRepository: firmwareRepository + ) + } +} + +extension FirmwarePresenter: FirmwareViewModelOutput { + func firmwareUpgradeDidFinishSuccessfully() { + output?.ruuviFirmwareSuccessfullyUpgraded(self) + } +} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Model/GitHubRelease+URL.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Model/GitHubRelease+URL.swift new file mode 100644 index 000000000..379dd8c83 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Model/GitHubRelease+URL.swift @@ -0,0 +1,43 @@ +import Foundation + +extension GitHubRelease { + var defaultFullZipName: String? { + return defaultFullZipAsset?.name + } + + var defaultFullZipUrl: URL? { + if let downloadUrlString = defaultFullZipAsset?.downloadUrlString { + return URL(string: downloadUrlString) + } else { + return nil + } + } + + var defaultAppZipName: String? { + return defaultAppZipAsset?.name + } + + var defaultAppZipUrl: URL? { + if let downloadUrlString = defaultAppZipAsset?.downloadUrlString { + return URL(string: downloadUrlString) + } else { + return nil + } + } + + private var defaultFullZipAsset: GitHubRelease.Asset? { + return assets.first(where: { + $0.name.hasSuffix("zip") + && $0.name.contains("default") + && !$0.name.contains("app") + }) + } + + private var defaultAppZipAsset: GitHubRelease.Asset? { + return assets.first(where: { + $0.name.hasSuffix("zip") + && $0.name.contains("default") + && $0.name.contains("app") + }) + } +} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Model/GitHubRelease.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Model/GitHubRelease.swift new file mode 100644 index 000000000..44ae0b56d --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Model/GitHubRelease.swift @@ -0,0 +1,22 @@ +import Foundation + +struct GitHubRelease: Codable { + struct Asset: Codable { + var name: String + var downloadUrlString: String + + enum CodingKeys: String, CodingKey { + case name + case downloadUrlString = "browser_download_url" + } + } + + var version: String + var assets: [Asset] + + enum CodingKeys: String, CodingKey { + case version = "tag_name" + case assets = "assets" + } +} + diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/FirmwareRepository/FirmwareRepository.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Repository/FirmwareRepository.swift similarity index 85% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/FirmwareRepository/FirmwareRepository.swift rename to Modules/RuuviFirmware/Sources/RuuviFirmware/Repository/FirmwareRepository.swift index 8dcfcb8ff..633d74d7b 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/FirmwareRepository/FirmwareRepository.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Repository/FirmwareRepository.swift @@ -1,21 +1,23 @@ import Foundation import Combine -enum FirmwareRepositoryError: Error { +public enum FirmwareRepositoryError: Error { case failedToGetDocumentsDirectory case fileNotFound } -protocol FirmwareRepository { +public protocol FirmwareRepository { func read(name: String) -> Future func save(name: String, fileUrl: URL) throws -> URL } -final class FirmwareRepositoryImpl: FirmwareRepository { +public final class FirmwareRepositoryImpl: FirmwareRepository { private let fwDir = "fw" private var isFwDirCreated = false - func read(name: String) -> Future { + public init() {} + + public func read(name: String) -> Future { return Future { [weak self] promise in DispatchQueue.global(qos: .userInitiated).async { [weak self] in do { @@ -32,7 +34,7 @@ final class FirmwareRepositoryImpl: FirmwareRepository { } } - func save(name: String, fileUrl: URL) throws -> URL { + public func save(name: String, fileUrl: URL) throws -> URL { let dstUrl = try self.getFirmwareDirectory().appendingPathComponent(name) if FileManager.default.fileExists(atPath: dstUrl.path) { try FileManager.default.removeItem(at: dstUrl) diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/Muli-Bold.ttf b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/Muli-Bold.ttf new file mode 100755 index 0000000000000000000000000000000000000000..0b9307a84d39e8bb21eb4a3e3df359ba2dbbe7cd GIT binary patch literal 89796 zcmdSCcYIvMxj%g7oGn^)X?L}fb|r1ou6kdsiY2X@WvjbLvTUmu*_M03rrQ`}TEIyz z7-G{&j7bR1gqp@pLLh|P00|+G+*}|%xw*+r4{-77_kCv0S?x+IAo;xiyaHL$>@#y_ zo_Xf!^Bjpul9YjebW(axSNHP#Q_ew&IX9#Ayq@8qHI}DCx8d&>B&pWYvu30tG~Rwt zVrzaPNr}H1T2ooGv*64(B%Q6D7j8assU*F7R+3V(W;Y$!hxT-gzY#wZW_Mk(wWD+M9g@TxlJw@q+qP`loMif2 zy(Ik-V@mbg&|v(E;o}(JiNC$ub|1X>{bLO!`22B6O4_k&@64vunjgF+NpInA{qwsw zUA#|Mm-1WueKX*ldp7OflK+Eci4sfD;Tiw7Z|{MF(ve@jC@~X0&w63s`CIli)(`HL zm;vjRPD_c>_*@aYMt)mTq%_GYSPDpuQj4@g$_Zt4wl+64)Yp|1d7ZhotjzR8 z9g`BPN?C?0!{)KpTJat51Zs`^r{C%cL|W-H4FbOh)ZaB2BXtbcvTMSx{^HKow!7Ne z+NSPmb2^XUx2d**BX>Tn{tD&kP=Uwk^lY4Qx!vxK zPESEcPMgab$SUvO*|@8}tn9pk@`8eLNs_TXN&bWUf@H)h%R@zk zyq=0_|9Axc0j-_pg`L&#&hZt&yEb1%en^9-`6%~B;Gc|X*YK{$Psg+$ioicX?L<*? z&2kve&6e!arckP#8I%Mjvuvi9mEOLyxx?#1`I13mvVm=t6vfh~W3p`Rlk|FN3IpUw z{q~SO0-(nUmS*PR z<8ih|sI#cB)Rmu85KaJ*p0zHkb~k3;#A(&k$gaWQ~ zonp}8T*yYI*U9=>Ob^@v2SlgK>Qfj$A7-<&z?^T+E6nm`q$e12N(0%u{azSi~ZbxV5-_ozbIv47Ye1GP**ZD$b}Z2V${pMY0SV@;(#c}BpD0V%Z6E; zUvOc}Td&Uo-ub+3Hm}F#wz&#znV7iAm>V;3Td>yn;gip`^;~*m(g!Rcx&P9voH%QU z(Br8H9X&4SXzqWo70-c=(j>Fg5^9o|B%7GLC6SpVy<*aDNr1F6PDn!~O8DPrjs?P_J7FdJ-79HTZxH8-DuoKpw=!K1n~N0no}-m}M&Vpg;5bSYfxCEIL*47YxcrrPe zKqAQPoktIZzsef-T;5z4e&N1rI=b#V*WSMTsi)ZF`i>2=@(VL#4QtG0n`>&qQcZoZ z?p5rvR6q9*`KbIooWi2DpV_%7 zOvh|#vZ706vSI)~F@c}>(M6{)9nPgeKLz5(x{OA?LMIW2JcVWE$o=-dv&kO}p0@y; zxYb7-qdLy=@fo{2LZsegQYJe1@uEOC3i)fov!N2%9fG^#8Dyv!d2_X^Z`+(v(} zLI(4Qvjy_{1D!fUlDE98C9Bq)TW(c7Hi`IlJ^1!f?2#hXv%HX_h$R>U#j+`(p2;Q$n7G|6>kXMqr`NDvLqx@n;S@^8 z(957#z+e&*j8nipHo#<(r-62CfL^bg0;kN;X&dm-dSWkPdeUBew4Slg3{}RPs2&GY zHxp;RkTBSxTxh!0<)uDvZg!R>JvGs2&|{5CMv~E5%8Z_1=0Cq_9iLn^d*esnIOU$( zZ-4*VkFP{K?}A5`B6y2AJWIuYdiK@O$CE|NXH1!k6y<{Fk@C|6Vu|vjJDs`}ukI z<2-w$-^jn?=l)S0G=9)pGXD87o}Mh(q-CK-Jt+gsD6=gf6J;U+?8wq*VmQJo!%Rtm zpR??*9s_ z-^?n`efs_Pp4AcglcdT}88D;hWMvDnXIeQV zn@*>PWYg=ddScH>v~YZp)WCwR+J6J=C*jYqm0<`3`Gu_{y|mR8^VL=ISwGC)60@df za!p#ae<7xwG(*w;D7DiZ!5L_d9_gk~T0S%C@~pDKXkmJTrqDrcfC2(4GG;QAdgKI?n;8?7 z-b9lk>!cMzr)>g-GL|H<*~l&$U@;j?v#BgOIcY*lN>aBok+!o><2*S=;3BwWXB<#t zf^jD97KPTyFn0Inv8aS3jVg+(Vh;QRZKp9Kf zXlbEdQ{}-e#KG!-qQMkzMHtkC&qg_s=Zi8mX&D#X>@zkIe99koh&N>|3FMT@l?_N zpw>?Ft+R5S)?N7(Flf@<4pNMYPb*SwgnYV-6(0Tt1 zxQ)!teg@n|n@Jo-q}L~SszDI*yZ zMATgC;znFy1T+C&9d5)e>cK$5$z;vp%i=QOJgWv>5bAJ*y=mHKP#!F+4KDYGAD`!U zmcn9JUT*$bYfDwYqcT6A%aNBl&jHD{5Ey%$Fs5?de5}qS6^DG0^BUp0dSOZc)Fhc` zY6fHWJimqD`(F4F))Iz9n0&K(nx3+@2D zBm-Sr;5LKIQ|)QOdq%ne_9&~(02jwMM4sGu#TDTbM~<-F+{F|Ke+O3D4{?x4r%>qh znW0mJLM_QAqoPmL$x@PD+L8jsEVCpTMx((Hd4dHJ#bUF7U80kjKac)NC6m$WQJ)FT zB2a5};oBH+S(W1PBY6DyI3{oezsXyt&%MWJ7KZ8b@b$vBZ9-pg$+SARG{mv}IoTGG zykF#;Mzo*R+QB)Z;ZIY$z>@S5#!)1A8PQ_tgD*}vL zNfmzKN}pES{{;9VPKg5k32Mg>wz+2MubggrLWxG4Tr*5$S!H)tZoA{qg14#XmGibt zpdbIwL_UVq@T3*+aYfdFAlo}?#PWnzVTNuQCSgTXNN2=~(npdAx-xE6Ct zA&W01If;x~T>@>hkmG=v1nyw?Su@g!qJkjk3}b)@IcPQh3L9LrapTc1eQC!ImK4|* zz~AAW`*&hwa5Ja_WY2+{CmZ35kyx+F%^~n;$c)U)jC4IoH{#~-z!3?V~j(}+^f;Ati)KV&x{V1b9>iSyhs z1CJs?rAKj6Wpddi)8Q*Fo@Ph*bN&)e0j1*H5k=|JFqT_7K+lk7 zVm+8SS9u(LdYJeOen-ag7+ki9{@K%Wvn&8i^%)@4=Dm;P8#Q>aF1SR6Z=bnuU9(-swyYI~S>~%*jzxJ9VN3NqC;B(+Rc{%Mcb~2Ce zjA$n6rkyk*(SA0jovakm{$`}TMgGso_!R%a_{3Kup92TnN)i3uif-ptifDg3 zrk$)5(f-ru_Q-P-@Yd*ckVF>n4@9@?^3`@oWNOE*K7pU4>+2#CnPVaf^1%g=^Rl}h zR7?A*J&Uh34vrs+o&%TBVs1}TyG9pE7pTH7?dJCL6EYmTtk+II!H~v z$EHZ}aR@KEsx{j~PVq5`C=LVW6$>&RN_99KeuvLzcKeFBuiaqG5+oH-ux(s!Lcx=x zh)n*^_QqwcAh6k6*Q~j1yR)#!8YtWKzbduKzg(4Aam#riH9>ZIT~$-2``ohlboYq` zbVu~k1ssa@({g?kJrdoC_Qg09?Hq>@oYR>T?T^Rce4c(EiD{pw_orjpNkbQVMD!6k zH(aBmc373v4*H?ayXh2K{h9mSD;m3E9`)>-O zMC>AW+ryWO$CAmE!!-YKJUDoZW8lbJ91kvbJm^&DC9#=!PZplw)cpMX;{2jgpT)zi zGo6SpYD!+jM^98`^hJ>ndxT<*86|;Wk8|dxp*6S8ZacO5lD$TihSG!3{90kQmV1=- zr+4qYcO1;?V^2HRM~DcX__=R_R&=mv3UE?7LTxq+#A%^7H%F()NeOTlD!o}&nXO1P z$x;v4t7=T!-IHl4mh$3$Twij|>qF_OJF%%p{PrUsDD6di-!6R#s#OpZa$(q%% zkjH6|8aGs_S@0(1Z{Ts+kc5(8Lzz}))aN7mln3*`1f^5gi%?QND2zTaEck>PP0@`B zy54b>p}C3N$Wdxal#NFH6uEXCeF@N2MHJ4e5RKEwa0$jh@~9T?Wtf1+#UeUQfC8-i zR~}-?Lx?3*qxFRQRWG7piSVVX-9RLY=mlqu)(HU*izK-U9JyF_cBaowc5o8H>rC^( z1VA(qf`K6{foTRaIL*kXxN~qKT-LUA`sUTEZ=T-P!hZ1nvwLRN*VnJ#yj%EJi>f!? zw`=Ep8>;+U!&iT-ggsqy-CI>$mi0_=;bm?s6=uwR615Q;xt(xtAt{-X*_&V=tVPoGP^v> z-Ba}}q99%RaMAa!6HG?K$w}-$CZusqs4|^F5W`=k16$N#AM|=oF64ROMxe!xyB-I9Pm!~Pl<{wWO} z+DkP2=@@vDjAERpBk;p9@b?ou&{7Jmb{rhSPc)PTmS9t0jLRSOl8!&*=ER zWnEW{naYYM{e^XvMWyDvjqBRZYe3Y!zp=Wc%xtY5XbMf$0dst&9HS4a7=43dD7M`L zO#crSW|SXfo1lVok8zr?C1W8GA!AV^=xTv88rdV-`3P@t&a3*IIkuWPwpv(6$WaA$ zS)C{AjSeR1KO~k9mNf-V2T!S*8U)b|dvHFMp9nTNADmwVzA%;_8~R@azHs!^e{S^H zOo0y>J+vrOU~vbYDZq0DN{c^2u7K~usY)Kd_M$jx1Kk&wE=_2A_ZwU>k+E)lspkXe zj?U{snmMb{49+W^8$mOQe1^es8-XW}prFzRHF%uYX!z3+c(ikyTF@SE2fyI`Kyd?e z@8R6O3?1{nzOz1TV`?#EiV0pOLenDGIHT9<nWrpwun}S+z(;t!s{%UC`?{BN+Ky_ z^2))+t)YGW-r-P9Q_sNObxmzu%|pXSZaKdH>e@=SWkYw+6Og_lWE!*zc?&F#sH8CrMT!o- zkg(?{WjuKR=q8^(29>9Nd;Iv7H{5`M<;ibu4!?->fp6|0iskd;eD#Z*uRhAYjh~n| zBIPvi0_mbqS{4L?H3i5_270wfc_D|FlvzTps*;%!WTdW#1pXw*OFmyfh9H+CkSpP)GdtJa!k@%acXHzZb_{546T*gaXO>h zPe3v)yApm4eXKdx*JbnE_`ghA7A5mdssH|If{0Y?4tb(G41z6+RrZ0{!~mm`B=m_ z4@BBq_?oo#(~)+pHEKQ&#k5nzSB&!{wS#UjPbCdLfn2FPR02|kCj=*v>5fq>jH|$! zH3#rqDc9pM`?=eXY)kJ;kk&M5A+Rr8fKe*zRj3gHOSm+zR|uw3&Z zEO&qM1V03DU9UU;ley+b)qzmylu!QK{F#WHhgTzbdMp}GJjz6PQeZD@`;2|y7B{t% z9WC%jbinZ^e1#I5`v*8PWo{WHdng-8TX4M-f7Xm9a8e2!ATorz0cLsZSoqoP;b*V; zJ$c>n{bS%J8@W*{F@lH{nABJSc-_4J9)Tt;RzRt`9;Mc7t~D#)J@o$e$DY{!f5*P? z#f?w!5v8z%pTC#Q=YES-^N~4KLPzCP{7udU7Pg<2quc3J3-||O+KIYF`$N>Ot{q9i z@QEXGWir6UvM54^AO{aTFq$@FwMd_4r&!v_uYdg{OAEhu^64*qitPx0iY12s&UUg1 zOd8|<2skCqm>_vVP9tO-3{bKS`O)V_7apG=C1hq&RE&{-AILS!cZAGZa@oV-XIKYfe0)TXi8lo%L=0(B``MUw!i0c-Af}x(GtvH_)(+lJGuGNqvzH0e zi^hLQgQpd8z97bVGNzr*vuJ-Jrk(hOXn&mAK|9DZlb7MSJZ}Tp;5@wonv3ew02Km? z@~wHmNd$o?h!tQi=m=kDm!10?+Y`P?mS$%sWo4FUM({B?u70E9>N!p|3)>%M(d~p2 z0so-Z4xG^3wD!|XP#Gdj@MWvOWH9oa7%_^pFa_nkFE z)lAHQGaQjEB=g((A8-}WAJA9n;~eOz@{|FTA{VHt8V)2yYE>Un9%*ql@{MzLwh$=f zTKG98V&x-oMZ}5h95{x|W=W!p4LLTg(lSmsl%&`!l|YR9+<%#EG}y7Vp>b<_ zaMae-)z#M8-QC9C4I5XLRE91b9K58nvZOz}X>@RSbbM%VElDAc0iHGa2W+EJz6F{C zWlPRSHU*B}1C9m6ZSf%#vP%WT_caJvi;fmypZv(jvyugmN!Lb_no z{jY`GC@S|RIw&KrE~^jrzBAFpfjLR)b5|fRJJPW_RaVjMN0fd6SR3uu9Fak2fRa&WAqF)M2NC1whH?C+b z>>FzMh}}RQR{mV>BXJr?Ncbx&9S(})S2k5P25KD@j*8M^k1IcKKCYkXO@sC#iTiLA zb0W`y#}{=Y&i27Fg(bALmFHylANWLasDiG@S?zY~pX16Ixv90Hyd`Ou{+29zMe7|7 zi#0FLYH|G6he{v$*OC3aL)%ZmP2kk2ntMlS$7wB>YNb}TtnaKF#BTAqa4*J*doiiF zz#t{Sc;nF_auv~MrbVB{X-*OmB09c>2~3xWeb-5|$tD>-0;JX&3_d)alKQ)Pg{H2qqN1*~ zuB9{r#Z=pM#@+%9;J*1|iOu{Wm&z(TDX=Fn+&Ka zAWD1q0eR&L-+;&C-d@+cGe2vhtzo>j@$fcZY0bJZPw~a|7grRF)rF=5;peQs&^J_u zUutn~9H{pHy>E>pcQnt_7_4t9?yYL*b|nNV>qZ@(Uazn1K>xi58k)oRt!VTXmwQV| zC*gZea+8^aP9k@6okW$F;Ne}++dAd9x!!h0#O@N)aAL8ELT?j)Aiq`fGv9E7yqd54{FGREp|a1$+X+Tor#j7{#ai^{LLZ%aetmiC6R ztji98P3D0swsm!dWJ5ctZ5>smYvi}X-z}*OuU$7ZI5IjkJOai6UdMiovtgIUz|NqC zM%^|Paw!WFS+bh+iktb0tEDf593I?Jtn%WHV)aM9qX;ypcN7-}Dq=$k>YbT+a0t+- zFv#Li!r~6x;fy!_2nL(TuG{_Dk~}U z{L|M4m!fX=%M+_MZ~4f$R}x-&>73;wY(Sh-a4MF@H3%6RHWTOML@Y$aY8BjXSG2(@ zI3c${Ij{Qw3pD!k#TMvCHb65L8=&o58ymKE)Q{MZ5YXDz-Q6m`ea;C3wBwS&!3*2V zi&@pVOGk%>Mn?vR)@e3)h5X-=Ln@Nih0Ju1gY`P>xjD8hx_Ow$aM_E5v<2s%;t8|S zi8l5)&BTU7DS3H$MR|UY%jczgl;Y0fd^UxTC*$CP7AZy1Yhdr!Tz^IHfwq=CJ)3H+ zO%It5H}>QmU4JZdVk?#t>g))~<`b(v_3351dzSB7)-ci(=<>N!*Jbw=b>)SVd%L=O zd%Kt8+J(Y3(SPGIiYf)1j|vK~CXjDuq|7UlHg3}SCn#eVn_)2UBrHwM2M)-eVuuwF z4~WYh((d^VlcO_~jtlNoQ2_GBLnQ@}M?z7WC@GIy{V|r zwQbLbLksuq7}l37`J_X%x&&ICNn4!{(G#pqp#%?u0V_;MP*;d*0w$4L$X8ghBp_cU zLC>!;({8u>?1hCCexY^pQUeq`id`onNpypxmQt%UhAJQ17_-)IeBcIwxErhQO@Oh+?}t*NLOnJL8s9!#;$ zu8Eq!LQE8F=2vF7CBu?Sm;z}6r&0H0MFv`sdc)m$`9Iq|RQI7h)qA(|&rc+a&e_l) zNe!(HEzM1VTJ2(KMp_DTp`=7_3UahFMXdt9dFIGIE>+7QBHy&_eQUrb_vc5bMSqhxG75VQI6+U{=0+O_uX<>Ai|9pt)nvHC_&>UF#42}6}*(R6Vtc25O_ zTu&Y}l`ej$K}37d=4p$2(BR(%jcH@Wc+dbjKi2DU#(GCiCcmNjv^U~GV2t(%#E+JM zAj?Eh^4;+v$b+Ur+_VG)$#*fv2@N7j4{qTcfkSX!BfQ$2Q$(GTo8$BZFCh<_I`&=h zA;^QKLfo?i1UzUe#GUaWlothrwdh)+3rE9)p%2xia$Y>HXU)+OM5T}Rm(s3LV zN@dd7P^RFDI+n>~9o-evsoBd#I7n0#2$u{gwG+aUb4QV5DQq5a%p9KKNp7+af`=wb zSr{sOs8Aakv%!s!nK(~yA|U{h*XQ$<`AWfGJtb}~dFMH-(Xb%Yh>T8E*VoSEJj+e6 z<(3z^@*VjZWr2nsk6z=ye`-tA`0q$UYI1gI9^7JWS#8zTE{z#43pO@sXO8?S>fYTE zyLVWLAJXQ1NE<8kE$EKGr;-6_qDh+qC|R)yDVn7WDMp5J=mR0R>Sf8owaF|;mOUpM zkFmHH8o+_rq!kY(t*p49ZP~8nyDnoBx)t61YrTcL8{1n<|7~chkqx1Xh6gX|xaK1B zF!)ZsC*0TE(9n!sCnqM`EdLUcvoTbk0c$XmNd~!>d^emF^7*w^p<=-Yr(NN(NM;Y^ zpJXQBo@=JniW+cg{t2c0*sMO!&-U*>JUzW(q|)iI%7@2GC&OFV?UU8(Hzm&)Ic+-S zGH!SKrEdxUVrDL`#3iGo22$%$R|5hYE=Fq9#Wt#5MpFHhDI?u2B8^Y=@gf~XwaQ)G zUrYoGHA<($cyW9(B`B>P6tT%J zm3V>~*Gxfr+#4k49vppyt_^>VeS^oM5jmD~m8XF*v_m4CWk_vDG!Z_YY#|A{5D6rV zX+2Mip3*Xm^DVv`A>Q)@%i>g_dWQtArLVDfp$m$8*|sI_Wp^E-h$m4Rc89faIuc{v z5<4bh=Pv;wz-duH+_nhfCxGxrjd5xb#1Am@x1%8L)*v)3hW3r+a-Bdt<)*k0EnK1k z0uq%&aEY45I5ljk^OEUt3r+w4g{+5>&@(UVPmlq zau`&EYYwc8OI@+DJ7QM`h-c^A>Rt?U{4Jtx4nfqNB6&j26bKN=4Z3sA7??j!)ilJH zOUAWxC*}GWqHmoC+*#hTLmSqXyDloJlx^pJzJ5AsGw7ejRB2Z{bph?F{HqbCF_E6i z@1N7nSMDh%1T*+1V(y>|-!;k;%8hsY*P%nNoc#H3e+&N9^yZ)Vc|+DBjpk;nF=fg% z{w!?-=aP+B+oD_UOFh9F`vmsxTX+B;NBSDZ*Em4dk{p0sP8tVjoHCUM?bh0Haw?=xN}I*$+Z^GDd{u5Hdh+v0J+XWLq4lI2!ni9#XYYh;kCm5m zznUAy$s)Xq5$?w-0Xp{={IeeIJau~I(gDrKBaJ@kw4;6qm8hY#m@G<~)K4WC4T@fG z>(c>^JSQfUi}PvYdYA#9$`n=8K7{6sId~+u$BYzIkC}W{@Y7)?!e6 zVnuNTeVtf^CT219-0_AOVb3txH5D~{rd*bitvQVeQfAIKq9r1&g&<_yj+VcKr^*DU zwQ_DQ`rW#?AI>SQm5aI&8QFAR>=5PjZ;eg&uw-6l#nG z3TuEunt>>a(NO$IvCp1WSju&(c|?EtWz*J#>K4{0bSo9zoG#poo9iD~JDoOp1IPLa zWq<5x!&--9uy_Bw27`98y#)5|h{Yba8{UzNfF-(_KPa5qHext*L7^b_dcHjr_Y=wv z3uVT+yFVYO6L$lm@9zKPg0{8`2Ko=SwH@ql>x56ftFtWuM%C~|A@T2dYgVrs8CkV@ z4e$Uo}aJs z{m{mW@%#XiJU?Qr*W-*uYa-8&fOumG2=e?0h#xHhL8nnb+#Mf+Yk30VruY!b4Pp$5 zv^?MzC;LwPMA^rw`jn~KYJy`r8B**lo--WnRB!!a~`QM+EL zY{_(or3GiCfz$V8Dra7d%NCh1JV zPiYWQrwb>7djZ8>-=jf9G=6c)Nm~~XM5FQOg?xHMY2*bI)Jz;Bj!!Q#uf;tG3vqgI zimT@wlWG@i3MHi(QQ{eO@%ZHdG70iwV?#63;WE1#o`>kbo=k&YsB}TdJ`aFqxQili zlAxG6U0vo_u>jdRZO(blWcx>~*w1U!@_PKVS3Ec@mHB z6^wTBs;o5{5rHOfBEN;T)vI*|wuJINu+D&%&!OH|f)<4|W9@tUW(UhJtEvWme=wfd`CG%ycX0MkiH{w)6!6U-6sz^~ho@t1dgs2uZ zXB36$fe&(BQ&|GdU6f>slXCWz zs=`z3Da!Ktya*8{Lk*vIV8bqs&J;ro85(#EF2t(=!{`XBawz^VZ!Uzp%UhKo=`Go#|q?97(NhAkb) z%!kdAXj$KkB(K&G61`+YC#6P&Doetz%N@gQW0isM+O>m2CEf)9T1&i)CxhJ;Mr%%fx+)y2{b0 z`xe5^#9M9jxRJTN@2nLhnVJf5hBFVDhS0$Z+>^!+MQh~uqzMe3D_qY-1sYDEYH|p1 zeeNC-H#&Lf3po`ci;r%0nmxP#4c;a|Nu2X^$@W{B(;ez0N;I#oll2Mbr}Vaj|Cj8c z@oK7K0Naw?%enTAD%U>D<$uI$$RR!v1#v4|1QGrtU#pv83}``T$S;Ahn=#@wQ9bY0 zdPejUSm`l6HJ?ZTJ@4RpiUul7vU7b1BO_j(Bw=cQap3pleCh8NII z^&=L^R+?>eu4F{EMm~t-N_r)ax0GW!iw95W!2A7Lj88?pCCg^xHAFlIS9w-#E3bAJ zuf4u*vbBD*udsi(v?|Xt+Sk2rQ$lFnvV6PEo@mbBThUYGDi~>SIxwl7JBgR2%Kb}Ub-U79R$nitZ~sm1gIK0s$r&?NDJPjEiKdvc$Ppym^cdx8%{ z_dFfxN$upRA}aU5%EgE(MMhaEphU_PzYe;kU;3CZJX8Fc875r!rm_@t#c%#^1{a4naOiPzg7CqHWiBpK_};H>z8-1B=_MPkGFxUL+%G@1B8TMbTEyFai;O4e@AF zu;`MxoV{=FWb>@Y+c#QPzWa*R9l_e3-b2@4x&5NhDzu;G#Tl#qGnZQ!zV{KImw*h zqC`l@NZGgepQC^zT}57^E97b_w#6c$j*}VHDX?U-)q<2WD-W~qF=RDAl~34lL=R` z9Q_S|{H z9o-a5!R=>HriZ@_K)e1NU8^De((K{7FCHqd40ce|f3T$N6;>U7DOk5+8Ox!$^SN-1 z=^;#wqA0?THLu5V2=31o5Sl-G0Yuaonh$zu2+cdJ#_hFvaPP2qisl`ThG^kfb2C6- zhcwUa!WC#f!-Y?$tUocf<}*|w)E&8odu}&|62akwb*nrg^OVB?`PWib%$e+9eWl0r{G?;QVHJ0~PWicgvcjaC_{Y)wN`* z*b)}PlS}Sei%ctWGe9iBR&>w!*t&*$SjE^2u%$hn`=bPe=8sy4af${AjB6g&=-tE_ z;FgMj&^)XQ#^Cu70z&h!E`U(ThXn{}-ovW-uvAE@w4&(F0%^)J;6<%n!Mn}!L_z!wb$?mU>kiM$X7oG=E4CugYR@SiqN!=Vz`xu?iIN3*5gu@PLQ%E5z~P|V#LjwiYYaOG zi~Gd$Tp=;Cf46H~A!30Fu0YW|u{%rA0Qn@v?r8o(&Ho+Q9nC753&VtWvv+`lm^v;v zbfS2MR>y@GUt#wh`mfzTK6WE}2XD@NC;TbWh(PGuu)B+^xI}WH;#YBz|8VK^yANNw z=lLtHJhuKAF-q1KegZ%5V4K6Yg5vqeoWngQ&YL{2z^+^faVkCp=Wt?-n>2_BP8W`G zvj!oocVsO59T=*_3Kvy-na>o_s=b&!ej_R}@oFy{esIfm*WLVsZ{2*^Ww$V0`27bS zV7kBEc_)^FH!nDVbIPl6gmRKidYw+{!Q~3%0r6MBq(~{b3TZP6)JK1PeK1IMZ)ErH ziVkgX^z>w_NbvnJes*wFUd<)wN8WJOOoP9^-QTN8;Y!SpM78io! zOpI}p2BG0hjKM7(0dYcuhVj@dj;7Vk^&EraBGsVM|m7Qeu@^_^i`0NgbQc>AYXN6~!Yy~oiDxkUGzBXQr z1)~5sgFXq_0`*0Q%lkTA7g=;($Qwjh*yT}h2)Us0coY~?qH}Xm;mw=tDagaqvTfW4Go>$)7ztLjLt**+lcX|`@6RX_FtNL!J z`@yPQd!w(sIK`Tovoa<9PkGsi>FFt%m`)~Ew*jk50xk6QopoY0k&KTn{+eK99l<7V zBTL(Y-(ct}n7EoQ(nVMPGLvybG})Gnx1VF2M6ba_7ldf8+Zu=C`cVZyu_%?m{v9n+L;-g>q z%9bP7Uw8QMb=MyOPH-;{cNeJ+xF_VK)IBoQa5O~SX(Y&TwZww@a#UZfkiU_OUQJWW zj^7?$dB=^<_if+4oqcEQz{T1w7Gf7|Qf;UTuVqA)KfFi+c7{UvhCD~tA)?mUbTa+$ zuT8Rf{m84dl@=1Is5>qSQE(TSQ7#O-|6E$s7?_+XExD?5=ixx>Bipx6F@5Eruezpp z(pSEHyk%D>65tr!ZIKT`Z3H@;vbS@OMeOwPk=V*pE6tc5ubjrDapwx;ndhCI_xx zRzE#mT6(N|`(f4`U=!;*CU%wiCwozsyLNVabsa5icC>knSC92$pF(_}Qm9&Z3fw}l z-;fs#-pAj>gWI8e+r)-}Cx9DBiS#~hsuo@d-xP>4fcwC%+6+0g<#HrR4$Ow1|H>b? z+;GD*`>${jOC$WX0DttZqI~HRyu$4PlDY zuhyqmUz&4rrlDnb_q8{5A6p-~q`Yi$Y-m)rO*T3@I~y97_cX9?H*M?e+ST&Z{TF_I zeQD8T?=^?Z1L2!jG&lFGXlh!C9jU|4d$A)13DpltZROe7T9JNXHDvPYk7k#Zd6=t? z{W1L2>sd$mcKL?sH(QjRNatBsTmb?qc`=Jzq~ zCw${Fii#YLqS~Swx=K`5h&Q~5qd+@HJSp;~3sF0tmmEUs0A0uCL2)D%&^tZYZwEUO zD88g~uzOi|X#a{8`$OH!9_#9EYU=K4?iv{C=olJ6`tip0mJL-^8(P{oW>`iWo5m_D z$C{ePGQ;&XmCYtob7f8axj!}3RWCD{mQ~l`4y`Qtu;-QYdyc9CdQ?ck+w6&&5edfm z)`NV>qelh#Q1Cp80mSaPw@~bP3|$7JqQiVa6kw$V-Em?$?RHt|)acNdY@29q<3!N5 ze0f6y_Fev7WVf%qyrNzZK=>BgZ`yZgOt!iA*%tN)CiouLpw{4MPO=B^_y6&~o%nm4 zfBruI+YWf~_c{Kz8K3Xx@US;Ao)@2=$Nxs*OZ-jnGt?hO5dDqXENlaPPT9@)+k(%x z@y`K(zq9f8CjPgA4sv9Eq`8#94T?5!%UL2EQT7a~>OUc=_O4quG=%Shy!`wE{IA=) zYsa2FJ9q9~67bI4P+ zW^{D;L`8wsX3ZS5WOvjTb`-C|)3x35NG+kJT*#;#$S6;YjDq$>uPsIGF)oB=HOhp@ zgxrA#ndFX_*rdiK=^fk)r4FXWs)|PjN=EXskdo2aUf+>tZ)&yWtu0(J>?!zOz#r(! zwha0!tJYLmZ2m!WPDib)CW&@fqo71s%^x6dw4$H!O`uyfo z!z)(w!;<^`$FO4&srsdo2 zynGkxyty$O?erq|K9s9U2&@9rq&J%5DB}H*bYlqeLGdFP#~ROG`uMZ#fwAxdjIQY@ zk@Ieo+)@SYcag)E#H9mnv68eGXPXNJEYjo2&h}Jz%Cp_st`d-9R)iEITwe`e63>sv z@|!9)4i0XtC@Cx&Td`uSsBo{lt)Re_=PvYk3q3yf_Zob`P$*awOiZbD1zK7H?m*%- zx!FY-3HGe)-0-g)IoWv$33=H$4%#h^JI(KwUeorXWcxhBpC_RY+%2Je2qsTE7qeT+ z{7#iC*r~>WbzKgR+mYvXIT*B4u~YTfsc!7ti|)KUH+_Sb+K`pHMg9+FB;L;Q5NDC( zr&%632e6lG@M1o^OCGu#-aD%4^xHNlzvSaXIvSNWpV6);Bk146C;iD=Rih? z=dk(b*f9%y3i`e-log)`iA0Osc@{+TqZf8@b=ZPe9*OKF2byC(i3DE@=sw;D41mxg zsnIGsi&3Nh1$M^%uoOQ7Hq5}re)$Dp9TG7X>-f|QY@EkGg?x;~6+R_g%@8I@S}yAA zW)4{K7@6-9-%kzC=xagWZM-i!i@u7w3-~k}pKjuxLar_v`2#2geN{@qil7rLnzM81 z-B(v6XaoAfqQ3vX!xenITjqX&dv3n~u^JwO1g|PJ`kAd~E&I$GN0t0a72#{{7s@Sw za3eE}@yt2b^qbCjRPC^W|;iq-HNi);cfJr*LBysG>y>Et|(d>=plf5(r% zN7JD%thEvgcoE)n8pj{8tOjZVXUQQ&7gRZlh19-=Jt=Skn zzN_DVJDa)ThQ4qulm}E@k+?6w4zFBKs0&p}O{sYIAu4iiO;0l_%mAD~HP}KGj4b@_ z8eZ&z_kI>Q3i9(%ye%7Vc&GAh>Q{OOz2MzLD>Hh6{5wz!?APL^FaK81DA$ga?6}lD z=Dq^oE7q0lI^-O4UV-nPH%hK3Vc&ms^+Wht{pzYS_zM5z)mJ%HgP!}zJqqi+2W$&;OxX!`iw~3Mo?yS{>+(Hn*xaS^Pr+|F{~U-~^rHr;%Z67a zB(tCP^}!DT&ihU2P1Xjid?2S@4ZhcQ8Q|f4XO{u9UdbDBSuHTf$&X7j=8+CKf$)Y! zrQcQQDk4X zlt+lz9zpDL-CT0MAUb!lQ!Q&M7S^^Jq8rz%Q5MbAveY&L4MF;n^v98GA)|1-pj zC`-#C_q)o(Y?zg5B$4$-CM=%=`Hsjqq6WlZ;7Vs3F@f>5t)+QId|G*>t*bXUyv!H< z@QMX9!vl9>E~A)>QF4b0B$+Z_lueqr5u`W&QY#zYFG=s1-1)nG`<_%TpE?(U_l&Pc z`Uf8avK@cp|4k}OrFD=fAgtOjTZ9y9|AF4WdvZ$t8uHSlt$6+l^i7e7J8A5n^&^A< zam$_e!CLMKvw7}rZ0gt=EGY?WZu`Ln7rcJ{)i3Sb@$$9wI0rcYIX((1pDZ{z2w-P% zfzSDnzgD>0@&Y9#^_x4In>wDn_T?QrU%LAI*DpBu+C?;b={L%sQO`z+NcAPC5>=Y4 z%AbD&f)u^jyC1a|dspq%E&WE$`6#`Dcvd(20d@OVXV@+Mgq@EVT}3 zX}x5*k?VmA|F%h^>_@oA?Uq~Vz~bLmgij3ZKj!UiyuFRuF?WJDpzdIgpL~kEbqR}5_0YHQqxV~vdgaN|P2C?`oSZZCi zT_>-+VPoBBX_39m#>aaK zkMnu`f1u&Xs4#w9ZdR57*9B5hsL)~0&a#>_(~=FyhKPgiYzrONLM#r;;#)8I=^b9=!Uh3$|8oaF%v2Th<*u-O||D(qB-TuxFp;nUkOTs%77v zgwle^hO~3xw1%-OZ0xUDSIm%{TQm1DIa59e3d*M$*>i1HOJ+uDl3tEKBeR&%2Tv%o za`o1k3oblwtH0CcDXpz53IDRZq@=u|H2vWIl!5Z zA6|yt%9y)K-U|E_k$0}pSP!-yih^bam6v5d*dv4IVx{)?K53aSUH z3UY#jeP!*Jt}Puea~IUD@6uUIHw?(zuRVPDWAyey6BG1Cz*6I@^+Qp>`Z!-H{OKR1D?+3 zkLo3GWozy(lo2k=D=jbcQIOJ0RvS6~`5FRsWX&PiE?%r);2hWo=}D`_>%8-;>TBxr z`-)b#1#5#s`H0;R{INlDUV?-<#RjaA#ekV$dyPp$5s!fmn>AkW2aRQPQ+Ud z5|cI|=MaXIT1D8_mmFI~xaLDU02x-^i|a#l12&ZF_uK9M5`Rf?QA|}~dRqcpx~g#W zO+X_=mprumP}Wdo^F&?k#InkPtebASe0g};vOrx+YweHN^K$XI*N2KK+AbIxJkV0+ zzj9#p>T|ysUAb~}?TWs!KMo9Ff6_s#eTY_-OCzDxIjCd^uN-)862;H)o(d$iBtUgR zl{egjKo~1YhEc2*Idou6NlBbsQJ)bfuUsm_di)ugh3*Us{!PJRyqq;txBwao&K+4^ z@ImvyB~dKdW#p~J530uanW2iZq6?a4ueD8$GB!G8yLPtuKyg{cP;o?S{WyY0FB(qH%}E}<@F?De?DsBTIh>r6n>@S{eh(()BP*zh=kRP4p~eDiKCCTX zOq0LL#KLo3)a)hFtrtO1(f|oQo(n~n8`H5!O4G^6bm5y<4KmUKkiy4R#vs*af;vm8 zEPE`&c<`$Ami+_mZ7b5(AGpeB**DM;lDDrb7!0qQS~s(f-8<-+8sAK_CA)tZRGB5+ z_XHGI1I0)A8$S?#rOJv_V^52A!)%{IHZ5H@q0&c`o+a#(;yA$kQVMFW@zQ+r9YXP7 z=fRK|#!!oj4-Ri>29}MNzzTyp(?zBH7<6^I)k*(Re4J`tW8Lzw>H3RrzLY%{{?^TV zGrQ~A-?knL|CI&8NbTAF_2G$NIjzK4MZ-m=e}6SP9=Q zV(oeaV^B636_3W?1tu$7#|ARJzHAG3gdn#dj&M|CqBX&QhlTz)GD5=fz}D)GE->+t z>B-e44Tsp#@aKI=Tsq$J3`s}ujlOFxKk~86C+J*YN641QkSarE$a?@!fOCS*0}ckn z&Q>alP3bBeNqB=H5(%{T%9=e2AqHA`ZHBp4sg z_<7bcz*@uKVvXT%;CaP(UI^!~Na_!*%)z}yRPZ!XYMIiTzz|rVxZD=pLrQ|BP46sL zZ}7om0F0_Rj75GQD#4lyDfiBrk(rF+S8p&h$>eAxLLSKEYAAiz*HX+L2 zCBKF!|C$hPkqY-q8h1s)<&%L|r-Tqa95Nxjp_5^uCYxN=zpRl*F}<} zkfa_Z|4_^UWEQj<={tjb1#;Kq?VBdn;Opr9`0|ubZ|Ga&X6Y3hEBh)oR@}B~a^qzG z)Wl@?og`GoN9+$+4uJ9yaS9dKEJ;u(c;XR0QV<@2=z_BjMa#|HTFuJL@YKmrv^*K9 zvelE0_Z;K-?6VWqmz({rX_wD@dG*E>Tjgi23BMA4=VwehkRE=Gm82h>`zie6)mNwP z-;aTblIRVXITGH#j5uQgatR?UlkolvP*MVwS4TB7?$V-)^Td{LgHP!vM;5NJal(S7 zN4qIrSqy#y;?lOW)(pe3R$e(aHa7dEod`CM&VF&%7`vf&_)qNL!|i_>?j8PpxRQMj zP61h3G53z{33!W_OGE72B93BSh7f2AOOuOPq5?06l*nIb#Ba?kV=0S13S~vNf-n=2 zr-K_)+6&2ol2MO^mj?^9{F-@73Qd9L4U|?B&DJI;)F-#;U;L4n>F9{AjX&SbQ zcEgeCB>YR=K`v@ksN=()o;)QbC*%D}VkVUF8Z!|w5-q;%14fckQq*xE6|tbW!-P8j z=@G!+tSVY?^1&ZbD+ByDzo(~XsAq7XFVx!9P*&nE^x*birYpm3_V~!V8OdDo8*x@d zLZAnkR~dB9`P&H8JAy%+84CXTC~Yvp2L!LovUz!27`=2W`dxLCExU%5{G1(|+bkEa zYdZYYj>Crf!(OWhN4RbVI?J*CXkH`R>B>o(3lJJ5ZQCsbKrHu7t|2` z{wd}GPvV*eR#_p(k3n0uys{TuYLk7(%HUx-N00Yyw@<&@)Yx2ChiGp~YW8qL z==W?3nBK*qhPjRvDDn4ub;jgrvB9E4W`&6vl5p2WGU&IE8mW3l6BCUS;Mtt%S!F0o z1$nvI=#u5)6V1p-hENrkIU`4#wvXpp_-lDupXcYF{Vbo@pZa$n*o^%2HnVZ?83VC4|qgv80Z`YjT}@aemqGipf-?*Y)Plo%Ssi z<->)A!^3!*CcRu#AJ_^78adN?A-#~VU{qxmbeJjZRE*5ZAaMm@MQ>zZAgm$;N_wIY zRPWmmPZd%sRz_(OYI@b-dHHm3Reu!!b&y3#{5Kl~7{Gv&HPV78*BEe8q8!D6wO7H= z7LkBYCxuoEB`AuAR9gPcUs#McoPZ4vC$8V(T)ujBk8@@`aj2_csApW02w`B9Fas{ISRI0^t`xG56g^WYZA-8{c22P{vr^-F_egPG)QJ(Al*P1pkS8^C;$ok zKjz*8AnGHFAD@{o?84Gv0V%@5(piw+M5SXv#e#ww1pyUBFrrZtlXz;Hx%7HzXL`S^ zrd-+?({s5LQ!edtNi@A*%9-Snu>a3{-|sF9qA{1>{eJ(2`F`Jb`n-AbX6DVC88*=% z%;dYry*Kz>>FmsHH;sGsr?Od@=gPKY+fGUD#Pd{pC&yz$Jm43I2Uy6 zk(Ay^gIiV7zV;W|uiiPrua90U*nXEv+1m=QR+ZGg^J;h|j$VR?9gYLWy)F5heZy-;$rn&8=5l z(R%sMA9D_i#A;>39-T4R_2YMUdR(xg9I}EYaagw^HjZFH$7|esGm3+!INEjfv3q=q?eEJfD+a&IFJ7PCSKYLIX4bOw zW$7y?Oy4>^WqGpvE}?wsgxon}E6O@2v{Vh=g0py$kCRlX+)FbG$Ul%Hd)yd^_wqd2 zcPzD|(H0FhfI$-!l=Tr;p^Zl#$>@=xGBJI6t-U%ry4qd~D7hv&x+eM6+|YyyTWU&@ z3`$A0RV0Mw#>%~|Q>M;O&CE=lKXpoLT4rY2cbT~@`Kf7n`KhV-ExG83rRaCn$&az# z97Q~lS|^SkN18acmXK1+gFrg#Lq3@t7dd0WTnAqE>;-exzJM;j`9FWsic`G(GILc_ zYdc~qK!f^U?~(bxkwyu23MHeLH3KVpPeQT_7?r$k@TYa^sh_rL(La5RMoX0kAZ^pi`V}mq1d(J_DoC@b_;~W(C83w;{*O7ws z_g^Ya^9P07!Q;<|TnR_{C|eFAzklVb{=xki<=x~~WFI`kquX9R+0bn_6PA6GhGBV?_Rpm2?@01opHh0x9m-^HT_9FFl(0@L-wqa-*y9OGRNY^IboH||TSs)~x- z_^+B)HMOCxXi^cT%SWgS>#wK_o58_JTR@*D>zghN7S5|ozfebVBGn-(Yw$vMZQW;2 zp}E&lRNI;5WWl%JjS2-wcroMj_xi5rq+&7NPQ9Xn)~_ z_BA_q?v$~E@$xFI^V(SaT2oP#w0h&?5v>@b5UhNl+x5s>Nau{nrC`LW9R`R{$iO9;`lx_MErs%!CswU} z@}zAKc9bnHFR3!A@n|k5O&MOzpxqQ{kW8*hv?m9tM zC5_9>nqbRGy{h+-lh1g%xBHf5i%y!9n>oK@PUD7#^rVSDMn>7jW-gjCXZwu#H>~Zs za$aW2tFqF5#{9goW1<6~f|m&O0MGGI z37EEEzT|U~z7+@k5UPsUGT19icaP+Oq+C_OHru!yTedB0Ot#$wp|5XRIw6g)rVs5f zdZOj|XhITJY7R_xaY0WynrT2nL8MDNbNMyVf<<%EwWK$Z63FxFXUr3qo z=k6er)Y!H)Z8(RvWNEcbyhqFZ=|%YxmNh4})AR@@+108j;5rvKOk%#0gi(4~UUG~D zr>0>GDN^#NF=3KON>%Y%Qz|x%+tX;IOe@{QnDk4u2q!oPQb(OJ?lhWmCuz&T)Veqm)3OpQd!VF12zU_sb>4)tT$pgGux2tZ z_lK-rYV+~Jb}yVorpcK$8}+xga$8wpeol5;N@!we!k8#TADk8d?oLyfk?nCJ)}Co< z#_cN#H;;NyWZ=j>Q9lbhYf5F=I!|JbKQXKQPdlGiz*ORK?hm%F2?l z6;X)^%{jj9@OvFXbah|fUe^5kc`au)H=o%u@Au8~kL&I{E;eRHcvS6#NwrboGsZxv z*=HCo3UD&%3dY7U1+?0Oy`et7Sn<(L!XQWB%p{=0Ed2bxcD*4&=LY=qPC1j=~nbc7IXvX%OWrdr`D88dTwSr4`HJNW#35y>a=;C&68(# zFF0API_8+cyJXWbgY)-adcm9W=5G*NlDt~ZVtR`cWsKh(A}@#_XxAW7lg_aqi~%)` za=QiL3+x>vB_4a>>v* ze>U{#o8Sap>^GVd7FMAD58I zxUu=NnVUAvysUX6m6CYZTrQ;prL@OmWj=3MZ=aM5jZs6?Lp^x}?lUZ6X^#m#J`QP= zQ|@VBdiTcj?`ryagReQ`#F?{CES)^@qK)7CTE?AHS9M~czpromHA~uWS>AVBx9RpM zzdWp8Ppy#yrai%drP(=!{^1Xqz&Ri$@tK001Yor?2{``?ok?!OU6_XIw`^=zZzLqf(`LjArDNzwk%#5iKbOgG27}a7)9GXp zjIL7$JG#0+E!mL2=HT2mlSpDt0DV>nzDUzRZ3B}P>x})1)Z|m`5bsA6s+^9UJ3C%z zKS!Q8xQ*1R|65&hw`MxYnp3Khd@))=lF&g!rHtNyp^i>}q>{eHqn6I9>1yyLwFqZ0 zJP$5n7O7ko?7zeyL_kFnc_hsZ+E`<#2UB^lX^(e{48F8+<9!=9s^eL(ycOz!n$|oP!zPZ@Wz>Es+XYmJ?K>9To>a0Cru=BI2;xs#WoDvMl*~2+TBobCa~R~ccUIRHgb~UWgb*i!817Y5M56im26xwj{He6VoMaYCe7&Jp|U_Ly)18j z(d*uAHN}0CHu#xKs2ta;c+qb9U+x=6*;h|RSH|#(hM(U3;=_|BVTrQyNqtCY zVBpy3n)=|-G4aq09^9vTg<0(ZJsjm;30e#o+$T#_@9f#2r+BmiS`!;1W^?YLE=Xt3 zkZ|37ushXMKiG`K1Y6hgRB~n#=oK z9KVzr7Z;wHT{IpFz~O3KoHahw65=<;QWTMu7(F&T$QmTn;2z}fX`|&7a1PUn`aFDs z*$^7}C<6%20VuK%=9`)A>C<7j8KE5w-m4lwm!E=ij9Sy_l6JhIT&O*~(Gy5Pd-aA9 zCac=&t0ME3Moe-{p5nlT@RQW14fU~e=f>7I0ION5$#uIH4S9rv^LzvyaAoNK`s`KbS~|T$NK#TbC8useRAEG5 zw!I)ZI5r|+ik~SUBQ+^K&)>f|I3da$(LRB)F!(g`e*<)_Lxn-*kXC}z2AO;{L26%z zFw0O8lI3QWCY~rq>%$GOO#8nYrZt96PZ}GG%g~D+ugou;?4KMlF@9|DL~Iuwyw{Z^ z5^-{6IzsOmv$avIPCs0V;rHK zN8^aQG+)<++D`b7t{Qy|q0#u^oK4F$-^(vY8C|uSuds87FdX%cYW5mCP`}?hYxySl zMgQgxp9SpGEV8POn)7KOJ(AIVH)Ua0{nQ0rlrWOUhyd}0AwHA9UZ}&22K13f`m3E= zrfuo0p`eQn4N0_l$S6S5M*y=qWUaRI^2;$e8Qi0Vh#2h>?Bc?%9*aLjY@-u&kO)jA zg65vzm}QylFD|l9w3eo(l;X8;q83t88fS}*wZ)Z?y0HsLcfG2;#Qi_?5x}YsH!mKg z??2jpUlWx%j)@Z;IhEz{R_gbydcTiyMQN9U_ z?!TaKqgVf~Yr)j|u7y)P^u0$5HE0cWqSM;wJ-Ub3s5j?P7ik8}TS&x~l2V4(qKVoi zr6sY6vG^}7ppaLjUjOxDjtI|~(lmo(A!F@~4G+M8;e*vsR$Uz%mnX~g|Qvn=7jZO@ltWEv#0xJRcxf#lWbvoQ*# zKAWV-Qq8nNL(;A65uq<>MJDr@{!$vY=U^DGo}gA+j&?i&n7UNulE4u$=W)!bkPM98 z)q|m6izpJH{Yx|k!KtQby2Y%4YA=4wm>p$KW!lUfz{I8Cp+SOn`Thcq4})Lr zQa64l5`LlNqH&Dai+6OmJq%u7@^Ibp*q!OYEAAn1(7sI9duocDhS{a2E;DSt2JR;i z?$sa22DvH3ZAzj44@ZV>Ed!pHGt5)$( zl7Zl+DjhSPcBdd);ytY8z)U@3=3>K-r)}f*Q9aZ_*Ld+FMxmOz(Fo;GIT$CSqg9t1 zem+;TWew)Ln!18)c#f7O#%dX$oiI^SRTyN3K31>^(mE(;>7yG3X#o^Hcmm0bpGuqQ zoz zzsdr)*VBd8GSZcT(j~<(B)kn0afPwfP{J&CM#7kxBk2HtRxTcwdlB5kCvMIgb7Fma3lq$ z(n-1(Iz$8cW=*ycelX{ViHS*zNzKLdnvT*iI$shk(p+?CYCXId1GT(2H`*SalRK__ z3?|x3MieR{9Gk$*X8*vva69e?_csMuHjP@!7?Ca}RaK_g$Hx1Zu;T>Cb_+OwS1j^j zl?yw1=95|?mbT0$^UT=T*!0-6wD1%Xd+=7XQA8fP%p;2C7M{uUb5&o$ncdu1IILK3i3m_jUK^4%6vMn`7)gH^wluO8Xku~1qtsqc26Udus`(b@mrDODM(#)ol;L)^o6hR+u0fC^e8Kn&b zxsbfi4#LOw7M<`98T*rn7v(kRJtK^yd`#{-xZEi9PZgGcP;01TJim4t<=unMdaOor z=>I9-)%wr=nVMB%qMPp`-54X?|2^MD@@MxCOP|Ue1KBEZB%DQr+dd_6rI;X`B&YW| z;Gq~N4l#ZVLeS&r>?qfsrS~}Q*~>3+(3nWSpzsLHW-<%%%Em;8hYe?;+M0;)2tUo_ zWA+ai7oHp!VfFV5v}_zD$3C3n|MNW5EjKbl+zc{! zTECfoU4EPV-t_y(Kg_?wf3^Q6|5N4IV6X}f4o(Qp3N8t*37!$WAhW#}J6Zw>u(=rf`FLl1`C9`;^%Qg~nZ zo#79K|1JF0@OQ(%4F5609I+^3MZ}2_XGC0Oy~KL0^$zO;)+ep6MlOrIH}dr;zbI?e zNl`nZE{?h;YG2fwQ6EKpi>m_yqsK(2MCV1XiQXK2dh~_SJEL!lzBl@@=zY=ek7*s# zHD=A2Q^wpd=A|)jkNI@WcQIPbxR})|Hn}}{pS{sO$G*hA&i=Cfefz-_ zbILm@U!|(l=+unV^3P6tk<*N&-Tww&MwTJpWT_gE_+M%McG$pKkdkNlsdLJ&U0MhxZQD|<7vk$ zIi)#GIjuQ8IS=GKlk?AhSxSX1%4ip$35j-NEXd3?|KGsfRD{>kyL zjsJN3e=6;j&6ORMYb&=^URb%aa#!Uel`mDkHz9aJ;)J{j)f1*qSUKTu6JDM0?nE)M zf8zZUUzzytN$HcCCLK3v*QD2~VyaH5y01F5dTaIdHHkHwYqr>ThpIZ76D}ZJ6EA(XgiBZa_r;@lRGA#KKY?35mPdz ztef)Yl#ixrQzuScJoUt>7fpS0TJp5IX-lV_GVRuBPfXiC?Wd;brh=x5rkbW1O$(Yf zH(lOzW7C~Y4>f%_Jz#q7u)ht{_sp=(IDN(!Gmo2jpt-!+IZMr|n04u_&u6F4UOi{e z+~~PW=l)^thb?6-C$#KnxxD3xmRDN7nU_6p{=5_Boj32sd5_K8KRSL|8w>WYIskv$W8R`v|^Z0jGlmh@=by5eh40}8}$YHi~q6FzI1&?M(q~U)$O9> zu;xEvy6-eGT?-R|xX;q_CfL^xVdwmhO(o)g7x_Dk(M-rwu?XZh!7#Wb$}q0CWt{6n zm?vPq)s1M>-Ccjjdjjmp&sTt>@jf7XT!UoPWk{Dy9^zcAzX|p>NLT-!Ec~_EVkQ~& zjhODU2=;i7X0-2z?6q)F^8W|plL-7$SuaOfktfKtrytR57uo7)&Etq`5OJ;o{T$A` zC#I-D2D?IK@|G}}?GRU+g6mcf)fj|}u$>g0DK<8X%a zGyl+h`D}t+%Ky})%YNaj`jN)r%tB}tEp&aX^!HozmcF7AhTbr)=V0E1c^T$o-LO0S zpbcZy7jN?O0buMCbG-`lsN1M?#BZ3PI63YrIa^OdSvZ{!WRvR~2(l{4ARk9GTDzBf zGs^e>1EXDweDoq;pa-gRc{=bk+>AHAi{`f#X)OMzz7N6}pYOnSgf|Oc6{HOq$$`zGE}a&)+O;FmW&uFewI{ zjJFkr&WHbh;!o^#b!+#EIfjXoe?=b0yFL^@ic%GZlY#MO_+R`U2Y8%XjP(xK%jZQa zOo)6E`{2KYAv=V{U3GzSoR}?76WK6dQIA`d zb@LVQ@D=cpgm)6&4s*a5COGFrhFBFr_e5 zU-X>`Qvs7g-#$(;ncjv8$D7>o?fM+=4`7amDKSiy7wonh{+`2h;I@TTwf1E>v#PyeTMO}!yOC`*VnKw)Ze&O$^ks+VaxHRcn-o2Vd$)t!99cb!|WM+ zg8v>K`HiAO+M<2#GT}6W>4Vq1mieZWjrR}hg+8iIJqSsSP&Z%v`m{nL+k{>Dm@LKIvH&f@&fWMe}I0n5H`rx5HSqBtt{Q6w~zUIe7`8R zKnn?Cd#pQ;gOunbnGbo-Ir4n$c5%vQv`KgLi8PInx#Qke+>Ou98dPe;dYUhDk zh!(EJX(?KUmaFA!#oC41wc5?vgWBE%|Adf)=mgyGlaQK_oiHw;G+}(gl!Q463ln-0 z`V&q_I3?kngbNZbNw_NE2U~zG)D~%rwI$e+ZE3bVTcNGOR%csd+hjY#cD3y~+l{uH zZMWNY+wQjAZ~IG9L{d~za#C7SE{;xg@&cgV+3rVr#N@;|sWG7EcMsZ0;3J?aVd8rEV=C{q~9WY^LTDU)A9 zV1hLvKEaldl8}{jO{Tuaq50_22GWnEa ze7G`n8^byz=eo{uo#xu&I@xu+YolxZ;Pk;sgB61rgQ?!W4iCQ@aUh0V51@S> z$R=q2PY0$SSbV^D|I7QY!rz+xx5MtP{eNb+OZd5Q|Hl1Y`)BT7@(#B3yt4uZYK8B# zyffvU^movH-@MCzi|Gx6j-Nw_Pvly4A%z4rrD4rZXeC;iR-tXyPSUos{i)jN+79hv zNFHyZ@6mtSW!e?mHQG(uEs#(CNpotuwY#)?w8yj;wU@O|w0~&_ebCq_EZ)2E1fTJF z&}Z+Vv5_m>oIc<>K6m*TIM@C8+y*OSM z#?zET*;F=8Xj-9Gg8sH38;PLNbhN!jF&RqEb44e5pylFNF@S}7=m!(w5Nphx~jr)uj%XYa+o-NOn=gB|F z>*ejB`^V+e@^A9*xKZ$Q(ES>mB$%S6t0g$YwnLqvwyCGpcKNodRL83E>J;@Hc5?Tr zP!*;gSI4WZDnUJ^LgYJYf{MkV5#R{eG2|-(MZAa*vDlhx$M$8M=qoC5twRg86tsy< zaU#y}K3V)uTp>SZs9QhpjaUbxmf8hcQU-VhfYm{La8-}8@!mV&=e5Y2MDSSn|TcAWb> zPu7SI93Zn$R*5b-3*(D9ILoR>&cleKRjkC)M6YZUYtSpMmmOk*>=MVxPK-s4m&?V) zSj^sn@!f^;ci=i_iR{&ES|^s)-FFuy9h)?BfXeqCXvoSjUEBHW$$dxf- z1$wfDVx2fat`JjYvG@bV(Q(o&5~M|3jxl+-_!;9KO^lbRqFQESd{u`7K&FY)u*2pe zxmDaGFA}%NOT=T)Yu_jTBJPws#b4yj=vWKI8S*&sNBMiPLv9cs$d|w=?+5?iqyDO% zRF9x9*sK1c9tQ9Ho7$(IS1+h%)rIOJb*Z{SU8ycp7pU{qRqAqeF-9FJ(Ef4AXptkw zV6>krYGsZnk_lplEJrUrQOuH+Vu5TBtK|ap&Wpra973{Dc8g7Nnb<6Q#FcV~xJsUh z-uo1BiQF!3mKTd#<)z{-d9}D(UL*b_FBeXErMO34EB4?f$cN-@;uZO*coDb%yonJg z&M+4LkWYyN7+roQU&ja;$DUykEl7NiO}_tu#`lj{zx@ffAN?TA;wxwceuMRsZ=uur zZ*;$3i-|HrRLLySAoE0t#446d7Uj||Dr5>qlSyJRcJwTglf{{Gqc}?*FScTKx?LVC zPLXTHsTfsl!`VsaU_^c%F7iHKo-8hqTg18YMDYa9F?vegEuNNt7SG80#Iy2#@tk}> z{7v2~-jgqgcjZ3uzI;)9C||}Ye3R8w)reD;OI3*~R%NPM)u<|r7JiRi^mB2Z(JVDv z&BJN4Eo!l9MbCDOTC0vz8&$Vjsy3ZI|x5qsy5A zE91-N%p>c=&(60&8_XQ!Cu59r-h&rf=b%s+Hs;~oKt4Ewb`AbxwX5k zEyt-jZ1py$PihBp=3Cp`>h!hOI8F8%l%vfl+jE>g4m)PeJw8lm*l;b!(2lRAm z?e(2bEh`C*wYD9$9Y|nTo^L7&IjglDD=D+vTJ3E~Z8m4soL0ESQPGU_bDX{or@1zJ zH^y6xDHA^JHFjX!Uen=JOP4uiCvxHR&B}3_9X85pKyBx}K4K}nAhT8NZRDlBjYwNgmw$JBHVVMUO>hBMY@Cce|~AhrNU9h4Cfg2&Yb495U(7C2GgsQKu&n zaG2oE6of)xPtm*s1riC_Yjy`%G*ot+J*h1#DaRS)*rimxv#X;n#~JKE0cMX5%XeUpdYYL=(y=u>k{}$hI@Mw%xX)-R2Ai(sG=kj%jmSclmVHwWTvs$Ok(JkYWU?0Ku;f`G*q_(AXS4c>$Q+CuiL$ZlxLCH0{0_hQihf_wO zCbZP%)?Gx%KvvBT)GsBQm1IXSHw2CZ>i6hrm^d^>bUDA@&+uy)yvBXR(9eYHaOD{_e0aD9(wRnjP)C!cE!EGqU57 zfhH@;7LlFfjCAah^o|0a=^gFZrO|tgW0w!TV;sAD=^cx`PV|m*>@w3k-m%M%-eVoR z{OO(P02Xw-J5BAtu-%sHl*dp5$#G_RIYxOLkJTNsy&Tg#j%#(t1cz`2W&aoDOGNn+ zkS`m`NADz*kKV~BAHD4;AH7phK6!9l6n!InI(_@(K#>g!fX^iHJ(I<=Psl?Eos!h}&0PoW!8=t#YRW4M8~9FglR zLVKQk82c%RPFf?J#qcxL;Vi{#8sV)T2(~q#Uv*=u$w4ISoCd^BcVJ#!2Ve#ONx)3U zZpk*y0N7?0`KgD~Z1O|E9P&fJT=GLei{nmky=p-707-`CJ8&2yL#=>xyEgJC$=?F< z$IwFZ$Iv43$Ivm9W-YuerZfpyLTM7vPH7U*L4FzlEG0h#bdnzey2uX!-JGu)K+8B^ z1TE)$5wwEyMNkjti=dU9FM?Kaz6k2&d=a!7IIi$iU>|=uC&Hm$2PXksLr5oY&MJHz zi*6Jk`B|%jZm9A5qK4+od zt-I5=3wxgGkjY>8od}6bhv*==uX=}8LtGg?b%P%(tVyf)abm^yu4MX#FZPF7@-Tn$ z4%biW9rnlJ-2QMk^w?qXJtJd`_-q^>38-d2Hq(X39ekr%$DD$K>`q z6q?Gp4&|@DN?c1=4Z%w%sva!!W zmBn&Eu9NHKaX1=lqud0^(D9JXy$3nZkMcyUq?|0b$luAWkP4Q{?eY|PDx{dF%QHk7 zqh+KxPJkTo19_9YS>7V*AgjDp-UgZPpRnHHgj8=8WTtmQdV06K z2U4b9-0prKMpru?UT z3v$=DsVCsL%5j6(c*xc#sEKM4Bz7dXt5tQ7k}pv8kn1(7$zq{cBtBD9#Ql)*O@p@e zbTvcG#K}(0;zO3}&A}?b!;tc|h%3cakn+tZ37@ze@^>p_@lnuTA0uMGLE}WcTA&s} z3U~~pfJ;<6ArI_R{a6V&7E;0iwN9;vtZ)OQg_|Jp zKLP6(C#sXw$!d%Gop=zE(0_vm2SLjJs5lMs{t$61RxhrF1U^h8i)*kJfb&qmvum(} zYq4k-6Vd$zV13|Du^Vd(+eIkW6iyX4i(AAV@etMk?hP$#6 z&l20!+2Sw4jP;Fk#SOT#_B_atFJP(i#p)7Bmj3|Fu~VQqb}`AAAujn6D**R`o1Y_a znufSYTqrIOH-e8}r>+v`i!0P0)lRHD{6Sm~Et5;p2R$L~Q`ZPPoQ)x76F{llQ9w>Rt67dfgAy zhw3BsvHHYkMoUwZse0+!?&G@6>-&20>#OVacTI`$&NJQx#=A&=SG(V}#<$_Wy3F{l zrgvUJo)Ny<{pNUJUtq3Y-O;%g7bI5qFYoW`US+9X+tataqjUYbZgX|L{^l&@l|iu5 zv$k{n>Sev%8!fe6{p&h9JG=YVaSHjhMW(vW4n&04+Wro<&9Bch@|DNs$;+=THq~=6 zP4(rlt~UzErN}p; z%r7$6>jl;kRa0wfJGh_mc|iD73BF$UfQu%4_{CnFnK7TVOM0D z;;B>Q*2r3cyL6nz{Q6q9hkLboijmbRde%%+*7fvubq7oxiaBtaSC$xi`L(5{Caxz_ z6PF;c$;*pR6LPI*r;v+|IxzB4Xry1H(?Wi2wP}VP&kQ}D8D8<|Q4}%a^XrRBwEDi~ zM)Ea=TbXI5r?mO?bw-`l8L8D7bysIZQK#poK&Ozrf&!z$3f*;W&_Zp!@5~kbYy0#> z>WneA-y(qzsQS$s1lDE3&lAG@o%2Fn1%&6#wB2ycC(XAT{YAQ5P)lgeWy#ds-u}+s8BKMj4i9EP3JrRUHKoQo-*^`q?_zqR6&V?+=5K_n)7`6$aMk6; zH#ZN^Ajbnbce@+$R&%^?FEn=;*y}JjamNrR?&$U+puF;c&LO;5Iz1&cb$KWOtk=j; z9v281E-`g;IZfSOzVZ!UHAb;(jqKGL*{d~*U8@(nAg|cc?MctTh*8oScS%dl-QIMN zZ$z12Z0;V$ayjX|g5q-1a?Vk}@}W`%F868}k5kT7!GlvJd#IG4~jm?=hHgkB4mY3JOaDRt}{VxXLS&fvc9U z?e6aD?da?3=`{6neVKZ>V1d0}{(O2-7(MYq#tf>)$X=nFl@^-%ID9}~$D00ub!+?A ztmroN>2dXW#id76WRPG{sn+e`%5L^mZtC|S0$kas);c4_I-`2)j40~#92Mxq18Ozu zw9ris2D#KW`1TL+i#j9U_3qdVUv&mi)#nHGAIdL4nEl>#Qf!1S=Cr_-YXbTY;mStL zMLJOz6x5m4>X=@uV`uFM?10r7SuZwkhX!Ca-#{97}+mrFs=903cML<*Sp`PzUzmuTW{1=gOPB( z8{0-?^$kJm55+FEI&bWjB9y_6*E2U>?;-2_`qFaK2A$wG43*t~gNGY$(7ExZAxE9^ z%8UwbC^l{K=EepU6&fgNC^sF?(OZrm(U8jvLwnd|$x1gj4wy2;nFD%;>>0C#VZXH;+LASB2TY;9&cK*xy*RM68p5qLE13eqr$})iQe4h?>_bgwrPWRZ? zV??N@(YJo}T26xjN`n9+4FdHvbcoVmf0PFM)6-y3PlG*j8UzuZ3i3)BFL`-2I+x3< zVZ7kmz)Put7u=?+`#11XYT%{Rz)NX))SB+KJ^fuY?nh7E#g$fDJ=e0VXZd=3V+^Io zpp!IuJtJkkd&E4%h!KNbPDvjW=jG`W6S#8@@n#|iJ1!3D?C>cq5EK9W~s5;N3`5r>25}eEl2E z(yx29_Q-5b0<^7Fkv^u)Q?1v(Yw6}ZPY?xBJ{bb!6l7wNOsyn3To>4BS1%332HXq3(oU`%e~-21IB34yg%T2;KscB>GiAYHh|rH*a7q?;nsUD##SyhcLTI zormZ7>SE~MUaIcH^F_5E@@*wdY^z{bp!lCvV-TX@Tb@x$;&AX3*@rL302q7 zG*<-ocC71zM9YVgMJ`Bt9{1FEedCZFNWDy}y4UuJH2t}{W9=%DYdlx2UL}fF^OM8s zX-LFE>mxXmnnH_U&2LOiUUT04`E)cDrD0JGLIpoUDFy#ao{N%)A_oWg?*-SFt_NLD z3ybSn*LkjQ;D6|624>v9WXJ?FupWT(D^RLoKiaq8ItZ&07j{?x{+ho$e(1|Zr`ZI< zient%{uxsL67hTD#n-T(>wxPcZwuE8i1BmEKi;3gyx{sf${<|N!aRwu2i?A12M{;; zz6Ul{t|tLK2p@PGKj01dy-h>{4+oLEU`QW_%56d#KXI%t0J9SSrMg~rz2$ll@qF!$ z0_i;|f?Th;u7=G}89oz!u1AsDvoM$9w7N%;k3!&2BkZGA;-SSIFG5Hr44Sej8z=~p zVMr?NkPa(Ihf_dxX^;<_AsS>VBs)&O`J5~W|1~nn~X5jEa5sl|5_;UY(^wPVYXDm`%v2q#xxr~a-Xy!6% zTsl84oyMi};nMkX>C9X@6PHfo(&6e-lumN#B$rNd=@gejnn;Gwaq`m3fbcU?&|HIorwz#`_b+f!U*c-XV)h~PWbwg+(!So{^PbM z-gEe$k+;KpaJwXc3W$s892vW)i2nh%Z{hD}YE!`ZL6L+Sv%2U%NhYy^XdS?Airt{8?lntv#;S^*~e-l+}$_!r5Eo;(7(< zbJvHiSKMV_%xdIHIHVA+Pu&R<|EHgheTFC{E(M+kKs%oypGkncj50*Z~%Jm#_F~iZ=$v5DQ*|`8=+QSL+AsZ+)^%Hbp4CsMauyO+^M_X z)uExjnOlhAJW5UtnjDIOyt=Rhb@35G4#J;O8_ z;2-evIohIL2ejXTxPcXRPr6=4{{Y+oJCCEZU*pcccU(_{Ceb^?=5h3;3Bb$a+?uSQ zHKM5>D4&c2YTuu`{()Q)mm*&C9pe2GalQ|~RFhPr#Le7!cGpn^?7*)m4BR5nDjq;S zB2Y)c;4iyeA9Ef3nd|0JaOV+qgjBu)6&bu0aZs*^vR))gc-}gOIk$Jm_hx zqcve@3$)1?=t=w)E99?358|KlpU`F4FZYXmSYh2FUQpZBDcFxmr*(}5u5lj@{v^0` z8tl^XXMqdty2_;6p`r7Ui#6YISh3fzPTz=>CnIfNq}>Hvc0

4;mrM(E?ZC&kQ}0 z)qp8a{+uT>^7Kc{%v|y)E_oD}+{|UR zaGB})j5_2$0lkr4S}KX+l1SuoCt%8x;@oJQ55@WLK|WqVnJH}(r)}o6{WxuZ?2hvj zV@ab$#ABCSKHvh0@fLQ@GlRU!%cAf23=NPZ=zpxla}{=PjfGam*?`Z* zD10n*GcE=E2kbA3fX)TRpwO^*6uYb*gGNL&G$NkHjI&ttV>pk!LV4^J%wsPr*7}b}u80N|*N5WKWE77k z17L^iP0?j9Q{RFfqCxe0T~DE9ehu>jTHmKIc!M$y|4V>tDz!H7Ps1O=5HCCQXX0Lt zdh?;a5+8@@-xIhUdbqDUIEmEv|0;5Da`+%8Pe!pTQ^l!iX* zIGQsd6K{%ymfK9g#GxXg#Wn{p@u^5?vMmBk z+$xf}RU~sOKjv1E&?7qsuEewam}f;Y&$2*M>^j&J=L%rXWo6D4$eb&LIaeTau2AM& zX89K6D^bk9{F#4A=3kM_FCv*=1TnwBj8h9G9-%e+1fwSy10tX?0FBy6ia>BMzP`cN zVSd~;i8q*O)CL+12K9cAHuWiwF40$Wn;i;W0-t1iP&C3fjaA>rxF=PNg-s!P9sJOK zBGE&0D>CBO!&@Mo!0d_rJP+tK8nYpN^3qJ=kah<<8s!pxESL#?!|n8EaEv#B zpAh8aI~rkmqWlG51SWCID*^<8@8qJqgQ5cEOhG5tgQr?AyWgv48Q{E*b;3mFdKg_X2rp&2_7ID63r`gfSP5voz)a2VJkiH_h6H|7dgqX*A+K4ce1XhUHYGIvZakZ>APUy&267^ij0l zUuoP^dG}GlUVW5ll-`L(#eN38&`8+dt3Cp_J_5Nu0*pR{#=VpS$T5+}251CJ9z))S zu|gOiGfGPHFpF?tw)p`@LNt>2&UF@KN_18Y{UJQpC5_J%<~~C`vz2>ht5?r#<(}Ef zJ#!@Y%vSE1-6f^@i7)rbdT*?^Ff*4lkg3yRv?MBNAeS_d+e9drG@L0ff=e33C5_;c zTJ#>0sm+h6Er7=`K}=ymJf06`nP~`*Tf&&aa33jT!2vvO@#pcpKac1Ac|0G$Yd|x z9+?HL`()sGCivtm(T+LfQp^|U^R9$ra01CDP|FFJ|E&fd?}O&<1DKuO3cYn7@hEl+ zn8dfzPezD;6GxH~`vCHAdUOF=b-b*E4t^@mk6t88zTu>!RAD+8H|auuvcT9p05=o@3}`kLwWh4(vW4*KnV3OV}W#OHg>|k)WgT7xwip z#d72{bXSVyXi^)V=dkbHxz{1a=7_Rc%TUrN_Ll)D*#qSs7K%TjzaqFcgg4F6FM2Obk5Z_AVuZ!a&XbnLTufdFAyW>32R=8dkzBBxWaDp~_ zAl>f5VXh^%M=5+Xl}NQuab$YV(SG8Fy=LL7y^!^UUwq`?r!ci0?+{|6XP;oK7>82WY;yCGK( zbl4mW<$gq7D0V%yh=gGfr#m9P5nRJ8P`l zbu=jAnuwbsE{2c07`ozDLFXPhEaF1UcwPg8nDIP!6uTi;F9zGh@2y)nHG|wZ+IY&9m>&e{o4Ayb&#RYJdkd; zd6?@6yQmq6bpeMM^5+BGgmT#|9tfC>%wRi$iagLrJK+8he?xXraE<4%Lv};)9f+)m zd?m6fvLTY7H;)3^ca;7P7vC42G<1mKJ3t8X&BW?H4Ltnhd{*eL9Ons~=S+rgCO`6KPVr{4(Vin4?Ky_mGrXQ- zIG+7%;!wwPs7;*K8En5pf3p19jij{VoLpE~w`GTWcT_Qh;dtiv4t0Q($Zn*nwmVE>;8s+|GOr%n$& zY`=nhLRL%9e6mq_9BL-J&g6K;bDR}A%=Q)RCtrWEJ+0J9$W$qngKS?+p;RQ>6f;(L zaoAl9^G#1UljLXk&*G<@U9;G=gu-fT$VS_w+X$Q#t{T-l@Sn%|8LRyc@K_F;$6+tv zw8oNuaXs1Kq+*J{Tz|5ka(3OWZH4Q0jxCpB7F#JcoNo*NI5UB$J%UpqO)kK?J%`## zp~O}W^$y4I82fpQ{Xa%N)j!Dw=NwQxxon@yd7$-2*s%SXoZC!_2Pd;oK1shEPlihv zE@8Ns;bMZ3F8qj(DF(5XV#XOYWPh20cCpmB6ws(7nC<_=scY>2D-L_TRsjEBaoFo| z9)%Qla2~AcHH6A!|CyX_CWVr;3Mu7JdTtr#yV#X9$fdlG;rn!${bPj?_Tg-Q1IHGs z!)zbQeta1Y)?xM&%zjQIdz{BZRCF4-;v0Hwc+sg#v>FhPXBJLDlF$;rmd>@nsTRER zLHHWq^hImcHZK$Ffu(CTV3J}pVx-%iE;3n6YYtibw_BiK>xyl zm7Hl<$LzpqR29O%dO&bEn%=4AnNOB%37wg~HEYYjIuv>nF+bA?#jY{bb!$AJ3Ke{h_B&;d$-o@NnF z%bASxgcf5>ZJpufk9EyNw98_&mnk@BXbE;Upg-ks77>ZIh+C>fHC9SnuqL+(`;j(u zU?-n?=C?d)XPtWaH$6L7uTk%H((?^|>hQ04(zaOj*>8C+!>(=h^>2Ch_AKvEKmDdB zPJhr8odKcw@iUm8R({6v)5gyNYdwq|9Wc>yWt&7gJB7d}EElJ}LPwK6RKhV>kpML!0 zUXt~EBy%MRZb5#i=Oz7zDE`5r*^H?{=d%7-!+OTh~qc2FK4_+AQIyb zjw7V7lEW&6g^8_ADjN%n6gCGIno?5vC#Z$Up&~&7HX5w_6Rb2UoR5sRMgLR zcK7Z)f`S~o_xA0)+4ttno1KMu->GM($riGjJ?Q;5vaQs}exzDzq(fGpOvj))weSEAy$0FZ?vM;oSeC5{znQ91i3W?_tV5TMeM(I7+X(RTX(g!fqs`xp{K9V0~2mVO1Prlnn?I)$r zV5{x4UzEOpu~uWk6WOEp_!t;%$-aWQwhNTDM1G>ZAhJmV98AACy0mF;8N2233eI7!h)xh?n2+n@swOuR^KoG7Fx}e&6pw;}{Q*!s4vO_5iZ0i;@ogQn zve%r~@VMRY4e)p#6rG@W85A#qf_WiQ%(G zlGcV+MUO&yBl#MdRJO88eDn84v=%;JIlh(XQ+ZV-LYvm?)9kmtz+1eW{h8>i_9Eh^ z1Wk;=*-6Be>d9?Z)Z;ahUrMV?{$q04u98nK4Lzl=af*;ipbl=&NvlGfi9NO!bY+hv zQH?ke<&{~Bou`u7IgXsd@t^kphxHluhrzZ(j~}9!gL+xj%m1b7svxnM@}8WVY=4WU@_`lReG8G~Ls*P1BUpmQpC7KoLQdO|fMu z2t_TZ2x!>~;ze)=#VhKSO|Rm1MX$?OxnH$HCcn?~zUNG4l1ah)`~CAPWP9g1@A5p) z`|R&~Bqm9c4c`n>T7OS(U%`pOQHgohqjgvR_}J8U?@7H3e?KKjft>!S=`MA1=fx76 z{trn?cyny3y6(KceENry^j03=cg!8wdC1$@eg*!<_M*Xj+H|EP{q-OC+qd_?#h1P682=qUze$o3_wB!6ZfD9ZKOT~#U*K=!w+`&Q z?2w@;`Az)2AMk|-cOIB`-`oB>%;%>V<8y~DxaeZ(s^5G^Vu{yEQs(oA4$mKIZWz5l zVwO(={*;s;ZC)y2*U4{4ij*ojq-@D6l}bUWS!$C8q--^_yFJv>)KFhm;w#K?W~Qel z7?_k$Q_gH|o73wEIPewp1_NgPv)JJcMq24J9Rj}xwcm9ZGdhcyAdbiEFJs!`t zLa(bUyTk1WW>yZL-@JdgqGFe;(&eg@Bw0$ww-@E-B{No8p_V2vgUklO1rjqzdn8%T z7&0m{V-5z=SS*n~1Lyw1bc$$y$=?MIpnD*n5_NQXnFO0N5LG8p*OKtL>Fm9HV zEA3QMa+yi7FqvgBqpS=Loz5QLq!vgfiOD9mM^coGAp?_T$B<++O0(!7TN=()b0Yvo z>|kkb8BQMFtR|%U+%{XL+icD)H=4YjqF{YPqsES2kI9jd8K`Sy;LAT1SJ!tJ`@19D zX)mwzx^i8Me*=>~p+%|S8I2L=H?+N8X{49{%Qj;2Vrx_HJ0sBHW zGowK^E?{~RGhu@m44Fd;PTimocTw1@uLwQdR*|( zQW#_aT_A1kQk&W$F-f*Ec|L(zC8J_B&Rd|V%rlbNoG}E}FwB^k!Qe0qr=_LY)9mSx zQ1mY?(VSn-+)lT{ZO0d95I0l2it=RmhD1$C z8AB!p=AOYb4r$owbQU=CecmFs&kQD!2*F;r%`I5OAE*O!c)b$;ZVSkzJy%>9ew7s* zcwZJMDfIu~$NUOs5qbpN44r#4kqc2pFdxasCQiz+%QD?wX6 z3y!ry!WQIy4ww5Y+aIBJKI=9<>w4*7)ma}XE;5)+If`sx*{QN(NMZN}@nMDdCe7>aCAs3?C8t=^`mHnf>|KF%$li9y-uDCNiqs_ir|N8K zEH5)yEd^%Tq~zOWqbZ#kj5-$U62K7b8f+x#8a!Y!Dv%Kti+L8f1VXJ=jz%EVXf(`1 z&}AERgub^Yf!nAj)#`Y|8L?9gbE`)!gqYu~f-i!B>dKO$yqwI8w3Gyk$%u(6wnVd| zoSD6i>Hizdmt5Dp=jwk2`^w2X?|kQm_eg>`e1AHI?>_)pC-%cbobP2WMIMF}vA_Z@ zQoZ0`E-HjxiLm5knC)4~PKYjhdKw-}wAp+KkRL*rd2O(DZGm(? zHL`wf0k%Zbo0<9Zhi<|IzxFk4j%=WdwJ#q1_(xg(Kf1zUZLadek+~}JBeIoC4SkL> zEN>16>xQuAk!Vc{tU&>{X=y`D`vZDAT$^ty1`XcJek}i<)S-N*;W{Z%vOJ=&(}|}8 z zjLEu?!jh5_XQaeLjjjnq*CAaVWt)MM#x)c@oqQtE{!~mm`9z}qiRgBNs|Hp*?KRl&~E@UzSEFSVk^=gKL3$k|%e;MIj;xfc$XzFvhq z0D-Z`31gZRPQ&V~QmI-L*|rfWY!n7RK&_IMre-o{Makby?5XgbY$^;5(F=S2OVlIT zoj1ZNE|A*QP+F>NlyjK^KL}_Vggl2uX@t!#%WM|H9tIHfF!`hT5{dZ&sURIjvX{g> zv%wtp#5I*05$2I^Ec-~`zPlzS?pPSQva+y#uKj&iUwd@(+Rux@-=!8m!f{|m!Taa z{nLIB?GNejgcEqWdixX9u3`T(z<#3SRtw;O%W&T3v0tJ8G;f!1Zc8)4V`Kpv#5um8 z{^a$Oli}%!3HBfbfLMR{OK_vUflWjsow^&my_&efanFtFIQeL%B?=^GIVHOP`bN5iR@~j&0F?T5pHch=xB!?E*{E=h2TM zAqI$+j3M}0B2>ohR0ZN4hLCO3Bw<6-^UTXfphzZsBIclxmnaVD=kyotk816IM0-XQ z{AsQIMLhkZsP-qd_C>%O6q1Lcp9iDbydz?RDt!Q$sbzzqY80~=;0yJ zgEYA`AbpYJOthcUdj1*UKOZ%dhc);h+JDa_r+`1B!HboWrfOrA3qG(pq0ZF3GBDU&tn(UTms#Lr@Wouu{;DB$b%q<6?$OZ!h&p zf58lsr9w3yGiJ$5mJoa)u7?W=|DO$e?QRA3v6=gZ7#A+Tr`TAT8z`L|+TaPCZ)xt8 zpIPkMyUju)p+~lr<8%(akT%`MaY2^pwHPTua;bRdzz1^KtHHKZ=Z#igqK7gBBP^ zjL9=Jl0znGXq1dLn*ojpaW`z;Nrphg;?X{=c+*m!{4M^hU20V8O`w*YA%u)z6hb$~ zIUz)NeZm(G%dKoo{LCTgDo<+fzB#7Witky(QZD zDn{hYcv3gpiM-uJ#Gwdo&BSqS=N2;V3z)6-z7&|?u>1fD<2n6VJN`G?6C%+)S zsP*V&A3@ycN-YI;Nex z7192)Nc({Ntw{frsUfWm`5O5gIN;ujc<$%X?c7@t?Qg`ileZ$;e-Ygt8Ap+yjA zlBVJykYOhI|61!v8H%Wj>| zsj0BH)vcQrTz276`M<|Zm3Qw2lWite+k~mrwWj8Vzs>pWuA5^y?xQO>jyR_xCmyG^t|9)s;=&i!IcJ6T793QxtflbtTwi8CVe=XM>n!>^=va1QMp z;+$xH0B^^Eq!mO#a*DTc&dEolZM&LaLhc2wBP<%>Ub;Y7WftZZ2xu_qF=C8LZc{b` zvB_kBxSxvyNZC89ucRo$>m^DXM5<1+$d;q!M18X_5=b{W*a>f8PGOqAw!YiFp1FY-s@IPGOMsWfgQJu zj(%+C{(koCJNF$ue4wp;|KX!rXtb(f^Zf@exNmc?vL`(KiDvebrn``s6d8pX*f|Ms zoXgZ=XmG4s;o*Eeh|R5%q{Q^JM0=9m<}0L%4!g)fdf{6$k-|b^f#n^%{E7qLnPiT! z@$oTOWcy}j&JTZ^UD>0m-QlxQqb0!ssaI=Z@gu3D80L{G2fpFn13%n@fQiX72aeZRBvi&bjOuW=LGCcn6Z_DMow{6?=fc*SD;jgu; zYU@8aUv+XxMcHqxGZR9J4a#7Ke$Y@4<7kEq)DYwja*A2y21;%gM`539n;3Z`7fm;p zt#@T6lWO4x%=tURCv;)cJy2gb*C0pim}?&MzNpI?f&C8y`*!HeI<-2DL0uxiWPnUG zfCiAB#4Hpm;4YgZBPS~(*O7||N}8FwZpBEw^7w{G31?c0xXs zihMQf3eDruX$T`NDqmeHmG~=tBz-fr&^fSER2(PQ>MW4CO?rIJ6+F0Z!%XG6w#j{6 z>XFgG4^$M^EwoK-pPb%yUY~mDxMfR6Wl?vVuQDeky=+Wvo2jp==qNAgZ*OSG$n+1j zw{EQ?eamOcG5U~(QTT1E+P#SD{0A0hmLFnUrF;?J%@>~E${rrkd`I4H@BnAjvsdQr zyoVRL+|?q)99wN1TbLM=7z8}RmABeO+q{CxpMZ=$pz@uH!;VIvOe&E6I z=YZl(OK0UP8-Rl0~ywW~@@8|Uh8x-UuDWJnW7DKvSRwHAUP7%-KGhW2)1fJ-DhAq$@xZ?V+kwnlC@xWohLt;= zlH|;H=H+DLIfo~sNGPmj_ax}1LK$;0syxyg8r{g`v2WioIegRhogW>M^R3q$`oL^q z)rW_!I${ntnl9TbzqIMpp$qQcyz$hbviDy*)lpu(c<}nGj^2Q2BtdG9LHe30LPN?y zD;^@-6GjZsCyFmg@IhI?V({9S;U9AMKjaVg^)15STka#3vL;5-Jka~{JZ$)=aw&91 z#t8nQOf9dR@tRYhnqukbRv!DuEw@bFatnHvKZvyaQ^?Z)qmQHUc6T+28ERY*3M*^KC|W@&T( z!L5UVXduztN@z2j2*e>U9I{dlN<3S^N$ztbn>A#0#!WSI6t2!P3!Kubv3F^89!aeF zep)rPV~<9+pNh0^h-rU7!_pMA+(*!lO{Xt6ilP;pO-i$S?Od@H1u04#6)yhe$0qjd zo|~V%x=YHewk>0JkozGp1v5< zP8O8F(^E0+6bBIPPeivH$ZMl^iUVN&upWp`$6UEo^M>cLKEAqH<3)8%T z`mQ2HBNkGIV+XI#NiHqmK7DIdpdgxL%Y03HlGdxpk458w`@f<+2G0gHf*;-v{1BZv zenf-~s{`KTr?5*+Qm&eXGAM+tNfzr43}hyS-H}(J+IM+wI{d;w_=Sx~k5Xv-`NdBX zh9JNU4d_F}+O1lwT|w883?ULVdaRuaQoTyRZg<+1-%OnC`|gXq|6Ko_?{}bf8(sD< zB89s6usp>UAEK4>zB#A9%2)mc`B}cxSGJ#yX{Vhl;2(@>CkY_hAEtK99eG-w6H27q zkJW^*2b5%NjtOZ39=K;TamFz706W4`cmC&3cd^uPc-KoW?PUAIx3a4657_~>HT+9f zfS#BBgq{xpD;CMC7Mh{eU||d*m&Z3acZDzki)2Ypr_2(g$T;;a9}2%Y8GdueFMkQX z*c5()x!GsKpJv;UC*wVGT>MPnf_5+8?KO(0~qRRAF3R`+&M_m7k`+IM1o7~siN_@ln5g<>~$ zyChLHf3_1-O)v7I)ECMaJXMe|dO5IKW{FqwGX!Nt7? zEjbxUI8g#oQU$;zpRU-WloVJH2j24L$R|^G)TOZs9eCa#Z^)Z%U6?7k7AIj z3T0$YGoSNhnE@a9Bf0L>NMm7vT4ShE}U(7V&b|P%`S0O{h+Uv1rmMR~_e3 zWN8+7{M`co+_~y8BFz74MC1kD(>%dU4n8VBAyEh~6nes2T}?Uh>Xz!}V4$MR=W!L} z=PhT*(|swhWh8M1jPgPhIPexlodR=$oGU0Ctx_0kZLKKC8sBtXT3dN$UcSSTpYOP7 zJg%ORTSMjLt*J+pTeAwvLw6NqI$SPCX2H*6v`_f%Rg{)rk5Kw6E>l+Fm+1Oj=DECz~(5~W`ByGg3LetCrT+?e>2$FFWyQ)-vgWE#`P4I9R z$FRWSjeDA!_K?vtF#!S8GC46gG(J8gE1J<$Gb6td{z`3qxOrh_>+an%GblKtxc^!9 zGI%Rj+Nh?|@gQd++<`2HdKyiHWMYPVZZ3)eL}DemD7RewK_Q(;K#U6g=?B^}^#og- z18uJ!2(?}?7?^eC7WMl_HfVIwKOu>8hbiU$Nag@xM9`W={Rm3M4gVK zEXsR(@?Skyx7L{N9VvvjVGAFQjdtEwpW|1S>Ktx33VUEjQW{9hoRVtDbz#hmv< z!8p6`MC{(uA*eQviT!yz79!$%3i-Ns+4qcijaE*%{`q6VsPN^aZy%(nU6TW3(LD!k}4`AwYt zD3La)_Ed;WHkg;2lkLpJkvv-h!^tPo$Qh71lmS?XE?~)x(@dEeH90>&za+od>n=ie z6=n-JR+eiNig=L=Qm$mkM6ZFp)_CQmedmW-_VpeN+K2DAUDq<O~WWwq!7HxGn@op7{6JK4~nt*(T1iie%^xWLsqFlcpi5|X2ejJ|CJW*B>PI@Ef zLuV)gRH_7viR*Luyd5#?{Pwpeb}UKyLi-kl?%bU1{y;J$06&4a%3~#|=$bgQYR})2imJT*)7H9!{ z6S}zs8859$4YChuC^`_Hj|1UIbgm7+*&@Z^aO6629Dbh%f_E>2)>Wncpphpi`2<_)j~TYM0J*IF;@9x zv&G9yX2T#(Qm}Pacx3#bB#Db=a@Js;;-F*#NL?_WY3$+J)Dhk(l z(0wR@qGWM4_uEMK{YxD{1;%thH-r339mLK+ZCG>m$ebb>F&A$U2Cfi2p^zknIzwuE zTT?@2d9mN^%7rXVPfNiuO)1fzfwMo29iE}!MXYEL@cj}-6#7f zj;8V3%Q{4K9Br9rc^nP70`RWhS4~9o3)JA(XF2q|3;%FMgYimG| zCna{sz40L^j;28zTLXfu1<}WG9U{t_AKx`b+3vE^|d8q;T6HGO~FYCdJy$1&I#XM{r9z-n4?adBmFg~MO(E%R_?zAU#_Wg#h2u%;w8JF)_$ zIIikV^VcfIenJuIgZn(Y5* znhdsRn#^Fq38T#gqb;^3MR)f>XY%&db3$-aF2jNJ3n{WJCzPe#WA{fYE&1}}l&zfq zq2}{?_g>5{lBXvprt^H~Hw=#?gnw#U*C8u6T{d>9`oSY9vvaMXLSML^q8p$LkXxqYW`X{Va?_%J5SCiQR%C@N|>IL6<~`0u-wE zaXN~;zpcFd@`+u$#`?YPye#=-Wn;G*UdNtPN5&?sy_BSct>~6hfI+HLe^pJ*OOZ`R zm;$)FLP7{xi%6MKX@Y?x#sHl#<<`IC!|7vQgW1PEYTo zFRlv+r(}BsxP-rpePfk%0thbs1jL>13UOi$i1f%PpNbE`eK|48@iibwJ_?9?Vj;kr zqgX+h`x2-rNd;4&*h^7hT%#-sg>43dOE1C2wo1q8EW4MV&XRc98MlPNlRVVL!V^uc zed{MCvNku%%D2PcU`>6U8`g#2Kve6SRW%rB>Cf6|IZ{Y%a`Mqow`69D#h_5pFCW)3 zYh@JjriucjG%;?Dlua9f#!f&jR_xfCVU7y|5pL7xFgrW({PU~k(FY^E?Ne1XpyB9J zIbXMjwO{~6{v3OnXT^U_GgQt1V`zt-I1N8J3$-DLUu6mXFuF7l^W-V!MZN^CrF+@mVR?#^(9ShZLXS>RGL-CKqE0^NBhlw=v3(+o{{ui2a9$J; zcdde;6(vUXabgw3%b58KQ4sg)5V~!%^gn=jn_CKElwhp`(DHVYD1-CX-PMwo0 zAv8>qwILurxeDS9JeexfZW0jp#6n2&(&AFH^zW#iRKPRmQRR?9!Hs?f%Jq;^FO<;3 z4E!;w*3z>05V1xh7q)a4mzob>0+%k##e;+rS8?l}(_u?ZNj8gHp3Jbh?GA6yuIXz! z;~F`y{lM<)OKXDNWyKT5in^l0JeT~^wr%fx0QoI{YdZT`*jnW&^w@#FA7frQToa3x z-5t9!K)kTzlRn3}dz|C%IBp||;cgB=+?^zO)k4%vF(k6+gg0YQEl@?|UApCAZ+aos z2AKkNyvT{NhjCf+@h_pN8M98iL8j+v$#tBo5 z0x3esWkP-|pZ50ipggYYlN0xa!xIyKTzKcNe}!V_2yxdm@ZWx-$q0b zqhMXD&Xcb-f@8%9?C-z*ufJ$LN%vv|eg9{!x&JA!rSJb7E{&!+*1rI{L`fs)cajh$ z-lv(cfYnPlf=Bj@qkulmCO#9pJ-VZ)WEDi7`-^>jp=keNgR)uOmdwExbaEriG;6^%a3IS%)Y)DHx#sLmnY) z(%PZ5C?>T33EW^DS-Mlmp;g*mD-N&&Qkmtav`JeDl&EVxgcT=aG?>y@a2zv1Tcxg~ zu{7tlP>iWSi`h~eBo5*;=KFsK=1w&~Pe)4}9YQ`Ud1UBr*pGnITce)4bMpW~=!z@ZiIrvH#?C*E!1{6rajPj*CyWQ{Q7x94OGDygZGU=5Z$HKQ3dU7*M zD!A#kOp$w@u=H8#d)c%w;iBn+`y2kkH36{1PuH&#*izQV?rdOXLkylD06rrWlF9Ew z55V)?v3TZQ%UL-I_@s08qrypXl4zU7h^`?NzbqfN&jmNe`GhCN)8m}PUru(4;|b9x z@n6{=qUbySJ~TeLj)L-L^^&o%OH}c_dv12y{QS1rIq(@(cO-E>JD;!OHumU>^>YYr zn+b@!;zLCBaUw2+pT~+sA1~_=x^0Ge3@p!s$DJPK^U?c?i8}$3;!dKkSK{>{?Lpgcvc#QaajLTLP(B3}XSEtZb)yv*wR z04S847keLoOWc7=T)tedur>@YS18mk4S;x|dj%k{qq?Cm2Sh?%US4rtQ4!r8K;ioM zcL(4!E8QIso#05Rt*oetYzbSQEwQ$0;C^jq$Q6TW?gM?1&0$dL+fs8DUth6DgdcqQ zntNmbzVsEqB_LK%A^OSqR7l|#z36)d6*Nkwa5*C&?vABX99rM5LqzQ^l0@Vc2wHzq zhlu3{?iC0K;!(1Um+!F={6fAFAi&KW0=!8QBThsyGOyK75EkM*!8xv(b2G(xaP@Ag z8L>c=3i3k>=rf_=aXkZeD|no7012A}3m~LS=CI9s;2zGNBB#O%R*S zjrRc$0wxu{x2p<}9YoqM6WgO$!TGf}DzK*JT3@ZdMEvHh^M}7v^5ufk!O7oFlziD$ z!X7%m8|%t!&sRO-x7J)W{G$NtPMx3m+T85cK=>;uLgHYZTnl_SW|ypx+?I$r9b9RkGqLcwhvfZ3|snpa-N9tw?0cvkFR9DP1XgeOFKi7f< zkny2EZ{9*F()O0-4q=3}H#c=$d-%!q!=sbo%jRZhc9TH@`xo|B2`b~r#xInPov}q% z#!*olR}it4ainM{)JGyfR0HSpjn7XGIG4|O7V1Fi+8yaIK$?iF7dnt06wbiP>bPZ( zN8DtfU4%sSar50&A4gu#*7nfE9);EWnanr$qsF9>mnHLb4ryM9kg%Y3I^@z**Ysrb8WZ2U+& ztw(uEl>E(a-MW`Ahhp|6vMoYKyD_T5an-pDs=(p$4s;Z+g;+&Lkr&}WSdRAYh_yS? zVOG&GqsWU?1kQKxBge7j5sfisgUvFLxk)?X(Y7TsVMeR0W`FM(UHl5Gt*R5%gN=dh z%f~!O?~u>82P?Npw+nHeh>fnKK%_%fXdIfz|73&sWFS|K2B6DM$f_by&tp!a6p|;} zs4zre1`#v_qo6@JkX8`0#v{N11taLlsol$Ovcatwqz0B5m`yljXTiFDVp;q823au; zTDEoyw|pkRYg%blALR1={gSq&rA~h4v7m{)g2AM3$ zT7^lJvZdMT*HTbLYD7IpK8RGL`X!&QeC3rD#klB0yc|SBeMY9!$?XmA`v!AM*Vi|P zN~)$idiQM%ZZFL3pJ)jAOQ-vK_H8wHwif0U`wM&t87TvGT~nUIP^i@J@+COZx*Ix2 zVP)}kaNOOg(dD)kbP*5?SO)|wx7+X&=~YAqYNQq^jbi&2${xekYZ39Vm3`icC}LEc zG&1Tfkv=&D@AEdUceQ*0^+~=Bc18748^?FM^q87oS0Ec#)WI4CYZF3!13T(^QRkOjVo$dk#FZ70jq38>u#5B?D`>m%5`zL# z;1W!xXwNd5Hu^ws$%Rm?95 z^Bcqb@}(nGrH_l65e1Y7bFyW#Ha`z8ltE0MF5$xIACt*ELxmccsaDH@*UaE3fwz>Cot=1xg0D~>a1FM3$9kavaRE6FjS&=BuT z$QM?UjtZ}u5PoGRasu{A6_MeB{kBO1& zJHllj=NP3|v_o<|$cmP5Ci@X4KehBcsV{mK(l7eiQ;}yku*;(Qe1O`4l_7B9TgbTC zrQs)VUnVd4q0(kM@(|o;qiY5s&Uk)Cb?UA7o79ysbm?3agenz(l^4V}J;bBaUthbo+Dmny@^9qQ& z;zLCBvAQmQ+eMIay4#A_QVw7WXAW(}3ym=TPcr5J+PNS85->N^UTYB0WDWWO* zJ{b!kXd>@NoGwq=bcSkwB1FOU4{%VffhHoGJBBiOF(0iW4~gD9DG#@lcpdyQ41P_C zR(KsnBVzTSyuYI*id4?#I{Av6j&W6>*4IY{fho z7h8ZJY>B>CU`rpJ$7=+{-Ld%8c_xY@Zr34J(3>KUf+nBTA!4bd&HYl;{Tr*pIH1`qk9XN8@SLibKW+ABT=VMTXii3X$Ap!r;R5e8r= z8^Sfnbod}5_(b``N*D;o7#P~)*%Y8LNw@)B<0sJ_KP#Lc`x(D8D{8+(XeQufu-9JV zj(O*ys0WK?sO1U?+3gPmyDN&9g}{WVG=LYBy6F^fajUH@Rvv`KL12x;P$!D>zZ!i$ zp<{mq1u4%Z=(83VP}EM)heK#GCWbx{UjSYosPQ*oBIf25Y(4JDMs8l=m!+^LCte$Q zdHVD0Z{Y-d?E-ysAsA5QhAIuZ;XL}*l}I&GyjxcScKM&%NO_slu^n_|alCpR@7ivw{YJ_MI>qK{)bL)5e5ri2&2^)06S&zHVL`Y35B zA2|Oz?wik3vy-ew7%lxU9#DzHtJ9LD|Wv_-ZRJ9cQq+>a)r0J65<4l3&C+F`Z%UTL~zFY z;9iD+IIcrPB#FL44+8|rLfOwX$I8)fjsGNpp`<)v!kv+}RN ze7O?dx~iWJfrp370%j1)7VpH9V7r1t^*7Pv=47~iyofR_f!qZ*{Ilh1;)Vdc2RiHB zh@Vfh;KZ-t>G;{dl+zqMC3G^ z;H$$uH>ik*ToZ2r5%=2wp6VoS=lBw<7B!N~t3JNwstedBm{ z7qL%F_x7w`-_twYQd?bFS65kGi!lo^FmBGG^GlND2^?IIWW10YmoEpIQ*pD8v9iSl zR_6T+`vtDo+E-U6-@a?{4eZC#r9s(^=aMATW2ni(GkANfL*ch8v7qb@@B5#(*ll48 zOAdn#dc&uh!>9V%*az7)t$4Z#qrNWxKyu@0*aS6{kEYiXMa|zyZ!3x%4T2x~`sSH0 zhR<%@{-H}R{m}Mp;j>?y*)nxv&z?IcS?A{`d%LC{*>K^NM-Od0J=N7a`T3cd8;6E& z#G44omnh*jaR$c1ku7@NxS*mqp|4#YDBOUy;)!TKAomaQ_jNx2JsDw9j$kKeqNh}b zp8RGCO$NP?`rd{{aeE?ylk$kUYIe(~Wshe=uW3Opy1cQmrBgA@Y+bzi6*6{%hoebLXs!1wn!@i}OZ*kYME=4n7Nznaee*WGldU;BK9l9rc z(LKk`RQLAw%K0;67ZZN5kCB9X2`i{kE0a-A0hWcBqq0vPX3Rq!BAf!yg1j|+cS=rQ zF-j4gxRk;jv}-iySA&XRky*|UH=M1j>gm|C+g0{~&RvHa)$jK9wzG_;EtR2;$&Qkm z`3-Fs_Wcy22SJlmjP94_)U>=@+_&L}P_SB{o%L`965nv>#igzM+>Lf=E2hFviJaqe z3U}cme!7MgsXV-LVTJo0bqj0M{Mq-qj_&Whs-kf2{Nb_tCcDPg_tHwruk6`zQEQNG z+tfXCepOk=WKY*My?vc6?UNm))w`zJwq<}LYJts0PMc)96+0RA!)8Q{JF^B^D~5Xg?=gbEHg;#da4$A%f?(D(&^+^Xle!-YWa z3doU|%CVh?Y5IJ~n-MBS^%ZU-iHc>=3oqRc#4T=~ZwMV&*Lk$uHMe(YdVSxXwr2KV z__LvH?Ahi$-Q9bet4lj3r`PpwoMNBq2{!|C4cJR1-~>AB-Kn-yTu{#DrPuIU_*Lt8 zt)>2=0za6o=O7=fSX#U0r)akALQ}hqi#~WhM9Bn%dkIKDu$Bf8(aUemcS{ zb%N?nP{SnQHbF8hc@?vM3B9oE)A@~xctbbyGIu9?IsE7*yqg>ErD|I|B3}dDOJ}9z za$q1EyP;N^P_5;8*@;MV=|!%Q)Qh$y^(v#~oJ`aQoN7r$MMbqmHB}-fqjNtnvZC(8 zM^&rZv1pDQ+%QARko|1rh9gIA80%GgS`YN~9cb-s5C467U|@O*r}zJ|Wp-?AcFTIU zb*6LcdFO5I+@5aV7;2ubuAXiVZM5&{w^;g{Lp?pAa7|BVi2e$7_5e{*Ehz29I;pk_ zluiSY`G%)r0@ThU8nF<`_Qve>JiKy)%Ah=jcs9rH_eBnSQ37APS~>dgPz<5(xas2` zY&%j}7}!?5Z5|Zv+)acZ0*#?od*zoN|I8CFfWYO&_uZP@)G4SQK1w7eQp5HsTzZFX zWnaV$|H*A6Tv5OV*n{}{ZT>ebZZ^R`e~14~@I(CXMe#R2U*Paz{&yul-^Bl3;(z<_ z_bkD~F(Lc5ocD+Rkvyfp^YQt1{y6~fcOL%U$p2RG0BiyLP4gpdbe~A1I_Lw4&xPfR zOLD}APA9_Liu0jJveFUfI3J29Q{sQf&+W&52$at)yiQj%{wT?>*~jJGwD7JO&;7b63k z8(UjjSzg6p5U|*9f^u0>ty+}=#g_~vNNP~QX#^azlbN_#Vp$2|Wf%TsCD^F%o+vG1 z#!Jb5bxTf;&z0Mems2oa+CJbZ+1J|IaBp6XGvAe!+2G7m1OD#P3up#9ulS`OsF``V zdx~D#$yFg{LzkKxHPN06Q;%NZiF?MlR$Rb3xje^)*XX(?h^U4q>aGbQdLbIG2|~TB z{VB;EqIZn$1UDVxa8RzpSQ)6G>S6+Ty}6^JWV`~9vT)R#1M<~xH`Zg*FU z$DQx00{S}Yya5WQkQK~#RsuZyb7)=NG>WfvaRdh^ZvsKK(9!p`7hAu6<;~6O*9Vy= z{L9CPLi%pamEKWPvY~Nt-8>5PmJeb2bX}^yZFX7tt|HO9!!Fb6-C>uB_U^EpdhZUV zlacg3WG&bG5VxyMC@58=d2mTPY5k<(4P7PUx!KLFCDm2F`r>ky@J&w*OB-zK7zObv z%lzJQ|J$MWBRwhU($0zV6+cr`Qkcx>eiyvk+pui;p&$XtP)g+p3m~HR#ga*i<%2eB z04?M296-y+I|mTQ+BrVg(Up;vB}rM{EKflmgm5OZKG7;lIC`QA!VEhkQ`fnqYHdSP z?IT-ujrxZ2vO^6uO)Rb1lUZKw^Ho;*Sn9g=j*-24FFc&*Y^WNU$Z`Fo((kXR@cS#V zdRR{*YP5`X5g9O=RTE>LM_(4~)#d$Qd{*ST!=4;~HpJhksJ(^H&lhlQmO_8pf^ii+GI!tSgp} z3?yzSXY@K5lD-RgE#m<9tMK+&-RI?sUShk*p;Cr*Rc~LV>e*&p*JB(%dYa(lz)BP2 zu;p=R7DI?{`El>gntGUy#^+&D_6pZ``FM6ae-;mmXB7?4_%sinZsecBc3su;Id}ojYP^6I!R}r)=X1~(&ua9= zv#`lmJzIzs{r?JAIAyu8^jqwVUx43CkHJ>0DK{50=S(a6OeotUzv>};E&W!x0uUY< zK`Y5CXR#~rQ(^DO*jn1>$Kre*);=%9^Wt+vuA`pkpJNZW**KlG6*F$f@?{jNl0#}3kytzc$Oxm&FoqB zEY7dty}lfNBf-<%t`Zx=uk>D68ml2H#!2smeRX|Z&H6yi`nuZnwVSJ_YOAK|sweAe zCvkg%j9EyS#UC&Wv(zeL-q3c82MUk^q2edVGQ7AZSGCh{peOExiL`D$13Qcd^=Phm zjU3GvGycQg@UO@nlGLS}rO(1M;%_5HRRv|awC*AM(W6zeI%(F8l&LSKnCEBn+(pI4 znuT>`eeV3qQgSOWOZfqz$nu(2oNh+uO+hHxyCr)*XLw=Z%k&E7^;jEvTN;eu4z)g%FQC^Q zp{!|Vq-Q79ie;l92`ZSQ4z-Wd8UkfygdeSpIZSQGc`0+i4m^(3<;=5d_wHRE=COP) zh74iuxsprjS9_8ZWort~tDv@MPg<&3VJ6@N7SVhXZgtM!=NUmY9MW>-;bvr9P?+U} zwnRac_AkwblnwLJ%FNzI{uK-W`vIIZ=U)mM<2}kWxndF8$GJ$Q~28S z!>UhJvH$#i=qdaQ{XTRW|H41{{qH$ngQGaD?EI{h^U(Ik`dUnUghVr(e^18C2#c41K=9ab8 z4gZbyMS-+mO@Qw!!w2T!OrkT+)WRE=F-087H7JJNRG%O=4H4WE`B=gSobU=x3v8ri z?BEZK<3s~5R4Xv#=ValsGm;c$l1Z4eOtE+@qY>D`4vyTTgettJ7w$e#Rat?>)Mk6~ zyzbWe-ad7d*ktk94Sj*Wva;^l^z8D^s(f#QzqGD&&`v_--u$>=H78ya6M)1Wg2=^( zmZk5qzwmVxJ!0D3qsdSqbGZy1iCXj{CaK2>AJW2p7YqjR^ls^g(sx-cuyRgmy&JNx z7Uv}qQ5~Ms0`_|GM1eD)+epp`HO(F-~8)hSgBOLAQQo$iwamF&E|_h9k=w(x8sdfP%9WjHL!X zO((0(EpZL>gz5`?6$J$qzJmIYI*jvaa7rwtmCtqcb(R)?v!cOb4px4nxJ>Que73UG zf-w&QFG0-3EO}IyBqNanX{jq5!FbCrTXT{^!PmiWUvkMA<*2%-bP@(Fkh|aKeL%a5 zb?nr264pVgfN<)h@EX3pkEg$Vrc+*20lOFD7vR}siKG*#LApBw_JD&FE>D6r26(91 z={?!d80u-Ls0eoVymsW`*AHF!^7;E-xr$~`h#CBt_agR9q#JaG(v3_~Xu{Jg4v2G% zg+cVw6KZH^J#*D7`_6y)%0sVTeB`ymG<)f<%3oPAI7`>-Yw%<6g&G~ zpJHdVr`Ab-l^yTpsYZ;oj=e~a{cmTuPWo@Qn^nF0y2Mzy|J~gUNu@s}%gx*pT={p7 zw26J1JqJnF4$LX|{v?OXMf)k<-oe{Ds2y_$Jm&EnLX>{hgO~v*j%^58y#mQb$(T-5 zgFzTDJ5OGF-O$xXH$C>mYDsKbm)n>H0AWvYi_?ziGL(qZWd5v>r}Eal>&p7w1!dfORoNfW z8@=fWT*vJ)8f1q0!fp`#aJ$UD(k_#qhfMYqkYPr%`v1Vblcm#fUMyN}?rx&TTVqA^ih_sOnyH{@Z&eit4 z@53Lttgm*?>-LTm6^(eqmu{V$+&by4HXS^e`s_V-Kbvy!psCv1;Vv^RK4mI%Z@ME* z?n%Ala%i}1OV^_+_%QNbg*2c1Jbt}%TJp;IWUrb}Lu5jjPh>iB&PaLh_6zH0+IuTT zvUA&7TH3-dsG*k5mTb52@ZrQ8&+j|bXE}VK(Vf#;YYty+u5I3#%-)wW2Z}PuvviF- z1MHNcN+ln$9>pjZ7iHS57L#POrGTZCK}SYfs)0cb^Y|l4RarSmSMhR11N#a6&@q1g z5(v~sK_rxe8Mji?H_B!*cKGmo z`AnI+^hiUwFVI|9nipyrtm!_wvAnCYq@=N{Cq2boHd8L&aMz7D-d$eOQCe#~nt3$S zbv*M+TR(Wk2rj*i%F+LeoN}eqr*`9g&A7dp<=T>Em|{r@ zc-b{n*I>3Cn<0^W3upnpOx&iU#|7bK6ciLx7F1ML6jOx&LUeHTA}a~jlM4tNQoJL? z#BE1P%TlloZ;!`u(_mS!aJY23v$3o(5NIrK=$xMF3|0gK-yEx|8mq1zt*RQWesQd@ zsjMM8x1p)5xqHKg?&gZ-hWf^e#@-E2)~>IsTVE@_lT}p-UM~eTy`X0;a^;z|HN{1) zg1p=;N3zwDOqMU~UoE$iN!|olA3Oa5eQ`uXLFjm&@~T#c{ut~d4JByby!lLy!)7Pl z2rTd&L@7$7Fl0_keJd5)@b+d2?LY#*o4VK`mmc2U*NbFy&CcfDEp3gv)V`MU{H}F# zT^n1%^L<_F05f)XwO_bD@!$bNRcS|Qi4smP8R=-;)Mz?z&{*Z~=t~U0l~%Ma#L^qm z7frp5;cg(Y)k|i_3};d5yWbJB2$*T6s^zua4Z@9eqO843#N& z3{GT@2SYOr!R?{?@yrt^CI^4n-{0LiG_3wRdq55>es6PCZQI3TV~0aEm3K97+qU?_ zxs4m=c5d9X`#a6e*y}0CL=V9yDwoF8VVv|a(6MRUdWJ-_0WWz0-_PT{bP0?l%5cQB z%Rck4n#4rCh5~!NT*5+%i)=Q($ChDB_a|c+K5YXR6~iXN<|SVb5r3R4r=9B|M-V*k z#1Dl2Kex5iReVwNdDmp@n`3NlU&gh2+YXevO1D-WD>!|Iu`{O&j*d$sz1=0{Uv5ox6{d!sA-Pqw)GOB_a+xb_89H4DTDm}N@Hf9rmfv4ZWrbjEQC3J+ zd_D>c(S$b?q9$bptp4^{B!6&##f>k1`4zlA%o%mE!dz{no5)}|lhMq65KK(E^7>ur zI|u6nl?{nIF8^?H`i`OcfP6y@Y`bvN)MR%}1N%lOG&RvhGai6@GXze|ls@xB1`1WE z&Vee(={j7xOO)=D)QeUSCYVK$03Ekdun3W-Cf~3$4lqBIh5H5hHI&N_#D!f3Lmei= z&1<}KBrt8DEZ&7I9C*8%uB~L;GtlZTsn8{WP23QWhZ5EejJ+_97dAfd!cg&E_Ez6i zSNKiVA4X+f@84!O@1WJzLK0O$5_zO9wF8Po!8_X#zM%IES@1ei)HqVEnaBWDFX6&B zBi>StTfH_S!c1PhfsLg5inAO%@PhiFxN2D|VytTndfCv=JUgoUF1uc+<-)R=irt4V z+}$#GoLv-t%ARXDa4_Y$d+z>9s?f_N<#*k9)7`nR)2;wr20<5_RIOH^f(a4X zNQpCpw1;$A}Fn+=aCi;~tQgs7m``BzYAp!c zdA(#-s9GS07^0Xilf@0dbmgwYmY#%N*nk%yiL%5Xro_Makw&oz#f7{Mu&(1*EhUPSR0yY?bxyx8?UsyTWxNg3FQ%8J0L?E zm?~O-R7;AVa(xtl}UDZ)9`L@On}|Kt#+cI zrJ|?2sbHdZOJAS-wQIvKhX3{#X1^>c{2~h^Ul#tupKz`)aBbqD3(z%j4DIA>Nmbh{ z%wlzrO*EK@_s@W1EcBiNyzq_(%;?<>B#3yJlfq;fbPAF)5iaGRAQ>l!R{<00Gz-|_ zmSUUD&d&D!b=`LS!;e{Z>-NywvUBlwZ-=&r&My8^E;x&6(7WLcpO#;hdZiKevN#`Y zZ$-Mk4R;il;66%75h=kycM*`R$%tuI23uJ&TZbFT^kxe)Bv>IO4dN61f`Tr|oRXAc zPCA;#QY9rJRhgGkQjGMf@5~{*5=@qpW~HPgy!4HJH{qbbLM66K4NqSj7!b>mu zY(!6{6tii~o=h`I792K>d0b@s=Elm|=MLrMSfS&HQdF)<41yV)rAz8=RIe67F3V3nK z60r-YR}#tC(Y6e19++F=lx0!zvNd5Qdy{g*J|1JS1q}5g?){q%56M}%Tel9TzJJG- zi3cyZQtq9&@x}`hvvMoOs+-!KP4!zwYBx63Zg=I34%UTgdlw%Yo7%8}B^A||s^iT; z!}j$oX?iC7w*2ZP=ihlJN`xc1erG{uVn$a}MQ@SU6$(}O-5y)TXQn5@j}x!z z`zBBFO9N_e!ixQpgaC6gvM7on2@HleQ_SFm03-;oW*EjxZ2b8?TpNxzIM5EV!T3lM z78F9y+`s@Z z+yXdtq)tId{x1pYRGfH@Y;z(X#lea>&Ai@c9)FzA?9D@0Ty@~~8>Xf|a}%rC-g4qZ z%k~hPIWW8ZV5qO}V~{@Sm{uQVEDG~Eon8>1TPuxtZ7}`jmitas zB=4J7=B9Eh9Cz)yJ*TA_ciZA+1(MQHm%=4e3hg%Fs;_6?9!_ zZ*#pp75q=LYJhRzVI6#2^u*6$1Z7V+13(@4T$SqOESXLg;q-$- zpOZt4fB^jHMmg)b=PLC7*&EM&wfwo~%D+lY=&wO4!hCVjt3+8m=w&)Q!)<-s){a;( zFQ^BIAXC-mc)|y|4{cHfKe6O|M<+@>~6B@9n#qJo@}z|gpeLeAaoLH zLI@B_LKU!L!Kc`JdFr!2y9;7(C_W3KPkpv$LBQ_Ur`Q{2f1h*i-OVNhME$?-@Auzi z?mc(aM%0?)vpJuAyD5Rq=8c zBs&M%mKhhU=zI|=bZAb+Ols_SjpnIVS6U4jqT<7Ab8Yy@Yj&6|BhV3Emz!9bH6kk< z4~2&fk=NxHMMsB*CEMci9mAqRLz72*c!&@8*1th}U8rR-uQp{32Xnz$7D4A&z-2H> zX*pZ)njlHvnrKPEr>{skLyJ#`Z;(ntp^Y=O}5W_F>n%R4-^N=u3v29+RAfAPExieS2+H8hACPzsn!samAZwCOt? zEl_rRGGyMaJP$g9mv>OI1}%MrLM)`~E@ejKb8kf`YWv z!Wp!bEl$P>#W(Q27)hLwMkvhcqd3?~CX^II@+&6$HS)g1xQHn&^|r*=NZiy*e)X0G zzdka7KCiMs)la~2$N$~)Z1jfqzjb!51gHFxF!SQOVE5>=3#4Q^II5DG`|fB~&mKHQ zD?9is7S{jli9pR&qMB46P9eHWlF1qvG>%a>^?g%wY5Vz`|3~#5ER(xN_jPF4obPq6 zZ%(xpvnlPR=I<=f%Lv)~F+Q(g7z&}?G5mdnICl`6qc9BS!Vm!m>-zKv`tD8`EXu>+ z=^s2TNN4*FC>vDX!=NYiy*FVv_$pC4le(_LB`Rmp(l}9M5IbnR`25+MSB+UYx_WtS z@wE8REemrqVlSGVJwA8Loa}LVn$OH#H{N=)tUhkqwBxHY^3OT0%Ji#!&Em=#Im;J} zo(*ZmB+BqT>b0P5;_q}$#vyi%cP0QcIBF?;O=jOE{?Y`+q@M|#4HGIGhKj>?yXnh_ z0T#S^}82oirLygDr-BQB0Cc4s&; z@ZDAYsE+=XaD4BAgcvJ66h83CYdH1|cz=@7_=q^8+1Ogb9OS}TvnEfTJ$rI3bh?;CU0K(t(kw6Z)ylt;!l@Adfw&G24AcDm)%;Mu5ZF`k!gukI2?t_) zh{V<9N0E;4t|zuo$(kGYCDqkMMQ;38kFOrrSWll5uP8f0Uqt+lzOZ?nSWWTTw{CFu zqv<1AjsBxP?7QCGTRYKZg?9T8rLqaCopRh(=|Pu|kB*G}e)_vSQ`_3-{yyjM2@drOl_dV0WMr zg|5ZgF<3vY787OUeYP-#!D_5B6_Wu%yqukgO=TuX2EHb_L|Cw{V)5&An^VCHB%7_W zT6w=nw3Ws(sf!AZE-|Ge9h;tz^yGiA)ao+4>cGr_^~9qu7^{RRmkt5N)YJ%3GqGmE zm_}e?bXZziY6K2wrjeS$$D@)l#274IhYV(D%3J5Man&(5;Xo!YQ*Y+g!Z-xqPdN%6UhCQmxI zb?zN&SKd6kAg5`H3>no?QeHW7o?~P!$wtMlAJi@CpODvb@jkGjdRRKto%a01*q9)^ z>Y$f_#&LL8#G)}7IK^fh4R2sRC(>&XFQUf5ay;>I@MGiKcSndpin8jkyu75Oypp`) zq}-&OVcBU|^~g?vW?PrScvBmrSXZl9q8V$D1W5O#qb{rzaY;N=lUj48mS-;?UB9G! z;>`Ti_Lgxoswdx)uZ>Y@Nqt|G#AVhN+SA80Jl0q-rD0}9Sz39nJ%3th_2QzEvFVM| zCt#K5lg}zq(vbzL37M72Y5Bk2HsQ7G3HGvD%=UTM3G^)_kzkQrZKL->yn~)d z>gZFT6xSDdWHXk~LPN+(xrwxS$)WCVGCSnA_3P^^XB8C8sr>amt>)n4@=M3;ii%kd zjI>Pb9sCZM&ljWVO(+S%etAK1j1?cq)1bM9#Um7tf6qp+IITGirXf<&NcyHTB&2lm ze0$Dg$C8)aOEJY;jCq}nmYSo9=wOZ^o$(kgzZ(%3);;UEiLu#}^2Z5eoVcVyzF zuSmic0Bw6y;9!snU`xZtv{;y7DO)pJ7Q^Zj-v4Lf28ttlP_o5lquJV4YAY$Ulb$tX zL`cH0C}ba$=8w67UX2D1(<-c9^NSy~KT5aoK!T7POU6fpW!cU1=ik)Tb<_O$H!o~G zZ_1SOT3gSbGUfc%8NI#pvM0q2s~BC~&`>?PVp#m7EK@sT-iY`MyKZXFoq9oA>-kfs zp5NMb!PEuEbafsRA5)S)X?*kK{F0b>XbuKop-_wzOBfGx3u&Qf97d4|i$&Ur5RL@C z;sQiigs-2)7h84xu&m~1TI>(n!>b@}e3%LEf({4a!7TF;SDwzi1IzwhZyD7NQ_S@EfMxB?U){mi=pGvU#4kS7}R7~)6lmSXvWMJ87Y0r zi_<mlqUOjtsGuN2Cq2B~+!wG)9I+4GSJqwr*5v_t!1cN9By&G(IZ$_6d>E_V`43 z$MW%!iFqa0dbK886jv8|w6a*Qb8BTGhxpCqMLQpA7pyU|YLhPgR!aw{WT}nZN^0kZ z;(r!x+*tI_;tkYN;$PFy(pZrL3Qdl~IzP3vpFR?kuoc$OCD9xoUWlErhN6jf$vWiN z``Q=WyWzs^&A+ZUSu##&nQ}tun5s)Q{AjY~Z?3OC!Qp2zwO>EK{kFwDcXXNWjPkW( zEqq+9Tw{JLD4;Yu*WnlTxEVYIDg>W&)Wje9gG8*poLy}V#YYVSFlW$iAd;BUh;vF` zGhVQK!8yzaJ5=@qP!AAVXeLcNm}U;I7v&sTX)gZDS)Hk!P4!xfz&V|K^pFA+TW+b)Lx7KqS)OADo!g)x8uT;h$MIfiJh8q!6>J(`&} zJ}Wb~nabRaGM6h~*H-4FUgt)z7gaBjG&kMZ4a#>1>eu%sTIND&9x9>lqVc9&n4i}R zP4e@F_)J@f&^d#SWD748cjkdnv&zS}YRKkb z^ij-oL)fy=3-hq+0j9hjA2~8RYvjl*7$%F1jEjv@`Q_PJ6%|=o6$SB8k@4}7QIKn7 z-*c)>1VNG=F7mjI$=Gb8;glp$jPL%y;sa(`nC66Kik7gHq_7m6$cf=b3VvVG7rPxK z%o-Ya5chKhnUQHRk;4O`hUa>L>Y_?4_XXIZON~2~|EgLGh50tn>QSEAprwPpS7p9h zTU7;`vVl%sQ@^7AQ@H+C-I500u8lWe@ICYvwpKzNJ`5Fd{|JBUqGOLPFO}lbX-_q zG$cILw+nTA)EGHgT+0zU73%zF?GVBMlQk&P0r%0Q=G@7X#^>=c!Z-q5jsso3hjR!< zpIQBgF6rDI+JwHt9W#IwbY?J61oRW8u@g{VK$+7P>4+*%NvVi(M7EWy_o`~5^0PAS zku_KY1V~actH|LRA7MW_Oi8g2#C66hDep-)TRJ~?X3b~}JV9dCB`Bs#4j0}#con%5j zqg-QLSGuk{8jeZZ5_Zm=JHL(k;uF_c*O#tqk?v@DwrL>GZl5`GCgG>=XV=xP`}^_Z zKKTf|58AH}{0wum2FO#4e5@gMM#rayhp7CqjGc&-sHsTmia^WuL*5%Mj$!==dnQo=9Eq`B={^R8cSb&ub~y!i!5ll3b_^OFntH!8w9h9L$l9N z5t8l3k(t#9(YltPkiHuBY3-Prpq%XF5wRme)9pJe^Bj#r8tv};hbvoz zxpsiq4Nk3(h#@((_kb|FEjaNaqQR$)`*P zpSrEGl4|&>cn4B@#L=fuHPXLRMvFInpJ?f>FSQep9Cin5P62+iW=yUPOg63G^P{ky#-V-iiWg+y1I~` zS>UwRVI&1zDoNinZbRvYabqbdcCrjkIi!T3>C(Y?PB~7y=87x2k@6W0M5|p0noF%t zItqGoO9lGd)C)7B@a^8zRH%8QW|ZN*uPiEK#E6WjG6#Cw1@nrom+@V6k_@n~0c`wm z@4rJx1&YRxK2;r2BGAOp5`h+tUOX2ZD6RUaq=DZr322i?8Ipi;=Mkbgpu}ATdi#x2 za&8GgbLbKP`u;WTdenDZ^?=!*4$Az|*&o8F*D+)7nSWzRWJGX4RCt0dC_Ou`7#jqF zHB(qK|6)>i{(d?vb-)Dj}Pa_u57qQi`ax?Zi_fz?#J8DYKiFsIL8@|9l&5g!6G%^tIG(?B+V3n_a>Yp5?Sfs{@=YGFT z65cP9JU5g~f{t1XdGdG2ptMcKBY}R6_oD4A-Tl@(7}*RzuKyiO6e_#89P)plFr-4z zKIy12nL|#c$z09H%&l4?u*=fDZ6sXZ+z^?>qx^Cb?Xw~3tEWk#FTjYVGbWcK=U+Kz zJI}wVSeF@E24D#>5Czc5DU!Rwc>XWOsbHK2E`HK@gHS(|yWboNkpFQiSB~N~AO7tz z92|eU@%AXi#=bAbeXfVl!lRr&Y0uZjQGH)N|2)du2pr#s_WaJ&DtFf|q%H(nF9$ab z6m%l_H*kCy{A!oF@moRoMJB&;jv3WQiQA#^sy*v@BP+y7QV(8X**k~Mkh;E7<7E}z zK{a)y?t}dbxiXt@udW~;)TSEWs|otQDKqLD6z~RE8l~@j#$h8}X54p_G9%jF->%Dz zmPV*0GFCyqf-g@nHoyV8#B-!4Q5WexF3;#w7aMUJfuC~5&!vWsXME#J7J5E-e-JN1 zKGoFU4WB}l&m%@tf7N|l->EiPfj46fUm7PotG;Jc2DonuC@55vR67D;p-2Xqp_l_- zg5Yo};y|;2JtX|1$%~;%Yw_{%3H1p{qeZ6ZY!X5S3Y{BEyJoyOBPu_-JT0v(Iv>J- zy5zirjKF;@eYro{rym54Ii_K z%qEF#VDZk=W^_#(T>N<}hA2N1GiawqCh$n3{q;^37eCMG65CM^%I;q*#!_=$L6J2sX?M+9P89x);) zD)C*w5^1_Vo|U!6Y3P=5Gn`JI1S_9!%$OOS@q*D>*(6$Ma|rJq9g| z2i^^>h#AZ2nELdU2r%jdGM|&&ACAq>FdL#_AoGZgX>Cm&qA$HhP!+A4r!i13;%06P%^oa*Oxu3U$ zve$EO(1-?YVh&kuBzvho(uR4>O@OeW1J#vSNu5H=FcM4Pv`;C*2YrLhgrGs8@#6QO zP#8xG4IRz|7jp!HGwNp@Kxrk>ptM)r)g6k&RvGwt4)_Vuin#@jYP$`Zf7+9dMV8YB z(hassV{e8f!a~@0Qwa{B9F|H**9ycDc|@kh29F?`@B-V6+8rzl46yjegk|$RHtYr+ zv(I2I3(o5LX;%bA+#~$YYKX5g?Y-DB* z;A);`86<~SkE}3nuI6qiaW%p;w7JyM(bbh6t~QYDhGbWNf>#w}dKi=!+cJ2SyZXBf z9+g+2^Q^ymbrFqv=n2*^ZCd#)+lyCW+=F3Z!X<7+%MVB7Q=q=@-FympCK!2ERF~>} z3e+#5p8cP#zwJHU;?vG7qb)F4uXOz)lYhhY7*U z%%=>oe9(>xOKsAhWo8jE#McaFroCE9%q%u6yF4(!>Sr)BmWGAe55>0?N@eVx#s2Yf zaTff~3yi`FEaq>q!uY#J+$Qc5Pr~Zc9`Tv@9@ABjOpsZ!MApiQa+X{qSIZOS7I~@s zK{cy8)C0<;`D-(^E47=oZ9daXQKlqQo@u_R*L1Jx3Da|?*G&6N--n4vRIbb>Hi%;$N+I)+B$NApr`=IZBKf7P0-x$AXe(iqC z{Wkbr=l8MSH-0Xwzcs~bw^mxmSf^Rrt?R5OThFmxVZF(^)%vKv@(=Pa^{?|^=D*(m z68~5H_xOM2|9yZZAUq%=peUdt;GBRf0v-=|KH!aj_XEBR_$AO1SRdFH*cG@c@SecO z1D_9kBk=veZvtIG{z1_}$wB!+^+9bxT|ujYP6+xu=*M86;E>?B;Edp+;OgM!;Ev#9 zg7=4v37Hns9gp zh={O78HxIvH_)RgnF;y`wG3_zyVor~_EasM&2V-`{yd85O zR>p?KCdU@VHpI?|T@bq__O#ebVsDOHA9qIl^7s=Hk`f#Vw~tUG!bhZx*lT;j_KNNO z#4(B6v1)!<(hW&>Cq0#%np~3Hl-!y!H>D@#q?C(OZc4c?<(ZT>Q$9`kIn|sRotlwa zo;ohIGxhkiVQHCZXQ%B-Uz@%;{nGTmr$3PXT>4uXp&2tW7G$i+I4R@&j9W7v%6LBG zos9ov^kqh8W@L`aoR~R3b7khqneS$Pk?Dekin6TvS11p{zYwpJn}=ZO)F( zPS2i{{bcrwIq5lNIdwVHa@uoN<(!c7O|EZlL~d&C`rI>eugJYE_u<@^a`)waou}nR z~Gi)6!;bF zC>&LIqa)FAw&QBYU5Tjd|J?guvh^lc_y;YZ2{j2Kd(dDDB8~s{!RrOWX zkJmVA&a1hs=5IBBuerPC{+h>Yo~ij~%^NlE)y}9rzV^|&Id$jOm(;&q|4YLaja4}8 zySnk@#?KmmYVvK0Zc1w^ZmMsZ+O(i)Rnw-X^O~+{y0ht#rstd9YWkn1U&i>4i5=54 zX2qDzW1M65j@8DdkDWMn^Voln{bF3@xEsdZJ#N={)A-c!_2cJ^zkd8D&DQ3O=JCy| zn$K?jd-Idc?>7H9K}_(S5HZ0vp>{&YgcTDuPS`x*jtMVK_{RHh;>d}oOmww$w|qTm z!=ycvODEqoMVnGJ<;p4hrp8TOFztcqVbf<%KX3Y5GqPv&%s64jxicP|@!X7$W+u!W zH?w!<=9zz;`M}KATK!t*v|iu(R9kS{jJD(3wzYlI);BADR>`c>XZ>ULhBVoe& z{X26yCv=|B`FN*m;fRH+7GAON`Gr4p#dei;&F=b3*Jq287EN8WX3<59wlCVf=)*-n zFHTxKdhwjaTNXdN#Ak_ZNzal?mprxP)9%Rbn(p@Q6S{BfeyjVNrD018md;vw`qJ~3 zUcU6YWj@OSmqjfbu`FX*!Lo{Fb<3KUO<#7wvX_@PE`MP82P?u?tX;8V#lfD+o~^w> zy=A@2dtYCfuJd_tcQK*r)SmglmEYmD;uH9aSADO(o$qns$MoIb_od0try9=|ic3HF zj=(Y??yyQrPVK=;>VMg3pSt?Usar*>xgP5FrPqwrOLJ$Jx92k_kdUv>`U z|2FD(IM*jywc)56?rsO!s8x5accgOt2W~gqueuX02%7?U5AMadQ=Cr$<3vCF#=3qX zr;bH_1tX>a!XR!M{a=pT?j@I3eyuLu5vqivR-P>X+`uD%%9>gZ#R*^W^sk1>d^IcyYm76AV)nGRs z?P>)c{+Arqphl5Hc@yQA!hSf%^{GCzUOw~SXZx?ZTzoOnqUNBC!@03yqQXuGrQbiG zyZAyh!qFYh^)lQCaIeFCt2+)y9M>y|lY=|O*$ek8+-q>pxgGRG6Wy*qPrVH3&-bz5 zwN%btnTT^`y`qsE>TyJ;m3oC&qJ94lIPE6XqZRc6Jy4&^rJ`|=8)-b3$faoS0g->S z4t#H-oCmuEOGE(Q2_EEBjTrx%t_5+1a=(=}T#%WM*uf5G`27{aj>?&_k~PRt->Xre zQCN7vF1l7cH_8bjLAHq~*vWxKHj$}?i!yH4WMKkc9dMiAs^N;^3g9NdmB7`&<-!%n zy|CM;+Zk)k_ZEVBY~nfg?Yp#n(-JWxiM_7oh!}fJccQIJz%^vuR&LmiY;?%serc z;XB1x>2{C8;P#^;R+@3g*PrEi$kT9?zuO_L5M6K|>v9oWkH#Z#UI{k`E(wnMh5BJ6 zTo7Cu+!#3OD|)7|(Qsw-?BisnTI-FAwtnFh3Xo#qgmvs1khk9;*h%v_*?~= z@)dL0jS&$@vl8~RBDB8UnKP=+*k$;8E z!Pj$h#3DE$b6j8JUI<4kYsbNDG@O?o&I9B?(Ub%F(C-nrBR!{W1dM#J(82k*zN2!C zzc>5n@43OxARcI2wEs{YO_hE3yB3?sfcJnOESUMI5_vu}H9`?B2yijJg9jE$+V?_1 z{Iii1&w1+4)5p)8D0T?(i_**Rsh80GPFFcKr7ZR)^5;l)gIAyB={u+CqyU2CnP4MCS)h%CzK|POcPr zzd*F!E-J*evWVMst-M=4g*JU8Ka)SJbd{y-+@^=sW9n)3CbX$$v?&yAO4ia2X_Ie4 zKte=9Tmnw8C1fS!C6pvoB-AD}C(KHim#{oxL&Bzna}zG)HeGA8piN=6VYWD%joVac zE9W+?wQWM1Zm`{qHr;O9iZ(rHdt^YHOlVUm+BDqLriI)li8e{1Ie8zqO}H|}69$x_ z-;Jl?G&=f!uJc{zx&GqXgk?Ax$!;l7rA^Y?BPV(${TiEz{Rj@_HS z*H4Idw)<@|lf^^&y$JW2T&*sq2T)U*hW2PBTA5a%9j~3JoyPvBYiDR%v`e*XwOi-WpHt{5NygC^a=73eJIJHnEs&bX4a+D3{ zK9;E^YANV%6RI%+G@6dF*MvQxE%@elCuX3~Me4cEV%jCK8e0hPqLf$0r1l|8b z?vl^T*RY}J4AA{bHCCml32MG-Q61_`b*kE>PLuDcO0^2#-`K2P#L4U)6{14bKh&}6 z6a{PYDp>ASqf`vcL4YIR{EkTkh&Y@~iV^Xcy+>oL6^lxI9%8zf2@ON0I6<5(P7)`J ztHc>v2uh=lVfF#tdk8g0$;b; zD3{9~d8S;a7R$fL?eZ>grETC#=gAi#Blv)K9T50dE#wRAK$M{(O@@gi>;uV?k&uI; zL@juAfs7NQWV&d8{DAZBV!SMYY)}L%g=L~ymg3!fl$az(iUo3_Xva4pX2@F60Xc29 ztcJWX8T@~$oF=;E46#hMilx|-v>X!LN?4RxCp*M?xlkMiaWi=Go$^YtP5w=6mDh;7@wNL$Fo!-2do>Tqo5gGLN%69LOgt&? z7O%=D#6RUD;$L!ycuPJb_R1H;KJlr19Twi-#7KEVoGXtL&w&qQh&(x5EP*66Tdc*L zwgg|^DHd1A(;?$nAZJ>|U*#FF()O#sN8iOrnJQ{zHsq^%nD!Vi{(|!{m&jAZE%Fj^ zo4iasCAW%~ASc};uN9BVTZId@FV2+5h`-6R#TL0g{DgT@RSc`GHL6xsLs~dnjZo8IxoEPQqGqT$YPy=I zS}|MCRjbu8YJ=)h3)DunLM?ZS9Gg>2Z*6F^*~UL0f+ml5ny1ccbr!`sGuql0*|tn? zb*j{k2eHFZbao~$h)qm%iZ-XHORnDreqGmIo9mQ0PFwq;T&K#hEwnjzOmh09&DsVF zpLGqL4Nh}IYob$2ZJRQ?H8D9cc1x?xIcXBSs@r01&N70^+S+Ve_1GN?of+^lo@`D# zh1)6Sj!CUH)MiVE&1s#~+72Il`z_IFC8&g;lJ?kkSUQMx%IvnbWT%+a+SS&U>(p{= z4K}AwY6og&s+-j6G$q$M&B?WBN1Ic&=Q@3Il2I?)!mXwSwKfW&8prB2psQ1BZ|HPt zS&0a&vu&|$K>=Isrc^X?a%=mf*p4Y}t;ubPZ8m51)K-MWQqzp`bDgFfr=>1?8{{p< zlo^l7waLJEa&3oGEm-7~ov4M=l$GnW2s@n6p)>2Is<#`dnvF4jN#yIRom(QM&*n z*S0wW>1hg{0`ZjV3`RB~j1n6#(1~h0gX-FCTiR{TARsN*8Im)8TI*Jyh4pPI&cLqZ z4Y|(Hobi)e$4}KgV-w*Y&i-LJTSai)^wzDx!F5jAQR@uOCYl8$*KQ4Aew=?~(wCWGK=ZS5%j-q27o=v!O6rG0CdIoo+=c5D*R z6oIydXXiR2bGAylM*+`tkIvbu(S2CXRv)?#&)I6CdkoGh(LFY2tA*}yIa__{9-p(- zkM5Z{z=Do_5=H5olim z>SaUw=$?r7(LD+6qkA&iNB0!8kM5~xAKlZ?KDwu)eRR)2`{+a-6x@&RmSbd<=jlQ0kDwFu9{FnKe~@ zY-j}|qYf}C?g*mojuCD{}WW%A{08D1c>XE;Qf_#c!eN}SV)6%`cRiRh*16A_ha%d<7n$OkURZrRd=)!+_WE2ao=RaXQ9Zf! z9%a*PvG=GnEvBuO7^yFKGRj5C$&DDo=+=Sb5zIqo>+^=HYhQ@bRoAf)yiC<~!~$+_ z0|OYGrUTUidrxlcD2q)-35{qUZd?lT8=??YggCAbxCA=E1j@n$F{mcUu>*-yxe~Zy z(jr#bUlvHC!i@*KCOS=N1|E_tfufO~Ag3?5h0WHO+(d;^?^U|PxG@HX#kAHuTP3Dk zs=d-Zk!gPym{ajI7D1lbUGKa@DXu-)=qc1U*Ez~v8e`w+s&*0q1~=K=y;Wcod4$DA zXGmS^q*zRuw#v4=t$8v619bF&&?&K#2831*2z96R&TnvvnjB|Yws!<~B6oqcInMIz zEg(IjuPqqThpQVpG|!obD%Nq6iG1CCLS&hYag~R0rZ=M=d_qA%!i3QhPotaA=tzBlL)^ev4$pHI zVLXpHjQ?0|;{rZ^1q^QcS$=2Mvjv{RV`bWof|01GG%0i6_wfQ1x?fG)0AEuckQ zFM<|xy$D*u^&+U7>qXE~t`|YexLyP;=Xw#e0ywVlbYKrZIja!RtAnEft|X*WG-oxQ zR$&?iNO4x{AjMh3aVUV|tVQCHo?O@Q6Q?*v2PwsR9i-?Rkk3dx%Z)ln5suYCif|m_ zR(kR~o}W0s6LgTGpQwWr{UoHU)brb=a0b@?6Yj`s>fi zt-?~fy~!~`!`UQ&_gDC)`G)ywzWP%=cDcow`N>-QNYDmtUiCw0VC^HKn*aD& z6ZKnDxObc-)sUDU5jo%b#a_dAL>3!8+`2%#|89w!WpQ@Lz*6@MSTtB%|=ozs%9^R4% z#FKZs4ywHzkJGv1;Vaeg1M=G~ha34Na(=K}Ef$ex*$28kXq2G^V;J8s#FGw_{rWQu z7~d5Zml`nH`FzTNP0%FagfOQy!~c5&4uYm22rcWy!HSJywdjV1YzZ_THc<$jQ-OfZ zXlTxsKyzlp$KlqA<%nSulMu64EQN0;$E`ugTEyyw{~Cm6z`s}Yz^{X2RKvFe&uiej z0p%=4${y5|Vy%ES%boKS_%G&CI*?N#V%Yg_B=lb6q4}B!%UJHXxxk@!Y`4E{kpB$C zqFQxxji_DjT-_-K=S1ya3w%^ScbJcqok-t}=e2fQ(G4!yhSwPb9YLoAJ@Ie ze~2IUjAGj_Vre1;`X!i#l_u!sU@}oW0}Y*(b&Y{C2%55BXtP3Os0@?gSYwG0cR`mC zDN;ombWJX3&7x#9^gQX%PJIg9WUP$CC)pB!@h)iiY%)JvP_oC3arcThQ{s%=!{;3_U>oskNyeW zXEij3wXzO6rg~_`8n6Q0D4XOMXcWiE@v<2@z5T)tEnfk&q?6=iXiA~kgSK=Abb5<` zlb4|1ds((&-|K8SN6y9i%VIenn$!;H;ub*1w@`LrN92)4v-mA8p{=rC`WcR&|>7uG?X z(Dp5ZF7+O0RqvJeLHo2E-;jS0`pt*r!}1a60ehg2TmdcS=@1AXj!ajoJjO8gfJE?H4 z5C%eE_|vQ`%2yn({FGJsi(^%Q3RFQVn04J@DqKatqHL6kR>Q<~YPdK7`tDd2hd1}B z*yAw`<_6-S3m*YJej+S9CyN=-qNj=vRhl@c(y>mK37vnoI8)4ou0I#HQS+f|FHnWB zdv&66U~RuhoUDq)NzmVwLVs7TDxhtzgjT%@--fGZeO{fahxUAyYJk44NsSS+#T@ZD z_KZ9P-QRfZ!k(ZesutL5nj}7Eecx294m<(v-*j=cxCYw4nWXs>e}!H?0y_FAoSq+s zz3MR{R>Y}UYBsckbDEc##n|Mq-jGmmlj=rw6Lw(Sto{ybqqnNt)a}>}f2X=j-L0HztJOOTp_Q*d7E&0RHjz0=b`Qy-$KLK6&PW2R4Ql5t1{8?zvcR^#m8`|<0p*4RA zdh=J*ztpShHTAlBL%pf~t=zFRfx}NTWhMETbURz?^?Z&;(xEJa7 z8uz`{~W2xy~+}qQ&%v!U$yJvAn=eo6B zmYN3r&Q-FPLE+N9x^vx%Ma#Q3SnC${uI=dT?CM#|B^1;Znd>_{kP&XHdpp>-puuj` z%g*hw7t|G-8@QR~29B)PuF$A$ff2jbXnmd0nmVJ_bw=y!xYekAk+oq!H3}MPjjU?j z4KJ}Y7!BlB6c||+6j>Vd2J48atur@qjr^PX8yV2l*}Gyzhu%zU)1aaX?LK1`bgb6X z7uNWX=}&0*6`99+`V_S_s#fT39apiSp^p6#USk<+RCTOgHS^fD-OCqt`H$<*Ibgh3 zl^A;kb*1KJ?k96Iw;-U|D~eAuYOPnt!A(aW81--%WwVw_1YBb6as_fMu$1veQnS} zU4yA*N$=_&y^wmN&JFI|j9B#sP8;ljElbvcepjzsvAkm)w;Y&lu(Ws+L9vm#n9H(b zxcRrNS>CZ`i5IyS895i}lv`L>XP%;CXNr!UDTATw-9L zq{M%!SI15rlwUzZiIHE4kxz+%%5uF*1!avs(?EdcXaI22Ys@njukJXe%fGEZP)}E8baZ2pxs9Xf-i-z|ISf=a zmYHX9_SRX0Ms0av$XE`UKQ3>1Z|Cxf&GqIE4`x6Lje3r?rN+I$xI2t{G2JnWjEdCo zGt$-T;Wb9OnsVcrhX-ho^8uZ^!;O4vIA4T2EFA{+It)(S(a(uHy1WR;Uhd!7j~8pF zr-kN)9!db~H7aE12BE?w<}Plhxyvh7ff1|LXm*`Zy*i_Mbw;!6^kx^@i>+Or@(hd^ zEv(i!;*CW;$+^ddbAZD$l+o*iE!Gya#WNR;Ul=?62 zFDqb~S0w|MEneN#)w8^#XJL1zc{%r&c{w*MV7XU3pXF$bUburXgRU{E=Ww%9hq;H- z`}cIL>|L{Vb??e0UFIG=uO6?w^lXX@5-cj!x;$Lj&A!Uby&gn>D;wQfZx1V3s8})8*=VrvJH;AgCAh7pPegVSl^`?_zBXu#C z1+HA{-+KsGHgYb~iMp_`-n?4J^lBYDs|R5Rtj?%%32uFV+x^yi zxbb?O8*l6n)G4pb=-|d;^G0uOY*3NIKv844`B={0dhDQqTxLyfxh$*vq;G@_dgD zc6BdavR04S(`{s^m(jCs#cD2t0V;z4qYMJ|GIWT_;CNI9$J5JTP%nccav1~>o(k=y zj2FATR_Ai|TE+{W4ZM^Zc)?e7_4o!}N)5b}8h9x!k6PKay1REF$^DqA7jmc7)l9Q4 z>R!AK&yb-{k%O&YTvE5!{^qkJA5s!%+?6^3v6Nl$|R-hNw zcC6m$v#_^ku}{Og)xCOpy(N&H>wT7YuV%79A|rD*S=5x6S9YyIdLxZN9ko1w5S_7t zJoI~Ef%{(U+qGil+Koub2@48!v=rKPX#Fr(Cv7i^91?bOJ=bH|lDcT*nh>Ck{07mA5uI0V!`y&@JRoGz~ zNw1PFy5O0q0e4*vb?B3W-Qg$>(5qgS*V(bA%Xlc|hagWw^+!)@y`$E8KNNaD)OkOY zct6zeLy)KS-eE=j5H_VN2?1gUm#w{x7q67Smxk!I&wHMYg z_2JG;3HLI_1mg9VP*~f*5B@sBO3VJj}4QRd0%eq$gh&27WqGRSajeLhB~5H%+NwCC7JIt$l`lM*&LacvjUYRM3-DQqTc;K3WdL%C7JE?={yqt|xF} z&FXr=b%E;(#P9!6p6=gp=maxFHk^i54fweZP;T(5aP6Z2*LVEni9=5=+8b$t7w0%A z{3De94f6Noi>CoU*M8Sm-X1tjCtL@p{lfE8!q@d5H6Foj^y4-vZli_U zsB!Cjxpf-1&WBrP;?`NXb!Kjz#;wCAOwl^Yt&`k3$*oh|3XSWpas3t7-;A>HT|;P( zm-<~9_*mHY;d?M11E>|ahrvm#?}ds7U0cLMa1X;h0{1A~V{nhd?QvZq-hp+Q~387qhE6boh~J4lGbPs>WTVO_e1XNuyXsIJ|10P zqoglTE`IR&4@NDGWOORZ2nRK5JfdhUf5DuAMzs59aUF!;w+Q>$^@C9g>Vkaeyo}Wt zFG+x--ARlZ8zY{4UC*F|Pth|t1c5Ssp|)XE3D;++m4?%_F!ha6K7g;C^Zp9>A`H?v z4@L~H8qw&3|1Sn#pnk=VutNU0;Ixx>eDa6SAUreg_zeD^0Z(Y1`-i7*Tpzoi2H*R6 zk?ZrpVcyUE@w|P9fD>Hrb4_%P4Bm$kM7Z6HKe7WWT)(0%Y3MPcEb7JYiBmHMb&8-& zGhA;YutRjR6|go8?S`3y%gel z7487|+^g<3;0!ZxN}+^9O5y2W#H2LvVeB(RC2=co-4ELN92AlRc#rFSG0e3aPs5P^ zKfqh8n31X7U%0lTt_MJ0#Bsl;^yu+lP&?q5WBkmt7KNt+DA9*{7&ZDH>r?n49{s*Y zdi?|!dGgPo32G_kB`)Dtq@(u08aUEZt6eA)K9ri$bEuKt$mJQ};uD53VuT-$y+GH$ zfyb3f&JT_&CB1u=5OB`yJ@>1J`cXvot%y z=NZhU3Bb!UOkojdInmS)Jgx}`G`kOA)X68TtMPd47tx)RWYs#Le7wCjLTw z6av3M;E_g#RfM?qp(kF({VB{!R`kOM+((aa-|Pf;9@IxDBc;z0in}!E3iX^cCpOBK8>}sCXC$zZE`sFNj!%Y@_%C=#Jloc>}A*|_lcLV!n#SktWHy# zaZZ!0c*PU0v6?vobY{a|3x$(o>A+3~{vxqkA{THT{-UtsqY*Ki@JF9&nFyS9iiH>> zUD)T~iya}0vCg>!e-`W+Spk^pz>4bU zsO^97XW^Ddam%B)ivx0YI>xFr&`ycRIkNpWp7u7~1!_@ExI zqs>&dnaj3t*}h!1A5P8r;)FbQwBU?<0QQ;0V~+{sEu5e$2V5 z>;Or`{*R@&F2kv=c=?w-)d-fZMzC}>f~BhWA{T4#sN6oQ=kmh-JEccyeL2w`|I8qp5?i9lrbJV^J z%%wZwgCE^d4&Kw5(gi3z1@8iBcpLHsMHk>b#ep3%VW8Q15l%Z(AcZRt?e%7*Ja1Nq zf2UGBF8saTsU(jJGj`z=pgbx=f9p7!cPgvb+Z1RXd&Gzz>D)JvIcp&EBgOnEkoi#{ z^P@24M}Z!`_&WF>@gt4-kq`4D6Z0c8^CMs8N1@nb=Z|xV#Fc!RD_NK;`O?{5_*a8B zMPip*3t-|r1DLo~By+1s=2pJUts=3H>^y`L&+=uS70Eoyik)IN z!k;*oKXa}K=3D{Hxq_K<1u*9dVa{cdd!S#5V*cgF{7W+bie!Ef$^0Ua`32rMwGbL1 z+9aPK%ml+g1T^nT@CAukgD2LA>u~<-pufXFD@@W1Ze&3)*cpKue^n)SMl~HbCIO&l`r^jd*y`G7Cb`vi?s7dXcIzz=jDz|SBZj&})zVeb}l7_f)&94OM! zwu2(y^_hrAJ<{QuAyR=?!P1BcVZPLIPUE?dGz6YOZ#SetAq;*GxzND7C)#A91i~O> z8uSYKNF)3~&ifiYX+|jh^ecmhUN|+phr$m|r_*~p_1!RB{c-n2ivsc0=&!Nc5VXR- z1mmvX0>KF(146!}w^@JGir#3y;G0Naht5-_N7u^Y%B%UBIz7fQ=58&Dd zp!Nk^`$(>RIM+U!Ib9^zRpYuwGN+4X9v98rEt>gSH1jf@i$!zIbp92^{41L4WaS!! za1FwkbA>SH3T4ivG3SbA&SmB~D9}sV>YrPZq3`O~*9Eh*rOzsUUbBiWZ5^u1(xt5< zYwCQxG#fTBTO|D-^5$OBEY0uxgYQTfsm9!KwDPO+gIRaBxhNOwn1GVAU3_V z4g8TT18p?&{tI?bVlyn4BGtKgB7JitN}<_|-VJmqTA!~po~gX&s35O7$~?sEL{hP@ zK`$f;`+4<;Kleuf_lLhRhtT^C)c|@-)Ugpef+fq4cR^MN#HiKK(t|8L+M#Fr44A=NfIHH-!kEnIpVr<_MmdBY0+xHWmSbFw}g z>m$sGFcS{lGD4d5{m!YvJB$_wX~MsZ8SxusTphGc5UJEht8b>;Ohaoo2&T;%6nT1{VNzn7OK>nI6+VKv#0Pl-4 z`E0^mSSHyBYB>(?e=C5;2eEVaVZ5E*j(zJsVkb@un8ml!SB8u4h$Bgfa{zW&l`h1n zj+2$xgP#h!(sN`9IL{*3_*jCS>Jx#%n_y%5@A7eZ7WS9F1$m@YsNqZhu=7D$5e+*r z9(O(Pu*dVPi4TxBKGN}r-EYUyW)NiO7T!>bk%`GD6a)QEB0A0g=w*k7*138C)jvT6|crt2H*h`^rA+P)3 z9$|?5-eKrjPiQ~%BI3PDq2W)5ejWNb*NUJYj|d$_ywJVBnah#O;84!xC`#kn_viPK zr}hjnHV5Srb_`nHMD6D@38rO;VFY5%I`=uz&H$}+J~Fbj!(E9`w#W&5A}wAv!;XU!sU2M8(i+7 z77a?vp?ZtHMNNO^yaZ~xdl1x*@f3uXa411pgCP45p-1)`gA@}v7lLMaph^$a?^o;b z8=PX=5V`dG5v1qR4ha1cwJ4$t(CY9F2DID*>3&t7&>^7k^TRIM-@@<6u3LcWN1_)yB_XhQ$L z%jIb5e8gHs1)!~FYA-{~HzLx2!yNL9D2!SZ$())Y@GQfxA3AcV9uH#+UkRBJF^77_ zfY1wvK;z&yiQ+{rjaVDeL!~iv>>q<779f{Dn6|%M&gJ*lWr?TG3^C>gn=t&Qx`@MzQUdw*3dLWM<+CeS*^HRYx{P7DY~pY>gzS z;wYfJql|aB{F*&w=n&<1gc_ixMO^!8Kotz-4dK@x>IMB~O$XJ5bLY|qL3+6ZTQn#w z<4^aShx#q#9F_uFc~}TE6nO@R5_J3^2()oX=#l-dL<*+ZNP_O*{0KVN1NHk|?C~3% z;^rZ8>GvZ@&t)5+ry_Snz7#nW^w@yV2RL58UqAFonMhalkk*WJh7bAPMrMQyKYzaF8 z@RvWZ&rJ3?ov)kO|8(+aOD7T^ccoP8*nb`6tkHU|)V@}alRxa2O4-CEHu(e)O!+9Y zpc0!nZ6fD<5yv@OhdH;iIrJokPtswIa}vin2^xDTPNqD?$>a|!yQJ%VmO`-ygJDiZ zt4vak=CoBDdNTXd%9K=>>sPLAnVt{l-@!FEF$_H#a=3+axP^SQZRDeEW4MFi4$k2i zjCaapIZzg{la8MYOu^k|OR$T3gh>z9Hsb29s%!gaWo;Z_c9<=k31w^s5O z&%iFdlx2+DksPOt$vJJod@cVa~sYWA?C54~O<}eC#+z&OMYfY$c#9 z*!v|s%pn+S0(8wGAC=9inmDwPW9D<7`8v%0`5Y%xzq0=>^2Z()DrFb@=W?oC`3rn< zIcLeCxs2O#&Sxx##xtC!UpZAC`D?StM{DQ!d7=+>%U64mTQf-&pDjMImc5> zSVN$iT*&@*{mMDpIiEDj2fN=X&ISq<8z>*aeJwU{4(r*U@hsMJD#<0%x*f$og|1W+ z*y5nvp5|IT$fZ2UF(0HH)DH52y#yLNY3!fI^`VtW_^^Kh`zNq}g6_ki8@NRY+{Oed z1#9Aj$^9IPYo8%%O{Yi_5GHvIMWCiaJoG2r z4y65~?zhT4a=z#EZBdMgB6|eSkLT$ZLSL8S2L>t7Q1lN&n8yZO~Li-@int-;+6?5%{K8APSM-M z-YG2;Y~tWF#F4{r!rCT_j68{YqfyUXoMULly3_)!L{Vw9KPM3DSjp&(a#0H#T&-9E z1UKg}4J)R@Vb>}j<=0^!VH;MlK*1d5gEiI|oaeB^ic&q+y=GybBxC~)GXX2HSW_&3 zeWeDBm)Tg8U1fxkjhi^^h$zG!lSZtS&A~d^Y9q{oy%X`kodau}O|U>T7xcHr2=m2W zAbfWPcA`dOrE)6l;&fy0rCy#NRxd|jWENw@jD@|S`8eSK`GV_W#fq&Br*}$34OUF2 zV{L93IP>}roaj@#|IC$6*r`|l)U|WPO7%e}UEkuX4*!lT9gkI?|C#F|oZePn|C#IZ z?!_JI;Gep}3WTP}7KG-@*C4(|@HK|7Hom6uHHWW-bhuV4`!mFSMUp-(QxPe0N4jW*64_z=yvJIKNL?IMi<$)qGy&RdG`b6GWH4J zE7>BXIf$+%zS3C(lBwv*vn$3n+dA!h6`Kw^v>Z3v7ezk|_my zWO-`XZ&;EdyHRfqwE2Wm@_>^QVUz3;?8|7u&X{ZDE&aC5bjxOJ*DL|M3i|D2v6U=* zkAc3q*u@JEkY((+^c?2~HF$od^mibgkL?yrf zoU?k6i-pBGcg~*KxwA8~b7o<7wwNdPV#>%ax1ZEbOLh+QiyCSjL?6k1Q%kLB7eIeF zKjeX30-g9He`r@gr_@;MG_uz0j9P15C_J(58uV^zwI%yY?X@1NwI%z<`k>ck0Zwf{ z)-lwB`@z_yAK@ln0!Ypa%W z&h_!Xns3ZBT9W35X2msz>_+lsEnI7Ri-a=`qxPJlzC6Co;3+>f$<(GdYrY$dMZV%$ z`{Ti@_9POg1Wt^Bm99pocI6_f?-0^4&YzOCD1uDh3zX@U($K%$Se!DY64eLWQ_`#u zWpa?M1zzS@64i(k*(~yo8u}mocL+z9^U76L`;o4?065mtlP1)C12PiTMD~E z9EO%uu;3*C1eGe|4Ba3M)G2t~^ ctU@IHCYf2IR3elo=#L%YkL4GOu^83(e_hdCU;qFB literal 0 HcmV?d00001 diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/Contents.json b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviMenuTextColor.colorset/Contents.json b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviMenuTextColor.colorset/Contents.json new file mode 100644 index 000000000..4f4b48058 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviMenuTextColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.239", + "green" : "0.235", + "red" : "0.031" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviTextColor.colorset/Contents.json b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviTextColor.colorset/Contents.json new file mode 100644 index 000000000..efe8a9b96 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviTextColor.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.239", + "green" : "0.235", + "red" : "0.031" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "0.800", + "blue" : "0xFF", + "green" : "0xFF", + "red" : "0xFF" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviTintColor.colorset/Contents.json b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviTintColor.colorset/Contents.json new file mode 100644 index 000000000..67e2f95b3 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviTintColor.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "0.624", + "green" : "0.677", + "red" : "0.209" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/station/Resources/Images/Assets.xcassets/ruuvitag-b8-and-older-button-location.imageset/Contents.json b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/ruuvitag-b8-and-older-button-location.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/ruuvitag-b8-and-older-button-location.imageset/Contents.json rename to Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/ruuvitag-b8-and-older-button-location.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/ruuvitag-b8-and-older-button-location.imageset/ruuvitag-b8-and-older-button-location.png b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/ruuvitag-b8-and-older-button-location.imageset/ruuvitag-b8-and-older-button-location.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/ruuvitag-b8-and-older-button-location.imageset/ruuvitag-b8-and-older-button-location.png rename to Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/ruuvitag-b8-and-older-button-location.imageset/ruuvitag-b8-and-older-button-location.png diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/de.lproj/RuuviFirmware.strings b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/de.lproj/RuuviFirmware.strings new file mode 100644 index 000000000..7c47df8bb --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/de.lproj/RuuviFirmware.strings @@ -0,0 +1,20 @@ +"DFUUIView.navigationTitle" = "Firmware Update"; +"DFUUIView.latestTitle" = "Neueste verfügbare Ruuvi Firmware-Version:"; +"DFUUIView.currentTitle" = "Aktuelle Version:"; +"DFUUIView.notReportingDescription" = "Ihr Sensor meldet seine aktuelle Firmware-Version nicht. Dies bedeutet, dass wahrscheinlich eine alte Firmware-Version ausgeführt wird und eine Aktualisierung empfohlen wird."; +"DFUUIView.alreadyOnLatest" = "Sie verwenden die neueste Firmware-Version, keine Aktualisierung erforderlich"; +"DFUUIView.startUpdateProcess" = "Update-Prozess starten"; +"DFUUIView.downloadingTitle" = "Laden Sie die neueste zu aktualisierende Firmware herunter..."; +"DFUUIView.prepareTitle" = "Bereiten Sie Ihren Sensor vor"; +"DFUUIView.openCoverTitle" = "1. Öffnen Sie den Deckel Ihres Ruuvi-Sensors"; +"DFUUIView.locateBootButtonTitle" = "2. Suchen Sie die kleinen runden schwarzen Knöpfe auf der weißen Platine; ältere Ruuvi-Sensoren haben zwei Knöpfe mit den Bezeichnungen \"R\" und \"B\", während neuere nur einen Knopf ohne Beschriftung haben."; +"DFUUIView.setUpdatingModeTitle" = "3. Stellen Sie den Sensor in den Aktualisierungsmodus:"; +"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. Wenn Ihr Sensor 2 Tasten hat: Halten Sie die Taste \"B\" gedrückt und tippen Sie gleichzeitig kurz auf die Taste \"R\". Lassen Sie die Taste \"B\" los."; +"DFUUIView.toBootModeOneButtonDescription" = "3.2. Wenn Ihr Sensor eine einzelne Taste hat: Halten Sie die Taste 10 Sekunden lang gedrückt."; +"DFUUIView.toBootModeSuccessTitle" = "4. Wenn die Einstellung erfolgreich war, leuchtet ein rotes Licht auf der Platine und die Schaltfläche in der App ändert sich in \"Start the update\"."; +"DFUUIView.updatingTitle" = "Aktualisierung..."; +"DFUUIView.searchingTitle" = "Suche nach einem Sensor"; +"DFUUIView.startTitle" = "Starten Sie die Aktualisierung"; +"DFUUIView.doNotCloseTitle" = "Schließen Sie die App nicht und schalten Sie den Sensor während des Updates nicht aus."; +"DFUUIView.successfulTitle" = "Aktualisierung erfolgreich"; +"DfuFlash.Finish.text" = "BEENDEN"; diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/en.lproj/RuuviFirmware.strings b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/en.lproj/RuuviFirmware.strings new file mode 100644 index 000000000..467ed1605 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/en.lproj/RuuviFirmware.strings @@ -0,0 +1,20 @@ +"DFUUIView.navigationTitle" = "Firmware Update"; +"DFUUIView.latestTitle" = "Latest available Ruuvi Firmware version:"; +"DFUUIView.currentTitle" = "Current version:"; +"DFUUIView.notReportingDescription" = "Your sensor doesn't report its current firmware version. Either you're not in its Bluetooth range, it's connected to another phone, or it's running a very old firmware version."; +"DFUUIView.alreadyOnLatest" = "You are running the latest firmware version, no need to update"; +"DFUUIView.startUpdateProcess" = "Start update process"; +"DFUUIView.downloadingTitle" = "Downloading the latest firmware to be updated..."; +"DFUUIView.prepareTitle" = "Prepare your sensor"; +"DFUUIView.openCoverTitle" = "1. Open the cover of your Ruuvi sensor"; +"DFUUIView.locateBootButtonTitle" = "2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label."; +"DFUUIView.setUpdatingModeTitle" = "3. Set the sensor to updating mode:"; +"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”."; +"DFUUIView.toBootModeOneButtonDescription" = "3.2. If your sensor has a single button: keep the button pressed for 10 seconds."; +"DFUUIView.toBootModeSuccessTitle" = "4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”."; +"DFUUIView.updatingTitle" = "Updating..."; +"DFUUIView.searchingTitle" = "Searching for a sensor"; +"DFUUIView.startTitle" = "Start the update"; +"DFUUIView.doNotCloseTitle" = "Do not close the app or power off the sensor during the update."; +"DFUUIView.successfulTitle" = "Update successful"; +"DfuFlash.Finish.text" = "FINISH"; diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/fi.lproj/RuuviFirmware.strings b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/fi.lproj/RuuviFirmware.strings new file mode 100644 index 000000000..d43a87b94 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/fi.lproj/RuuviFirmware.strings @@ -0,0 +1,20 @@ +"DFUUIView.navigationTitle" = "Laiteohjelmiston päivitys"; +"DFUUIView.latestTitle" = "Uusin saatavilla oleva Ruuvi-laiteohjelmisto:"; +"DFUUIView.currentTitle" = "Nykyinen versio:"; +"DFUUIView.notReportingDescription" = "Laitteessa oleva laiteohjelmisto ei ilmoita nykyistä versiota. Joko et ole sen Bluetooth-kuuluvuusalueella, se on samanaikaisesti yhteydessä toiseen puhelimeen tai kyseessä on hyvin vanha laiteohjelmisto."; +"DFUUIView.alreadyOnLatest" = "Laitteessa on jo viimeisin saatavilla oleva laiteohjelmisto"; +"DFUUIView.startUpdateProcess" = "Siirry päivittämään"; +"DFUUIView.downloadingTitle" = "Ladataan viimeisin laiteohjelmisto päivitystä varten..."; +"DFUUIView.prepareTitle" = "Laitteen asettaminen päivitystilaan"; +"DFUUIView.openCoverTitle" = "1. Avaa Ruuvi-anturin suojakotelo"; +"DFUUIView.locateBootButtonTitle" = "2. Paikanna valkoisella piirilevyllä olevat pienet pyöreät mustat painikkeet; vanhemmissa Ruuvi-antureissa on 2 painiketta “R” ja “B”, kun taas uudemmissa on vain yksi nimeämätön painike."; +"DFUUIView.setUpdatingModeTitle" = "3. Aseta anturi päivitystilaan:"; +"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. Anturissasi on kaksi painiketta: pidä painike “B” alaspainettuna ja napauta samalla painiketta “R”. Vapauta painike “B”."; +"DFUUIView.toBootModeOneButtonDescription" = "3.2. Anturissasi on yksi painike: pidä painiketta alaspainettuna 10 sekunnin ajan."; +"DFUUIView.toBootModeSuccessTitle" = "4. Päivitystilaan siirtyminen onnistui, mikäli piirilevyllä oleva punainen LED-valo on nyt aktiivinen ja sovelluksen painikkeen nimeksi on vaihtunut “Aloita päivitys”."; +"DFUUIView.updatingTitle" = "Päivitetään..."; +"DFUUIView.searchingTitle" = "Laitetta etsitään"; +"DFUUIView.startTitle" = "Aloita päivitys"; +"DFUUIView.doNotCloseTitle" = "Älä sulje sovellusta tai poista paristoa laitteesta päivityksen aikana."; +"DFUUIView.successfulTitle" = "Päivitys onnistui"; +"DfuFlash.Finish.text" = "VALMIS"; diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/fr.lproj/RuuviFirmware.strings b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/fr.lproj/RuuviFirmware.strings new file mode 100644 index 000000000..5b0c767bf --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/fr.lproj/RuuviFirmware.strings @@ -0,0 +1,20 @@ +"DFUUIView.navigationTitle" = "Mise à jour du firmware"; +"DFUUIView.latestTitle" = "Dernière version du Ruuvi Firmware :"; +"DFUUIView.currentTitle" = "Version actuelle :"; +"DFUUIView.notReportingDescription" = "Impossible d'obtenir la version actuelle de l'appareil. La version est probablement trop ancienne et il est recommandé d'effectuer une mise à jour."; +"DFUUIView.alreadyOnLatest" = "L'appareil est à déjà à jour"; +"DFUUIView.startUpdateProcess" = "Début de la mise à jour"; +"DFUUIView.downloadingTitle" = "Téléchargement de la dernière version pour la mise à jour..."; +"DFUUIView.prepareTitle" = "Préparez votre capteur"; +"DFUUIView.openCoverTitle" = "1. Ouvrez le couvercle de votre capteur Ruuvi"; +"DFUUIView.locateBootButtonTitle" = "2. Localisez les petits boutons ronds noirs sur la carte de circuit imprimé blanche ; les anciens capteurs Ruuvi ont 2 boutons étiquetés \"R\" et \"B\" tandis que les plus récents n'ont qu'un seul bouton sans étiquette."; +"DFUUIView.setUpdatingModeTitle" = "3. Mettez le capteur en mode de mise à jour :"; +"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. Si votre capteur est équipé de 2 boutons : maintenez le bouton \"B\" enfoncé tout en appuyant momentanément sur le bouton \"R\". Relâchez le bouton \"B\"."; +"DFUUIView.toBootModeOneButtonDescription" = "3.2. Si votre capteur possède un seul bouton : maintenez le bouton enfoncé pendant 10 secondes."; +"DFUUIView.toBootModeSuccessTitle" = "4. Si le réglage est réussi, vous verrez une lumière rouge fixe s'allumer sur la carte de circuit imprimé et le bouton de l'application passera à \"Démarrer la mise à jour\"."; +"DFUUIView.updatingTitle" = "Mise à jour..."; +"DFUUIView.searchingTitle" = "Recherche d'un capteur"; +"DFUUIView.startTitle" = "Lancer la mise à jour"; +"DFUUIView.doNotCloseTitle" = "Ne pas fermer l'application ou enlever la pile du capteur pendant la mise à jour."; +"DFUUIView.successfulTitle" = "Mise à jour réussie"; +"DfuFlash.Finish.text" = "PRÊT"; diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/ru.lproj/RuuviFirmware.strings b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/ru.lproj/RuuviFirmware.strings new file mode 100644 index 000000000..7574cdef1 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/ru.lproj/RuuviFirmware.strings @@ -0,0 +1,20 @@ +"DFUUIView.navigationTitle" = "Обновление Прошивки"; +"DFUUIView.latestTitle" = "Доступная версия прошивки Ruuvi:"; +"DFUUIView.currentTitle" = "Текущая версия:"; +"DFUUIView.notReportingDescription" = "Ваш сенсор не возвращает версию прошивки. Вероятно, на нем установлена старая версия прошивки и обновление рекомендовано."; +"DFUUIView.alreadyOnLatest" = "Последняя версия прошивки уже установлена, обновление не требуется"; +"DFUUIView.startUpdateProcess" = "Начать процесс обновления"; +"DFUUIView.downloadingTitle" = "Идет скачивание обновления прошивки..."; +"DFUUIView.prepareTitle" = "Prepare your sensor"; +"DFUUIView.openCoverTitle" = "1. Open the cover of your Ruuvi sensor"; +"DFUUIView.locateBootButtonTitle" = "2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label."; +"DFUUIView.setUpdatingModeTitle" = "3. Set the sensor to updating mode:"; +"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”."; +"DFUUIView.toBootModeOneButtonDescription" = "3.2. If your sensor has a single button: keep the button pressed for 10 seconds."; +"DFUUIView.toBootModeSuccessTitle" = "4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”."; +"DFUUIView.updatingTitle" = "Обновляю..."; +"DFUUIView.searchingTitle" = "Searching for a sensor"; +"DFUUIView.startTitle" = "Start the update"; +"DFUUIView.doNotCloseTitle" = "Не закрывайте приложение и не отключайте сенсор во время обновления."; +"DFUUIView.successfulTitle" = "Обновление успешно завершено"; +"DfuFlash.Finish.text" = "УСПЕХ"; diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/sv.lproj/RuuviFirmware.strings b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/sv.lproj/RuuviFirmware.strings new file mode 100644 index 000000000..4cf842198 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/sv.lproj/RuuviFirmware.strings @@ -0,0 +1,20 @@ +"DFUUIView.navigationTitle" = "Firmware Uppdatering"; +"DFUUIView.latestTitle" = "Senast tillgängliga Ruuvi firmwareversion:"; +"DFUUIView.currentTitle" = "Nuvarande version:"; +"DFUUIView.notReportingDescription" = "Din sensor rapporterar inte sin nuvarande firmwareversion. Det betyder att den förmodligen har en gammal firmwareversion och uppdatering rekommenderas."; +"DFUUIView.alreadyOnLatest" = "Du har redan den senaste firmwareversionen, ingen uppdatering behövs"; +"DFUUIView.startUpdateProcess" = "Starta uppdateringsprocessen"; +"DFUUIView.downloadingTitle" = "Hämtar senaste firmware.."; +"DFUUIView.prepareTitle" = "Förbered din sensor"; +"DFUUIView.openCoverTitle" = "1. Öppna locket på din Ruuvi sensor"; +"DFUUIView.locateBootButtonTitle" = "2. Leta reda på små runda svarta knappar på det vita kretskortet; äldre Ruuvi-sensorer har 2 knappar märkta “R“ och “B“ medan nyare har bara en knapp utan etikett."; +"DFUUIView.setUpdatingModeTitle" = "3. Lägg sensorn i uppdateringsläge"; +"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. Om din sensor har två knappar: håll knappen “B” intryckt medan du trycker en gång på “R”. Släpp knapp “B”."; +"DFUUIView.toBootModeOneButtonDescription" = "3.2. Om din sensor har en knapp, håll knappen intryckt i 10 sekunder."; +"DFUUIView.toBootModeSuccessTitle" = "4. Uppgraderingsläget lyckades om den röda lysdioden på kretskortet lyser och knappens text i appen har bytts till “Starta uppdatering“."; +"DFUUIView.updatingTitle" = "Uppdaterar..."; +"DFUUIView.searchingTitle" = "Söker efter en sensor"; +"DFUUIView.startTitle" = "Starta uppdatering"; +"DFUUIView.doNotCloseTitle" = "Stäng inte appen eller stäng av sensorn under uppdateringen."; +"DFUUIView.successfulTitle" = "Uppdateringen lyckades"; +"DfuFlash.Finish.text" = "KLAR"; diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmware.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmware.swift new file mode 100644 index 000000000..4ae823873 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmware.swift @@ -0,0 +1,11 @@ +import UIKit + +public protocol RuuviFirmware: AnyObject { + var viewController: UIViewController { get } + var router: AnyObject? { get set } + var output: RuuviFirmwareOutput? { get set } +} + +public protocol RuuviFirmwareOutput: AnyObject { + func ruuviFirmwareSuccessfullyUpgraded(_ ruuviDiscover: RuuviFirmware) +} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmwareBuilder.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmwareBuilder.swift new file mode 100644 index 000000000..870d5a354 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmwareBuilder.swift @@ -0,0 +1,37 @@ +import BTKit +import RuuviDFU + +public struct RuuviFirmwareDependencies { + public var background: BTBackground + public var ruuviDFU: RuuviDFU + public var firmwareRepository: FirmwareRepository +} + +public final class RuuviFirmwareBuilder { + public init() {} + + public func build( + uuid: String, + currentFirmware: String? = nil, + dependencies: RuuviFirmwareDependencies = .default + ) -> RuuviFirmware { + let presenter = FirmwarePresenter( + uuid: uuid, + currentFirmware: currentFirmware, + background: dependencies.background, + ruuviDFU: dependencies.ruuviDFU, + firmwareRepository: dependencies.firmwareRepository + ) + return presenter + } +} + +public extension RuuviFirmwareDependencies { + static var `default`: Self { + RuuviFirmwareDependencies( + background: BTKit.background, + ruuviDFU: RuuviDFUImpl.shared, + firmwareRepository: FirmwareRepositoryImpl() + ) + } +} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift new file mode 100644 index 000000000..78f2f1c00 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift @@ -0,0 +1,438 @@ +import SwiftUI + +struct FirmwareView: View { + @ObservedObject var viewModel: FirmwareViewModel + + private struct Texts { + let navigationTitle = "DFUUIView.navigationTitle".localized(for: FirmwareViewModel.self) + let latestTitle = "DFUUIView.latestTitle".localized(for: FirmwareViewModel.self) + let currentTitle = "DFUUIView.currentTitle".localized(for: FirmwareViewModel.self) + let lowBatteryWarningMessage = "DFUUIView.lowBattery.warning.message".localized(for: FirmwareViewModel.self) + let okTitle = "ErrorPresenterAlert.OK".localized(for: FirmwareViewModel.self) + let notReportingDescription = "DFUUIView.notReportingDescription".localized(for: FirmwareViewModel.self) + let alreadyOnLatest = "DFUUIView.alreadyOnLatest".localized(for: FirmwareViewModel.self) + let startUpdateProcess = "DFUUIView.startUpdateProcess".localized(for: FirmwareViewModel.self) + let downloadingTitle = "DFUUIView.downloadingTitle".localized(for: FirmwareViewModel.self) + let prepareTitle = "DFUUIView.prepareTitle".localized(for: FirmwareViewModel.self) + let openCoverTitle = "DFUUIView.openCoverTitle".localized(for: FirmwareViewModel.self) + let localBootButtonTitle = "DFUUIView.locateBootButtonTitle".localized(for: FirmwareViewModel.self) + let setUpdatingModeTitle = "DFUUIView.setUpdatingModeTitle".localized(for: FirmwareViewModel.self) + let toBootModeTwoButtonsDescription = "DFUUIView.toBootModeTwoButtonsDescription".localized(for: FirmwareViewModel.self) + let toBootModeOneButtonDescription = "DFUUIView.toBootModeOneButtonDescription".localized(for: FirmwareViewModel.self) + let toBootModeSuccessTitle = "DFUUIView.toBootModeSuccessTitle".localized(for: FirmwareViewModel.self) + let updatingTitle = "DFUUIView.updatingTitle".localized(for: FirmwareViewModel.self) + let searchingTitle = "DFUUIView.searchingTitle".localized(for: FirmwareViewModel.self) + let startTitle = "DFUUIView.startTitle".localized(for: FirmwareViewModel.self) + let doNotCloseTitle = "DFUUIView.doNotCloseTitle".localized(for: FirmwareViewModel.self) + let successfulTitle = "DFUUIView.successfulTitle".localized(for: FirmwareViewModel.self) + let finish = "DfuFlash.Finish.text".localized(for: FirmwareViewModel.self) + } + + private let texts = Texts() + private static let fontSize: CGFloat = 16 + private let muliBold16 = Font( + UIFont(name: "Muli-Bold", size: fontSize.adjustedFontSize()) ?? + UIFont.systemFont(ofSize: fontSize.adjustedFontSize(), weight: .bold)) + private let muliRegular16 = Font( + UIFont(name: "Muli-Regular", size: fontSize.adjustedFontSize()) ?? + UIFont.systemFont(ofSize: fontSize.adjustedFontSize(), weight: .regular)) + + private var content: some View { + switch viewModel.state { + case .idle: + return Color.clear.eraseToAnyView() + case .loading: + return VStack(alignment: .leading, spacing: 16) { + Text(texts.latestTitle).bold() + .font(muliBold16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + Spinner(isAnimating: true, style: .medium).eraseToAnyView() + } + .frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .topLeading + ) + .padding() + .eraseToAnyView() + case .error(let error): + return Text(error.localizedDescription) + .font(muliRegular16) + .eraseToAnyView() + case let .loaded(latestRelease): + return VStack(alignment: .leading, spacing: 16) { + Text(texts.latestTitle).bold() + .font(muliBold16) + .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + Text(latestRelease.version) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + Text(texts.currentTitle).bold() + .font(muliBold16) + .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + Spinner(isAnimating: true, style: .medium).eraseToAnyView() + } + .frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .topLeading + ) + .padding() + .onAppear { self.viewModel.send(event: .onLoaded(latestRelease)) } + .eraseToAnyView() + case let .serving(latestRelease): + return VStack(alignment: .leading, spacing: 16) { + Text(texts.latestTitle).bold() + .font(muliBold16) + .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + Text(latestRelease.version) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + Text(texts.currentTitle).bold() + .font(muliBold16) + .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + Spinner(isAnimating: true, style: .medium).eraseToAnyView() + } + .frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .topLeading + ) + .padding() + .eraseToAnyView() + case let .checking(latestRelease, currentRelease): + return VStack(alignment: .leading, spacing: 16) { + Text(texts.latestTitle).bold() + .font(muliBold16) + .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + Text(latestRelease.version) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + Text(texts.currentTitle).bold() + .font(muliBold16) + .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + if let currentVersion = currentRelease?.version { + Text(currentVersion) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + } else { + Text(texts.notReportingDescription) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + } + } + .frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .topLeading + ) + .padding() + .onAppear { self.viewModel.send(event: .onLoadedAndServed(latestRelease, currentRelease)) } + .eraseToAnyView() + case .noNeedToUpgrade: + return VStack { + Text(texts.alreadyOnLatest) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + .frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .topLeading + ) + .padding() + Button( + action: { + self.viewModel.finish() + }, + label: { + Text(texts.finish) + .font(muliBold16) + .frame(maxWidth: .infinity) + } + ) + .buttonStyle( + LargeButtonStyle( + backgroundColor: RuuviColor.ruuviTintColorSUI, + foregroundColor: Color.white, + isDisabled: false + ) + ) + .padding() + .frame(maxWidth: .infinity) + } + .eraseToAnyView() + case let .isAbleToUpgrade(latestRelease, currentRelease): + return VStack { + VStack(alignment: .leading, spacing: 16) { + Text(texts.latestTitle).bold() + .font(muliBold16) + .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + Text(latestRelease.version) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + Text(texts.currentTitle).bold() + .font(muliBold16) + .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + if let currentVersion = currentRelease?.version { + Text(currentVersion) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + } else { + Text(texts.notReportingDescription) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + } + Button( + action: { + self.viewModel.send( + event: .onStartUpgrade(latestRelease, currentRelease) + ) + }, + label: { + HStack { + Text(texts.startUpdateProcess) + .font(muliBold16) + }.frame(maxWidth: .infinity) + } + ) + .buttonStyle( + LargeButtonStyle( + backgroundColor: RuuviColor.ruuviTintColorSUI, + foregroundColor: Color.white, + isDisabled: false + ) + ) + .padding() + .frame(maxWidth: .infinity) + } + } + .frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .topLeading + ) + .padding() + .eraseToAnyView() + case .reading: + return VStack { + Spinner(isAnimating: true, style: .medium).eraseToAnyView() + }.eraseToAnyView() + case .downloading: + return VStack(alignment: .center, spacing: 16) { + Text(texts.downloadingTitle) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + ProgressBar(value: $viewModel.downloadProgress) + .frame(height: 16) + .padding() + Text("\(Int(viewModel.downloadProgress * 100))%") + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + } + .frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .topLeading + ) + .padding() + .eraseToAnyView() + case .listening: + return VStack { + ScrollView(showsIndicators: false) { + VStack(spacing: 20) { + RuuviBoardView() + VStack(alignment: .leading, spacing: 16) { + Text(texts.prepareTitle).bold() + .font(muliBold16) + .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + Text(texts.openCoverTitle) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + Text(texts.localBootButtonTitle) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + Text(texts.setUpdatingModeTitle) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + Text(texts.toBootModeTwoButtonsDescription) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + Text(texts.toBootModeOneButtonDescription) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + Text(texts.toBootModeSuccessTitle) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + } + Button( + action: {}, + label: { + HStack { + Text(texts.searchingTitle) + .font(muliBold16) + .foregroundColor(.secondary) + Spinner(isAnimating: true, style: .medium).eraseToAnyView() + }.frame(maxWidth: .infinity) + } + ) + .buttonStyle( + LargeButtonStyle( + backgroundColor: RuuviColor.ruuviTintColorSUI, + foregroundColor: Color.white, + isDisabled: true + ) + ) + .padding() + .disabled(true) + .frame(maxWidth: .infinity) + } + } + } + .frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .top + ) + .padding(EdgeInsets(top: 0, leading: 20, bottom: 20, trailing: 20)) + .eraseToAnyView() + case let .readyToUpdate(latestRelease, currentRelease, uuid, appUrl, fullUrl): + return VStack { + ScrollView(showsIndicators: false) { + VStack(spacing: 20) { + RuuviBoardView() + VStack(alignment: .leading, spacing: 16) { + Text(texts.prepareTitle).bold() + .font(muliBold16) + .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + Text(texts.openCoverTitle) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + Text(texts.localBootButtonTitle) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + Text(texts.setUpdatingModeTitle) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + Text(texts.toBootModeTwoButtonsDescription) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + Text(texts.toBootModeOneButtonDescription) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + Text(texts.toBootModeSuccessTitle) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + } + Button( + action: { + self.viewModel.send( + event: .onUserDidConfirmToFlash( + latestRelease, + currentRelease, + uuid: uuid, + appUrl: appUrl, + fullUrl: fullUrl + ) + ) + }, + label: { + Text(texts.startTitle) + .font(muliBold16) + .frame(maxWidth: .infinity) + } + ) + .buttonStyle( + LargeButtonStyle( + backgroundColor: RuuviColor.ruuviTintColorSUI, + foregroundColor: Color.white, + isDisabled: false + ) + ) + .padding() + .frame(maxWidth: .infinity) + } + } + } + .frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .top + ) + .padding(EdgeInsets(top: 0, leading: 20, bottom: 20, trailing: 20)) + .eraseToAnyView() + case .flashing: + return VStack(alignment: .center, spacing: 24) { + Text(texts.updatingTitle) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + ProgressBar(value: $viewModel.flashProgress) + .frame(height: 16) + Text("\(Int(viewModel.flashProgress * 100))%") + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + Text(texts.doNotCloseTitle) + .font(muliBold16) + .bold() + .multilineTextAlignment(.center) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + + } + .frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .topLeading + ) + .padding() + .eraseToAnyView() + case .successfulyFlashed: + return VStack { + Text(texts.successfulTitle) + .font(muliRegular16) + .foregroundColor(RuuviColor.ruuviTextColorSUI) + .frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .topLeading + ) + .padding() + Button( + action: { + self.viewModel.finish() + }, + label: { + Text(texts.finish) + .font(muliBold16) + .frame(maxWidth: .infinity) + } + ) + .buttonStyle( + LargeButtonStyle( + backgroundColor: RuuviColor.ruuviTintColorSUI, + foregroundColor: Color.white, + isDisabled: false + ) + ) + .padding() + .frame(maxWidth: .infinity) + } + .eraseToAnyView() + } + } + + var body: some View { + VStack { + content + } + .accentColor(.red) + .navigationBarBackButtonHidden(true) + .onAppear { + self.viewModel.send(event: .onAppear) + } + } +} + +private extension CGFloat { + func adjustedFontSize() -> CGFloat { + return UIDevice.current.userInterfaceIdiom == .pad ? self + 4 : self + } +} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift new file mode 100644 index 000000000..caeb38507 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift @@ -0,0 +1,410 @@ +import Combine +import Foundation + +protocol FirmwareViewModelOutput: AnyObject { + func firmwareUpgradeDidFinishSuccessfully() +} + +final class FirmwareViewModel: ObservableObject { + @Published private(set) var state: State = .idle + @Published var downloadProgress: Double = 0 + @Published var flashProgress: Double = 0 + var output: FirmwareViewModelOutput? + private let input = PassthroughSubject() + private let uuid: String + private var currentFirmware: String? + private let interactor: FirmwareInteractor + private var bag = Set() + + init( + uuid: String, + currentFirmware: String?, + interactor: FirmwareInteractor + ) { + self.uuid = uuid + self.currentFirmware = currentFirmware + self.interactor = interactor + Publishers.system( + initial: state, + reduce: Self.reduce, + scheduler: RunLoop.main, + feedbacks: [ + self.whenLoading(), + self.whenServing(), + self.whenReading(), + self.whenDownloading(), + self.whenListening(), + self.whenReadyToUpdate(), + self.whenFlashing(), + self.userInput(input: input.eraseToAnyPublisher()) + ] + ) + .assign(to: \.state, on: self) + .store(in: &bag) + } + + func send(event: Event) { + input.send(event) + } + + func finish() { + output?.firmwareUpgradeDidFinishSuccessfully() + } +} + +// MARK: - Feedbacks +extension FirmwareViewModel { + func userInput(input: AnyPublisher) -> Feedback { + Feedback { _ in + return input + } + } + + func whenLoading() -> Feedback { + Feedback { [weak self] (state: State) -> AnyPublisher in + guard case .loading = state, let self else { + return Empty().eraseToAnyPublisher() + } + return self.interactor.loadLatestGitHubRelease() + .receive(on: RunLoop.main) + .map(Event.onLoaded) + .catch { Just(Event.onDidFailLoading($0)) } + .eraseToAnyPublisher() + } + } + + func whenServing() -> Feedback { + Feedback { [weak self] (state: State) -> AnyPublisher in + guard case .serving = state, let self else { + return Empty().eraseToAnyPublisher() + } + if let currentFirmware = self.currentFirmware { + return Just(CurrentRelease(version: currentFirmware)) + .map(Event.onServed) + .eraseToAnyPublisher() + } else { + return self.interactor.serveCurrentRelease(uuid: self.uuid) + .receive(on: RunLoop.main) + .map(Event.onServed) + .catch { _ in Just(Event.onServed(nil)) } + .eraseToAnyPublisher() + } + } + } + + func whenReading() -> Feedback { + Feedback { [weak self] (state: State) -> AnyPublisher in + guard case let .reading(latestRelease, currentRelease) = state, + let sSelf = self else { + return Empty().eraseToAnyPublisher() + } + return sSelf.interactor.read(release: latestRelease) + .receive(on: RunLoop.main) + .map { tuple in + return Event.onRead( + latestRelease, + currentRelease, + appUrl: tuple.appUrl, + fullUrl: tuple.fullUrl + ) + } + .catch { error in Just(Event.onDidFailReading(latestRelease, currentRelease, error)) } + .eraseToAnyPublisher() + } + } + + func whenDownloading() -> Feedback { + Feedback { [weak self] (state: State) -> AnyPublisher in + guard case let .downloading(latestRelease, currentRelease) = state, let self else { + return Empty().eraseToAnyPublisher() + } + return self.interactor.download(release: latestRelease) + .receive(on: RunLoop.main) + .compactMap({ [weak self] response in + switch response { + case let .response(appUrl, fullUrl): + return Event.onDownloaded(latestRelease, currentRelease, appUrl: appUrl, fullUrl: fullUrl) + case .progress(let progress): + self?.downloadProgress = progress.fractionCompleted + return nil + } + }) + .catch { Just(Event.onDidFailDownloading($0)) } + .eraseToAnyPublisher() + } + } + + func whenListening() -> Feedback { + Feedback { [weak self] (state: State) -> AnyPublisher in + guard case let .listening(latestRelease, currentRelease, appUrl, fullUrl) = state, + let sSelf = self else { + return Empty().eraseToAnyPublisher() + } + return sSelf.interactor.listen() + .receive(on: RunLoop.main) + .map { uuid in + return Event.onHeardRuuviBootDevice( + latestRelease, + currentRelease, + uuid: uuid, + appUrl: appUrl, + fullUrl: fullUrl + ) + } + .eraseToAnyPublisher() + } + } + + func whenReadyToUpdate() -> Feedback { + Feedback { [weak self] (state: State) -> AnyPublisher in + guard case let .readyToUpdate(latestRelease, currentRelease, uuid, appUrl, fullUrl) = state, + let sSelf = self else { + return Empty().eraseToAnyPublisher() + } + return sSelf.interactor.observeLost(uuid: uuid) + .receive(on: RunLoop.main) + .map { uuid in + return Event.onLostRuuviBootDevice( + latestRelease, + currentRelease, + uuid: uuid, + appUrl: appUrl, + fullUrl: fullUrl + ) + } + .eraseToAnyPublisher() + } + } + + func whenFlashing() -> Feedback { + Feedback { [weak self] (state: State) -> AnyPublisher in + guard case let .flashing( + latestRelease, + currentRelease, + uuid, + appUrl, + fullUrl + ) = state, let sSelf = self else { + return Empty().eraseToAnyPublisher() + } + return sSelf.interactor.flash( + uuid: uuid, + latestRelease: latestRelease, + currentRelease: currentRelease, + appUrl: appUrl, + fullUrl: fullUrl + ) + .receive(on: RunLoop.main) + .compactMap({ [weak sSelf] response in + switch response { + case .done: + return Event.onSuccessfullyFlashedFirmware(latestRelease) + case .progress(let percentage): + sSelf?.flashProgress = percentage + return nil + case .log: + return nil + } + }) + .catch { Just(Event.onDidFailFlashingFirmware($0)) } + .eraseToAnyPublisher() + } + } +} + +extension FirmwareViewModel { + enum State { + case idle + case loading + case loaded(GitHubRelease) + case serving(GitHubRelease) + case checking(GitHubRelease, CurrentRelease?) + case noNeedToUpgrade(GitHubRelease, CurrentRelease?) + case isAbleToUpgrade(GitHubRelease, CurrentRelease?) + case reading(GitHubRelease, CurrentRelease?) + case downloading(GitHubRelease, CurrentRelease?) + case listening( + GitHubRelease, + CurrentRelease?, + appUrl: URL, + fullUrl: URL + ) + case readyToUpdate( + GitHubRelease, + CurrentRelease?, + uuid: String, + appUrl: URL, + fullUrl: URL + ) + case flashing( + GitHubRelease, + CurrentRelease?, + uuid: String, + appUrl: URL, + fullUrl: URL + ) + case successfulyFlashed(GitHubRelease) + case error(Error) + } + + enum Event { + case onAppear + case onLoaded(GitHubRelease) + case onDidFailLoading(Error) + case onServed(CurrentRelease?) + case onLoadedAndServed(GitHubRelease, CurrentRelease?) + case onStartUpgrade(GitHubRelease, CurrentRelease?) + case onRead( + GitHubRelease, + CurrentRelease?, + appUrl: URL, + fullUrl: URL + ) + case onDidFailReading(GitHubRelease, CurrentRelease?, Error) + case onDownloading(GitHubRelease, CurrentRelease?, Double) + case onDownloaded( + GitHubRelease, + CurrentRelease?, + appUrl: URL, + fullUrl: URL + ) + case onDidFailDownloading(Error) + case onHeardRuuviBootDevice( + GitHubRelease, + CurrentRelease?, + uuid: String, + appUrl: URL, + fullUrl: URL + ) + case onLostRuuviBootDevice( + GitHubRelease, + CurrentRelease?, + uuid: String, + appUrl: URL, + fullUrl: URL + ) + case onUserDidConfirmToFlash( + GitHubRelease, + CurrentRelease?, + uuid: String, + appUrl: URL, + fullUrl: URL + ) + case onSuccessfullyFlashedFirmware(GitHubRelease) + case onServedAfterUpdate(CurrentRelease?) + case onDidFailFlashingFirmware(Error) + } +} + +extension FirmwareViewModel { + static func reduce(_ state: State, _ event: Event) -> State { + switch state { + case .idle: + switch event { + case .onAppear: + return .loading + default: + return state + } + case .loading: + switch event { + case let .onDidFailLoading(error): + return .error(error) + case let .onLoaded(latestRelease): + return .loaded(latestRelease) + default: + return state + } + case let .loaded(latestRelease): + return .serving(latestRelease) + case let .serving(latestRelease): + switch event { + case let .onServed(currentRelease): + return .checking(latestRelease, currentRelease) + default: + return state + } + case let .checking(latestRelease, currentRelease): + if isRecommendedToUpdate( + latestRelease: latestRelease, + currentRelease: currentRelease + ) { + return .isAbleToUpgrade(latestRelease, currentRelease) + } else { + return .noNeedToUpgrade(latestRelease, currentRelease) + } + case .noNeedToUpgrade: + return state + case let .isAbleToUpgrade(latestRelease, currentRelease): + return .reading(latestRelease, currentRelease) + case .reading: + switch event { + case let .onRead(latestRelease, currentRelease, appUrl, fullUrl): + return .listening( + latestRelease, + currentRelease, + appUrl: appUrl, + fullUrl: fullUrl + ) + case let .onDidFailReading(latestRelease, currentRelease, _): + return .downloading(latestRelease, currentRelease) + default: + return state + } + case .downloading: + switch event { + case let .onDownloaded( + latestRelease, + currentRelease, + appUrl, + fullUrl + ): + return .listening( + latestRelease, + currentRelease, + appUrl: appUrl, + fullUrl: fullUrl + ) + default: + return state + } + case .listening: + switch event { + case let .onHeardRuuviBootDevice(latestRelease, currentRelease, uuid, appUrl, fullUrl): + return .readyToUpdate(latestRelease, currentRelease, uuid: uuid, appUrl: appUrl, fullUrl: fullUrl) + default: + return state + } + case .readyToUpdate: + switch event { + case let .onLostRuuviBootDevice(latestRelease, currentRelease, _, appUrl, fullUrl): + return .listening(latestRelease, currentRelease, appUrl: appUrl, fullUrl: fullUrl) + case let .onUserDidConfirmToFlash(latestRelease, currentRelease, uuid, appUrl, fullUrl): + return .flashing(latestRelease, currentRelease, uuid: uuid, appUrl: appUrl, fullUrl: fullUrl) + default: + return state + } + case .flashing: + switch event { + case .onSuccessfullyFlashedFirmware(let latestRelease): + return .successfulyFlashed(latestRelease) + case .onDidFailFlashingFirmware(let error): + return .error(error) + default: + return state + } + case .successfulyFlashed: + return state + case .error: + return state + } + } + + static func isRecommendedToUpdate( + latestRelease: GitHubRelease, + currentRelease: CurrentRelease? + ) -> Bool { + guard let currentRelease = currentRelease else { return true } + return !currentRelease.version.contains(latestRelease.version) + } +} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift new file mode 100644 index 000000000..be1ad1013 --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift @@ -0,0 +1,88 @@ +import Foundation +import UIKit + +extension Bundle { + public static func pod(_ clazz: AnyClass) -> Bundle { + if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { + if let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), let bundle = Bundle(url: bundleURL) { + return bundle + } else if let bundleURL = Bundle(for: clazz).resourceURL, let bundle = Bundle(url: bundleURL) { + return bundle + } else { + assertionFailure() + return Bundle.main + } + } else { + assertionFailure() + return Bundle.main + } + } +} + +extension UIImage { + public static func named(_ name: String, for clazz: AnyClass) -> UIImage? { + #if SWIFT_PACKAGE + return UIImage(named: name, in: Bundle.module, compatibleWith: nil) + #else + return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) + #endif + } +} + +extension String { + public func localized(for clazz: AnyClass) -> String { + let bundle: Bundle + #if SWIFT_PACKAGE + bundle = Bundle.module + #else + bundle = Bundle.pod(clazz) + #endif + if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { + if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), + let bundle = Bundle(path: path) { + return bundle.localizedString(forKey: self, value: nil, table: module) + } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), + let bundle = Bundle(path: path) { + return bundle.localizedString(forKey: self, value: nil, table: module) + } else { + assertionFailure() + return self + } + } else { + assertionFailure() + return self + } + } + + private func currentLanguage() -> String { + if let preferred = Bundle.main.preferredLocalizations.first { + return preferred + } else { + return "Base" + } + } +} + +extension UIStoryboard { + public static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { + let bundle: Bundle + #if SWIFT_PACKAGE + bundle = Bundle.module + #else + bundle = Bundle.pod(clazz) + #endif + return UIStoryboard(name: name, bundle: bundle) + } +} + +extension UINib { + public static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { + let bundle: Bundle + #if SWIFT_PACKAGE + bundle = Bundle.module + #else + bundle = Bundle.pod(clazz) + #endif + return UINib(nibName: nibName, bundle: bundle) + } +} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviColor.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviColor.swift new file mode 100644 index 000000000..299f683da --- /dev/null +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviColor.swift @@ -0,0 +1,8 @@ +import SwiftUI + +struct RuuviColor { + static let green = Color("RuuviGreen") + static let ruuviTintColorSUI = Color("RuuviTintColor") + static let ruuviTextColorSUI = Color("RuuviTextColor") + static let ruuviTitleTextColorSUI = Color("RuuviMenuTextColor") +} diff --git a/Modules/RuuviFirmware/Tests/RuuviFirmwareTests/RuuviFirmwareTests.swift b/Modules/RuuviFirmware/Tests/RuuviFirmwareTests/RuuviFirmwareTests.swift new file mode 100644 index 000000000..7bf78dcd8 --- /dev/null +++ b/Modules/RuuviFirmware/Tests/RuuviFirmwareTests/RuuviFirmwareTests.swift @@ -0,0 +1,12 @@ +import XCTest +@testable import RuuviFirmware + +final class RuuviFirmwareTests: XCTestCase { + func testExample() throws { + // XCTest Documentation + // https://developer.apple.com/documentation/xctest + + // Defining Test Cases and Test Methods + // https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods + } +} diff --git a/Modules/RuuviFirmware/target.yml b/Modules/RuuviFirmware/target.yml new file mode 100644 index 000000000..5ef05adf0 --- /dev/null +++ b/Modules/RuuviFirmware/target.yml @@ -0,0 +1,11 @@ +--- +targets: + RuuviFirmware: + settings: + base: + MERGEABLE_LIBRARY: false + templates: + - Module + dependencies: + - package: BTKit + - target: RuuviDFU diff --git a/project_frameworks.yml b/project_frameworks.yml index b3e650b3c..4ea95427f 100644 --- a/project_frameworks.yml +++ b/project_frameworks.yml @@ -181,6 +181,7 @@ include: - Common/RuuviLocalization/target.yml - Modules/RuuviDiscover/target.yml - Modules/RuuviOnboard/target.yml +- Modules/RuuviFirmware/target.yml - widget_frameworks.yml - pnservice.yml - intents_frameworks.yml @@ -243,6 +244,7 @@ targets: - target: RuuviPresenters - target: RuuviDiscover - target: RuuviOnboard + - target: RuuviFirmware - target: RuuviLocalization info: path: station/Resources/Plists/Info.plist diff --git a/station/Classes/Application/AppAssembly.swift b/station/Classes/Application/AppAssembly.swift index 7a73e36cd..fee63d44f 100644 --- a/station/Classes/Application/AppAssembly.swift +++ b/station/Classes/Application/AppAssembly.swift @@ -18,6 +18,7 @@ import RuuviNotifier import RuuviNotification import RuuviRepository import RuuviCore +import RuuviFirmware import RuuviDiscover import RuuviPresenters #if canImport(RuuviCloudPure) @@ -776,7 +777,8 @@ private final class ModulesAssembly: Assembly { permissionPresenter: permissionPresenter, foreground: foreground, ruuviReactor: ruuviReactor, - ruuviOwnershipService: ruuviOwnershipService + ruuviOwnershipService: ruuviOwnershipService, + firmwareBuilder: RuuviFirmwareBuilder() ) return factory.create(dependencies: dependencies) } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Common/Spinner.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Common/Spinner.swift deleted file mode 100644 index ff819451f..000000000 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Common/Spinner.swift +++ /dev/null @@ -1,21 +0,0 @@ -import SwiftUI -import UIKit - -struct Spinner: UIViewRepresentable { - let isAnimating: Bool - let style: UIActivityIndicatorView.Style - - func makeUIView(context: Context) -> UIActivityIndicatorView { - let spinner = UIActivityIndicatorView(style: style) - spinner.hidesWhenStopped = true - return spinner - } - - func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) { - if isAnimating { - uiView.startAnimating() - } else { - uiView.stopAnimating() - } - } -} diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Extensions/View+Any.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Extensions/View+Any.swift deleted file mode 100644 index d1e9b9381..000000000 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Extensions/View+Any.swift +++ /dev/null @@ -1,15 +0,0 @@ -import SwiftUI - -extension View { - func eraseToAnyView() -> AnyView { AnyView(self) } -} -extension View { - func onReceive(_ name: Notification.Name, - center: NotificationCenter = .default, - object: AnyObject? = nil, - perform action: @escaping (Notification) -> Void) -> some View { - self.onReceive( - center.publisher(for: name, object: object), perform: action - ) - } -} diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift index dff55dbbf..124271411 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift @@ -3,6 +3,7 @@ import Combine import BTKit import RuuviOntology import RuuviDFU +import RuuviFirmware final class DFUInteractor { var ruuviDFU: RuuviDFU! diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift index dab7709c2..aa0530769 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift @@ -9,6 +9,7 @@ import RuuviDaemon import RuuviPresenters import BTKit import RuuviPersistence +import RuuviFirmware final class DFUViewModel: ObservableObject { @Published private(set) var state: State = .idle diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift index 5590c934b..9dc412610 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift @@ -1,4 +1,6 @@ +import RuuviFirmware import SwiftUI + // swiftlint:disable file_length // swiftlint:disable:next type_body_length struct DFUUIView: View { @@ -442,31 +444,4 @@ struct DFUUIView: View { func goBack() { self.presentationMode.wrappedValue.dismiss() } - - struct RuuviBoardView: View { - @State private var isPortrait = false - private let boardImageName = "ruuvitag-b8-and-older-button-location" - var body: some View { - HStack { - if isPortrait { - Image(boardImageName) - .resizable() - .aspectRatio(contentMode: .fit) - } else { - Spacer() - Image(boardImageName) - .resizable() - .aspectRatio(contentMode: .fit) - .scaledToFit() - .frame(width: 300, height: 147) - Spacer() - } - } - .padding() - .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in - guard let scene = UIApplication.shared.windows.first?.windowScene else { return } - self.isPortrait = scene.interfaceOrientation.isPortrait - } - } - } } diff --git a/station/Resources/Colors/Colors.xcassets/RuuviTintColor.colorset/Contents.json b/station/Resources/Colors/Colors.xcassets/RuuviTintColor.colorset/Contents.json index 986f01823..67e2f95b3 100644 --- a/station/Resources/Colors/Colors.xcassets/RuuviTintColor.colorset/Contents.json +++ b/station/Resources/Colors/Colors.xcassets/RuuviTintColor.colorset/Contents.json @@ -6,8 +6,8 @@ "components" : { "alpha" : "1.000", "blue" : "0.624", - "green" : "0.678", - "red" : "0.208" + "green" : "0.677", + "red" : "0.209" } }, "idiom" : "universal" From 443fc2e56b595efdc7f3026360a5fc717f4fbca1 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sun, 3 Dec 2023 22:25:07 +0200 Subject: [PATCH 24/84] Replace [pod] based build with [frameworks] on alpha merge (#1745) From now frameworks xcodeproj is being used to build on merge to alpha branch --- .github/workflows/firebase.yml | 12 ++++-------- .github/workflows/firebase_frameworks.yml | 10 +++++++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/firebase.yml b/.github/workflows/firebase.yml index 1d0f41a57..b01e5a1ca 100644 --- a/.github/workflows/firebase.yml +++ b/.github/workflows/firebase.yml @@ -1,14 +1,10 @@ name: Upload to Firebase on: - pull_request: - types: - - closed - branches: [ alpha ] + workflow_dispatch: jobs: build: - if: github.event.pull_request.merged == true runs-on: macos-latest steps: @@ -64,7 +60,7 @@ jobs: - name: Build app run: | xcodebuild -workspace station.xcworkspace -scheme station_dev -configuration Debug -archivePath ./Build/Station_Dev.xcarchive archive -allowProvisioningUpdates - + - name: Export IPA env: EXPORT_PLIST: ${{ secrets.ADHOC_EXPORT_OPTIONS }} @@ -80,7 +76,7 @@ jobs: --app ${{ secrets.GOOGLE_APP_ID }} \ --token ${{ secrets.FIREBASE_REFRESH_TOKEN }} \ --groups ${{ secrets.ALPHA_TESTERS_GROUP }} \ - --release-notes "Features, enhancements and bug fixes." + --release-notes "Features, enhancements and bug fixes." - name: Zip dSYM files run: | @@ -89,7 +85,7 @@ jobs: - name: Upload dSYM to Firebase run: | find ${{ runner.temp }}/export -name '*.dSYM.zip' | xargs -I \{\} firebase crashlytics:upload-symbols --app ${{ secrets.GOOGLE_APP_ID }} -g \{\} - + - name: Clean up keychain and provisioning profiles if: ${{ always() }} run: | diff --git a/.github/workflows/firebase_frameworks.yml b/.github/workflows/firebase_frameworks.yml index e39a05eb3..48b6d5309 100644 --- a/.github/workflows/firebase_frameworks.yml +++ b/.github/workflows/firebase_frameworks.yml @@ -1,10 +1,14 @@ name: Deploy to Firebase [frameworks] on: - workflow_dispatch: + pull_request: + types: + - closed + branches: [alpha] jobs: build: + if: github.event.pull_request.merged == true runs-on: macos-13 steps: @@ -69,7 +73,7 @@ jobs: - name: Build app run: | - xcodebuild -project frameworks.xcodeproj -scheme station -configuration Alpha -archivePath ./Build/Station_Dev.xcarchive archive -allowProvisioningUpdates + xcodebuild -project frameworks.xcodeproj -scheme station -configuration Alpha -archivePath ./Build/Station_Dev.xcarchive archive -allowProvisioningUpdates - name: Export IPA env: EXPORT_PLIST: ${{ secrets.ADHOC_EXPORT_OPTIONS }} @@ -89,7 +93,7 @@ jobs: --app ${{ secrets.GOOGLE_APP_ID }} \ --token ${{ secrets.FIREBASE_REFRESH_TOKEN }} \ --groups ${{ secrets.ALPHA_TESTERS_GROUP }} \ - --release-notes ${{ steps.build_changelog.outputs.changelog }} + --release-notes "${{ steps.build_changelog.outputs.changelog }}" - name: Zip dSYM files run: | From 1cfeba467dde72a9004935e82bf74645dc0f7110 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Wed, 6 Dec 2023 22:29:57 +0200 Subject: [PATCH 25/84] Script for setting build number to datetime (#1752) Implements build script that sets the build number to the date time. Adds this script execution to firebase_frameworks workflow. --- .github/workflows/firebase_frameworks.yml | 3 +-- Makefile | 4 ++++ project_frameworks.yml | 6 ++++-- scripts/build/set_build_number.sh | 17 +++++++++++++++++ 4 files changed, 26 insertions(+), 4 deletions(-) create mode 100755 scripts/build/set_build_number.sh diff --git a/.github/workflows/firebase_frameworks.yml b/.github/workflows/firebase_frameworks.yml index 48b6d5309..a596062c8 100644 --- a/.github/workflows/firebase_frameworks.yml +++ b/.github/workflows/firebase_frameworks.yml @@ -56,8 +56,7 @@ jobs: - name: Increment build number run: | - buildNumber=$(date '+%y%m%d%H%M') - /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" ${{ github.workspace }}/station/Resources/Plists/Info.plist + make set_build_number_frameworks - name: Make xcodeproj run: | diff --git a/Makefile b/Makefile index 176718ac7..2c90e4873 100644 --- a/Makefile +++ b/Makefile @@ -40,3 +40,7 @@ build_with_pods: d=$$(date +%s)\ ; xcodebuild -workspace station.xcworkspace -scheme station -configuration Release -sdk iphoneos17.0 build\ && echo "Build took $$(($$(date +%s)-d)) seconds" + +# sets the build number to current datetime +set_build_number_frameworks: + scripts/build/set_build_number.sh project_frameworks.yml \ No newline at end of file diff --git a/project_frameworks.yml b/project_frameworks.yml index 4ea95427f..4c3d7d50d 100644 --- a/project_frameworks.yml +++ b/project_frameworks.yml @@ -1,3 +1,5 @@ +BUILD_NUMBER: &BUILD_NUMBER 1 +APP_VERSION: &APP_VERSION 2.5.2 APP_NAME: &APP_NAME frameworks DEVELOPMENT_TEAM: &DEVELOPMENT_TEAM 4MUYJ4YYH4 BUNDLE_ID_PREFIX: &BUNDLE_ID_PREFIX com.ruuvi @@ -7,8 +9,8 @@ attributes: settings: base: - CURRENT_PROJECT_VERSION: 1 - MARKETING_VERSION: "2.5.2" + CURRENT_PROJECT_VERSION: *BUILD_NUMBER + MARKETING_VERSION: *APP_VERSION DEVELOPMENT_TEAM: *DEVELOPMENT_TEAM name: *APP_NAME diff --git a/scripts/build/set_build_number.sh b/scripts/build/set_build_number.sh new file mode 100755 index 000000000..d5d734224 --- /dev/null +++ b/scripts/build/set_build_number.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# Check if a file name is provided +if [ "$#" -ne 1 ]; then + echo "Usage: $0 " + exit 1 +fi + +# Assign the filename to a variable +filename=$1 + +# Generate the replacement string +replacement=$(date '+%y%m%d%H%M') + +# Use sed to replace the number at the end of the line +# The regex looks for the pattern, captures the start of the line, and replaces only the last number +sed -i '' "s/^\(BUILD_NUMBER: &BUILD_NUMBER \)[0-9]*$/\1$replacement/" "$filename" From 3500e7680aa292ac3b9c4c6c07ba02269eac24b2 Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Sun, 3 Dec 2023 18:40:45 +0100 Subject: [PATCH 26/84] task: Implement toast based activity indicator #1600 - Replaces old implementation of indicator --- .../RuuviLogo/ActivityPresenterPosition.swift | 7 ++ .../ActivityPresenterRuuviLogo.swift | 77 +++++-------- .../RuuviLogo/ActivityPresenterState.swift | 26 +++++ .../View/ActivityPresenterView.swift | 107 ++++++++++++++++++ .../View/ActivityPresenterViewProvider.swift | 29 +++++ .../ActivityRuuviLogoViewController.swift | 76 ------------- .../RuuviLogo/View/ActivitySpinnerView.swift | 15 ++- .../RuuviPresenters/ActivityPresenter.swift | 13 ++- .../Error/Alert/ErrorPresenterAlert.swift | 7 +- .../Contents.json | 2 +- .../ruuvi_activity_presenter_logo.png} | Bin .../de.lproj/RuuviPresenters.strings | 3 + .../en.lproj/RuuviPresenters.strings | 3 + .../fi.lproj/RuuviPresenters.strings | 3 + .../fr.lproj/RuuviPresenters.strings | 3 + .../ru.lproj/RuuviPresenters.strings | 3 + .../sv.lproj/RuuviPresenters.strings | 3 + station.localization | 2 +- .../TagChartsViewInteractorOutput.swift | 1 - .../Presenter/TagChartsViewPresenter.swift | 17 +-- .../Home/Presenter/DashboardPresenter.swift | 4 +- .../Presenter/MyRuuviAccountPresenter.swift | 11 +- .../Share/Presenter/SharePresenter.swift | 8 +- .../SignIn/Presenter/SignInPresenter.swift | 20 ++-- .../Presenter/TagSettingsPresenter.swift | 10 +- .../Submodules/DFU/View/DFUViewModel.swift | 2 +- .../Presenter/SensorForceClaimPresenter.swift | 21 +--- .../Owner/Presenter/OwnerPresenter.swift | 23 ++-- .../Alert/Impl/AlertPresenterImpl.swift | 6 +- .../Strings/de.lproj/Localizable.strings | 6 + .../Strings/en.lproj/Localizable.strings | 6 + .../Strings/fi.lproj/Localizable.strings | 6 + .../Strings/fr.lproj/Localizable.strings | 6 + .../Strings/ru.lproj/Localizable.strings | 6 + .../Strings/sv.lproj/Localizable.strings | 6 + 35 files changed, 321 insertions(+), 217 deletions(-) create mode 100644 Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterPosition.swift create mode 100644 Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterState.swift create mode 100644 Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift create mode 100644 Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterViewProvider.swift delete mode 100644 Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityRuuviLogoViewController.swift rename Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/{ruuvi_logo_for_activity_presenter.imageset => ruuvi_activity_presenter_logo.imageset}/Contents.json (68%) rename Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/{ruuvi_logo_for_activity_presenter.imageset/web-ruuvi-eye-nega.png => ruuvi_activity_presenter_logo.imageset/ruuvi_activity_presenter_logo.png} (100%) diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterPosition.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterPosition.swift new file mode 100644 index 000000000..7b8d675c1 --- /dev/null +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterPosition.swift @@ -0,0 +1,7 @@ +import Foundation + +public enum ActivityPresenterPosition { + case top + case bottom + case center +} diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift index 340e07d42..1dc2b30a2 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift @@ -1,74 +1,51 @@ import UIKit public final class ActivityPresenterRuuviLogo: ActivityPresenter { - var counter = 0 { - didSet { - switch counter { - case 0: - hide() - case 1: - show() - default: - return - } - } - } - let minAnimationTime: CFTimeInterval = 0.75 + let minAnimationTime: CFTimeInterval = 1.0 var startTime: CFTimeInterval? let window = UIWindow(frame: UIScreen.main.bounds) - let hudViewController: ActivityRuuviLogoViewController + let activityPresenterViewProvider: ActivityPresenterViewProvider + let activityPresenterViewController: UIViewController + let stateHolder = ActivityPresenterStateHolder() + weak var appWindow: UIWindow? public init() { - hudViewController = ActivityRuuviLogoViewController() + activityPresenterViewProvider = ActivityPresenterViewProvider(stateHolder: stateHolder) + activityPresenterViewController = activityPresenterViewProvider.makeViewController() + activityPresenterViewController.view.backgroundColor = .clear window.windowLevel = .normal - hudViewController.view.translatesAutoresizingMaskIntoConstraints = false - window.rootViewController = hudViewController - } - - public func increment() { - counter += 1 - hideMessageLabel() - } - - public func increment(with message: String) { - counter += 1 - showMessageLabel(with: message) + activityPresenterViewController.view.translatesAutoresizingMaskIntoConstraints = false + window.rootViewController = activityPresenterViewController } +} - public func decrement() { - guard counter > 0 else { - return - } - counter -= 1 +extension ActivityPresenterRuuviLogo { + public func setPosition(_ position: ActivityPresenterPosition) { + activityPresenterViewProvider.updatePosition(position) } - private func show() { + public func show(with state: ActivityPresenterState) { startTime = CFAbsoluteTimeGetCurrent() appWindow = UIWindow.key window.makeKeyAndVisible() - hudViewController.spinnerView.animate() + window.layoutIfNeeded() + activityPresenterViewProvider.updateState(state) } - private func showMessageLabel(with message: String) { - hudViewController.messageLabel.alpha = 1 - hudViewController.messageLabel.text = message + public func update(with state: ActivityPresenterState) { + activityPresenterViewProvider.updateState(state) } - private func hide() { + public func dismiss(immediately: Bool) { let executionTime = CFAbsoluteTimeGetCurrent() - (startTime ?? 0) - let additionalWaitTime = executionTime < minAnimationTime ? (minAnimationTime - executionTime) : 0 - DispatchQueue.main.asyncAfter(deadline: .now() + additionalWaitTime) { - self.appWindow?.makeKeyAndVisible() - self.appWindow = nil - self.window.isHidden = true - self.hudViewController.spinnerView.stopAnimating() - self.hideMessageLabel() + let additionalWaitTime = immediately ? 0 : + executionTime < minAnimationTime ? (minAnimationTime - executionTime) : 0 + DispatchQueue.main.asyncAfter(deadline: .now() + additionalWaitTime) { [weak self] in + self?.activityPresenterViewProvider.updateState(.dismiss) + self?.appWindow?.makeKeyAndVisible() + self?.appWindow = nil + self?.window.isHidden = true } } - - private func hideMessageLabel() { - hudViewController.messageLabel.alpha = 0 - hudViewController.messageLabel.text = nil - } } diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterState.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterState.swift new file mode 100644 index 000000000..4534bbf82 --- /dev/null +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterState.swift @@ -0,0 +1,26 @@ +import Foundation + +public enum ActivityPresenterState: Equatable { + case loading(message: String?) + case success(message: String?) + case failed(message: String?) + case dismiss + + public static func == ( + lhs: ActivityPresenterState, + rhs: ActivityPresenterState + ) -> Bool { + switch (lhs, rhs) { + case (.loading(let lhsMessage), .loading(let rhsMessage)): + return lhsMessage == rhsMessage + case (.success(let lhsMessage), .success(let rhsMessage)): + return lhsMessage == rhsMessage + case (.failed(let lhsMessage), .failed(let rhsMessage)): + return lhsMessage == rhsMessage + case (.dismiss, .dismiss): + return true + default: + return false + } + } +} diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift new file mode 100644 index 000000000..bd4f999b3 --- /dev/null +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift @@ -0,0 +1,107 @@ +import UIKit +import SwiftUI + +private struct ActivityPresenterAssets { + static let activityOngoingDefault = "activity_ongoing_generic" + static let activitySuccessDefault = "activity_success_generic" + static let activityFailedDefault = "activity_failed_generic" + + static let activityLogoRuuvi = "ruuvi_activity_presenter_logo" +} + +public struct ActivityPresenterView: View { + @EnvironmentObject var stateHolder: ActivityPresenterStateHolder + + public var body: some View { + VStack { + if stateHolder.position == .bottom || stateHolder.position == .center { + Spacer() + } + + ActivityPresenterContentView(state: stateHolder.state) + .padding([.leading, .trailing], + stateHolder.state == .dismiss ? 0 : 12) + .padding([.top, .bottom], + stateHolder.state == .dismiss ? 0 : 12) + .background(Color.black.opacity(0.8)) + .cornerRadius(8) + .foregroundColor(.white) + .transition(.scale.combined(with: .opacity)) + .opacity(stateHolder.state == .dismiss ? 0 : 1) + + if stateHolder.position == .top || stateHolder.position == .center { + Spacer() + } + } + } +} + +struct ActivityPresenterContentView: View { + let state: ActivityPresenterState + + var body: some View { + HStack(spacing: 8) { + if case .loading = state { + ZStack { + contentImage? + .resizable() + .frame(width: 24, height: 24) + ActivitySpinnerViewRepresentable() + .frame(width: 30, height: 30) + } + } else { + contentImage? + .resizable() + .frame(width: 12, height: 12) + } + Text(message) + } + } + + private var contentImage: Image? { + switch state { + case .loading: + return Image( + ActivityPresenterAssets.activityLogoRuuvi, + bundle: .pod(ActivityPresenterViewProvider.self) + ) + case .success: + return Image(systemName: "checkmark") + case .failed: + return Image(systemName: "xmark") + default: + return nil + } + } + + private var message: String { + switch state { + case .loading(let message): + if let message = message { + return message + } else { + return ActivityPresenterAssets + .activityOngoingDefault + .localized(for: ActivityPresenterViewProvider.self) + } + case .success(let message): + if let message = message { + return message + } else { + return ActivityPresenterAssets + .activitySuccessDefault + .localized(for: ActivityPresenterViewProvider.self) + } + case .failed(let message): + if let message = message { + return message + } else { + return ActivityPresenterAssets + .activityFailedDefault + .localized(for: ActivityPresenterViewProvider.self) + } + case .dismiss: + return "" // Placeholder for dismiss state + } + } +} diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterViewProvider.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterViewProvider.swift new file mode 100644 index 000000000..8feb10916 --- /dev/null +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterViewProvider.swift @@ -0,0 +1,29 @@ +import UIKit +import SwiftUI + +public class ActivityPresenterStateHolder: ObservableObject { + @Published var state: ActivityPresenterState = .dismiss + @Published var position: ActivityPresenterPosition = .bottom +} + +public class ActivityPresenterViewProvider: NSObject { + private var stateHolder: ActivityPresenterStateHolder + + public init(stateHolder: ActivityPresenterStateHolder) { + self.stateHolder = stateHolder + } + + public func makeViewController() -> UIViewController { + return UIHostingController( + rootView: ActivityPresenterView().environmentObject(stateHolder) + ) + } + + func updateState(_ newState: ActivityPresenterState) { + self.stateHolder.state = newState + } + + func updatePosition(_ position: ActivityPresenterPosition) { + self.stateHolder.position = position + } +} diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityRuuviLogoViewController.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityRuuviLogoViewController.swift deleted file mode 100644 index c50eab597..000000000 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityRuuviLogoViewController.swift +++ /dev/null @@ -1,76 +0,0 @@ -import UIKit - -public final class ActivityRuuviLogoViewController: UIViewController { - var statusBarStyle = UIStatusBarStyle.default - var statusBarHidden = false - - private var logoImageView = UIImageView() - var spinnerView = ActivitySpinnerView() - var messageLabel = UILabel() - - public init() { - super.init(nibName: nil, bundle: nil) - setupView() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - public override func viewDidLoad() { - super.viewDidLoad() - logoImageView.tintColor = UIColor.white - messageLabel.textColor = .white - } - - public override var preferredStatusBarStyle: UIStatusBarStyle { - guard let topVC = UIApplication.shared.topViewController() else { return statusBarStyle } - if !topVC.isKind(of: ActivityRuuviLogoViewController.self) { - statusBarStyle = topVC.preferredStatusBarStyle - } - return statusBarStyle - } - - public override var prefersStatusBarHidden: Bool { - guard let topVC = UIApplication.shared.topViewController() else { return statusBarHidden } - if !topVC.isKind(of: ActivityRuuviLogoViewController.self) { - statusBarHidden = topVC.prefersStatusBarHidden - } - return statusBarHidden - } - - private func setupView() { - view.backgroundColor = UIColor(white: 0, alpha: 0.8) - - logoImageView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(logoImageView) - NSLayoutConstraint.activate([ - logoImageView.widthAnchor.constraint(equalToConstant: 64), - logoImageView.heightAnchor.constraint(equalToConstant: 64), - logoImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor), - logoImageView.centerYAnchor.constraint(equalTo: view.centerYAnchor), - ]) - - logoImageView.image = UIImage.named("ruuvi_logo_for_activity_presenter", for: Self.self) - - spinnerView.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(spinnerView) - NSLayoutConstraint.activate([ - spinnerView.widthAnchor.constraint(equalToConstant: 80), - spinnerView.heightAnchor.constraint(equalToConstant: 80), - spinnerView.centerXAnchor.constraint(equalTo: logoImageView.centerXAnchor), - spinnerView.centerYAnchor.constraint(equalTo: logoImageView.centerYAnchor), - ]) - - messageLabel.numberOfLines = 0 - messageLabel.textAlignment = .center - messageLabel.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(messageLabel) - NSLayoutConstraint.activate([ - messageLabel.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 16), - view.safeAreaLayoutGuide.trailingAnchor.constraint(equalTo: messageLabel.trailingAnchor, constant: 16), - messageLabel.topAnchor.constraint(equalTo: spinnerView.bottomAnchor, constant: 16), - ]) - } -} diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivitySpinnerView.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivitySpinnerView.swift index 42d5978a1..2fc57ef06 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivitySpinnerView.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivitySpinnerView.swift @@ -1,6 +1,19 @@ import UIKit +import SwiftUI + +// UIViewRepresentable wrapper for ActivitySpinnerView +struct ActivitySpinnerViewRepresentable: UIViewRepresentable { + func makeUIView(context: Context) -> ActivitySpinnerView { + let spinnerView = ActivitySpinnerView() + spinnerView.animate() + return spinnerView + } + + func updateUIView(_ uiView: ActivitySpinnerView, context: Context) { + // No op + } +} -@IBDesignable class ActivitySpinnerView: UIView { private var strokeColor = UIColor(red: 0.21, green: 0.68, blue: 0.62, alpha: 1.00) diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/ActivityPresenter.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/ActivityPresenter.swift index 6850e281c..084b591bd 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/ActivityPresenter.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/ActivityPresenter.swift @@ -1,7 +1,14 @@ import Foundation public protocol ActivityPresenter { - func increment() - func increment(with message: String) - func decrement() + func setPosition(_ position: ActivityPresenterPosition) + func show(with state: ActivityPresenterState) + func update(with state: ActivityPresenterState) + func dismiss(immediately: Bool) +} + +public extension ActivityPresenter { + func dismiss(immediately: Bool = false) { + dismiss(immediately: immediately) + } } diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Error/Alert/ErrorPresenterAlert.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Error/Alert/ErrorPresenterAlert.swift index 3c6f5bd9c..2c217c1d2 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Error/Alert/ErrorPresenterAlert.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Error/Alert/ErrorPresenterAlert.swift @@ -22,14 +22,9 @@ public final class ErrorPresenterAlert: ErrorPresenter { let group = DispatchGroup() DispatchQueue.main.async { group.enter() - let topViewController = UIApplication.shared.topViewController() - var fireAfter: DispatchTimeInterval = .milliseconds(0) - if topViewController is ActivityRuuviLogoViewController { - fireAfter = .milliseconds(750) - } group.leave() group.notify(queue: .main) { - DispatchQueue.main.asyncAfter(deadline: .now() + fireAfter) { + DispatchQueue.main.async { let feedback = UINotificationFeedbackGenerator() feedback.notificationOccurred(.error) feedback.prepare() diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/ruuvi_logo_for_activity_presenter.imageset/Contents.json b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/ruuvi_activity_presenter_logo.imageset/Contents.json similarity index 68% rename from Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/ruuvi_logo_for_activity_presenter.imageset/Contents.json rename to Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/ruuvi_activity_presenter_logo.imageset/Contents.json index 265ff6156..7164fe16b 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/ruuvi_logo_for_activity_presenter.imageset/Contents.json +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/ruuvi_activity_presenter_logo.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "web-ruuvi-eye-nega.png", + "filename" : "ruuvi_activity_presenter_logo.png", "idiom" : "universal" } ], diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/ruuvi_logo_for_activity_presenter.imageset/web-ruuvi-eye-nega.png b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/ruuvi_activity_presenter_logo.imageset/ruuvi_activity_presenter_logo.png similarity index 100% rename from Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/ruuvi_logo_for_activity_presenter.imageset/web-ruuvi-eye-nega.png rename to Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/ruuvi_activity_presenter_logo.imageset/ruuvi_activity_presenter_logo.png diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/de.lproj/RuuviPresenters.strings b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/de.lproj/RuuviPresenters.strings index 04fc50a21..8c6a6e367 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/de.lproj/RuuviPresenters.strings +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/de.lproj/RuuviPresenters.strings @@ -6,3 +6,6 @@ "PermissionPresenter.settings" = "Einstellungen"; "PermissionPresenter.NoPushNotificationsPermission.message" = "Ruuvi Station benötigt die Berechtigung für Push-Benachrichtigungen, um diese Funktion zu aktivieren"; "Cancel" = "Abbrechen"; +"activity_ongoing_generic" = "Please wait..."; +"activity_success_generic" = "Operation successful."; +"activity_failed_generic" = "Operation failed."; diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/en.lproj/RuuviPresenters.strings b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/en.lproj/RuuviPresenters.strings index 388ecf8fc..f06d8f267 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/en.lproj/RuuviPresenters.strings +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/en.lproj/RuuviPresenters.strings @@ -6,3 +6,6 @@ "PermissionPresenter.settings" = "Settings"; "PermissionPresenter.NoPushNotificationsPermission.message" = "Ruuvi Station needs Push Notifications permission to enable this feature"; "Cancel" = "Cancel"; +"activity_ongoing_generic" = "Please wait..."; +"activity_success_generic" = "Operation successful."; +"activity_failed_generic" = "Operation failed."; diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/fi.lproj/RuuviPresenters.strings b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/fi.lproj/RuuviPresenters.strings index 540220e1b..97a76334a 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/fi.lproj/RuuviPresenters.strings +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/fi.lproj/RuuviPresenters.strings @@ -6,3 +6,6 @@ "PermissionPresenter.settings" = "Asetukset"; "PermissionPresenter.NoPushNotificationsPermission.message" = "Tämä ominaisuus vaatii oikeuden palveluilmoitusten näyttämiseen."; "Cancel" = "Peruuta"; +"activity_ongoing_generic" = "Please wait..."; +"activity_success_generic" = "Operation successful."; +"activity_failed_generic" = "Operation failed."; diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/fr.lproj/RuuviPresenters.strings b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/fr.lproj/RuuviPresenters.strings index 8af2b7633..af478a56a 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/fr.lproj/RuuviPresenters.strings +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/fr.lproj/RuuviPresenters.strings @@ -6,3 +6,6 @@ "PermissionPresenter.settings" = "Réglages"; "PermissionPresenter.NoPushNotificationsPermission.message" = "Veuillez autoriser les notifications dans les réglages de l'appareil."; "Cancel" = "Annuler"; +"activity_ongoing_generic" = "Please wait..."; +"activity_success_generic" = "Operation successful."; +"activity_failed_generic" = "Operation failed."; diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/ru.lproj/RuuviPresenters.strings b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/ru.lproj/RuuviPresenters.strings index 5642f7623..f5c97052c 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/ru.lproj/RuuviPresenters.strings +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/ru.lproj/RuuviPresenters.strings @@ -6,3 +6,6 @@ "PermissionPresenter.settings" = "Настройки"; "PermissionPresenter.NoPushNotificationsPermission.message" = "Ruuvi Station необходим доступ к уведомлениям для того, чтобы использовать эту функцию"; "Cancel" = "Отмена"; +"activity_ongoing_generic" = "Please wait..."; +"activity_success_generic" = "Operation successful."; +"activity_failed_generic" = "Operation failed."; diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/sv.lproj/RuuviPresenters.strings b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/sv.lproj/RuuviPresenters.strings index 27d00de4c..1fb12d7d6 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/sv.lproj/RuuviPresenters.strings +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/sv.lproj/RuuviPresenters.strings @@ -6,3 +6,6 @@ "PermissionPresenter.settings" = "Inställningar"; "PermissionPresenter.NoPushNotificationsPermission.message" = "Ruuvi Station behöver behörighett ill Push-meddelanden för att aktivera den här funktionen."; "Cancel" = "Avbryt"; +"activity_ongoing_generic" = "Please wait..."; +"activity_success_generic" = "Operation successful."; +"activity_failed_generic" = "Operation failed."; diff --git a/station.localization b/station.localization index 45c2e8f00..abd81752b 160000 --- a/station.localization +++ b/station.localization @@ -1 +1 @@ -Subproject commit 45c2e8f008e6d9c94a259b120f7ea190087aa94e +Subproject commit abd81752bbe8a799ff315786287c614b893f6816 diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorOutput.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorOutput.swift index e68d3c750..89299bb21 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorOutput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorOutput.swift @@ -2,7 +2,6 @@ import Foundation import RuuviOntology protocol TagChartsViewInteractorOutput: AnyObject { - var isLoading: Bool { get set } func insertMeasurements(_ newValues: [RuuviMeasurement]) func updateLatestRecord(_ record: RuuviTagSensorRecord) func interactorDidError(_ error: RUError) diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift index b6f9cd155..6592c1f46 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift @@ -52,15 +52,6 @@ class TagChartsViewPresenter: NSObject, TagChartsViewModuleInput { var infoProvider: InfoProvider! private var isSyncing: Bool = false - var isLoading: Bool = false { - didSet { - if isLoading { - activityPresenter.increment() - } else { - activityPresenter.decrement() - } - } - } private var output: TagChartsViewModuleOutput? private var advertisementToken: ObservationToken? @@ -235,12 +226,12 @@ extension TagChartsViewPresenter: TagChartsViewOutput { } func viewDidConfirmToClear(for viewModel: TagChartsViewModel) { - isLoading = true + activityPresenter.show(with: .loading(message: nil)) interactor.deleteAllRecords(for: ruuviTag) .on(failure: {[weak self] (error) in self?.errorPresenter.present(error: error) }, completion: { [weak self] in - self?.isLoading = false + self?.activityPresenter.dismiss(immediately: true) }) } @@ -254,14 +245,14 @@ extension TagChartsViewPresenter: TagChartsViewOutput { } func viewDidTapOnExport() { - isLoading = true + activityPresenter.show(with: .loading(message: nil)) exportService.csvLog(for: ruuviTag.id, settings: sensorSettings) .on(success: { [weak self] url in self?.view?.showExportSheet(with: url) }, failure: { [weak self] (error) in self?.errorPresenter.present(error: error) }, completion: { [weak self] in - self?.isLoading = false + self?.activityPresenter.dismiss(immediately: true) }) } diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift index 57d041a42..e203939e5 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift @@ -1682,7 +1682,7 @@ extension DashboardPresenter { /// Log out user if the auth token is expired. private func forceLogoutUser() { guard ruuviUser.isAuthorized else { return } - activityPresenter.increment() + activityPresenter.show(with: .loading(message: nil)) cloudNotificationService.unregister( token: pnManager.fcmToken, tokenId: nil @@ -1703,7 +1703,7 @@ extension DashboardPresenter { self?.reloadWidgets() self?.handleCloudModeState() }, completion: { [weak self] in - self?.activityPresenter.decrement() + self?.activityPresenter.dismiss() }) } diff --git a/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift b/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift index 791619ffe..690d0ad12 100644 --- a/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift +++ b/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift @@ -34,14 +34,16 @@ extension MyRuuviAccountPresenter: MyRuuviAccountViewOutput { func viewDidTapDeleteButton() { guard let email = ruuviUser.email else { return } - activityPresenter.increment() + activityPresenter.show(with: .loading(message: nil)) ruuviCloud.deleteAccount(email: email).on(success: { [weak self] _ in + self?.activityPresenter.update(with: .success(message: nil)) self?.view.viewDidShowAccountDeletionConfirmation() }, failure: { [weak self] error in + self?.activityPresenter.update(with: .failed(message: nil)) self?.errorPresenter.present(error: error) }, completion: { [weak self] in - self?.activityPresenter.decrement() + self?.activityPresenter.dismiss(immediately: false) }) } @@ -75,13 +77,14 @@ extension MyRuuviAccountPresenter { let confirmAction = UIAlertAction(title: confirmActionTitle, style: .default) { [weak self] (_) in guard let sSelf = self else { return } - sSelf.activityPresenter.increment() + sSelf.activityPresenter.show(with: .loading(message: nil)) sSelf.cloudNotificationService.unregister( token: sSelf.pnManager.fcmToken, tokenId: nil ).on(success: { _ in sSelf.pnManager.fcmToken = nil sSelf.pnManager.fcmTokenLastRefreshed = nil + sSelf.activityPresenter.update(with: .success(message: nil)) }) sSelf.authService.logout() @@ -91,7 +94,7 @@ extension MyRuuviAccountPresenter { sSelf.syncViewModel() sSelf.reloadWidgets() }, completion: { [weak self] in - self?.activityPresenter.decrement() + self?.activityPresenter.dismiss() }) } let cancleAction = UIAlertAction(title: cancelActionTitle, diff --git a/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift b/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift index b4b7c5ab3..ebf527cfe 100644 --- a/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift +++ b/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift @@ -48,7 +48,7 @@ extension SharePresenter: ShareViewOutput { return } - activityPresenter.increment() + activityPresenter.show(with: .loading(message: nil)) ruuviOwnershipService .share(macId: sensor.id.mac, with: email) .on(success: { [weak self] result in @@ -63,12 +63,12 @@ extension SharePresenter: ShareViewOutput { }, failure: { [weak self] error in self?.errorPresenter.present(error: error) }, completion: { [weak self] in - self?.activityPresenter.decrement() + self?.activityPresenter.dismiss() }) } private func unshareTag(_ email: String) { - activityPresenter.increment() + activityPresenter.show(with: .loading(message: nil)) ruuviOwnershipService .unshare(macId: sensor.id.mac, with: email) .on(success: { [weak self] _ in @@ -76,7 +76,7 @@ extension SharePresenter: ShareViewOutput { }, failure: { [weak self] error in self?.errorPresenter.present(error: error) }, completion: { [weak self] in - self?.activityPresenter.decrement() + self?.activityPresenter.dismiss() }) } diff --git a/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift b/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift index 94d96a99e..653039973 100644 --- a/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift +++ b/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift @@ -126,7 +126,7 @@ extension SignInPresenter { } private func sendVerificationCode(for email: String) { - activityPresenter.increment() + activityPresenter.show(with: .loading(message: nil)) ruuviCloud.requestCode(email: email) .on(success: { [weak self] email in guard let sSelf = self else { return } @@ -136,12 +136,12 @@ extension SignInPresenter { }, failure: { [weak self] (error) in self?.errorPresenter.present(error: error) }, completion: { [weak self] in - self?.activityPresenter.decrement() + self?.activityPresenter.dismiss() }) } private func verify(_ code: String) { - activityPresenter.increment(with: "SignIn.Sync.message".localized()) + activityPresenter.show(with: .loading(message: "SignIn.Sync.message".localized())) ruuviCloud.validateCode(code: code) .on(success: { [weak self] result in guard let sSelf = self else { return } @@ -156,26 +156,26 @@ extension SignInPresenter { sSelf.registerFCMToken() sSelf.cloudSyncService.syncAllRecords().on(success: { [weak sSelf] _ in guard let ssSelf = sSelf else { return } - ssSelf.activityPresenter.decrement() ssSelf.cloudSyncDaemon.start() ssSelf.output?.signIn(module: ssSelf, didSuccessfulyLogin: nil) sSelf?.settings.isSyncing = false }, failure: { [weak self] error in - self?.activityPresenter.decrement() self?.errorPresenter.present(error: error) + }, completion: { [weak self] in + self?.activityPresenter.dismiss() }) } else if let requestedEmail = sSelf.ruuviUser.email { - sSelf.activityPresenter.decrement() + sSelf.activityPresenter.dismiss() sSelf.view.showEmailsAreDifferent( requestedEmail: requestedEmail, validatedEmail: result.email ) } else { sSelf.view.showFailedToGetRequestedEmail() - sSelf.activityPresenter.decrement() + sSelf.activityPresenter.dismiss() } }, failure: { [weak self] (error) in - self?.activityPresenter.decrement() + self?.activityPresenter.dismiss() self?.view.showInvalidTokenEntered() self?.errorPresenter.present(error: error) }) @@ -214,7 +214,7 @@ extension SignInPresenter { @objc private func handleAppEnterForgroundState() { switch state { case .isSyncing: - activityPresenter.increment(with: "SignIn.Sync.message".localized()) + activityPresenter.show(with: .loading(message: "SignIn.Sync.message".localized())) default: return } @@ -223,7 +223,7 @@ extension SignInPresenter { @objc private func handleAppEnterBackgroundState() { switch state { case .isSyncing: - activityPresenter.decrement() + activityPresenter.dismiss() default: return } diff --git a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift index 788205a2f..824e6c84a 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift @@ -86,15 +86,7 @@ class TagSettingsPresenter: NSObject, TagSettingsModuleInput { syncOffsetCorrection() } } - private var isLoading: Bool = false { - didSet { - if isLoading { - activityPresenter.increment() - } else { - activityPresenter.decrement() - } - } - } + private var firmwareUpdateDialogShown: Bool = false private var timer: Timer? diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift index dab7709c2..e3ecbf1a1 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift @@ -35,7 +35,7 @@ final class DFUViewModel: ObservableObject { var isLoading: Bool = false { didSet { - isLoading ? activityPresenter.increment() : activityPresenter.decrement() + isLoading ? activityPresenter.show(with: .loading(message: nil)) : activityPresenter.dismiss() } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift index bbd9d27d0..dad1a507e 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift @@ -21,15 +21,7 @@ final class SensorForceClaimPresenter: SensorForceClaimModuleInput { private var ruuviTag: RuuviTagSensor? private var secret: String? - private var isLoading: Bool = false { - didSet { - if isLoading { - activityPresenter.increment() - } else { - activityPresenter.decrement() - } - } - } + private var timer: Timer? private var gattTimeoutSeconds: Double = 15 @@ -90,7 +82,7 @@ extension SensorForceClaimPresenter { withTimeInterval: gattTimeoutSeconds, repeats: true, block: { [weak self] (_) in - self?.isLoading = false + self?.activityPresenter.dismiss() self?.invalidateTimer() self?.view?.showGATTConnectionTimeoutDialog() }) @@ -106,8 +98,7 @@ extension SensorForceClaimPresenter { guard let luid = ruuviTag?.luid else { return } - isLoading = true - // TODO: Check the timeout issue. Timeout not trigerred now. + activityPresenter.show(with: .loading(message: nil)) background.services.gatt.serialRevision( for: self, uuid: luid.value, @@ -117,8 +108,8 @@ extension SensorForceClaimPresenter { case .success(let secret): self?.contestSensor(with: secret) case .failure(let error): + self?.activityPresenter.dismiss() self?.errorPresenter.present(error: error) - self?.isLoading = false } } } @@ -128,7 +119,7 @@ extension SensorForceClaimPresenter { guard let ruuviTag = ruuviTag, let secret = secret else { return } - isLoading = true + activityPresenter.show(with: .loading(message: nil)) ruuviOwnershipService .contest(sensor: ruuviTag, secret: secret) .on(success: { [weak self] _ in @@ -136,7 +127,7 @@ extension SensorForceClaimPresenter { }, failure: { [weak self] error in self?.errorPresenter.present(error: error) }, completion: { [weak self] in - self?.isLoading = false + self?.activityPresenter.dismiss() }) } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift index 853ff5759..5d3f66d7e 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift @@ -29,15 +29,6 @@ final class OwnerPresenter: OwnerModuleInput { view.mode = ownershipMode } } - private var isLoading: Bool = false { - didSet { - if isLoading { - activityPresenter.increment() - } else { - activityPresenter.decrement() - } - } - } func configure(ruuviTag: RuuviTagSensor, mode: OwnershipMode) { self.ruuviTag = ruuviTag @@ -102,12 +93,13 @@ extension OwnerPresenter { } private func claimSensor() { - isLoading = true + activityPresenter.show(with: .loading(message: nil)) ruuviOwnershipService .claim(sensor: ruuviTag) .on(success: { [weak self] _ in self?.router.dismiss() self?.removeConnection() + self?.activityPresenter.show(with: .success(message: nil)) }, failure: { [weak self] error in switch error { case .ruuviCloud(.api(.api(.erSensorAlreadyClaimed))): @@ -116,15 +108,15 @@ extension OwnerPresenter { } self?.view.showSensorAlreadyClaimedDialog() default: - self?.errorPresenter.present(error: error) + self?.activityPresenter.show(with: .failed(message: error.localizedDescription)) } }, completion: { [weak self] in - self?.isLoading = false + self?.activityPresenter.dismiss() }) } private func unclaimSensor(removeCloudHistory: Bool) { - isLoading = true + activityPresenter.show(with: .loading(message: nil)) ruuviOwnershipService .unclaim( sensor: ruuviTag, @@ -132,10 +124,11 @@ extension OwnerPresenter { ) .on(success: { [weak self] _ in self?.router.dismiss() + self?.activityPresenter.update(with: .success(message: nil)) }, failure: { [weak self] error in - self?.errorPresenter.present(error: error) + self?.activityPresenter.show(with: .failed(message: error.localizedDescription)) }, completion: { [weak self] in - self?.isLoading = false + self?.activityPresenter.dismiss() }) } } diff --git a/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift b/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift index b489f0b85..cf5934113 100644 --- a/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift +++ b/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift @@ -11,13 +11,9 @@ class AlertPresenterImpl: AlertPresenter { DispatchQueue.main.async { group.enter() let topViewController = UIApplication.shared.topViewController() - var fireAfter: DispatchTimeInterval = .milliseconds(0) - if topViewController is ActivityRuuviLogoViewController { - fireAfter = .milliseconds(750) - } group.leave() group.notify(queue: .main) { - DispatchQueue.main.asyncAfter(deadline: .now() + fireAfter) { + DispatchQueue.main.async { let feedback = UINotificationFeedbackGenerator() feedback.notificationOccurred(.error) feedback.prepare() diff --git a/station/Resources/Strings/de.lproj/Localizable.strings b/station/Resources/Strings/de.lproj/Localizable.strings index b6072e237..0779fa1a1 100644 --- a/station/Resources/Strings/de.lproj/Localizable.strings +++ b/station/Resources/Strings/de.lproj/Localizable.strings @@ -751,3 +751,9 @@ Wenn die Beanspruchung nicht erfolgreich war oder NFC auf Ihrem Gerät nicht ver "remove_claimed_sensor_description" = "Durch das Entfernen des Sensors wird Ihr Sensor-Eigentumsstatus aufgehoben, und Sensor-Einstellungen wie Name, Hintergrundbild, Kalibrierungseinstellungen und Alarmeinstellungen werden entfernt. Nach der Entfernung kann jemand anderes das Eigentum am Sensor beanspruchen. Jeder Ruuvi-Sensor kann nur einen Besitzer haben."; "remove_shared_sensor_description" = "Wenn Sie diesen freigegebenen Sensor entfernen, wird der Eigentümer des Sensors benachrichtigt und Sie können nicht mehr auf den Sensor zugreifen.\n\nSie verlieren außerdem alle zugehörigen Sensoreinstellungen wie Name, Hintergrundbild und Alarmkonfigurationen ."; "remove_local_sensor_description" = "Wenn Sie diesen Sensor entfernen, führt dies zur Löschung Ihres lokal gespeicherten Messverlaufs sowie zur Entfernung aller zugehörigen Sensoreinstellungen wie Name, Hintergrundbild, Kalibrierung und Alarmkonfigurationen.\n\nSie können hinzufügen diesen Sensor später bei Bedarf erneut."; +"activity_saving_to_cloud" = "Speichern in der Cloud...bitte warten."; +"activity_saving_success" = "Erfolgreich gespeichert."; +"activity_saving_fail" = "Die Änderungen konnten nicht in der Cloud gespeichert werden."; +"activity_ongoing_generic" = "Please wait..."; +"activity_success_generic" = "Operation successful."; +"activity_failed_generic" = "Operation failed."; diff --git a/station/Resources/Strings/en.lproj/Localizable.strings b/station/Resources/Strings/en.lproj/Localizable.strings index 7e28af6cd..87102a26d 100644 --- a/station/Resources/Strings/en.lproj/Localizable.strings +++ b/station/Resources/Strings/en.lproj/Localizable.strings @@ -746,3 +746,9 @@ Your RuuviTag sensor is ready for use!"; "remove_claimed_sensor_description" = "By removing the sensor, your sensor ownership status will be revoked and sensor settings, such as name, background image, calibration settings and alert settings will be removed. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner."; "remove_shared_sensor_description" = "If you choose to remove this shared sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore.\n\nYou will also lose any related sensor settings like name, background image and alert configurations."; "remove_local_sensor_description" = "If you choose to remove this sensor, it will result in the deletion of your locally stored measurement history, along with the removal of any related sensor settings like name, background image, calibration, and alert configurations.\n\nYou can add this sensor later again, if needed."; +"activity_saving_to_cloud" = "Saving to cloud...please wait."; +"activity_saving_success" = "Saved successfully."; +"activity_saving_fail" = "Couldn't save changes to cloud."; +"activity_ongoing_generic" = "Please wait..."; +"activity_success_generic" = "Operation successful."; +"activity_failed_generic" = "Operation failed."; diff --git a/station/Resources/Strings/fi.lproj/Localizable.strings b/station/Resources/Strings/fi.lproj/Localizable.strings index fcc3332bb..ee58e036e 100644 --- a/station/Resources/Strings/fi.lproj/Localizable.strings +++ b/station/Resources/Strings/fi.lproj/Localizable.strings @@ -746,3 +746,9 @@ RuuviTag on valmis käyttöön!"; "remove_claimed_sensor_description" = "Poistamalla anturin omistusoikeutesi peruutetaan, ja anturin asetukset, kuten nimi, taustakuva, kalibrointiasetukset ja hälytysasetukset poistetaan. Poiston jälkeen joku toinen voi ottaa anturin omistukseensa. Jokaisella Ruuvi-anturilla voi olla vain yksi omistaja."; "remove_shared_sensor_description" = "Jos poistat tämän jaetun anturin, anturin omistajalle lähetetään ilmoitus poistosta, etkä voi enää käyttää anturia.\n\nMenetät myös kaikki tähän anturiin liittyvät anturin asetukset, kuten nimen, taustakuvan ja asetetut hälytykset."; "remove_local_sensor_description" = "Jos poistat tämän anturin, paikallisesti tallennettu mittaushistoria ja kaikki tähän anturiin liittyvät asetukset, kuten nimi, taustakuva, kalibrointiasetukset ja hälytysasetukset poistetaan.\n\nVoit lisätä tämän anturin myöhemmin uudelleen tarvittaessa."; +"activity_saving_to_cloud" = "Tallennetaan pilveen...odota hetki."; +"activity_saving_success" = "Tallennus onnistui."; +"activity_saving_fail" = "Muutoksia ei voitu tallentaa pilveen."; +"activity_ongoing_generic" = "Please wait..."; +"activity_success_generic" = "Operation successful."; +"activity_failed_generic" = "Operation failed."; diff --git a/station/Resources/Strings/fr.lproj/Localizable.strings b/station/Resources/Strings/fr.lproj/Localizable.strings index d74b054d2..dbd59e762 100644 --- a/station/Resources/Strings/fr.lproj/Localizable.strings +++ b/station/Resources/Strings/fr.lproj/Localizable.strings @@ -747,4 +747,10 @@ RuuviTag est prêt à être utilisé !"; "remove_claimed_sensor_description" = "En supprimant le capteur, votre statut de propriétaire du capteur sera révoqué, et les paramètres du capteur, tels que le nom, l'image d'arrière-plan, les paramètres de calibration et les paramètres d'alerte, seront supprimés. Après la suppression, quelqu'un d'autre peut revendiquer la propriété du capteur. Chaque capteur Ruuvi ne peut avoir qu'un seul propriétaire."; "remove_shared_sensor_description" = "Si vous choisissez de supprimer ce capteur partagé, le propriétaire du capteur sera averti et vous ne pourrez plus accéder au capteur.\n\nVous perdrez également tous les paramètres du capteur associés, tels que le nom, l'image d'arrière-plan et les configurations d'alerte. ."; "remove_local_sensor_description" = "Si vous choisissez de supprimer ce capteur, cela entraînera la suppression de votre historique de mesures stocké localement, ainsi que la suppression de tous les paramètres du capteur associés tels que le nom, l'image d'arrière-plan, l'étalonnage et les configurations d'alerte.\n\nVous pouvez ajouter ce capteur plus tard, si nécessaire."; +"activity_saving_to_cloud" = "Enregistrement dans le cloud... veuillez patienter."; +"activity_saving_success" = "Enregistré avec succès."; +"activity_saving_fail" = "Impossible d'enregistrer les modifications dans le cloud."; +"activity_ongoing_generic" = "Please wait..."; +"activity_success_generic" = "Operation successful."; +"activity_failed_generic" = "Operation failed."; diff --git a/station/Resources/Strings/ru.lproj/Localizable.strings b/station/Resources/Strings/ru.lproj/Localizable.strings index ce889a66e..1087d203b 100644 --- a/station/Resources/Strings/ru.lproj/Localizable.strings +++ b/station/Resources/Strings/ru.lproj/Localizable.strings @@ -746,3 +746,9 @@ If you cannot see the Language option in the settings, make sure that you have a "remove_claimed_sensor_description" = "By removing the sensor, your sensor ownership status will be revoked and sensor settings, such as name, background image, calibration settings and alert settings will be removed. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner."; "remove_shared_sensor_description" = "If you choose to remove this shared sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore.\n\nYou will also lose any related sensor settings like name, background image and alert configurations."; "remove_local_sensor_description" = "If you choose to remove this sensor, it will result in the deletion of your locally stored measurement history, along with the removal of any related sensor settings like name, background image, calibration, and alert configurations.\n\nYou can add this sensor later again, if needed."; +"activity_saving_to_cloud" = "Saving to cloud...please wait."; +"activity_saving_success" = "Saved successfully."; +"activity_saving_fail" = "Couldn't save changes to cloud."; +"activity_ongoing_generic" = "Please wait..."; +"activity_success_generic" = "Operation successful."; +"activity_failed_generic" = "Operation failed."; diff --git a/station/Resources/Strings/sv.lproj/Localizable.strings b/station/Resources/Strings/sv.lproj/Localizable.strings index bbe7a036c..c7e23633d 100644 --- a/station/Resources/Strings/sv.lproj/Localizable.strings +++ b/station/Resources/Strings/sv.lproj/Localizable.strings @@ -746,3 +746,9 @@ RuuviTag-sensorn är redo att användas!"; "remove_claimed_sensor_description" = "Genom att ta bort sensorn kommer den inte längre synas i ditt konto och sensorinställningar som namn, bakgrundsbild, kalibreringsinställningar och larminställningar kommer att tas bort. Efter borttagning kan någon annan ta ägande om sensorn. Varje Ruuvi-sensor kan bara ha en ägare."; "remove_shared_sensor_description" = "Om du tar bort den här delade sensorn kommer sensorns ägare att meddelas om borttagningen och du kommer inte längre att kunna använda sensorn.\n\nDu kommer också att förlora alla sensorinställningar som är kopplade till denna sensor, t.ex. namn, bakgrundsbild och ställ in alarm."; "remove_local_sensor_description" = "Om du väljer att ta bort den här sensorn kommer det att resultera i radering av din lokalt lagrade mäthistorik, tillsammans med att eventuella relaterade sensorinställningar som namn, bakgrundsbild, kalibrering och varningskonfigurationer tas bort.\n\nDu kan lägga till denna sensor senare igen, om det behövs."; +"activity_saving_to_cloud" = "Sparar till molnet... vänligen vänta."; +"activity_saving_success" = "Sparad."; +"activity_saving_fail" = "Det gick inte att spara ändringar i molnet."; +"activity_ongoing_generic" = "Please wait..."; +"activity_success_generic" = "Operation successful."; +"activity_failed_generic" = "Operation failed."; From 046eec63f488c87ddeec4761036d439f56023274 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Wed, 6 Dec 2023 23:39:05 +0200 Subject: [PATCH 27/84] Install firebase CLI locally (#1754) Implements script for installing Firebase CLI tools locally and adds it to github action --- .github/workflows/firebase_frameworks.yml | 15 +++++++-- Makefile | 9 +++++- scripts/install/install_firebase.sh | 37 +++++++++++++++++++++++ station.localization | 2 +- 4 files changed, 59 insertions(+), 4 deletions(-) create mode 100755 scripts/install/install_firebase.sh diff --git a/.github/workflows/firebase_frameworks.yml b/.github/workflows/firebase_frameworks.yml index a596062c8..d5e3013f7 100644 --- a/.github/workflows/firebase_frameworks.yml +++ b/.github/workflows/firebase_frameworks.yml @@ -58,6 +58,14 @@ jobs: run: | make set_build_number_frameworks + - name: Tools cache + uses: actions/cache@v2 + with: + path: .tools/ + key: ${{ runner.os }}-tools-${{ hashFiles('/.tools/') }} + restore-keys: | + ${{ runner.os }}-tools- + - name: Make xcodeproj run: | make xcodeproj_with_frameworks @@ -85,10 +93,13 @@ jobs: id: build_changelog uses: mikepenz/release-changelog-builder-action@v4.1.0 + - name: Install firebase CLI + run: | + make installed_firebase + - name: Distribute to Firebase run: | - curl -sL https://firebase.tools | bash - firebase appdistribution:distribute ${{ runner.temp }}/export/*.ipa \ + .tools/firebase/firebase appdistribution:distribute ${{ runner.temp }}/export/*.ipa \ --app ${{ secrets.GOOGLE_APP_ID }} \ --token ${{ secrets.FIREBASE_REFRESH_TOKEN }} \ --groups ${{ secrets.ALPHA_TESTERS_GROUP }} \ diff --git a/Makefile b/Makefile index 2c90e4873..0e75f75ff 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,16 @@ -.PHONY: installed_xcodegen installed_swiftgen +.PHONY: installed_xcodegen installed_swiftgen installed_firebase # generates xcodeproj for frameworks build configuration xcodeproj_with_frameworks: installed_xcodegen installed_swiftgen .tools/xcodegen/bin/xcodegen -s project_frameworks.yml +# install firebase +installed_firebase: .tools/firebase/firebase + +.tools/firebase/firebase: scripts/install/install_firebase.sh + scripts/install/install_firebase.sh + touch $@ + # install swiftgen installed_swiftgen: .tools/swiftgen/bin/swiftgen diff --git a/scripts/install/install_firebase.sh b/scripts/install/install_firebase.sh new file mode 100755 index 000000000..621c82dae --- /dev/null +++ b/scripts/install/install_firebase.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +set -e + +OUTPUT_DIR=".tools/firebase" + + +EXPECTED_FIREBASE_HASH="7861cece52615d89aeed5b29601a8c46" + +# check if firebase is already installed by hashing all files in the output directory +if [ -d "$OUTPUT_DIR" ] && [ "$(find "$OUTPUT_DIR" -type f -exec md5 {} \; | md5)" = $EXPECTED_FIREBASE_HASH ]; then + echo "firebase is already installed" + exit 0 +fi + +# remove the output directory if it exists +if [ -d "$OUTPUT_DIR" ]; then + rm -rf "$OUTPUT_DIR" +fi + +# create the output directory +mkdir -p "$OUTPUT_DIR" + +# download the latest release of firebase +curl -o "$OUTPUT_DIR/firebase" -L --progress-bar "https://firebase.tools/bin/macos/latest" +chmod +x ./$OUTPUT_DIR/firebase + +# if the hash of downloaded firebase is not the expected value, exit with an error +INSTALLED_FIREBASE_HASH="$(find "$OUTPUT_DIR" -type f -exec md5 {} \; | md5)" +if [ "$INSTALLED_FIREBASE_HASH" != "$EXPECTED_FIREBASE_HASH" ]; then + echo "firebase failed to install" + echo "Expected hash: $EXPECTED_FIREBASE_HASH" + echo "Actual hash: $INSTALLED_FIREBASE_HASH" + exit 1 +else + echo "No firebase install needed" +fi \ No newline at end of file diff --git a/station.localization b/station.localization index abd81752b..45c2e8f00 160000 --- a/station.localization +++ b/station.localization @@ -1 +1 @@ -Subproject commit abd81752bbe8a799ff315786287c614b893f6816 +Subproject commit 45c2e8f008e6d9c94a259b120f7ea190087aa94e From 921d1602d05738494e833136aca7c176cd2da8d1 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Thu, 7 Dec 2023 00:10:09 +0200 Subject: [PATCH 28/84] Use Firebase CLI 12 (#1756) 13 needs new node --- scripts/install/install_firebase.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/install/install_firebase.sh b/scripts/install/install_firebase.sh index 621c82dae..246e5409f 100755 --- a/scripts/install/install_firebase.sh +++ b/scripts/install/install_firebase.sh @@ -5,7 +5,7 @@ set -e OUTPUT_DIR=".tools/firebase" -EXPECTED_FIREBASE_HASH="7861cece52615d89aeed5b29601a8c46" +EXPECTED_FIREBASE_HASH="9a1c3fb10726c370144f5ea6ca063664" # check if firebase is already installed by hashing all files in the output directory if [ -d "$OUTPUT_DIR" ] && [ "$(find "$OUTPUT_DIR" -type f -exec md5 {} \; | md5)" = $EXPECTED_FIREBASE_HASH ]; then @@ -22,7 +22,7 @@ fi mkdir -p "$OUTPUT_DIR" # download the latest release of firebase -curl -o "$OUTPUT_DIR/firebase" -L --progress-bar "https://firebase.tools/bin/macos/latest" +curl -o "$OUTPUT_DIR/firebase" -L --progress-bar "https://firebase.tools/bin/macos/v12.9.1" chmod +x ./$OUTPUT_DIR/firebase # if the hash of downloaded firebase is not the expected value, exit with an error From 3c468da639d899951372a4df2c2dee7dc02fc726 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 9 Dec 2023 14:54:29 +0200 Subject: [PATCH 29/84] Use SwiftGen for localization (#1759) * Use SwiftGen for localization Implements extracting localizable strings to framework, utilizing power of swiftgen to generate static enum. Replaces all occurences of String.localized() with enum RuuviLocalization * fix percent * remove humidity_relative_unit * remove outdated method * remove unused text * days * fix token id * dew symbol * fix user api errors * remove localization service as we dont need localization on the fly --- .../RuuviLocalization/Localizable.swift | 11 - .../LocalizationService.swift | 23 - .../Resources}/de.lproj/Localizable.strings | 21 +- .../Resources}/en.lproj/Localizable.strings | 15 +- .../Resources}/fi.lproj/Localizable.strings | 21 +- .../Resources}/fr.lproj/Localizable.strings | 21 +- .../Resources}/ru.lproj/Localizable.strings | 17 +- .../Resources}/sv.lproj/Localizable.strings | 21 +- .../RuuviLocalization/RuuviLocalization.swift | 2648 +++++++++++++++++ .../Templates}/Localizable_de.strings.stencil | 0 .../Templates}/Localizable_en.strings.stencil | 0 .../Templates}/Localizable_fi.strings.stencil | 0 .../Templates}/Localizable_fr.strings.stencil | 0 .../Templates}/Localizable_ru.strings.stencil | 0 .../Templates}/Localizable_sv.strings.stencil | 0 .../VMP/View/DiscoverViewInput.swift | 2 +- .../Table/DiscoverTableViewController.swift | 1 - .../RuuviCloud/RuuviCloudApiError.swift | 5 - .../RuuviCloud/RuuviCloudApiErrorCode.swift | 2 +- .../Sources/RuuviDFU/RuuviDFUError.swift | 9 +- project_frameworks.yml | 6 + station.localization | 2 +- station/Classes/Application/AppAssembly.swift | 5 +- station/Classes/Application/AppDelegate.swift | 5 +- .../Presentation/Contract/ViewInput.swift | 3 +- .../Localization/Localizable.swift | 11 - .../Localization/LocalizationService.swift | 23 - .../Localization/LocalizedCache.swift | 7 - .../About/Presenter/AboutPresenter.swift | 11 +- .../Modules/About/Router/AboutRouter.swift | 3 +- .../About/View/AboutViewController.swift | 36 +- .../BackgroundSelectionViewController.swift | 7 +- .../UI/BackgroundSelectionViewHeader.swift | 9 +- .../Cards/View/UI/CardsLargeImageCell.swift | 17 +- .../Cards/View/UI/CardsViewController.swift | 43 +- .../TagChartsViewInteractorOutput.swift | 1 - .../Presenter/TagChartsViewPresenter.swift | 23 +- .../Charts/View/UI/TagChartsView.swift | 7 +- .../View/UI/TagChartsViewController.swift | 140 +- .../Home/Router/DashboardRouter.swift | 7 +- .../Home/View/DashboardImageCell.swift | 11 +- .../Home/View/DashboardPlainCell.swift | 9 +- .../Home/View/DashboardViewController.swift | 65 +- .../Dashboard/Home/View/LowBatteryView.swift | 3 +- .../Dashboard/Home/View/NoSensorView.swift | 11 +- .../MenuTableEmbededViewController.swift | 22 +- .../Presenter/MyRuuviAccountPresenter.swift | 9 +- .../View/MyRuuviAccountViewController.swift | 17 +- .../Module/Presenter/SettingsPresenter.swift | 7 +- .../Table/SettingsTableViewController.swift | 34 +- .../AppearanceSettingsModuleFactory.swift | 3 +- .../AppearanceSettingsPresenter.swift | 3 +- .../Router/AppearanceSettingsRouter.swift | 3 +- .../UI/ASSelectionTableViewController.swift | 5 +- ...ppearanceSettingsTableViewController.swift | 3 +- .../Presenter/ChartSettingsPresenter.swift | 9 +- .../Chart/View/ChartSettingsViewModel.swift | 5 +- .../ChartSettingsStepperTableViewCell.swift | 3 +- .../ChartSettingsTableViewController.swift | 3 +- .../Presenter/DefaultsPresenter.swift | 41 +- .../View/DefaultsViewController.swift | 10 +- .../Cells/DefaultsStepperTableViewCell.swift | 7 +- .../Table/DefaultsTableViewController.swift | 9 +- .../View/UI/DevicesTableViewCell.swift | 5 +- .../View/UI/DevicesTableViewController.swift | 12 +- .../View/HeartbeatViewController.swift | 4 +- .../Heartbeat/View/HeartbeatViewModel.swift | 5 +- .../View/SwiftUI/HeartbeatList.swift | 5 +- .../Table/HeartbeatTableViewController.swift | 19 +- .../NotificationsSettingsModuleFactory.swift | 3 +- .../NotificationsSettingsPresenter.swift | 21 +- ...ertSoundSelectionTableViewController.swift | 5 +- ...ficationsSettingsTableViewController.swift | 6 +- .../Presenter/RuuviCloudPresenter.swift | 3 +- .../UI/RuuviCloudTableViewController.swift | 6 +- .../Selection/Model/SelectionItem.swift | 2 +- .../Table/SelectionTableViewController.swift | 10 +- .../Presenter/UnitSettingsPresenter.swift | 27 +- .../UnitSettingsTableViewController.swift | 18 +- .../Share/Presenter/SharePresenter.swift | 7 +- .../ViewController/ShareViewController.swift | 32 +- .../SignIn/Presenter/SignInPresenter.swift | 5 +- .../View/SignInBenefitsViewController.swift | 29 +- .../View/UI/Helper/SignInVerifyView.swift | 7 +- .../SignIn/View/UI/Helper/SignInView.swift | 11 +- .../SignIn/View/UI/SignInViewController.swift | 16 +- .../Presenter/TagSettingsPresenter.swift | 3 +- .../DFU/View/SwiftUI/DFUUIView.swift | 47 +- .../UI/SensorForceClaimViewController.swift | 17 +- .../OffsetCorrectionAppleViewController.swift | 41 +- .../View/OffsetCorrectionViewModel.swift | 7 +- .../Owner/View/OwnerViewController.swift | 44 +- .../View/UI/SensorRemovalViewController.swift | 23 +- .../View/UI/TagSettingsAlertConfigCell.swift | 5 +- .../TagSettingsBackgroundSelectionView.swift | 3 +- .../TagSettingsExpandableSectionHeader.swift | 3 +- .../View/UI/TagSettingsViewController.swift | 258 +- .../Classess/AppDateFormatter.swift | 3 +- station/Extensions/Date+Ruuvi.swift | 7 +- station/Extensions/DfuFirmware+Log.swift | 11 +- station/Extensions/Errors/RUError.swift | 67 +- .../RuuviCloudApiError+LocalizedError.swift | 88 +- .../RuuviCloudError+LocalizedError.swift | 3 +- .../RuuviCoreError+LocalizedError.swift | 7 +- .../Errors/RuuviDFUError+LocalizedError.swift | 3 +- .../RuuviLocalError+LocalizedError.swift | 5 +- ...RuuviPersistenceError+LocalizedError.swift | 3 +- .../RuuviServiceError+LocalizedError.swift | 15 +- .../HumidityUnit+Localization.swift | 17 +- station/Extensions/Int+Extension.swift | 3 +- .../Extensions/Language+Localization.swift | 13 +- .../MeasurementAccuracyType+Extension.swift | 8 +- .../RuuviAlertSound+Extension.swift | 7 +- station/Extensions/RuuviTheme+Extension.swift | 9 +- station/Extensions/String+Localization.swift | 7 - .../Structs/ExportHeadersProvider.swift | 33 +- .../Extensions/Structs/GlobalHelpers.swift | 5 +- .../Structs/HeartbeatDaemonTitles.swift | 5 +- .../Structs/RuuviNotifierTitlesImpl.swift | 23 +- .../TemperatureUnit+Localization.swift | 19 +- .../Extensions/UIViewController+Alert.swift | 3 +- .../Extensions/UnitPressure+Extension.swift | 11 +- station/Extensions/UnitSettingsType.swift | 7 +- swiftgen.yml | 33 +- 124 files changed, 3677 insertions(+), 922 deletions(-) delete mode 100644 Common/RuuviLocalization/Sources/RuuviLocalization/Localizable.swift delete mode 100644 Common/RuuviLocalization/Sources/RuuviLocalization/LocalizationService.swift rename {station/Resources/Strings => Common/RuuviLocalization/Sources/RuuviLocalization/Resources}/de.lproj/Localizable.strings (98%) rename {station/Resources/Strings => Common/RuuviLocalization/Sources/RuuviLocalization/Resources}/en.lproj/Localizable.strings (98%) rename {station/Resources/Strings => Common/RuuviLocalization/Sources/RuuviLocalization/Resources}/fi.lproj/Localizable.strings (98%) rename {station/Resources/Strings => Common/RuuviLocalization/Sources/RuuviLocalization/Resources}/fr.lproj/Localizable.strings (98%) rename {station/Resources/Strings => Common/RuuviLocalization/Sources/RuuviLocalization/Resources}/ru.lproj/Localizable.strings (98%) rename {station/Resources/Strings => Common/RuuviLocalization/Sources/RuuviLocalization/Resources}/sv.lproj/Localizable.strings (97%) create mode 100644 Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift rename {Templates => Common/RuuviLocalization/Templates}/Localizable_de.strings.stencil (100%) rename {templates => Common/RuuviLocalization/Templates}/Localizable_en.strings.stencil (100%) rename {templates => Common/RuuviLocalization/Templates}/Localizable_fi.strings.stencil (100%) rename {templates => Common/RuuviLocalization/Templates}/Localizable_fr.strings.stencil (100%) rename {templates => Common/RuuviLocalization/Templates}/Localizable_ru.strings.stencil (100%) rename {templates => Common/RuuviLocalization/Templates}/Localizable_sv.strings.stencil (100%) delete mode 100644 station/Classes/Presentation/Localization/Localizable.swift delete mode 100644 station/Classes/Presentation/Localization/LocalizationService.swift delete mode 100644 station/Classes/Presentation/Localization/LocalizedCache.swift delete mode 100644 station/Extensions/String+Localization.swift diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/Localizable.swift b/Common/RuuviLocalization/Sources/RuuviLocalization/Localizable.swift deleted file mode 100644 index 0aa7426fb..000000000 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/Localizable.swift +++ /dev/null @@ -1,11 +0,0 @@ -import Foundation - -public protocol Localizable: AnyObject { - func localize() -} - -extension Localizable { - public func setupLocalization() { - LocalizationService.shared.add(localizable: self) - } -} diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/LocalizationService.swift b/Common/RuuviLocalization/Sources/RuuviLocalization/LocalizationService.swift deleted file mode 100644 index 92416b4f1..000000000 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/LocalizationService.swift +++ /dev/null @@ -1,23 +0,0 @@ -import Foundation - -class LocalizationService { - static let shared = LocalizationService() - - init() {} - - private var listeners = NSHashTable.weakObjects() - - func add(localizable: Localizable, applyImmediately: Bool = true) { - guard !listeners.contains(localizable) else { return } - listeners.add(localizable) - if applyImmediately { - localizable.localize() - } - } - - @objc func apply() { - listeners.allObjects - .compactMap { $0 as? Localizable } - .forEach { $0.localize()} - } -} diff --git a/station/Resources/Strings/de.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/de.lproj/Localizable.strings similarity index 98% rename from station/Resources/Strings/de.lproj/Localizable.strings rename to Common/RuuviLocalization/Sources/RuuviLocalization/Resources/de.lproj/Localizable.strings index 0779fa1a1..7b56f5ec0 100644 --- a/station/Resources/Strings/de.lproj/Localizable.strings +++ b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/de.lproj/Localizable.strings @@ -279,7 +279,6 @@ "HumidityUnit.gm3.title" = "Absolut (g/m³)"; "g/m³" = "g/m³"; "HumidityUnit.Percent.title" = "Relative (%)"; -"%" = "%"; "TagSettings.Mac.Alert.title" = "MAC-Adresse"; "Menu.Label.AboutHelp.text" = "Über / Hilfe"; "Menu.Label.AddAnNewSensor.text" = "Neuen Sensor hinzufügen"; @@ -754,6 +753,20 @@ Wenn die Beanspruchung nicht erfolgreich war oder NFC auf Ihrem Gerät nicht ver "activity_saving_to_cloud" = "Speichern in der Cloud...bitte warten."; "activity_saving_success" = "Erfolgreich gespeichert."; "activity_saving_fail" = "Die Änderungen konnten nicht in der Cloud gespeichert werden."; -"activity_ongoing_generic" = "Please wait..."; -"activity_success_generic" = "Operation successful."; -"activity_failed_generic" = "Operation failed."; +"activity_ongoing_generic" = "Bitte warten..."; +"activity_success_generic" = "Operation erfolgreich."; +"activity_failed_generic" = "Operation fehlgeschlagen."; +"Devices.tokenId" = "Token Id"; +"UserApiError.ER_GATEWAY_NOT_FOUND" = "Gateway not found"; +"UserApiError.ER_GATEWAY_ALREADY_WHITELISTED" = "Gateway already whitelisted"; +"UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED" = "Gateway status report failed"; +"UserApiError.ER_CONFLICT" = "Data already exists, cannot update"; +"UserApiError.ER_CLAIM_COUNT_REACHED" = "Maximum claim count for the user reached"; +"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Maximum share count for the sensor reached"; +"UserApiError.ER_NO_DATA_TO_SHARE" = "In order to share a sensor, it must have data"; +"UserApiError.ER_SENSOR_ALREADY_REGISTERED" = "The sensor has already been registered"; +"UserApiError.ER_SUBSCRIPTION_CODE_EXISTS" = "Tried to add duplicate subscription to a code"; +"UserApiError.ER_SUBSCRIPTION_CODE_USED" = "Tried to claim already used code"; +"UserApiError.ER_OLD_ENTRY" = "Newer data already exists, cannot update"; +"UserApiError.ER_INVALID_ENUM_VALUE" = "Invalid ENUM value given"; +"UserApiError.OK" = "Operation was successful"; diff --git a/station/Resources/Strings/en.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings similarity index 98% rename from station/Resources/Strings/en.lproj/Localizable.strings rename to Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings index 87102a26d..f815def81 100644 --- a/station/Resources/Strings/en.lproj/Localizable.strings +++ b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings @@ -280,7 +280,6 @@ If you cannot see the Language option in the settings, make sure that you have a "HumidityUnit.gm3.title" = "Absolute (g/m³)"; "g/m³" = "g/m³"; "HumidityUnit.Percent.title" = "Relative (%)"; -"%" = "%"; "TagSettings.Mac.Alert.title" = "MAC Address"; "Menu.Label.AboutHelp.text" = "About / Help"; "Menu.Label.AddAnNewSensor.text" = "Add a New Sensor"; @@ -752,3 +751,17 @@ Your RuuviTag sensor is ready for use!"; "activity_ongoing_generic" = "Please wait..."; "activity_success_generic" = "Operation successful."; "activity_failed_generic" = "Operation failed."; +"Devices.tokenId" = "Token Id"; +"UserApiError.ER_GATEWAY_NOT_FOUND" = "Gateway not found"; +"UserApiError.ER_GATEWAY_ALREADY_WHITELISTED" = "Gateway already whitelisted"; +"UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED" = "Gateway status report failed"; +"UserApiError.ER_CONFLICT" = "Data already exists, cannot update"; +"UserApiError.ER_CLAIM_COUNT_REACHED" = "Maximum claim count for the user reached"; +"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Maximum share count for the sensor reached"; +"UserApiError.ER_NO_DATA_TO_SHARE" = "In order to share a sensor, it must have data"; +"UserApiError.ER_SENSOR_ALREADY_REGISTERED" = "The sensor has already been registered"; +"UserApiError.ER_SUBSCRIPTION_CODE_EXISTS" = "Tried to add duplicate subscription to a code"; +"UserApiError.ER_SUBSCRIPTION_CODE_USED" = "Tried to claim already used code"; +"UserApiError.ER_OLD_ENTRY" = "Newer data already exists, cannot update"; +"UserApiError.ER_INVALID_ENUM_VALUE" = "Invalid ENUM value given"; +"UserApiError.OK" = "Operation was successful"; diff --git a/station/Resources/Strings/fi.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fi.lproj/Localizable.strings similarity index 98% rename from station/Resources/Strings/fi.lproj/Localizable.strings rename to Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fi.lproj/Localizable.strings index ee58e036e..be1cbb293 100644 --- a/station/Resources/Strings/fi.lproj/Localizable.strings +++ b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fi.lproj/Localizable.strings @@ -280,7 +280,6 @@ Mikäli et näe Kieli-valintaa asetuksissa, varmista, että sinulla on vähintä "HumidityUnit.gm3.title" = "Absoluuttinen (g/m³)"; "g/m³" = "g/m³"; "HumidityUnit.Percent.title" = "Suhteellinen (%)"; -"%" = "%"; "TagSettings.Mac.Alert.title" = "MAC-osoite"; "Menu.Label.AboutHelp.text" = "Tietoa / Apua"; "Menu.Label.AddAnNewSensor.text" = "Lisää uusi anturi"; @@ -749,6 +748,20 @@ RuuviTag on valmis käyttöön!"; "activity_saving_to_cloud" = "Tallennetaan pilveen...odota hetki."; "activity_saving_success" = "Tallennus onnistui."; "activity_saving_fail" = "Muutoksia ei voitu tallentaa pilveen."; -"activity_ongoing_generic" = "Please wait..."; -"activity_success_generic" = "Operation successful."; -"activity_failed_generic" = "Operation failed."; +"activity_ongoing_generic" = "Odota..."; +"activity_success_generic" = "Toiminto onnistui."; +"activity_failed_generic" = "Toiminto epäonnistui."; +"Devices.tokenId" = "Token Id"; +"UserApiError.ER_GATEWAY_NOT_FOUND" = "Gateway not found"; +"UserApiError.ER_GATEWAY_ALREADY_WHITELISTED" = "Gateway already whitelisted"; +"UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED" = "Gateway status report failed"; +"UserApiError.ER_CONFLICT" = "Data already exists, cannot update"; +"UserApiError.ER_CLAIM_COUNT_REACHED" = "Maximum claim count for the user reached"; +"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Maximum share count for the sensor reached"; +"UserApiError.ER_NO_DATA_TO_SHARE" = "In order to share a sensor, it must have data"; +"UserApiError.ER_SENSOR_ALREADY_REGISTERED" = "The sensor has already been registered"; +"UserApiError.ER_SUBSCRIPTION_CODE_EXISTS" = "Tried to add duplicate subscription to a code"; +"UserApiError.ER_SUBSCRIPTION_CODE_USED" = "Tried to claim already used code"; +"UserApiError.ER_OLD_ENTRY" = "Newer data already exists, cannot update"; +"UserApiError.ER_INVALID_ENUM_VALUE" = "Invalid ENUM value given"; +"UserApiError.OK" = "Operation was successful"; diff --git a/station/Resources/Strings/fr.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fr.lproj/Localizable.strings similarity index 98% rename from station/Resources/Strings/fr.lproj/Localizable.strings rename to Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fr.lproj/Localizable.strings index dbd59e762..34b04170f 100644 --- a/station/Resources/Strings/fr.lproj/Localizable.strings +++ b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fr.lproj/Localizable.strings @@ -279,7 +279,6 @@ "HumidityUnit.gm3.title" = "Absolue (g/m³)"; "g/m³" = "g/m³"; "HumidityUnit.Percent.title" = "Relative (%)"; -"%" = "%"; "TagSettings.Mac.Alert.title" = "Adresse MAC"; "Menu.Label.AboutHelp.text" = "Infos/Aide"; "Menu.Label.AddAnNewSensor.text" = "Ajouter un capteur"; @@ -750,7 +749,21 @@ RuuviTag est prêt à être utilisé !"; "activity_saving_to_cloud" = "Enregistrement dans le cloud... veuillez patienter."; "activity_saving_success" = "Enregistré avec succès."; "activity_saving_fail" = "Impossible d'enregistrer les modifications dans le cloud."; -"activity_ongoing_generic" = "Please wait..."; -"activity_success_generic" = "Operation successful."; -"activity_failed_generic" = "Operation failed."; +"activity_ongoing_generic" = "S'il vous plaît, attendez..."; +"activity_success_generic" = "Opération réussie."; +"activity_failed_generic" = "L'opération a échoué."; +"Devices.tokenId" = "Token Id"; +"UserApiError.ER_GATEWAY_NOT_FOUND" = "Gateway not found"; +"UserApiError.ER_GATEWAY_ALREADY_WHITELISTED" = "Gateway already whitelisted"; +"UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED" = "Gateway status report failed"; +"UserApiError.ER_CONFLICT" = "Data already exists, cannot update"; +"UserApiError.ER_CLAIM_COUNT_REACHED" = "Maximum claim count for the user reached"; +"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Maximum share count for the sensor reached"; +"UserApiError.ER_NO_DATA_TO_SHARE" = "In order to share a sensor, it must have data"; +"UserApiError.ER_SENSOR_ALREADY_REGISTERED" = "The sensor has already been registered"; +"UserApiError.ER_SUBSCRIPTION_CODE_EXISTS" = "Tried to add duplicate subscription to a code"; +"UserApiError.ER_SUBSCRIPTION_CODE_USED" = "Tried to claim already used code"; +"UserApiError.ER_OLD_ENTRY" = "Newer data already exists, cannot update"; +"UserApiError.ER_INVALID_ENUM_VALUE" = "Invalid ENUM value given"; +"UserApiError.OK" = "Operation was successful"; diff --git a/station/Resources/Strings/ru.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/ru.lproj/Localizable.strings similarity index 98% rename from station/Resources/Strings/ru.lproj/Localizable.strings rename to Common/RuuviLocalization/Sources/RuuviLocalization/Resources/ru.lproj/Localizable.strings index 1087d203b..5f8df82b7 100644 --- a/station/Resources/Strings/ru.lproj/Localizable.strings +++ b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/ru.lproj/Localizable.strings @@ -280,7 +280,6 @@ If you cannot see the Language option in the settings, make sure that you have a "HumidityUnit.gm3.title" = "Абсолютная влажность (г/м³)"; "g/m³" = "г/м³"; "HumidityUnit.Percent.title" = "Относительная влажность (%)"; -"%" = "%"; "TagSettings.Mac.Alert.title" = "MAC адрес"; "Menu.Label.AboutHelp.text" = "О Приложении"; "Menu.Label.AddAnNewSensor.text" = "Добавить Сенсор"; @@ -674,7 +673,7 @@ If you cannot see the Language option in the settings, make sure that you have a "lets_do_it" = "Let's Sign In"; "enter_code" = "Enter Code"; "dashboard_no_sensors_message" = "Seems that you don't have any Ruuvi sensors added yet."; -"dashboard_no_sensors_message_signed_out" = "You are not signed in.\n\nIf you have an account and have already added Ruuvi sensors to it, they will automatically synchronise with Ruuvi Station mobile app when you sign in."; +"dashboard_no_sensors_message_signed_out" = "Вы не вошли в аккаунт.\n\nЕсли у вас уже есть аккаунт Ruuvi и добавлены датчики в него, то они будут автоматичеки синхронизированы с мобильным приложением после того как вы войдете в свой аккаунт."; "add_a_sensor" = "Add a Sensor"; "changelog" = "(changelog)"; "changelog_ios_url" = "https://f.ruuvi.com/t/3192"; @@ -752,3 +751,17 @@ If you cannot see the Language option in the settings, make sure that you have a "activity_ongoing_generic" = "Please wait..."; "activity_success_generic" = "Operation successful."; "activity_failed_generic" = "Operation failed."; +"Devices.tokenId" = "Token Id"; +"UserApiError.ER_GATEWAY_NOT_FOUND" = "Gateway not found"; +"UserApiError.ER_GATEWAY_ALREADY_WHITELISTED" = "Gateway already whitelisted"; +"UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED" = "Gateway status report failed"; +"UserApiError.ER_CONFLICT" = "Data already exists, cannot update"; +"UserApiError.ER_CLAIM_COUNT_REACHED" = "Maximum claim count for the user reached"; +"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Maximum share count for the sensor reached"; +"UserApiError.ER_NO_DATA_TO_SHARE" = "In order to share a sensor, it must have data"; +"UserApiError.ER_SENSOR_ALREADY_REGISTERED" = "The sensor has already been registered"; +"UserApiError.ER_SUBSCRIPTION_CODE_EXISTS" = "Tried to add duplicate subscription to a code"; +"UserApiError.ER_SUBSCRIPTION_CODE_USED" = "Tried to claim already used code"; +"UserApiError.ER_OLD_ENTRY" = "Newer data already exists, cannot update"; +"UserApiError.ER_INVALID_ENUM_VALUE" = "Invalid ENUM value given"; +"UserApiError.OK" = "Operation was successful"; diff --git a/station/Resources/Strings/sv.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/sv.lproj/Localizable.strings similarity index 97% rename from station/Resources/Strings/sv.lproj/Localizable.strings rename to Common/RuuviLocalization/Sources/RuuviLocalization/Resources/sv.lproj/Localizable.strings index c7e23633d..b9779e4e8 100644 --- a/station/Resources/Strings/sv.lproj/Localizable.strings +++ b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/sv.lproj/Localizable.strings @@ -280,7 +280,6 @@ Om du inte kan se språkalternativet i inställningarna, se till att du har lagt "HumidityUnit.gm3.title" = "Absolut (g/m³)"; "g/m³" = "g/m³"; "HumidityUnit.Percent.title" = "Relativ (%)"; -"%" = "%"; "TagSettings.Mac.Alert.title" = "MAC Adress"; "Menu.Label.AboutHelp.text" = "Om / Hjälp"; "Menu.Label.AddAnNewSensor.text" = "Lägg till en ny Sensor"; @@ -749,6 +748,20 @@ RuuviTag-sensorn är redo att användas!"; "activity_saving_to_cloud" = "Sparar till molnet... vänligen vänta."; "activity_saving_success" = "Sparad."; "activity_saving_fail" = "Det gick inte att spara ändringar i molnet."; -"activity_ongoing_generic" = "Please wait..."; -"activity_success_generic" = "Operation successful."; -"activity_failed_generic" = "Operation failed."; +"activity_ongoing_generic" = "Vänta..."; +"activity_success_generic" = "Operationen lyckades."; +"activity_failed_generic" = "Operationen misslyckades."; +"Devices.tokenId" = "Token Id"; +"UserApiError.ER_GATEWAY_NOT_FOUND" = "Gateway not found"; +"UserApiError.ER_GATEWAY_ALREADY_WHITELISTED" = "Gateway already whitelisted"; +"UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED" = "Gateway status report failed"; +"UserApiError.ER_CONFLICT" = "Data already exists, cannot update"; +"UserApiError.ER_CLAIM_COUNT_REACHED" = "Maximum claim count for the user reached"; +"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Maximum share count for the sensor reached"; +"UserApiError.ER_NO_DATA_TO_SHARE" = "In order to share a sensor, it must have data"; +"UserApiError.ER_SENSOR_ALREADY_REGISTERED" = "The sensor has already been registered"; +"UserApiError.ER_SUBSCRIPTION_CODE_EXISTS" = "Tried to add duplicate subscription to a code"; +"UserApiError.ER_SUBSCRIPTION_CODE_USED" = "Tried to claim already used code"; +"UserApiError.ER_OLD_ENTRY" = "Newer data already exists, cannot update"; +"UserApiError.ER_INVALID_ENUM_VALUE" = "Invalid ENUM value given"; +"UserApiError.OK" = "Operation was successful"; diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift b/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift new file mode 100644 index 000000000..b8a4daaad --- /dev/null +++ b/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift @@ -0,0 +1,2648 @@ +// swiftlint:disable all +// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen + +import Foundation + +// swiftlint:disable superfluous_disable_command file_length implicit_return prefer_self_in_static_references + +// MARK: - Strings + +// swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length +// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces +public enum RuuviLocalization { + /// Operation failed. + public static let activityFailedGeneric = RuuviLocalization.tr("Localizable", "activity_failed_generic", fallback: "Operation failed.") + /// Please wait... + public static let activityOngoingGeneric = RuuviLocalization.tr("Localizable", "activity_ongoing_generic", fallback: "Please wait...") + /// Couldn't save changes to cloud. + public static let activitySavingFail = RuuviLocalization.tr("Localizable", "activity_saving_fail", fallback: "Couldn't save changes to cloud.") + /// Saved successfully. + public static let activitySavingSuccess = RuuviLocalization.tr("Localizable", "activity_saving_success", fallback: "Saved successfully.") + /// Saving to cloud...please wait. + public static let activitySavingToCloud = RuuviLocalization.tr("Localizable", "activity_saving_to_cloud", fallback: "Saving to cloud...please wait.") + /// Operation successful. + public static let activitySuccessGeneric = RuuviLocalization.tr("Localizable", "activity_success_generic", fallback: "Operation successful.") + /// Add a Sensor + public static let addASensor = RuuviLocalization.tr("Localizable", "add_a_sensor", fallback: "Add a Sensor") + /// Add Sensor + public static let addSensor = RuuviLocalization.tr("Localizable", "add_sensor", fallback: "Add Sensor") + /// This page shows nearby Ruuvi sensors not yet added to the app. Tap a sensor to add it. + public static let addSensorDescription = RuuviLocalization.tr("Localizable", "add_sensor_description", fallback: "This page shows nearby Ruuvi sensors not yet added to the app. Tap a sensor to add it.") + /// This sensor cannot be added with NFC due to old firmware. Please add the sensor with Bluetooth and update firmware. + public static let addSensorNfcDf3Error = RuuviLocalization.tr("Localizable", "add_sensor_nfc_df3_error", fallback: "This sensor cannot be added with NFC due to old firmware. Please add the sensor with Bluetooth and update firmware.") + /// Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone. + public static let addSensorViaNfc = RuuviLocalization.tr("Localizable", "add_sensor_via_nfc", fallback: "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone.") + /// Add with NFC + public static let addWithNfc = RuuviLocalization.tr("Localizable", "add_with_nfc", fallback: "Add with NFC") + /// ago + public static let ago = RuuviLocalization.tr("Localizable", "ago", fallback: "ago") + /// Alert if sensor data hasn't been updated to the cloud for longer than %d minutes. + public static func alertCloudConnectionDescription(_ p1: Int) -> String { + return RuuviLocalization.tr("Localizable", "alert_cloud_connection_description", p1, fallback: "Alert if sensor data hasn't been updated to the cloud for longer than %d minutes.") + } + /// Enter the desired delay to be used in minutes before alert is triggered. Minimum value is 2 minutes. + public static let alertCloudConnectionDialogDescription = RuuviLocalization.tr("Localizable", "alert_cloud_connection_dialog_description", fallback: "Enter the desired delay to be used in minutes before alert is triggered. Minimum value is 2 minutes.") + /// Set cloud connection alert + public static let alertCloudConnectionDialogTitle = RuuviLocalization.tr("Localizable", "alert_cloud_connection_dialog_title", fallback: "Set cloud connection alert") + /// Cloud Connection + public static let alertCloudConnectionTitle = RuuviLocalization.tr("Localizable", "alert_cloud_connection_title", fallback: "Cloud Connection") + /// Air Humidity is above %@ + public static func alertNotificationHumidityHighThreshold(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "alert_notification_humidity_high_threshold", String(describing: p1), fallback: "Air Humidity is above %@") + } + /// Air Humidity is below %@ + public static func alertNotificationHumidityLowThreshold(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "alert_notification_humidity_low_threshold", String(describing: p1), fallback: "Air Humidity is below %@") + } + /// Air Pressure is above %@ + public static func alertNotificationPressureHighThreshold(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "alert_notification_pressure_high_threshold", String(describing: p1), fallback: "Air Pressure is above %@") + } + /// Air Pressure is below %@ + public static func alertNotificationPressureLowThreshold(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "alert_notification_pressure_low_threshold", String(describing: p1), fallback: "Air Pressure is below %@") + } + /// Signal strength is above %@ + public static func alertNotificationRssiHighThreshold(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "alert_notification_rssi_high_threshold", String(describing: p1), fallback: "Signal strength is above %@") + } + /// Signal strength is below %@ + public static func alertNotificationRssiLowThreshold(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "alert_notification_rssi_low_threshold", String(describing: p1), fallback: "Signal strength is below %@") + } + /// Temperature is above %@ + public static func alertNotificationTemperatureHighThreshold(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "alert_notification_temperature_high_threshold", String(describing: p1), fallback: "Temperature is above %@") + } + /// Temperature is below %@ + public static func alertNotificationTemperatureLowThreshold(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "alert_notification_temperature_low_threshold", String(describing: p1), fallback: "Temperature is below %@") + } + /// All + public static let all = RuuviLocalization.tr("Localizable", "all", fallback: "All") + /// App Theme + public static let appTheme = RuuviLocalization.tr("Localizable", "app_theme", fallback: "App Theme") + /// Read more about Ruuvi account benefits or sign in later + public static let benefitsSignIn = RuuviLocalization.tr("Localizable", "benefits_sign_in", fallback: "Read more about Ruuvi account benefits or sign in later") + /// Bluetooth download + public static let bluetoothDownload = RuuviLocalization.tr("Localizable", "bluetooth_download", fallback: "Bluetooth download") + /// Local sensor data can be downloaded, when you're within its Bluetooth range. + public static let bluetoothDownloadDescription = RuuviLocalization.tr("Localizable", "bluetooth_download_description", fallback: "Local sensor data can be downloaded, when you're within its Bluetooth range.") + /// Cancel + public static let cancel = RuuviLocalization.tr("Localizable", "Cancel", fallback: "Cancel") + /// Card action + public static let cardAction = RuuviLocalization.tr("Localizable", "card_action", fallback: "Card action") + /// Card type + public static let cardType = RuuviLocalization.tr("Localizable", "card_type", fallback: "Card type") + /// Change background + public static let changeBackground = RuuviLocalization.tr("Localizable", "change_background", fallback: "Change background") + /// Change background image + public static let changeBackgroundImage = RuuviLocalization.tr("Localizable", "change_background_image", fallback: "Change background image") + /// Select background image. If you're not signed in, you'll lose the image in case of app reinstall. + public static let changeBackgroundMessage = RuuviLocalization.tr("Localizable", "change_background_message", fallback: "Select background image. If you're not signed in, you'll lose the image in case of app reinstall.") + /// (changelog) + public static let changelog = RuuviLocalization.tr("Localizable", "changelog", fallback: "(changelog)") + /// https://f.ruuvi.com/t/3192 + public static let changelogIosUrl = RuuviLocalization.tr("Localizable", "changelog_ios_url", fallback: "https://f.ruuvi.com/t/3192") + /// Average + public static let chartStatAvg = RuuviLocalization.tr("Localizable", "chart_stat_avg", fallback: "Average") + /// Hide min/max/avg + public static let chartStatHide = RuuviLocalization.tr("Localizable", "chart_stat_hide", fallback: "Hide min/max/avg") + /// Max + public static let chartStatMax = RuuviLocalization.tr("Localizable", "chart_stat_max", fallback: "Max") + /// Min + public static let chartStatMin = RuuviLocalization.tr("Localizable", "chart_stat_min", fallback: "Min") + /// Show min/max/avg + public static let chartStatShow = RuuviLocalization.tr("Localizable", "chart_stat_show", fallback: "Show min/max/avg") + /// Checking claim state + public static let checkClaimState = RuuviLocalization.tr("Localizable", "check_claim_state", fallback: "Checking claim state") + /// Claiming in progress + public static let claimInProgress = RuuviLocalization.tr("Localizable", "claim_in_progress", fallback: "Claiming in progress") + /// Claim sensor ownership + public static let claimSensorOwnership = RuuviLocalization.tr("Localizable", "claim_sensor_ownership", fallback: "Claim sensor ownership") + /// Secure the ownership information of your sensors by claiming their ownerships in the app. + public static let claimWarning = RuuviLocalization.tr("Localizable", "claim_warning", fallback: "Secure the ownership information of your sensors by claiming their ownerships in the app.") + /// You are scanning different RuuviTag + public static let claimWrongSensorScanned = RuuviLocalization.tr("Localizable", "claim_wrong_sensor_scanned", fallback: "You are scanning different RuuviTag") + /// Clear local history + public static let clearLocalHistory = RuuviLocalization.tr("Localizable", "clear_local_history", fallback: "Clear local history") + /// Do you want to clear locally stored history data from the app? This won't clear internally stored history from the sensor or history data stored on the Ruuvi Cloud service. + public static let clearLocalHistoryDescription = RuuviLocalization.tr("Localizable", "clear_local_history_description", fallback: "Do you want to clear locally stored history data from the app? This won't clear internally stored history from the sensor or history data stored on the Ruuvi Cloud service.") + /// Clear history view + public static let clearView = RuuviLocalization.tr("Localizable", "clear_view", fallback: "Clear history view") + /// Close + public static let close = RuuviLocalization.tr("Localizable", "Close", fallback: "Close") + /// ● Background images + public static let cloudStoredAlerts = RuuviLocalization.tr("Localizable", "cloud_stored_alerts", fallback: "● Background images") + /// ● Alert settings + public static let cloudStoredBackgrounds = RuuviLocalization.tr("Localizable", "cloud_stored_backgrounds", fallback: "● Alert settings") + /// ● Calibration settings + public static let cloudStoredCalibration = RuuviLocalization.tr("Localizable", "cloud_stored_calibration", fallback: "● Calibration settings") + /// ● Custom names + public static let cloudStoredNames = RuuviLocalization.tr("Localizable", "cloud_stored_names", fallback: "● Custom names") + /// ● Sensor ownerships + public static let cloudStoredOwnerships = RuuviLocalization.tr("Localizable", "cloud_stored_ownerships", fallback: "● Sensor ownerships") + /// ● App settings + public static let cloudStoredSharing = RuuviLocalization.tr("Localizable", "cloud_stored_sharing", fallback: "● App settings") + /// Confirm + public static let confirm = RuuviLocalization.tr("Localizable", "Confirm", fallback: "Confirm") + /// Copy + public static let copy = RuuviLocalization.tr("Localizable", "Copy", fallback: "Copy") + /// Copy MAC Address + public static let copyMacAddress = RuuviLocalization.tr("Localizable", "copy_mac_address", fallback: "Copy MAC Address") + /// Copy Unique ID + public static let copyUniqueId = RuuviLocalization.tr("Localizable", "copy_unique_id", fallback: "Copy Unique ID") + /// Dark theme + public static let darkTheme = RuuviLocalization.tr("Localizable", "dark_theme", fallback: "Dark theme") + /// Seems that you don't have any Ruuvi sensors added yet. + public static let dashboardNoSensorsMessage = RuuviLocalization.tr("Localizable", "dashboard_no_sensors_message", fallback: "Seems that you don't have any Ruuvi sensors added yet.") + /// You are not signed in. + /// + /// If you have an account and have already added Ruuvi sensors to it, they will automatically synchronise with Ruuvi Station mobile app when you sign in. + public static let dashboardNoSensorsMessageSignedOut = RuuviLocalization.tr("Localizable", "dashboard_no_sensors_message_signed_out", fallback: "You are not signed in.\n\nIf you have an account and have already added Ruuvi sensors to it, they will automatically synchronise with Ruuvi Station mobile app when you sign in.") + /// 1 day + public static let day1 = RuuviLocalization.tr("Localizable", "day_1", fallback: "1 day") + /// 10 days + public static let day10 = RuuviLocalization.tr("Localizable", "day_10", fallback: "10 days") + /// 2 days + public static let day2 = RuuviLocalization.tr("Localizable", "day_2", fallback: "2 days") + /// 3 days + public static let day3 = RuuviLocalization.tr("Localizable", "day_3", fallback: "3 days") + /// 4 days + public static let day4 = RuuviLocalization.tr("Localizable", "day_4", fallback: "4 days") + /// 5 days + public static let day5 = RuuviLocalization.tr("Localizable", "day_5", fallback: "5 days") + /// 6 days + public static let day6 = RuuviLocalization.tr("Localizable", "day_6", fallback: "6 days") + /// 7 days + public static let day7 = RuuviLocalization.tr("Localizable", "day_7", fallback: "7 days") + /// 8 days + public static let day8 = RuuviLocalization.tr("Localizable", "day_8", fallback: "8 days") + /// 9 days + public static let day9 = RuuviLocalization.tr("Localizable", "day_9", fallback: "9 days") + /// %0.f days + public static let dayX = RuuviLocalization.tr("Localizable", "day_x", fallback: "%0.f days") + /// dBm + public static let dBm = RuuviLocalization.tr("Localizable", "dBm", fallback: "dBm") + /// Are you sure? + public static let dialogAreYouSure = RuuviLocalization.tr("Localizable", "dialog_are_you_sure", fallback: "Are you sure?") + /// This operation cannot be undone. + public static let dialogOperationUndone = RuuviLocalization.tr("Localizable", "dialog_operation_undone", fallback: "This operation cannot be undone.") + /// Don't show this again + public static let doNotShowAgain = RuuviLocalization.tr("Localizable", "do_not_show_again", fallback: "Don't show this again") + /// Do you own this sensor? + public static let doYouOwnSensor = RuuviLocalization.tr("Localizable", "do_you_own_sensor", fallback: "Do you own this sensor?") + /// Done + public static let done = RuuviLocalization.tr("Localizable", "Done", fallback: "Done") + /// Download + public static let download = RuuviLocalization.tr("Localizable", "download", fallback: "Download") + /// No data available + /// in the selected history window. + public static let emptyChartMessage = RuuviLocalization.tr("Localizable", "empty_chart_message", fallback: "No data available \nin the selected history window.") + /// Enter Code + public static let enterCode = RuuviLocalization.tr("Localizable", "enter_code", fallback: "Enter Code") + /// You can export a sensor's history from its history graph page. Tap the three dots menu icon in the top right corner, and then select "Export history (csv)". + public static let exportCsvFeatureLocation = RuuviLocalization.tr("Localizable", "export_csv_feature_location", fallback: "You can export a sensor's history from its history graph page. Tap the three dots menu icon in the top right corner, and then select \"Export history (csv)\".") + /// Export history (csv) + public static let exportHistory = RuuviLocalization.tr("Localizable", "export_history", fallback: "Export history (csv)") + /// Firmware Version: + public static let firmwareVersion = RuuviLocalization.tr("Localizable", "firmware_version", fallback: "Firmware Version:") + /// System theme + public static let followSystemTheme = RuuviLocalization.tr("Localizable", "follow_system_theme", fallback: "System theme") + /// Force Claim + public static let forceClaim = RuuviLocalization.tr("Localizable", "force_claim", fallback: "Force Claim") + /// Force Claim Sensor + public static let forceClaimSensor = RuuviLocalization.tr("Localizable", "force_claim_sensor", fallback: "Force Claim Sensor") + /// This sensor has been claimed by another user. You can force the ownership to your account if you have physical access to this sensor. Each Ruuvi sensor can have only one owner. + public static let forceClaimSensorDescription1 = RuuviLocalization.tr("Localizable", "force_claim_sensor_description1", fallback: "This sensor has been claimed by another user. You can force the ownership to your account if you have physical access to this sensor. Each Ruuvi sensor can have only one owner.") + /// Force Claim is done by using Near-Field Communication (NFC). Make sure NFC is enabled on your mobile device. + /// + /// 1. Touch your Ruuvi sensor with your mobile device to start the claiming process. + /// + /// 2. When successfully claimed, you will be sent back to Sensor Settings. + /// + /// If claiming was unsuccessful or NFC is not available on your device: + /// + /// 1. Open the cover of your Ruuvi sensor. + /// + /// 2. Locate the round black button (or button "B" in case your sensor has 2 buttons) on the white circuit board and press it briefly, then tap on Use BT button to start the claiming process. + /// + /// 3. When successfully claimed you will be sent back to Sensor Settings. + public static let forceClaimSensorDescription2 = RuuviLocalization.tr("Localizable", "force_claim_sensor_description2", fallback: "Force Claim is done by using Near-Field Communication (NFC). Make sure NFC is enabled on your mobile device.\n\n\t1. Touch your Ruuvi sensor with your mobile device to start the claiming process.\n\n\t2. When successfully claimed, you will be sent back to Sensor Settings.\n\nIf claiming was unsuccessful or NFC is not available on your device:\n\n\t1. Open the cover of your Ruuvi sensor.\n\n\t2. Locate the round black button (or button \"B\" in case your sensor has 2 buttons) on the white circuit board and press it briefly, then tap on Use BT button to start the claiming process.\n\n\t3. When successfully claimed you will be sent back to Sensor Settings.") + /// Full image view + public static let fullImageView = RuuviLocalization.tr("Localizable", "full_image_view", fallback: "Full image view") + /// g + public static let g = RuuviLocalization.tr("Localizable", "g", fallback: "g") + /// g/m³ + public static let gm³ = RuuviLocalization.tr("Localizable", "g/m³", fallback: "g/m³") + /// Ruuvi Station downloads the internal history of the sensor for the last 10 days if the measurement history is available. + /// + /// The history is downloaded using a Bluetooth connection. Make sure you are near the sensor. + public static let gattSyncDescription = RuuviLocalization.tr("Localizable", "gatt_sync_description", fallback: "Ruuvi Station downloads the internal history of the sensor for the last 10 days if the measurement history is available.\n\nThe history is downloaded using a Bluetooth connection. Make sure you are near the sensor.") + /// Go to sensor card + public static let goToSensor = RuuviLocalization.tr("Localizable", "go_to_sensor", fallback: "Go to sensor card") + /// h + public static let h = RuuviLocalization.tr("Localizable", "h", fallback: "h") + /// History view + public static let historyView = RuuviLocalization.tr("Localizable", "history_view", fallback: "History view") + /// Hour + public static let hour = RuuviLocalization.tr("Localizable", "hour", fallback: "Hour") + /// Hours + public static let hours = RuuviLocalization.tr("Localizable", "hours", fallback: "Hours") + /// hPa + public static let hPa = RuuviLocalization.tr("Localizable", "hPa", fallback: "hPa") + /// Image cards + public static let imageCards = RuuviLocalization.tr("Localizable", "image_cards", fallback: "Image cards") + /// Internet connection problem + public static let internetConnectionProblem = RuuviLocalization.tr("Localizable", "internet_connection_problem", fallback: "Internet connection problem") + /// Let's Sign In + public static let letsDoIt = RuuviLocalization.tr("Localizable", "lets_do_it", fallback: "Let's Sign In") + /// Light theme + public static let lightTheme = RuuviLocalization.tr("Localizable", "light_theme", fallback: "Light theme") + /// Ruuvi Station mobile app supports maximum 10 days of history. Ruuvi Cloud subscribers are able to view up to 2 years of historical data using web app at ruuvi.com/station (requires Ruuvi Gateway router). + public static let longerHistoryMessage = RuuviLocalization.tr("Localizable", "longer_history_message", fallback: "Ruuvi Station mobile app supports maximum 10 days of history. Ruuvi Cloud subscribers are able to view up to 2 years of historical data using web app at ruuvi.com/station (requires Ruuvi Gateway router).") + /// Longer history + public static let longerHistoryTitle = RuuviLocalization.tr("Localizable", "longer_history_title", fallback: "Longer history") + /// Low battery + public static let lowBattery = RuuviLocalization.tr("Localizable", "low_battery", fallback: "Low battery") + /// Mac Address: + public static let macAddress = RuuviLocalization.tr("Localizable", "mac_address", fallback: "Mac Address:") + /// min + public static let min = RuuviLocalization.tr("Localizable", "min", fallback: "min") + /// Minutes + public static let minutes = RuuviLocalization.tr("Localizable", "minutes", fallback: "Minutes") + /// More... + public static let more = RuuviLocalization.tr("Localizable", "more", fallback: "More...") + /// - + public static let na = RuuviLocalization.tr("Localizable", "N/A", fallback: "-") + /// Name: + public static let name = RuuviLocalization.tr("Localizable", "name", fallback: "Name:") + /// Only sensors within range of your Ruuvi Gateway can be shared. + public static let networkSharingDisabled = RuuviLocalization.tr("Localizable", "network_sharing_disabled", fallback: "Only sensors within range of your Ruuvi Gateway can be shared.") + /// No + public static let no = RuuviLocalization.tr("Localizable", "No", fallback: "No") + /// A free account will be created for this email if you don't already have one. Only email address is required. We keep your information safe. + public static let noPasswordNeeded = RuuviLocalization.tr("Localizable", "no_password_needed", fallback: "A free account will be created for this email if you don't already have one. Only email address is required. We keep your information safe.") + /// Note! + public static let note = RuuviLocalization.tr("Localizable", "note", fallback: "Note!") + /// Off + public static let off = RuuviLocalization.tr("Localizable", "Off", fallback: "Off") + /// OK + public static let ok = RuuviLocalization.tr("Localizable", "OK", fallback: "OK") + /// On + public static let on = RuuviLocalization.tr("Localizable", "On", fallback: "On") + /// Bring your favorite sensors to your Home Screen and Lock Screen as + public static let onboardingAccessWidgets = RuuviLocalization.tr("Localizable", "onboarding_access_widgets", fallback: "Bring your favorite sensors to your Home Screen and Lock Screen as") + /// Alerts + public static let onboardingAlerts = RuuviLocalization.tr("Localizable", "onboarding_alerts", fallback: "Alerts") + /// Next + public static let onboardingContinue = RuuviLocalization.tr("Localizable", "onboarding_continue", fallback: "Next") + /// Dashboard + public static let onboardingDashboard = RuuviLocalization.tr("Localizable", "onboarding_dashboard", fallback: "Dashboard") + /// Explore your measurement + public static let onboardingExploreDetailed = RuuviLocalization.tr("Localizable", "onboarding_explore_detailed", fallback: "Explore your measurement") + /// View all sensors at a glance on your + public static let onboardingFollowMeasurement = RuuviLocalization.tr("Localizable", "onboarding_follow_measurement", fallback: "View all sensors at a glance on your") + /// A Ruuvi Gateway router is required. + public static let onboardingGatewayRequired = RuuviLocalization.tr("Localizable", "onboarding_gateway_required", fallback: "A Ruuvi Gateway router is required.") + /// Ruuvi experience is better when you're signed in. Do it now or continue without cloud features. + public static let onboardingGoToSignIn = RuuviLocalization.tr("Localizable", "onboarding_go_to_sign_in", fallback: "Ruuvi experience is better when you're signed in. Do it now or continue without cloud features.") + /// Let's start measuring! + public static let onboardingGoToSignInAlreadySignedIn = RuuviLocalization.tr("Localizable", "onboarding_go_to_sign_in_already_signed_in", fallback: "Let's start measuring!") + /// Widgets + public static let onboardingHandyWidgets = RuuviLocalization.tr("Localizable", "onboarding_handy_widgets", fallback: "Widgets") + /// History + public static let onboardingHistory = RuuviLocalization.tr("Localizable", "onboarding_history", fallback: "History") + /// Measure Your World + public static let onboardingMeasureYourWorld = RuuviLocalization.tr("Localizable", "onboarding_measure_your_world", fallback: "Measure Your World") + /// Personalise + public static let onboardingPersonalise = RuuviLocalization.tr("Localizable", "onboarding_personalise", fallback: "Personalise") + /// Read Your Ruuvi Sensors + public static let onboardingReadSensorsData = RuuviLocalization.tr("Localizable", "onboarding_read_sensors_data", fallback: "Read Your Ruuvi Sensors") + /// Set and customise your + public static let onboardingSetCustom = RuuviLocalization.tr("Localizable", "onboarding_set_custom", fallback: "Set and customise your") + /// to measure together with your friends and family. + public static let onboardingShareYourSensors = RuuviLocalization.tr("Localizable", "onboarding_share_your_sensors", fallback: "to measure together with your friends and family.") + /// Share Sensors + public static let onboardingShareesCanUse = RuuviLocalization.tr("Localizable", "onboarding_sharees_can_use", fallback: "Share Sensors") + /// Skip + public static let onboardingSkip = RuuviLocalization.tr("Localizable", "onboarding_skip", fallback: "Skip") + /// Ruuvi Web App + public static let onboardingStationWeb = RuuviLocalization.tr("Localizable", "onboarding_station_web", fallback: "Ruuvi Web App") + /// Swipe to continue → + public static let onboardingSwipeToContinue = RuuviLocalization.tr("Localizable", "onboarding_swipe_to_continue", fallback: "Swipe to continue →") + /// Almost there! + public static let onboardingThatsIt = RuuviLocalization.tr("Localizable", "onboarding_thats_it", fallback: "Almost there!") + /// Let's get started! + public static let onboardingThatsItAlreadySignedIn = RuuviLocalization.tr("Localizable", "onboarding_thats_it_already_signed_in", fallback: "Let's get started!") + /// using Bluetooth or Ruuvi Cloud + public static let onboardingViaBluetoothOrCloud = RuuviLocalization.tr("Localizable", "onboarding_via_bluetooth_or_cloud", fallback: "using Bluetooth or Ruuvi Cloud") + /// Large dashboard, multi-year history, email alerts and more on + public static let onboardingWebPros = RuuviLocalization.tr("Localizable", "onboarding_web_pros", fallback: "Large dashboard, multi-year history, email alerts and more on") + /// Let's get to know your Ruuvi Station app. + public static let onboardingWithRuuviSensors = RuuviLocalization.tr("Localizable", "onboarding_with_ruuvi_sensors", fallback: "Let's get to know your Ruuvi Station app.") + /// your app with custom names and backgrounds. + public static let onboardingYourSensors = RuuviLocalization.tr("Localizable", "onboarding_your_sensors", fallback: "your app with custom names and backgrounds.") + /// Open history view + public static let openHistoryView = RuuviLocalization.tr("Localizable", "open_history_view", fallback: "Open history view") + /// Open sensor view + public static let openSensorView = RuuviLocalization.tr("Localizable", "open_sensor_view", fallback: "Open sensor view") + /// Owner's Ruuvi Plan + public static let ownersPlan = RuuviLocalization.tr("Localizable", "owners_plan", fallback: "Owner's Ruuvi Plan") + /// Reading Bluetooth: %0.f + public static let readingHistoryX = RuuviLocalization.tr("Localizable", "reading_history_x", fallback: "Reading Bluetooth: %0.f") + /// Remove + public static let remove = RuuviLocalization.tr("Localizable", "Remove", fallback: "Remove") + /// By removing the sensor, your sensor ownership status will be revoked and sensor settings, such as name, background image, calibration settings and alert settings will be removed. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner. + public static let removeClaimedSensorDescription = RuuviLocalization.tr("Localizable", "remove_claimed_sensor_description", fallback: "By removing the sensor, your sensor ownership status will be revoked and sensor settings, such as name, background image, calibration settings and alert settings will be removed. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner.") + /// I also want to remove sensor history data from Ruuvi Cloud. + public static let removeCloudHistoryDescription = RuuviLocalization.tr("Localizable", "remove_cloud_history_description", fallback: "I also want to remove sensor history data from Ruuvi Cloud.") + /// Remove cloud history + public static let removeCloudHistoryTitle = RuuviLocalization.tr("Localizable", "remove_cloud_history_title", fallback: "Remove cloud history") + /// If you choose to remove this sensor, it will result in the deletion of your locally stored measurement history, along with the removal of any related sensor settings like name, background image, calibration, and alert configurations. + /// + /// You can add this sensor later again, if needed. + public static let removeLocalSensorDescription = RuuviLocalization.tr("Localizable", "remove_local_sensor_description", fallback: "If you choose to remove this sensor, it will result in the deletion of your locally stored measurement history, along with the removal of any related sensor settings like name, background image, calibration, and alert configurations.\n\nYou can add this sensor later again, if needed.") + /// If you choose to remove this shared sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore. + /// + /// You will also lose any related sensor settings like name, background image and alert configurations. + public static let removeSharedSensorDescription = RuuviLocalization.tr("Localizable", "remove_shared_sensor_description", fallback: "If you choose to remove this shared sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore.\n\nYou will also lose any related sensor settings like name, background image and alert configurations.") + /// Rename + public static let rename = RuuviLocalization.tr("Localizable", "rename", fallback: "Rename") + /// Request Code + public static let requestCode = RuuviLocalization.tr("Localizable", "request_code", fallback: "Request Code") + /// Using this alert requires you to be signed in to the app, and that you have claimed the ownership of this sensor and it's in the range of Ruuvi Gateway router. iOS devices are unable to indicate signal strength information of received data sent by Ruuvi sensor when sensor is paired and measurements are being received in the background. Realtime Bluetooth signal strength is shown in the app but doesn't affect this alert. + public static let rssiAlertDescription = RuuviLocalization.tr("Localizable", "rssi_alert_description", fallback: "Using this alert requires you to be signed in to the app, and that you have claimed the ownership of this sensor and it's in the range of Ruuvi Gateway router. iOS devices are unable to indicate signal strength information of received data sent by Ruuvi sensor when sensor is paired and measurements are being received in the background. Realtime Bluetooth signal strength is shown in the app but doesn't affect this alert.") + /// Ruuvi Cloud + public static let ruuviCloud = RuuviLocalization.tr("Localizable", "ruuvi_cloud", fallback: "Ruuvi Cloud") + /// s + public static let s = RuuviLocalization.tr("Localizable", "s", fallback: "s") + /// Select from default images + public static let selectDefaultImage = RuuviLocalization.tr("Localizable", "select_default_image", fallback: "Select from default images") + /// Select from phone gallery + public static let selectFromGallery = RuuviLocalization.tr("Localizable", "select_from_gallery", fallback: "Select from phone gallery") + /// Sensor Details + public static let sensorDetails = RuuviLocalization.tr("Localizable", "sensor_details", fallback: "Sensor Details") + /// Sensor not found. Try again. + public static let sensorNotFoundError = RuuviLocalization.tr("Localizable", "sensor_not_found_error", fallback: "Sensor not found. Try again.") + /// Signing in to the app has many advantages. Settings will be safely stored to your account: + public static let sensorsOwnershipAndSettingsStoredInCloud = RuuviLocalization.tr("Localizable", "sensors_ownership_and_settings_stored_in_cloud", fallback: "Signing in to the app has many advantages. Settings will be safely stored to your account:") + /// Limit alert notifications + public static let settingsAlertLimitNotification = RuuviLocalization.tr("Localizable", "settings_alert_limit_notification", fallback: "Limit alert notifications") + /// Trigger Bluetooth alert notification only once per hour even if alert was retriggered. + public static let settingsAlertLimitNotificationDescription = RuuviLocalization.tr("Localizable", "settings_alert_limit_notification_description", fallback: "Trigger Bluetooth alert notification only once per hour even if alert was retriggered.") + /// Alert Notifications + public static let settingsAlertNotifications = RuuviLocalization.tr("Localizable", "settings_alert_notifications", fallback: "Alert Notifications") + /// Alert Sound + public static let settingsAlertSound = RuuviLocalization.tr("Localizable", "settings_alert_sound", fallback: "Alert Sound") + /// System Default + public static let settingsAlertSoundDefault = RuuviLocalization.tr("Localizable", "settings_alert_sound_default", fallback: "System Default") + /// Select push notification alert sound. + public static let settingsAlertSoundDescription = RuuviLocalization.tr("Localizable", "settings_alert_sound_description", fallback: "Select push notification alert sound.") + /// Ruuvi Alert + public static let settingsAlertSoundRuuviSpeak = RuuviLocalization.tr("Localizable", "settings_alert_sound_ruuvi_speak", fallback: "Ruuvi Alert") + /// You can also adjust Notification settings under iOS Settings -> Notifications + public static let settingsAlertsFooterDescription = RuuviLocalization.tr("Localizable", "settings_alerts_footer_description", fallback: "You can also adjust Notification settings under iOS Settings -> Notifications") + /// iOS Settings -> Notifications + public static let settingsAlertsFooterDescriptionLinkMask = RuuviLocalization.tr("Localizable", "settings_alerts_footer_description_link_mask", fallback: "iOS Settings -> Notifications") + /// Settings & alerts + public static let settingsAndAlerts = RuuviLocalization.tr("Localizable", "settings_and_alerts", fallback: "Settings & alerts") + /// Appearance + public static let settingsAppearance = RuuviLocalization.tr("Localizable", "settings_appearance", fallback: "Appearance") + /// Email Alerts + public static let settingsEmailAlerts = RuuviLocalization.tr("Localizable", "settings_email_alerts", fallback: "Email Alerts") + /// If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive email alerts by enabling this. + public static let settingsEmailAlertsDescription = RuuviLocalization.tr("Localizable", "settings_email_alerts_description", fallback: "If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive email alerts by enabling this.") + /// Push Alerts + public static let settingsPushAlerts = RuuviLocalization.tr("Localizable", "settings_push_alerts", fallback: "Push Alerts") + /// If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive push alerts by enabling this. + public static let settingsPushAlertsDescription = RuuviLocalization.tr("Localizable", "settings_push_alerts_description", fallback: "If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive push alerts by enabling this.") + /// Share pending + public static let sharePending = RuuviLocalization.tr("Localizable", "share_pending", fallback: "Share pending") + /// Shared successfully! This email address isn't linked to a Ruuvi account yet. An invite to create a free account has been sent. Once created, you'll see it in the sharee listing. + public static let sharePendingMessage = RuuviLocalization.tr("Localizable", "share_pending_message", fallback: "Shared successfully! This email address isn't linked to a Ruuvi account yet. An invite to create a free account has been sent. Once created, you'll see it in the sharee listing.") + /// Shared to %d/%d + public static func sharedToX(_ p1: Int, _ p2: Int) -> String { + return RuuviLocalization.tr("Localizable", "shared_to_x", p1, p2, fallback: "Shared to %d/%d") + } + /// Continue + public static let signInContinue = RuuviLocalization.tr("Localizable", "sign_in_continue", fallback: "Continue") + /// Sign in or create a free Ruuvi account + public static let signInOrCreateFreeAccount = RuuviLocalization.tr("Localizable", "sign_in_or_create_free_account", fallback: "Sign in or create a free Ruuvi account") + /// Signal Strength (dBm) + public static let signalStrengthDbm = RuuviLocalization.tr("Localizable", "signal_strength_dbm", fallback: "Signal Strength (dBm)") + /// (Signing in is optional) + public static let signingInIsOptional = RuuviLocalization.tr("Localizable", "signing_in_is_optional", fallback: "(Signing in is optional)") + /// Simple cards + public static let simpleCards = RuuviLocalization.tr("Localizable", "simple_cards", fallback: "Simple cards") + /// Support + public static let support = RuuviLocalization.tr("Localizable", "support", fallback: "Support") + /// Synchronisation + public static let synchronisation = RuuviLocalization.tr("Localizable", "synchronisation", fallback: "Synchronisation") + /// Synchronised + public static let synchronized = RuuviLocalization.tr("Localizable", "Synchronized", fallback: "Synchronised") + /// Loading history from the cloud... + public static let syncing = RuuviLocalization.tr("Localizable", "Syncing...", fallback: "Loading history from the cloud...") + /// Take a photo + public static let takePhoto = RuuviLocalization.tr("Localizable", "take_photo", fallback: "Take a photo") + /// No password needed. + public static let toUseAllAppFeatures = RuuviLocalization.tr("Localizable", "to_use_all_app_features", fallback: "No password needed.") + /// Type your email.. + public static let typeYourEmail = RuuviLocalization.tr("Localizable", "type_your_email", fallback: "Type your email..") + /// Unclaim + public static let unclaim = RuuviLocalization.tr("Localizable", "unclaim", fallback: "Unclaim") + /// Unclaim sensor + public static let unclaimSensor = RuuviLocalization.tr("Localizable", "unclaim_sensor", fallback: "Unclaim sensor") + /// Ownership of this sensor has been claimed to your Ruuvi account. Press Unclaim to remove this sensor's settings and related data from your Ruuvi account. + public static let unclaimSensorDescription = RuuviLocalization.tr("Localizable", "unclaim_sensor_description", fallback: "Ownership of this sensor has been claimed to your Ruuvi account. Press Unclaim to remove this sensor's settings and related data from your Ruuvi account.") + /// Unique ID: + public static let uniqueId = RuuviLocalization.tr("Localizable", "unique_id", fallback: "Unique ID:") + /// Updated + public static let updated = RuuviLocalization.tr("Localizable", "Updated", fallback: "Updated") + /// Uploading: %.0f + public static func uploadingProgress(_ p1: Float) -> String { + return RuuviLocalization.tr("Localizable", "uploading_progress", p1, fallback: "Uploading: %.0f") + } + /// Use BT + public static let useBluetooth = RuuviLocalization.tr("Localizable", "use_bluetooth", fallback: "Use BT") + /// Use NFC + public static let useNfc = RuuviLocalization.tr("Localizable", "use_nfc", fallback: "Use NFC") + /// No thanks, skip + public static let useWithoutAccount = RuuviLocalization.tr("Localizable", "use_without_account", fallback: "No thanks, skip") + /// V + public static let v = RuuviLocalization.tr("Localizable", "V", fallback: "V") + /// View + public static let view = RuuviLocalization.tr("Localizable", "view", fallback: "View") + /// Benefits + public static let whyShouldSignIn = RuuviLocalization.tr("Localizable", "why_should_sign_in", fallback: "Benefits") + /// Yes + public static let yes = RuuviLocalization.tr("Localizable", "Yes", fallback: "Yes") + /// °C + public static let ºC = RuuviLocalization.tr("Localizable", "ºC", fallback: "°C") + /// °F + public static let ºF = RuuviLocalization.tr("Localizable", "ºF", fallback: "°F") + public enum About { + public enum AboutHelp { + /// Ruuvi Station is an easy-to-use application that allows you to monitor the measurement data of Ruuvi sensors. + public static let contents = RuuviLocalization.tr("Localizable", "About.AboutHelp.contents", fallback: "Ruuvi Station is an easy-to-use application that allows you to monitor the measurement data of Ruuvi sensors.") + /// About / Help + public static let header = RuuviLocalization.tr("Localizable", "About.AboutHelp.header", fallback: "About / Help") + } + public enum DatabaseSize { + /// Database size: %@ + public static func text(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "About.DatabaseSize.text", String(describing: p1), fallback: "Database size: %@") + } + } + public enum MeasurementsCount { + /// Number of locally stored measurements: %d + public static func text(_ p1: Int) -> String { + return RuuviLocalization.tr("Localizable", "About.MeasurementsCount.text", p1, fallback: "Number of locally stored measurements: %d") + } + } + public enum More { + /// Ruuvi's website: ruuvi.com + /// Ruuvi Forum: f.ruuvi.com + /// Ruuvi Blog: ruuvi.com/blog + /// Ruuvi on Twitter: twitter.com/ruuvicom + public static let contents = RuuviLocalization.tr("Localizable", "About.More.contents", fallback: "Ruuvi's website: ruuvi.com\nRuuvi Forum: f.ruuvi.com\nRuuvi Blog: ruuvi.com/blog\nRuuvi on Twitter: twitter.com/ruuvicom") + /// More to read + public static let header = RuuviLocalization.tr("Localizable", "About.More.header", fallback: "More to read") + } + public enum OpenSource { + /// Just like Ruuvi sensors, Ruuvi Station apps are open source. Follow the development and contribute at: github.com/ruuvi + public static let contents = RuuviLocalization.tr("Localizable", "About.OpenSource.contents", fallback: "Just like Ruuvi sensors, Ruuvi Station apps are open source. Follow the development and contribute at: github.com/ruuvi") + /// Open-source + public static let header = RuuviLocalization.tr("Localizable", "About.OpenSource.header", fallback: "Open-source") + } + public enum OperationsManual { + /// Get started using the Ruuvi Station mobile application with our online guides: ruuvi.com/support/station-mobile + public static let contents = RuuviLocalization.tr("Localizable", "About.OperationsManual.contents", fallback: "Get started using the Ruuvi Station mobile application with our online guides: ruuvi.com/support/station-mobile") + /// Operations manual + public static let header = RuuviLocalization.tr("Localizable", "About.OperationsManual.header", fallback: "Operations manual") + } + public enum Privacy { + /// By using the application, you accept Ruuvi's standard terms and conditions: ruuvi.com/terms + public static let contents = RuuviLocalization.tr("Localizable", "About.Privacy.contents", fallback: "By using the application, you accept Ruuvi's standard terms and conditions: ruuvi.com/terms") + /// Privacy policy + public static let header = RuuviLocalization.tr("Localizable", "About.Privacy.header", fallback: "Privacy policy") + } + public enum TagsCount { + /// Added sensors: %d + public static func text(_ p1: Int) -> String { + return RuuviLocalization.tr("Localizable", "About.TagsCount.text", p1, fallback: "Added sensors: %d") + } + } + public enum Troubleshooting { + /// Find help using the Ruuvi Station apps, Ruuvi products and Ruuvi Cloud service from our support center: ruuvi.com/support + public static let contents = RuuviLocalization.tr("Localizable", "About.Troubleshooting.contents", fallback: "Find help using the Ruuvi Station apps, Ruuvi products and Ruuvi Cloud service from our support center: ruuvi.com/support") + /// Troubleshooting + public static let header = RuuviLocalization.tr("Localizable", "About.Troubleshooting.header", fallback: "Troubleshooting") + } + public enum Version { + /// Version + public static let text = RuuviLocalization.tr("Localizable", "About.Version.text", fallback: "Version") + } + } + public enum Background { + public enum Interval { + public enum Every { + /// every + public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Every.string", fallback: "every") + } + public enum Min { + /// min + public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Min.string", fallback: "min") + } + public enum Sec { + /// sec + public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Sec.string", fallback: "sec") + } + } + public enum KeepConnection { + /// Keep the Connection + public static let title = RuuviLocalization.tr("Localizable", "Background.KeepConnection.title", fallback: "Keep the Connection") + } + public enum PresentNotifications { + /// Show Notifications + public static let title = RuuviLocalization.tr("Localizable", "Background.PresentNotifications.title", fallback: "Show Notifications") + } + public enum ReadRSSITitle { + /// Read RSSI + public static let title = RuuviLocalization.tr("Localizable", "Background.readRSSITitle.title", fallback: "Read RSSI") + } + } + public enum BluetoothError { + /// Disconnected + public static let disconnected = RuuviLocalization.tr("Localizable", "BluetoothError.disconnected", fallback: "Disconnected") + } + public enum Cards { + public enum Alert { + public enum AlreadyLoggedIn { + /// User %@ is already signed in. If you'd like to use a different account, please sign out first and then try again. + public static func message(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "Cards.Alert.AlreadyLoggedIn.message", String(describing: p1), fallback: "User %@ is already signed in. If you'd like to use a different account, please sign out first and then try again.") + } + } + } + public enum BluetoothDisabledAlert { + /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. + public static let message = RuuviLocalization.tr("Localizable", "Cards.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") + /// Bluetooth is not enabled + public static let title = RuuviLocalization.tr("Localizable", "Cards.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") + } + public enum Connected { + /// Connected + public static let title = RuuviLocalization.tr("Localizable", "Cards.Connected.title", fallback: "Connected") + } + public enum Error { + public enum ReverseGeocodingFailed { + /// Failed to load data for Virtual Sensor. Reverse geocode operation limit exceeded. + public static let message = RuuviLocalization.tr("Localizable", "Cards.Error.ReverseGeocodingFailed.message", fallback: "Failed to load data for Virtual Sensor. Reverse geocode operation limit exceeded.") + } + } + public enum KeepConnectionDialog { + /// Seems like you are running a connectable firmware on your Ruuvi device. Would you like to keep the connection open to this Ruuvi device in the background? This will allow histograms and alerts to work even when the application is minimised. + public static let message = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.message", fallback: "Seems like you are running a connectable firmware on your Ruuvi device. Would you like to keep the connection open to this Ruuvi device in the background? This will allow histograms and alerts to work even when the application is minimised.") + public enum Dismiss { + /// Cancel + public static let title = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.Dismiss.title", fallback: "Cancel") + } + public enum KeepConnection { + /// Keep the Connection + public static let title = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.KeepConnection.title", fallback: "Keep the Connection") + } + } + public enum LegacyFirmwareUpdateDialog { + /// Looks like your sensor is using an old firmware software version. To access new features such as history graphs, alerts and cloud services, updating is mandatory. + public static let message = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.message", fallback: "Looks like your sensor is using an old firmware software version. To access new features such as history graphs, alerts and cloud services, updating is mandatory.") + public enum CancelConfirmation { + /// Are you sure? Without updating, you won't be able to claim ownership of the sensor, download history graphs and set alerts. The update also includes bug fixes. If you cancel now, you can start the update process again from the sensor's settings page. + public static let message = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message", fallback: "Are you sure? Without updating, you won't be able to claim ownership of the sensor, download history graphs and set alerts. The update also includes bug fixes. If you cancel now, you can start the update process again from the sensor's settings page.") + } + public enum CheckForUpdate { + /// Check for update + public static let title = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title", fallback: "Check for update") + } + } + public enum Movements { + /// movements + public static let title = RuuviLocalization.tr("Localizable", "Cards.Movements.title", fallback: "movements") + } + public enum NoSensors { + /// No sensors added + /// Press here to add sensors + public static let title = RuuviLocalization.tr("Localizable", "Cards.NoSensors.title", fallback: "No sensors added\nPress here to add sensors") + } + public enum UpdatedLabel { + public enum NoData { + /// No data during the last 10 days + public static let message = RuuviLocalization.tr("Localizable", "Cards.UpdatedLabel.NoData.message", fallback: "No data during the last 10 days") + } + } + public enum WebTagAPILimitExcededError { + public enum Alert { + /// Please try again in 5 minutes + public static let message = RuuviLocalization.tr("Localizable", "Cards.WebTagAPILimitExcededError.Alert.message", fallback: "Please try again in 5 minutes") + /// Too many requests + public static let title = RuuviLocalization.tr("Localizable", "Cards.WebTagAPILimitExcededError.Alert.title", fallback: "Too many requests") + } + } + } + public enum ChartSettings { + public enum AllPoints { + /// Charts may be updated slowly when enabled. + public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.AllPoints.description", fallback: "Charts may be updated slowly when enabled.") + /// Show all measurements + public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.AllPoints.title", fallback: "Show all measurements") + } + public enum DrawDots { + /// Small dots will help to understand when measurements were collected. + public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.DrawDots.description", fallback: "Small dots will help to understand when measurements were collected.") + /// Show datapoints + public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.DrawDots.title", fallback: "Show datapoints") + } + public enum Duration { + /// Configure the period of history to be shown on chart from 1 to 10 days. + public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.Duration.description", fallback: "Configure the period of history to be shown on chart from 1 to 10 days.") + /// Chart History View Period + public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.Duration.title", fallback: "Chart History View Period") + } + } + public enum CoreError { + /// Failed to get current location + public static let failedToGetCurrentLocation = RuuviLocalization.tr("Localizable", "CoreError.failedToGetCurrentLocation", fallback: "Failed to get current location") + /// Failed to get data from response + public static let failedToGetDataFromResponse = RuuviLocalization.tr("Localizable", "CoreError.failedToGetDataFromResponse", fallback: "Failed to get data from response") + /// Failed to get background directory + public static let failedToGetDocumentsDirectory = RuuviLocalization.tr("Localizable", "CoreError.failedToGetDocumentsDirectory", fallback: "Failed to get background directory") + /// Failed to get PNG representation + public static let failedToGetPngRepresentation = RuuviLocalization.tr("Localizable", "CoreError.failedToGetPngRepresentation", fallback: "Failed to get PNG representation") + /// Missing permission for Location Services + public static let locationPermissionDenied = RuuviLocalization.tr("Localizable", "CoreError.locationPermissionDenied", fallback: "Missing permission for Location Services") + /// Location permission authorisation status is not determined + public static let locationPermissionNotDetermined = RuuviLocalization.tr("Localizable", "CoreError.locationPermissionNotDetermined", fallback: "Location permission authorisation status is not determined") + /// Object invalidated + public static let objectInvalidated = RuuviLocalization.tr("Localizable", "CoreError.objectInvalidated", fallback: "Object invalidated") + /// Object not found + public static let objectNotFound = RuuviLocalization.tr("Localizable", "CoreError.objectNotFound", fallback: "Object not found") + /// Unable to send email + public static let unableToSendEmail = RuuviLocalization.tr("Localizable", "CoreError.unableToSendEmail", fallback: "Unable to send email") + } + public enum DFUUIView { + /// You are running the latest firmware version, no need to update + public static let alreadyOnLatest = RuuviLocalization.tr("Localizable", "DFUUIView.alreadyOnLatest", fallback: "You are running the latest firmware version, no need to update") + /// Current version: + public static let currentTitle = RuuviLocalization.tr("Localizable", "DFUUIView.currentTitle", fallback: "Current version:") + /// Do not close the app or power off the sensor during the update. + public static let doNotCloseTitle = RuuviLocalization.tr("Localizable", "DFUUIView.doNotCloseTitle", fallback: "Do not close the app or power off the sensor during the update.") + /// Downloading the latest firmware to be updated... + public static let downloadingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.downloadingTitle", fallback: "Downloading the latest firmware to be updated...") + /// Latest available Ruuvi Firmware version: + public static let latestTitle = RuuviLocalization.tr("Localizable", "DFUUIView.latestTitle", fallback: "Latest available Ruuvi Firmware version:") + /// 2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label. + public static let locateBootButtonTitle = RuuviLocalization.tr("Localizable", "DFUUIView.locateBootButtonTitle", fallback: "2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label.") + /// Firmware Update + public static let navigationTitle = RuuviLocalization.tr("Localizable", "DFUUIView.navigationTitle", fallback: "Firmware Update") + /// Your sensor doesn't report its current firmware version. Either you're not in its Bluetooth range, it's connected to another phone, or it's running a very old firmware version. + public static let notReportingDescription = RuuviLocalization.tr("Localizable", "DFUUIView.notReportingDescription", fallback: "Your sensor doesn't report its current firmware version. Either you're not in its Bluetooth range, it's connected to another phone, or it's running a very old firmware version.") + /// 1. Open the cover of your Ruuvi sensor + public static let openCoverTitle = RuuviLocalization.tr("Localizable", "DFUUIView.openCoverTitle", fallback: "1. Open the cover of your Ruuvi sensor") + /// Prepare your sensor + public static let prepareTitle = RuuviLocalization.tr("Localizable", "DFUUIView.prepareTitle", fallback: "Prepare your sensor") + /// Searching for a sensor + public static let searchingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.searchingTitle", fallback: "Searching for a sensor") + /// 3. Set the sensor to updating mode: + public static let setUpdatingModeTitle = RuuviLocalization.tr("Localizable", "DFUUIView.setUpdatingModeTitle", fallback: "3. Set the sensor to updating mode:") + /// Start the update + public static let startTitle = RuuviLocalization.tr("Localizable", "DFUUIView.startTitle", fallback: "Start the update") + /// Start update process + public static let startUpdateProcess = RuuviLocalization.tr("Localizable", "DFUUIView.startUpdateProcess", fallback: "Start update process") + /// Update successful + public static let successfulTitle = RuuviLocalization.tr("Localizable", "DFUUIView.successfulTitle", fallback: "Update successful") + /// 3.2. If your sensor has a single button: keep the button pressed for 10 seconds. + public static let toBootModeOneButtonDescription = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeOneButtonDescription", fallback: "3.2. If your sensor has a single button: keep the button pressed for 10 seconds.") + /// 4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”. + public static let toBootModeSuccessTitle = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeSuccessTitle", fallback: "4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”.") + /// 3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”. + public static let toBootModeTwoButtonsDescription = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeTwoButtonsDescription", fallback: "3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”.") + /// Updating... + public static let updatingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.updatingTitle", fallback: "Updating...") + public enum DBMigration { + public enum Error { + /// The update was successful, but an unexpected database migration error occurred. To continue using this sensor, please remove it from the app and then add it again. + public static let message = RuuviLocalization.tr("Localizable", "DFUUIView.DBMigration.Error.message", fallback: "The update was successful, but an unexpected database migration error occurred. To continue using this sensor, please remove it from the app and then add it again.") + } + } + public enum LowBattery { + public enum Warning { + /// Sensor's battery voltage seems to be low and the firmware update process may fail. We recommend to replace the battery before updating. + public static let message = RuuviLocalization.tr("Localizable", "DFUUIView.lowBattery.warning.message", fallback: "Sensor's battery voltage seems to be low and the firmware update process may fail. We recommend to replace the battery before updating.") + } + } + } + public enum Defaults { + public enum AlertsMuteInterval { + /// Alerts Mute Interval + public static let title = RuuviLocalization.tr("Localizable", "Defaults.AlertsMuteInterval.title", fallback: "Alerts Mute Interval") + } + public enum AlertsRepeatInterval { + /// Alerts Interval + public static let title = RuuviLocalization.tr("Localizable", "Defaults.AlertsRepeatInterval.title", fallback: "Alerts Interval") + } + public enum AppLaunchRequiredForReview { + public enum Count { + /// App launch count to ask for review for the first time + public static let title = RuuviLocalization.tr("Localizable", "Defaults.AppLaunchRequiredForReview.Count.title", fallback: "App launch count to ask for review for the first time") + } + } + public enum AskReviewIfLaunchDivisibleBy { + public enum Count { + /// Ask review if app launch divisible by + public static let title = RuuviLocalization.tr("Localizable", "Defaults.AskReviewIfLaunchDivisibleBy.Count.title", fallback: "Ask review if app launch divisible by") + } + } + public enum CardsSwipeHint { + /// Cards Swipe Hint Was Shown + public static let title = RuuviLocalization.tr("Localizable", "Defaults.CardsSwipeHint.title", fallback: "Cards Swipe Hint Was Shown") + } + public enum ChartDurationHours { + /// Chart Duration + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartDurationHours.title", fallback: "Chart Duration") + } + public enum ChartIntervalSeconds { + /// Chart Interval + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartIntervalSeconds.title", fallback: "Chart Interval") + } + public enum ChartsSwipeInstructionWasShown { + /// Charts Swipe Hint Was Shown + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartsSwipeInstructionWasShown.title", fallback: "Charts Swipe Hint Was Shown") + } + public enum ConnectionTimeout { + /// Connection Timeout + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ConnectionTimeout.title", fallback: "Connection Timeout") + } + public enum DashboardTapActionChart { + /// Show Chart on Dashboard Card Tap + public static let title = RuuviLocalization.tr("Localizable", "Defaults.DashboardTapActionChart.title", fallback: "Show Chart on Dashboard Card Tap") + } + public enum DevServer { + /// Changing Ruuvi Cloud endpoint requires signing out from current session and restart the app. Are you sure? + public static let message = RuuviLocalization.tr("Localizable", "Defaults.DevServer.message", fallback: "Changing Ruuvi Cloud endpoint requires signing out from current session and restart the app. Are you sure?") + /// Use Dev Server + public static let title = RuuviLocalization.tr("Localizable", "Defaults.DevServer.title", fallback: "Use Dev Server") + } + public enum HideNFC { + /// Hide NFC Option for sensor contest + public static let title = RuuviLocalization.tr("Localizable", "Defaults.HideNFC.title", fallback: "Hide NFC Option for sensor contest") + } + public enum Interval { + public enum Hour { + /// h + public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Hour.string", fallback: "h") + } + public enum Min { + /// min + public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Min.string", fallback: "min") + } + public enum Sec { + /// sec + public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Sec.string", fallback: "sec") + } + } + public enum PruningOffsetHours { + /// Pruning Offset Hours + public static let title = RuuviLocalization.tr("Localizable", "Defaults.PruningOffsetHours.title", fallback: "Pruning Offset Hours") + } + public enum ServiceTimeout { + /// Service Timeout + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ServiceTimeout.title", fallback: "Service Timeout") + } + public enum ShowEmailAlertsSettings { + /// Show email alerts settings + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ShowEmailAlertsSettings.title", fallback: "Show email alerts settings") + } + public enum ShowPushAlertsSettings { + /// Show push alerts settings + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ShowPushAlertsSettings.title", fallback: "Show push alerts settings") + } + public enum UserAuthorized { + /// User Authorized + public static let title = RuuviLocalization.tr("Localizable", "Defaults.UserAuthorized.title", fallback: "User Authorized") + } + public enum WebPullInterval { + /// Web Alerts Interval + public static let title = RuuviLocalization.tr("Localizable", "Defaults.WebPullInterval.title", fallback: "Web Alerts Interval") + } + public enum WelcomeShown { + /// Welcome Displayed + public static let title = RuuviLocalization.tr("Localizable", "Defaults.WelcomeShown.title", fallback: "Welcome Displayed") + } + public enum NavigationItem { + /// Defaults + public static let title = RuuviLocalization.tr("Localizable", "Defaults.navigationItem.title", fallback: "Defaults") + } + } + public enum Devices { + /// Token Id + public static let tokenId = RuuviLocalization.tr("Localizable", "Devices.tokenId", fallback: "Token Id") + } + public enum DfuDevicesScanner { + public enum BluetoothDisabled { + /// (Bluetooth is disabled) + public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabled.text", fallback: "(Bluetooth is disabled)") + } + public enum BluetoothDisabledAlert { + /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. + public static let message = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") + /// Bluetooth is not enabled + public static let title = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") + } + public enum Description { + /// Find and select sensor "RuuviBoot". + public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.Description.text", fallback: "Find and select sensor \"RuuviBoot\".") + } + public enum NoDevice { + /// (No sensors in Bluetooth range) + public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.NoDevice.text", fallback: "(No sensors in Bluetooth range)") + } + public enum Title { + /// Devices + public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.Title.text", fallback: "Devices") + } + } + public enum DfuFlash { + public enum Cancel { + /// CANCEL + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Cancel.text", fallback: "CANCEL") + } + public enum CancelAlert { + /// Are you sure you want to cancel the firmware update process? + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.CancelAlert.text", fallback: "Are you sure you want to cancel the firmware update process?") + } + public enum Finish { + /// FINISH + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Finish.text", fallback: "FINISH") + } + public enum FinishGuide { + /// Firmware update process has been completed successfully. + /// Your RuuviTag sensor is ready for use! + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.FinishGuide.text", fallback: "Firmware update process has been completed successfully.\nYour RuuviTag sensor is ready for use!") + } + public enum Firmware { + public enum BootloaderSize { + /// Bootloader size + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.BootloaderSize.text", fallback: "Bootloader size") + } + public enum FileName { + /// File name + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.FileName.text", fallback: "File name") + } + public enum Parts { + /// Parts + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.Parts.text", fallback: "Parts") + } + public enum Size { + /// Size + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.Size.text", fallback: "Size") + } + public enum SoftDeviceSize { + /// Soft Device size + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.SoftDeviceSize.text", fallback: "Soft Device size") + } + } + public enum FirmwareSelectionGuide { + /// Locate the previously downloaded ZIP file on your mobile device. + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.FirmwareSelectionGuide.text", fallback: "Locate the previously downloaded ZIP file on your mobile device.") + } + public enum OpenDocumentPicker { + /// OPEN DOCUMENT PICKER + public static let title = RuuviLocalization.tr("Localizable", "DfuFlash.OpenDocumentPicker.title", fallback: "OPEN DOCUMENT PICKER") + } + public enum Progress { + /// Progress + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Progress.text", fallback: "Progress") + } + public enum Start { + /// Start + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Start.text", fallback: "Start") + } + public enum Step { + /// Step + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Step.text", fallback: "Step") + } + public enum Steps { + public enum Completed { + /// Completed + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.Completed.text", fallback: "Completed") + } + public enum PackageSelection { + /// Package selection + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.PackageSelection.text", fallback: "Package selection") + } + public enum ReadyForUpload { + /// Ready For upload + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.ReadyForUpload.text", fallback: "Ready For upload") + } + public enum Uploading { + /// Uploading + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.Uploading.text", fallback: "Uploading") + } + } + public enum Title { + /// DFU Flash + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Title.text", fallback: "DFU Flash") + } + } + public enum DiscoverTable { + public enum BluetoothDisabledAlert { + /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. + public static let message = RuuviLocalization.tr("Localizable", "DiscoverTable.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") + /// Bluetooth is not enabled + public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") + } + public enum GetMoreSensors { + public enum Button { + /// Buy Ruuvi Sensors + public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.GetMoreSensors.button.title", fallback: "Buy Ruuvi Sensors") + } + } + public enum NavigationItem { + /// Add a New Sensor + public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.NavigationItem.title", fallback: "Add a New Sensor") + } + public enum NoDevicesSection { + public enum BluetoothDisabled { + /// (Bluetooth is disabled) + public static let text = RuuviLocalization.tr("Localizable", "DiscoverTable.NoDevicesSection.BluetoothDisabled.text", fallback: "(Bluetooth is disabled)") + } + public enum NotFound { + /// (No sensors in Bluetooth range) + public static let text = RuuviLocalization.tr("Localizable", "DiscoverTable.NoDevicesSection.NotFound.text", fallback: "(No sensors in Bluetooth range)") + } + } + public enum RuuviDevice { + /// Ruuvi + public static let `prefix` = RuuviLocalization.tr("Localizable", "DiscoverTable.RuuviDevice.prefix", fallback: "Ruuvi") + } + public enum SectionTitle { + /// Nearby Ruuvi sensors + public static let devices = RuuviLocalization.tr("Localizable", "DiscoverTable.SectionTitle.Devices", fallback: "Nearby Ruuvi sensors") + /// Virtual sensors + public static let webTags = RuuviLocalization.tr("Localizable", "DiscoverTable.SectionTitle.WebTags", fallback: "Virtual sensors") + } + public enum WebTagsInfoDialog { + /// Virtual Sensors show public weather data provided by local weather stations. + public static let message = RuuviLocalization.tr("Localizable", "DiscoverTable.WebTagsInfoDialog.message", fallback: "Virtual Sensors show public weather data provided by local weather stations.") + } + } + public enum ErrorPresenterAlert { + /// Error + public static let error = RuuviLocalization.tr("Localizable", "ErrorPresenterAlert.Error", fallback: "Error") + /// OK + public static let ok = RuuviLocalization.tr("Localizable", "ErrorPresenterAlert.OK", fallback: "OK") + } + public enum ExpectedError { + /// Unable to remove a connected device that is not reachable. Please check your Bluetooth connection. + public static let failedToDeleteTag = RuuviLocalization.tr("Localizable", "ExpectedError.failedToDeleteTag", fallback: "Unable to remove a connected device that is not reachable. Please check your Bluetooth connection.") + /// App is already in the process of syncing logs with this sensor + public static let isAlreadySyncingLogsWithThisTag = RuuviLocalization.tr("Localizable", "ExpectedError.isAlreadySyncingLogsWithThisTag", fallback: "App is already in the process of syncing logs with this sensor") + /// Missing OpenWeatherMap API Key. Please get one from openweathermap.org website and enter it in the station/Classes/Networking/Assembly/Networking.plist file + public static let missingOpenWeatherMapAPIKey = RuuviLocalization.tr("Localizable", "ExpectedError.missingOpenWeatherMapAPIKey", fallback: "Missing OpenWeatherMap API Key. Please get one from openweathermap.org website and enter it in the station/Classes/Networking/Assembly/Networking.plist file") + } + public enum ExportService { + /// Acceleration X + public static let accelerationX = RuuviLocalization.tr("Localizable", "ExportService.AccelerationX", fallback: "Acceleration X") + /// Acceleration Y + public static let accelerationY = RuuviLocalization.tr("Localizable", "ExportService.AccelerationY", fallback: "Acceleration Y") + /// Acceleration Z + public static let accelerationZ = RuuviLocalization.tr("Localizable", "ExportService.AccelerationZ", fallback: "Acceleration Z") + /// Date + public static let date = RuuviLocalization.tr("Localizable", "ExportService.Date", fallback: "Date") + /// Dew point (%@) + public static func dewPoint(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "ExportService.DewPoint", String(describing: p1), fallback: "Dew point (%@)") + } + /// Humidity (%@) + public static func humidity(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "ExportService.Humidity", String(describing: p1), fallback: "Humidity (%@)") + } + /// ISO8601 + public static let iso8601 = RuuviLocalization.tr("Localizable", "ExportService.ISO8601", fallback: "ISO8601") + /// Measurement Sequence Number + public static let measurementSequenceNumber = RuuviLocalization.tr("Localizable", "ExportService.MeasurementSequenceNumber", fallback: "Measurement Sequence Number") + /// Movement Counter + public static let movementCounter = RuuviLocalization.tr("Localizable", "ExportService.MovementCounter", fallback: "Movement Counter") + /// Pressure (%@) + public static func pressure(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "ExportService.Pressure", String(describing: p1), fallback: "Pressure (%@)") + } + /// Temperature (%@) + public static func temperature(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "ExportService.Temperature", String(describing: p1), fallback: "Temperature (%@)") + } + /// TX Power + public static let txPower = RuuviLocalization.tr("Localizable", "ExportService.TXPower", fallback: "TX Power") + /// Voltage (V) + public static let voltage = RuuviLocalization.tr("Localizable", "ExportService.Voltage", fallback: "Voltage (V)") + } + public enum Foreground { + public enum Interval { + public enum All { + /// All + public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.All.string", fallback: "All") + } + public enum Every { + /// Every + public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.Every.string", fallback: "Every") + } + public enum Min { + /// min + public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.Min.string", fallback: "min") + } + } + public enum NavigationItem { + /// Foreground + public static let title = RuuviLocalization.tr("Localizable", "Foreground.navigationItem.title", fallback: "Foreground") + } + } + public enum ForegroundRow { + public enum Advertisement { + /// ADVERTISEMENTS + public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.advertisement.section", fallback: "ADVERTISEMENTS") + /// Save advertisements + public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.advertisement.title", fallback: "Save advertisements") + } + public enum Connection { + /// LOGS + public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.connection.section", fallback: "LOGS") + /// Connect and sync logs + public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.connection.title", fallback: "Connect and sync logs") + } + public enum WebTags { + /// VIRTUAL SENSORS + public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.webTags.section", fallback: "VIRTUAL SENSORS") + /// Load and save from web + public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.webTags.title", fallback: "Load and save from web") + } + } + public enum Heartbeat { + public enum Interval { + public enum All { + /// All + public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.All.string", fallback: "All") + } + public enum Every { + /// every + public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Every.string", fallback: "every") + } + public enum Min { + /// min + public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Min.string", fallback: "min") + } + public enum Sec { + /// sec + public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Sec.string", fallback: "sec") + } + } + public enum ReadRSSITitle { + /// Read RSSI + public static let title = RuuviLocalization.tr("Localizable", "Heartbeat.readRSSITitle.title", fallback: "Read RSSI") + } + } + public enum HumidityCalibration { + public enum Button { + public enum Calibrate { + /// Calibrate + public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Calibrate.title", fallback: "Calibrate") + } + public enum Clear { + /// Clear + public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Clear.title", fallback: "Clear") + } + public enum Close { + /// Close + public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Close.title", fallback: "Close") + } + } + public enum CalibrationConfirmationAlert { + /// You are going to calibrate humidity offset. Tap "Confirm" to continue + public static let message = RuuviLocalization.tr("Localizable", "HumidityCalibration.CalibrationConfirmationAlert.message", fallback: "You are going to calibrate humidity offset. Tap \"Confirm\" to continue") + /// Are you sure? + public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.CalibrationConfirmationAlert.title", fallback: "Are you sure?") + } + public enum ClearCalibrationConfirmationAlert { + /// You are going to clear humidity offset. This can't be undone. Tap "Confirm" to continue. + public static let message = RuuviLocalization.tr("Localizable", "HumidityCalibration.ClearCalibrationConfirmationAlert.message", fallback: "You are going to clear humidity offset. This can't be undone. Tap \"Confirm\" to continue.") + /// Are you sure? + public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.ClearCalibrationConfirmationAlert.title", fallback: "Are you sure?") + } + public enum Description { + /// In order to measure relative humidity as accurately as possible, a sodium chloride (salt) calibration is recommended. See video tutorials on how to easily do this at home. + public static let text = RuuviLocalization.tr("Localizable", "HumidityCalibration.Description.text", fallback: "In order to measure relative humidity as accurately as possible, a sodium chloride (salt) calibration is recommended. See video tutorials on how to easily do this at home.") + } + public enum Label { + public enum Note { + /// Note that calibration data will be stored locally in your mobile device. After Ruuvi Station uninstall and install, you may need to recalibrate. + public static let text = RuuviLocalization.tr("Localizable", "HumidityCalibration.Label.note.text", fallback: "Note that calibration data will be stored locally in your mobile device. After Ruuvi Station uninstall and install, you may need to recalibrate.") + } + } + public enum VideoTutorials { + /// video tutorials + public static let link = RuuviLocalization.tr("Localizable", "HumidityCalibration.VideoTutorials.link", fallback: "video tutorials") + } + public enum LastCalibrationDate { + /// Calibrated: %@ + public static func format(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "HumidityCalibration.lastCalibrationDate.format", String(describing: p1), fallback: "Calibrated: %@") + } + } + } + public enum HumidityUnit { + public enum Dew { + /// Dew point (%@) + public static func title(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "HumidityUnit.Dew.title", String(describing: p1), fallback: "Dew point (%@)") + } + } + public enum Percent { + /// Relative (%) + public static let title = RuuviLocalization.tr("Localizable", "HumidityUnit.Percent.title", fallback: "Relative (%)") + } + public enum Gm3 { + /// Absolute (g/m³) + public static let title = RuuviLocalization.tr("Localizable", "HumidityUnit.gm3.title", fallback: "Absolute (g/m³)") + } + } + public enum Interval { + public enum Day { + /// Day + public static let string = RuuviLocalization.tr("Localizable", "Interval.Day.string", fallback: "Day") + } + public enum Days { + /// Days + public static let string = RuuviLocalization.tr("Localizable", "Interval.Days.string", fallback: "Days") + } + } + public enum Language { + /// English + public static let english = RuuviLocalization.tr("Localizable", "Language.English", fallback: "English") + /// Suomi + public static let finnish = RuuviLocalization.tr("Localizable", "Language.Finnish", fallback: "Suomi") + /// Français + public static let french = RuuviLocalization.tr("Localizable", "Language.French", fallback: "Français") + /// Deutsch + public static let german = RuuviLocalization.tr("Localizable", "Language.German", fallback: "Deutsch") + /// Русский + public static let russian = RuuviLocalization.tr("Localizable", "Language.Russian", fallback: "Русский") + /// Svenska + public static let swedish = RuuviLocalization.tr("Localizable", "Language.Swedish", fallback: "Svenska") + } + public enum LocalNotificationsManager { + public enum DidConnect { + /// Connected + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidConnect.title", fallback: "Connected") + } + public enum DidDisconnect { + /// Disconnected + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidDisconnect.title", fallback: "Disconnected") + } + public enum DidMove { + /// Movement detected! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidMove.title", fallback: "Movement detected!") + } + public enum Disable { + /// Turn off + public static let button = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.Disable.button", fallback: "Turn off") + } + public enum HighDewPoint { + /// Dew Point is too high! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighDewPoint.title", fallback: "Dew Point is too high!") + } + public enum HighHumidity { + /// Air Humidity is too high! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighHumidity.title", fallback: "Air Humidity is too high!") + } + public enum HighPressure { + /// Air Pressure is too high! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighPressure.title", fallback: "Air Pressure is too high!") + } + public enum HighSignal { + /// Signal strength is too high! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighSignal.title", fallback: "Signal strength is too high!") + } + public enum HighTemperature { + /// Temperature is too high! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighTemperature.title", fallback: "Temperature is too high!") + } + public enum LowDewPoint { + /// Dew Point is too low! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowDewPoint.title", fallback: "Dew Point is too low!") + } + public enum LowHumidity { + /// Air Humidity is too low! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowHumidity.title", fallback: "Air Humidity is too low!") + } + public enum LowPressure { + /// Air Pressure is too low! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowPressure.title", fallback: "Air Pressure is too low!") + } + public enum LowSignal { + /// Signal strength is too low! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowSignal.title", fallback: "Signal strength is too low!") + } + public enum LowTemperature { + /// Temperature is too low! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowTemperature.title", fallback: "Temperature is too low!") + } + public enum Mute { + /// Mute for an hour + public static let button = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.Mute.button", fallback: "Mute for an hour") + } + } + public enum Menu { + public enum BuyGateway { + public enum Url { + /// https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios + public static let ios = RuuviLocalization.tr("Localizable", "Menu.BuyGateway.URL.IOS", fallback: "https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") + } + } + public enum Label { + public enum AboutHelp { + /// About / Help + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AboutHelp.text", fallback: "About / Help") + } + public enum AddAnNewSensor { + /// Add a New Sensor + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AddAnNewSensor.text", fallback: "Add a New Sensor") + } + public enum AppSettings { + /// App Settings + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AppSettings.text", fallback: "App Settings") + } + public enum BuyRuuviGateway { + /// Buy Ruuvi Gateway + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.BuyRuuviGateway.text", fallback: "Buy Ruuvi Gateway") + } + public enum Feedback { + /// Send Feedback + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.Feedback.text", fallback: "Send Feedback") + } + public enum GetMoreSensors { + /// Buy Ruuvi Sensors + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.GetMoreSensors.text", fallback: "Buy Ruuvi Sensors") + } + public enum MyRuuviAccount { + /// My Ruuvi Account + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.MyRuuviAccount.text", fallback: "My Ruuvi Account") + } + public enum WhatToMeasure { + /// What to measure with Ruuvi? + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.WhatToMeasure.text", fallback: "What to measure with Ruuvi?") + } + } + public enum LoggedIn { + /// Signed in: + public static let title = RuuviLocalization.tr("Localizable", "Menu.LoggedIn.title", fallback: "Signed in:") + } + public enum Measure { + public enum Url { + /// https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios + public static let ios = RuuviLocalization.tr("Localizable", "Menu.Measure.URL.IOS", fallback: "https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") + } + } + public enum RuuviNetworkStatus { + /// Ruuvi Cloud status + public static let text = RuuviLocalization.tr("Localizable", "Menu.RuuviNetworkStatus.text", fallback: "Ruuvi Cloud status") + } + public enum SignOut { + /// Sign out + public static let text = RuuviLocalization.tr("Localizable", "Menu.SignOut.text", fallback: "Sign out") + } + } + public enum MenuTableViewController { + /// none + public static let `none` = RuuviLocalization.tr("Localizable", "MenuTableViewController.None", fallback: "none") + /// User: %@ + public static func user(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "MenuTableViewController.User", String(describing: p1), fallback: "User: %@") + } + } + public enum MyRuuvi { + public enum Settings { + public enum DeleteAccount { + /// Delete Account + public static let title = RuuviLocalization.tr("Localizable", "MyRuuvi.Settings.DeleteAccount.title", fallback: "Delete Account") + public enum Confirmation { + /// A confirmation has been sent to your email. To proceed with the deletion, please check your inbox and follow the instructions. + public static let message = RuuviLocalization.tr("Localizable", "MyRuuvi.Settings.DeleteAccount.Confirmation.message", fallback: "A confirmation has been sent to your email. To proceed with the deletion, please check your inbox and follow the instructions.") + } + } + } + } + public enum OWMError { + /// API limit exceeded + public static let apiLimitExceeded = RuuviLocalization.tr("Localizable", "OWMError.apiLimitExceeded", fallback: "API limit exceeded") + /// Failed to parse Open Weather Map response + public static let failedToParseOpenWeatherMapResponse = RuuviLocalization.tr("Localizable", "OWMError.failedToParseOpenWeatherMapResponse", fallback: "Failed to parse Open Weather Map response") + /// Invalid API Key + public static let invalidApiKey = RuuviLocalization.tr("Localizable", "OWMError.invalidApiKey", fallback: "Invalid API Key") + /// Not an HTTP response + public static let notAHttpResponse = RuuviLocalization.tr("Localizable", "OWMError.notAHttpResponse", fallback: "Not an HTTP response") + } + public enum OffsetCorrection { + public enum Calibrate { + /// Offset correction + public static let button = RuuviLocalization.tr("Localizable", "OffsetCorrection.Calibrate.button", fallback: "Offset correction") + } + public enum CalibrationDescription { + /// In normal use, it's not necessary to adjust the offset. + /// + /// If you're an advanced user and you'd like to manually configure the factory calibrated sensors, it's possible to do so. + /// + /// Calibration tips are available on ruuvi.com/support + public static let text = RuuviLocalization.tr("Localizable", "OffsetCorrection.CalibrationDescription.text", fallback: "In normal use, it's not necessary to adjust the offset.\n\nIf you're an advanced user and you'd like to manually configure the factory calibrated sensors, it's possible to do so.\n\nCalibration tips are available on ruuvi.com/support") + } + public enum CorrectedValue { + /// Corrected value + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.CorrectedValue.title", fallback: "Corrected value") + } + public enum Dialog { + public enum Calibration { + /// Clear calibration settings? + public static let clearConfirm = RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.ClearConfirm", fallback: "Clear calibration settings?") + /// Enter the expected humidity value from sensor under current conditions (%@): + public static func enterHumidity(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterHumidity", String(describing: p1), fallback: "Enter the expected humidity value from sensor under current conditions (%@): ") + } + /// Enter the expected pressure value from sensor under current conditions (%@): + public static func enterPressure(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterPressure", String(describing: p1), fallback: "Enter the expected pressure value from sensor under current conditions (%@): ") + } + /// Enter the expected temperature value from sensor under current conditions (%@): + public static func enterTemperature(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterTemperature", String(describing: p1), fallback: "Enter the expected temperature value from sensor under current conditions (%@): ") + } + /// Calibration setup + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.Title", fallback: "Calibration setup") + } + } + public enum Humidity { + /// Humidity offset + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Humidity.Title", fallback: "Humidity offset") + } + public enum OriginalValue { + /// Original measured value + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.OriginalValue.title", fallback: "Original measured value") + } + public enum Pressure { + /// Pressure offset + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Pressure.Title", fallback: "Pressure offset") + } + public enum Temperature { + /// Temperature offset + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Temperature.Title", fallback: "Temperature offset") + } + } + public enum Owner { + /// Claim sensor + public static let title = RuuviLocalization.tr("Localizable", "Owner.title", fallback: "Claim sensor") + public enum Claim { + /// Do you own this sensor? If yes, please claim ownership of the sensor and it'll be added to your Ruuvi account. Each Ruuvi sensor can have only one owner. To claim ownership, you need to be signed in. + /// + /// Benefits: + /// + /// ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud + /// + /// ● Access sensors remotely over the Internet (requires a Ruuvi Gateway) + /// + /// ● Share sensors with friends and family (requires a Ruuvi Gateway) + /// + /// ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway) + public static let description = RuuviLocalization.tr("Localizable", "Owner.Claim.description", fallback: "Do you own this sensor? If yes, please claim ownership of the sensor and it'll be added to your Ruuvi account. Each Ruuvi sensor can have only one owner. To claim ownership, you need to be signed in.\n\nBenefits:\n\n ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud\n\n ● Access sensors remotely over the Internet (requires a Ruuvi Gateway)\n\n ● Share sensors with friends and family (requires a Ruuvi Gateway)\n\n ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway)") + } + public enum ClaimOwnership { + /// Claim ownership + public static let button = RuuviLocalization.tr("Localizable", "Owner.ClaimOwnership.button", fallback: "Claim ownership") + } + } + public enum PermissionPresenter { + /// Settings + public static let settings = RuuviLocalization.tr("Localizable", "PermissionPresenter.settings", fallback: "Settings") + public enum NoCameraAccess { + /// Ruuvi Station needs to access your camera to enable this feature. + public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoCameraAccess.message", fallback: "Ruuvi Station needs to access your camera to enable this feature.") + } + public enum NoLocationAccess { + /// Ruuvi Station needs to access your location to enable this feature. + public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoLocationAccess.message", fallback: "Ruuvi Station needs to access your location to enable this feature.") + } + public enum NoPhotoLibraryAccess { + /// Ruuvi Station needs to access your camera library to enable this feature. + public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoPhotoLibraryAccess.message", fallback: "Ruuvi Station needs to access your camera library to enable this feature.") + } + public enum NoPushNotificationsPermission { + /// Ruuvi Station needs push notifications permission to enable this feature + public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoPushNotificationsPermission.message", fallback: "Ruuvi Station needs push notifications permission to enable this feature") + } + } + public enum PhotoPicker { + public enum Sheet { + /// Take photo + public static let camera = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.camera", fallback: "Take photo") + /// Choose from files + public static let files = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.files", fallback: "Choose from files") + /// Choose from the library + public static let library = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.library", fallback: "Choose from the library") + /// Pick a photo + public static let message = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.message", fallback: "Pick a photo") + } + } + public enum Ruuvi { + public enum BuySensors { + public enum Menu { + public enum Url { + /// https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios + public static let ios = RuuviLocalization.tr("Localizable", "Ruuvi.BuySensors.Menu.URL.IOS", fallback: "https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios") + } + } + public enum Url { + /// https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios + public static let ios = RuuviLocalization.tr("Localizable", "Ruuvi.BuySensors.URL.IOS", fallback: "https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") + } + } + } + public enum RuuviCloudApiError { + /// Empty response + public static let emptyResponse = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.emptyResponse", fallback: "Empty response") + /// Failed to get data from response + public static let failedToGetDataFromResponse = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.failedToGetDataFromResponse", fallback: "Failed to get data from response") + /// Unexpected HTTP status code + public static let unexpectedHTTPStatusCode = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.unexpectedHTTPStatusCode", fallback: "Unexpected HTTP status code") + } + public enum RuuviCloudError { + /// Not authorised + public static let notAuthorized = RuuviLocalization.tr("Localizable", "RuuviCloudError.NotAuthorized", fallback: "Not authorised") + } + public enum RuuviDfuError { + /// Failed to construct UUID + public static let failedToConstructUUID = RuuviLocalization.tr("Localizable", "RuuviDfuError.failedToConstructUUID", fallback: "Failed to construct UUID") + /// Invalid firmware file + public static let invalidFirmwareFile = RuuviLocalization.tr("Localizable", "RuuviDfuError.invalidFirmwareFile", fallback: "Invalid firmware file") + } + public enum RuuviLocalError { + /// Failed to get background directory + public static let failedToGetDocumentsDirectory = RuuviLocalization.tr("Localizable", "RuuviLocalError.failedToGetDocumentsDirectory", fallback: "Failed to get background directory") + /// Failed to get JPG representation + public static let failedToGetJpegRepresentation = RuuviLocalization.tr("Localizable", "RuuviLocalError.failedToGetJpegRepresentation", fallback: "Failed to get JPG representation") + } + public enum RuuviOnboard { + public enum Access { + /// Access data for each linked sensor in real time and explore history graphs. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Access.title", fallback: "Access data for each linked sensor in real time and explore history graphs.") + } + public enum Alerts { + /// Set alerts and get notified whenever your limits are hit. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Alerts.title", fallback: "Set alerts and get notified whenever your limits are hit.") + } + public enum Cloud { + /// Claim ownership of your sensors with a free Ruuvi Cloud account. + public static let subtitle = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.subtitle", fallback: "Claim ownership of your sensors with a free Ruuvi Cloud account.") + /// Sign in to use the full potential of the app. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.title", fallback: "Sign in to use the full potential of the app.") + public enum Benefits { + /// Benefits: + /// + /// ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud + /// + /// ● Access sensors remotely over the Internet (requires a Ruuvi Gateway) + /// + /// ● Share sensors with friends and family (requires a Ruuvi Gateway) + /// + /// ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway) + public static let message = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Benefits.message", fallback: "Benefits:\n\n ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud\n\n ● Access sensors remotely over the Internet (requires a Ruuvi Gateway)\n\n ● Share sensors with friends and family (requires a Ruuvi Gateway)\n\n ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway)") + } + public enum Details { + /// Details + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Details.title", fallback: "Details") + } + public enum Skip { + /// Are you sure you want to skip sign in? + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.title", fallback: "Are you sure you want to skip sign in?") + public enum GoBack { + /// Go back + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.GoBack.title", fallback: "Go back") + } + public enum Yes { + /// Yes, skip + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.Yes.title", fallback: "Yes, skip") + } + } + public enum Subtitle { + /// Great! You already signed in! + public static let signed = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.subtitle.signed", fallback: "Great! You already signed in!") + } + } + public enum Measure { + /// Measure environmental data: temperature, relative humidity and air pressure. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Measure.title", fallback: "Measure environmental data: temperature, relative humidity and air pressure.") + } + public enum Start { + /// Press SCAN to find and add nearby sensors to your Ruuvi Station. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Start.title", fallback: "Press SCAN to find and add nearby sensors to your Ruuvi Station.") + } + public enum Welcome { + /// Swipe to see what Ruuvi Station can do for you. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Welcome.title", fallback: "Swipe to see what Ruuvi Station can do for you.") + } + } + public enum RuuviPersistenceError { + /// Failed to find sensor + public static let failedToFindRuuviTag = RuuviLocalization.tr("Localizable", "RuuviPersistenceError.failedToFindRuuviTag", fallback: "Failed to find sensor") + } + public enum RuuviServiceError { + /// Both local and MAC identifiers are nil + public static let bothLuidAndMacAreNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.bothLuidAndMacAreNil", fallback: "Both local and MAC identifiers are nil") + /// Failed to find or generate background image + public static let failedToFindOrGenerateBackgroundImage = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToFindOrGenerateBackgroundImage", fallback: "Failed to find or generate background image") + /// Failed to get JPG representation + public static let failedToGetJpegRepresentation = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToGetJpegRepresentation", fallback: "Failed to get JPG representation") + /// Failed to parse response. + public static let failedToParseNetworkResponse = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToParseNetworkResponse", fallback: "Failed to parse response.") + /// MAC identifier is nil + public static let macIdIsNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.macIdIsNil", fallback: "MAC identifier is nil") + /// Photo URL is nil + public static let pictureUrlIsNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.pictureUrlIsNil", fallback: "Photo URL is nil") + } + public enum Settings { + public enum BackgroundScanning { + /// Data logging interval + public static let interval = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.interval", fallback: "Data logging interval") + /// Background Scanning + public static let title = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.title", fallback: "Background Scanning") + public enum Footer { + /// Important note: Bluetooth background history logging and Bluetooth alerts work only when background scanning is enabled. If you disable the background scanning, all paired Ruuvi sensors will be automatically unpaired and you need to pair them again from their settings pages. + public static let message = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.Footer.message", fallback: "Important note: Bluetooth background history logging and Bluetooth alerts work only when background scanning is enabled. If you disable the background scanning, all paired Ruuvi sensors will be automatically unpaired and you need to pair them again from their settings pages.") + } + } + public enum ChooseHumidityUnit { + /// Choose the humidity unit you want to be displayed. + public static let text = RuuviLocalization.tr("Localizable", "Settings.ChooseHumidityUnit.text", fallback: "Choose the humidity unit you want to be displayed.") + } + public enum ChoosePressureUnit { + /// Choose the pressure unit you want to be displayed. + public static let text = RuuviLocalization.tr("Localizable", "Settings.ChoosePressureUnit.text", fallback: "Choose the pressure unit you want to be displayed.") + } + public enum ChooseTemperatureUnit { + /// Choose the temperature unit you want to be displayed. + public static let text = RuuviLocalization.tr("Localizable", "Settings.ChooseTemperatureUnit.text", fallback: "Choose the temperature unit you want to be displayed.") + } + public enum Humidity { + public enum Resolution { + /// Humidity Resolution + public static let title = RuuviLocalization.tr("Localizable", "Settings.Humidity.Resolution.title", fallback: "Humidity Resolution") + } + } + public enum Label { + /// Chart Settings + public static let chart = RuuviLocalization.tr("Localizable", "Settings.Label.Chart", fallback: "Chart Settings") + /// Cloud mode + public static let cloudMode = RuuviLocalization.tr("Localizable", "Settings.Label.CloudMode", fallback: "Cloud mode") + /// Defaults + public static let defaults = RuuviLocalization.tr("Localizable", "Settings.Label.Defaults", fallback: "Defaults") + /// Foreground + public static let foreground = RuuviLocalization.tr("Localizable", "Settings.Label.Foreground", fallback: "Foreground") + /// Humidity + public static let humidity = RuuviLocalization.tr("Localizable", "Settings.Label.Humidity", fallback: "Humidity") + /// Pressure + public static let pressure = RuuviLocalization.tr("Localizable", "Settings.Label.Pressure", fallback: "Pressure") + /// Temperature + public static let temperature = RuuviLocalization.tr("Localizable", "Settings.Label.Temperature", fallback: "Temperature") + public enum CloudMode { + /// Refresh nearby cloud sensors only from the cloud by ignoring their Bluetooth messages and receiving alerts only by email. Requires a Ruuvi Gateway router. + public static let description = RuuviLocalization.tr("Localizable", "Settings.Label.CloudMode.description", fallback: "Refresh nearby cloud sensors only from the cloud by ignoring their Bluetooth messages and receiving alerts only by email. Requires a Ruuvi Gateway router.") + } + public enum HumidityUnit { + /// Humidity Unit + public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.HumidityUnit.text", fallback: "Humidity Unit") + } + public enum Language { + /// Language + public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.Language.text", fallback: "Language") + } + public enum PressureUnit { + /// Pressure Unit + public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.PressureUnit.text", fallback: "Pressure Unit") + } + public enum TemperatureUnit { + /// Temperature Unit + public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.TemperatureUnit.text", fallback: "Temperature Unit") + } + } + public enum Language { + public enum Dialog { + /// Open settings and tap Language to change language of the app. + /// If you cannot see the Language option in the settings, make sure that you have at least one preferred language added in system settings: Settings -> General -> Language & Region. + public static let message = RuuviLocalization.tr("Localizable", "Settings.Language.Dialog.message", fallback: "Open settings and tap Language to change language of the app.\nIf you cannot see the Language option in the settings, make sure that you have at least one preferred language added in system settings: Settings -> General -> Language & Region.") + /// Select Language + public static let title = RuuviLocalization.tr("Localizable", "Settings.Language.Dialog.title", fallback: "Select Language") + } + } + public enum Measurement { + public enum Resolution { + /// Select how accurately you'd like to see the sensors' live measurement values in the app. This setting doesn't affect history charts or alerts. + public static let description = RuuviLocalization.tr("Localizable", "Settings.Measurement.Resolution.description", fallback: "Select how accurately you'd like to see the sensors' live measurement values in the app. This setting doesn't affect history charts or alerts.") + /// Resolution + public static let title = RuuviLocalization.tr("Localizable", "Settings.Measurement.Resolution.title", fallback: "Resolution") + } + public enum Unit { + /// Unit + public static let title = RuuviLocalization.tr("Localizable", "Settings.Measurement.Unit.title", fallback: "Unit") + } + } + public enum Pressure { + public enum Resolution { + /// Pressure Resolution + public static let title = RuuviLocalization.tr("Localizable", "Settings.Pressure.Resolution.title", fallback: "Pressure Resolution") + } + } + public enum SectionHeader { + public enum Application { + /// APPLICATION + public static let title = RuuviLocalization.tr("Localizable", "Settings.SectionHeader.Application.title", fallback: "APPLICATION") + } + public enum General { + /// GENERAL + public static let title = RuuviLocalization.tr("Localizable", "Settings.SectionHeader.General.title", fallback: "GENERAL") + } + } + public enum SegmentedControl { + public enum Humidity { + public enum Absolute { + /// Abs + public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.Absolute.title", fallback: "Abs") + } + public enum DewPoint { + /// Dew + public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.DewPoint.title", fallback: "Dew") + } + public enum Relative { + /// Rel + public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.Relative.title", fallback: "Rel") + } + } + } + public enum Temperature { + public enum Resolution { + /// Temperature Resolution + public static let title = RuuviLocalization.tr("Localizable", "Settings.Temperature.Resolution.title", fallback: "Temperature Resolution") + } + } + public enum NavigationItem { + /// Settings + public static let title = RuuviLocalization.tr("Localizable", "Settings.navigationItem.title", fallback: "Settings") + } + } + public enum Share { + public enum Send { + /// Send + public static let button = RuuviLocalization.tr("Localizable", "Share.Send.button", fallback: "Send") + } + public enum Success { + /// Successfully shared sensor + public static let message = RuuviLocalization.tr("Localizable", "Share.Success.message", fallback: "Successfully shared sensor") + } + } + public enum SharePresenter { + public enum UnshareSensor { + /// Do you want to unshare sensor for %@? + public static func message(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "SharePresenter.UnshareSensor.Message", String(describing: p1), fallback: "Do you want to unshare sensor for %@?") + } + } + } + public enum ShareViewController { + /// You can share the sensor with friends and family if it's in range of a Ruuvi Gateway. + /// + /// Receiver will be notified by email. If the receiver doesn't have a Ruuvi account, a free Ruuvi account will automatically be created at first log in. + /// + /// Note that the sensor's custom name and background image will be shared. The name and image sync is one time only, and after this, they can be privately customised by the receiver. Offset values (if any) set by the owner, will be automatically synced, and the receiver will always see the final corrected values. + public static let description = RuuviLocalization.tr("Localizable", "ShareViewController.Description", fallback: "You can share the sensor with friends and family if it's in range of a Ruuvi Gateway.\n\nReceiver will be notified by email. If the receiver doesn't have a Ruuvi account, a free Ruuvi account will automatically be created at first log in.\n\nNote that the sensor's custom name and background image will be shared. The name and image sync is one time only, and after this, they can be privately customised by the receiver. Offset values (if any) set by the owner, will be automatically synced, and the receiver will always see the final corrected values.") + /// Share sensor + public static let title = RuuviLocalization.tr("Localizable", "ShareViewController.Title", fallback: "Share sensor") + public enum AddFriend { + /// Add friend + public static let title = RuuviLocalization.tr("Localizable", "ShareViewController.addFriend.Title", fallback: "Add friend") + } + public enum EmailTextField { + /// Type email + public static let placeholder = RuuviLocalization.tr("Localizable", "ShareViewController.emailTextField.placeholder", fallback: "Type email") + } + public enum SharedEmails { + /// You have used %d/%d of maximum shares of this sensor. The sensor has been shared to following users: + public static func title(_ p1: Int, _ p2: Int) -> String { + return RuuviLocalization.tr("Localizable", "ShareViewController.sharedEmails.Title", p1, p2, fallback: "You have used %d/%d of maximum shares of this sensor. The sensor has been shared to following users:") + } + } + } + public enum SignIn { + /// We've sent a one-time password to your email %@. Sign in by entering it here: + public static func checkMailbox(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "SignIn.CheckMailbox", String(describing: p1), fallback: "We've sent a one-time password to your email %@. Sign in by entering it here:") + } + /// Code + public static let codeHint = RuuviLocalization.tr("Localizable", "SignIn.CodeHint", fallback: "Code") + /// Email + public static let emailPlaceholder = RuuviLocalization.tr("Localizable", "SignIn.EmailPlaceholder", fallback: "Email") + /// Email sent + public static let emailSent = RuuviLocalization.tr("Localizable", "SignIn.EmailSent", fallback: "Email sent") + /// Please enter verification code + public static let enterVerificationCode = RuuviLocalization.tr("Localizable", "SignIn.EnterVerificationCode", fallback: "Please enter verification code") + /// Request a code + public static let requestCode = RuuviLocalization.tr("Localizable", "SignIn.RequestCode", fallback: "Request a code") + /// Submit + public static let submitCode = RuuviLocalization.tr("Localizable", "SignIn.SubmitCode", fallback: "Submit") + /// verification code in format: CJSM + public static let verificationCodePlaceholder = RuuviLocalization.tr("Localizable", "SignIn.VerificationCodePlaceholder", fallback: "verification code in format: CJSM") + public enum EmailMismatch { + public enum Alert { + /// Oops, you've requested the code for %@, but used the code for %@. Please double check that you are using the code for %@ + public static func message(_ p1: Any, _ p2: Any, _ p3: Any) -> String { + return RuuviLocalization.tr("Localizable", "SignIn.EmailMismatch.Alert.message", String(describing: p1), String(describing: p2), String(describing: p3), fallback: "Oops, you've requested the code for %@, but used the code for %@. Please double check that you are using the code for %@") + } + } + } + public enum EmailMissing { + public enum Alert { + /// Oops, the email you've used to get the code was not saved. Please try to sign in again. + public static let message = RuuviLocalization.tr("Localizable", "SignIn.EmailMissing.Alert.message", fallback: "Oops, the email you've used to get the code was not saved. Please try to sign in again.") + } + } + public enum SubtitleLabel { + /// To enjoy all the features, create a free account or sign in to your existing Ruuvi account by entering your email address. + public static let text = RuuviLocalization.tr("Localizable", "SignIn.SubtitleLabel.text", fallback: "To enjoy all the features, create a free account or sign in to your existing Ruuvi account by entering your email address.") + } + public enum Sync { + /// Downloading content from the cloud. Please wait. + public static let message = RuuviLocalization.tr("Localizable", "SignIn.Sync.message", fallback: "Downloading content from the cloud. Please wait.") + } + public enum Title { + /// Sign in + public static let text = RuuviLocalization.tr("Localizable", "SignIn.Title.text", fallback: "Sign in") + } + public enum TitleLabel { + /// Sign in to + /// Ruuvi + /// Station + public static let text = RuuviLocalization.tr("Localizable", "SignIn.TitleLabel.text", fallback: "Sign in to\nRuuvi\nStation") + } + } + public enum TagCharts { + public enum AbortSync { + public enum Alert { + /// Sometimes the history download is slow due to the Bluetooth connectivity. Please wait a moment. + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.AbortSync.Alert.message", fallback: "Sometimes the history download is slow due to the Bluetooth connectivity. Please wait a moment.") + } + public enum Button { + /// Abort download + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.AbortSync.Button.title", fallback: "Abort download") + } + } + public enum BluetoothDisabledAlert { + /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") + /// Bluetooth is not enabled + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") + } + public enum Clear { + /// Clear + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Clear.title", fallback: "Clear") + } + public enum DeleteHistoryConfirmationDialog { + /// Clear the local history data from the app? + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.message", fallback: "Clear the local history data from the app?") + /// Are you sure? + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.title", fallback: "Are you sure?") + public enum Button { + public enum Delete { + /// Delete + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.button.delete.title", fallback: "Delete") + } + } + } + public enum Dismiss { + public enum Alert { + /// The history download via Bluetooth connection is in progress. Please wait. + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.Dismiss.Alert.message", fallback: "The history download via Bluetooth connection is in progress. Please wait.") + } + } + public enum Export { + /// EXPORT + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Export.title", fallback: "EXPORT") + } + public enum FailedToSyncDialog { + /// Bluetooth history download failed. Check that you're within Bluetooth range, your sensor has firmware that supports downloading and that the sensor is not simultaneously connected to another iOS device. Sensor connection is reserved for Ruuvi Station when using connected mode in iOS. + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.FailedToSyncDialog.message", fallback: "Bluetooth history download failed. Check that you're within Bluetooth range, your sensor has firmware that supports downloading and that the sensor is not simultaneously connected to another iOS device. Sensor connection is reserved for Ruuvi Station when using connected mode in iOS.") + /// Download failed + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.FailedToSyncDialog.title", fallback: "Download failed") + } + public enum NoChartData { + /// No chart data available + public static let text = RuuviLocalization.tr("Localizable", "TagCharts.NoChartData.text", fallback: "No chart data available") + } + public enum Status { + /// Connecting... + public static let connecting = RuuviLocalization.tr("Localizable", "TagCharts.Status.Connecting", fallback: "Connecting...") + /// Disconnecting... + public static let disconnecting = RuuviLocalization.tr("Localizable", "TagCharts.Status.Disconnecting", fallback: "Disconnecting...") + /// Error + public static let error = RuuviLocalization.tr("Localizable", "TagCharts.Status.Error", fallback: "Error") + /// Reading history + public static let readingHistory = RuuviLocalization.tr("Localizable", "TagCharts.Status.ReadingHistory", fallback: "Reading history") + /// Synchronising... + public static let serving = RuuviLocalization.tr("Localizable", "TagCharts.Status.Serving", fallback: "Synchronising...") + /// Success + public static let success = RuuviLocalization.tr("Localizable", "TagCharts.Status.Success", fallback: "Success") + } + public enum Sync { + /// Sync + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Sync.title", fallback: "Sync") + } + public enum SyncConfirmationDialog { + /// Download history data from the sensor? + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.SyncConfirmationDialog.message", fallback: "Download history data from the sensor?") + /// Are you sure? + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.SyncConfirmationDialog.title", fallback: "Are you sure?") + } + public enum TryAgain { + /// Try again + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.TryAgain.title", fallback: "Try again") + } + } + public enum TagChartsPresenter { + /// Synchronised: %@ + public static func numberOfPointsSynchronizedOverNetwork(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "TagChartsPresenter.NumberOfPointsSynchronizedOverNetwork", String(describing: p1), fallback: "Synchronised: %@") + } + } + public enum TagSettings { + /// Share + public static let shareButton = RuuviLocalization.tr("Localizable", "TagSettings.ShareButton", fallback: "Share") + public enum AirHumidityAlert { + /// Air Humidity (%@) + public static func title(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "TagSettings.AirHumidityAlert.title", String(describing: p1), fallback: "Air Humidity (%@)") + } + } + public enum Alert { + public enum CustomDescription { + /// Set custom description... + public static let placeholder = RuuviLocalization.tr("Localizable", "TagSettings.Alert.CustomDescription.placeholder", fallback: "Set custom description...") + /// Alert custom description + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.CustomDescription.title", fallback: "Alert custom description") + } + public enum SetHumidity { + /// Set humidity alert + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetHumidity.title", fallback: "Set humidity alert") + } + public enum SetPressure { + /// Set pressure alert + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetPressure.title", fallback: "Set pressure alert") + } + public enum SetRSSI { + /// Set signal strength alert + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetRSSI.title", fallback: "Set signal strength alert") + } + public enum SetTemperature { + /// Set temperature alert + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetTemperature.title", fallback: "Set temperature alert") + } + } + public enum AlertSettings { + public enum Dialog { + /// Max (%0.f) + public static let max = RuuviLocalization.tr("Localizable", "TagSettings.AlertSettings.Dialog.Max", fallback: "Max (%0.f)") + /// Min (%0.f) + public static let min = RuuviLocalization.tr("Localizable", "TagSettings.AlertSettings.Dialog.Min", fallback: "Min (%0.f)") + } + } + public enum Alerts { + /// Off + public static let off = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Off", fallback: "Off") + public enum Connection { + /// Alert when connected/disconnected + public static let description = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Connection.description", fallback: "Alert when connected/disconnected") + } + public enum DewPoint { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + return RuuviLocalization.tr("Localizable", "TagSettings.Alerts.DewPoint.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } + } + public enum Humidity { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + return RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Humidity.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } + } + public enum Movement { + /// Alert when sensor is moved + public static let description = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Movement.description", fallback: "Alert when sensor is moved") + } + public enum Pressure { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + return RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Pressure.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } + } + public enum Temperature { + /// Alert when less than %0.f or more than %0.f + public static let description = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Temperature.description", fallback: "Alert when less than %0.f or more than %0.f") + } + } + public enum AlertsAreDisabled { + public enum Dialog { + public enum BothNotConnectedAndNoPNPermission { + /// Alerts are disabled because the device is not connected and missing push notification permission. Please connect to the device first. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.BothNotConnectedAndNoPNPermission.message", fallback: "Alerts are disabled because the device is not connected and missing push notification permission. Please connect to the device first.") + } + public enum Connect { + /// Connect + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.Connect.title", fallback: "Connect") + } + public enum NotConnected { + /// Alerts are disabled because you are not connected to the device. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.NotConnected.message", fallback: "Alerts are disabled because you are not connected to the device.") + } + } + } + public enum BatteryStatusLabel { + public enum Ok { + /// Battery OK + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.BatteryStatusLabel.Ok.message", fallback: "Battery OK") + } + public enum Replace { + /// Low battery + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.BatteryStatusLabel.Replace.message", fallback: "Low battery") + } + } + public enum ClaimTagButton { + /// Claim ownership + public static let claim = RuuviLocalization.tr("Localizable", "TagSettings.ClaimTagButton.Claim", fallback: "Claim ownership") + } + public enum ConnectStatus { + /// Disconnected + public static let disconnected = RuuviLocalization.tr("Localizable", "TagSettings.ConnectStatus.Disconnected", fallback: "Disconnected") + } + public enum ConnectionAlert { + /// Connection + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.ConnectionAlert.title", fallback: "Connection") + } + public enum DataSource { + public enum Advertisement { + /// Advertisement + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Advertisement.title", fallback: "Advertisement") + } + public enum Heartbeat { + /// Heartbeat + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Heartbeat.title", fallback: "Heartbeat") + } + public enum Network { + /// Cloud + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Network.title", fallback: "Cloud") + } + } + public enum EmptyValue { + /// - + public static let sign = RuuviLocalization.tr("Localizable", "TagSettings.EmptyValue.sign", fallback: "-") + } + public enum Firmware { + /// Current version + public static let currentVersion = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.CurrentVersion", fallback: "Current version") + /// Update + public static let updateFirmware = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.UpdateFirmware", fallback: "Update") + public enum CurrentVersion { + /// Very old + public static let veryOld = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.CurrentVersion.VeryOld", fallback: "Very old") + } + } + public enum General { + public enum Owner { + /// No owner + public static let `none` = RuuviLocalization.tr("Localizable", "TagSettings.General.Owner.none", fallback: "No owner") + } + } + public enum HumidityIsClipped { + public enum Alert { + /// Humidity value is greater than 100% after calibration. This value doesn't make sense, so the value has been adjusted to 100%. + public static func message(_ p1: Float) -> String { + return RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.message", p1, fallback: "Humidity value is greater than 100% after calibration. This value doesn't make sense, so the value has been adjusted to 100%.") + } + /// Humidity is adjusted + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.title", fallback: "Humidity is adjusted") + public enum Fix { + /// Fix + public static let button = RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.Fix.button", fallback: "Fix") + } + } + } + public enum Label { + public enum Alerts { + /// Alerts + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.alerts.text", fallback: "Alerts") + } + public enum Disabled { + /// DISABLED? + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.disabled.text", fallback: "DISABLED?") + } + public enum MoreInfo { + /// More info + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.moreInfo.text", fallback: "More info") + } + public enum NoValues { + /// NO VALUES? + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.noValues.text", fallback: "NO VALUES?") + } + } + public enum Mac { + public enum Alert { + /// MAC Address + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Mac.Alert.title", fallback: "MAC Address") + } + } + public enum MovementAlert { + /// Movement + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.MovementAlert.title", fallback: "Movement") + } + public enum NetworkInfo { + /// Owner + public static let owner = RuuviLocalization.tr("Localizable", "TagSettings.NetworkInfo.Owner", fallback: "Owner") + } + public enum NotShared { + /// Not shared + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.NotShared.title", fallback: "Not shared") + } + public enum OffsetCorrection { + /// Humidity + public static let humidity = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Humidity", fallback: "Humidity") + /// Pressure + public static let pressure = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Pressure", fallback: "Pressure") + /// Temperature + public static let temperature = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Temperature", fallback: "Temperature") + } + public enum PairAndBackgroundScan { + /// Alerts are not available over Bluetooth connection if background scanning is not enabled. Only one iOS device can be paired to a Ruuvi sensor at a time. + public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.description", fallback: "Alerts are not available over Bluetooth connection if background scanning is not enabled. Only one iOS device can be paired to a Ruuvi sensor at a time.") + public enum Paired { + /// Paired and background scan is on + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Paired.title", fallback: "Paired and background scan is on") + } + public enum Pairing { + /// Connecting to the sensor + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Pairing.title", fallback: "Connecting to the sensor") + } + public enum Unpaired { + /// Pair and use background scan + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Unpaired.title", fallback: "Pair and use background scan") + } + } + public enum PairError { + public enum CloudMode { + /// The sensor cannot be connected to via Bluetooth when the cloud mode is active. You can re-enable the Bluetooth connection for the cloud sensors by disabling cloud mode in the app settings. + public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairError.CloudMode.description", fallback: "The sensor cannot be connected to via Bluetooth when the cloud mode is active. You can re-enable the Bluetooth connection for the cloud sensors by disabling cloud mode in the app settings.") + } + public enum Timeout { + /// Connection timed out. Pairing was unsuccessful. Please try again. + public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairError.Timeout.description", fallback: "Connection timed out. Pairing was unsuccessful. Please try again.") + } + } + public enum PressureAlert { + /// Air Pressure (%@) + public static func title(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "TagSettings.PressureAlert.title", String(describing: p1), fallback: "Air Pressure (%@)") + } + } + public enum RemoveThisSensor { + /// Remove this sensor + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.RemoveThisSensor.title", fallback: "Remove this sensor") + } + public enum SectionHeader { + public enum BTConnection { + /// BLUETOOTH CONNECTION + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.BTConnection.title", fallback: "BLUETOOTH CONNECTION") + } + public enum Calibration { + /// CALIBRATION + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Calibration.title", fallback: "CALIBRATION") + } + public enum Firmware { + /// Firmware + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Firmware.title", fallback: "Firmware") + } + public enum General { + /// General + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.General.title", fallback: "General") + } + public enum Name { + /// NAME + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Name.title", fallback: "NAME") + } + public enum NetworkInfo { + /// NETWORK INFO + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.NetworkInfo.title", fallback: "NETWORK INFO") + } + public enum OffsetCorrection { + /// OFFSET CORRECTION + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.OffsetCorrection.Title", fallback: "OFFSET CORRECTION") + } + public enum Remove { + /// REMOVE + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Remove.title", fallback: "REMOVE") + } + } + public enum Share { + /// Share + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Share.title", fallback: "Share") + } + public enum Shared { + /// Shared + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Shared.title", fallback: "Shared") + } + public enum Uuid { + public enum Alert { + /// UUID + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UUID.Alert.title", fallback: "UUID") + } + } + public enum UpdateFirmware { + public enum Alert { + /// In order to see missing values: + /// If you are using the latest firmware, set RAWv2 mode by pressing "B" on a sensor. + /// Or update your sensor with the latest firmware. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.message", fallback: "In order to see missing values:\nIf you are using the latest firmware, set RAWv2 mode by pressing \"B\" on a sensor.\nOr update your sensor with the latest firmware.") + /// RAWv2 mode is required + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.title", fallback: "RAWv2 mode is required") + public enum Buttons { + public enum LearnMore { + /// Learn more + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.Buttons.LearnMore.title", fallback: "Learn more") + } + } + } + } + public enum AccelerationXTitleLabel { + /// Acceleration X + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationXTitleLabel.text", fallback: "Acceleration X") + } + public enum AccelerationYTitleLabel { + /// Acceleration Y + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationYTitleLabel.text", fallback: "Acceleration Y") + } + public enum AccelerationZTitleLabel { + /// Acceleration Z + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationZTitleLabel.text", fallback: "Acceleration Z") + } + public enum BackgroundImageLabel { + /// Background image + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.backgroundImageLabel.text", fallback: "Background image") + } + public enum BatteryVoltageTitleLabel { + /// Battery Voltage + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.batteryVoltageTitleLabel.text", fallback: "Battery Voltage") + } + public enum ConfirmSharedTagRemovalDialog { + /// If you remove the sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmSharedTagRemovalDialog.message", fallback: "If you remove the sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore.") + } + public enum ConfirmTagRemovalDialog { + /// Do you want to remove the sensor? You can add it again later, if needed. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagRemovalDialog.message", fallback: "Do you want to remove the sensor? You can add it again later, if needed.") + /// Remove sensor + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagRemovalDialog.title", fallback: "Remove sensor") + } + public enum ConfirmTagUnclaimAndRemoveDialog { + /// By removing the sensor, your sensor ownership status will be revoked. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagUnclaimAndRemoveDialog.message", fallback: "By removing the sensor, your sensor ownership status will be revoked. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner.") + } + public enum DataFormatTitleLabel { + /// Data Format + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dataFormatTitleLabel.text", fallback: "Data Format") + } + public enum DataSourceTitleLabel { + /// Data Received Via + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dataSourceTitleLabel.text", fallback: "Data Received Via") + } + public enum DewPointAlertTitleLabel { + /// Dew Point + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dewPointAlertTitleLabel.text", fallback: "Dew Point") + } + public enum HumidityTitleLabel { + /// Humidity + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.humidityTitleLabel.text", fallback: "Humidity") + } + public enum MacAddressTitleLabel { + /// MAC Address + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.macAddressTitleLabel.text", fallback: "MAC Address") + } + public enum McTitleLabel { + /// Movement Counter + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.mcTitleLabel.text", fallback: "Movement Counter") + } + public enum MsnTitleLabel { + /// Measurement Sequence Number + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.msnTitleLabel.text", fallback: "Measurement Sequence Number") + } + public enum NavigationItem { + /// Sensor Settings + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.navigationItem.title", fallback: "Sensor Settings") + } + public enum RssiTitleLabel { + /// Signal Strength (RSSI) + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.rssiTitleLabel.text", fallback: "Signal Strength (RSSI)") + } + public enum TagNameTitleLabel { + /// Name + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.tagNameTitleLabel.text", fallback: "Name") + public enum Rename { + /// Your sensors are displayed in alphabetical order. + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.tagNameTitleLabel.rename.text", fallback: "Your sensors are displayed in alphabetical order.") + } + } + public enum TemperatureAlertTitleLabel { + /// Temperature (%@) + public static func text(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "TagSettings.temperatureAlertTitleLabel.text", String(describing: p1), fallback: "Temperature (%@)") + } + } + public enum TxPowerTitleLabel { + /// Tx Power + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.txPowerTitleLabel.text", fallback: "Tx Power") + } + public enum UuidTitleLabel { + /// UUID + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.uuidTitleLabel.text", fallback: "UUID") + } + } + public enum TagsManagerPresenter { + public enum SignOutConfirmAlert { + /// When you sign out, sensors the ownerships of which you've claimed on the sensor Settings page will be automatically removed from the app. When you sign in again using the same email address, the sensors will be returned from the cloud. + /// + /// Do you want to sign out? + public static let message = RuuviLocalization.tr("Localizable", "TagsManagerPresenter.SignOutConfirmAlert.Message", fallback: "When you sign out, sensors the ownerships of which you've claimed on the sensor Settings page will be automatically removed from the app. When you sign in again using the same email address, the sensors will be returned from the cloud.\n\nDo you want to sign out?") + } + } + public enum TemperatureUnit { + public enum Celsius { + /// Celsius (℃) + public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Celsius.title", fallback: "Celsius (℃)") + } + public enum Fahrenheit { + /// Fahrenheit (℉) + public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Fahrenheit.title", fallback: "Fahrenheit (℉)") + } + public enum Kelvin { + /// Kelvin (K) + public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Kelvin.title", fallback: "Kelvin (K)") + } + } + public enum UnexpectedError { + /// Attempt to read data from Realm without LUID + public static let attemptToReadDataFromRealmWithoutLUID = RuuviLocalization.tr("Localizable", "UnexpectedError.attemptToReadDataFromRealmWithoutLUID", fallback: "Attempt to read data from Realm without LUID") + /// Both local and MAC identifiers are nil + public static let bothLuidAndMacAreNil = RuuviLocalization.tr("Localizable", "UnexpectedError.bothLuidAndMacAreNil", fallback: "Both local and MAC identifiers are nil") + /// Both callback result and error are nil + public static let callbackErrorAndResultAreNil = RuuviLocalization.tr("Localizable", "UnexpectedError.callbackErrorAndResultAreNil", fallback: "Both callback result and error are nil") + /// Caller was deallocated during operation + public static let callerDeinitedDuringOperation = RuuviLocalization.tr("Localizable", "UnexpectedError.callerDeinitedDuringOperation", fallback: "Caller was deallocated during operation") + /// Failed to find logs for the sensor + public static let failedToFindLogsForTheTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindLogsForTheTag", fallback: "Failed to find logs for the sensor") + /// Failed to find or generate background image + public static let failedToFindOrGenerateBackgroundImage = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindOrGenerateBackgroundImage", fallback: "Failed to find or generate background image") + /// Failed to find sensor + public static let failedToFindRuuviTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindRuuviTag", fallback: "Failed to find sensor") + /// Failed to find virtual sensor + public static let failedToFindVirtualTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindVirtualTag", fallback: "Failed to find virtual sensor") + /// Failed to reverse geocode location + public static let failedToReverseGeocodeCoordinate = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToReverseGeocodeCoordinate", fallback: "Failed to reverse geocode location") + /// View Model UUID is nil + public static let viewModelUUIDIsNil = RuuviLocalization.tr("Localizable", "UnexpectedError.viewModelUUIDIsNil", fallback: "View Model UUID is nil") + } + public enum UnitPressure { + public enum Hectopascal { + /// Hectopascal (hPa) + public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.hectopascal.title", fallback: "Hectopascal (hPa)") + } + public enum InchOfMercury { + /// Inch of mercury (inHg) + public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.inchOfMercury.title", fallback: "Inch of mercury (inHg)") + } + public enum MillimetreOfMercury { + /// Millimetre of mercury (mmHg) + public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.millimetreOfMercury.title", fallback: "Millimetre of mercury (mmHg)") + } + } + public enum UpdateFirmware { + public enum Download { + /// To start with the update process, first download the latest software package on the device you're going to use for updates. Latest version is available on ruuvi.com/software-update + public static let content = RuuviLocalization.tr("Localizable", "UpdateFirmware.Download.content", fallback: "To start with the update process, first download the latest software package on the device you're going to use for updates. Latest version is available on ruuvi.com/software-update") + /// DOWNLOAD LATEST FIRMWARE + public static let header = RuuviLocalization.tr("Localizable", "UpdateFirmware.Download.header", fallback: "DOWNLOAD LATEST FIRMWARE") + } + public enum NextButton { + /// NEXT + public static let title = RuuviLocalization.tr("Localizable", "UpdateFirmware.NextButton.title", fallback: "NEXT") + } + public enum SetDfu { + /// Open the RuuviTag's enclosure by pulling it open with your fingers or gently with a flat head screw driver. + /// + /// Set RuuviTag to bootloader mode by holding down button B and pressing reset button R. Red indicator LED light will light up and stay on. If your device has only 1 button, keep it pressed 10 seconds to enter the bootloader. + public static let content = RuuviLocalization.tr("Localizable", "UpdateFirmware.SetDfu.content", fallback: "Open the RuuviTag's enclosure by pulling it open with your fingers or gently with a flat head screw driver.\n\nSet RuuviTag to bootloader mode by holding down button B and pressing reset button R. Red indicator LED light will light up and stay on. If your device has only 1 button, keep it pressed 10 seconds to enter the bootloader.") + /// SET RUUVI TAG TO DFU MODE + public static let header = RuuviLocalization.tr("Localizable", "UpdateFirmware.SetDfu.header", fallback: "SET RUUVI TAG TO DFU MODE") + } + public enum Title { + /// Update Firmware + public static let text = RuuviLocalization.tr("Localizable", "UpdateFirmware.Title.text", fallback: "Update Firmware") + } + } + public enum UserApiError { + /// Maximum claim count for the user reached + public static let erClaimCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_CLAIM_COUNT_REACHED", fallback: "Maximum claim count for the user reached") + /// Data already exists, cannot update + public static let erConflict = RuuviLocalization.tr("Localizable", "UserApiError.ER_CONFLICT", fallback: "Data already exists, cannot update") + /// Forbidden + public static let erForbidden = RuuviLocalization.tr("Localizable", "UserApiError.ER_FORBIDDEN", fallback: "Forbidden") + /// Gateway already whitelisted + public static let erGatewayAlreadyWhitelisted = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_ALREADY_WHITELISTED", fallback: "Gateway already whitelisted") + /// Gateway not found + public static let erGatewayNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_NOT_FOUND", fallback: "Gateway not found") + /// Gateway status report failed + public static let erGatewayStatusReportFailed = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED", fallback: "Gateway status report failed") + /// Internal error + public static let erInternal = RuuviLocalization.tr("Localizable", "UserApiError.ER_INTERNAL", fallback: "Internal error") + /// Invalid density mode + public static let erInvalidDensityMode = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_DENSITY_MODE", fallback: "Invalid density mode") + /// Invalid email address + public static let erInvalidEmailAddress = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_EMAIL_ADDRESS", fallback: "Invalid email address") + /// Invalid ENUM value given + public static let erInvalidEnumValue = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_ENUM_VALUE", fallback: "Invalid ENUM value given") + /// Invalid request format + public static let erInvalidFormat = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_FORMAT", fallback: "Invalid request format") + /// Invalid MAC-address + public static let erInvalidMacAddress = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_MAC_ADDRESS", fallback: "Invalid MAC-address") + /// Invalid sort mode + public static let erInvalidSortMode = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_SORT_MODE", fallback: "Invalid sort mode") + /// Invalid time range + public static let erInvalidTimeRange = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_TIME_RANGE", fallback: "Invalid time range") + /// Missing argument + public static let erMissingArgument = RuuviLocalization.tr("Localizable", "UserApiError.ER_MISSING_ARGUMENT", fallback: "Missing argument") + /// In order to share a sensor, it must have data + public static let erNoDataToShare = RuuviLocalization.tr("Localizable", "UserApiError.ER_NO_DATA_TO_SHARE", fallback: "In order to share a sensor, it must have data") + /// Newer data already exists, cannot update + public static let erOldEntry = RuuviLocalization.tr("Localizable", "UserApiError.ER_OLD_ENTRY", fallback: "Newer data already exists, cannot update") + /// Sensor already claimed by %@ + public static func erSensorAlreadyClaimed(_ p1: Any) -> String { + return RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_CLAIMED", String(describing: p1), fallback: "Sensor already claimed by %@") + } + /// Sensor already claimed + public static let erSensorAlreadyClaimedNoEmail = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_CLAIMED_NO_EMAIL", fallback: "Sensor already claimed") + /// The sensor has already been registered + public static let erSensorAlreadyRegistered = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_REGISTERED", fallback: "The sensor has already been registered") + /// This sensor is already shared + public static let erSensorAlreadyShared = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_SHARED", fallback: "This sensor is already shared") + /// Sensor not found + public static let erSensorNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_NOT_FOUND", fallback: "Sensor not found") + /// Maximum share count for the sensor reached + public static let erSensorShareCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_SHARE_COUNT_REACHED", fallback: "Maximum share count for the sensor reached") + /// The share limit is reached + public static let erShareCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_SHARE_COUNT_REACHED", fallback: "The share limit is reached") + /// Data storage error + public static let erSubDataStorageError = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUB_DATA_STORAGE_ERROR", fallback: "Data storage error") + /// No user + public static let erSubNoUser = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUB_NO_USER", fallback: "No user") + /// Tried to add duplicate subscription to a code + public static let erSubscriptionCodeExists = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_CODE_EXISTS", fallback: "Tried to add duplicate subscription to a code") + /// Tried to claim already used code + public static let erSubscriptionCodeUsed = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_CODE_USED", fallback: "Tried to claim already used code") + /// Subscription is not found + public static let erSubscriptionNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_NOT_FOUND", fallback: "Subscription is not found") + /// Too many requests + public static let erThrottled = RuuviLocalization.tr("Localizable", "UserApiError.ER_THROTTLED", fallback: "Too many requests") + /// Token is expired + public static let erTokenExpired = RuuviLocalization.tr("Localizable", "UserApiError.ER_TOKEN_EXPIRED", fallback: "Token is expired") + /// Unable to send email + public static let erUnableToSendEmail = RuuviLocalization.tr("Localizable", "UserApiError.ER_UNABLE_TO_SEND_EMAIL", fallback: "Unable to send email") + /// Unauthorised + public static let erUnauthorized = RuuviLocalization.tr("Localizable", "UserApiError.ER_UNAUTHORIZED", fallback: "Unauthorised") + /// User not found + public static let erUserNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_USER_NOT_FOUND", fallback: "User not found") + /// Operation was successful + public static let ok = RuuviLocalization.tr("Localizable", "UserApiError.OK", fallback: "Operation was successful") + } + public enum WebTagLocationSource { + /// Your location + public static let current = RuuviLocalization.tr("Localizable", "WebTagLocationSource.current", fallback: "Your location") + /// Pick from the map + public static let manual = RuuviLocalization.tr("Localizable", "WebTagLocationSource.manual", fallback: "Pick from the map") + } + public enum WebTagSettings { + public enum AirHumidityAlert { + /// Air Humidity + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.AirHumidityAlert.title", fallback: "Air Humidity") + } + public enum Alerts { + /// Off + public static let off = RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Off", fallback: "Off") + public enum DewPoint { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + return RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.DewPoint.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } + } + public enum Humidity { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + return RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Humidity.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } + } + public enum Pressure { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + return RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Pressure.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } + } + public enum Temperature { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + return RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Temperature.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } + } + } + public enum AlertsAreDisabled { + public enum Dialog { + public enum BothNoPNPermissionAndNoLocationPermission { + /// In order to enable virtual sensor alerts please always grant location and notification permissions in Settings. + public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.AlertsAreDisabled.Dialog.BothNoPNPermissionAndNoLocationPermission.message", fallback: "In order to enable virtual sensor alerts please always grant location and notification permissions in Settings.") + } + public enum Settings { + /// Settings + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.AlertsAreDisabled.Dialog.Settings.title", fallback: "Settings") + } + } + } + public enum Button { + public enum Remove { + /// REMOVE THIS VIRTUAL SENSOR + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.Button.Remove.title", fallback: "REMOVE THIS VIRTUAL SENSOR") + } + } + public enum Label { + public enum BackgroundImage { + /// BACKGROUND + /// IMAGE + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.BackgroundImage.text", fallback: "BACKGROUND\nIMAGE") + } + public enum Location { + /// Location + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.Location.text", fallback: "Location") + } + public enum TagName { + /// Sensor Name + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.TagName.text", fallback: "Sensor Name") + } + public enum Alerts { + /// ALERTS + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.alerts.text", fallback: "ALERTS") + } + public enum Disabled { + /// DISABLED? + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.disabled.text", fallback: "DISABLED?") + } + } + public enum Location { + /// Your location + public static let current = RuuviLocalization.tr("Localizable", "WebTagSettings.Location.Current", fallback: "Your location") + } + public enum PressureAlert { + /// Air Pressure + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.PressureAlert.title", fallback: "Air Pressure") + } + public enum SectionHeader { + public enum MoreInfo { + /// MORE INFO + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.SectionHeader.MoreInfo.title", fallback: "MORE INFO") + } + public enum Name { + /// NAME + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.SectionHeader.Name.title", fallback: "NAME") + } + } + public enum ConfirmClearLocationDialog { + /// Are you sure you want to clear location for this virtual sensor? Current location will be used instead. + public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmClearLocationDialog.message", fallback: "Are you sure you want to clear location for this virtual sensor? Current location will be used instead.") + /// Clear Location + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmClearLocationDialog.title", fallback: "Clear Location") + } + public enum ConfirmTagRemovalDialog { + /// Are you sure you want to remove this virtual sensor? + public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmTagRemovalDialog.message", fallback: "Are you sure you want to remove this virtual sensor?") + /// Remove virtual sensor + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmTagRemovalDialog.title", fallback: "Remove virtual sensor") + } + public enum DewPointAlertTitleLabel { + /// Dew Point + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.dewPointAlertTitleLabel.text", fallback: "Dew Point") + } + public enum NavigationItem { + /// Virtual Sensor Settings + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.navigationItem.title", fallback: "Virtual Sensor Settings") + } + public enum TemperatureAlertTitleLabel { + /// Temperature + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.temperatureAlertTitleLabel.text", fallback: "Temperature") + } + } + public enum Welcome { + public enum Description { + /// To find nearby sensors and receive live sensor data, press 'scan'. + public static let text = RuuviLocalization.tr("Localizable", "Welcome.description.text", fallback: "To find nearby sensors and receive live sensor data, press 'scan'.") + } + public enum Scan { + /// SCAN + public static let title = RuuviLocalization.tr("Localizable", "Welcome.scan.title", fallback: "SCAN") + } + } + public enum Widgets { + public enum Description { + /// Create widgets of your favourite Ruuvi sensors. Widgets update from the Ruuvi Cloud. A Ruuvi Gateway router is required. + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Description.message", fallback: "Create widgets of your favourite Ruuvi sensors. Widgets update from the Ruuvi Cloud. A Ruuvi Gateway router is required.") + } + public enum Loading { + /// loading... + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Loading.message", fallback: "loading...") + } + public enum Select { + public enum Sensor { + /// Selected Ruuvi sensor + public static let title = RuuviLocalization.tr("Localizable", "Widgets.Select.Sensor.title", fallback: "Selected Ruuvi sensor") + } + } + public enum Sensor { + public enum `Type` { + /// Selected sensor type + public static let title = RuuviLocalization.tr("Localizable", "Widgets.Sensor.Type.title", fallback: "Selected sensor type") + } + } + public enum Unauthorized { + public enum Inline { + /// Sign in to Ruuvi Station + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unauthorized.Inline.message", fallback: "Sign in to Ruuvi Station") + } + public enum Regular { + /// Sign in to use the widget. + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unauthorized.Regular.message", fallback: "Sign in to use the widget.") + } + } + public enum Unconfigured { + public enum Circular { + /// +Add + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Circular.message", fallback: "+Add") + } + public enum Inline { + /// Add sensor to use Ruuvi Widget + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Inline.message", fallback: "Add sensor to use Ruuvi Widget") + } + public enum Rectangular { + /// Add sensor to use Ruuvi Widget + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Rectangular.message", fallback: "Add sensor to use Ruuvi Widget") + } + public enum Simple { + /// Force tap to edit the widget. + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Simple.message", fallback: "Force tap to edit the widget.") + } + } + } +} +// swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length +// swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces + +// MARK: - Implementation Details + +extension RuuviLocalization { + private static func tr(_ table: String, _ key: String, _ args: CVarArg..., fallback value: String) -> String { + let format = BundleToken.bundle.localizedString(forKey: key, value: value, table: table) + return String(format: format, locale: Locale.current, arguments: args) + } +} + +// swiftlint:disable convenience_type +private final class BundleToken { + static let bundle: Bundle = { + #if SWIFT_PACKAGE + return Bundle.module + #else + return Bundle(for: BundleToken.self) + #endif + }() +} +// swiftlint:enable convenience_type diff --git a/Templates/Localizable_de.strings.stencil b/Common/RuuviLocalization/Templates/Localizable_de.strings.stencil similarity index 100% rename from Templates/Localizable_de.strings.stencil rename to Common/RuuviLocalization/Templates/Localizable_de.strings.stencil diff --git a/templates/Localizable_en.strings.stencil b/Common/RuuviLocalization/Templates/Localizable_en.strings.stencil similarity index 100% rename from templates/Localizable_en.strings.stencil rename to Common/RuuviLocalization/Templates/Localizable_en.strings.stencil diff --git a/templates/Localizable_fi.strings.stencil b/Common/RuuviLocalization/Templates/Localizable_fi.strings.stencil similarity index 100% rename from templates/Localizable_fi.strings.stencil rename to Common/RuuviLocalization/Templates/Localizable_fi.strings.stencil diff --git a/templates/Localizable_fr.strings.stencil b/Common/RuuviLocalization/Templates/Localizable_fr.strings.stencil similarity index 100% rename from templates/Localizable_fr.strings.stencil rename to Common/RuuviLocalization/Templates/Localizable_fr.strings.stencil diff --git a/templates/Localizable_ru.strings.stencil b/Common/RuuviLocalization/Templates/Localizable_ru.strings.stencil similarity index 100% rename from templates/Localizable_ru.strings.stencil rename to Common/RuuviLocalization/Templates/Localizable_ru.strings.stencil diff --git a/templates/Localizable_sv.strings.stencil b/Common/RuuviLocalization/Templates/Localizable_sv.strings.stencil similarity index 100% rename from templates/Localizable_sv.strings.stencil rename to Common/RuuviLocalization/Templates/Localizable_sv.strings.stencil diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift index a858dbc3c..6d4f9a683 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift @@ -3,7 +3,7 @@ import UIKit import RuuviOntology import RuuviLocalization -protocol DiscoverViewInput: UIViewController, Localizable { +protocol DiscoverViewInput: UIViewController { var ruuviTags: [DiscoverRuuviTagViewModel] { get set } var isBluetoothEnabled: Bool { get set } var isCloseEnabled: Bool { get set } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift index 0c8018804..186907a46 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift @@ -177,7 +177,6 @@ extension DiscoverTableViewController { override func viewDidLoad() { super.viewDidLoad() - setupLocalization() configureViews() updateUI() output.viewDidLoad() diff --git a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloudApiError.swift b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloudApiError.swift index 3fbc6bd3c..a4931187a 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloudApiError.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloudApiError.swift @@ -5,13 +5,8 @@ public enum RuuviCloudApiError: Error { case networking(Error) case parsing(Error) case api(RuuviCloudApiErrorCode) - case claim(RuuviCloudApiClaimError) case emptyResponse case unexpectedHTTPStatusCode case failedToGetDataFromResponse case unauthorized } - -public struct RuuviCloudApiClaimError: Decodable { - public let error, code: String? -} diff --git a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloudApiErrorCode.swift b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloudApiErrorCode.swift index c6fead3a9..8d6a84311 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloudApiErrorCode.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloudApiErrorCode.swift @@ -22,7 +22,7 @@ public enum RuuviCloudApiErrorCode: String, Codable { // Gateway already whitelisted // swiftlint:disable:next inclusive_language case erGatewayAlreadyWhitelisted = "ER_GATEWAY_ALREADY_WHITELISTED" - // Gateway already whitelisted + // Gateway status report failed case erGatewayStatusReportFailed = "ER_GATEWAY_STATUS_REPORT_FAILED" // Data already exists, cannot update case erConflict = "ER_CONFLICT" diff --git a/Packages/RuuviDFU/Sources/RuuviDFU/RuuviDFUError.swift b/Packages/RuuviDFU/Sources/RuuviDFU/RuuviDFUError.swift index cc68b7fd9..dcb111ca0 100644 --- a/Packages/RuuviDFU/Sources/RuuviDFU/RuuviDFUError.swift +++ b/Packages/RuuviDFU/Sources/RuuviDFU/RuuviDFUError.swift @@ -1,8 +1,13 @@ import Foundation +import RuuviLocalization public struct RuuviDfuError: Error { - public static let invalidFirmwareFile = RuuviDfuError(description: "RuuviDfuError.invalidFirmwareFile") - public static let failedToConstructUUID = RuuviDfuError(description: "RuuviDfuError.failedToConstructUUID") + public static let invalidFirmwareFile = RuuviDfuError( + description: RuuviLocalization.RuuviDfuError.invalidFirmwareFile + ) + public static let failedToConstructUUID = RuuviDfuError( + description: RuuviLocalization.RuuviDfuError.failedToConstructUUID + ) public let description: String public init(description: String) { self.description = description diff --git a/project_frameworks.yml b/project_frameworks.yml index 4c3d7d50d..98ba56094 100644 --- a/project_frameworks.yml +++ b/project_frameworks.yml @@ -33,6 +33,7 @@ targetTemplates: sources: - path: Packages/${target_name} excludes: + - "*.stencil" - target.yml - Info.plist - .swiftpm @@ -42,6 +43,7 @@ targetTemplates: - README.md - "*.podspec" - Tests + - Templates settings: base: DEVELOPMENT_TEAM: *DEVELOPMENT_TEAM @@ -64,6 +66,7 @@ targetTemplates: sources: - path: Modules/${target_name} excludes: + - "*.stencil" - target.yml - Info.plist - .swiftpm @@ -73,6 +76,7 @@ targetTemplates: - README.md - "*.podspec" - Tests + - Templates settings: base: DEVELOPMENT_TEAM: *DEVELOPMENT_TEAM @@ -95,6 +99,7 @@ targetTemplates: sources: - path: Common/${target_name} excludes: + - "*.stencil" - target.yml - Info.plist - .swiftpm @@ -104,6 +109,7 @@ targetTemplates: - README.md - "*.podspec" - Tests + - Templates settings: base: DEVELOPMENT_TEAM: *DEVELOPMENT_TEAM diff --git a/station.localization b/station.localization index 45c2e8f00..3aabb0eb2 160000 --- a/station.localization +++ b/station.localization @@ -1 +1 @@ -Subproject commit 45c2e8f008e6d9c94a259b120f7ea190087aa94e +Subproject commit 3aabb0eb204558f83c98374e4f34b57d031cbbee diff --git a/station/Classes/Application/AppAssembly.swift b/station/Classes/Application/AppAssembly.swift index fee63d44f..495ef02f6 100644 --- a/station/Classes/Application/AppAssembly.swift +++ b/station/Classes/Application/AppAssembly.swift @@ -14,6 +14,7 @@ import RuuviReactor import RuuviCloud import RuuviUser import RuuviDaemon +import RuuviLocalization import RuuviNotifier import RuuviNotification import RuuviRepository @@ -750,8 +751,8 @@ private final class CoreAssembly: Assembly { let settings = r.resolve(RuuviLocalSettings.self)! let service = RuuviServiceMeasurementImpl( settings: settings, - emptyValueString: "N/A".localized(), - percentString: "%".localized() + emptyValueString: RuuviLocalization.na, + percentString: "%" ) return service }) diff --git a/station/Classes/Application/AppDelegate.swift b/station/Classes/Application/AppDelegate.swift index 4e8d6c67a..871230e57 100644 --- a/station/Classes/Application/AppDelegate.swift +++ b/station/Classes/Application/AppDelegate.swift @@ -12,6 +12,7 @@ import RuuviMigration import RuuviContext import RuuviService import RuuviOntology +import RuuviLocalization @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { @@ -52,8 +53,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { appStateService = r.resolve(AppStateService.self) appStateService.application(application, didFinishLaunchingWithOptions: launchOptions) localNotificationsManager = r.resolve(RuuviNotificationLocal.self) - let disableTitle = "LocalNotificationsManager.Disable.button".localized() - let muteTitle = "LocalNotificationsManager.Mute.button".localized() + let disableTitle = RuuviLocalization.LocalNotificationsManager.Disable.button + let muteTitle = RuuviLocalization.LocalNotificationsManager.Mute.button localNotificationsManager.setup( disableTitle: disableTitle, muteTitle: muteTitle, diff --git a/station/Classes/Presentation/Contract/ViewInput.swift b/station/Classes/Presentation/Contract/ViewInput.swift index 7f8492819..5e241e176 100644 --- a/station/Classes/Presentation/Contract/ViewInput.swift +++ b/station/Classes/Presentation/Contract/ViewInput.swift @@ -1,5 +1,4 @@ import Foundation -protocol ViewInput: Localizable { - +protocol ViewInput: AnyObject { } diff --git a/station/Classes/Presentation/Localization/Localizable.swift b/station/Classes/Presentation/Localization/Localizable.swift deleted file mode 100644 index 4e3ce583a..000000000 --- a/station/Classes/Presentation/Localization/Localizable.swift +++ /dev/null @@ -1,11 +0,0 @@ -import Foundation - -protocol Localizable: AnyObject { - func localize() -} - -extension Localizable { - func setupLocalization() { - LocalizationService.shared.add(localizable: self) - } -} diff --git a/station/Classes/Presentation/Localization/LocalizationService.swift b/station/Classes/Presentation/Localization/LocalizationService.swift deleted file mode 100644 index 92416b4f1..000000000 --- a/station/Classes/Presentation/Localization/LocalizationService.swift +++ /dev/null @@ -1,23 +0,0 @@ -import Foundation - -class LocalizationService { - static let shared = LocalizationService() - - init() {} - - private var listeners = NSHashTable.weakObjects() - - func add(localizable: Localizable, applyImmediately: Bool = true) { - guard !listeners.contains(localizable) else { return } - listeners.add(localizable) - if applyImmediately { - localizable.localize() - } - } - - @objc func apply() { - listeners.allObjects - .compactMap { $0 as? Localizable } - .forEach { $0.localize()} - } -} diff --git a/station/Classes/Presentation/Localization/LocalizedCache.swift b/station/Classes/Presentation/Localization/LocalizedCache.swift deleted file mode 100644 index 1f857729a..000000000 --- a/station/Classes/Presentation/Localization/LocalizedCache.swift +++ /dev/null @@ -1,7 +0,0 @@ -struct LocalizedCache { - let notAvailable = "N/A".localized() - let hPa = "hPa".localized() - let gm3 = "g/m³".localized() - let dBm = "dBm".localized() - let volts = "V".localized() -} diff --git a/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift b/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift index c55c82521..7179d2ae5 100644 --- a/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift +++ b/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift @@ -1,5 +1,6 @@ import Foundation import RuuviContext +import RuuviLocalization import RuuviStorage import UIKit @@ -45,8 +46,8 @@ extension AboutPresenter { let buildVersion = Bundle.main.infoDictionary?["CFBundleVersion"] as? String else { return nil } - let changelogString = "changelog".localized() - let versionText = "About.Version.text".localized() + " " + appVersion + "(" + buildVersion + ")" + let changelogString = RuuviLocalization.changelog + let versionText = RuuviLocalization.About.Version.text + " " + appVersion + "(" + buildVersion + ")" let text = versionText + " " + changelogString @@ -78,14 +79,14 @@ extension AboutPresenter { private func obtainTagsCount() { ruuviStorage.getStoredTagsCount().on(success: { [weak self] count in - let tagsCount = String(format: "About.TagsCount.text".localized(), count) + let tagsCount = RuuviLocalization.About.TagsCount.text(count) self?.viewModel.addedTags.value = tagsCount }) } private func obtainMeasurementsCount() { ruuviStorage.getStoredMeasurementsCount().on(success: { [weak self] count in - let measurementsCount = String(format: "About.MeasurementsCount.text".localized(), count) + let measurementsCount = RuuviLocalization.About.MeasurementsCount.text(count) self?.viewModel.storedMeasurements.value = measurementsCount }) } @@ -94,7 +95,7 @@ extension AboutPresenter { let realmSize = getRealmFileSize() let sqliteSize = getSQLiteFileSize() let dbSize = ByteCountFormatter().string(fromByteCount: realmSize + sqliteSize) - let dbSizeString = String(format: "About.DatabaseSize.text".localized(), dbSize) + let dbSizeString = RuuviLocalization.About.DatabaseSize.text(dbSize) viewModel.databaseSize.value = dbSizeString } diff --git a/station/Classes/Presentation/Modules/About/Router/AboutRouter.swift b/station/Classes/Presentation/Modules/About/Router/AboutRouter.swift index c1b0038e3..ca3fe2f40 100644 --- a/station/Classes/Presentation/Modules/About/Router/AboutRouter.swift +++ b/station/Classes/Presentation/Modules/About/Router/AboutRouter.swift @@ -1,5 +1,6 @@ import Foundation import LightRoute +import RuuviLocalization import UIKit class AboutRouter: AboutRouterInput { @@ -10,7 +11,7 @@ class AboutRouter: AboutRouterInput { } func openChangelogPage() { - guard let url = URL(string: "changelog_ios_url".localized()) else { + guard let url = URL(string: RuuviLocalization.changelogIosUrl) else { return } UIApplication.shared.open(url, options: [:], completionHandler: nil) diff --git a/station/Classes/Presentation/Modules/About/View/AboutViewController.swift b/station/Classes/Presentation/Modules/About/View/AboutViewController.swift index 255471a14..8c964b011 100644 --- a/station/Classes/Presentation/Modules/About/View/AboutViewController.swift +++ b/station/Classes/Presentation/Modules/About/View/AboutViewController.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit class AboutViewController: UIViewController { @@ -37,7 +38,6 @@ extension AboutViewController { extension AboutViewController { override func viewDidLoad() { super.viewDidLoad() - setupLocalization() configureViews() setUpChangelogTapGesture() output.viewDidLoad() @@ -81,7 +81,7 @@ extension AboutViewController: UITextViewDelegate { // MARK: - View configuration extension AboutViewController { private func configureViews() { - headerTitleLabel.text = "About.AboutHelp.header".localized() + headerTitleLabel.text = RuuviLocalization.About.AboutHelp.header configureTextView() bindViewModel() } @@ -104,17 +104,17 @@ extension AboutViewController { private func configureTextView() { let text = - "About.AboutHelp.contents".localized() + fourNewlines + - "About.OperationsManual.header".localized() + twoNewlines + - "About.OperationsManual.contents".localized() + fourNewlines + - "About.Troubleshooting.header".localized() + twoNewlines + - "About.Troubleshooting.contents".localized() + fourNewlines + - "About.OpenSource.header".localized() + twoNewlines + - "About.OpenSource.contents".localized() + fourNewlines + - "About.More.header".localized() + twoNewlines + - "About.More.contents".localized() + fourNewlines + - "About.Privacy.header".localized() + twoNewlines + - "About.Privacy.contents".localized() + "\n" + RuuviLocalization.About.AboutHelp.contents + fourNewlines + + RuuviLocalization.About.OperationsManual.header + twoNewlines + + RuuviLocalization.About.OperationsManual.contents + fourNewlines + + RuuviLocalization.About.Troubleshooting.header + twoNewlines + + RuuviLocalization.About.Troubleshooting.contents + fourNewlines + + RuuviLocalization.About.OpenSource.header + twoNewlines + + RuuviLocalization.About.OpenSource.contents + fourNewlines + + RuuviLocalization.About.More.header + twoNewlines + + RuuviLocalization.About.More.contents + fourNewlines + + RuuviLocalization.About.Privacy.header + twoNewlines + + RuuviLocalization.About.Privacy.contents + "\n" let attrString = NSMutableAttributedString(string: text) let range = NSString(string: attrString.string).range(of: attrString.string) @@ -123,11 +123,11 @@ extension AboutViewController { range: range) // make headers bold - let makeBold = ["About.OperationsManual.header".localized(), - "About.Troubleshooting.header".localized(), - "About.OpenSource.header".localized(), - "About.More.header".localized(), - "About.Privacy.header".localized()] + let makeBold = [RuuviLocalization.About.OperationsManual.header, + RuuviLocalization.About.Troubleshooting.header, + RuuviLocalization.About.OpenSource.header, + RuuviLocalization.About.More.header, + RuuviLocalization.About.Privacy.header] let boldFont = UIFont.Muli(.bold, size: 16) for bold in makeBold { let range = NSString(string: attrString.string).range(of: bold) diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift index 73062b9e6..ed7e849a0 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift @@ -1,4 +1,5 @@ import UIKit +import RuuviLocalization class BackgroundSelectionViewController: UIViewController { // View configure @@ -50,7 +51,6 @@ extension BackgroundSelectionViewController { override func viewDidLoad() { super.viewDidLoad() setUpUI() - setupLocalization() bindViewModel() output.viewDidLoad() } @@ -209,8 +209,7 @@ extension BackgroundSelectionViewController { uploadProgressView.progressLabel.bind(viewModel.uploadingBackgroundPercentage) { lb, percentage in if let percentage = percentage { - lb.text = String(format: "uploading_progress".localized(), - percentage * 100.0, "%") + lb.text = RuuviLocalization.uploadingProgress(Float(percentage) * 100) } } } @@ -218,7 +217,7 @@ extension BackgroundSelectionViewController { extension BackgroundSelectionViewController: BackgroundSelectionViewInput { func localize() { - self.title = "change_background".localized() + self.title = RuuviLocalization.changeBackground } func viewShouldDismiss() { diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift index f3b1f7fd4..996d6cf34 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift @@ -1,4 +1,5 @@ import UIKit +import RuuviLocalization enum SelectionMode { case camera @@ -19,17 +20,17 @@ class BackgroundSelectionViewHeader: UICollectionReusableView { label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Muli(.regular, size: 16) - label.text = "change_background_message".localized() + label.text = RuuviLocalization.changeBackgroundMessage return label }() lazy var seprator = UIView(color: RuuviColor.ruuviLineColor) lazy var takePhotoButton = BackgroundSelectionButtonView( - title: "take_photo".localized(), + title: RuuviLocalization.takePhoto, icon: "camera.fill", delegate: self) lazy var selectFromGalleryButton = BackgroundSelectionButtonView( - title: "select_from_gallery".localized(), + title: RuuviLocalization.selectFromGallery, icon: "photo", delegate: self) @@ -39,7 +40,7 @@ class BackgroundSelectionViewHeader: UICollectionReusableView { label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Muli(.bold, size: 16) - label.text = "select_default_image".localized() + label.text = RuuviLocalization.selectDefaultImage return label }() diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift index 4a66a21d0..5ce64fcaf 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift @@ -2,6 +2,7 @@ import UIKit import RuuviService import RuuviLocal +import RuuviLocalization import RuuviOntology class CardsLargeImageCell: UICollectionViewCell { @@ -226,13 +227,13 @@ extension CardsLargeImageCell { if let temp = measurementService?.stringWithoutSign(for: viewModel.temperature.value) { temperatureLabel.text = temp.components(separatedBy: String.nbsp).first } else { - temperatureLabel.text = "N/A".localized() + temperatureLabel.text = RuuviLocalization.na } if let temperatureUnit = measurementService?.units.temperatureUnit { temperatureUnitLabel.text = temperatureUnit.symbol } else { - temperatureUnitLabel.text = "N/A".localized() + temperatureUnitLabel.text = RuuviLocalization.na } // Humidity @@ -271,7 +272,7 @@ extension CardsLargeImageCell { hideMovementView(hide: false) movementView.setValue( with: "\(movement)", - unit: "Cards.Movements.title".localized() + unit: RuuviLocalization.Cards.Movements.title ) } else { hideMovementView(hide: true) @@ -282,7 +283,7 @@ extension CardsLargeImageCell { if let date = viewModel.date.value?.ruuviAgo() { updatedAtLabel.text = date } else { - updatedAtLabel.text = "Cards.UpdatedLabel.NoData.message".localized() + updatedAtLabel.text = RuuviLocalization.Cards.UpdatedLabel.NoData.message } startTimer(with: viewModel.date.value) @@ -332,7 +333,7 @@ extension CardsLargeImageCell { timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { [weak self] (_) in - self?.updatedAtLabel.text = date?.ruuviAgo() ?? "Cards.UpdatedLabel.NoData.message".localized() + self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message }) } @@ -361,12 +362,12 @@ extension CardsLargeImageCell { isSyncing = false case .syncing: isSyncing = true - syncStateLabel.text = "TagCharts.Status.Serving".localized() + syncStateLabel.text = RuuviLocalization.TagCharts.Status.serving case .complete: - syncStateLabel.text = "Synchronized".localized() + syncStateLabel.text = RuuviLocalization.synchronized hideSyncStatusLabel() case .onError: - syncStateLabel.text = "ErrorPresenterAlert.Error".localized() + syncStateLabel.text = RuuviLocalization.ErrorPresenterAlert.error hideSyncStatusLabel() } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift index 151b9435c..b4a5e7da9 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift @@ -4,6 +4,7 @@ import Humidity import RuuviOntology import RuuviLocal import RuuviService +import RuuviLocalization class CardsViewController: UIViewController { @@ -199,7 +200,6 @@ extension CardsViewController { super.viewDidLoad() setUpUI() configureGestureViews() - setupLocalization() output.viewDidLoad() } @@ -542,10 +542,10 @@ extension CardsViewController: CardsViewInput { } func showBluetoothDisabled(userDeclined: Bool) { - let title = "Cards.BluetoothDisabledAlert.title".localized() - let message = "Cards.BluetoothDisabledAlert.message".localized() + let title = RuuviLocalization.Cards.BluetoothDisabledAlert.title + let message = RuuviLocalization.Cards.BluetoothDisabledAlert.message let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "PermissionPresenter.settings".localized(), + alertVC.addAction(UIAlertAction(title: RuuviLocalization.PermissionPresenter.settings, style: .default, handler: { _ in guard let url = URL(string: userDeclined ? UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), @@ -554,7 +554,7 @@ extension CardsViewController: CardsViewInput { } UIApplication.shared.open(url) })) - alertVC.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) + alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) } @@ -576,13 +576,13 @@ extension CardsViewController: CardsViewInput { } func showKeepConnectionDialogChart(for viewModel: CardsViewModel) { - let message = "Cards.KeepConnectionDialog.message".localized() + let message = RuuviLocalization.Cards.KeepConnectionDialog.message let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) - let dismissTitle = "Cards.KeepConnectionDialog.Dismiss.title".localized() + let dismissTitle = RuuviLocalization.Cards.KeepConnectionDialog.Dismiss.title alert.addAction(UIAlertAction(title: dismissTitle, style: .cancel, handler: { [weak self] _ in self?.output.viewDidDismissKeepConnectionDialogChart(for: viewModel) })) - let keepTitle = "Cards.KeepConnectionDialog.KeepConnection.title".localized() + let keepTitle = RuuviLocalization.Cards.KeepConnectionDialog.KeepConnection.title alert.addAction(UIAlertAction(title: keepTitle, style: .default, handler: { [weak self] _ in self?.output.viewDidConfirmToKeepConnectionChart(to: viewModel) })) @@ -590,13 +590,13 @@ extension CardsViewController: CardsViewInput { } func showKeepConnectionDialogSettings(for viewModel: CardsViewModel) { - let message = "Cards.KeepConnectionDialog.message".localized() + let message = RuuviLocalization.Cards.KeepConnectionDialog.message let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) - let dismissTitle = "Cards.KeepConnectionDialog.Dismiss.title".localized() + let dismissTitle = RuuviLocalization.Cards.KeepConnectionDialog.Dismiss.title alert.addAction(UIAlertAction(title: dismissTitle, style: .cancel, handler: { [weak self] _ in self?.output.viewDidDismissKeepConnectionDialogSettings(for: viewModel) })) - let keepTitle = "Cards.KeepConnectionDialog.KeepConnection.title".localized() + let keepTitle = RuuviLocalization.Cards.KeepConnectionDialog.KeepConnection.title alert.addAction(UIAlertAction(title: keepTitle, style: .default, handler: { [weak self] _ in self?.output.viewDidConfirmToKeepConnectionSettings(to: viewModel) })) @@ -604,13 +604,13 @@ extension CardsViewController: CardsViewInput { } func showFirmwareUpdateDialog(for viewModel: CardsViewModel) { - let message = "Cards.LegacyFirmwareUpdateDialog.message".localized() + let message = RuuviLocalization.Cards.LegacyFirmwareUpdateDialog.message let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) - let dismissTitle = "Cards.KeepConnectionDialog.Dismiss.title".localized() + let dismissTitle = RuuviLocalization.Cards.KeepConnectionDialog.Dismiss.title alert.addAction(UIAlertAction(title: dismissTitle, style: .cancel, handler: { [weak self] _ in self?.output.viewDidIgnoreFirmwareUpdateDialog(for: viewModel) })) - let checkForUpdateTitle = "Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title".localized() + let checkForUpdateTitle = RuuviLocalization.Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title alert.addAction(UIAlertAction(title: checkForUpdateTitle, style: .default, handler: { [weak self] _ in self?.output.viewDidConfirmFirmwareUpdate(for: viewModel) })) @@ -618,13 +618,13 @@ extension CardsViewController: CardsViewInput { } func showFirmwareDismissConfirmationUpdateDialog(for viewModel: CardsViewModel) { - let message = "Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message".localized() + let message = RuuviLocalization.Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) - let dismissTitle = "Cards.KeepConnectionDialog.Dismiss.title".localized() + let dismissTitle = RuuviLocalization.Cards.KeepConnectionDialog.Dismiss.title alert.addAction(UIAlertAction(title: dismissTitle, style: .cancel, handler: { [weak self] _ in self?.output.viewDidDismissFirmwareUpdateDialog(for: viewModel) })) - let checkForUpdateTitle = "Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title".localized() + let checkForUpdateTitle = RuuviLocalization.Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title alert.addAction(UIAlertAction(title: checkForUpdateTitle, style: .default, handler: { [weak self] _ in self?.output.viewDidConfirmFirmwareUpdate(for: viewModel) })) @@ -632,17 +632,16 @@ extension CardsViewController: CardsViewInput { } func showReverseGeocodingFailed() { - let message = "Cards.Error.ReverseGeocodingFailed.message".localized() + let message = RuuviLocalization.Cards.Error.ReverseGeocodingFailed.message let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) + alert.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alert, animated: true) } func showAlreadyLoggedInAlert(with email: String) { - let message = String.localizedStringWithFormat("Cards.Alert.AlreadyLoggedIn.message".localized(), - email) + let message = RuuviLocalization.Cards.Alert.AlreadyLoggedIn.message(email) let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) + alert.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alert, animated: true) } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorOutput.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorOutput.swift index 89299bb21..b7c039373 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorOutput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorOutput.swift @@ -7,5 +7,4 @@ protocol TagChartsViewInteractorOutput: AnyObject { func interactorDidError(_ error: RUError) func createChartModules(from: [MeasurementType]) func interactorDidUpdate(sensor: AnyRuuviTagSensor) - func interactorDidSyncComplete(_ recordsCount: Int) } diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift index 6592c1f46..a78385146 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift @@ -1,4 +1,5 @@ // swiftlint:disable file_length +import RuuviLocalization import Foundation import BTKit import UIKit @@ -293,28 +294,6 @@ extension TagChartsViewPresenter: TagChartsViewInteractorOutput { ruuviTagData = interactor.ruuviTagData self.createChartData() } - - func interactorDidSyncComplete(_ recordsCount: Int) { - let okAction = UIAlertAction(title: "OK".localized(), - style: .default, - handler: nil) - let title, message: String - if recordsCount > 0 { - title = "TagCharts.Status.Success".localized() - message = String(format: "TagChartsPresenter.NumberOfPointsSynchronizedOverNetwork".localized(), - String(recordsCount)) - } else { - title = "TagChartsPresenter.NetworkSync".localized() - message = "TagChartsPresenter.NoNewMeasurementsFromNetwork".localized() - } - - let alertViewModel: AlertViewModel = AlertViewModel( - title: title, - message: message, - style: .alert, - actions: [okAction]) - alertPresenter.showAlert(alertViewModel) - } } // MARK: - RuuviNotifierObserver diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift index b4804bf72..829c82fc4 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit import Charts import RuuviLocal @@ -274,11 +275,11 @@ extension TagChartsView { type: MeasurementType ) { let roundedTo: Int = 2 - let minText = "chart_stat_min".localized() + ": " + + let minText = RuuviLocalization.chartStatMin + ": " + GlobalHelpers().formattedString(from: min.round(to: roundedTo)) - let maxText = "chart_stat_max".localized() + ": " + + let maxText = RuuviLocalization.chartStatMax + ": " + GlobalHelpers().formattedString(from: max.round(to: roundedTo)) - let avgText = "chart_stat_avg".localized() + ": " + + let avgText = RuuviLocalization.chartStatAvg + ": " + GlobalHelpers().formattedString(from: avg.round(to: roundedTo)) chartMinMaxAvgLabel.text = minText + " " + maxText + " " + avgText diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift index 49c2a5c6c..4c4b78a51 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift @@ -8,6 +8,7 @@ import RuuviLocal import BTKit import RuuviService import GestureInstructions +import RuuviLocalization // swiftlint:disable type_body_length class TagChartsViewController: UIViewController { @@ -18,7 +19,7 @@ class TagChartsViewController: UIViewController { var historyLengthInDay: Int = 1 { didSet { - historySelectionButton.updateTitle(with: "day_\(historyLengthInDay)".localized()) + historySelectionButton.updateTitle(with: historyLengthInDay.days) } } @@ -27,7 +28,7 @@ class TagChartsViewController: UIViewController { if historyLengthInHours >= 24 { historyLengthInDay = historyLengthInHours / 24 } else { - let unit = historyLengthInHours == 1 ? "hour".localized() : "hours".localized() + let unit = historyLengthInHours == 1 ? RuuviLocalization.hour : RuuviLocalization.hours historySelectionButton.updateTitle( with: "\(historyLengthInHours) " + unit.lowercased() ) @@ -47,7 +48,7 @@ class TagChartsViewController: UIViewController { historySelectionButton.updateMenu(with: historyLengthOptions()) if showChartAll { historySelectionButton.updateTitle( - with: "all".localized() + with: RuuviLocalization.all ) } } @@ -66,7 +67,7 @@ class TagChartsViewController: UIViewController { // Body lazy var noDataLabel: UILabel = { let label = UILabel() - label.text = "empty_chart_message".localized() + label.text = RuuviLocalization.emptyChartMessage label.textColor = .white label.textAlignment = .center label.numberOfLines = 0 @@ -78,7 +79,7 @@ class TagChartsViewController: UIViewController { private lazy var historySelectionButton: RuuviContextMenuButton = RuuviContextMenuButton(menu: historyLengthOptions(), titleColor: .white, - title: "1 day".localized(), + title: RuuviLocalization.day1, icon: RuuviAssets.dropDownArrowImage, iconTintColor: RuuviColor.logoTintColor, iconSize: .init(width: 14, height: 14), @@ -121,7 +122,6 @@ class TagChartsViewController: UIViewController { lazy var syncProgressView = UIView(color: .clear) lazy var syncStatusLabel: UILabel = { let label = UILabel() - label.text = "Reading history..." label.textColor = .white label.textAlignment = .left label.font = UIFont.Muli(.regular, size: 16) @@ -132,7 +132,7 @@ class TagChartsViewController: UIViewController { let button = RuuviContextMenuButton( menu: nil, titleColor: .white, - title: "TagCharts.Sync.title".localized(), + title: RuuviLocalization.TagCharts.Sync.title, icon: UIImage(named: "icon_sync_bt"), iconTintColor: .white, iconSize: .init(width: 22, height: 22), @@ -184,7 +184,6 @@ class TagChartsViewController: UIViewController { // MARK: - LIFECYCLE override func viewDidLoad() { super.viewDidLoad() - setupLocalization() setUpUI() output.viewDidLoad() } @@ -395,7 +394,7 @@ class TagChartsViewController: UIViewController { var actions: [UIAction] = [] // Add 'All' at the top - let all_action = UIAction(title: "all".localized()) { [weak self] _ in + let all_action = UIAction(title: RuuviLocalization.all) { [weak self] _ in self?.handleHistorySelectionAll() } all_action.state = showChartAll ? .on : .off @@ -403,7 +402,7 @@ class TagChartsViewController: UIViewController { for hour in historyHoursOptions { let action = UIAction( - title: "\(hour) \(hour == 1 ? "hour".localized() : "hours".localized())".lowercased() + title: "\(hour) \(hour == 1 ? RuuviLocalization.hour : RuuviLocalization.hours)".lowercased() ) { [weak self] _ in self?.handleHistoryLengthSelection(hours: hour) } @@ -416,7 +415,7 @@ class TagChartsViewController: UIViewController { } for day in minimumHistoryLimit...maximumHistoryLimit { - let action = UIAction(title: "day_\(day)".localized()) { + let action = UIAction(title: day.days) { [weak self] _ in self?.handleHistoryLengthSelection(hours: day*24) } @@ -429,7 +428,7 @@ class TagChartsViewController: UIViewController { } // Add more at the bottom - let more_action = UIAction(title: "more".localized()) { [weak self] _ in + let more_action = UIAction(title: RuuviLocalization.more) { [weak self] _ in self?.handleHistoryLengthSelection(hours: nil) } actions.append(more_action) @@ -441,10 +440,10 @@ class TagChartsViewController: UIViewController { fileprivate func handleHistoryLengthSelection(hours: Int?) { if let hours = hours { if hours >= 24 { - historySelectionButton.updateTitle(with: "day_\(hours/24)".localized()) + historySelectionButton.updateTitle(with: "\((hours/24).days)") historySelectionButton.updateMenu(with: historyLengthOptions()) } else { - let unit = hours == 1 ? "hour".localized() : "hours".localized() + let unit = hours == 1 ? RuuviLocalization.hour : RuuviLocalization.hours historySelectionButton.updateTitle( with: "\(hours) " + unit.lowercased() ) @@ -462,19 +461,19 @@ class TagChartsViewController: UIViewController { } fileprivate func moreButtonOptions(showChartStat: Bool = true) -> UIMenu { - let exportHistoryAction = UIAction(title: "export_history".localized()) { + let exportHistoryAction = UIAction(title: RuuviLocalization.exportHistory) { [weak self] _ in self?.output.viewDidTapOnExport() } - let clearViewHistory = UIAction(title: "clear_view".localized()) { + let clearViewHistory = UIAction(title: RuuviLocalization.clearView) { [weak self] _ in guard let sSelf = self else { return } sSelf.output.viewDidTriggerClear(for: sSelf.viewModel) } let minMaxAvgAction = UIAction( - title: !showChartStat ? "chart_stat_show".localized() : "chart_stat_hide".localized() + title: !showChartStat ? RuuviLocalization.chartStatShow : RuuviLocalization.chartStatHide ) { [weak self] _ in guard let sSelf = self else { return } @@ -572,21 +571,21 @@ extension TagChartsViewController: TagChartsViewInput { switch data.chartType { case .temperature: populateChartView(from: data.chartData, - title: "TagSettings.OffsetCorrection.Temperature".localized(), + title: RuuviLocalization.TagSettings.OffsetCorrection.temperature, type: data.chartType, unit: settings.temperatureUnit.symbol, settings: settings, view: temperatureChartView) case .humidity: populateChartView(from: data.chartData, - title: "TagSettings.OffsetCorrection.Humidity".localized(), + title: RuuviLocalization.TagSettings.OffsetCorrection.humidity, type: data.chartType, unit: settings.humidityUnit.symbol, settings: settings, view: humidityChartView) case .pressure: populateChartView(from: data.chartData, - title: "TagSettings.OffsetCorrection.Pressure".localized(), + title: RuuviLocalization.TagSettings.OffsetCorrection.pressure, type: data.chartType, unit: settings.pressureUnit.symbol, settings: settings, @@ -661,14 +660,14 @@ extension TagChartsViewController: TagChartsViewInput { } func localize() { - syncButton.updateTitle(with: "TagCharts.Sync.title".localized()) + syncButton.updateTitle(with: RuuviLocalization.TagCharts.Sync.title) } func showBluetoothDisabled(userDeclined: Bool) { - let title = "TagCharts.BluetoothDisabledAlert.title".localized() - let message = "TagCharts.BluetoothDisabledAlert.message".localized() + let title = RuuviLocalization.TagCharts.BluetoothDisabledAlert.title + let message = RuuviLocalization.TagCharts.BluetoothDisabledAlert.message let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "PermissionPresenter.settings".localized(), + alertVC.addAction(UIAlertAction(title: RuuviLocalization.PermissionPresenter.settings, style: .default, handler: { _ in guard let url = URL(string: userDeclined ? UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), @@ -677,16 +676,16 @@ extension TagChartsViewController: TagChartsViewInput { } UIApplication.shared.open(url) })) - alertVC.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) + alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) } func showClearConfirmationDialog(for viewModel: TagChartsViewModel) { - let title = "clear_local_history".localized() - let message = "clear_local_history_description".localized() + let title = RuuviLocalization.clearLocalHistory + let message = RuuviLocalization.clearLocalHistoryDescription let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil)) - let actionTitle = "TagCharts.Clear.title".localized() + alertVC.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) + let actionTitle = RuuviLocalization.TagCharts.Clear.title alertVC.addAction(UIAlertAction(title: actionTitle, style: .destructive, handler: { [weak self] _ in self?.output.viewDidConfirmToClear(for: viewModel) @@ -699,18 +698,18 @@ extension TagChartsViewController: TagChartsViewInput { showSyncStatusLabel(show: true) switch progress { case .connecting: - syncStatusLabel.text = "TagCharts.Status.Connecting".localized() + syncStatusLabel.text = RuuviLocalization.TagCharts.Status.connecting case .serving: - syncStatusLabel.text = "TagCharts.Status.Serving".localized() + syncStatusLabel.text = RuuviLocalization.TagCharts.Status.serving case .reading(let points): - let format = "reading_history_x".localized() + let format = RuuviLocalization.readingHistoryX syncStatusLabel.text = String(format: format, Float(points)) case .disconnecting: - syncStatusLabel.text = "TagCharts.Status.Disconnecting".localized() + syncStatusLabel.text = RuuviLocalization.TagCharts.Status.disconnecting case .success: - syncStatusLabel.text = "TagCharts.Status.Success".localized() + syncStatusLabel.text = RuuviLocalization.TagCharts.Status.success case .failure: - syncStatusLabel.text = "TagCharts.Status.Error".localized() + syncStatusLabel.text = RuuviLocalization.TagCharts.Status.error } } else { showSyncStatusLabel(show: false) @@ -722,11 +721,11 @@ extension TagChartsViewController: TagChartsViewInput { } func showFailedToSyncIn() { - let title = "TagCharts.FailedToSyncDialog.title".localized() - let message = "TagCharts.FailedToSyncDialog.message".localized() + let title = RuuviLocalization.TagCharts.FailedToSyncDialog.title + let message = RuuviLocalization.TagCharts.FailedToSyncDialog.message let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) - alertVC.addAction(UIAlertAction(title: "TagCharts.TryAgain.title".localized(), + alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) + alertVC.addAction(UIAlertAction(title: RuuviLocalization.TagCharts.TryAgain.title, style: .default, handler: { [weak self] _ in guard let self = self else { return } @@ -740,11 +739,11 @@ extension TagChartsViewController: TagChartsViewInput { } func showSyncConfirmationDialog(for viewModel: TagChartsViewModel) { - let title = "synchronisation".localized() - let message = "gatt_sync_description".localized() + let title = RuuviLocalization.synchronisation + let message = RuuviLocalization.gattSyncDescription let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "Close".localized(), style: .cancel, handler: nil)) - let actionTitle = "do_not_show_again".localized() + alertVC.addAction(UIAlertAction(title: RuuviLocalization.close, style: .cancel, handler: nil)) + let actionTitle = RuuviLocalization.doNotShowAgain alertVC.addAction(UIAlertAction(title: actionTitle, style: .default, handler: { [weak self] _ in @@ -755,12 +754,12 @@ extension TagChartsViewController: TagChartsViewInput { } func showSyncAbortAlert(dismiss: Bool) { - let title = "TagCharts.DeleteHistoryConfirmationDialog.title".localized() - let message = dismiss ? "TagCharts.Dismiss.Alert.message".localized() : - "TagCharts.AbortSync.Alert.message".localized() + let title = RuuviLocalization.TagCharts.DeleteHistoryConfirmationDialog.title + let message = dismiss ? RuuviLocalization.TagCharts.Dismiss.Alert.message : + RuuviLocalization.TagCharts.AbortSync.Alert.message let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) - let actionTitle = "TagCharts.AbortSync.Button.title".localized() + alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) + let actionTitle = RuuviLocalization.TagCharts.AbortSync.Button.title alertVC.addAction(UIAlertAction(title: actionTitle, style: .destructive, handler: { [weak self] _ in self?.output.viewDidConfirmAbortSync(dismiss: dismiss) })) @@ -768,11 +767,11 @@ extension TagChartsViewController: TagChartsViewInput { } func showSyncAbortAlertForSwipe() { - let title = "TagCharts.DeleteHistoryConfirmationDialog.title".localized() - let message = "TagCharts.Dismiss.Alert.message".localized() + let title = RuuviLocalization.TagCharts.DeleteHistoryConfirmationDialog.title + let message = RuuviLocalization.TagCharts.Dismiss.Alert.message let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) - let actionTitle = "TagCharts.AbortSync.Button.title".localized() + alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) + let actionTitle = RuuviLocalization.TagCharts.AbortSync.Button.title alertVC.addAction(UIAlertAction(title: actionTitle, style: .destructive, handler: { [weak self] _ in self?.output.viewDidConfirmAbortSync(dismiss: false) })) @@ -798,12 +797,12 @@ extension TagChartsViewController: TagChartsViewInput { } func showLongerHistoryDialog() { - let title = "longer_history_title".localized() - let message = "longer_history_message".localized() + let title = RuuviLocalization.longerHistoryTitle + let message = RuuviLocalization.longerHistoryMessage let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: "OK".localized(), + controller.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(controller, animated: true) @@ -991,7 +990,7 @@ extension TagChartsViewController { timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { [weak self] (_) in - self?.updatedAtLabel.text = date?.ruuviAgo() ?? "Cards.UpdatedLabel.NoData.message".localized() + self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message }) } @@ -1094,4 +1093,33 @@ extension TagChartsViewController { extension TagChartsViewController: RuuviServiceMeasurementDelegate { func measurementServiceDidUpdateUnit() {} } + +private extension Int { + var days: String { + switch self { + case 1: + return RuuviLocalization.day1 + case 2: + return RuuviLocalization.day2 + case 3: + return RuuviLocalization.day3 + case 4: + return RuuviLocalization.day4 + case 5: + return RuuviLocalization.day5 + case 6: + return RuuviLocalization.day6 + case 7: + return RuuviLocalization.day7 + case 8: + return RuuviLocalization.day8 + case 9: + return RuuviLocalization.day9 + case 10: + return RuuviLocalization.day10 + default: + return String(format: RuuviLocalization.dayX, self) + } + } +} // swiftlint:enable type_body_length diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift index 1eb974e2a..838065c0e 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift @@ -3,6 +3,7 @@ import Foundation import UIKit import RuuviOntology import RuuviLocal +import RuuviLocalization class DashboardRouter: NSObject, DashboardRouterInput { weak var transitionHandler: UIViewController! @@ -56,21 +57,21 @@ class DashboardRouter: NSObject, DashboardRouterInput { } func openWhatToMeasurePage() { - guard let url = URL(string: "Menu.Measure.URL.IOS".localized()) else { + guard let url = URL(string: RuuviLocalization.Menu.Measure.Url.ios) else { return } UIApplication.shared.open(url, options: [:], completionHandler: nil) } func openRuuviProductsPage() { - guard let url = URL(string: "Ruuvi.BuySensors.URL.IOS".localized()) else { + guard let url = URL(string: RuuviLocalization.Ruuvi.BuySensors.Url.ios) else { return } UIApplication.shared.open(url, options: [:], completionHandler: nil) } func openRuuviProductsPageFromMenu() { - guard let url = URL(string: "Ruuvi.BuySensors.Menu.URL.IOS".localized()) else { + guard let url = URL(string: RuuviLocalization.Ruuvi.BuySensors.Menu.Url.ios) else { return } UIApplication.shared.open(url, options: [:], completionHandler: nil) diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift index 8f766435a..751313f8c 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift @@ -2,6 +2,7 @@ import UIKit import RuuviService import RuuviLocal +import RuuviLocalization import RuuviOntology class DashboardImageCell: UICollectionViewCell { @@ -320,13 +321,13 @@ extension DashboardImageCell { if let temp = measurementService?.stringWithoutSign(for: viewModel.temperature.value) { temperatureLabel.text = temp.components(separatedBy: String.nbsp).first } else { - temperatureLabel.text = "N/A".localized() + temperatureLabel.text = RuuviLocalization.na } if let temperatureUnit = measurementService?.units.temperatureUnit { temperatureUnitLabel.text = temperatureUnit.symbol } else { - temperatureUnitLabel.text = "N/A".localized() + temperatureUnitLabel.text = RuuviLocalization.na } // Humidity @@ -364,7 +365,7 @@ extension DashboardImageCell { if let movement = viewModel.movementCounter.value { hideMovementView(hide: false) movementView.setValue(with: "\(movement)", - unit: "Cards.Movements.title".localized()) + unit: RuuviLocalization.Cards.Movements.title) } else { hideMovementView(hide: true) } @@ -374,7 +375,7 @@ extension DashboardImageCell { if let date = viewModel.date.value?.ruuviAgo() { updatedAtLabel.text = date } else { - updatedAtLabel.text = "Cards.UpdatedLabel.NoData.message".localized() + updatedAtLabel.text = RuuviLocalization.Cards.UpdatedLabel.NoData.message } startTimer(with: viewModel.date.value) @@ -529,7 +530,7 @@ extension DashboardImageCell { if let date = date?.ruuviAgo() { self?.updatedAtLabel.text = date } else { - self?.updatedAtLabel.text = date?.ruuviAgo() ?? "Cards.UpdatedLabel.NoData.message".localized() + self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message } }) } diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift index ea899d16a..47e93eac6 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift @@ -2,6 +2,7 @@ import UIKit import RuuviService import RuuviLocal +import RuuviLocalization import RuuviOntology class DashboardPlainCell: UICollectionViewCell { @@ -283,7 +284,7 @@ extension DashboardPlainCell { let temperatureUnit = measurementService?.units.temperatureUnit { temperatureView.setValue(with: temp, unit: temperatureUnit.symbol) } else { - temperatureView.setValue(with: "N/A".localized()) + temperatureView.setValue(with: RuuviLocalization.na) } // Humidity @@ -321,7 +322,7 @@ extension DashboardPlainCell { if let movement = viewModel.movementCounter.value { hideMovementView(hide: false) movementView.setValue(with: "\(movement)", - unit: "Cards.Movements.title".localized()) + unit: RuuviLocalization.Cards.Movements.title) } else { hideMovementView(hide: true) } @@ -331,7 +332,7 @@ extension DashboardPlainCell { if let date = viewModel.date.value?.ruuviAgo() { updatedAtLabel.text = date } else { - updatedAtLabel.text = "Cards.UpdatedLabel.NoData.message".localized() + updatedAtLabel.text = RuuviLocalization.Cards.UpdatedLabel.NoData.message } startTimer(with: viewModel.date.value) @@ -489,7 +490,7 @@ extension DashboardPlainCell { if let date = date?.ruuviAgo() { self?.updatedAtLabel.text = date } else { - self?.updatedAtLabel.text = date?.ruuviAgo() ?? "Cards.UpdatedLabel.NoData.message".localized() + self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message } }) } diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift index 1894a379f..3507ab71e 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift @@ -3,6 +3,7 @@ import UIKit import Humidity import RuuviOntology import RuuviLocal +import RuuviLocalization import RuuviService class DashboardViewController: UIViewController { @@ -109,7 +110,7 @@ class DashboardViewController: UIViewController { private lazy var viewButton: RuuviContextMenuButton = RuuviContextMenuButton(menu: viewToggleMenuOptions(), titleColor: RuuviColor.dashboardIndicatorTextColor, - title: "view".localized(), + title: RuuviLocalization.view, icon: RuuviAssets.dropDownArrowImage, iconTintColor: RuuviColor.logoTintColor, iconSize: .init(width: 14, height: 14), @@ -158,7 +159,6 @@ extension DashboardViewController { override func viewDidLoad() { super.viewDidLoad() setUpUI() - setupLocalization() configureRestartAnimationsOnAppDidBecomeActive() output.viewDidLoad() } @@ -235,14 +235,14 @@ extension DashboardViewController { extension DashboardViewController { private func viewToggleMenuOptions() -> UIMenu { // Card Type - let imageViewTypeAction = UIAction(title: "image_cards".localized()) { + let imageViewTypeAction = UIAction(title: RuuviLocalization.imageCards) { [weak self] _ in self?.output.viewDidChangeDashboardType(dashboardType: .image) self?.reloadCollectionView(redrawLayout: true) self?.viewButton.updateMenu(with: self?.viewToggleMenuOptions()) } - let simpleViewTypeAction = UIAction(title: "simple_cards".localized()) { + let simpleViewTypeAction = UIAction(title: RuuviLocalization.simpleCards) { [weak self] _ in self?.output.viewDidChangeDashboardType(dashboardType: .simple) self?.reloadCollectionView(redrawLayout: true) @@ -252,20 +252,20 @@ extension DashboardViewController { simpleViewTypeAction.state = dashboardType == .simple ? .on : .off imageViewTypeAction.state = dashboardType == .image ? .on : .off - let cardTypeMenu = UIMenu(title: "card_type".localized(), + let cardTypeMenu = UIMenu(title: RuuviLocalization.cardType, options: .displayInline, children: [ imageViewTypeAction, simpleViewTypeAction ]) // Card action - let openSensorViewAction = UIAction(title: "open_sensor_view".localized()) { + let openSensorViewAction = UIAction(title: RuuviLocalization.openSensorView) { [weak self] _ in self?.output.viewDidChangeDashboardTapAction(type: .card) self?.viewButton.updateMenu(with: self?.viewToggleMenuOptions()) } - let openHistoryViewAction = UIAction(title: "open_history_view".localized()) { + let openHistoryViewAction = UIAction(title: RuuviLocalization.openHistoryView) { [weak self] _ in self?.output.viewDidChangeDashboardTapAction(type: .chart) self?.viewButton.updateMenu(with: self?.viewToggleMenuOptions()) @@ -274,7 +274,7 @@ extension DashboardViewController { openSensorViewAction.state = dashboardTapActionType == .card ? .on : .off openHistoryViewAction.state = dashboardTapActionType == .chart ? .on : .off - let cardActionMenu = UIMenu(title: "card_action".localized(), + let cardActionMenu = UIMenu(title: RuuviLocalization.cardAction, options: .displayInline, children: [ openSensorViewAction, openHistoryViewAction @@ -289,42 +289,42 @@ extension DashboardViewController { } private func cardContextMenuOption(for index: Int) -> UIMenu { - let fullImageViewAction = UIAction(title: "full_image_view".localized()) { + let fullImageViewAction = UIAction(title: RuuviLocalization.fullImageView) { [weak self] _ in if let viewModel = self?.viewModels[index] { self?.output.viewDidTriggerOpenCardImageView(for: viewModel) } } - let historyViewAction = UIAction(title: "history_view".localized()) { + let historyViewAction = UIAction(title: RuuviLocalization.historyView) { [weak self] _ in if let viewModel = self?.viewModels[index] { self?.output.viewDidTriggerChart(for: viewModel) } } - let settingsAction = UIAction(title: "settings_and_alerts".localized()) { + let settingsAction = UIAction(title: RuuviLocalization.settingsAndAlerts) { [weak self] _ in if let viewModel = self?.viewModels[index] { self?.output.viewDidTriggerSettings(for: viewModel) } } - let changeBackgroundAction = UIAction(title: "change_background".localized()) { + let changeBackgroundAction = UIAction(title: RuuviLocalization.changeBackground) { [weak self] _ in if let viewModel = self?.viewModels[index] { self?.output.viewDidTriggerChangeBackground(for: viewModel) } } - let renameAction = UIAction(title: "rename".localized()) { + let renameAction = UIAction(title: RuuviLocalization.rename) { [weak self] _ in if let viewModel = self?.viewModels[index] { self?.output.viewDidTriggerRename(for: viewModel) } } - let shareSensorAction = UIAction(title: "TagSettings.ShareButton".localized()) { + let shareSensorAction = UIAction(title: RuuviLocalization.TagSettings.shareButton) { [weak self] _ in if let viewModel = self?.viewModels[index] { self?.output.viewDidTriggerShare(for: viewModel) @@ -622,10 +622,10 @@ extension DashboardViewController: DashboardViewInput { } func showBluetoothDisabled(userDeclined: Bool) { - let title = "Cards.BluetoothDisabledAlert.title".localized() - let message = "Cards.BluetoothDisabledAlert.message".localized() + let title = RuuviLocalization.Cards.BluetoothDisabledAlert.title + let message = RuuviLocalization.Cards.BluetoothDisabledAlert.message let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "PermissionPresenter.settings".localized(), + alertVC.addAction(UIAlertAction(title: RuuviLocalization.PermissionPresenter.settings, style: .default, handler: { _ in guard let url = URL(string: userDeclined ? UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), @@ -634,7 +634,7 @@ extension DashboardViewController: DashboardViewInput { } UIApplication.shared.open(url) })) - alertVC.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) + alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) } @@ -645,13 +645,13 @@ extension DashboardViewController: DashboardViewInput { } func showKeepConnectionDialogChart(for viewModel: CardsViewModel) { - let message = "Cards.KeepConnectionDialog.message".localized() + let message = RuuviLocalization.Cards.KeepConnectionDialog.message let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) - let dismissTitle = "Cards.KeepConnectionDialog.Dismiss.title".localized() + let dismissTitle = RuuviLocalization.Cards.KeepConnectionDialog.Dismiss.title alert.addAction(UIAlertAction(title: dismissTitle, style: .cancel, handler: { [weak self] _ in self?.output.viewDidDismissKeepConnectionDialogChart(for: viewModel) })) - let keepTitle = "Cards.KeepConnectionDialog.KeepConnection.title".localized() + let keepTitle = RuuviLocalization.Cards.KeepConnectionDialog.KeepConnection.title alert.addAction(UIAlertAction(title: keepTitle, style: .default, handler: { [weak self] _ in self?.output.viewDidConfirmToKeepConnectionChart(to: viewModel) })) @@ -659,13 +659,13 @@ extension DashboardViewController: DashboardViewInput { } func showKeepConnectionDialogSettings(for viewModel: CardsViewModel) { - let message = "Cards.KeepConnectionDialog.message".localized() + let message = RuuviLocalization.Cards.KeepConnectionDialog.message let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) - let dismissTitle = "Cards.KeepConnectionDialog.Dismiss.title".localized() + let dismissTitle = RuuviLocalization.Cards.KeepConnectionDialog.Dismiss.title alert.addAction(UIAlertAction(title: dismissTitle, style: .cancel, handler: { [weak self] _ in self?.output.viewDidDismissKeepConnectionDialogSettings(for: viewModel) })) - let keepTitle = "Cards.KeepConnectionDialog.KeepConnection.title".localized() + let keepTitle = RuuviLocalization.Cards.KeepConnectionDialog.KeepConnection.title alert.addAction(UIAlertAction(title: keepTitle, style: .default, handler: { [weak self] _ in self?.output.viewDidConfirmToKeepConnectionSettings(to: viewModel) })) @@ -673,17 +673,16 @@ extension DashboardViewController: DashboardViewInput { } func showReverseGeocodingFailed() { - let message = "Cards.Error.ReverseGeocodingFailed.message".localized() + let message = RuuviLocalization.Cards.Error.ReverseGeocodingFailed.message let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) + alert.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alert, animated: true) } func showAlreadyLoggedInAlert(with email: String) { - let message = String.localizedStringWithFormat("Cards.Alert.AlreadyLoggedIn.message".localized(), - email) + let message = RuuviLocalization.Cards.Alert.AlreadyLoggedIn.message(email) let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) + alert.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alert, animated: true) } @@ -692,8 +691,8 @@ extension DashboardViewController: DashboardViewInput { from: viewModel.mac.value?.mac, luid: viewModel.luid.value?.value ) - let alert = UIAlertController(title: "TagSettings.tagNameTitleLabel.text".localized(), - message: "TagSettings.tagNameTitleLabel.rename.text".localized(), + let alert = UIAlertController(title: RuuviLocalization.TagSettings.TagNameTitleLabel.text, + message: RuuviLocalization.TagSettings.TagNameTitleLabel.Rename.text, preferredStyle: .alert) alert.addTextField { [weak self] alertTextField in guard let self = self else { return } @@ -702,7 +701,7 @@ extension DashboardViewController: DashboardViewInput { alertTextField.placeholder = defaultName self.tagNameTextField = alertTextField } - let action = UIAlertAction(title: "OK".localized(), style: .default) { [weak self] _ in + let action = UIAlertAction(title: RuuviLocalization.ok, style: .default) { [weak self] _ in guard let self = self else { return } if let name = self.tagNameTextField.text, !name.isEmpty { self.output.viewDidRenameTag(to: name, viewModel: viewModel) @@ -710,7 +709,7 @@ extension DashboardViewController: DashboardViewInput { self.output.viewDidRenameTag(to: defaultName, viewModel: viewModel) } } - let cancelAction = UIAlertAction(title: "Cancel".localized(), style: .cancel) + let cancelAction = UIAlertAction(title: RuuviLocalization.cancel, style: .cancel) alert.addAction(action) alert.addAction(cancelAction) present(alert, animated: true, completion: nil) diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift index ece4295af..63bd821e6 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit class BatteryLevelView: UIView { @@ -10,7 +11,7 @@ class BatteryLevelView: UIView { label.textAlignment = .right label.numberOfLines = 0 label.font = UIFont.Muli(.regular, size: 10) - label.text = "low_battery".localized() + label.text = RuuviLocalization.lowBattery return label }() diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift index 7e716ca08..7be2a5595 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift @@ -1,4 +1,5 @@ import UIKit +import RuuviLocalization protocol NoSensorViewDelegate: NSObjectProtocol { func didTapSignInButton(sender: NoSensorView) @@ -48,7 +49,7 @@ class NoSensorView: UIView { private lazy var signInButton: UIButton = { let button = UIButton(color: RuuviColor.ruuviTintColor, cornerRadius: UIDevice.isiPhoneSE() ? 20 : 25) - button.setTitle("SignIn.Title.text".localized(), + button.setTitle(RuuviLocalization.SignIn.Title.text, for: .normal) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, @@ -62,7 +63,7 @@ class NoSensorView: UIView { private lazy var addSensorButton: UIButton = { let button = UIButton(color: RuuviColor.ruuviTintColor, cornerRadius: UIDevice.isiPhoneSE() ? 20 : 25) - button.setTitle("add_a_sensor".localized(), + button.setTitle(RuuviLocalization.addASensor, for: .normal) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, @@ -76,7 +77,7 @@ class NoSensorView: UIView { private lazy var buySensorButton: UIButton = { let button = UIButton() button.setTitleColor(RuuviColor.ruuviTextColor, for: .normal) - button.setTitle("DiscoverTable.GetMoreSensors.button.title".localized(), + button.setTitle(RuuviLocalization.DiscoverTable.GetMoreSensors.Button.title, for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, size: 14) @@ -112,8 +113,8 @@ extension NoSensorView { centerButtonStackView.addArrangedSubview(button) } messageLabel.text = userSignInOnce ? - "dashboard_no_sensors_message_signed_out".localized() : - "dashboard_no_sensors_message".localized() + RuuviLocalization.dashboardNoSensorsMessageSignedOut : + RuuviLocalization.dashboardNoSensorsMessage centerButtonCenterYAnchor.isActive = userSignInOnce ? activateCenterButtonStackConstraint() : true } diff --git a/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift b/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift index 120a344ab..48241f44e 100644 --- a/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift +++ b/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit class MenuTableEmbededViewController: UITableViewController, MenuViewInput { @@ -22,22 +23,17 @@ class MenuTableEmbededViewController: UITableViewController, MenuViewInput { // MARK: - MenuViewInput extension MenuTableEmbededViewController { func localize() { - addANewSensorLabel.text = "Menu.Label.AddAnNewSensor.text".localized() - appSettingsLabel.text = "Menu.Label.AppSettings.text".localized() - aboutHelpLabel.text = "Menu.Label.AboutHelp.text".localized() - whatToMeasureLabel.text = "Menu.Label.WhatToMeasure.text".localized() - getMoreSensorsLabel.text = "Menu.Label.GetMoreSensors.text".localized() - feedbackLabel.text = "Menu.Label.Feedback.text".localized() + addANewSensorLabel.text = RuuviLocalization.Menu.Label.AddAnNewSensor.text + appSettingsLabel.text = RuuviLocalization.Menu.Label.AppSettings.text + aboutHelpLabel.text = RuuviLocalization.Menu.Label.AboutHelp.text + whatToMeasureLabel.text = RuuviLocalization.Menu.Label.WhatToMeasure.text + getMoreSensorsLabel.text = RuuviLocalization.Menu.Label.GetMoreSensors.text + feedbackLabel.text = RuuviLocalization.Menu.Label.Feedback.text } } // MARK: - View lifecycle extension MenuTableEmbededViewController { - override func viewDidLoad() { - super.viewDidLoad() - setupLocalization() - } - override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) output.viewWillAppear() @@ -55,8 +51,8 @@ extension MenuTableEmbededViewController { forRowAt indexPath: IndexPath) { if cell == accountCell { accountAuthLabel.text = output.userIsAuthorized - ? "Menu.Label.MyRuuviAccount.text".localized() - : "SignIn.Title.text".localized() + ? RuuviLocalization.Menu.Label.MyRuuviAccount.text + : RuuviLocalization.SignIn.Title.text } } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { diff --git a/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift b/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift index 690d0ad12..a22c4957f 100644 --- a/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift +++ b/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift @@ -6,6 +6,7 @@ import RuuviCloud import RuuviCore import Future import RuuviLocal +import RuuviLocalization import UIKit #if canImport(WidgetKit) @@ -70,10 +71,10 @@ extension MyRuuviAccountPresenter { extension MyRuuviAccountPresenter { private func createSignOutAlert() { - let title = "Menu.SignOut.text".localized() - let message = "TagsManagerPresenter.SignOutConfirmAlert.Message".localized() - let confirmActionTitle = "OK".localized() - let cancelActionTitle = "Cancel".localized() + let title = RuuviLocalization.Menu.SignOut.text + let message = RuuviLocalization.TagsManagerPresenter.SignOutConfirmAlert.message + let confirmActionTitle = RuuviLocalization.ok + let cancelActionTitle = RuuviLocalization.cancel let confirmAction = UIAlertAction(title: confirmActionTitle, style: .default) { [weak self] (_) in guard let sSelf = self else { return } diff --git a/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift b/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift index c6619524e..de118c87f 100644 --- a/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift +++ b/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift @@ -1,5 +1,6 @@ import Foundation import UIKit +import RuuviLocalization class MyRuuviAccountViewController: UIViewController { var output: MyRuuviAccountViewOutput! @@ -40,9 +41,9 @@ extension MyRuuviAccountViewController: MyRuuviAccountViewInput { func localize() {} func viewDidShowAccountDeletionConfirmation() { - let message = "MyRuuvi.Settings.DeleteAccount.Confirmation.message".localized() + let message = RuuviLocalization.MyRuuvi.Settings.DeleteAccount.Confirmation.message let alertVC = UIAlertController(title: message, message: nil, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) + alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) } } @@ -56,15 +57,15 @@ extension MyRuuviAccountViewController { label.text = username } loggedInLabel.bind(viewModel.username) { label, username in - label.text = username == nil ? nil : "Menu.LoggedIn.title".localized() + label.text = username == nil ? nil : RuuviLocalization.Menu.LoggedIn.title } } private func configureViews() { - headerTitleLabel.text = "Menu.Label.MyRuuviAccount.text".localized() - deleteAccountButton.setTitle("MyRuuvi.Settings.DeleteAccount.title".localized(), for: .normal) - deleteAccountButton.setTitle("MyRuuvi.Settings.DeleteAccount.title".localized(), for: .normal) - signoutButton.setTitle("Menu.SignOut.text".localized(), for: .normal) - signoutButton.setTitle("Menu.SignOut.text".localized(), for: .highlighted) + headerTitleLabel.text = RuuviLocalization.Menu.Label.MyRuuviAccount.text + deleteAccountButton.setTitle(RuuviLocalization.MyRuuvi.Settings.DeleteAccount.title, for: .normal) + deleteAccountButton.setTitle(RuuviLocalization.MyRuuvi.Settings.DeleteAccount.title, for: .normal) + signoutButton.setTitle(RuuviLocalization.Menu.SignOut.text, for: .normal) + signoutButton.setTitle(RuuviLocalization.Menu.SignOut.text, for: .highlighted) } } diff --git a/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift index ff9d608a3..7c4e1b7d0 100644 --- a/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import Foundation import RuuviOntology import RuuviContext @@ -58,7 +59,7 @@ extension SettingsPresenter: SettingsViewOutput { .fahrenheit, .kelvin ] - let viewModel = UnitSettingsViewModel(title: "TagSettings.OffsetCorrection.Temperature".localized(), + let viewModel = UnitSettingsViewModel(title: RuuviLocalization.TagSettings.OffsetCorrection.temperature, items: selectionItems, measurementType: .temperature) router.openUnitSettings(with: viewModel, output: nil) @@ -70,7 +71,7 @@ extension SettingsPresenter: SettingsViewOutput { .gm3, .dew ] - let viewModel = UnitSettingsViewModel(title: "TagSettings.OffsetCorrection.Humidity".localized(), + let viewModel = UnitSettingsViewModel(title: RuuviLocalization.TagSettings.OffsetCorrection.humidity, items: selectionItems, measurementType: .humidity) router.openUnitSettings(with: viewModel, output: nil) @@ -82,7 +83,7 @@ extension SettingsPresenter: SettingsViewOutput { .inchesOfMercury, .millimetersOfMercury ] - let viewModel = UnitSettingsViewModel(title: "TagSettings.OffsetCorrection.Pressure".localized(), + let viewModel = UnitSettingsViewModel(title: RuuviLocalization.TagSettings.OffsetCorrection.pressure, items: selectionItems, measurementType: .pressure) router.openUnitSettings(with: viewModel, output: nil) diff --git a/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift index 457a56786..998efab4e 100644 --- a/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit import RuuviOntology @@ -72,29 +73,29 @@ class SettingsTableViewController: UITableViewController { // MARK: - SettingsViewInput extension SettingsTableViewController: SettingsViewInput { func localize() { - navigationItem.title = "Settings.navigationItem.title".localized() - temperatureTitleLabel.text = "Settings.Label.Temperature".localized() - humidityTitleLabel.text = "Settings.Label.Humidity".localized() - pressureTitleLabel.text = "Settings.Label.Pressure".localized() - languageTitleLabel.text = "Settings.Label.Language.text".localized() - defaultsTitleLabel.text = "Settings.Label.Defaults".localized() - devicesTitleLabel.text = "DfuDevicesScanner.Title.text".localized() - heartbeatTitleLabel.text = "Settings.BackgroundScanning.title".localized() - chartTitleLabel.text = "Settings.Label.Chart".localized() - ruuviCloudTitleLabel.text = "ruuvi_cloud".localized() - appearanceTitleLabel.text = "settings_appearance".localized() - alertNotificationsTitleLabel.text = "settings_alert_notifications".localized() + navigationItem.title = RuuviLocalization.Settings.NavigationItem.title + temperatureTitleLabel.text = RuuviLocalization.Settings.Label.temperature + humidityTitleLabel.text = RuuviLocalization.Settings.Label.humidity + pressureTitleLabel.text = RuuviLocalization.Settings.Label.pressure + languageTitleLabel.text = RuuviLocalization.Settings.Label.Language.text + defaultsTitleLabel.text = RuuviLocalization.Settings.Label.defaults + devicesTitleLabel.text = RuuviLocalization.DfuDevicesScanner.Title.text + heartbeatTitleLabel.text = RuuviLocalization.Settings.BackgroundScanning.title + chartTitleLabel.text = RuuviLocalization.Settings.Label.chart + ruuviCloudTitleLabel.text = RuuviLocalization.ruuviCloud + appearanceTitleLabel.text = RuuviLocalization.settingsAppearance + alertNotificationsTitleLabel.text = RuuviLocalization.settingsAlertNotifications updateUILanguage() tableView.reloadData() } func viewDidShowLanguageChangeDialog() { - let title = "Settings.Language.Dialog.title".localized() - let message = "Settings.Language.Dialog.message".localized() + let title = RuuviLocalization.Settings.Language.Dialog.title + let message = RuuviLocalization.Settings.Language.Dialog.message let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - let cancelTitle = "Cancel".localized() + let cancelTitle = RuuviLocalization.cancel alert.addAction(UIAlertAction(title: cancelTitle, style: .cancel, handler: nil)) - let settingsTitle = "WebTagSettings.AlertsAreDisabled.Dialog.Settings.title".localized() + let settingsTitle = RuuviLocalization.WebTagSettings.AlertsAreDisabled.Dialog.Settings.title alert.addAction(UIAlertAction(title: settingsTitle, style: .default, handler: { [weak self] _ in self?.output.viewDidSelectChangeLanguage() })) @@ -119,7 +120,6 @@ extension SettingsTableViewController { override func viewDidLoad() { super.viewDidLoad() updateNavBarTitleFont() - setupLocalization() updateUI() output.viewDidLoad() becomeFirstResponder() diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Assembly/AppearanceSettingsModuleFactory.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Assembly/AppearanceSettingsModuleFactory.swift index 1b45b28af..32a24b6c8 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Assembly/AppearanceSettingsModuleFactory.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Assembly/AppearanceSettingsModuleFactory.swift @@ -1,5 +1,6 @@ import UIKit import RuuviLocal +import RuuviLocalization protocol AppearanceSettingsModuleFactory { func create() -> AppearanceSettingsTableViewController @@ -10,7 +11,7 @@ final class AppearanceSettingsModuleFactoryImpl: AppearanceSettingsModuleFactory let r = AppAssembly.shared.assembler.resolver let view = AppearanceSettingsTableViewController( - title: "settings_appearance".localized() + title: RuuviLocalization.settingsAppearance ) let router = AppearanceSettingsRouter() router.transitionHandler = view diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift index 7d962ddee..f41b48607 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift @@ -2,6 +2,7 @@ import Foundation import UIKit import RuuviOntology import RuuviLocal +import RuuviLocalization class AppearanceSettingsPresenter: NSObject, AppearanceSettingsModuleInput { weak var view: AppearanceSettingsViewInput? @@ -35,7 +36,7 @@ extension AppearanceSettingsPresenter { } fileprivate func appThemeSetting() -> AppearanceSettingsViewModel { - let title = "app_theme".localized() + let title = RuuviLocalization.appTheme let selectionItems: [RuuviTheme] = [ .system, .dark, diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouter.swift index f558deb24..24fe30995 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouter.swift @@ -1,4 +1,5 @@ import LightRoute +import RuuviLocalization import UIKit class AppearanceSettingsRouter: AppearanceSettingsRouterInput { @@ -10,7 +11,7 @@ class AppearanceSettingsRouter: AppearanceSettingsRouterInput { func openSelection(with viewModel: AppearanceSettingsViewModel) { let factory: ASSelectionModuleFactory = ASSelectionModuleFactoryImpl() - let module = factory.create(with: "app_theme".localized()) + let module = factory.create(with: RuuviLocalization.appTheme) transitionHandler? .navigationController? diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift index dee530522..2930741cf 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift @@ -25,7 +25,6 @@ class ASSelectionTableViewController: UITableViewController { extension ASSelectionTableViewController { override func viewDidLoad() { super.viewDidLoad() - setupLocalization() setUpUI() output.viewDidLoad() } @@ -76,8 +75,8 @@ extension ASSelectionTableViewController { if let viewModel = viewModel { let item = viewModel.items[indexPath.row] cell.configure( - title: item.title, - selection: viewModel.selection.title + title: item.title(""), + selection: viewModel.selection.title("") ) } return cell diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift index d01b3ccb5..504083e94 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift @@ -25,7 +25,6 @@ class AppearanceSettingsTableViewController: UITableViewController { extension AppearanceSettingsTableViewController { override func viewDidLoad() { super.viewDidLoad() - setupLocalization() setUpUI() output.viewDidLoad() } @@ -74,7 +73,7 @@ extension AppearanceSettingsTableViewController { fatalError() } let viewModel = viewModels[indexPath.row] - cell.configure(title: viewModel.title, value: viewModel.selection.title) + cell.configure(title: viewModel.title, value: viewModel.selection.title("")) return cell } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift index 28b31ae71..becb92f5f 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift @@ -1,6 +1,7 @@ import Foundation import RuuviLocal import RuuviService +import RuuviLocalization class ChartSettingsPresenter: NSObject, ChartSettingsModuleInput { weak var view: ChartSettingsViewInput! @@ -24,7 +25,7 @@ class ChartSettingsPresenter: NSObject, ChartSettingsModuleInput { private func buildDisplayAllDataSection() -> ChartSettingsSection { return ChartSettingsSection( - note: "ChartSettings.AllPoints.description".localized(), + note: RuuviLocalization.ChartSettings.AllPoints.description, cells: [ buildChartDownsampling() ] @@ -35,7 +36,7 @@ class ChartSettingsPresenter: NSObject, ChartSettingsModuleInput { // maintain better performance until we find a better approach to do it. private func buildDrawDotsSection() -> ChartSettingsSection { return ChartSettingsSection( - note: "ChartSettings.DrawDots.description".localized(), + note: RuuviLocalization.ChartSettings.DrawDots.description, cells: [ buildChartDotsDrawing() ] @@ -54,7 +55,7 @@ extension ChartSettingsPresenter: ChartSettingsViewOutput { extension ChartSettingsPresenter { private func buildChartDownsampling() -> ChartSettingsCell { - let title = "ChartSettings.AllPoints.title".localized() + let title = RuuviLocalization.ChartSettings.AllPoints.title let value = !settings.chartDownsamplingOn let type: ChartSettingsCellType = .switcher(title: title, value: value) @@ -69,7 +70,7 @@ extension ChartSettingsPresenter { } private func buildChartDotsDrawing() -> ChartSettingsCell { - let title = "ChartSettings.DrawDots.title".localized() + let title = RuuviLocalization.ChartSettings.DrawDots.title let value = settings.chartDrawDotsOn let type: ChartSettingsCellType = .switcher(title: title, value: value) diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift index 9a4d74b79..c1c89de64 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift @@ -1,4 +1,5 @@ import Foundation +import RuuviLocalization struct ChartSettingsViewModel { let sections: [ChartSettingsSection] @@ -22,9 +23,9 @@ enum ChartSettingsIntegerUnit { var unitString: String { switch self { case .day: - return "Interval.Day.string".localized() + return RuuviLocalization.Interval.Day.string case .days: - return "Interval.Days.string".localized() + return RuuviLocalization.Interval.Days.string } } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift index bd63ca907..af4b17253 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift @@ -1,4 +1,5 @@ import UIKit +import RuuviLocalization // swiftlint:disable:next type_name protocol ChartSettingsStepperTableViewCellDelegate: AnyObject { @@ -20,7 +21,7 @@ class ChartSettingsStepperTableViewCell: UITableViewCell { @IBAction func stepperValueChanged(_ sender: Any) { let result = Int(stepper.value) - let unitString: String = result > 1 ? "Interval.Days.string".localized() : "Interval.Day.string".localized() + let unitString: String = result > 1 ? RuuviLocalization.Interval.Days.string : RuuviLocalization.Interval.Day.string titleLabel.text = prefix + " " + "(" + "\(result)" + " " + unitString + ")" delegate?.chartSettingsStepper(cell: self, didChange: result) } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift index fdd5c7d43..187e49230 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift @@ -1,4 +1,5 @@ import UIKit +import RuuviLocalization class ChartSettingsTableViewController: UITableViewController { var output: ChartSettingsViewOutput! @@ -25,7 +26,7 @@ class ChartSettingsTableViewController: UITableViewController { extension ChartSettingsTableViewController: ChartSettingsViewInput { func localize() { - title = "Settings.Label.Chart".localized() + title = RuuviLocalization.Settings.Label.chart } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift index 7fa156aa7..deb48a5be 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift @@ -1,5 +1,6 @@ import Foundation import RuuviLocal +import RuuviLocalization import RuuviUser import WidgetKit @@ -56,7 +57,7 @@ extension DefaultsPresenter: DefaultsViewOutput { extension DefaultsPresenter { private func buildWelcomeShown() -> DefaultsViewModel { let welcomeShown = DefaultsViewModel() - welcomeShown.title = "Defaults.WelcomeShown.title".localized() + welcomeShown.title = RuuviLocalization.Defaults.WelcomeShown.title welcomeShown.boolean.value = settings.welcomeShown welcomeShown.type.value = .switcher @@ -68,7 +69,7 @@ extension DefaultsPresenter { private func buildChartsSwipeInstruction() -> DefaultsViewModel { let tagChartsLandscapeSwipeInstructionWasShown = DefaultsViewModel() - tagChartsLandscapeSwipeInstructionWasShown.title = "Defaults.ChartsSwipeInstructionWasShown.title".localized() + tagChartsLandscapeSwipeInstructionWasShown.title = RuuviLocalization.Defaults.ChartsSwipeInstructionWasShown.title tagChartsLandscapeSwipeInstructionWasShown.boolean.value = settings.tagChartsLandscapeSwipeInstructionWasShown tagChartsLandscapeSwipeInstructionWasShown.type.value = .switcher @@ -82,7 +83,7 @@ extension DefaultsPresenter { private func buildConnectionTimeout() -> DefaultsViewModel { let connectionTimeout = DefaultsViewModel() - connectionTimeout.title = "Defaults.ConnectionTimeout.title".localized() + connectionTimeout.title = RuuviLocalization.Defaults.ConnectionTimeout.title connectionTimeout.integer.value = Int(settings.connectionTimeout) connectionTimeout.type.value = .stepper connectionTimeout.unit = .seconds @@ -95,7 +96,7 @@ extension DefaultsPresenter { private func buildServiceTimeout() -> DefaultsViewModel { let serviceTimeout = DefaultsViewModel() - serviceTimeout.title = "Defaults.ServiceTimeout.title".localized() + serviceTimeout.title = RuuviLocalization.Defaults.ServiceTimeout.title serviceTimeout.integer.value = Int(settings.serviceTimeout) serviceTimeout.type.value = .stepper serviceTimeout.unit = .seconds @@ -108,7 +109,7 @@ extension DefaultsPresenter { private func buildCardsSwipeHint() -> DefaultsViewModel { let cardsSwipeHint = DefaultsViewModel() - cardsSwipeHint.title = "Defaults.CardsSwipeHint.title".localized() + cardsSwipeHint.title = RuuviLocalization.Defaults.CardsSwipeHint.title cardsSwipeHint.boolean.value = settings.cardsSwipeHintWasShown cardsSwipeHint.type.value = .switcher @@ -120,7 +121,7 @@ extension DefaultsPresenter { private func buildAlertsMuteInterval() -> DefaultsViewModel { let alertsInterval = DefaultsViewModel() - alertsInterval.title = "Defaults.AlertsMuteInterval.title".localized() + alertsInterval.title = RuuviLocalization.Defaults.AlertsMuteInterval.title alertsInterval.integer.value = settings.alertsMuteIntervalMinutes alertsInterval.unit = .minutes alertsInterval.type.value = .stepper @@ -133,7 +134,7 @@ extension DefaultsPresenter { private func buildWebPullInterval() -> DefaultsViewModel { let webPullInterval = DefaultsViewModel() - webPullInterval.title = "Defaults.WebPullInterval.title".localized() + webPullInterval.title = RuuviLocalization.Defaults.WebPullInterval.title webPullInterval.integer.value = settings.webPullIntervalMinutes webPullInterval.unit = .minutes webPullInterval.type.value = .stepper @@ -146,7 +147,7 @@ extension DefaultsPresenter { private func buildPruningOffsetHours() -> DefaultsViewModel { let pruningOffsetHours = DefaultsViewModel() - pruningOffsetHours.title = "Defaults.PruningOffsetHours.title".localized() + pruningOffsetHours.title = RuuviLocalization.Defaults.PruningOffsetHours.title pruningOffsetHours.integer.value = settings.dataPruningOffsetHours pruningOffsetHours.unit = .hours pruningOffsetHours.type.value = .stepper @@ -159,7 +160,7 @@ extension DefaultsPresenter { private func buildChartIntervalSeconds() -> DefaultsViewModel { let chartIntervalSeconds = DefaultsViewModel() - chartIntervalSeconds.title = "Defaults.ChartIntervalSeconds.title".localized() + chartIntervalSeconds.title = RuuviLocalization.Defaults.ChartIntervalSeconds.title chartIntervalSeconds.integer.value = settings.chartIntervalSeconds chartIntervalSeconds.unit = .seconds chartIntervalSeconds.type.value = .stepper @@ -172,7 +173,7 @@ extension DefaultsPresenter { private func buildChartDurationHours() -> DefaultsViewModel { let chartDurationHours = DefaultsViewModel() - chartDurationHours.title = "Defaults.ChartDurationHours.title".localized() + chartDurationHours.title = RuuviLocalization.Defaults.ChartDurationHours.title chartDurationHours.integer.value = settings.chartDurationHours chartDurationHours.unit = .hours chartDurationHours.type.value = .stepper @@ -185,7 +186,7 @@ extension DefaultsPresenter { private func saveAdvertisementsInterval() -> DefaultsViewModel { let advertisementInterval = DefaultsViewModel() - advertisementInterval.title = "ForegroundRow.advertisement.title".localized() + advertisementInterval.title = RuuviLocalization.ForegroundRow.Advertisement.title advertisementInterval.integer.value = settings.advertisementDaemonIntervalMinutes advertisementInterval.unit = .minutes advertisementInterval.type.value = .stepper @@ -198,7 +199,7 @@ extension DefaultsPresenter { private func buildAskForReviewFirstTime() -> DefaultsViewModel { let askForReviewAtLaunch = DefaultsViewModel() - askForReviewAtLaunch.title = "Defaults.AppLaunchRequiredForReview.Count.title".localized() + askForReviewAtLaunch.title = RuuviLocalization.Defaults.AppLaunchRequiredForReview.Count.title askForReviewAtLaunch.integer.value = settings.appOpenedInitialCountToAskReview askForReviewAtLaunch.unit = .decimal askForReviewAtLaunch.type.value = .stepper @@ -211,7 +212,7 @@ extension DefaultsPresenter { private func buildAskForReviewLater() -> DefaultsViewModel { let askForReviewAtLaunch = DefaultsViewModel() - askForReviewAtLaunch.title = "Defaults.AskReviewIfLaunchDivisibleBy.Count.title".localized() + askForReviewAtLaunch.title = RuuviLocalization.Defaults.AskReviewIfLaunchDivisibleBy.Count.title askForReviewAtLaunch.integer.value = settings.appOpenedCountDivisibleToAskReview askForReviewAtLaunch.unit = .decimal askForReviewAtLaunch.type.value = .stepper @@ -224,9 +225,9 @@ extension DefaultsPresenter { private func buildIsAuthorized() -> DefaultsViewModel { let viewModel = DefaultsViewModel() - viewModel.title = "Defaults.UserAuthorized.title".localized() + viewModel.title = RuuviLocalization.Defaults.UserAuthorized.title viewModel.type.value = .plain - viewModel.value.value = ruuviUser.isAuthorized ? "Yes".localized() : "No".localized() + viewModel.value.value = ruuviUser.isAuthorized ? RuuviLocalization.yes : RuuviLocalization.no return viewModel } @@ -240,7 +241,7 @@ extension DefaultsPresenter { private func buildDashboardCardTapAction() -> DefaultsViewModel { let viewModel = DefaultsViewModel() - viewModel.title = "Defaults.DashboardTapActionChart.title".localized() + viewModel.title = RuuviLocalization.Defaults.DashboardTapActionChart.title viewModel.boolean.value = settings.dashboardTapActionType == .chart viewModel.type.value = .switcher @@ -258,7 +259,7 @@ extension DefaultsPresenter { ) ?? false let viewModel = DefaultsViewModel() - viewModel.title = "Defaults.DevServer.title".localized() + viewModel.title = RuuviLocalization.Defaults.DevServer.title viewModel.boolean.value = useDevServer viewModel.type.value = .switcher @@ -280,7 +281,7 @@ extension DefaultsPresenter { private func buildHideNFCButtonInSensorContents() -> DefaultsViewModel { let viewModel = DefaultsViewModel() - viewModel.title = "Defaults.HideNFC.title".localized() + viewModel.title = RuuviLocalization.Defaults.HideNFC.title viewModel.boolean.value = settings.hideNFCForSensorContest viewModel.type.value = .switcher @@ -294,7 +295,7 @@ extension DefaultsPresenter { private func buildShowEmailAlertSettings() -> DefaultsViewModel { let viewModel = DefaultsViewModel() - viewModel.title = "Defaults.ShowEmailAlertsSettings.title".localized() + viewModel.title = RuuviLocalization.Defaults.ShowEmailAlertsSettings.title viewModel.boolean.value = settings.showEmailAlertSettings viewModel.type.value = .switcher @@ -308,7 +309,7 @@ extension DefaultsPresenter { private func buildShowPushAlertSettings() -> DefaultsViewModel { let viewModel = DefaultsViewModel() - viewModel.title = "Defaults.ShowPushAlertsSettings.title".localized() + viewModel.title = RuuviLocalization.Defaults.ShowPushAlertsSettings.title viewModel.boolean.value = settings.showPushAlertSettings viewModel.type.value = .switcher diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift index 091337504..37060f877 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift @@ -1,4 +1,5 @@ import UIKit +import RuuviLocalization #if canImport(SwiftUI) && canImport(Combine) import SwiftUI #endif @@ -30,11 +31,11 @@ class DefaultsViewController: UIViewController { extension DefaultsViewController: DefaultsViewInput { func showEndpointChangeConfirmationDialog(useDevServer: Bool?) { - let message = "Defaults.DevServer.message".localized() + let message = RuuviLocalization.Defaults.DevServer.message let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) - let cancelActionTitle = "Cancel".localized() + let cancelActionTitle = RuuviLocalization.cancel alert.addAction(UIAlertAction(title: cancelActionTitle, style: .cancel, handler: nil)) - let signOutTitle = "Menu.SignOut.text".localized() + let signOutTitle = RuuviLocalization.Menu.SignOut.text alert.addAction(UIAlertAction(title: signOutTitle, style: .default, handler: { [weak self] _ in self?.output.viewDidTriggerUseDevServer(useDevServer: useDevServer) })) @@ -42,7 +43,7 @@ extension DefaultsViewController: DefaultsViewInput { } func localize() { - navigationItem.title = "Defaults.navigationItem.title".localized() + navigationItem.title = RuuviLocalization.Defaults.NavigationItem.title } } @@ -50,7 +51,6 @@ extension DefaultsViewController: DefaultsViewInput { extension DefaultsViewController { override func viewDidLoad() { super.viewDidLoad() - setupLocalization() configureViews() } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsStepperTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsStepperTableViewCell.swift index 75235910d..e9067d56e 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsStepperTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsStepperTableViewCell.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit protocol DefaultsStepperTableViewCellDelegate: AnyObject { @@ -23,11 +24,11 @@ class DefaultsStepperTableViewCell: UITableViewCell { let unitString: String switch unit { case .hours: - unitString = "Defaults.Interval.Hour.string".localized() + unitString = RuuviLocalization.Defaults.Interval.Hour.string case .minutes: - unitString = "Defaults.Interval.Min.string".localized() + unitString = RuuviLocalization.Defaults.Interval.Min.string case .seconds: - unitString = "Defaults.Interval.Sec.string".localized() + unitString = RuuviLocalization.Defaults.Interval.Sec.string case .decimal: unitString = "" } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift index 902004891..72bb8f95e 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit class DefaultsTableViewController: UITableViewController { @@ -49,7 +50,7 @@ extension DefaultsTableViewController { for: indexPath) as! DefaultsPlainTableViewCell // swiftlint:enable force_cast cell.titleLabel.text = viewModel.title - cell.valueLabel.text = viewModel.value.value ?? "N/A".localized() + cell.valueLabel.text = viewModel.value.value ?? RuuviLocalization.na return cell case .switcher: // swiftlint:disable force_cast @@ -71,13 +72,13 @@ extension DefaultsTableViewController { let unitString: String switch viewModel.unit { case .hours: - unitString = "Defaults.Interval.Hour.string".localized() + unitString = RuuviLocalization.Defaults.Interval.Hour.string cell.stepper.stepValue = 1 case .minutes: - unitString = "Defaults.Interval.Min.string".localized() + unitString = RuuviLocalization.Defaults.Interval.Min.string cell.stepper.stepValue = 5 case .seconds: - unitString = "Defaults.Interval.Sec.string".localized() + unitString = RuuviLocalization.Defaults.Interval.Sec.string cell.stepper.stepValue = 30 case .decimal: unitString = "" diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift index 2c46af03b..d41aeffe6 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit class DevicesTableViewCell: UITableViewCell { @@ -77,7 +78,7 @@ extension DevicesTableViewCell { if let tokenId = viewModel.id.value { tokenIdLabel.text = "Token Id: " + tokenId.stringValue } else { - tokenIdLabel.text = "Token Id: " + "N/A".localized() + tokenIdLabel.text = "Token Id: " + RuuviLocalization.na } if let lastAccessed = viewModel.lastAccessed.value { @@ -85,7 +86,7 @@ extension DevicesTableViewCell { lastAccessedLabel.text = "Last accessed: " + AppDateFormatter.shared.ruuviAgoString(from: date) } else { - lastAccessedLabel.text = "Last accessed: " + "N/A".localized() + lastAccessedLabel.text = "Last accessed: " + RuuviLocalization.na } } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift index 3b14df658..483407470 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift @@ -1,4 +1,5 @@ import UIKit +import RuuviLocalization class DevicesTableViewController: UITableViewController { var output: DevicesViewOutput! @@ -23,7 +24,6 @@ class DevicesTableViewController: UITableViewController { extension DevicesTableViewController { override func viewDidLoad() { super.viewDidLoad() - setupLocalization() setUpTableView() output.viewDidLoad() } @@ -36,7 +36,7 @@ extension DevicesTableViewController { extension DevicesTableViewController: DevicesViewInput { func localize() { - self.title = "DfuDevicesScanner.Title.text".localized() + self.title = RuuviLocalization.DfuDevicesScanner.Title.text } func showTokenIdDialog(for viewModel: DevicesViewModel) { @@ -44,16 +44,16 @@ extension DevicesTableViewController: DevicesViewInput { return } - let title = "Token Id".localized() + let title = RuuviLocalization.Devices.tokenId let controller = UIAlertController(title: title, message: tokenId.stringValue, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: "Copy".localized(), + controller.addAction(UIAlertAction(title: RuuviLocalization.copy, style: .default, handler: { _ in UIPasteboard.general.string = tokenId.stringValue })) - controller.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil)) + controller.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) present(controller, animated: true) } @@ -61,7 +61,7 @@ extension DevicesTableViewController: DevicesViewInput { let controller = UIAlertController(title: nil, message: error.localizedDescription, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: "Ok".localized(), + controller.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .default, handler: { [weak self] _ in self?.navigationController?.popViewController(animated: true) diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift index 20fc039db..7bcd5ad64 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift @@ -1,4 +1,5 @@ import UIKit +import RuuviLocalization #if canImport(SwiftUI) && canImport(Combine) import SwiftUI #endif @@ -30,7 +31,7 @@ class HeartbeatViewController: UIViewController { extension HeartbeatViewController: HeartbeatViewInput { func localize() { - navigationItem.title = "Settings.BackgroundScanning.title".localized() + navigationItem.title = RuuviLocalization.Settings.BackgroundScanning.title } } @@ -38,7 +39,6 @@ extension HeartbeatViewController: HeartbeatViewInput { extension HeartbeatViewController { override func viewDidLoad() { super.viewDidLoad() - setupLocalization() configureViews() } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewModel.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewModel.swift index 7066ac435..45af19a3e 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewModel.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewModel.swift @@ -1,14 +1,15 @@ import Foundation +import RuuviLocalization class HeartbeatViewModel { var bgScanningState = Observable() var bgScanningInterval = Observable(1) var bgScanningTitle: String { - return "Settings.BackgroundScanning.title".localized() + return RuuviLocalization.Settings.BackgroundScanning.title } var bgScanningIntervalTitle: String { - return "Settings.BackgroundScanning.interval".localized() + return RuuviLocalization.Settings.BackgroundScanning.interval } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift index dc1ce5bab..69e32f4db 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift @@ -1,3 +1,4 @@ +import RuuviLocalization #if canImport(SwiftUI) && canImport(Combine) import SwiftUI @@ -13,9 +14,9 @@ struct HeartbeatList: View { } if self.env.viewModel.bgScanningState.value.bound { - Stepper("Heartbeat.Interval.Every.string".localized() + Stepper(RuuviLocalization.Heartbeat.Interval.Every.string + " " + "\(self.env.viewModel.bgScanningInterval.value.bound)" - + " " + "Heartbeat.Interval.Min.string".localized(), + + " " + RuuviLocalization.Heartbeat.Interval.Min.string, value: self.$env.viewModel.bgScanningInterval.value.bound, in: 0...3600) } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift index 8abd1cc5e..30938368e 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit class HeartbeatTableViewController: UITableViewController { @@ -15,8 +16,6 @@ class HeartbeatTableViewController: UITableViewController { @IBOutlet weak var bgScanningIntervalTitleLabel: UILabel! @IBOutlet weak var bgScanningIntervalValueLabel: UILabel! @IBOutlet weak var bgScanningIntervalStepper: UIStepper! - - private let everyString = "Heartbeat.Interval.Every.string" } // MARK: - HeartbeatViewInput @@ -25,11 +24,11 @@ extension HeartbeatTableViewController: HeartbeatViewInput { bgScanningTitleLabel.text = viewModel.bgScanningTitle bgScanningIntervalTitleLabel.text = viewModel.bgScanningIntervalTitle if viewModel.bgScanningInterval.value.bound > 0 { - bgScanningIntervalValueLabel.text = everyString.localized() + bgScanningIntervalValueLabel.text = RuuviLocalization.Heartbeat.Interval.Every.string + " " + "\(viewModel.bgScanningInterval.value.bound)" - + " " + "Heartbeat.Interval.Min.string".localized() + + " " + RuuviLocalization.Heartbeat.Interval.Min.string } else { - bgScanningIntervalValueLabel.text = "Heartbeat.Interval.All.string".localized() + bgScanningIntervalValueLabel.text = RuuviLocalization.Heartbeat.Interval.All.string } } } @@ -49,7 +48,6 @@ extension HeartbeatTableViewController { extension HeartbeatTableViewController { override func viewDidLoad() { super.viewDidLoad() - setupLocalization() bindViewModel() updateUIComponent() } @@ -67,7 +65,7 @@ extension HeartbeatTableViewController { footerLabel.textColor = RuuviColor.ruuviTextColor footerLabel.font = UIFont.Muli(.regular, size: 13) footerLabel.numberOfLines = 0 - footerLabel.text = "Settings.BackgroundScanning.Footer.message".localized() + footerLabel.text = RuuviLocalization.Settings.BackgroundScanning.Footer.message footerView.addSubview(footerLabel) footerLabel.fillSuperview(padding: .init(top: 8, left: 20, bottom: 8, right: 20)) return footerView @@ -86,14 +84,13 @@ extension HeartbeatTableViewController { bgScanningSwitch.bind(viewModel.bgScanningState) { (view, isOn) in view.isOn = isOn.bound } - let every = everyString bgScanningIntervalValueLabel.bind(viewModel.bgScanningInterval) { (label, interval) in if interval.bound > 0 { - label.text = every.localized() + label.text = RuuviLocalization.Heartbeat.Interval.Every.string + " " + "\(interval.bound)" - + " " + "Heartbeat.Interval.Min.string".localized() + + " " + RuuviLocalization.Heartbeat.Interval.Min.string } else { - label.text = "Heartbeat.Interval.All.string".localized() + label.text = RuuviLocalization.Heartbeat.Interval.All.string } } bgScanningIntervalStepper.bind(viewModel.bgScanningInterval) { (stepper, interval) in diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Assembly/NotificationsSettingsModuleFactory.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Assembly/NotificationsSettingsModuleFactory.swift index 8e2b97d41..24b57b157 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Assembly/NotificationsSettingsModuleFactory.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Assembly/NotificationsSettingsModuleFactory.swift @@ -1,6 +1,7 @@ import UIKit import RuuviLocal import RuuviService +import RuuviLocalization protocol NotificationsSettingsModuleFactory { func create() -> NotificationsSettingsTableViewController @@ -11,7 +12,7 @@ final class NotificationsSettingsModuleFactoryImpl: NotificationsSettingsModuleF let r = AppAssembly.shared.assembler.resolver let view = NotificationsSettingsTableViewController( - title: "settings_alert_notifications".localized() + title: RuuviLocalization.settingsAlertNotifications ) let router = NotificationsSettingsRouter() router.transitionHandler = view diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift index 9b23c7b29..612934414 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift @@ -3,6 +3,7 @@ import UIKit import RuuviOntology import RuuviLocal import RuuviService +import RuuviLocalization class NotificationsSettingsPresenter: NSObject, NotificationsSettingsModuleInput { weak var view: NotificationsSettingsViewInput? @@ -39,7 +40,7 @@ extension NotificationsSettingsPresenter: NotificationsSettingsViewOutput { func viewDidTapSoundSelection() { let pushAlertSoundViewModel = PushAlertSoundSelectionViewModel( - title: "settings_alert_sound".localized(), + title: RuuviLocalization.settingsAlertSound, items: [ RuuviAlertSound.systemDefault, RuuviAlertSound.ruuviSpeak @@ -70,8 +71,8 @@ extension NotificationsSettingsPresenter { private func buildEmailAlertSettings() -> NotificationsSettingsViewModel { let viewModel = NotificationsSettingsViewModel() - viewModel.title = "settings_email_alerts".localized() - viewModel.subtitle = "settings_email_alerts_description".localized() + viewModel.title = RuuviLocalization.settingsEmailAlerts + viewModel.subtitle = RuuviLocalization.settingsEmailAlertsDescription viewModel.boolean.value = settings.emailAlertEnabled viewModel.configType.value = .switcher viewModel.settingsType.value = .email @@ -87,8 +88,8 @@ extension NotificationsSettingsPresenter { private func buildPushSettings() -> NotificationsSettingsViewModel { let viewModel = NotificationsSettingsViewModel() - viewModel.title = "settings_push_alerts".localized() - viewModel.subtitle = "settings_push_alerts_description".localized() + viewModel.title = RuuviLocalization.settingsPushAlerts + viewModel.subtitle = RuuviLocalization.settingsPushAlertsDescription viewModel.boolean.value = settings.pushAlertEnabled viewModel.configType.value = .switcher viewModel.settingsType.value = .push @@ -104,8 +105,8 @@ extension NotificationsSettingsPresenter { private func buildLimitAlertNotificationsSettings() -> NotificationsSettingsViewModel { let viewModel = NotificationsSettingsViewModel() - viewModel.title = "settings_alert_limit_notification".localized() - viewModel.subtitle = "settings_alert_limit_notification_description".localized() + viewModel.title = RuuviLocalization.settingsAlertLimitNotification + viewModel.subtitle = RuuviLocalization.settingsAlertLimitNotificationDescription viewModel.boolean.value = settings.limitAlertNotificationsEnabled viewModel.configType.value = .switcher viewModel.settingsType.value = .limitAlert @@ -120,9 +121,9 @@ extension NotificationsSettingsPresenter { private func buildSoundSettings() -> NotificationsSettingsViewModel { let viewModel = NotificationsSettingsViewModel() - viewModel.title = "settings_alert_sound".localized() - viewModel.subtitle = "settings_alert_sound_description".localized() - viewModel.value.value = settings.alertSound.title + viewModel.title = RuuviLocalization.settingsAlertSound + viewModel.subtitle = RuuviLocalization.settingsAlertSoundDescription + viewModel.value.value = settings.alertSound.title("") viewModel.configType.value = .plain viewModel.settingsType.value = .alertSound return viewModel diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift index ea6a7cee8..68430ac7f 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift @@ -35,7 +35,6 @@ class PushAlertSoundSelectionTableViewController: UITableViewController { extension PushAlertSoundSelectionTableViewController { override func viewDidLoad() { super.viewDidLoad() - setupLocalization() setUpUI() output.viewDidLoad() } @@ -95,8 +94,8 @@ extension PushAlertSoundSelectionTableViewController { if let viewModel = viewModel { let item = viewModel.items[indexPath.row] cell.configure( - title: item.title, - selection: viewModel.selection.title + title: item.title(""), + selection: viewModel.selection.title("") ) } return cell diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift index 9f917daf7..b31f30378 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift @@ -1,5 +1,6 @@ import UIKit import Foundation +import RuuviLocalization class NotificationsSettingsTableViewController: UITableViewController { var output: NotificationsSettingsViewOutput? @@ -26,7 +27,6 @@ class NotificationsSettingsTableViewController: UITableViewController { extension NotificationsSettingsTableViewController { override func viewDidLoad() { super.viewDidLoad() - setupLocalization() setUpUI() output?.viewDidLoad() } @@ -121,8 +121,8 @@ extension NotificationsSettingsTableViewController { viewForFooterInSection section: Int) -> UIView? { let footerView = UIView() let footerTextView = RuuviLinkTextView( - fullTextString: "settings_alerts_footer_description".localized(), - linkString: "settings_alerts_footer_description_link_mask".localized(), + fullTextString: RuuviLocalization.settingsAlertsFooterDescription, + linkString: RuuviLocalization.settingsAlertsFooterDescriptionLinkMask, link: UIApplication.openSettingsURLString ) footerTextView.linkDelegate = self diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudPresenter.swift index fbbc80417..d23ef666d 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudPresenter.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import Foundation import UIKit import RuuviService @@ -40,7 +41,7 @@ extension RuuviCloudPresenter { fileprivate func ruuviCloudIsOn() -> RuuviCloudViewModel { let cloudMode = RuuviCloudViewModel() - cloudMode.title = "Settings.Label.CloudMode".localized() + cloudMode.title = RuuviLocalization.Settings.Label.cloudMode cloudMode.boolean.value = settings.cloudModeEnabled bind(cloudMode.boolean, fire: false) { observer, isOn in observer.settings.cloudModeEnabled = isOn.bound diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift index 9599a4daf..ba2316210 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit import Foundation @@ -24,7 +25,6 @@ class RuuviCloudTableViewController: UITableViewController { extension RuuviCloudTableViewController { override func viewDidLoad() { super.viewDidLoad() - setupLocalization() setUpUI() output.viewDidLoad() } @@ -37,7 +37,7 @@ extension RuuviCloudTableViewController { extension RuuviCloudTableViewController: RuuviCloudViewInput { func localize() { - self.title = "ruuvi_cloud".localized() + self.title = RuuviLocalization.ruuviCloud } } @@ -93,7 +93,7 @@ extension RuuviCloudTableViewController { footerLabel.textColor = RuuviColor.ruuviTextColor footerLabel.font = UIFont.Muli(.regular, size: 13) footerLabel.numberOfLines = 0 - footerLabel.text = "Settings.Label.CloudMode.description".localized() + footerLabel.text = RuuviLocalization.Settings.Label.CloudMode.description footerView.addSubview(footerLabel) footerLabel.fillSuperview(padding: .init(top: 8, left: 20, bottom: 8, right: 20)) return footerView diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Model/SelectionItem.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Model/SelectionItem.swift index 4e1675af3..485cc22d5 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Model/SelectionItem.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Model/SelectionItem.swift @@ -2,7 +2,7 @@ import Foundation import RuuviOntology protocol SelectionItemProtocol { - var title: String { get } + var title: (String) -> String { get } } struct SelectionViewModel { diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift index 9a9ff709c..8d71a8fe2 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift @@ -1,6 +1,7 @@ import UIKit import RuuviOntology import RuuviLocal +import RuuviLocalization class SelectionTableViewController: UITableViewController { var output: SelectionViewOutput! @@ -47,7 +48,6 @@ extension SelectionTableViewController { super.viewDidLoad() output.viewDidLoad() updateUI() - setupLocalization() } } @@ -81,17 +81,17 @@ extension SelectionTableViewController { case .pressure: cell.nameLabel.text = title + " " + pressureUnit.symbol default: - cell.nameLabel.text = "N/A".localized() + cell.nameLabel.text = RuuviLocalization.na } updateCellStyle(with: title, cell: cell) } else { if let humidityUnit = item as? HumidityUnit, humidityUnit == .dew { - cell.nameLabel.text = String(format: item.title, settings.temperatureUnit.symbol) + cell.nameLabel.text = item.title(settings.temperatureUnit.symbol) } else { - cell.nameLabel.text = item.title + cell.nameLabel.text = item.title("") } - updateCellStyle(with: item.title, cell: cell) + updateCellStyle(with: item.title(""), cell: cell) } return cell diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift index 55e57d75b..a3a2a8a5d 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift @@ -2,6 +2,7 @@ import Foundation import RuuviOntology import RuuviLocal import RuuviService +import RuuviLocalization class UnitSettingsPresenter { weak var view: UnitSettingsViewInput! @@ -115,26 +116,26 @@ extension UnitSettingsPresenter { switch viewModel.measurementType { case .temperature: - return SelectionViewModel(title: "Settings.Label.TemperatureUnit.text".localized(), + return SelectionViewModel(title: RuuviLocalization.Settings.Label.TemperatureUnit.text, items: viewModel.items, - description: "Settings.ChooseTemperatureUnit.text".localized(), - selection: settings.temperatureUnit.title, + description: RuuviLocalization.Settings.ChooseTemperatureUnit.text, + selection: settings.temperatureUnit.title(""), measurementType: viewModel.measurementType, unitSettingsType: .unit) case .humidity: - return SelectionViewModel(title: "Settings.Label.HumidityUnit.text".localized(), + return SelectionViewModel(title: RuuviLocalization.Settings.Label.HumidityUnit.text, items: viewModel.items, - description: "Settings.ChooseHumidityUnit.text".localized(), - selection: settings.humidityUnit.title, + description: RuuviLocalization.Settings.ChooseHumidityUnit.text, + selection: settings.humidityUnit.title(""), measurementType: viewModel.measurementType, unitSettingsType: .unit) case .pressure: - return SelectionViewModel(title: "Settings.Label.PressureUnit.text".localized(), + return SelectionViewModel(title: RuuviLocalization.Settings.Label.PressureUnit.text, items: viewModel.items, - description: "Settings.ChoosePressureUnit.text".localized(), - selection: settings.pressureUnit.title, + description: RuuviLocalization.Settings.ChoosePressureUnit.text, + selection: settings.pressureUnit.title(""), measurementType: viewModel.measurementType, unitSettingsType: .unit) @@ -152,13 +153,13 @@ extension UnitSettingsPresenter { let titleProvider = MeasurementAccuracyTitles() switch measurementType { case .temperature: - accuracyTitle = "Settings.Temperature.Resolution.title".localized() + accuracyTitle = RuuviLocalization.Settings.Temperature.Resolution.title selection = titleProvider.formattedTitle(type: settings.temperatureAccuracy, settings: settings) case .humidity: - accuracyTitle = "Settings.Humidity.Resolution.title".localized() + accuracyTitle = RuuviLocalization.Settings.Humidity.Resolution.title selection = titleProvider.formattedTitle(type: settings.humidityAccuracy, settings: settings) case .pressure: - accuracyTitle = "Settings.Pressure.Resolution.title".localized() + accuracyTitle = RuuviLocalization.Settings.Pressure.Resolution.title selection = titleProvider.formattedTitle(type: settings.pressureAccuracy, settings: settings) default: return nil @@ -172,7 +173,7 @@ extension UnitSettingsPresenter { return SelectionViewModel(title: accuracyTitle, items: selectionItems, - description: "Settings.Measurement.Resolution.description".localized(), + description: RuuviLocalization.Settings.Measurement.Resolution.description, selection: selection, measurementType: measurementType, unitSettingsType: .accuracy) diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift index 3bb68eb99..734f4de5f 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift @@ -1,6 +1,7 @@ import UIKit import RuuviOntology import RuuviLocal +import RuuviLocalization class UnitSettingsTableViewController: UITableViewController { var output: UnitSettingsViewOutput! @@ -66,7 +67,6 @@ extension UnitSettingsTableViewController { super.viewDidLoad() output.viewDidLoad() updateUI() - setupLocalization() } } @@ -85,24 +85,24 @@ extension UnitSettingsTableViewController { } if indexPath.row == 0 { - cell.titleLbl.text = "Settings.Measurement.Unit.title".localized() + cell.titleLbl.text = RuuviLocalization.Settings.Measurement.Unit.title switch viewModel?.measurementType { case .temperature: - cell.valueLbl.text = temperatureUnit.title + cell.valueLbl.text = temperatureUnit.title("") case .humidity: if humidityUnit == .dew { - cell.valueLbl.text = String(format: humidityUnit.title, temperatureUnit.symbol) + cell.valueLbl.text = humidityUnit.title(temperatureUnit.symbol) } else { - cell.valueLbl.text = humidityUnit.title + cell.valueLbl.text = humidityUnit.title("") } case .pressure: - cell.valueLbl.text = pressureUnit.title + cell.valueLbl.text = pressureUnit.title("") default: - cell.valueLbl.text = "N/A".localized() + cell.valueLbl.text = RuuviLocalization.na } } else { - cell.titleLbl.text = "Settings.Measurement.Resolution.title".localized() + cell.titleLbl.text = RuuviLocalization.Settings.Measurement.Resolution.title let titleProvider = MeasurementAccuracyTitles() switch viewModel?.measurementType { case .temperature: @@ -120,7 +120,7 @@ extension UnitSettingsTableViewController { cell.valueLbl.text = titleProvider.formattedTitle(type: pressureAccuracy, settings: settings) + " \(pressureUnit.symbol)" default: - cell.valueLbl.text = "N/A".localized() + cell.valueLbl.text = RuuviLocalization.na } } diff --git a/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift b/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift index ebf527cfe..2474db52c 100644 --- a/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift +++ b/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import Foundation import Future import UIKit @@ -86,9 +87,9 @@ extension SharePresenter: ShareViewOutput { return } let title: String? = nil - let message = String(format: "SharePresenter.UnshareSensor.Message".localized(), email) - let confirmActionTitle = "Yes".localized() - let cancelActionTitle = "No".localized() + let message = RuuviLocalization.SharePresenter.UnshareSensor.message(email) + let confirmActionTitle = RuuviLocalization.yes + let cancelActionTitle = RuuviLocalization.no let confirmAction = UIAlertAction(title: confirmActionTitle, style: .default) { [weak self] (_) in self?.unshareTag(email) diff --git a/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift b/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift index 087fa72f2..bcd178f8e 100644 --- a/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift +++ b/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit extension ShareViewController { enum Section: Int { @@ -18,14 +19,14 @@ extension ShareViewController { } } - var title: String? { + var title: ((Int, Int) -> String)? { switch self { case .description: return nil case .addFriend: - return "ShareViewController.addFriend.Title".localized() + return { _, _ in RuuviLocalization.ShareViewController.AddFriend.title } case .sharedEmails: - return "ShareViewController.sharedEmails.Title".localized() + return { a, b in RuuviLocalization.ShareViewController.SharedEmails.title(a, b) } } } } @@ -51,7 +52,6 @@ class ShareViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() configureTableView() - setupLocalization() setupCustomBackButton() output.viewDidLoad() } @@ -93,12 +93,10 @@ class ShareViewController: UITableViewController { case .sharedEmails: if let count = viewModel.sharedEmails.value?.count, let title = section.title { - titleLabel.text = String(format: title, - count, - viewModel.maxCount) + titleLabel.text = title(count, viewModel.maxCount) } default: - titleLabel.text = section.title + titleLabel.text = section.title?(0, 0) } headerView.addSubview(titleLabel) titleLabel.fillSuperviewToSafeArea( @@ -129,7 +127,7 @@ class ShareViewController: UITableViewController { // MARK: - ShareViewInput extension ShareViewController: ShareViewInput { func localize() { - title = "ShareViewController.Title".localized() + title = RuuviLocalization.ShareViewController.title } func reloadTableView() { @@ -147,21 +145,21 @@ extension ShareViewController: ShareViewInput { func showInvalidEmail() { showAlert( title: nil, - message: "UserApiError.ER_INVALID_EMAIL_ADDRESS".localized() + message: RuuviLocalization.UserApiError.erInvalidEmailAddress ) } func showSuccessfullyShared() { showAlert( title: nil, - message: "Share.Success.message".localized() + message: RuuviLocalization.Share.Success.message ) } func showSuccessfullyInvited() { showAlert( - title: "share_pending".localized(), - message: "share_pending_message".localized() + title: RuuviLocalization.sharePending, + message: RuuviLocalization.sharePendingMessage ) } } @@ -194,10 +192,10 @@ extension ShareViewController { if let canShare = viewModel.canShare.value, canShare { cell.sharingDisabledLabel.text = "" } else { - cell.sharingDisabledLabel.text = "network_sharing_disabled".localized() + cell.sharingDisabledLabel.text = RuuviLocalization.networkSharingDisabled } - let description = "ShareViewController.Description".localized() + let description = RuuviLocalization.ShareViewController.description cell.descriptionLabel.text = description.trimmingCharacters(in: .whitespacesAndNewlines) cell.descriptionLabel.textColor = RuuviColor.ruuviTextColor return cell @@ -206,7 +204,7 @@ extension ShareViewController { private func getAddFriendCell(_ tableView: UITableView, indexPath: IndexPath) -> ShareEmailInputTableViewCell { let cell = tableView.dequeueReusableCell(with: ShareEmailInputTableViewCell.self, for: indexPath) cell.separatorInset = UIEdgeInsets(top: 0, left: tableView.bounds.width, bottom: 0, right: 0) - cell.emailTextField.placeholder = "ShareViewController.emailTextField.placeholder".localized() + cell.emailTextField.placeholder = RuuviLocalization.ShareViewController.EmailTextField.placeholder cell.emailTextField.delegate = self return cell } @@ -214,7 +212,7 @@ extension ShareViewController { private func getButtonCell(_ tableView: UITableView, indexPath: IndexPath) -> ShareSendButtonTableViewCell { let cell = tableView.dequeueReusableCell(with: ShareSendButtonTableViewCell.self, for: indexPath) cell.sendButton.addTarget(self, action: #selector(didTapSendButton(_:)), for: .touchUpInside) - cell.sendButton.setTitle("TagSettings.Share.title".localized(), for: .normal) + cell.sendButton.setTitle(RuuviLocalization.TagSettings.Share.title, for: .normal) cell.separatorInset = UIEdgeInsets(top: 0, left: tableView.bounds.width, bottom: 0, right: 0) return cell } diff --git a/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift b/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift index 653039973..a4d568535 100644 --- a/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift +++ b/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import Foundation import Future import RuuviCloud @@ -141,7 +142,7 @@ extension SignInPresenter { } private func verify(_ code: String) { - activityPresenter.show(with: .loading(message: "SignIn.Sync.message".localized())) + activityPresenter.show(with: .loading(message: RuuviLocalization.SignIn.Sync.message)) ruuviCloud.validateCode(code: code) .on(success: { [weak self] result in guard let sSelf = self else { return } @@ -214,7 +215,7 @@ extension SignInPresenter { @objc private func handleAppEnterForgroundState() { switch state { case .isSyncing: - activityPresenter.show(with: .loading(message: "SignIn.Sync.message".localized())) + activityPresenter.show(with: .loading(message: RuuviLocalization.SignIn.Sync.message)) default: return } diff --git a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift b/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift index 87443f29a..c00ba1137 100644 --- a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift +++ b/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import Foundation import UIKit @@ -36,7 +37,7 @@ class SignInBenefitsViewController: UIViewController, SignInBenefitsViewInput { label.textColor = .white label.textAlignment = .center label.numberOfLines = 0 - label.text = "why_should_sign_in".localized() + label.text = RuuviLocalization.whyShouldSignIn label.font = UIFont.Montserrat(.extraBold, size: UIDevice.isiPhoneSE() ? 24 : 30) return label }() @@ -46,7 +47,7 @@ class SignInBenefitsViewController: UIViewController, SignInBenefitsViewInput { label.textColor = .white label.textAlignment = .center label.numberOfLines = 0 - label.text = "sensors_ownership_and_settings_stored_in_cloud".localized() + label.text = RuuviLocalization.sensorsOwnershipAndSettingsStoredInCloud label.font = UIFont.Muli(.semiBoldItalic, size: UIDevice.isiPhoneSE() ? 16 : 20) return label }() @@ -74,7 +75,7 @@ class SignInBenefitsViewController: UIViewController, SignInBenefitsViewInput { private lazy var continueButton: UIButton = { let button = UIButton(color: RuuviColor.ruuviTintColor, cornerRadius: 25) - button.setTitle("sign_in_continue".localized(), + button.setTitle(RuuviLocalization.signInContinue, for: .normal) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, size: 16) @@ -86,7 +87,7 @@ class SignInBenefitsViewController: UIViewController, SignInBenefitsViewInput { private lazy var signInOptionalLabel: UILabel = { let label = UILabel() - label.text = "signing_in_is_optional".localized() + label.text = RuuviLocalization.signingInIsOptional label.textColor = .white label.textAlignment = .center label.numberOfLines = 0 @@ -223,19 +224,17 @@ extension SignInBenefitsViewController { extension SignInBenefitsViewController { private func prepareFeatures() -> String { return [ - "cloud_stored_ownerships".localized(), - "cloud_stored_names".localized(), - "cloud_stored_alerts".localized(), - "cloud_stored_backgrounds".localized(), - "cloud_stored_calibration".localized(), - "cloud_stored_sharing".localized() + RuuviLocalization.cloudStoredOwnerships, + RuuviLocalization.cloudStoredNames, + RuuviLocalization.cloudStoredAlerts, + RuuviLocalization.cloudStoredBackgrounds, + RuuviLocalization.cloudStoredCalibration, + RuuviLocalization.cloudStoredSharing ].joined(separator: "\n") } private func prepareNote() -> NSMutableAttributedString { - let text = - "note".localized() + " " + - "claim_warning".localized() + let text = RuuviLocalization.note + " " + RuuviLocalization.claimWarning let attrString = NSMutableAttributedString(string: text) let range = NSString(string: attrString.string).range(of: attrString.string) @@ -244,7 +243,7 @@ extension SignInBenefitsViewController { range: range) // Make note bold and orange color - let makeBoldOrange = "note".localized() + let makeBoldOrange = RuuviLocalization.note let boldFont = UIFont.Muli(.bold, size: UIDevice.isiPhoneSE() ? 16 : 18) let boldRange = NSString(string: attrString.string).range(of: makeBoldOrange) attrString.addAttribute(NSAttributedString.Key.font, @@ -256,7 +255,7 @@ extension SignInBenefitsViewController { // Make rest of the text white let regularRange = NSString(string: attrString.string) - .range(of: "claim_warning".localized()) + .range(of: RuuviLocalization.claimWarning) attrString.addAttribute(.foregroundColor, value: UIColor.white, range: regularRange) diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift index 272ef7814..87c09cca8 100644 --- a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift +++ b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit protocol SignInVerifyViewDelegate: NSObjectProtocol { @@ -25,7 +26,7 @@ class SignInVerifyView: UIView { label.textColor = .white label.textAlignment = .center label.numberOfLines = 0 - label.text = "enter_code".localized() + label.text = RuuviLocalization.enterCode label.font = UIFont.Montserrat(.extraBold, size: UIDevice.isiPhoneSE() ? 24 : 30) return label }() @@ -35,7 +36,7 @@ class SignInVerifyView: UIView { label.textColor = .white label.textAlignment = .center label.numberOfLines = 0 - label.text = "SignIn.CheckMailbox".localized() + label.text = RuuviLocalization.SignIn.checkMailbox("") label.font = UIFont.Muli(.semiBoldItalic, size: UIDevice.isiPhoneSE() ? 14 : 18) return label }() @@ -134,7 +135,7 @@ extension SignInVerifyView: RuuviCodeViewDelegate { extension SignInVerifyView { func updateMessage(with email: String?) { guard let email = email else { return } - subtitleLabel.text = String(format: "SignIn.CheckMailbox".localized(), email) + subtitleLabel.text = RuuviLocalization.SignIn.checkMailbox(email) } func populate(from code: String?) { diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift index 60c2181a9..362852cc2 100644 --- a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift +++ b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit protocol SignInViewDelegate: NSObjectProtocol { @@ -25,7 +26,7 @@ class SignInView: UIView { label.textColor = .white label.textAlignment = .center label.numberOfLines = 0 - label.text = "sign_in_or_create_free_account".localized() + label.text = RuuviLocalization.signInOrCreateFreeAccount label.font = UIFont.Montserrat(.extraBold, size: UIDevice.isiPhoneSE() ? 24 : 30) return label @@ -36,7 +37,7 @@ class SignInView: UIView { label.textColor = .white label.textAlignment = .center label.numberOfLines = 0 - label.text = "to_use_all_app_features".localized() + label.text = RuuviLocalization.toUseAllAppFeatures label.font = UIFont.Muli(.semiBoldItalic, size: UIDevice.isiPhoneSE() ? 14 : 18) return label }() @@ -49,7 +50,7 @@ class SignInView: UIView { textField.textColor = .white textField.textAlignment = .left textField.font = UIFont.Muli(.bold, size: UIDevice.isiPhoneSE() ? 14 : 16) - textField.placeholder = "type_your_email".localized() + textField.placeholder = RuuviLocalization.typeYourEmail textField.addPadding(padding: .equalSpacing(16)) textField.setPlaceHolderColor(color: UIColor.darkGray.withAlphaComponent(0.7)) textField.keyboardType = .emailAddress @@ -62,7 +63,7 @@ class SignInView: UIView { private lazy var requestCodeButton: UIButton = { let button = UIButton(color: RuuviColor.ruuviTintColor, cornerRadius: 25) - button.setTitle("request_code".localized(), + button.setTitle(RuuviLocalization.requestCode, for: .normal) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, size: UIDevice.isiPhoneSE() ? 14 : 16) @@ -77,7 +78,7 @@ class SignInView: UIView { label.textColor = .white label.textAlignment = .center label.numberOfLines = 0 - label.text = "no_password_needed".localized() + label.text = RuuviLocalization.noPasswordNeeded label.font = UIFont.Muli(.semiBoldItalic, size: UIDevice.isiPhoneSE() ? 14 : 16) return label }() diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift b/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift index 3a3f76e26..84112bf27 100644 --- a/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift +++ b/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import Foundation import UIKit @@ -46,7 +47,7 @@ class SignInViewController: UIViewController { private lazy var useWithoutAccountButton: UIButton = { let button = UIButton() button.setTitleColor(.white, for: .normal) - button.setTitle("use_without_account".localized(), + button.setTitle(RuuviLocalization.useWithoutAccount, for: .normal) button.titleLabel?.font = UIFont.Muli(.semiBoldItalic, size: 14) button.titleLabel?.numberOfLines = 0 @@ -121,17 +122,16 @@ extension SignInViewController: SignInViewInput { } func showEmailsAreDifferent(requestedEmail: String, validatedEmail: String) { - let format = "SignIn.EmailMismatch.Alert.message".localized() - let message = String(format: format, requestedEmail, validatedEmail, requestedEmail) + let message = RuuviLocalization.SignIn.EmailMismatch.Alert.message(requestedEmail, validatedEmail, requestedEmail) let alertVC = UIAlertController(title: nil, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) + alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) } func showFailedToGetRequestedEmail() { - let message = "SignIn.EmailMissing.Alert.message".localized() + let message = RuuviLocalization.SignIn.EmailMissing.Alert.message let alertVC = UIAlertController(title: nil, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) + alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) } @@ -140,9 +140,9 @@ extension SignInViewController: SignInViewInput { } func showInvalidEmailEntered() { - let message = "UserApiError.ER_INVALID_EMAIL_ADDRESS".localized() + let message = RuuviLocalization.UserApiError.erInvalidEmailAddress let alertVC = UIAlertController(title: nil, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) + alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) } diff --git a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift index 824e6c84a..e77aacd01 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift @@ -1,4 +1,5 @@ // swiftlint:disable file_length +import RuuviLocalization import Foundation import BTKit import UIKit @@ -539,7 +540,7 @@ extension TagSettingsPresenter { if let owner = ruuviTag.owner { viewModel.owner.value = owner } else { - viewModel.owner.value = "TagSettings.General.Owner.none".localized() + viewModel.owner.value = RuuviLocalization.TagSettings.General.Owner.none } // Set isOwner value viewModel.isOwner.value = ruuviTag.isOwner diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift index 9dc412610..c927fe4b6 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift @@ -1,5 +1,6 @@ import RuuviFirmware import SwiftUI +import RuuviLocalization // swiftlint:disable file_length // swiftlint:disable:next type_body_length @@ -8,29 +9,29 @@ struct DFUUIView: View { @ObservedObject var viewModel: DFUViewModel private struct Texts { - let navigationTitle = "DFUUIView.navigationTitle".localized() - let latestTitle = "DFUUIView.latestTitle".localized() - let currentTitle = "DFUUIView.currentTitle".localized() - let lowBatteryWarningMessage = "DFUUIView.lowBattery.warning.message".localized() - let okTitle = "ErrorPresenterAlert.OK".localized() - let notReportingDescription = "DFUUIView.notReportingDescription".localized() - let alreadyOnLatest = "DFUUIView.alreadyOnLatest".localized() - let startUpdateProcess = "DFUUIView.startUpdateProcess".localized() - let downloadingTitle = "DFUUIView.downloadingTitle".localized() - let prepareTitle = "DFUUIView.prepareTitle".localized() - let openCoverTitle = "DFUUIView.openCoverTitle".localized() - let localBootButtonTitle = "DFUUIView.locateBootButtonTitle".localized() - let setUpdatingModeTitle = "DFUUIView.setUpdatingModeTitle".localized() - let toBootModeTwoButtonsDescription = "DFUUIView.toBootModeTwoButtonsDescription".localized() - let toBootModeOneButtonDescription = "DFUUIView.toBootModeOneButtonDescription".localized() - let toBootModeSuccessTitle = "DFUUIView.toBootModeSuccessTitle".localized() - let updatingTitle = "DFUUIView.updatingTitle".localized() - let searchingTitle = "DFUUIView.searchingTitle".localized() - let startTitle = "DFUUIView.startTitle".localized() - let doNotCloseTitle = "DFUUIView.doNotCloseTitle".localized() - let successfulTitle = "DFUUIView.successfulTitle".localized() - let errorTitle = "ErrorPresenterAlert.Error".localized() - let dbMigrationErrorTitle = "DFUUIView.DBMigration.Error.message".localized() + let navigationTitle = RuuviLocalization.DFUUIView.navigationTitle + let latestTitle = RuuviLocalization.DFUUIView.latestTitle + let currentTitle = RuuviLocalization.DFUUIView.currentTitle + let lowBatteryWarningMessage = RuuviLocalization.DFUUIView.LowBattery.Warning.message + let okTitle = RuuviLocalization.ErrorPresenterAlert.ok + let notReportingDescription = RuuviLocalization.DFUUIView.notReportingDescription + let alreadyOnLatest = RuuviLocalization.DFUUIView.alreadyOnLatest + let startUpdateProcess = RuuviLocalization.DFUUIView.startUpdateProcess + let downloadingTitle = RuuviLocalization.DFUUIView.downloadingTitle + let prepareTitle = RuuviLocalization.DFUUIView.prepareTitle + let openCoverTitle = RuuviLocalization.DFUUIView.openCoverTitle + let localBootButtonTitle = RuuviLocalization.DFUUIView.locateBootButtonTitle + let setUpdatingModeTitle = RuuviLocalization.DFUUIView.setUpdatingModeTitle + let toBootModeTwoButtonsDescription = RuuviLocalization.DFUUIView.toBootModeTwoButtonsDescription + let toBootModeOneButtonDescription = RuuviLocalization.DFUUIView.toBootModeOneButtonDescription + let toBootModeSuccessTitle = RuuviLocalization.DFUUIView.toBootModeSuccessTitle + let updatingTitle = RuuviLocalization.DFUUIView.updatingTitle + let searchingTitle = RuuviLocalization.DFUUIView.searchingTitle + let startTitle = RuuviLocalization.DFUUIView.startTitle + let doNotCloseTitle = RuuviLocalization.DFUUIView.doNotCloseTitle + let successfulTitle = RuuviLocalization.DFUUIView.successfulTitle + let errorTitle = RuuviLocalization.ErrorPresenterAlert.error + let dbMigrationErrorTitle = RuuviLocalization.DFUUIView.DBMigration.Error.message } private let muliBold16 = Font(UIFont.Muli(.bold, size: 16)) diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift index 5543a2fe3..9817204a9 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit import CoreNFC import RuuviOntology @@ -21,7 +22,7 @@ class SensorForceClaimViewController: UIViewController { label.textColor = RuuviColor.ruuviTextColor label.textAlignment = .left label.numberOfLines = 0 - label.text = "force_claim_sensor_description1".localized() + label.text = RuuviLocalization.forceClaimSensorDescription1 label.font = UIFont.Muli(.regular, size: 16) return label }() @@ -29,7 +30,7 @@ class SensorForceClaimViewController: UIViewController { private lazy var claimSensorButton: UIButton = { let button = UIButton(color: RuuviColor.ruuviTintColor, cornerRadius: 25) - button.setTitle("force_claim".localized(), for: .normal) + button.setTitle(RuuviLocalization.forceClaim, for: .normal) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, size: 16) button.addTarget(self, @@ -46,7 +47,7 @@ class SensorForceClaimViewController: UIViewController { tv.isSelectable = false tv.isEditable = false tv.textAlignment = .left - tv.text = "force_claim_sensor_description2".localized() + tv.text = RuuviLocalization.forceClaimSensorDescription2 tv.textColor = RuuviColor.ruuviTextColor tv.backgroundColor = .clear tv.font = UIFont.Muli(.regular, size: 16) @@ -58,7 +59,7 @@ class SensorForceClaimViewController: UIViewController { let button = UIButton(color: RuuviColor.ruuviTintColor, cornerRadius: 25) button.setTitle( - "use_nfc".localized(), + RuuviLocalization.useNfc, for: .normal ) button.setTitleColor(.white, for: .normal) @@ -73,7 +74,7 @@ class SensorForceClaimViewController: UIViewController { let button = UIButton(color: RuuviColor.ruuviTintColor, cornerRadius: 25) button.setTitle( - "use_bluetooth".localized(), + RuuviLocalization.useBluetooth, for: .normal ) button.setTitleColor(.white, for: .normal) @@ -135,12 +136,12 @@ extension SensorForceClaimViewController: SensorForceClaimViewInput { } func showGATTConnectionTimeoutDialog() { - let message = "sensor_not_found_error".localized() + let message = RuuviLocalization.sensorNotFoundError let controller = UIAlertController( title: nil, message: message, preferredStyle: .alert ) controller.addAction( - UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil) + UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil) ) present(controller, animated: true) } @@ -155,7 +156,7 @@ extension SensorForceClaimViewController { } private func setUpBase() { - self.title = "force_claim_sensor".localized() + self.title = RuuviLocalization.forceClaimSensor view.backgroundColor = RuuviColor.ruuviPrimary diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift index 7587af092..efb698e25 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift @@ -1,5 +1,6 @@ import UIKit import RuuviOntology +import RuuviLocalization import RuuviService #if canImport(RuuviServiceMeasurement) import RuuviServiceMeasurement @@ -48,7 +49,6 @@ class OffsetCorrectionAppleViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - setupLocalization() timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { [weak self] (_) in if let updateAt = self?.updatedAt { @@ -93,7 +93,7 @@ class OffsetCorrectionAppleViewController: UIViewController { originalValueLabel.bind(viewModel.originalValue) { [weak self] label, value in switch self?.viewModel.type { case .humidity: - label.text = "\((value.bound * 100).round(to: 2))\("%".localized())" + label.text = "\((value.bound * 100).round(to: 2))%)" case .pressure: label.text = self?.measurementService.string(for: Pressure(value, unit: .hectopascals), allowSettings: false) @@ -124,7 +124,7 @@ class OffsetCorrectionAppleViewController: UIViewController { correctedValueLabel.bind(viewModel.correctedValue) { [weak self] label, value in switch self?.viewModel.type { case .humidity: - label.text = "\((value.bound * 100).round(to: 2))\("%".localized())" + label.text = "\((value.bound * 100).round(to: 2))%" case .pressure: label.text = self?.measurementService.string(for: Pressure(value, unit: .hectopascals), allowSettings: false) @@ -139,15 +139,15 @@ class OffsetCorrectionAppleViewController: UIViewController { extension OffsetCorrectionAppleViewController: OffsetCorrectionViewInput { func localize() { configDescriptionContent() - correctedValueTitle.text = "OffsetCorrection.CorrectedValue.title".localized() - originalValueTitle.text = "OffsetCorrection.OriginalValue.title".localized() - calibrateButton.setTitle("HumidityCalibration.Button.Calibrate.title".localized(), for: .normal) - clearButton.setTitle("HumidityCalibration.Button.Clear.title".localized(), for: .normal) + correctedValueTitle.text = RuuviLocalization.OffsetCorrection.CorrectedValue.title + originalValueTitle.text = RuuviLocalization.OffsetCorrection.OriginalValue.title + calibrateButton.setTitle(RuuviLocalization.HumidityCalibration.Button.Calibrate.title, for: .normal) + clearButton.setTitle(RuuviLocalization.HumidityCalibration.Button.Clear.title, for: .normal) self.title = self.viewModel.title } private func configDescriptionContent() { - let text = "OffsetCorrection.CalibrationDescription.text".localized() + let text = RuuviLocalization.OffsetCorrection.CalibrationDescription.text let attrString = NSMutableAttributedString(string: text) let muliRegular = UIFont.Muli(.regular, size: 16) @@ -163,46 +163,45 @@ extension OffsetCorrectionAppleViewController: OffsetCorrectionViewInput { } func showCalibrateDialog() { - let title = "OffsetCorrection.Dialog.Calibration.Title".localized() + let title = RuuviLocalization.OffsetCorrection.Dialog.Calibration.title var message = "" switch self.viewModel.type { case .humidity: - let format = "OffsetCorrection.Dialog.Calibration.EnterHumidity".localized() - message = String(format: format, "%".localized()) + message = RuuviLocalization.OffsetCorrection.Dialog.Calibration.enterHumidity("%") case .pressure: - let format = "OffsetCorrection.Dialog.Calibration.EnterPressure".localized() + let format = RuuviLocalization.OffsetCorrection.Dialog.Calibration.enterPressure let unit = self.viewModel.pressureUnit.value ?? .hectopascals - message = String(format: format, unit.symbol) + message = format(unit.symbol) default: - let format = "OffsetCorrection.Dialog.Calibration.EnterTemperature".localized() + let format = RuuviLocalization.OffsetCorrection.Dialog.Calibration.enterTemperature let unit = self.viewModel.temperatureUnit.value ?? .celsius - message = String(format: format, unit.symbol) + message = format(unit.symbol) } let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) controller.addTextField { textfield in textfield.keyboardType = .numbersAndPunctuation } - controller.addAction(UIAlertAction(title: "Confirm".localized(), + controller.addAction(UIAlertAction(title: RuuviLocalization.confirm, style: .destructive, handler: { [weak self] _ in let text = controller.textFields?.first?.text ?? "0.0" self?.output.viewDidSetCorrectValue(correctValue: text.doubleValue) })) - controller.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil)) + controller.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) present(controller, animated: true) } func showClearConfirmationDialog() { - let title = "OffsetCorrection.Dialog.Calibration.Title".localized() - let message = "OffsetCorrection.Dialog.Calibration.ClearConfirm".localized() + let title = RuuviLocalization.OffsetCorrection.Dialog.Calibration.title + let message = RuuviLocalization.OffsetCorrection.Dialog.Calibration.clearConfirm let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: "Confirm".localized(), + controller.addAction(UIAlertAction(title: RuuviLocalization.confirm, style: .destructive, handler: { [weak self] _ in self?.output.viewDidClearOffsetValue() })) - controller.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil)) + controller.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) present(controller, animated: true) } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift index b2f41cf1e..d9da13165 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift @@ -3,6 +3,7 @@ import BTKit import Humidity import RuuviOntology import RuuviLocal +import RuuviLocalization class OffsetCorrectionViewModel { var type: OffsetCorrectionType = .temperature @@ -20,11 +21,11 @@ class OffsetCorrectionViewModel { var title: String { switch type { case .humidity: - return "OffsetCorrection.Humidity.Title".localized() + return RuuviLocalization.OffsetCorrection.Humidity.title case .pressure: - return "OffsetCorrection.Pressure.Title".localized() + return RuuviLocalization.OffsetCorrection.Pressure.title default: - return "OffsetCorrection.Temperature.Title".localized() + return RuuviLocalization.OffsetCorrection.Temperature.title } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift index dd9ed2b0a..ba8aece2a 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit final class OwnerViewController: UIViewController { @@ -11,7 +12,7 @@ final class OwnerViewController: UIViewController { private lazy var removeCloudHistoryTitleLabel: UILabel = { let label = UILabel() - label.text = "remove_cloud_history_title".localized() + label.text = RuuviLocalization.removeCloudHistoryTitle label.textColor = RuuviColor.ruuviTextColor label.textAlignment = .left label.numberOfLines = 0 @@ -21,7 +22,7 @@ final class OwnerViewController: UIViewController { private lazy var removeCloudHistoryDescriptionLabel: UILabel = { let label = UILabel() - label.text = "remove_cloud_history_description".localized() + label.text = RuuviLocalization.removeCloudHistoryDescription label.textColor = RuuviColor.ruuviTextColor label.textAlignment = .left label.numberOfLines = 0 @@ -58,7 +59,6 @@ final class OwnerViewController: UIViewController { super.viewDidLoad() setUpCustomBackButton() setUpCloudHistoryContentView() - setupLocalization() output.viewDidTriggerFirmwareUpdateDialog() } } @@ -66,11 +66,11 @@ final class OwnerViewController: UIViewController { extension OwnerViewController: OwnerViewInput { func showSensorAlreadyClaimedDialog() { let alertVC = UIAlertController( - title: "ErrorPresenterAlert.Error".localized(), - message: "UserApiError.ER_SENSOR_ALREADY_CLAIMED_NO_EMAIL".localized(), + title: RuuviLocalization.ErrorPresenterAlert.error, + message: RuuviLocalization.UserApiError.erSensorAlreadyClaimedNoEmail, preferredStyle: .alert ) - alertVC.addAction(UIAlertAction(title: "OK".localized(), style: .default, handler: { + alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .default, handler: { [weak self] _ in // TODO: - Update with masked email once backend is adjusted. self?.output.updateOwnerInfo(with: "*****") @@ -82,13 +82,13 @@ extension OwnerViewController: OwnerViewInput { // No op. switch mode { case .claim: - title = "Owner.title".localized() - claimOwnershipDescriptionLabel.text = "Owner.Claim.description".localized() - claimOwnershipButton.setTitle("Owner.ClaimOwnership.button".localized().capitalized, for: .normal) + title = RuuviLocalization.Owner.title + claimOwnershipDescriptionLabel.text = RuuviLocalization.Owner.Claim.description + claimOwnershipButton.setTitle(RuuviLocalization.Owner.ClaimOwnership.button.capitalized, for: .normal) case .unclaim: - title = "unclaim_sensor".localized() - claimOwnershipDescriptionLabel.text = "unclaim_sensor_description".localized() - claimOwnershipButton.setTitle("unclaim".localized().capitalized, for: .normal) + title = RuuviLocalization.unclaimSensor + claimOwnershipDescriptionLabel.text = RuuviLocalization.unclaimSensorDescription + claimOwnershipButton.setTitle(RuuviLocalization.unclaim.capitalized, for: .normal) } removeCloudHistoryContainerVisibleConstraint.isActive = mode == .unclaim removeCloudHistoryContainerHiddenConstraint.isActive = mode == .claim @@ -97,13 +97,13 @@ extension OwnerViewController: OwnerViewInput { } func showFirmwareUpdateDialog() { - let message = "Cards.LegacyFirmwareUpdateDialog.message".localized() + let message = RuuviLocalization.Cards.LegacyFirmwareUpdateDialog.message let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) - let dismissTitle = "Cards.KeepConnectionDialog.Dismiss.title".localized() + let dismissTitle = RuuviLocalization.Cards.KeepConnectionDialog.Dismiss.title alert.addAction(UIAlertAction(title: dismissTitle, style: .cancel, handler: { [weak self] _ in self?.output.viewDidIgnoreFirmwareUpdateDialog() })) - let checkForUpdateTitle = "Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title".localized() + let checkForUpdateTitle = RuuviLocalization.Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title alert.addAction(UIAlertAction(title: checkForUpdateTitle, style: .default, handler: { [weak self] _ in self?.output.viewDidConfirmFirmwareUpdate() })) @@ -111,11 +111,11 @@ extension OwnerViewController: OwnerViewInput { } func showFirmwareDismissConfirmationUpdateDialog() { - let message = "Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message".localized() + let message = RuuviLocalization.Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) - let dismissTitle = "Cards.KeepConnectionDialog.Dismiss.title".localized() + let dismissTitle = RuuviLocalization.Cards.KeepConnectionDialog.Dismiss.title alert.addAction(UIAlertAction(title: dismissTitle, style: .cancel, handler: nil)) - let checkForUpdateTitle = "Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title".localized() + let checkForUpdateTitle = RuuviLocalization.Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title alert.addAction(UIAlertAction(title: checkForUpdateTitle, style: .default, handler: { [weak self] _ in self?.output.viewDidConfirmFirmwareUpdate() })) @@ -123,16 +123,16 @@ extension OwnerViewController: OwnerViewInput { } func showUnclaimHistoryDataRemovalConfirmationDialog() { - let title = "dialog_are_you_sure".localized() - let message = "dialog_operation_undone".localized() + let title = RuuviLocalization.dialogAreYouSure + let message = RuuviLocalization.dialogOperationUndone let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: "Confirm".localized(), + controller.addAction(UIAlertAction(title: RuuviLocalization.confirm, style: .destructive, handler: { [weak self] _ in guard let self = self else { return } self.output?.viewDidConfirmUnclaim(removeCloudHistory: self.removeCloudHistorySwitch.isOn) })) - controller.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil)) + controller.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) present(controller, animated: true) } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift index 509e88eb6..10409a932 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit import CoreNFC import RuuviOntology @@ -28,7 +29,7 @@ class SensorRemovalViewController: UIViewController { private var removeCloudHistoryActionContainer = UIView.init(color: .clear) private lazy var removeCloudHistoryTitleLabel: UILabel = { let label = UILabel() - label.text = "remove_cloud_history_title".localized() + label.text = RuuviLocalization.removeCloudHistoryTitle label.textColor = RuuviColor.ruuviTextColor label.textAlignment = .left label.numberOfLines = 0 @@ -38,7 +39,7 @@ class SensorRemovalViewController: UIViewController { private lazy var removeCloudHistoryDescriptionLabel: UILabel = { let label = UILabel() - label.text = "remove_cloud_history_description".localized() + label.text = RuuviLocalization.removeCloudHistoryDescription label.textColor = RuuviColor.ruuviTextColor label.textAlignment = .left label.numberOfLines = 0 @@ -55,7 +56,7 @@ class SensorRemovalViewController: UIViewController { private lazy var removeButton: UIButton = { let button = UIButton(color: RuuviColor.ruuviTintColor, cornerRadius: 25) - button.setTitle("Remove".localized(), for: .normal) + button.setTitle(RuuviLocalization.remove, for: .normal) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, size: 16) button.addTarget(self, @@ -90,15 +91,15 @@ extension SensorRemovalViewController: SensorRemovalViewInput { func updateView(claimedAndOwned: Bool, locallyOwned: Bool, shared: Bool) { var message: String = "" if claimedAndOwned { - message = "remove_claimed_sensor_description".localized() + message = RuuviLocalization.removeClaimedSensorDescription } if locallyOwned { - message = "remove_local_sensor_description".localized() + message = RuuviLocalization.removeLocalSensorDescription } if shared { - message = "remove_shared_sensor_description".localized() + message = RuuviLocalization.removeSharedSensorDescription } messageLabel.text = message @@ -110,16 +111,16 @@ extension SensorRemovalViewController: SensorRemovalViewInput { } func showHistoryDataRemovalConfirmationDialog() { - let title = "dialog_are_you_sure".localized() - let message = "dialog_operation_undone".localized() + let title = RuuviLocalization.dialogAreYouSure + let message = RuuviLocalization.dialogOperationUndone let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: "Confirm".localized(), + controller.addAction(UIAlertAction(title: RuuviLocalization.confirm, style: .destructive, handler: { [weak self] _ in guard let self = self else { return } self.output?.viewDidConfirmTagRemoval(with: self.removeCloudHistorySwitch.isOn) })) - controller.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil)) + controller.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) present(controller, animated: true) } } @@ -132,7 +133,7 @@ extension SensorRemovalViewController { } private func setUpBase() { - self.title = "TagSettings.confirmTagRemovalDialog.title".localized() + self.title = RuuviLocalization.TagSettings.ConfirmTagRemovalDialog.title view.backgroundColor = RuuviColor.ruuviPrimary diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift index cb56d5a8b..72d3dd88a 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift @@ -1,5 +1,6 @@ import UIKit import RangeSeekSlider +import RuuviLocalization protocol TagSettingsAlertConfigCellDelegate: AnyObject { func didSelectSetCustomDescription(sender: TagSettingsAlertConfigCell) @@ -39,7 +40,7 @@ class TagSettingsAlertConfigCell: UITableViewCell { private lazy var statusLabel: UILabel = { let label = UILabel() - label.text = "Off".localized() + label.text = RuuviLocalization.off label.textAlignment = .right label.numberOfLines = 0 label.textColor = .label @@ -246,7 +247,7 @@ extension TagSettingsAlertConfigCell { extension TagSettingsAlertConfigCell { func setStatus(with value: Bool?) { if let value = value { - statusLabel.text = value ? "On".localized() : "Off".localized() + statusLabel.text = value ? RuuviLocalization.on : RuuviLocalization.off statusSwitch.setOn(value, animated: false) } } diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift index a5877a805..883bfe40f 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift @@ -1,4 +1,5 @@ import UIKit +import RuuviLocalization // swiftlint:disable:next type_name protocol TagSettingsBackgroundSelectionViewDelegate: NSObjectProtocol { @@ -16,7 +17,7 @@ class TagSettingsBackgroundSelectionView: UIView { label.textAlignment = .center label.numberOfLines = 0 label.font = UIFont.Muli(.bold, size: 14) - label.text = "change_background_image".localized() + label.text = RuuviLocalization.changeBackgroundImage return label }() diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift index b2c4d68f6..b5dec9ba9 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift @@ -1,5 +1,6 @@ import UIKit import RuuviOntology +import RuuviLocalization // swiftlint:disable:next type_name protocol TagSettingsExpandableSectionHeaderDelegate: NSObjectProtocol { @@ -50,7 +51,7 @@ class TagSettingsExpandableSectionHeader: UIView { private lazy var noValueContainer = UIView(color: .clear) private lazy var noValueLabel: UILabel = { let label = UILabel() - label.text = "TagSettings.Label.noValues.text".localized() + label.text = RuuviLocalization.TagSettings.Label.NoValues.text label.textColor = RuuviColor.ruuviTextColor label.textAlignment = .right label.numberOfLines = 0 diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift index 63bfd2f85..284f4bb2a 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift @@ -1,5 +1,6 @@ // swiftlint:disable file_length import UIKit +import RuuviLocalization import RuuviOntology import RuuviService @@ -128,13 +129,13 @@ class TagSettingsViewController: UIViewController { private var cloudConnectionAlertDelayTextField = UITextField() private let cloudConnectionAlertDelayCharaterLimit: Int = 2 - private let pairedString = "TagSettings.PairAndBackgroundScan.Paired.title".localized() - private let pairingString = "TagSettings.PairAndBackgroundScan.Pairing.title".localized() - private let unpairedString = "TagSettings.PairAndBackgroundScan.Unpaired.title".localized() + private let pairedString = RuuviLocalization.TagSettings.PairAndBackgroundScan.Paired.title + private let pairingString = RuuviLocalization.TagSettings.PairAndBackgroundScan.Pairing.title + private let unpairedString = RuuviLocalization.TagSettings.PairAndBackgroundScan.Unpaired.title - private let temperatureAlertFormat = "TagSettings.temperatureAlertTitleLabel.text".localized() - private let airHumidityAlertFormat = "TagSettings.AirHumidityAlert.title".localized() - private let pressureAlertFormat = "TagSettings.PressureAlert.title".localized() + private let temperatureAlertFormat = RuuviLocalization.TagSettings.TemperatureAlertTitleLabel.text + private let airHumidityAlertFormat = RuuviLocalization.TagSettings.AirHumidityAlert.title + private let pressureAlertFormat = RuuviLocalization.TagSettings.PressureAlert.title // Cell static let ReuseIdentifier = "SettingsCell" @@ -172,9 +173,8 @@ class TagSettingsViewController: UIViewController { }() private lazy var temperatureAlertSection: TagSettingsSection? = { - let sectionTitle = String( - format: temperatureAlertFormat, - viewModel?.temperatureUnit.value?.symbol ?? "N/A".localized() + let sectionTitle = temperatureAlertFormat( + viewModel?.temperatureUnit.value?.symbol ?? RuuviLocalization.na ) let section = TagSettingsSection( identifier: .alertTemperature, @@ -199,7 +199,7 @@ class TagSettingsViewController: UIViewController { }() private lazy var humidityAlertSection: TagSettingsSection? = { let symbol = HumidityUnit.percent.symbol - let sectionTitle = String(format: airHumidityAlertFormat, symbol) + let sectionTitle = airHumidityAlertFormat(symbol) let section = TagSettingsSection( identifier: .alertHumidity, title: sectionTitle, @@ -221,9 +221,8 @@ class TagSettingsViewController: UIViewController { return TagSettingsExpandableSectionHeader() }() private lazy var pressureAlertSection: TagSettingsSection? = { - let sectionTitle = String( - format: pressureAlertFormat, - viewModel?.pressureUnit.value?.symbol ?? "N/A".localized() + let sectionTitle = pressureAlertFormat( + viewModel?.pressureUnit.value?.symbol ?? RuuviLocalization.na ) let section = TagSettingsSection( identifier: .alertPressure, @@ -675,7 +674,7 @@ extension TagSettingsViewController { let availableItems = itemsForGeneralSection() let section = TagSettingsSection( identifier: .general, - title: "TagSettings.SectionHeader.General.title".localized().capitalized, + title: RuuviLocalization.TagSettings.SectionHeader.General.title.capitalized, cells: availableItems, collapsed: false, headerType: .simple @@ -687,7 +686,7 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( identifier: .generalName, createdCell: { [weak self] in - self?.tagNameCell?.configure(title: "TagSettings.tagNameTitleLabel.text".localized(), + self?.tagNameCell?.configure(title: RuuviLocalization.TagSettings.TagNameTitleLabel.text, value: self?.viewModel?.name.value) self?.tagNameCell?.setAccessory(type: .pencil) return self?.tagNameCell ?? UITableViewCell() @@ -703,7 +702,7 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( identifier: .generalOwner, createdCell: { [weak self] in - self?.tagOwnerCell?.configure(title: "TagSettings.NetworkInfo.Owner".localized(), + self?.tagOwnerCell?.configure(title: RuuviLocalization.TagSettings.NetworkInfo.owner, value: self?.viewModel?.owner.value) self?.tagOwnerCell?.setAccessory(type: .chevron) self?.tagOwnerCell?.hideSeparator(hide: false) @@ -720,8 +719,10 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( identifier: .generalOwnersPlan, createdCell: { [weak self] in - self?.tagOwnersPlanCell?.configure(title: "owners_plan".localized(), - value: self?.viewModel?.ownersPlan.value) + self?.tagOwnersPlanCell?.configure( + title: RuuviLocalization.ownersPlan, + value: self?.viewModel?.ownersPlan.value + ) self?.tagOwnersPlanCell?.setAccessory(type: .none) self?.tagOwnersPlanCell?.hideSeparator(hide: !GlobalHelpers.getBool(from: self?.showShare())) return self?.tagOwnersPlanCell ?? UITableViewCell() @@ -736,7 +737,7 @@ extension TagSettingsViewController { identifier: .generalShare, createdCell: { [weak self] in self?.tagShareCell?.configure( - title: "TagSettings.Share.title".localized(), + title: RuuviLocalization.TagSettings.Share.title, value: self?.sensorSharedTo( from: self?.viewModel?.sharedTo.value ) @@ -767,14 +768,9 @@ extension TagSettingsViewController { private func sensorSharedTo(from: [String]?) -> String { let maxShareCount = 10 if let sharedTo = from, sharedTo.count > 0 { - let format = "shared_to_x".localized() - return String( - format: format, - sharedTo.count, - maxShareCount - ) + return RuuviLocalization.sharedToX(sharedTo.count, maxShareCount) } else { - return "TagSettings.NotShared.title".localized() + return RuuviLocalization.TagSettings.NotShared.title } } } @@ -845,7 +841,7 @@ extension TagSettingsViewController: TagSettingsSwitchCellDelegate { let section = TagSettingsSection( identifier: .btPair, - title: "TagSettings.SectionHeader.BTConnection.title".localized().capitalized, + title: RuuviLocalization.TagSettings.SectionHeader.BTConnection.title.capitalized, cells: [ tagPairSettingItem(), tagPairFooterItem() @@ -886,7 +882,7 @@ extension TagSettingsViewController: TagSettingsSwitchCellDelegate { let settingItem = TagSettingsItem( createdCell: { let cell = TagSettingsFooterCell(style: .value1, reuseIdentifier: Self.ReuseIdentifier) - cell.configure(value: "TagSettings.PairAndBackgroundScan.description".localized()) + cell.configure(value: RuuviLocalization.TagSettings.PairAndBackgroundScan.description) return cell }, action: nil @@ -914,9 +910,8 @@ extension TagSettingsViewController { // Temperature tableView.bind(viewModel.temperatureUnit) { [weak self] _, value in guard let sSelf = self else { return } - sSelf.temperatureAlertSection?.title = String( - format: sSelf.temperatureAlertFormat, - value?.symbol ?? "N/A".localized() + sSelf.temperatureAlertSection?.title = sSelf.temperatureAlertFormat( + value?.symbol ?? RuuviLocalization.na ) } @@ -965,8 +960,9 @@ extension TagSettingsViewController { temperatureAlertSectionHeaderView.bind(viewModel.temperatureUnit) { [weak self] header, unit in guard let sSelf = self else { return } - let sectionTitle = String(format: sSelf.temperatureAlertFormat, - unit?.symbol ?? "N/A".localized()) + let sectionTitle = sSelf.temperatureAlertFormat( + unit?.symbol ?? RuuviLocalization.na + ) header.setTitle(with: sectionTitle) } @@ -1078,9 +1074,8 @@ extension TagSettingsViewController { // Pressure tableView.bind(viewModel.pressureUnit) { [weak self] _, value in guard let sSelf = self else { return } - sSelf.pressureAlertSection?.title = String( - format: sSelf.pressureAlertFormat, - value?.symbol ?? "N/A".localized() + sSelf.pressureAlertSection?.title = sSelf.pressureAlertFormat( + value?.symbol ?? RuuviLocalization.na ) } @@ -1133,9 +1128,8 @@ extension TagSettingsViewController { pressureAlertSectionHeaderView.bind(viewModel.pressureUnit) { [weak self ] header, unit in guard let sSelf = self else { return } - let sectionTitle = String( - format: sSelf.pressureAlertFormat, - unit?.symbol ?? "N/A".localized() + let sectionTitle = sSelf.pressureAlertFormat( + unit?.symbol ?? RuuviLocalization.na ) header.setTitle(with: sectionTitle) } @@ -1417,7 +1411,7 @@ extension TagSettingsViewController { let section = TagSettingsSection( identifier: .alertHeader, - title: "TagSettings.Label.alerts.text".localized().capitalized, + title: RuuviLocalization.TagSettings.Label.Alerts.text.capitalized, cells: [], collapsed: false, headerType: .simple @@ -1532,7 +1526,7 @@ extension TagSettingsViewController { private func configureRSSIAlertSection() -> TagSettingsSection { let section = TagSettingsSection( identifier: .alertRSSI, - title: "signal_strength_dbm".localized(), + title: RuuviLocalization.signalStrengthDbm, cells: [ rssiAlertItem() ], @@ -1549,7 +1543,7 @@ extension TagSettingsViewController { createdCell: { [weak self] in self?.rssiAlertCell?.showNoticeView() self?.rssiAlertCell? - .setNoticeText(with: "rssi_alert_description".localized()) + .setNoticeText(with: RuuviLocalization.rssiAlertDescription) self?.rssiAlertCell?.showAlertRangeSetter() self?.rssiAlertCell? .setStatus(with: self?.viewModel?.isSignalAlertOn.value) @@ -1579,7 +1573,7 @@ extension TagSettingsViewController { private func configureMovementAlertSection() -> TagSettingsSection { let section = TagSettingsSection( identifier: .alertMovement, - title: "TagSettings.MovementAlert.title".localized(), + title: RuuviLocalization.TagSettings.MovementAlert.title, cells: [ movementAlertItem() ], @@ -1595,7 +1589,7 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( createdCell: { [weak self] in self?.movementAlertCell? - .setAlertAddtionalText(with: "TagSettings.Alerts.Movement.description".localized()) + .setAlertAddtionalText(with: RuuviLocalization.TagSettings.Alerts.Movement.description) self?.movementAlertCell?.hideAlertRangeSetter() self?.movementAlertCell?.hideNoticeView() self?.movementAlertCell?.showAdditionalTextview() @@ -1615,7 +1609,7 @@ extension TagSettingsViewController { private func configureConnectionAlertSection() -> TagSettingsSection { let section = TagSettingsSection( identifier: .alertConnection, - title: "TagSettings.ConnectionAlert.title".localized(), + title: RuuviLocalization.TagSettings.ConnectionAlert.title, cells: [ connectionAlertItem() ], @@ -1630,7 +1624,7 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( createdCell: { [weak self] in self?.connectionAlertCell? - .setAlertAddtionalText(with: "TagSettings.Alerts.Connection.description".localized()) + .setAlertAddtionalText(with: RuuviLocalization.TagSettings.Alerts.Connection.description) self?.connectionAlertCell?.hideAlertRangeSetter() self?.connectionAlertCell?.hideNoticeView() self?.connectionAlertCell?.showAdditionalTextview() @@ -1650,7 +1644,7 @@ extension TagSettingsViewController { private func configureCloudConnectionAlertSection() -> TagSettingsSection { let section = TagSettingsSection( identifier: .alertCloudConnection, - title: "alert_cloud_connection_title".localized(), + title: RuuviLocalization.alertCloudConnectionTitle, cells: [ cloudConnectionAlertItem() ], @@ -1786,14 +1780,14 @@ extension TagSettingsViewController { } private func alertCustomDescription(from string: String?) -> String? { - let alertPlaceholder = "TagSettings.Alert.CustomDescription.placeholder".localized() + let alertPlaceholder = RuuviLocalization.TagSettings.Alert.CustomDescription.placeholder return string.hasText() ? string : alertPlaceholder } private func temperatureAlertRangeDescription(from min: CGFloat? = nil, max: CGFloat? = nil) -> NSMutableAttributedString? { guard isViewLoaded else { return nil } - var format = "TagSettings.Alerts.Temperature.description".localized() + var format = RuuviLocalization.TagSettings.Alerts.Temperature.description if let min = min, let max = max { return attributedString(from: String(format: format, locale: Locale.autoupdatingCurrent, @@ -1863,7 +1857,7 @@ extension TagSettingsViewController { private func humidityAlertRangeDescription(from min: CGFloat? = nil, max: CGFloat? = nil) -> NSMutableAttributedString? { guard isViewLoaded else { return nil } - var format = "TagSettings.Alerts.Temperature.description".localized() + var format = RuuviLocalization.TagSettings.Alerts.Temperature.description if let min = min, let max = max { return attributedString(from: String(format: format, locale: Locale.autoupdatingCurrent, @@ -1919,7 +1913,7 @@ extension TagSettingsViewController { private func pressureAlertRangeDescription(from minValue: CGFloat? = nil, maxValue: CGFloat? = nil) -> NSMutableAttributedString? { guard isViewLoaded else { return nil } - var format = "TagSettings.Alerts.Temperature.description".localized() + var format = RuuviLocalization.TagSettings.Alerts.Temperature.description if let minValue = minValue, let maxValue = maxValue { return attributedString(from: String(format: format, @@ -2000,7 +1994,7 @@ extension TagSettingsViewController { private func rssiAlertRangeDescription(from min: CGFloat? = nil, max: CGFloat? = nil) -> NSMutableAttributedString? { guard isViewLoaded else { return nil } - let format = "TagSettings.Alerts.Temperature.description".localized() + let format = RuuviLocalization.TagSettings.Alerts.Temperature.description if let min = min, let max = max { return attributedString(from: String(format: format, @@ -2071,12 +2065,8 @@ extension TagSettingsViewController { from delay: Int? = nil ) -> NSMutableAttributedString? { guard isViewLoaded else { return nil } - let format = "alert_cloud_connection_description".localized() - if let delay = delay { - return attributedString(from: String(format: format, - locale: Locale.autoupdatingCurrent, - delay)) + return attributedString(from: RuuviLocalization.alertCloudConnectionDescription(delay)) } else { return nil } @@ -2287,7 +2277,7 @@ extension TagSettingsViewController: TagSettingsAlertConfigCellDelegate { extension TagSettingsViewController { private func showTemperatureAlertSetPopup(sender: TagSettingsAlertConfigCell) { let temperatureUnit = viewModel?.temperatureUnit.value ?? .celsius - let titleFormat = "TagSettings.Alert.SetTemperature.title".localized() + let titleFormat = RuuviLocalization.TagSettings.Alert.SetTemperature.title let title = titleFormat + " (\(temperatureUnit.symbol))" let (minimumRange, maximumRange) = temperatureAlertRange() @@ -2302,7 +2292,7 @@ extension TagSettingsViewController { private func showHumidityAlertSetDialog(sender: TagSettingsAlertConfigCell) { let symbol = HumidityUnit.percent.symbol - let titleFormat = "TagSettings.Alert.SetHumidity.title".localized() + let titleFormat = RuuviLocalization.TagSettings.Alert.SetHumidity.title let title = titleFormat + " (\(symbol))" let (minimumRange, maximumRange) = humidityAlertRange() @@ -2317,7 +2307,7 @@ extension TagSettingsViewController { private func showPressureAlertSetDialog(sender: TagSettingsAlertConfigCell) { let pressureUnit = viewModel?.pressureUnit.value ?? .hectopascals - let titleFormat = "TagSettings.Alert.SetPressure.title".localized() + let titleFormat = RuuviLocalization.TagSettings.Alert.SetPressure.title let title = titleFormat + " (\(pressureUnit.symbol))" let (minimumRange, maximumRange) = pressureAlertRange() @@ -2331,8 +2321,8 @@ extension TagSettingsViewController { } private func showRSSIAlertSetDialog(sender: TagSettingsAlertConfigCell) { - let symbol = "dBm".localized() - let titleFormat = "TagSettings.Alert.SetRSSI.title".localized() + let symbol = RuuviLocalization.dBm + let titleFormat = RuuviLocalization.TagSettings.Alert.SetRSSI.title let title = titleFormat + " (\(symbol))" let (minimumRange, maximumRange) = rssiAlertRange() @@ -2346,8 +2336,8 @@ extension TagSettingsViewController { } private func showCloudConnectionAlertSetDialog(sender: TagSettingsAlertConfigCell) { - let title = "alert_cloud_connection_dialog_title".localized() - let message = "alert_cloud_connection_dialog_description".localized() + let title = RuuviLocalization.alertCloudConnectionDialogTitle + let message = RuuviLocalization.alertCloudConnectionDialogDescription let minimumDuration = cloudConnectionMinUnseenDuration() let defaultDuration = cloudConnectionDefaultUnseenDuration() @@ -2520,7 +2510,7 @@ extension TagSettingsViewController { let section = TagSettingsSection( identifier: .offsetCorrection, - title: "TagSettings.SectionHeader.OffsetCorrection.Title".localized().capitalized, + title: RuuviLocalization.TagSettings.SectionHeader.OffsetCorrection.title.capitalized, cells: offsetCorrectionItems, collapsed: true, headerType: .expandable, @@ -2536,7 +2526,7 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( identifier: .offsetTemperature, createdCell: { [weak self] in - self?.tempOffsetCorrectionCell?.configure(title: "TagSettings.OffsetCorrection.Temperature".localized(), + self?.tempOffsetCorrectionCell?.configure(title: RuuviLocalization.TagSettings.OffsetCorrection.temperature, value: self?.measurementService .temperatureOffsetCorrectionString(for: tempOffset)) self?.tempOffsetCorrectionCell?.setAccessory(type: .chevron) @@ -2559,7 +2549,7 @@ extension TagSettingsViewController { createdCell: { [weak self] in self? .humidityOffsetCorrectionCell? - .configure(title: "TagSettings.OffsetCorrection.Humidity".localized(), + .configure(title: RuuviLocalization.TagSettings.OffsetCorrection.humidity, value: self?.measurementService .humidityOffsetCorrectionString(for: humOffset)) self?.humidityOffsetCorrectionCell?.setAccessory(type: .chevron) @@ -2584,7 +2574,7 @@ extension TagSettingsViewController { createdCell: { [weak self] in self? .pressureOffsetCorrectionCell? - .configure(title: "TagSettings.OffsetCorrection.Pressure".localized(), + .configure(title: RuuviLocalization.TagSettings.OffsetCorrection.pressure, value: self?.measurementService.pressureOffsetCorrectionString(for: pressureOffset)) self?.pressureOffsetCorrectionCell?.setAccessory(type: .chevron) self?.pressureOffsetCorrectionCell?.hideSeparator(hide: true) @@ -2640,7 +2630,7 @@ extension TagSettingsViewController { return } - let emptyString = "N/A".localized() + let emptyString = RuuviLocalization.na // Mac address if let moreInfoMacAddressCell = moreInfoMacAddressCell { @@ -2741,7 +2731,7 @@ extension TagSettingsViewController { let section = TagSettingsSection( identifier: .moreInfo, - title: "TagSettings.Label.moreInfo.text".localized().capitalized, + title: RuuviLocalization.TagSettings.Label.MoreInfo.text.capitalized, cells: [ moreInfoMacAddressItem(), moreInfoDataFormatItem(), @@ -2765,8 +2755,8 @@ extension TagSettingsViewController { private func moreInfoMacAddressItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoMacAddressCell?.configure(title: "TagSettings.macAddressTitleLabel.text".localized(), - value: self?.viewModel?.mac.value ?? "N/A".localized()) + self?.moreInfoMacAddressCell?.configure(title: RuuviLocalization.TagSettings.MacAddressTitleLabel.text, + value: self?.viewModel?.mac.value ?? RuuviLocalization.na) return self?.moreInfoMacAddressCell ?? UITableViewCell() }, action: { [weak self] _ in @@ -2779,7 +2769,7 @@ extension TagSettingsViewController { private func moreInfoDataFormatItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoDataFormatCell?.configure(title: "TagSettings.dataFormatTitleLabel.text".localized(), + self?.moreInfoDataFormatCell?.configure(title: RuuviLocalization.TagSettings.DataFormatTitleLabel.text, value: self?.viewModel?.version.value?.stringValue) self?.moreInfoDataFormatCell?.selectionStyle = .none return self?.moreInfoDataFormatCell ?? UITableViewCell() @@ -2792,7 +2782,7 @@ extension TagSettingsViewController { private func moreInfoDataSourceItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoDataSourceCell?.configure(title: "TagSettings.dataSourceTitleLabel.text".localized(), + self?.moreInfoDataSourceCell?.configure(title: RuuviLocalization.TagSettings.DataSourceTitleLabel.text, value: self?.formattedDataSource(from: self?.viewModel?.source.value)) self?.moreInfoDataSourceCell?.selectionStyle = .none return self?.moreInfoDataSourceCell ?? UITableViewCell() @@ -2807,7 +2797,7 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( createdCell: { [weak self] in self?.moreInfoBatteryVoltageCell?.configure( - title: "TagSettings.batteryVoltageTitleLabel.text".localized(), + title: RuuviLocalization.TagSettings.BatteryVoltageTitleLabel.text, value: self?.formattedBatteryVoltage(from: self?.viewModel?.voltage.value), note: status, noteColor: color @@ -2823,7 +2813,7 @@ extension TagSettingsViewController { private func moreInfoAccXItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoAccXCell?.configure(title: "TagSettings.accelerationXTitleLabel.text".localized(), + self?.moreInfoAccXCell?.configure(title: RuuviLocalization.TagSettings.AccelerationXTitleLabel.text, value: self?.formattedAccelerationValue(from: self?.viewModel?.accelerationX.value)) self?.moreInfoAccXCell?.selectionStyle = .none return self?.moreInfoAccXCell ?? UITableViewCell() @@ -2836,7 +2826,7 @@ extension TagSettingsViewController { private func moreInfoAccYItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoAccYCell?.configure(title: "TagSettings.accelerationYTitleLabel.text".localized(), + self?.moreInfoAccYCell?.configure(title: RuuviLocalization.TagSettings.AccelerationYTitleLabel.text, value: self?.formattedAccelerationValue(from: self?.viewModel?.accelerationY.value)) self?.moreInfoAccYCell?.selectionStyle = .none return self?.moreInfoAccYCell ?? UITableViewCell() @@ -2849,7 +2839,7 @@ extension TagSettingsViewController { private func moreInfoAccZItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoAccZCell?.configure(title: "TagSettings.accelerationZTitleLabel.text".localized(), + self?.moreInfoAccZCell?.configure(title: RuuviLocalization.TagSettings.AccelerationZTitleLabel.text, value: self?.formattedAccelerationValue(from: self?.viewModel?.accelerationZ.value)) self?.moreInfoAccZCell?.selectionStyle = .none return self?.moreInfoAccZCell ?? UITableViewCell() @@ -2862,7 +2852,7 @@ extension TagSettingsViewController { private func moreInfoTxPowerItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoTxPowerCell?.configure(title: "TagSettings.txPowerTitleLabel.text".localized(), + self?.moreInfoTxPowerCell?.configure(title: RuuviLocalization.TagSettings.TxPowerTitleLabel.text, value: self?.formattedTXPower(from: self?.viewModel?.txPower.value)) self?.moreInfoTxPowerCell?.selectionStyle = .none return self?.moreInfoTxPowerCell ?? UITableViewCell() @@ -2875,7 +2865,7 @@ extension TagSettingsViewController { private func moreInfoRSSIItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoRSSICell?.configure(title: "TagSettings.rssiTitleLabel.text".localized(), + self?.moreInfoRSSICell?.configure(title: RuuviLocalization.TagSettings.RssiTitleLabel.text, value: self?.viewModel?.rssi.value.stringValue) return self?.moreInfoRSSICell ?? UITableViewCell() }, @@ -2889,7 +2879,7 @@ extension TagSettingsViewController { private func moreInfoMeasurementSequenceItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoMSNCell?.configure(title: "TagSettings.msnTitleLabel.text".localized(), + self?.moreInfoMSNCell?.configure(title: RuuviLocalization.TagSettings.MsnTitleLabel.text, value: self?.viewModel?.measurementSequenceNumber.value.stringValue) return self?.moreInfoMSNCell ?? UITableViewCell() }, @@ -2902,19 +2892,19 @@ extension TagSettingsViewController { // More Info Helpers private func formattedDataSource(from source: RuuviTagSensorRecordSource?) -> String { - let emptyString = "N/A".localized() + let emptyString = RuuviLocalization.na if let source = source { var sourceString = emptyString switch source { case .advertisement: - sourceString = "TagSettings.DataSource.Advertisement.title".localized() + sourceString = RuuviLocalization.TagSettings.DataSource.Advertisement.title case .heartbeat: - sourceString = "TagSettings.DataSource.Heartbeat.title".localized() + sourceString = RuuviLocalization.TagSettings.DataSource.Heartbeat.title case .log: - sourceString = "TagSettings.DataSource.Heartbeat.title".localized() + sourceString = RuuviLocalization.TagSettings.DataSource.Heartbeat.title case .ruuviNetwork: - sourceString = "TagSettings.DataSource.Network.title".localized() + sourceString = RuuviLocalization.TagSettings.DataSource.Network.title default: sourceString = emptyString } @@ -2925,16 +2915,16 @@ extension TagSettingsViewController { } private func formattedBatteryVoltage(from value: Double?) -> String { if let value = value { - return String.localizedStringWithFormat("%.3f", value) + " " + "V".localized() + return String.localizedStringWithFormat("%.3f", value) + " " + RuuviLocalization.v } else { - return "N/A".localized() + return RuuviLocalization.na } } private func formattedBatteryStatus(from batteryLow: Bool?) -> (status: String?, color: UIColor?) { if let batteryLow = batteryLow { // swiftlint:disable:next line_length - let batteryStatus = batteryLow ? "(\("TagSettings.BatteryStatusLabel.Replace.message".localized()))" : "(\("TagSettings.BatteryStatusLabel.Ok.message".localized()))" + let batteryStatus = batteryLow ? "(\(RuuviLocalization.TagSettings.BatteryStatusLabel.Replace.message))" : "(\(RuuviLocalization.TagSettings.BatteryStatusLabel.Ok.message))" let indicatorColor = batteryLow ? .red : RuuviColor.ruuviTintColor return (status: batteryStatus, color: indicatorColor) } else { @@ -2944,17 +2934,17 @@ extension TagSettingsViewController { private func formattedAccelerationValue(from value: Double?) -> String { if let value = value { - return String.localizedStringWithFormat("%.3f", value) + " " + "g".localized() + return String.localizedStringWithFormat("%.3f", value) + " " + RuuviLocalization.g } else { - return "N/A".localized() + return RuuviLocalization.na } } private func formattedTXPower(from value: Int?) -> String { if let value = value { - return value.stringValue + " " + "dBm".localized() + return value.stringValue + " " + RuuviLocalization.dBm } else { - return "N/A".localized() + return RuuviLocalization.na } } } @@ -2968,7 +2958,7 @@ extension TagSettingsViewController { if let firmwareVersionCell = firmwareVersionCell { firmwareVersionCell.bind(viewModel.firmwareVersion) { cell, value in - cell.configure(value: value ?? "N/A".localized()) + cell.configure(value: value ?? RuuviLocalization.na) } } } @@ -2977,7 +2967,7 @@ extension TagSettingsViewController { let section = TagSettingsSection( identifier: .firmware, - title: "TagSettings.SectionHeader.Firmware.title".localized().capitalized, + title: RuuviLocalization.TagSettings.SectionHeader.Firmware.title.capitalized, cells: [ tagFirmwareVersionItem(), tagFirmwareUpdateItem() @@ -2993,8 +2983,8 @@ extension TagSettingsViewController { private func tagFirmwareVersionItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.firmwareVersionCell?.configure(title: "TagSettings.Firmware.CurrentVersion".localized(), - value: self?.viewModel?.firmwareVersion.value ?? "N/A".localized()) + self?.firmwareVersionCell?.configure(title: RuuviLocalization.TagSettings.Firmware.currentVersion, + value: self?.viewModel?.firmwareVersion.value ?? RuuviLocalization.na) self?.firmwareVersionCell?.setAccessory(type: .none) self?.firmwareVersionCell?.selectionStyle = .none return self?.firmwareVersionCell ?? UITableViewCell() @@ -3008,7 +2998,7 @@ extension TagSettingsViewController { let cell = TagSettingsBasicCell(style: .value1, reuseIdentifier: Self.ReuseIdentifier) let settingItem = TagSettingsItem( createdCell: { - cell.configure(title: "TagSettings.Firmware.UpdateFirmware".localized(), + cell.configure(title: RuuviLocalization.TagSettings.Firmware.updateFirmware, value: nil) cell.setAccessory(type: .chevron) cell.hideSeparator(hide: true) @@ -3029,7 +3019,7 @@ extension TagSettingsViewController { let section = TagSettingsSection( identifier: .remove, - title: "Remove".localized().capitalized, + title: RuuviLocalization.remove.capitalized, cells: [ tagRemoveItem() ], @@ -3045,7 +3035,7 @@ extension TagSettingsViewController { let cell = TagSettingsBasicCell(style: .value1, reuseIdentifier: Self.ReuseIdentifier) let settingItem = TagSettingsItem( createdCell: { - cell.configure(title: "TagSettings.RemoveThisSensor.title".localized(), value: nil) + cell.configure(title: RuuviLocalization.TagSettings.RemoveThisSensor.title, value: nil) cell.setAccessory(type: .chevron) cell.hideSeparator(hide: true) return cell @@ -3387,7 +3377,7 @@ extension TagSettingsViewController { fileprivate func setUpUI() { - self.title = "TagSettings.navigationItem.title".localized() + self.title = RuuviLocalization.TagSettings.NavigationItem.title view.backgroundColor = RuuviColor.ruuviPrimary @@ -3463,8 +3453,8 @@ extension TagSettingsViewController { from: self.viewModel?.mac.value, luid: self.viewModel?.uuid.value ) - let alert = UIAlertController(title: "TagSettings.tagNameTitleLabel.text".localized(), - message: "TagSettings.tagNameTitleLabel.rename.text".localized(), + let alert = UIAlertController(title: RuuviLocalization.TagSettings.TagNameTitleLabel.text, + message: RuuviLocalization.TagSettings.TagNameTitleLabel.Rename.text, preferredStyle: .alert) alert.addTextField { [weak self] alertTextField in guard let self = self else { return } @@ -3473,7 +3463,7 @@ extension TagSettingsViewController { alertTextField.placeholder = defaultName self.tagNameTextField = alertTextField } - let action = UIAlertAction(title: "OK".localized(), style: .default) { [weak self] _ in + let action = UIAlertAction(title: RuuviLocalization.ok, style: .default) { [weak self] _ in guard let self = self else { return } if let name = self.tagNameTextField.text, !name.isEmpty { self.output.viewDidChangeTag(name: name) @@ -3481,7 +3471,7 @@ extension TagSettingsViewController { self.output.viewDidChangeTag(name: defaultName) } } - let cancelAction = UIAlertAction(title: "Cancel".localized(), style: .cancel) + let cancelAction = UIAlertAction(title: RuuviLocalization.cancel, style: .cancel) alert.addAction(action) alert.addAction(cancelAction) present(alert, animated: true, completion: nil) @@ -3493,7 +3483,7 @@ extension TagSettingsViewController { // swiftlint:disable:next function_body_length private func showSensorCustomAlertDescriptionDialog(description: String?, sender: TagSettingsAlertConfigCell) { - let alert = UIAlertController(title: "TagSettings.Alert.CustomDescription.title".localized(), + let alert = UIAlertController(title: RuuviLocalization.TagSettings.Alert.CustomDescription.title, message: nil, preferredStyle: .alert) alert.addTextField { [weak self] alertTextField in @@ -3503,7 +3493,7 @@ extension TagSettingsViewController { self.customAlertDescriptionTextField = alertTextField } - let action = UIAlertAction(title: "OK".localized(), style: .default) { [weak self] _ in + let action = UIAlertAction(title: RuuviLocalization.ok, style: .default) { [weak self] _ in guard let self = self else { return } let inputText = self.customAlertDescriptionTextField.text @@ -3547,7 +3537,7 @@ extension TagSettingsViewController { break } } - let cancelAction = UIAlertAction(title: "Cancel".localized(), style: .cancel) + let cancelAction = UIAlertAction(title: RuuviLocalization.cancel, style: .cancel) alert.addAction(action) alert.addAction(cancelAction) present(alert, animated: true, completion: nil) @@ -3569,7 +3559,7 @@ extension TagSettingsViewController { alert.addTextField { [weak self] alertTextField in guard let self = self else { return } alertTextField.delegate = self - let format = "TagSettings.AlertSettings.Dialog.Min".localized() + let format = RuuviLocalization.TagSettings.AlertSettings.Dialog.min alertTextField.placeholder = String(format: format, locale: Locale.autoupdatingCurrent, minimumBound) @@ -3593,7 +3583,7 @@ extension TagSettingsViewController { alert.addTextField { [weak self] alertTextField in guard let self = self else { return } alertTextField.delegate = self - let format = "TagSettings.AlertSettings.Dialog.Max".localized() + let format = RuuviLocalization.TagSettings.AlertSettings.Dialog.max alertTextField.placeholder = String(format: format, locale: Locale.autoupdatingCurrent, maximumBound) @@ -3614,7 +3604,7 @@ extension TagSettingsViewController { } } - let action = UIAlertAction(title: "OK".localized(), style: .default) { [weak self] _ in + let action = UIAlertAction(title: RuuviLocalization.ok, style: .default) { [weak self] _ in guard let self = self else { return } guard let minimumInputText = self.alertMinRangeTextField.text, minimumInputText.doubleValue >= minimumBound else { @@ -3630,7 +3620,7 @@ extension TagSettingsViewController { minValue: minimumInputText.doubleValue, maxValue: maximumInputText.doubleValue ) } - let cancelAction = UIAlertAction(title: "Cancel".localized(), style: .cancel) + let cancelAction = UIAlertAction(title: RuuviLocalization.cancel, style: .cancel) alert.addAction(action) alert.addAction(cancelAction) present(alert, animated: true, completion: nil) @@ -3657,7 +3647,7 @@ extension TagSettingsViewController { alertTextField.text = current?.stringValue } - let action = UIAlertAction(title: "OK".localized(), style: .default) { [weak self] _ in + let action = UIAlertAction(title: RuuviLocalization.ok, style: .default) { [weak self] _ in guard let self = self else { return } guard let durationInput = self.cloudConnectionAlertDelayTextField.text?.intValue, durationInput >= minimum else { @@ -3671,7 +3661,7 @@ extension TagSettingsViewController { self.output.viewDidChangeCloudConnectionAlertUnseenDuration(duration: durationInput*60) } - let cancelAction = UIAlertAction(title: "Cancel".localized(), style: .cancel) + let cancelAction = UIAlertAction(title: RuuviLocalization.cancel, style: .cancel) alert.addAction(action) alert.addAction(cancelAction) present(alert, animated: true, completion: nil) @@ -3684,38 +3674,38 @@ extension TagSettingsViewController: TagSettingsViewInput { } func showTagClaimDialog() { - let title = "claim_sensor_ownership".localized() - let message = "do_you_own_sensor".localized() + let title = RuuviLocalization.claimSensorOwnership + let message = RuuviLocalization.doYouOwnSensor let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: "Yes".localized(), + controller.addAction(UIAlertAction(title: RuuviLocalization.yes, style: .default, handler: { [weak self] _ in self?.output.viewDidConfirmClaimTag() })) - controller.addAction(UIAlertAction(title: "No".localized(), style: .cancel, handler: nil)) + controller.addAction(UIAlertAction(title: RuuviLocalization.no, style: .cancel, handler: nil)) present(controller, animated: true) } func showMacAddressDetail() { - let title = "TagSettings.Mac.Alert.title".localized() + let title = RuuviLocalization.TagSettings.Mac.Alert.title let controller = UIAlertController(title: title, message: viewModel?.mac.value, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: "Copy".localized(), style: .default, handler: { [weak self] _ in + controller.addAction(UIAlertAction(title: RuuviLocalization.copy, style: .default, handler: { [weak self] _ in if let mac = self?.viewModel?.mac.value { UIPasteboard.general.string = mac } })) - controller.addAction(UIAlertAction(title: "Cancel".localized(), style: .cancel, handler: nil)) + controller.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) present(controller, animated: true) } func showFirmwareUpdateDialog() { - let message = "Cards.LegacyFirmwareUpdateDialog.message".localized() + let message = RuuviLocalization.Cards.LegacyFirmwareUpdateDialog.message let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) - let dismissTitle = "Cards.KeepConnectionDialog.Dismiss.title".localized() + let dismissTitle = RuuviLocalization.Cards.KeepConnectionDialog.Dismiss.title alert.addAction(UIAlertAction(title: dismissTitle, style: .cancel, handler: { [weak self] _ in self?.output.viewDidIgnoreFirmwareUpdateDialog() })) - let checkForUpdateTitle = "Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title".localized() + let checkForUpdateTitle = RuuviLocalization.Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title alert.addAction(UIAlertAction(title: checkForUpdateTitle, style: .default, handler: { [weak self] _ in self?.output.viewDidConfirmFirmwareUpdate() })) @@ -3723,11 +3713,11 @@ extension TagSettingsViewController: TagSettingsViewInput { } func showFirmwareDismissConfirmationUpdateDialog() { - let message = "Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message".localized() + let message = RuuviLocalization.Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) - let dismissTitle = "Cards.KeepConnectionDialog.Dismiss.title".localized() + let dismissTitle = RuuviLocalization.Cards.KeepConnectionDialog.Dismiss.title alert.addAction(UIAlertAction(title: dismissTitle, style: .cancel, handler: nil)) - let checkForUpdateTitle = "Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title".localized() + let checkForUpdateTitle = RuuviLocalization.Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title alert.addAction(UIAlertAction(title: checkForUpdateTitle, style: .default, handler: { [weak self] _ in self?.output.viewDidConfirmFirmwareUpdate() })) @@ -3735,9 +3725,9 @@ extension TagSettingsViewController: TagSettingsViewInput { } func showKeepConnectionTimeoutDialog() { - let message = "TagSettings.PairError.Timeout.description".localized() + let message = RuuviLocalization.TagSettings.PairError.Timeout.description let controller = UIAlertController(title: nil, message: message, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) + controller.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(controller, animated: true) } @@ -3749,9 +3739,9 @@ extension TagSettingsViewController: TagSettingsViewInput { } func showKeepConnectionCloudModeDialog() { - let message = "TagSettings.PairError.CloudMode.description".localized() + let message = RuuviLocalization.TagSettings.PairError.CloudMode.description let controller = UIAlertController(title: nil, message: message, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: "OK".localized(), + controller.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: { [weak self] _ in self?.resetKeepConnectionSwitch() @@ -3772,12 +3762,12 @@ extension TagSettingsViewController: TagSettingsViewInput { } func showCSVExportLocationDialog() { - let title = "export_history".localized() - let message = "export_csv_feature_location".localized() + let title = RuuviLocalization.exportHistory + let message = RuuviLocalization.exportCsvFeatureLocation let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: "OK".localized(), + controller.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(controller, animated: true) diff --git a/station/Extensions/Classess/AppDateFormatter.swift b/station/Extensions/Classess/AppDateFormatter.swift index f2b55e057..0f7b3465f 100644 --- a/station/Extensions/Classess/AppDateFormatter.swift +++ b/station/Extensions/Classess/AppDateFormatter.swift @@ -1,4 +1,5 @@ import Foundation +import RuuviLocalization class AppDateFormatter { static let shared = AppDateFormatter() @@ -45,7 +46,7 @@ extension AppDateFormatter { if let formattedDate = calendar.date(from: dateComponents) { return graphXAxisDateFormatter.string(from: formattedDate) } else { - return "N/A".localized() + return RuuviLocalization.na } } diff --git a/station/Extensions/Date+Ruuvi.swift b/station/Extensions/Date+Ruuvi.swift index fb04a8b5d..b1b735d66 100644 --- a/station/Extensions/Date+Ruuvi.swift +++ b/station/Extensions/Date+Ruuvi.swift @@ -1,4 +1,5 @@ import Foundation +import RuuviLocalization extension Date { func ruuviAgo(prefix: String = "") -> String { @@ -12,12 +13,12 @@ extension Date { let minutes = (elapsed / 60) % 60 let hours = (elapsed / (60*60)) % 24 if hours > 0 { - output += String(hours) + " " + "h".localized() + " " + output += String(hours) + " " + RuuviLocalization.h + " " } if minutes > 0 { - output += String(minutes) + " " + "min".localized() + " " + output += String(minutes) + " " + RuuviLocalization.min + " " } - output += String(seconds) + " " + "s".localized() + " " + "ago".localized() + output += String(seconds) + " " + RuuviLocalization.s + " " + RuuviLocalization.ago } return output } diff --git a/station/Extensions/DfuFirmware+Log.swift b/station/Extensions/DfuFirmware+Log.swift index 30a950cc8..d8638a716 100644 --- a/station/Extensions/DfuFirmware+Log.swift +++ b/station/Extensions/DfuFirmware+Log.swift @@ -1,4 +1,5 @@ import Foundation +import RuuviLocalization import RuuviDFU #if canImport(NordicDFU) import NordicDFU @@ -9,15 +10,15 @@ import iOSDFULibrary extension DFUFirmware { var log: DFULog { - let str = "\("DfuFlash.Firmware.FileName.text".localized()): \(fileName ?? "")" + let str = "\(RuuviLocalization.DfuFlash.Firmware.FileName.text): \(fileName ?? "")" .appending("\r\n") - .appending("\("DfuFlash.Firmware.Parts.text".localized()): \(parts)") + .appending("\(RuuviLocalization.DfuFlash.Firmware.Parts.text): \(parts)") .appending("\r\n") - .appending("\("DfuFlash.Firmware.Size.text".localized()): \(size.application / 1024) KB") + .appending("\(RuuviLocalization.DfuFlash.Firmware.Size.text): \(size.application / 1024) KB") .appending("\r\n") - .appending("\("DfuFlash.Firmware.SoftDeviceSize.text".localized()): \(size.softdevice / 1024) KB") + .appending("\(RuuviLocalization.DfuFlash.Firmware.SoftDeviceSize.text): \(size.softdevice / 1024) KB") .appending("\r\n") - .appending("\("DfuFlash.Firmware.BootloaderSize.text".localized()): \(size.bootloader) byte") + .appending("\(RuuviLocalization.DfuFlash.Firmware.BootloaderSize.text): \(size.bootloader) byte") return DFULog(message: str, time: Date()) } } diff --git a/station/Extensions/Errors/RUError.swift b/station/Extensions/Errors/RUError.swift index 468a3a073..e0856a7ac 100644 --- a/station/Extensions/Errors/RUError.swift +++ b/station/Extensions/Errors/RUError.swift @@ -6,6 +6,7 @@ import RuuviPool import RuuviLocal import RuuviService import RuuviDFU +import RuuviLocalization enum RUError: Error { case ruuviLocal(RuuviLocalError) @@ -23,7 +24,6 @@ enum RUError: Error { case expected(ExpectedError) case unexpected(UnexpectedError) case writeToDisk(Error) - case userApi(UserApiError) case dfuError(RuuviDfuError) } @@ -60,8 +60,6 @@ extension RUError: LocalizedError { return error.localizedDescription case .writeToDisk(let error): return error.localizedDescription - case .userApi(let error): - return error.localizedDescription case .dfuError(let error): return error.localizedDescription } @@ -76,7 +74,7 @@ extension BluetoothError: LocalizedError { public var errorDescription: String? { switch self { case .disconnected: - return "BluetoothError.disconnected".localized() + return RuuviLocalization.BluetoothError.disconnected } } } @@ -97,23 +95,23 @@ extension CoreError: LocalizedError { public var errorDescription: String? { switch self { case .failedToGetDataFromResponse: - return "CoreError.failedToGetDataFromResponse".localized() + return RuuviLocalization.CoreError.failedToGetDataFromResponse case .failedToGetCurrentLocation: - return "CoreError.failedToGetCurrentLocation".localized() + return RuuviLocalization.CoreError.failedToGetCurrentLocation case .failedToGetPngRepresentation: - return "CoreError.failedToGetPngRepresentation".localized() + return RuuviLocalization.CoreError.failedToGetPngRepresentation case .failedToGetDocumentsDirectory: - return "CoreError.failedToGetDocumentsDirectory".localized() + return RuuviLocalization.CoreError.failedToGetDocumentsDirectory case .locationPermissionDenied: - return "CoreError.locationPermissionDenied".localized() + return RuuviLocalization.CoreError.locationPermissionDenied case .locationPermissionNotDetermined: - return "CoreError.locationPermissionNotDetermined".localized() + return RuuviLocalization.CoreError.locationPermissionNotDetermined case .objectNotFound: - return "CoreError.objectNotFound".localized() + return RuuviLocalization.CoreError.objectNotFound case .objectInvalidated: - return "CoreError.objectInvalidated".localized() + return RuuviLocalization.CoreError.objectInvalidated case .unableToSendEmail: - return "CoreError.unableToSendEmail".localized() + return RuuviLocalization.CoreError.unableToSendEmail } } } @@ -128,11 +126,11 @@ extension ExpectedError: LocalizedError { public var errorDescription: String? { switch self { case .missingOpenWeatherMapAPIKey: - return "ExpectedError.missingOpenWeatherMapAPIKey".localized() + return RuuviLocalization.ExpectedError.missingOpenWeatherMapAPIKey case .isAlreadySyncingLogsWithThisTag: - return "ExpectedError.isAlreadySyncingLogsWithThisTag".localized() + return RuuviLocalization.ExpectedError.isAlreadySyncingLogsWithThisTag case .failedToDeleteTag: - return "ExpectedError.failedToDeleteTag".localized() + return RuuviLocalization.ExpectedError.failedToDeleteTag } } } @@ -145,9 +143,6 @@ enum UnexpectedError: Error { case failedToFindLogsForTheTag case viewModelUUIDIsNil case attemptToReadDataFromRealmWithoutLUID - case failedToConstructURL - case notAHttpResponse - case failedToParseHttpResponse case failedToFindOrGenerateBackgroundImage case bothLuidAndMacAreNil } @@ -156,39 +151,23 @@ extension UnexpectedError: LocalizedError { public var errorDescription: String? { switch self { case .callbackErrorAndResultAreNil: - return "UnexpectedError.callbackErrorAndResultAreNil".localized() + return RuuviLocalization.UnexpectedError.callbackErrorAndResultAreNil case .callerDeinitedDuringOperation: - return "UnexpectedError.callerDeinitedDuringOperation".localized() + return RuuviLocalization.UnexpectedError.callerDeinitedDuringOperation case .failedToReverseGeocodeCoordinate: - return "UnexpectedError.failedToReverseGeocodeCoordinate".localized() + return RuuviLocalization.UnexpectedError.failedToReverseGeocodeCoordinate case .failedToFindRuuviTag: - return "UnexpectedError.failedToFindRuuviTag".localized() + return RuuviLocalization.UnexpectedError.failedToFindRuuviTag case .failedToFindLogsForTheTag: - return "UnexpectedError.failedToFindLogsForTheTag".localized() + return RuuviLocalization.UnexpectedError.failedToFindLogsForTheTag case .viewModelUUIDIsNil: - return "UnexpectedError.viewModelUUIDIsNil".localized() + return RuuviLocalization.UnexpectedError.viewModelUUIDIsNil case .attemptToReadDataFromRealmWithoutLUID: - return "UnexpectedError.attemptToReadDataFromRealmWithoutLUID".localized() - case .failedToConstructURL: - return "UnexpectedError.failedToConstructURL".localized() - case .notAHttpResponse: - return "UnexpectedError.notAHttpResponse".localized() - case .failedToParseHttpResponse: - return "UnexpectedError.failedToParseHttpResponse".localized() + return RuuviLocalization.UnexpectedError.attemptToReadDataFromRealmWithoutLUID case .failedToFindOrGenerateBackgroundImage: - return "UnexpectedError.failedToFindOrGenerateBackgroundImage".localized() + return RuuviLocalization.UnexpectedError.failedToFindOrGenerateBackgroundImage case .bothLuidAndMacAreNil: - return "UnexpectedError.bothLuidAndMacAreNil".localized() + return RuuviLocalization.UnexpectedError.bothLuidAndMacAreNil } } } - -struct UserApiError: Error { - static let emptyResponse: UserApiError = UserApiError(description: "Empty response") - let description: String -} -extension UserApiError: LocalizedError { - public var errorDescription: String? { - return description.localized() - } -} diff --git a/station/Extensions/Errors/RuuviCloudApiError+LocalizedError.swift b/station/Extensions/Errors/RuuviCloudApiError+LocalizedError.swift index 2fc08b7a0..272b57389 100644 --- a/station/Extensions/Errors/RuuviCloudApiError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviCloudApiError+LocalizedError.swift @@ -1,21 +1,20 @@ import Foundation import RuuviCloud +import RuuviLocalization extension RuuviCloudApiError: LocalizedError { public var errorDescription: String? { switch self { case .connection: - return "internet_connection_problem".localized() + return RuuviLocalization.internetConnectionProblem case .emptyResponse: - return "RuuviCloudApiError.emptyResponse".localized() + return RuuviLocalization.RuuviCloudApiError.emptyResponse case .failedToGetDataFromResponse: - return "RuuviCloudApiError.failedToGetDataFromResponse".localized() + return RuuviLocalization.RuuviCloudApiError.failedToGetDataFromResponse case .unexpectedHTTPStatusCode: - return "RuuviCloudApiError.unexpectedHTTPStatusCode".localized() + return RuuviLocalization.RuuviCloudApiError.unexpectedHTTPStatusCode case .api(let code): - return "UserApiError.\(code.rawValue)".localized() - case .claim(let claimError): - return claimError.error?.localized() + return code.localizedDescription case .networking(let error): return error.localizedDescription case .parsing(let error): @@ -25,3 +24,78 @@ extension RuuviCloudApiError: LocalizedError { } } } + +private extension RuuviCloudApiErrorCode { + var localizedDescription: String { + switch self { + case .erForbidden: + return RuuviLocalization.UserApiError.erForbidden + case .erUnauthorized: + return RuuviLocalization.UserApiError.erUnauthorized + case .erInternal: + return RuuviLocalization.UserApiError.erInternal + case .erInvalidFormat: + return RuuviLocalization.UserApiError.erInvalidFormat + case .erUserNotFound: + return RuuviLocalization.UserApiError.erUserNotFound + case .erSensorNotFound: + return RuuviLocalization.UserApiError.erSensorNotFound + case .erTokenExpired: + return RuuviLocalization.UserApiError.erTokenExpired + case .erThrottled: + return RuuviLocalization.UserApiError.erThrottled + case .erGatewayNotFound: + return RuuviLocalization.UserApiError.erGatewayNotFound + case .erGatewayAlreadyWhitelisted: + return RuuviLocalization.UserApiError.erGatewayAlreadyWhitelisted + case .erGatewayStatusReportFailed: + return RuuviLocalization.UserApiError.erGatewayStatusReportFailed + case .erConflict: + return RuuviLocalization.UserApiError.erConflict + case .erSubscriptionNotFound: + return RuuviLocalization.UserApiError.erSubscriptionNotFound + case .erShareCountReached: + return RuuviLocalization.UserApiError.erShareCountReached + case .erClaimCountReached: + return RuuviLocalization.UserApiError.erClaimCountReached + case .erSensorShareCountReached: + return RuuviLocalization.UserApiError.erSensorShareCountReached + case .erNoDataToShare: + return RuuviLocalization.UserApiError.erNoDataToShare + case .erSensorAlreadyShared: + return RuuviLocalization.UserApiError.erSensorAlreadyShared + case .erSensorAlreadyClaimed: + return RuuviLocalization.UserApiError.erSensorAlreadyClaimed("") + case .erSensorAlreadyRegistered: + return RuuviLocalization.UserApiError.erSensorAlreadyRegistered + case .erUnableToSendEmail: + return RuuviLocalization.UserApiError.erUnableToSendEmail + case .erSubscriptionCodeExists: + return RuuviLocalization.UserApiError.erSubscriptionCodeExists + case .erSubscriptionCodeUsed: + return RuuviLocalization.UserApiError.erSubscriptionCodeUsed + case .erMissingArgument: + return RuuviLocalization.UserApiError.erMissingArgument + case .erInvalidDensityMode: + return RuuviLocalization.UserApiError.erInvalidDensityMode + case .erInvalidSortMode: + return RuuviLocalization.UserApiError.erInvalidSortMode + case .erInvalidTimeRange: + return RuuviLocalization.UserApiError.erInvalidTimeRange + case .erOldEntry: + return RuuviLocalization.UserApiError.erOldEntry + case .erInvalidEmailAddress: + return RuuviLocalization.UserApiError.erInvalidEmailAddress + case .erInvalidMacAddress: + return RuuviLocalization.UserApiError.erInvalidMacAddress + case .erInvalidEnumValue: + return RuuviLocalization.UserApiError.erInvalidEnumValue + case .erSubDataStorageError: + return RuuviLocalization.UserApiError.erSubDataStorageError + case .erSubNoUser: + return RuuviLocalization.UserApiError.erSubNoUser + case .ok: + return RuuviLocalization.UserApiError.ok + } + } +} diff --git a/station/Extensions/Errors/RuuviCloudError+LocalizedError.swift b/station/Extensions/Errors/RuuviCloudError+LocalizedError.swift index 0d4bc00e7..3a56ba119 100644 --- a/station/Extensions/Errors/RuuviCloudError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviCloudError+LocalizedError.swift @@ -1,5 +1,6 @@ import RuuviCloud import Foundation +import RuuviLocalization extension RuuviCloudError: LocalizedError { public var errorDescription: String? { @@ -7,7 +8,7 @@ extension RuuviCloudError: LocalizedError { case .api(let error): return error.errorDescription case .notAuthorized: - return "RuuviCloudError.NotAuthorized".localized() + return RuuviLocalization.RuuviCloudError.notAuthorized } } } diff --git a/station/Extensions/Errors/RuuviCoreError+LocalizedError.swift b/station/Extensions/Errors/RuuviCoreError+LocalizedError.swift index 7c784a430..badd8412d 100644 --- a/station/Extensions/Errors/RuuviCoreError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviCoreError+LocalizedError.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import Foundation import RuuviCore @@ -5,11 +6,11 @@ extension RuuviCoreError: LocalizedError { public var errorDescription: String? { switch self { case .locationPermissionDenied: - return "CoreError.locationPermissionDenied".localized() + return RuuviLocalization.CoreError.locationPermissionDenied case .locationPermissionNotDetermined: - return "CoreError.locationPermissionNotDetermined".localized() + return RuuviLocalization.CoreError.locationPermissionNotDetermined case .failedToGetCurrentLocation: - return "CoreError.failedToGetCurrentLocation".localized() + return RuuviLocalization.CoreError.failedToGetCurrentLocation } } } diff --git a/station/Extensions/Errors/RuuviDFUError+LocalizedError.swift b/station/Extensions/Errors/RuuviDFUError+LocalizedError.swift index 6b6a78bc8..2284a39e9 100644 --- a/station/Extensions/Errors/RuuviDFUError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviDFUError+LocalizedError.swift @@ -1,8 +1,9 @@ +import RuuviLocalization import Foundation import RuuviDFU extension RuuviDfuError: LocalizedError { public var errorDescription: String? { - return description.localized() + return description } } diff --git a/station/Extensions/Errors/RuuviLocalError+LocalizedError.swift b/station/Extensions/Errors/RuuviLocalError+LocalizedError.swift index a8352f2eb..e974c89ba 100644 --- a/station/Extensions/Errors/RuuviLocalError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviLocalError+LocalizedError.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import Foundation import RuuviLocal @@ -7,9 +8,9 @@ extension RuuviLocalError: LocalizedError { case .disk(let error): return error.localizedDescription case .failedToGetJpegRepresentation: - return "RuuviLocalError.failedToGetJpegRepresentation".localized() + return RuuviLocalization.RuuviLocalError.failedToGetJpegRepresentation case .failedToGetDocumentsDirectory: - return "RuuviLocalError.failedToGetDocumentsDirectory".localized() + return RuuviLocalization.RuuviLocalError.failedToGetDocumentsDirectory } } } diff --git a/station/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift b/station/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift index 619c94029..d6d0002f2 100644 --- a/station/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import Foundation import RuuviPersistence @@ -9,7 +10,7 @@ extension RuuviPersistenceError: LocalizedError { case .realm(let error): return error.localizedDescription case .failedToFindRuuviTag: - return "RuuviPersistenceError.failedToFindRuuviTag".localized() + return RuuviLocalization.RuuviPersistenceError.failedToFindRuuviTag } } } diff --git a/station/Extensions/Errors/RuuviServiceError+LocalizedError.swift b/station/Extensions/Errors/RuuviServiceError+LocalizedError.swift index 56a4ea0dc..0077f87f9 100644 --- a/station/Extensions/Errors/RuuviServiceError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviServiceError+LocalizedError.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import Foundation import RuuviService @@ -21,19 +22,19 @@ extension RuuviServiceError: LocalizedError { case .networking(let error): return error.localizedDescription case .pictureUrlIsNil: - return "RuuviServiceError.pictureUrlIsNil".localized() + return RuuviLocalization.RuuviServiceError.pictureUrlIsNil case .macIdIsNil: - return "RuuviServiceError.macIdIsNil".localized() + return RuuviLocalization.RuuviServiceError.macIdIsNil case .bothLuidAndMacAreNil: - return "RuuviServiceError.bothLuidAndMacAreNil".localized() + return RuuviLocalization.RuuviServiceError.bothLuidAndMacAreNil case .failedToParseNetworkResponse: - return "RuuviServiceError.failedToParseNetworkResponse".localized() + return RuuviLocalization.RuuviServiceError.failedToParseNetworkResponse case .failedToFindOrGenerateBackgroundImage: - return "RuuviServiceError.failedToFindOrGenerateBackgroundImage".localized() + return RuuviLocalization.RuuviServiceError.failedToFindOrGenerateBackgroundImage case .failedToGetJpegRepresentation: - return "RuuviServiceError.failedToGetJpegRepresentation".localized() + return RuuviLocalization.RuuviServiceError.failedToGetJpegRepresentation case .isAlreadySyncingLogsWithThisTag: - return "ExpectedError.isAlreadySyncingLogsWithThisTag".localized() + return RuuviLocalization.ExpectedError.isAlreadySyncingLogsWithThisTag } } } diff --git a/station/Extensions/HumidityUnit+Localization.swift b/station/Extensions/HumidityUnit+Localization.swift index 58153835a..0119e50da 100644 --- a/station/Extensions/HumidityUnit+Localization.swift +++ b/station/Extensions/HumidityUnit+Localization.swift @@ -1,26 +1,27 @@ import Foundation import RuuviOntology +import RuuviLocalization extension HumidityUnit: SelectionItemProtocol { - var title: String { + var title: (String) -> String { switch self { case .percent: - return "HumidityUnit.Percent.title".localized() + return { _ in RuuviLocalization.HumidityUnit.Percent.title } case .gm3: - return "HumidityUnit.gm3.title".localized() + return { _ in RuuviLocalization.HumidityUnit.Gm3.title } case .dew: - return "HumidityUnit.Dew.title".localized() + return RuuviLocalization.HumidityUnit.Dew.title } } var symbol: String { switch self { case .percent: - return "%".localized() + return "%" case .gm3: - return "g/m³".localized() - default: - return "°".localized() + return RuuviLocalization.gm³ + case .dew: + return "°" } } diff --git a/station/Extensions/Int+Extension.swift b/station/Extensions/Int+Extension.swift index 3c4b3f0e7..93edbf702 100644 --- a/station/Extensions/Int+Extension.swift +++ b/station/Extensions/Int+Extension.swift @@ -1,4 +1,5 @@ import Foundation +import RuuviLocalization extension Int { var stringValue: String { @@ -11,7 +12,7 @@ extension Optional where Wrapped == Int { if let self = self { return "\(self)" } else { - return "N/A".localized() + return RuuviLocalization.na } } } diff --git a/station/Extensions/Language+Localization.swift b/station/Extensions/Language+Localization.swift index b49e3e0b4..cfe7e70d7 100644 --- a/station/Extensions/Language+Localization.swift +++ b/station/Extensions/Language+Localization.swift @@ -1,22 +1,23 @@ import Foundation import Humidity import RuuviOntology +import RuuviLocalization extension Language { var name: String { switch self { case .english: - return "Language.English".localized() + return RuuviLocalization.Language.english case .russian: - return "Language.Russian".localized() + return RuuviLocalization.Language.russian case .finnish: - return "Language.Finnish".localized() + return RuuviLocalization.Language.finnish case .french: - return "Language.French".localized() + return RuuviLocalization.Language.french case .swedish: - return "Language.Swedish".localized() + return RuuviLocalization.Language.swedish case .german: - return "Language.German".localized() + return RuuviLocalization.Language.german } } } diff --git a/station/Extensions/MeasurementAccuracyType+Extension.swift b/station/Extensions/MeasurementAccuracyType+Extension.swift index 051f4f3ae..4191714a0 100644 --- a/station/Extensions/MeasurementAccuracyType+Extension.swift +++ b/station/Extensions/MeasurementAccuracyType+Extension.swift @@ -2,14 +2,14 @@ import Foundation import RuuviOntology extension MeasurementAccuracyType: SelectionItemProtocol { - public var title: String { + public var title: (String) -> String { switch self { case .zero: - return "1" + return { _ in "1" } case .one: - return "0.1" + return { _ in "0.1" } case .two: - return "0.01" + return { _ in "0.01" } } } } diff --git a/station/Extensions/RuuviAlertSound+Extension.swift b/station/Extensions/RuuviAlertSound+Extension.swift index e2abff838..a7640981b 100644 --- a/station/Extensions/RuuviAlertSound+Extension.swift +++ b/station/Extensions/RuuviAlertSound+Extension.swift @@ -1,13 +1,14 @@ import Foundation import RuuviOntology +import RuuviLocalization extension RuuviAlertSound: SelectionItemProtocol { - var title: String { + var title: (String) -> String { switch self { case .systemDefault: - return "settings_alert_sound_default".localized() + return { _ in RuuviLocalization.settingsAlertSoundDefault } case .ruuviSpeak: - return "settings_alert_sound_ruuvi_speak".localized() + return { _ in RuuviLocalization.settingsAlertSoundRuuviSpeak } } } } diff --git a/station/Extensions/RuuviTheme+Extension.swift b/station/Extensions/RuuviTheme+Extension.swift index b94911432..761bf319c 100644 --- a/station/Extensions/RuuviTheme+Extension.swift +++ b/station/Extensions/RuuviTheme+Extension.swift @@ -1,15 +1,16 @@ +import RuuviLocalization import Foundation import RuuviOntology extension RuuviTheme: SelectionItemProtocol { - var title: String { + var title: (String) -> String { switch self { case .light: - return "light_theme".localized() + return { _ in RuuviLocalization.lightTheme } case .dark: - return "dark_theme".localized() + return { _ in RuuviLocalization.darkTheme } case .system: - return "follow_system_theme".localized() + return { _ in RuuviLocalization.followSystemTheme } } } } diff --git a/station/Extensions/String+Localization.swift b/station/Extensions/String+Localization.swift deleted file mode 100644 index 12012322a..000000000 --- a/station/Extensions/String+Localization.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation - -extension String { - func localized() -> String { - return NSLocalizedString(self, comment: self) - } -} diff --git a/station/Extensions/Structs/ExportHeadersProvider.swift b/station/Extensions/Structs/ExportHeadersProvider.swift index ccb10e8a5..8ac996f05 100644 --- a/station/Extensions/Structs/ExportHeadersProvider.swift +++ b/station/Extensions/Structs/ExportHeadersProvider.swift @@ -1,26 +1,27 @@ +import RuuviLocalization import Foundation import RuuviService struct ExportHeadersProvider: RuuviServiceExportHeaders { func getHeaders(_ units: RuuviServiceMeasurementSettingsUnit) -> [String] { - let tempFormat = "ExportService.Temperature".localized() - let pressureFormat = "ExportService.Pressure".localized() - let humidityFormat = "ExportService.Humidity".localized() + let tempFormat = RuuviLocalization.ExportService.temperature + let pressureFormat = RuuviLocalization.ExportService.pressure + let humidityFormat = RuuviLocalization.ExportService.humidity return [ - "ExportService.Date".localized(), - String(format: tempFormat, units.temperatureUnit.symbol), + RuuviLocalization.ExportService.date, + tempFormat(units.temperatureUnit.symbol), units.humidityUnit == .dew - ? String(format: humidityFormat, units.temperatureUnit.symbol) - : String(format: humidityFormat, units.humidityUnit.symbol), - String(format: pressureFormat, units.pressureUnit.symbol), - "RSSI" + " (\("dBm".localized()))", - "ExportService.AccelerationX".localized() + " (\("g".localized()))", - "ExportService.AccelerationY".localized() + " (\("g".localized()))", - "ExportService.AccelerationZ".localized() + " (\("g".localized()))", - "ExportService.Voltage".localized(), - "ExportService.MovementCounter".localized() + " (\("Cards.Movements.title".localized()))", - "ExportService.MeasurementSequenceNumber".localized(), - "ExportService.TXPower".localized() + " (\("dBm".localized()))" + ? humidityFormat(units.temperatureUnit.symbol) + : humidityFormat(units.humidityUnit.symbol), + pressureFormat(units.pressureUnit.symbol), + "RSSI" + " (\(RuuviLocalization.dBm))", + RuuviLocalization.ExportService.accelerationX + " (\(RuuviLocalization.g))", + RuuviLocalization.ExportService.accelerationY + " (\(RuuviLocalization.g))", + RuuviLocalization.ExportService.accelerationZ + " (\(RuuviLocalization.g))", + RuuviLocalization.ExportService.voltage, + RuuviLocalization.ExportService.movementCounter + " (\(RuuviLocalization.Cards.Movements.title))", + RuuviLocalization.ExportService.measurementSequenceNumber, + RuuviLocalization.ExportService.txPower + " (\(RuuviLocalization.dBm))" ] } } diff --git a/station/Extensions/Structs/GlobalHelpers.swift b/station/Extensions/Structs/GlobalHelpers.swift index cde84164d..5de55b8b5 100644 --- a/station/Extensions/Structs/GlobalHelpers.swift +++ b/station/Extensions/Structs/GlobalHelpers.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit struct GlobalHelpers { @@ -21,10 +22,10 @@ struct GlobalHelpers { static func ruuviTagDefaultName(from macId: String?, luid: String?) -> String { // identifier if let mac = macId { - return "DiscoverTable.RuuviDevice.prefix".localized() + return RuuviLocalization.DiscoverTable.RuuviDevice.prefix + " " + mac.replacingOccurrences(of: ":", with: "").suffix(4) } else { - return "DiscoverTable.RuuviDevice.prefix".localized() + return RuuviLocalization.DiscoverTable.RuuviDevice.prefix + " " + (luid?.prefix(4) ?? "") } } diff --git a/station/Extensions/Structs/HeartbeatDaemonTitles.swift b/station/Extensions/Structs/HeartbeatDaemonTitles.swift index 87c3923ac..8430173ef 100644 --- a/station/Extensions/Structs/HeartbeatDaemonTitles.swift +++ b/station/Extensions/Structs/HeartbeatDaemonTitles.swift @@ -1,7 +1,8 @@ import Foundation import RuuviDaemon +import RuuviLocalization struct HeartbeatDaemonTitles: RuuviTagHeartbeatDaemonTitles { - var didConnect: String = "LocalNotificationsManager.DidConnect.title".localized() - var didDisconnect: String = "LocalNotificationsManager.DidDisconnect.title".localized() + var didConnect: String = RuuviLocalization.LocalNotificationsManager.DidConnect.title + var didDisconnect: String = RuuviLocalization.LocalNotificationsManager.DidDisconnect.title } diff --git a/station/Extensions/Structs/RuuviNotifierTitlesImpl.swift b/station/Extensions/Structs/RuuviNotifierTitlesImpl.swift index ee912c952..de02947bc 100644 --- a/station/Extensions/Structs/RuuviNotifierTitlesImpl.swift +++ b/station/Extensions/Structs/RuuviNotifierTitlesImpl.swift @@ -1,16 +1,17 @@ +import RuuviLocalization import Foundation import RuuviNotifier struct RuuviNotifierTitlesImpl: RuuviNotifierTitles { - let lowTemperature = "LocalNotificationsManager.LowTemperature.title".localized() - let highTemperature = "LocalNotificationsManager.HighTemperature.title".localized() - let lowHumidity = "LocalNotificationsManager.LowHumidity.title".localized() - let highHumidity = "LocalNotificationsManager.HighHumidity.title".localized() - let lowDewPoint = "LocalNotificationsManager.LowDewPoint.title".localized() - let highDewPoint = "LocalNotificationsManager.HighDewPoint.title".localized() - let lowPressure = "LocalNotificationsManager.LowPressure.title".localized() - let highPressure = "LocalNotificationsManager.HighPressure.title".localized() - let lowSignal = "LocalNotificationsManager.LowSignal.title".localized() - let highSignal = "LocalNotificationsManager.HighSignal.title".localized() - let didMove = "LocalNotificationsManager.DidMove.title".localized() + let lowTemperature = RuuviLocalization.LocalNotificationsManager.LowTemperature.title + let highTemperature = RuuviLocalization.LocalNotificationsManager.HighTemperature.title + let lowHumidity = RuuviLocalization.LocalNotificationsManager.LowHumidity.title + let highHumidity = RuuviLocalization.LocalNotificationsManager.HighHumidity.title + let lowDewPoint = RuuviLocalization.LocalNotificationsManager.LowDewPoint.title + let highDewPoint = RuuviLocalization.LocalNotificationsManager.HighDewPoint.title + let lowPressure = RuuviLocalization.LocalNotificationsManager.LowPressure.title + let highPressure = RuuviLocalization.LocalNotificationsManager.HighPressure.title + let lowSignal = RuuviLocalization.LocalNotificationsManager.LowSignal.title + let highSignal = RuuviLocalization.LocalNotificationsManager.HighSignal.title + let didMove = RuuviLocalization.LocalNotificationsManager.DidMove.title } diff --git a/station/Extensions/TemperatureUnit+Localization.swift b/station/Extensions/TemperatureUnit+Localization.swift index c9dfcc525..79a18d252 100644 --- a/station/Extensions/TemperatureUnit+Localization.swift +++ b/station/Extensions/TemperatureUnit+Localization.swift @@ -1,30 +1,31 @@ import Foundation import RuuviOntology +import RuuviLocalization extension TemperatureUnit: SelectionItemProtocol { - var title: String { + var title: (String) -> String { switch self { case .celsius: - return "TemperatureUnit.Celsius.title".localized() + return { _ in RuuviLocalization.TemperatureUnit.Celsius.title } case .fahrenheit: - return "TemperatureUnit.Fahrenheit.title".localized() + return { _ in RuuviLocalization.TemperatureUnit.Fahrenheit.title } case .kelvin: - return "TemperatureUnit.Kelvin.title".localized() + return { _ in RuuviLocalization.TemperatureUnit.Kelvin.title } } } } extension UnitTemperature: SelectionItemProtocol { - var title: String { + var title: (String) -> String { switch self { case .celsius: - return "TemperatureUnit.Celsius.title".localized() + return { _ in RuuviLocalization.TemperatureUnit.Celsius.title } case .fahrenheit: - return "TemperatureUnit.Fahrenheit.title".localized() + return { _ in RuuviLocalization.TemperatureUnit.Fahrenheit.title } case .kelvin: - return "TemperatureUnit.Kelvin.title".localized() + return { _ in RuuviLocalization.TemperatureUnit.Kelvin.title } default: - return "N/A".localized() + return { _ in RuuviLocalization.na } } } } diff --git a/station/Extensions/UIViewController+Alert.swift b/station/Extensions/UIViewController+Alert.swift index 35377a2c0..801715ef6 100644 --- a/station/Extensions/UIViewController+Alert.swift +++ b/station/Extensions/UIViewController+Alert.swift @@ -1,10 +1,11 @@ import UIKit +import RuuviLocalization extension UIViewController { func showAlert(title: String? = nil, message: String? = nil) { let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "OK".localized(), style: .cancel, handler: nil)) + alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) } } diff --git a/station/Extensions/UnitPressure+Extension.swift b/station/Extensions/UnitPressure+Extension.swift index f30ae9f8d..baf35f0da 100644 --- a/station/Extensions/UnitPressure+Extension.swift +++ b/station/Extensions/UnitPressure+Extension.swift @@ -1,18 +1,19 @@ import Foundation import RuuviOntology +import RuuviLocalization extension UnitPressure: SelectionItemProtocol { - var title: String { + var title: (String) -> String { switch self { case .hectopascals: - return "UnitPressure.hectopascal.title".localized() + return { _ in RuuviLocalization.UnitPressure.Hectopascal.title } case .inchesOfMercury: - return "UnitPressure.inchOfMercury.title".localized() + return { _ in RuuviLocalization.UnitPressure.InchOfMercury.title } case .millimetersOfMercury: - return "UnitPressure.millimetreOfMercury.title".localized() + return { _ in RuuviLocalization.UnitPressure.MillimetreOfMercury.title } default: assert(false, "Not allowed") - return .init() + return { _ in .init() } } } var alertRange: Range { diff --git a/station/Extensions/UnitSettingsType.swift b/station/Extensions/UnitSettingsType.swift index 8ffff8605..3e0554d1d 100644 --- a/station/Extensions/UnitSettingsType.swift +++ b/station/Extensions/UnitSettingsType.swift @@ -1,4 +1,5 @@ import Foundation +import RuuviLocalization enum UnitSettingsType { case unit @@ -6,12 +7,12 @@ enum UnitSettingsType { } extension UnitSettingsType: SelectionItemProtocol { - var title: String { + var title: (String) -> String { switch self { case .unit: - return "Settings.Measurement.Unit.title".localized() + return { _ in RuuviLocalization.Settings.Measurement.Unit.title } case .accuracy: - return "Settings.Measurement.Resolution.title".localized() + return { _ in RuuviLocalization.Settings.Measurement.Resolution.title } } } } diff --git a/swiftgen.yml b/swiftgen.yml index b20fb6b31..0752caad9 100644 --- a/swiftgen.yml +++ b/swiftgen.yml @@ -1,25 +1,34 @@ json: - inputs: ./station.localization/station.localization.json outputs: - - templatePath: ./templates/Localizable_en.strings.stencil - output: ./station/Resources/Strings/en.lproj/Localizable.strings + - templatePath: ./Common/RuuviLocalization/Templates/Localizable_en.strings.stencil + output: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings - inputs: ./station.localization/station.localization.json outputs: - - templatePath: ./templates/Localizable_sv.strings.stencil - output: ./station/Resources/Strings/sv.lproj/Localizable.strings + - templatePath: ./Common/RuuviLocalization/Templates/Localizable_sv.strings.stencil + output: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/sv.lproj/Localizable.strings - inputs: ./station.localization/station.localization.json outputs: - - templatePath: ./templates/Localizable_ru.strings.stencil - output: ./station/Resources/Strings/ru.lproj/Localizable.strings + - templatePath: ./Common/RuuviLocalization/Templates/Localizable_ru.strings.stencil + output: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/ru.lproj/Localizable.strings - inputs: ./station.localization/station.localization.json outputs: - - templatePath: ./templates/Localizable_fi.strings.stencil - output: ./station/Resources/Strings/fi.lproj/Localizable.strings + - templatePath: ./Common/RuuviLocalization/Templates/Localizable_fi.strings.stencil + output: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fi.lproj/Localizable.strings - inputs: ./station.localization/station.localization.json outputs: - - templatePath: ./templates/Localizable_fr.strings.stencil - output: ./station/Resources/Strings/fr.lproj/Localizable.strings + - templatePath: ./Common/RuuviLocalization/Templates/Localizable_fr.strings.stencil + output: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fr.lproj/Localizable.strings - inputs: ./station.localization/station.localization.json outputs: - - templatePath: ./templates/Localizable_de.strings.stencil - output: ./station/Resources/Strings/de.lproj/Localizable.strings + - templatePath: ./Common/RuuviLocalization/Templates/Localizable_de.strings.stencil + output: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/de.lproj/Localizable.strings +strings: + inputs: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings + outputs: + templateName: structured-swift5 + params: + forceProvidesNamespaces: true + publicAccess: true + enumName: RuuviLocalization + output: ./Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift \ No newline at end of file From 2e1024b77b0bee8f93a0eaa48097b4e91d8afa04 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 9 Dec 2023 14:56:42 +0200 Subject: [PATCH 30/84] update localization --- station.localization | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/station.localization b/station.localization index 3aabb0eb2..7847c3820 160000 --- a/station.localization +++ b/station.localization @@ -1 +1 @@ -Subproject commit 3aabb0eb204558f83c98374e4f34b57d031cbbee +Subproject commit 7847c38208cc1a7228ed3f312b6001c83ca626d0 From b050b7104ab1c69ade9e1f839f5d98bbd08052c1 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 9 Dec 2023 16:11:44 +0200 Subject: [PATCH 31/84] Formats the swift codebase with a SwiftFormat (#1760) Apply changes made by swift format to the whole app project --- .swiftformat | 2 + Common/RuuviLocalization/Package.swift | 9 +- .../RuuviLocalizationTests.swift | 5 +- Common/RuuviPresenters/Package.swift | 4 +- .../ActivityPresenterRuuviLogo.swift | 10 +- .../RuuviLogo/ActivityPresenterState.swift | 18 +- .../View/ActivityPresenterView.swift | 40 +- .../View/ActivityPresenterViewProvider.swift | 8 +- .../RuuviLogo/View/ActivitySpinnerView.swift | 19 +- .../Alert/PermissionPresenterAlert.swift | 2 +- .../Util/RuuviBundleUtils.swift | 42 +- .../Util/UIWindow+Orientation.swift | 10 +- .../RuuviPresentersTests.swift | 5 +- Modules/RuuviDiscover/Package.swift | 9 +- .../Sources/RuuviDiscover/RuuviDiscover.swift | 2 +- .../RuuviDiscover/RuuviDiscoverFactory.swift | 10 +- .../RuuviDiscover/Util/RuuviBundleUtils.swift | 42 +- .../Util/UITableViewCell+ReusableView.swift | 21 +- .../Util/UIViewController+Alert.swift | 3 +- .../VMP/Presenter/DiscoverPresenter.swift | 122 +- .../VMP/View/DiscoverViewInput.swift | 4 +- .../VMP/View/DiscoverViewOutput.swift | 2 +- .../Model/DiscoverRuuviTagViewModel.swift | 2 +- .../DiscoverAddWithMACTableViewCell.swift | 2 +- .../Cell/DiscoverDeviceTableViewCell.swift | 6 +- .../Cell/DiscoverNoDevicesTableViewCell.swift | 2 +- .../View/Table/DiscoverTableHeaderView.swift | 36 +- .../Table/DiscoverTableViewController.swift | 99 +- .../RuuviDiscoverTests.swift | 3 +- Modules/RuuviFirmware/Package.swift | 6 +- .../RuuviFirmware/Common/Feedback.swift | 2 +- .../Common/LargeButtonStyle.swift | 2 +- .../RuuviFirmware/Common/ProgressBar.swift | 6 +- .../RuuviFirmware/Common/RuuvoBoardView.swift | 5 +- .../RuuviFirmware/Common/Spinner.swift | 6 +- .../URLSession+downloadTaskPublisher.swift | 34 +- .../RuuviFirmware/FirmwareInteractor.swift | 70 +- .../RuuviFirmware/FirmwarePresenter.swift | 7 +- .../Model/GitHubRelease+URL.swift | 38 +- .../RuuviFirmware/Model/GitHubRelease.swift | 3 +- .../Repository/FirmwareRepository.swift | 9 +- .../RuuviFirmware/SwiftUI/FirmwareView.swift | 55 +- .../SwiftUI/FirmwareViewModel.swift | 142 +- .../RuuviFirmware/Util/RuuviBundleUtils.swift | 42 +- .../RuuviFirmware/Util/RuuviColor.swift | 2 +- .../RuuviFirmwareTests.swift | 2 +- Modules/RuuviOnboard/Package.swift | 11 +- .../Pages/Assests/RuuviAssets.swift | 2 +- .../Pages/Extensions/UIButton+Extension.swift | 6 +- .../Pages/Extensions/UIFont+Extension.swift | 28 +- .../Pages/Extensions/UIImageView+Init.swift | 9 +- .../Pages/Extensions/UILabel+Init.swift | 7 +- .../Pages/Extensions/UIView+Init.swift | 11 +- .../Pages/Extensions/UIView+Layout.swift | 42 +- .../Sources/RuuviOnboard/Pages/Helpers.swift | 9 +- .../Pages/RuuviOnboardCoreFeaturesCell.swift | 18 +- .../RuuviOnboardGatewayFeaturesCell.swift | 22 +- .../Pages/RuuviOnboardPages.swift | 14 +- .../Pages/RuuviOnboardSignInCell.swift | 25 +- .../Pages/RuuviOnboardStartCell.swift | 21 +- .../Pages/RuuviOnboardViewController.swift | 62 +- .../Pages/Util/RuuviBundleUtils.swift | 42 +- .../RuuviOnboardTests/RuuviOnboardTests.swift | 5 +- Packages/RuuviAnalytics/Package.swift | 19 +- .../RuuviAnalyticsImpl.swift | 202 +-- .../RuuviAnalyticsTests.swift | 5 +- Packages/RuuviCloud/Package.swift | 20 +- .../Sources/RuuviCloud/RuuviCloud.swift | 8 +- .../RuuviCloudApi/Helpers/Reachability.swift | 7 +- .../Sources/RuuviCloudApi/RuuviCloudApi.swift | 4 +- .../RuuviCloudApiGetSensorsDenseRequest.swift | 3 +- .../Request/RuuviCloudApiUserRequest.swift | 3 +- .../RuuviCloudPNTokenRegisterRequest.swift | 5 +- .../RuuviCloudPNTokenUnregisterRequest.swift | 2 +- ...uuviCloudApiSensorImageUploadRequest.swift | 2 +- .../Response/RuuviCloudApiBaseResponse.swift | 16 +- .../Response/RuuviCloudApiClaimResponse.swift | 4 +- .../RuuviCloudApiGetAlertsResponse.swift | 9 +- .../RuuviCloudApiGetSensorResponse.swift | 6 +- ...RuuviCloudApiGetSensorsDenseResponse.swift | 4 +- .../RuuviCloudApiGetSensorsResponse.swift | 2 +- .../RuuviCloudApiGetSettingsResponse.swift | 52 +- .../Response/RuuviCloudApiUserResponse.swift | 35 +- .../RuuviCloudPNTokenListResponse.swift | 6 +- .../Settings/RuuviCloudApiSettings.swift | 108 +- .../RuuviCloudApiFactoryURLSession.swift | 2 +- .../URLSession/RuuviCloudApiURLSession.swift | 184 +-- .../ThirdParty/URLQueryItemEncoder.swift | 818 +++++------ .../RuuviCloudFactoryPure.swift | 7 +- .../RuuviCloudPure/RuuviCloudPure.swift | 106 +- .../RuuviCloudTests/RuuviCloudTests.swift | 5 +- Packages/RuuviContext/Package.swift | 13 +- .../RealmContextFactoryImpl.swift | 2 +- .../RuuviContextRealm/RealmContextImpl.swift | 4 +- .../SQLiteContextFactoryGRDB.swift | 2 +- .../SQLiteContextGRDB.swift | 60 +- .../RuuviContextTests/RuuviContextTests.swift | 5 +- Packages/RuuviCore/Package.swift | 23 +- .../Sources/RuuviCore/RuuviCoreLocation.swift | 2 +- .../RuuviCore/RuuviCorePermission.swift | 6 +- .../Impl/DiffCalculatorImpl.swift | 31 +- .../RuuviCoreDiff/Models/ReloadableCell.swift | 2 +- .../Models/ReloadableCellData.swift | 4 +- .../Models/ReloadableSection.swift | 2 +- .../Models/ReloadableSectionData.swift | 4 +- .../RuuviCoreDiff/Models/SectionChanges.swift | 9 +- .../RuuviCoreDiff/Util/Array+Extension.swift | 18 +- .../RuuviCoreImage/RuuviCoreImageImpl.swift | 12 +- .../RuuviCoreLocationImpl.swift | 20 +- .../Sources/RuuviCorePN/RuuviCorePNImpl.swift | 20 +- .../RuuviCorePermissionImpl.swift | 34 +- .../Tests/RuuviCoreTests/RuuviCoreTests.swift | 5 +- Packages/RuuviDFU/Package.swift | 16 +- .../RuuviDFU/Sources/RuuviDFU/DFUDevice.swift | 2 +- .../RuuviDFU/Sources/RuuviDFU/RuuviDFU.swift | 6 +- .../Sources/RuuviDFUImpl/DfuFlasher.swift | 15 +- .../Sources/RuuviDFUImpl/DfuScanner.swift | 42 +- .../Sources/RuuviDFUImpl/RuuviDFUImpl.swift | 16 +- .../Tests/RuuviDFUTests/RuuviDFUTests.swift | 5 +- Packages/RuuviDaemon/Package.swift | 28 +- .../RuuviDaemon/RuuviDaemonError.swift | 8 +- .../RuuviDaemon/RuuviDaemonWorker.swift | 5 +- .../RuuviTagAdvertisementDaemon.swift | 6 +- .../RuuviDaemon/RuuviTagHeartbeatDaemon.swift | 6 +- .../RuuviTagPropertiesDaemon.swift | 4 +- .../BackgroundProcessServiceiOS13.swift | 5 +- .../RuuviDaemonCloudSyncWorker.swift | 4 +- .../RuuviDaemonFactoryCloudSync.swift | 4 +- .../RuuviDaemonOperation/AsyncOperation.swift | 72 +- .../Data/DataPruningOperationsManager.swift | 9 +- .../Data/RuuviTagDataPruningOperation.swift | 1 - .../RuuviTagAdvertisementDaemonBTKit.swift | 127 +- .../RuuviTagHeartbeatDaemonBTKit.swift | 177 +-- .../RuuviTagPropertiesDaemonBTKit.swift | 80 +- .../RuuviDaemonTests/RuuviDaemonTests.swift | 5 +- Packages/RuuviLocal/Package.swift | 15 +- .../RuuviLocal/RuuviLocalConnections.swift | 6 +- .../Sources/RuuviLocal/RuuviLocalImages.swift | 8 +- .../RuuviLocal/RuuviLocalSettings.swift | 44 +- .../RuuviLocal/RuuviLocalSyncState.swift | 12 +- .../Documents/ImagePersistenceDocuments.swift | 6 +- .../Background/Image/ImagePersistence.swift | 4 +- .../RuuviLocalImagesUserDefaults.swift | 26 +- .../RuuviLocalConnectionsUserDefaults.swift | 16 +- .../RuuviLocalFactoryUserDefaults.swift | 10 +- .../RuuviLocalIDsUserDefaults.swift | 6 +- .../RuuviLocalSettingsUserDefaults.swift | 128 +- .../RuuviLocalSyncStateUserDefaults.swift | 33 +- .../RuuviLocalUserDefaults/UserDefault.swift | 2 +- .../RuuviLocalTests/RuuviLocalTests.swift | 5 +- Packages/RuuviMigration/Package.swift | 17 +- .../MigrationManagerAlertService.swift | 54 +- .../RuuviMigrationFactoryImpl.swift | 6 +- .../MigrationManagerSensorSettings.swift | 4 +- .../CalibrationPersistenceUserDefaults.swift | 5 +- .../RuuviMigrationImpl/Util/UserDefault.swift | 2 +- .../RuuviMigrationFixRHAlerts.swift | 11 +- .../toRH/MigrationManagerToRH.swift | 25 +- .../toSQLite/MigrationManagerToSQLite.swift | 10 +- .../toVIPER/MigrationManagerToVIPER.swift | 60 +- .../RuuviMigrationTests.swift | 5 +- Packages/RuuviNotification/Package.swift | 17 +- .../RuuviNotificationLocal.swift | 4 +- .../RuuviNotificationLocalImpl.swift | 127 +- .../RuuviNotificationTests.swift | 5 +- Packages/RuuviNotifier/Package.swift | 19 +- .../Sources/RuuviNotifier/RuuviNotifier.swift | 10 +- .../RuuviNotifierImpl+Process.swift | 103 +- .../RuuviNotifierImpl/RuuviNotifierImpl.swift | 14 +- .../RuuviNotifierTests.swift | 5 +- Packages/RuuviOntology/Package.swift | 22 +- .../RuuviOntology/Alert/AlertType.swift | 18 +- .../RuuviOntology/Alert/RuuviAlertSound.swift | 4 +- .../Common/Double+Temperature.swift | 18 +- .../RuuviOntology/Common/Location.swift | 44 +- .../RuuviOntology/Common/Reorderable.swift | 4 +- .../Common/RuuviCloudQueuedRequest.swift | 7 +- .../RuuviOntology/Common/RuuviTheme.swift | 6 +- .../Common/TemperatureUnit.swift | 16 +- .../RuuviOntology/Identifier/Identifier.swift | 48 +- .../Mappers/RuuviTag+RuuviTagSensor.swift | 8 +- .../RuuviTag+RuuviTagSensorRecord.swift | 38 +- ...viTagEnvLogFull+RuuviTagSensorRecord.swift | 17 +- ...uuviTagSensorRecord+RuuviMeasurement.swift | 6 +- .../Measurement/Measurement.swift | 51 +- .../Measurement/MeasurementAccuracyType.swift | 12 +- .../Measurement/RuuviMeasurement.swift | 12 +- .../Notification/RuuviCloudPNToken.swift | 3 +- .../RuuviOntology/Sensor/CloudSensor.swift | 46 +- .../Sensor/CloudSensorDense.swift | 68 +- .../RuuviOntology/Sensor/PhysicalSensor.swift | 11 +- .../Sensor/RuuviTag/RuuviTagSensor.swift | 134 +- .../RuuviTag/RuuviTagSensorRecord.swift | 84 +- .../RuuviOntology/Sensor/SensorSettings.swift | 16 +- .../Sensor/ShareableSensor.swift | 16 +- .../RuuviTagDataRealm+Extension.swift | 46 +- ...uviTagDataRealm+RuuviTagSensorRecord.swift | 6 +- .../RuuviTagDataRealm.swift | 85 +- .../RuuviTagLatestDataRealm+Extension.swift | 46 +- ...LatestDataRealm+RuuviTagSensorRecord.swift | 6 +- .../RuuviTagLatestDataRealm.swift | 85 +- .../RuuviTagRealm+RuuviTagSensor.swift | 28 +- .../RuuviOntologyRealm/RuuviTagRealm.swift | 44 +- .../SensorSettingsRealm.swift | 6 +- .../RuuviCloudQueuedRequestSQLite.swift | 40 +- .../RuuviTagDataSQLite.swift | 60 +- .../RuuviTagLatestDataSQLite.swift | 60 +- .../RuuviOntologySQLite/RuuviTagSQLite.swift | 38 +- ...viTagSensorRecord+RuuviTagDataSQLite.swift | 10 +- .../SensorSettingsSQLite.swift | 38 +- .../RuuviOntologyTests.swift | 5 +- Packages/RuuviPersistence/Package.swift | 20 +- .../RuuviPersistence/RuuviPersistence.swift | 3 +- .../RuuviPersistenceRealm.swift | 100 +- .../RuuviPersistenceSQLite.swift | 75 +- .../RuuviPersistenceTests.swift | 5 +- Packages/RuuviPool/Package.swift | 15 +- .../Sources/RuuviPool/RuuviPool.swift | 7 +- .../Sources/RuuviPool/RuuviPoolFactory.swift | 2 +- .../RuuviPoolCoordinator.swift | 57 +- .../RuuviPoolFactoryCoordinator.swift | 4 +- .../Tests/RuuviPoolTests/RuuviPoolTests.swift | 5 +- Packages/RuuviReactor/Package.swift | 15 +- .../RuuviTagLastRecordSubjectCombine.swift | 23 +- .../RuuviTagLatestRecordSubjectCombine.swift | 23 +- .../RuuviTagRecordSubjectCombine.swift | 33 +- .../RuuviTagSubjectCombine.swift | 26 +- .../SensorSettingsCombine.swift | 31 +- .../RuuviReactorFactoryImpl.swift | 2 +- .../RuuviReactorImpl/RuuviReactorImpl.swift | 42 +- .../RuuviReactorTests/RuuviReactorTests.swift | 5 +- Packages/RuuviRepository/Package.swift | 15 +- .../RuuviRepositoryCoordinator.swift | 14 +- .../RuuviRepositoryFactoryCoordinator.swift | 4 +- .../RuuviRepositoryTests.swift | 5 +- Packages/RuuviService/Package.swift | 74 +- .../Sources/RuuviService/AsyncOperation.swift | 74 +- .../Sources/RuuviService/GATTService.swift | 22 +- .../RuuviService/RuuviServiceAlert.swift | 12 +- .../RuuviServiceCloudNotification.swift | 1 - .../RuuviService/RuuviServiceError.swift | 6 +- .../RuuviServiceMeasurement.swift | 56 +- .../RuuviServiceOffsetCalibration.swift | 6 +- .../RuuviService/RuuviServiceOwnership.swift | 2 +- .../RuuviServiceSensorProperties.swift | 8 +- .../AlertPersistenceUserDefaults.swift | 188 +-- .../UserDefaults/KeyedArchiver.swift | 8 +- .../RuuviServiceAlertImpl.swift | 277 ++-- .../RuuviServiceAppSettingsImpl.swift | 21 +- .../RuuviServiceAuthImpl.swift | 10 +- .../RuuviServiceCloudNotificationImpl.swift | 64 +- .../RuuviServiceCloudSyncImpl.swift | 196 +-- ...uuviServiceCloudSyncRecordsOperation.swift | 19 +- .../RuuviServiceExportImpl.swift | 37 +- .../RuuviServiceFactory.swift | 42 +- .../RuuviTagReadLogsOperation.swift | 38 +- .../Queue/GATTServiceQueue.swift | 5 +- .../RuuviServiceMeasurementImpl.swift | 123 +- ...RuuviServiceAppOffsetCalibrationImpl.swift | 11 +- .../RuuviServiceOwnershipImpl.swift | 20 +- .../RuuviServiceSensorPropertiesImpl.swift | 28 +- .../RuuviServiceSensorRecordsImpl.swift | 2 +- .../RuuviServiceTests/RuuviServiceTests.swift | 5 +- Packages/RuuviStorage/Package.swift | 15 +- .../Sources/RuuviStorage/RuuviStorage.swift | 1 + .../RuuviStorageCoordinator.swift | 20 +- .../RuuviStorageFactoryCoordinator.swift | 2 +- .../RuuviStorageTests/RuuviStorageTests.swift | 5 +- Packages/RuuviUser/Package.swift | 13 +- .../Sources/RuuviUser/RuuviUser.swift | 4 +- .../Keychain/Impl/KeychainServiceImpl.swift | 6 +- .../RuuviUserCoordinator.swift | 8 +- .../Tests/RuuviUserTests/RuuviUserTests.swift | 5 +- intents/IntentHandler.swift | 11 +- pnservice/NotificationService.swift | 72 +- ruuvi-widgets/Assembly/WidgetAssembly.swift | 14 +- ruuvi-widgets/Enum/WidgetSensorEnum.swift | 17 +- ruuvi-widgets/Helper/Constants.swift | 18 +- ruuvi-widgets/Helper/Extensions.swift | 72 +- ruuvi-widgets/Helper/MeasurementService.swift | 35 +- ruuvi-widgets/Model/Model+Extension.swift | 58 +- ruuvi-widgets/Model/WidgetEntry.swift | 53 +- ruuvi-widgets/Provider/WidgetProvider.swift | 37 +- ruuvi-widgets/RuuviWidgets.swift | 14 +- .../View Model/WidgetViewModel.swift | 51 +- ruuvi-widgets/View/EmptyWidgetView.swift | 9 +- ruuvi-widgets/View/SimpleWidgetView.swift | 11 +- .../View/SimpleWidgetViewCircular.swift | 14 +- .../View/SimpleWidgetViewRectangle.swift | 18 +- ruuvi-widgets/View/UnauthorizedView.swift | 1 + station/Classes/Application/AppAssembly.swift | 149 +- .../Application/AppAssemblyConstants.swift | 2 +- station/Classes/Application/AppDelegate.swift | 90 +- .../Application/AppGroupConstants.swift | 2 +- .../AppState/Impl/AppStateServiceImpl.swift | 45 +- .../Features/FeatureToggleService.swift | 12 +- .../FallbackFeatureToggleProvider.swift | 19 +- .../FirebaseFeatureToggleProvider.swift | 9 +- .../FirebaseRemoteConfigService.swift | 4 +- .../RemoteConfig/RemoteConfigService.swift | 2 +- .../Info/Impl/InfoProviderImpl.swift | 41 +- .../Impl/UniversalLinkCoordinatormpl.swift | 34 +- .../Router/Impl/UniversalLinkRouterImpl.swift | 2 +- .../Router/UniversalLinkRouter.swift | 2 +- .../Assembly/PresentationAssembly.swift | 2 +- .../Assembly/PresentationConstants.swift | 2 +- .../Binding/NSObject+Observable.swift | 7 +- .../Presentation/Binding/Observable.swift | 4 +- .../Presentation/Binding/Optional.swift | 30 +- .../Presentation/Colors/RuuviColor.swift | 2 +- .../Presentation/Contract/ViewInput.swift | 3 +- .../FLEX/FeatureTogglesViewController.swift | 70 +- .../About/Assembly/AboutInitializer.swift | 2 +- .../About/Presenter/AboutModuleInput.swift | 4 +- .../About/Presenter/AboutPresenter.swift | 13 +- .../About/View/AboutViewController.swift | 68 +- .../BackgroundSelectionModuleFactory.swift | 6 +- .../BackgroundSelectionPresenter.swift | 110 +- .../View/BackgroundSelectionViewModel.swift | 8 +- .../View/BackgroundSelectionViewOutput.swift | 2 +- .../UI/BackgroundSelectionButtonView.swift | 21 +- ...ackgroundSelectionUploadProgressView.swift | 38 +- .../View/UI/BackgroundSelectionViewCell.swift | 4 +- .../BackgroundSelectionViewController.swift | 70 +- .../UI/BackgroundSelectionViewHeader.swift | 24 +- .../Assembly/CardsViewModuleFactory.swift | 14 +- .../Cards/Interactor/CardsInteractor.swift | 14 +- .../Interactor/CardsInteractorInput.swift | 2 +- .../Cards/Presenter/CardsPresenter.swift | 584 ++++---- .../Dashboard/Cards/Router/CardsRouter.swift | 18 +- .../Dashboard/Cards/View/CardsViewInput.swift | 4 +- .../Dashboard/Cards/View/CardsViewModel.swift | 117 +- .../Cards/View/UI/CardsBackgroundView.swift | 11 +- .../Cards/View/UI/CardsIndicatorView.swift | 8 +- .../Cards/View/UI/CardsLargeImageCell.swift | 44 +- .../Cards/View/UI/CardsViewController.swift | 146 +- .../Assembly/TagChartsModuleFactory.swift | 13 +- .../Assembly/TagChartsViewConfigurator.swift | 15 +- .../Charts/Helpers/CustomXAxisRenderer.swift | 49 +- .../Charts/Helpers/CustomYAxisRenderer.swift | 14 +- .../Charts/Helpers/TagChartsHelper.swift | 4 +- .../Charts/Helpers/XAxisValueFormatter.swift | 5 +- .../Charts/Helpers/YAxisValueFormatter.swift | 4 +- .../Interactor/TagChartsViewInteractor.swift | 101 +- .../TagChartsViewInteractorInput.swift | 2 +- .../Presenter/TagChartsViewModuleInput.swift | 1 + .../Presenter/TagChartsViewPresenter.swift | 283 ++-- .../Charts/View/TagChartsViewInput.swift | 2 +- .../Charts/View/TagChartsViewModel.swift | 22 +- .../Charts/View/UI/TagChartsMarkerView.swift | 35 +- .../Charts/View/UI/TagChartsView.swift | 62 +- .../View/UI/TagChartsViewController.swift | 262 ++-- .../Assembly/DashboardModuleFactory.swift | 19 +- .../Home/Interactor/DashboardInteractor.swift | 28 +- .../Interactor/DashboardInteractorInput.swift | 2 +- .../Home/Presenter/DashboardModuleInput.swift | 4 +- .../Home/Presenter/DashboardPresenter.swift | 709 +++++----- .../Home/Router/DashboardRouter.swift | 62 +- .../Home/View/DashboardImageCell.swift | 87 +- .../Home/View/DashboardIndicatorView.swift | 7 +- .../Home/View/DashboardPlainCell.swift | 99 +- .../Home/View/DashboardViewController.swift | 214 +-- .../Home/View/DashboardViewInput.swift | 2 +- .../Dashboard/Home/View/LowBatteryView.swift | 6 +- .../Dashboard/Home/View/NoSensorView.swift | 28 +- .../Home/View/RuuviContextMenuButton.swift | 31 +- .../RuuviSimpleViewCompositionalLayout.swift | 5 +- .../Table/MenuTableConfigurator.swift | 4 +- .../Assembly/Table/MenuTableInitializer.swift | 2 +- .../Menu/Presenter/MenuPresenter.swift | 13 +- .../MenuTableDismissTransitionAnimation.swift | 21 +- .../MenuTablePresentTransitionAnimation.swift | 15 +- .../MenuTablePresentationController.swift | 25 +- .../Table/MenuTableTransitionManager.swift | 4 +- .../MenuTableTransitioningDelegate.swift | 41 +- .../Modules/Menu/View/MenuViewInput.swift | 4 +- .../MenuTableEmbededViewController.swift | 43 +- .../View/Table/MenuTableViewController.swift | 3 +- .../Assembly/MyRuuviAccountConfigurator.swift | 6 +- .../Assembly/MyRuuviAccountInitializer.swift | 2 +- .../Presenter/MyRuuviAccountPresenter.swift | 18 +- .../View/MyRuuviAccountViewController.swift | 21 +- .../View/MyRuuviAccountViewInput.swift | 2 +- .../View/MyRuuviAccountViewModel.swift | 2 +- .../Table/SettingsTableConfigurator.swift | 6 +- .../Table/SettingsTableInitializer.swift | 2 +- .../Presenter/SettingsModuleInput.swift | 4 +- .../Module/Presenter/SettingsPresenter.swift | 24 +- .../Module/Router/SettingsRouter.swift | 20 +- .../Table/SettingsTableViewController.swift | 85 +- .../AppearanceSettingsModuleFactory.swift | 2 +- .../AppearanceSettingsModuleInput.swift | 4 +- .../AppearanceSettingsPresenter.swift | 28 +- .../Assembly/ASSelectionModuleFactory.swift | 2 +- .../Presenter/ASSelectionPresenter.swift | 13 +- .../View/UI/ASSelectionTableViewCell.swift | 7 +- .../UI/ASSelectionTableViewController.swift | 35 +- ...AppearanceSettingsTableViewBasicCell.swift | 9 +- ...ppearanceSettingsTableViewController.swift | 31 +- .../Assembly/ChartSettingsInitializer.swift | 2 +- .../Presenter/ChartSettingsPresenter.swift | 26 +- .../Router/ChartSettingsRouterInput.swift | 3 +- .../Chart/View/ChartSettingsViewModel.swift | 8 +- ...ChartSettingsDisclosureTableViewCell.swift | 3 +- .../ChartSettingsStepperTableViewCell.swift | 8 +- .../ChartSettingsSwitchTableViewCell.swift | 8 +- .../ChartSettingsTableViewController.swift | 31 +- .../Assembly/DefaultsInitializer.swift | 2 +- .../Presenter/DefaultsPresenter.swift | 17 +- .../View/DefaultsViewController.swift | 64 +- .../Defaults/View/DefaultsViewModel.swift | 9 +- .../SwiftUI/DefaultsEnvironmentObject.swift | 12 +- .../Defaults/View/SwiftUI/DefaultsList.swift | 35 +- .../Cells/DefaultsPlainTableViewCell.swift | 6 +- .../Cells/DefaultsStepperTableViewCell.swift | 17 +- .../Cells/DefaultsSwitchTableViewCell.swift | 8 +- .../Table/DefaultsTableViewController.swift | 18 +- .../Assembly/DevicesModuleFactory.swift | 6 +- .../Devices/Presenter/DevicesPresenter.swift | 14 +- .../Devices/View/DevicesViewModel.swift | 8 +- .../Devices/View/DevicesViewOutput.swift | 2 +- .../View/UI/DevicesTableViewCell.swift | 9 +- .../View/UI/DevicesTableViewController.swift | 39 +- .../Assembly/HeartbeatInitializer.swift | 2 +- .../Presenter/HeartbeatPresenter.swift | 4 +- .../Router/HeartbeatRouterInput.swift | 4 +- .../View/HeartbeatViewController.swift | 64 +- .../Heartbeat/View/HeartbeatViewModel.swift | 4 +- .../Heartbeat/View/HeartbeatViewOutput.swift | 4 +- .../SwiftUI/HeartbeatEnvironmentObject.swift | 12 +- .../View/SwiftUI/HeartbeatList.swift | 41 +- .../Table/HeartbeatTableViewController.swift | 43 +- .../NotificationsSettingsModuleFactory.swift | 4 +- .../NotificationsSettingsPresenter.swift | 44 +- .../Router/NotificationsSettingsRouter.swift | 2 +- ...PushAlertSoundSelectionModuleFactory.swift | 2 +- .../PushAlertSoundSelectionPresenter.swift | 7 +- ...PushAlertSoundSelectionTableViewCell.swift | 7 +- ...ertSoundSelectionTableViewController.swift | 39 +- .../View/NotificationsSettingsViewModel.swift | 8 +- .../UI/NotificationsSettingsSwitchCell.swift | 15 +- ...ficationsSettingsTableViewController.swift | 52 +- .../UI/NotificationsSettingsTextCell.swift | 14 +- .../Assembly/RuuviCloudModuleFactory.swift | 4 +- .../Presenter/RuuviCloudPresenter.swift | 18 +- .../View/RuuviCloudViewModel.swift | 2 +- .../View/UI/RuuviCloudTableViewCell.swift | 10 +- .../UI/RuuviCloudTableViewController.swift | 36 +- .../Table/SelectionTableInitializer.swift | 2 +- .../Presenter/SelectionPresenter.swift | 8 +- .../View/Table/SelectionTableViewCell.swift | 3 +- .../Table/SelectionTableViewController.swift | 26 +- .../Table/UnitSettingsTableInitializer.swift | 2 +- .../Presenter/UnitSettingsPresenter.swift | 53 +- .../Router/UnitSettingsRouter.swift | 4 +- .../Table/UnitSettingsTableViewCell.swift | 4 +- .../UnitSettingsTableViewController.swift | 17 +- .../Share/Assembly/ShareConfigurator.swift | 2 +- .../Share/Assembly/ShareInitializer.swift | 2 +- .../Share/Presenter/ShareModuleOutput.swift | 3 +- .../Share/Presenter/SharePresenter.swift | 54 +- .../Share/Router/ShareRouterInput.swift | 1 + .../Cells/ShareDescriptionTableViewCell.swift | 4 +- .../Cells/ShareEmailInputTableViewCell.swift | 2 +- .../View/Cells/ShareEmailTableViewCell.swift | 7 +- .../Cells/ShareSendButtonTableViewCell.swift | 2 +- .../Modules/Share/View/ShareViewModel.swift | 2 +- .../ViewController/ShareViewController.swift | 70 +- .../SignIn/Assembly/SignInModuleFactory.swift | 6 +- .../SignIn/Presenter/SignInPresenter.swift | 52 +- .../Modules/SignIn/Router/SignInRouter.swift | 3 +- .../SignInBenefitsModuleFactory.swift | 1 - .../Presenter/SignInBenefitsPresenter.swift | 15 +- .../View/SignInBenefitsViewController.swift | 40 +- .../View/UI/Helper/RuuviCodeTextField.swift | 1 - .../SignIn/View/UI/Helper/RuuviCodeView.swift | 17 +- .../View/UI/Helper/SignInVerifyView.swift | 22 +- .../SignIn/View/UI/Helper/SignInView.swift | 20 +- .../SignIn/View/UI/SignInViewController.swift | 32 +- .../Assembly/TagSettingsModuleFactory.swift | 18 +- .../Presenter/TagSettingsPresenter.swift | 335 +++-- .../Router/TagSettingsRouter.swift | 28 +- .../Router/TagSettingsRouterInput.swift | 2 +- .../Submodules/DFU/DFUModuleFactory.swift | 14 +- .../DFU/Interactor/DFUInteractor.swift | 54 +- .../DFU/Interactor/DFUInteractorInput.swift | 6 +- .../DFU/Interactor/LatestRelease.swift | 18 +- .../DFU/Presenter/DFUModuleInput.swift | 2 +- .../DFU/Presenter/DFUPresenter.swift | 26 +- .../Submodules/DFU/View/DFUViewModel.swift | 285 ++-- .../DFU/View/SwiftUI/DFUUIView.swift | 25 +- .../SensorForceClaimModuleFactory.swift | 10 +- .../Presenter/SensorForceClaimPresenter.swift | 23 +- .../View/SensorForceClaimViewOutput.swift | 2 +- .../UI/SensorForceClaimViewController.swift | 33 +- .../OffsetCorrectionAppleInitializer.swift | 2 +- .../Apple/OffsetCorrectionConfigurator.swift | 8 +- .../Presenter/OffsetCorrectionPresenter.swift | 98 +- .../OffsetCorrectionAppleViewController.swift | 90 +- .../View/OffsetCorrectionViewModel.swift | 65 +- .../Owner/Assembly/OwnerConfigurator.swift | 6 +- .../Owner/Assembly/OwnerInitializer.swift | 2 +- .../Owner/Presenter/OwnerPresenter.swift | 15 +- .../Submodules/Owner/Router/OwnerRouter.swift | 2 +- .../Owner/View/OwnerViewController.swift | 49 +- .../Assembly/SensorRemovalModuleFactory.swift | 4 +- .../Presenter/SensorRemovalPresenter.swift | 11 +- .../View/SensorRemovalViewOutput.swift | 2 +- .../View/UI/SensorRemovalViewController.swift | 43 +- .../View/TagSettingsViewModel.swift | 198 +-- .../View/TagSettingsViewOutput.swift | 2 +- .../RUAlertDetailsCellChildView.swift | 9 +- .../RUAlertExpandButton.swift | 7 +- .../RangeSeekSlider/RURangeSeekSlider.swift | 7 +- .../View/UI/TagSettingsAlertConfigCell.swift | 63 +- .../TagSettingsBackgroundSelectionView.swift | 17 +- .../View/UI/TagSettingsBasicCell.swift | 31 +- .../TagSettingsExpandableSectionHeader.swift | 51 +- .../View/UI/TagSettingsFooterCell.swift | 7 +- .../View/UI/TagSettingsPlainCell.swift | 18 +- .../UI/TagSettingsSimpleSectionHeader.swift | 11 +- .../View/UI/TagSettingsSwitchCell.swift | 10 +- .../View/UI/TagSettingsViewController.swift | 1208 ++++++++--------- .../Alert/Impl/AlertPresenterImpl.swift | 4 +- .../MailComposer/MailComposerPresenter.swift | 2 +- .../MailComposerPresenterMessageUI.swift | 16 +- .../Sheet/PhotoPickerPresenterSheet.swift | 13 +- ...ipeDownToDismissNavigationController.swift | 14 +- ...wipeDownToDismissTransitionAnimation.swift | 16 +- ...peDownToDismissTransitioningDelegate.swift | 12 +- station/Classes/Routers/AppRouter.swift | 48 +- station/Classes/Routers/DiscoverRouter.swift | 16 +- station/Classes/Routers/OnboardRouter.swift | 19 +- .../Extensions/Array+AnyRuuviTagSensor.swift | 6 +- station/Extensions/CALayer+IB.swift | 9 +- .../Classess/AppDateFormatter.swift | 6 +- .../Classess/RuuviCustomButton.swift | 10 +- .../Classess/RuuviLinkTextView.swift | 19 +- .../Extensions/Classess/RuuviUISwitch.swift | 1 - station/Extensions/Color+Ruuvi.swift | 10 +- station/Extensions/Date+Ruuvi.swift | 2 +- station/Extensions/DfuFirmware+Log.swift | 6 +- station/Extensions/Double+Extension.swift | 6 +- station/Extensions/Double+Temperature.swift | 16 +- station/Extensions/Errors/RUError.swift | 118 +- .../RuuviCloudApiError+LocalizedError.swift | 90 +- .../RuuviCloudError+LocalizedError.swift | 8 +- .../RuuviCoreError+LocalizedError.swift | 8 +- .../Errors/RuuviDFUError+LocalizedError.swift | 4 +- .../RuuviDaemonError+LocalizedError.swift | 30 +- .../RuuviLocalError+LocalizedError.swift | 10 +- ...RuuviPersistenceError+LocalizedError.swift | 12 +- .../RuuviPoolError+LocalizedError.swift | 4 +- .../RuuviReactorError+LocalizedError.swift | 4 +- .../RuuviRepositoryError+LocalizedError.swift | 10 +- .../RuuviServiceError+LocalizedError.swift | 48 +- .../RuuviStorageError+LocalizedError.swift | 4 +- station/Extensions/FileManager+Date.swift | 6 +- station/Extensions/Humidity+Offset.swift | 9 +- .../HumidityUnit+Localization.swift | 20 +- station/Extensions/Int+Extension.swift | 10 +- .../Extensions/Language+Localization.swift | 14 +- .../MeasurementAccuracyType+Extension.swift | 6 +- station/Extensions/MeasurementType.swift | 4 +- .../NSObjectProtocol+Invalidation.swift | 1 - .../RuuviAlertSound+Extension.swift | 6 +- station/Extensions/RuuviTheme+Extension.swift | 8 +- station/Extensions/String+Characters.swift | 8 +- station/Extensions/String+Replace.swift | 23 +- .../Structs/AppStoreReviewHelper.swift | 6 +- station/Extensions/Structs/AppUtility.swift | 8 +- .../Structs/ExportHeadersProvider.swift | 18 +- .../Extensions/Structs/GlobalHelpers.swift | 13 +- .../Structs/MeasurementAccuracyTitles.swift | 5 +- .../Structs/RuuviNotifierTitlesImpl.swift | 2 +- .../RuuviTagBatteryStatusProvider.swift | 16 +- .../TemperatureUnit+Localization.swift | 20 +- station/Extensions/UIButton+Extension.swift | 6 +- .../UICollectionView+Extension.swift | 10 +- station/Extensions/UIColor+Extension.swift | 10 +- .../Extensions/UIDevice+ReadableModel.swift | 182 +-- station/Extensions/UIFont+Extension.swift | 28 +- station/Extensions/UIImage+Extension.swift | 6 +- station/Extensions/UIImageView+Init.swift | 9 +- .../Extensions/UINavigationController.swift | 6 +- .../UITableViewCell+ReusableView.swift | 21 +- .../Extensions/UITextField+Extension.swift | 49 +- station/Extensions/UIView+Extension.swift | 24 +- station/Extensions/UIView+Init.swift | 11 +- station/Extensions/UIView+Layout.swift | 42 +- .../Extensions/UIViewController+Alert.swift | 5 +- station/Extensions/UIWindow+Orientation.swift | 10 +- station/Extensions/UIWindow+Shake.swift | 14 +- .../Extensions/UnitPressure+Extension.swift | 5 +- station/Extensions/UnitSettingsType.swift | 4 +- .../Extensions/UserDefaults+Optional.swift | 1 - station/Resources/Assets/RuuviAssets.swift | 2 +- stationTests/MockAlertPersistence.swift | 153 ++- stationTests/MockCalibrationService.swift | 27 +- .../MockLocalNotificationsManager.swift | 20 +- .../Services/Alert/AlertServiceSpec.swift | 117 +- .../MeasurementsServiceEnSpec.swift | 5 +- .../MeasurementsServiceFiSpec.swift | 5 +- .../MeasurementsServiceRuSpec.swift | 5 +- .../MeasurementsServiceSvSpec.swift | 5 +- stationTests/StationTests.swift | 20 +- stationUITests/StationUITests.swift | 3 - 607 files changed, 9828 insertions(+), 8987 deletions(-) create mode 100644 .swiftformat diff --git a/.swiftformat b/.swiftformat new file mode 100644 index 000000000..61f6ea500 --- /dev/null +++ b/.swiftformat @@ -0,0 +1,2 @@ +--swiftversion 5.9 +--exclude ./Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift \ No newline at end of file diff --git a/Common/RuuviLocalization/Package.swift b/Common/RuuviLocalization/Package.swift index 7ce392528..1178a1008 100644 --- a/Common/RuuviLocalization/Package.swift +++ b/Common/RuuviLocalization/Package.swift @@ -10,7 +10,8 @@ let package = Package( // Products define the executables and libraries a package produces, and make them visible to other packages. .library( name: "RuuviLocalization", - targets: ["RuuviLocalization"]) + targets: ["RuuviLocalization"] + ), ], dependencies: [ // Dependencies declare other packages that this package depends on. @@ -21,9 +22,11 @@ let package = Package( // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "RuuviLocalization", - dependencies: []), + dependencies: [] + ), .testTarget( name: "RuuviLocalizationTests", - dependencies: ["RuuviLocalization"]) + dependencies: ["RuuviLocalization"] + ), ] ) diff --git a/Common/RuuviLocalization/Tests/RuuviLocalizationTests/RuuviLocalizationTests.swift b/Common/RuuviLocalization/Tests/RuuviLocalizationTests/RuuviLocalizationTests.swift index 904e86e9a..25e166b34 100644 --- a/Common/RuuviLocalization/Tests/RuuviLocalizationTests/RuuviLocalizationTests.swift +++ b/Common/RuuviLocalization/Tests/RuuviLocalizationTests/RuuviLocalizationTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviLocalization +import XCTest final class RuuviLocalizationTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Common/RuuviPresenters/Package.swift b/Common/RuuviPresenters/Package.swift index e8997bec6..f80164945 100644 --- a/Common/RuuviPresenters/Package.swift +++ b/Common/RuuviPresenters/Package.swift @@ -11,7 +11,7 @@ let package = Package( .library( name: "RuuviPresenters", targets: ["RuuviPresenters"] - ) + ), ], targets: [ .target( @@ -21,6 +21,6 @@ let package = Package( .testTarget( name: "RuuviPresentersTests", dependencies: ["RuuviPresenters"] - ) + ), ] ) diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift index 1dc2b30a2..312022224 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift @@ -20,12 +20,12 @@ public final class ActivityPresenterRuuviLogo: ActivityPresenter { } } -extension ActivityPresenterRuuviLogo { - public func setPosition(_ position: ActivityPresenterPosition) { +public extension ActivityPresenterRuuviLogo { + func setPosition(_ position: ActivityPresenterPosition) { activityPresenterViewProvider.updatePosition(position) } - public func show(with state: ActivityPresenterState) { + func show(with state: ActivityPresenterState) { startTime = CFAbsoluteTimeGetCurrent() appWindow = UIWindow.key window.makeKeyAndVisible() @@ -33,11 +33,11 @@ extension ActivityPresenterRuuviLogo { activityPresenterViewProvider.updateState(state) } - public func update(with state: ActivityPresenterState) { + func update(with state: ActivityPresenterState) { activityPresenterViewProvider.updateState(state) } - public func dismiss(immediately: Bool) { + func dismiss(immediately: Bool) { let executionTime = CFAbsoluteTimeGetCurrent() - (startTime ?? 0) let additionalWaitTime = immediately ? 0 : executionTime < minAnimationTime ? (minAnimationTime - executionTime) : 0 diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterState.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterState.swift index 4534bbf82..841670828 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterState.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterState.swift @@ -7,20 +7,20 @@ public enum ActivityPresenterState: Equatable { case dismiss public static func == ( - lhs: ActivityPresenterState, + lhs: ActivityPresenterState, rhs: ActivityPresenterState ) -> Bool { switch (lhs, rhs) { - case (.loading(let lhsMessage), .loading(let rhsMessage)): - return lhsMessage == rhsMessage - case (.success(let lhsMessage), .success(let rhsMessage)): - return lhsMessage == rhsMessage - case (.failed(let lhsMessage), .failed(let rhsMessage)): - return lhsMessage == rhsMessage + case let (.loading(lhsMessage), .loading(rhsMessage)): + lhsMessage == rhsMessage + case let (.success(lhsMessage), .success(rhsMessage)): + lhsMessage == rhsMessage + case let (.failed(lhsMessage), .failed(rhsMessage)): + lhsMessage == rhsMessage case (.dismiss, .dismiss): - return true + true default: - return false + false } } } diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift index bd4f999b3..8d51f6bc2 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift @@ -1,7 +1,7 @@ -import UIKit import SwiftUI +import UIKit -private struct ActivityPresenterAssets { +private enum ActivityPresenterAssets { static let activityOngoingDefault = "activity_ongoing_generic" static let activitySuccessDefault = "activity_success_generic" static let activityFailedDefault = "activity_failed_generic" @@ -61,47 +61,47 @@ struct ActivityPresenterContentView: View { private var contentImage: Image? { switch state { case .loading: - return Image( - ActivityPresenterAssets.activityLogoRuuvi, + Image( + ActivityPresenterAssets.activityLogoRuuvi, bundle: .pod(ActivityPresenterViewProvider.self) ) case .success: - return Image(systemName: "checkmark") + Image(systemName: "checkmark") case .failed: - return Image(systemName: "xmark") + Image(systemName: "xmark") default: - return nil + nil } } private var message: String { switch state { - case .loading(let message): - if let message = message { - return message + case let .loading(message): + if let message { + message } else { - return ActivityPresenterAssets + ActivityPresenterAssets .activityOngoingDefault .localized(for: ActivityPresenterViewProvider.self) } - case .success(let message): - if let message = message { - return message + case let .success(message): + if let message { + message } else { - return ActivityPresenterAssets + ActivityPresenterAssets .activitySuccessDefault .localized(for: ActivityPresenterViewProvider.self) } - case .failed(let message): - if let message = message { - return message + case let .failed(message): + if let message { + message } else { - return ActivityPresenterAssets + ActivityPresenterAssets .activityFailedDefault .localized(for: ActivityPresenterViewProvider.self) } case .dismiss: - return "" // Placeholder for dismiss state + "" // Placeholder for dismiss state } } } diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterViewProvider.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterViewProvider.swift index 8feb10916..0106ff9c2 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterViewProvider.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterViewProvider.swift @@ -1,5 +1,5 @@ -import UIKit import SwiftUI +import UIKit public class ActivityPresenterStateHolder: ObservableObject { @Published var state: ActivityPresenterState = .dismiss @@ -14,16 +14,16 @@ public class ActivityPresenterViewProvider: NSObject { } public func makeViewController() -> UIViewController { - return UIHostingController( + UIHostingController( rootView: ActivityPresenterView().environmentObject(stateHolder) ) } func updateState(_ newState: ActivityPresenterState) { - self.stateHolder.state = newState + stateHolder.state = newState } func updatePosition(_ position: ActivityPresenterPosition) { - self.stateHolder.position = position + stateHolder.position = position } } diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivitySpinnerView.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivitySpinnerView.swift index 2fc57ef06..456ea8956 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivitySpinnerView.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivitySpinnerView.swift @@ -1,30 +1,29 @@ -import UIKit import SwiftUI +import UIKit // UIViewRepresentable wrapper for ActivitySpinnerView struct ActivitySpinnerViewRepresentable: UIViewRepresentable { - func makeUIView(context: Context) -> ActivitySpinnerView { + func makeUIView(context _: Context) -> ActivitySpinnerView { let spinnerView = ActivitySpinnerView() spinnerView.animate() return spinnerView } - - func updateUIView(_ uiView: ActivitySpinnerView, context: Context) { + + func updateUIView(_: ActivitySpinnerView, context _: Context) { // No op } } class ActivitySpinnerView: UIView { - private var strokeColor = UIColor(red: 0.21, green: 0.68, blue: 0.62, alpha: 1.00) override var layer: CAShapeLayer { // swiftlint:disable force_cast - return super.layer as! CAShapeLayer + super.layer as! CAShapeLayer // swiftlint:enable force_cast } override class var layerClass: AnyClass { - return CAShapeLayer.self + CAShapeLayer.self } override func layoutSubviews() { @@ -51,8 +50,7 @@ class ActivitySpinnerView: UIView { } class var poses: [Pose] { - - return [ + [ Pose(0.0, 0.000, 0.7), Pose(0.6, 0.500, 0.5), Pose(0.6, 1.000, 0.3), @@ -60,7 +58,7 @@ class ActivitySpinnerView: UIView { Pose(0.2, 1.875, 0.1), Pose(0.2, 2.250, 0.3), Pose(0.2, 2.625, 0.5), - Pose(0.2, 3.000, 0.7) + Pose(0.2, 3.000, 0.7), ] } @@ -118,5 +116,4 @@ class ActivitySpinnerView: UIView { animation.repeatCount = Float.infinity layer.add(animation, forKey: animation.keyPath) } - } diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Permission/Alert/PermissionPresenterAlert.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Permission/Alert/PermissionPresenterAlert.swift index 866dd72f1..39665620e 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Permission/Alert/PermissionPresenterAlert.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Permission/Alert/PermissionPresenterAlert.swift @@ -28,7 +28,7 @@ public final class PermissionPresenterAlert: PermissionPresenter { let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) let cancel = UIAlertAction(title: "Cancel".localized(for: Self.self), style: .cancel, handler: nil) let actionTitle = "PermissionPresenter.settings".localized(for: Self.self) - let settings = UIAlertAction(title: actionTitle, style: .default) { _ -> Void in + let settings = UIAlertAction(title: actionTitle, style: .default) { _ in if let settingsUrl = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(settingsUrl, options: [:]) } diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift index be1ad1013..ccd444085 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift @@ -1,8 +1,8 @@ import Foundation import UIKit -extension Bundle { - public static func pod(_ clazz: AnyClass) -> Bundle { +public extension Bundle { + static func pod(_ clazz: AnyClass) -> Bundle { if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { if let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), let bundle = Bundle(url: bundleURL) { return bundle @@ -19,12 +19,12 @@ extension Bundle { } } -extension UIImage { - public static func named(_ name: String, for clazz: AnyClass) -> UIImage? { +public extension UIImage { + static func named(_ name: String, for clazz: AnyClass) -> UIImage? { #if SWIFT_PACKAGE - return UIImage(named: name, in: Bundle.module, compatibleWith: nil) + return UIImage(named: name, in: Bundle.module, compatibleWith: nil) #else - return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) + return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) #endif } } @@ -33,16 +33,18 @@ extension String { public func localized(for clazz: AnyClass) -> String { let bundle: Bundle #if SWIFT_PACKAGE - bundle = Bundle.module + bundle = Bundle.module #else - bundle = Bundle.pod(clazz) + bundle = Bundle.pod(clazz) #endif if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), - let bundle = Bundle(path: path) { + let bundle = Bundle(path: path) + { return bundle.localizedString(forKey: self, value: nil, table: module) } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), - let bundle = Bundle(path: path) { + let bundle = Bundle(path: path) + { return bundle.localizedString(forKey: self, value: nil, table: module) } else { assertionFailure() @@ -56,32 +58,32 @@ extension String { private func currentLanguage() -> String { if let preferred = Bundle.main.preferredLocalizations.first { - return preferred + preferred } else { - return "Base" + "Base" } } } -extension UIStoryboard { - public static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { +public extension UIStoryboard { + static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { let bundle: Bundle #if SWIFT_PACKAGE - bundle = Bundle.module + bundle = Bundle.module #else - bundle = Bundle.pod(clazz) + bundle = Bundle.pod(clazz) #endif return UIStoryboard(name: name, bundle: bundle) } } -extension UINib { - public static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { +public extension UINib { + static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { let bundle: Bundle #if SWIFT_PACKAGE - bundle = Bundle.module + bundle = Bundle.module #else - bundle = Bundle.pod(clazz) + bundle = Bundle.pod(clazz) #endif return UINib(nibName: nibName, bundle: bundle) } diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/UIWindow+Orientation.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/UIWindow+Orientation.swift index 12ef5f2a3..59136b908 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/UIWindow+Orientation.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/UIWindow+Orientation.swift @@ -3,25 +3,25 @@ import UIKit extension UIWindow { static var isLandscape: Bool { if #available(iOS 13.0, *) { - return UIApplication.shared.windows + UIApplication.shared.windows .first? .windowScene? .interfaceOrientation .isLandscape ?? false } else { - return UIApplication.shared.statusBarOrientation.isLandscape + UIApplication.shared.statusBarOrientation.isLandscape } } static var isPortrait: Bool { - return !self.isLandscape + !isLandscape } static var key: UIWindow? { if #available(iOS 13, *) { - return UIApplication.shared.windows.first { $0.isKeyWindow } + UIApplication.shared.windows.first { $0.isKeyWindow } } else { - return UIApplication.shared.keyWindow + UIApplication.shared.keyWindow } } } diff --git a/Common/RuuviPresenters/Tests/RuuviPresentersTests/RuuviPresentersTests.swift b/Common/RuuviPresenters/Tests/RuuviPresentersTests/RuuviPresentersTests.swift index 81d4e300e..04d1af9d4 100644 --- a/Common/RuuviPresenters/Tests/RuuviPresentersTests/RuuviPresentersTests.swift +++ b/Common/RuuviPresenters/Tests/RuuviPresentersTests/RuuviPresentersTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviPresenters +import XCTest final class RuuviPresentersTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Modules/RuuviDiscover/Package.swift b/Modules/RuuviDiscover/Package.swift index 2e4f4431d..0848745a7 100644 --- a/Modules/RuuviDiscover/Package.swift +++ b/Modules/RuuviDiscover/Package.swift @@ -10,7 +10,8 @@ let package = Package( products: [ .library( name: "RuuviDiscover", - targets: ["RuuviDiscover"]) + targets: ["RuuviDiscover"] + ), ], dependencies: [ .package(path: "../../Packages/RuuviOntology"), @@ -27,17 +28,17 @@ let package = Package( name: "RuuviDiscover", dependencies: [ "RuuviOntology", - "RuuviContext", + "RuuviContext", "RuuviReactor", "RuuviLocal", "RuuviService", "RuuviPresenters", "BTKit", - "RuuviLocalization" + "RuuviLocalization", ] ), .testTarget( name: "RuuviDiscoverTests" - ) + ), ] ) diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscover.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscover.swift index f6279d2aa..ea2151fc0 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscover.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscover.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviOntology +import UIKit public protocol RuuviDiscover: AnyObject { var viewController: UIViewController { get } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscoverFactory.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscoverFactory.swift index 7f1276e32..34e46614f 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscoverFactory.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscoverFactory.swift @@ -1,12 +1,12 @@ -import Foundation import BTKit +import Foundation import RuuviContext -import RuuviReactor -import RuuviLocal -import RuuviService import RuuviCore -import RuuviPresenters import RuuviFirmware +import RuuviLocal +import RuuviPresenters +import RuuviReactor +import RuuviService public struct RuuviDiscoverDependencies { var errorPresenter: ErrorPresenter diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift index be1ad1013..ccd444085 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift @@ -1,8 +1,8 @@ import Foundation import UIKit -extension Bundle { - public static func pod(_ clazz: AnyClass) -> Bundle { +public extension Bundle { + static func pod(_ clazz: AnyClass) -> Bundle { if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { if let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), let bundle = Bundle(url: bundleURL) { return bundle @@ -19,12 +19,12 @@ extension Bundle { } } -extension UIImage { - public static func named(_ name: String, for clazz: AnyClass) -> UIImage? { +public extension UIImage { + static func named(_ name: String, for clazz: AnyClass) -> UIImage? { #if SWIFT_PACKAGE - return UIImage(named: name, in: Bundle.module, compatibleWith: nil) + return UIImage(named: name, in: Bundle.module, compatibleWith: nil) #else - return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) + return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) #endif } } @@ -33,16 +33,18 @@ extension String { public func localized(for clazz: AnyClass) -> String { let bundle: Bundle #if SWIFT_PACKAGE - bundle = Bundle.module + bundle = Bundle.module #else - bundle = Bundle.pod(clazz) + bundle = Bundle.pod(clazz) #endif if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), - let bundle = Bundle(path: path) { + let bundle = Bundle(path: path) + { return bundle.localizedString(forKey: self, value: nil, table: module) } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), - let bundle = Bundle(path: path) { + let bundle = Bundle(path: path) + { return bundle.localizedString(forKey: self, value: nil, table: module) } else { assertionFailure() @@ -56,32 +58,32 @@ extension String { private func currentLanguage() -> String { if let preferred = Bundle.main.preferredLocalizations.first { - return preferred + preferred } else { - return "Base" + "Base" } } } -extension UIStoryboard { - public static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { +public extension UIStoryboard { + static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { let bundle: Bundle #if SWIFT_PACKAGE - bundle = Bundle.module + bundle = Bundle.module #else - bundle = Bundle.pod(clazz) + bundle = Bundle.pod(clazz) #endif return UIStoryboard(name: name, bundle: bundle) } } -extension UINib { - public static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { +public extension UINib { + static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { let bundle: Bundle #if SWIFT_PACKAGE - bundle = Bundle.module + bundle = Bundle.module #else - bundle = Bundle.pod(clazz) + bundle = Bundle.pod(clazz) #endif return UINib(nibName: nibName, bundle: bundle) } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UITableViewCell+ReusableView.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UITableViewCell+ReusableView.swift index f09fcc784..11a546dff 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UITableViewCell+ReusableView.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UITableViewCell+ReusableView.swift @@ -6,26 +6,27 @@ protocol ReusableView: AnyObject { extension ReusableView where Self: UIView { static var reuseIdentifier: String { - return String(describing: self) + String(describing: self) } } -extension UICollectionViewCell: ReusableView { -} +extension UICollectionViewCell: ReusableView {} + +extension UITableViewCell: ReusableView {} + +extension UITableViewHeaderFooterView: ReusableView {} -extension UITableViewCell: ReusableView { -} -extension UITableViewHeaderFooterView: ReusableView { -} extension UITableView { - func dequeueReusableCell(with type: T.Type, - for indexPath: IndexPath) -> T { + func dequeueReusableCell(with _: T.Type, + for indexPath: IndexPath) -> T + { guard let cell = dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as? T else { preconditionFailure("Unable to dequeue \(T.description()) for indexPath: \(indexPath)") } return cell } - func dequeueReusableHeaderFooterView(with type: T.Type) -> T { + + func dequeueReusableHeaderFooterView(with _: T.Type) -> T { guard let cell = dequeueReusableHeaderFooterView(withIdentifier: T.reuseIdentifier) as? T else { preconditionFailure("Unable to dequeue \(T.description())") } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UIViewController+Alert.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UIViewController+Alert.swift index 513cae227..8c53be715 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UIViewController+Alert.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UIViewController+Alert.swift @@ -2,7 +2,8 @@ import UIKit extension UIViewController { func showAlert(title: String? = nil, - message: String? = nil) { + message: String? = nil) + { let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) alertVC.addAction(UIAlertAction(title: "OK".localized(for: Self.self), style: .cancel, handler: nil)) present(alertVC, animated: true) diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift index 9932bc2e6..f6e59a52e 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift @@ -1,22 +1,22 @@ +import BTKit +import CoreBluetooth +import CoreNFC // swiftlint:disable file_length import Foundation -import BTKit -import UIKit import Future -import RuuviOntology import RuuviContext -import RuuviReactor -import RuuviLocal -import RuuviService import RuuviCore -import RuuviPresenters import RuuviFirmware -import CoreBluetooth -import CoreNFC +import RuuviLocal +import RuuviOntology +import RuuviPresenters +import RuuviReactor +import RuuviService +import UIKit class DiscoverPresenter: NSObject, RuuviDiscover { var viewController: UIViewController { - if let view = view { + if let view { return view } else { let storyboard = UIStoryboard.named("Discover", for: Self.self) @@ -47,7 +47,7 @@ class DiscoverPresenter: NSObject, RuuviDiscover { private var _persistedSensors: [RuuviTagSensor] = [] private var persistedSensors: [RuuviTagSensor]! { get { - return accessQueue.sync { + accessQueue.sync { _persistedSensors } } @@ -64,7 +64,7 @@ class DiscoverPresenter: NSObject, RuuviDiscover { private var _ruuviTags = Set() private var ruuviTags: Set { get { - return accessQueue.sync { + accessQueue.sync { _ruuviTags } } @@ -74,6 +74,7 @@ class DiscoverPresenter: NSObject, RuuviDiscover { } } } + private var nfcSensor: NFCSensor? private var reloadTimer: Timer? @@ -102,6 +103,7 @@ class DiscoverPresenter: NSObject, RuuviDiscover { } // MARK: - DiscoverViewOutput + extension DiscoverPresenter: DiscoverViewOutput { func viewDidLoad() { view?.isBluetoothEnabled = foreground.bluetoothState == .poweredOn @@ -163,11 +165,11 @@ extension DiscoverPresenter: DiscoverViewOutput { if let (key, value) = parse(record: record) { switch key { case "idID": - self.nfcSensor?.id = trimNulls(from: value) + nfcSensor?.id = trimNulls(from: value) case "adMAC": - self.nfcSensor?.macId = trimNulls(from: value) + nfcSensor?.macId = trimNulls(from: value) case "swSW": - self.nfcSensor?.firmwareVersion = trimNulls(from: value) + nfcSensor?.firmwareVersion = trimNulls(from: value) default: break } @@ -187,7 +189,7 @@ extension DiscoverPresenter: DiscoverViewOutput { for: nfcSensor, displayName: addedTag.name ) else { return } - self.view?.showSensorDetailsDialog( + view?.showSensorDetailsDialog( for: nfcSensor, message: message, showAddSensor: false, @@ -204,9 +206,9 @@ extension DiscoverPresenter: DiscoverViewOutput { }) { guard let message = self.message( for: nfcSensor, - displayName: self.displayName(for: nfcSensor) + displayName: displayName(for: nfcSensor) ) else { return } - self.view?.showSensorDetailsDialog( + view?.showSensorDetailsDialog( for: nfcSensor, message: message, showAddSensor: true, @@ -222,11 +224,11 @@ extension DiscoverPresenter: DiscoverViewOutput { // is done when sensor is not yet seen by BT. // Show info for DF3 case to add the tag using BT and update FW. // TODO: Discuss about the other case to handle it. - guard let message = self.message( + guard let message = message( for: nfcSensor, - displayName: self.displayName(for: nfcSensor) + displayName: displayName(for: nfcSensor) ) else { return } - self.view?.showSensorDetailsDialog( + view?.showSensorDetailsDialog( for: nfcSensor, message: message, showAddSensor: false, @@ -274,6 +276,7 @@ extension DiscoverPresenter: DiscoverViewOutput { } // MARK: - RuuviFirmwareOutput + extension DiscoverPresenter: RuuviFirmwareOutput { func ruuviFirmwareSuccessfullyUpgraded(_ ruuviDiscover: RuuviFirmware) { ruuviDiscover.viewController.dismiss(animated: true) @@ -281,25 +284,26 @@ extension DiscoverPresenter: RuuviFirmwareOutput { } // MARK: - Private + extension DiscoverPresenter { private func startObservingPersistedRuuviSensors() { - persistedReactorToken = ruuviReactor.observe({ [weak self] (change) in + persistedReactorToken = ruuviReactor.observe { [weak self] change in switch change { - case .initial(let sensors): + case let .initial(sensors): guard let sSelf = self else { return } self?.persistedSensors = sensors - case .insert(let sensor): + case let .insert(sensor): self?.persistedSensors.append(sensor) - case .delete(let sensor): - self?.persistedSensors.removeAll(where: {$0.any == sensor}) + case let .delete(sensor): + self?.persistedSensors.removeAll(where: { $0.any == sensor }) default: return } - }) + } } private func startObservingLost() { - lostToken = foreground.lost(self, options: [.lostDeviceDelay(10)], closure: { (observer, device) in + lostToken = foreground.lost(self, options: [.lostDeviceDelay(10)], closure: { observer, device in if let ruuviTag = device.ruuvi?.tag { observer.ruuviTags.remove(ruuviTag) } @@ -311,7 +315,7 @@ extension DiscoverPresenter { } private func startObservingBluetoothState() { - stateToken = foreground.state(self, closure: { (observer, state) in + stateToken = foreground.state(self, closure: { observer, state in observer.view?.isBluetoothEnabled = state == .poweredOn if state == .poweredOff || !self.isBluetoothPermissionGranted { observer.ruuviTags.removeAll() @@ -326,7 +330,7 @@ extension DiscoverPresenter { } private func startScanning() { - scanToken = foreground.scan(self) { (observer, device) in + scanToken = foreground.scan(self) { observer, device in if let ruuviTag = device.ruuvi?.tag { // when mode is changed, the device should be replaced if let sameUUID = observer.ruuviTags.first(where: { $0.uuid == ruuviTag.uuid }), sameUUID != ruuviTag { @@ -345,9 +349,10 @@ extension DiscoverPresenter { reloadTimer = Timer.scheduledTimer( withTimeInterval: 3, repeats: true, - block: { [weak self] (_) in - self?.updateViewDevices() - }) + block: { [weak self] _ in + self?.updateViewDevices() + } + ) // don't wait for timer, reload after 0.5 sec DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in self?.updateViewDevices() @@ -359,8 +364,8 @@ extension DiscoverPresenter { } private func updateViewDevices() { - let ruuviTags = ruuviTags.map { (ruuviTag) -> DiscoverRuuviTagViewModel in - return DiscoverRuuviTagViewModel( + let ruuviTags = ruuviTags.map { ruuviTag -> DiscoverRuuviTagViewModel in + DiscoverRuuviTagViewModel( luid: ruuviTag.luid?.any, isConnectable: ruuviTag.isConnectable, rssi: ruuviTag.rssi, @@ -373,23 +378,25 @@ extension DiscoverPresenter { } private func visibleTags(ruuviTags: [DiscoverRuuviTagViewModel]) -> [DiscoverRuuviTagViewModel] { - let filtered = ruuviTags.filter({ tag in + let filtered = ruuviTags.filter { tag in !persistedSensors.contains(where: { persistedTag in if let tagLuid = tag.luid?.value, - let persistedTagLuid = persistedTag.luid?.value { - return tagLuid == persistedTagLuid + let persistedTagLuid = persistedTag.luid?.value + { + tagLuid == persistedTagLuid } else if let tagMacId = tag.mac, - let persistedTagMacId = persistedTag.macId?.value { - return tagMacId == persistedTagMacId + let persistedTagMacId = persistedTag.macId?.value + { + tagMacId == persistedTagMacId } else { - return false + false } }) - }).sorted(by: { + }.sorted(by: { if let rssi0 = $0.rssi, let rssi1 = $1.rssi { - return rssi0 > rssi1 + rssi0 > rssi1 } else { - return false + false } }) @@ -421,16 +428,17 @@ extension DiscoverPresenter { } private func displayName(for tag: NFCSensor?) -> String? { - guard let tag = tag else { + guard let tag else { return nil } return "DiscoverTable.RuuviDevice.prefix".localized(for: Self.self) - + " " + tag.macId.replacingOccurrences(of: ":", with: "").suffix(4) + + " " + tag.macId.replacingOccurrences(of: ":", with: "").suffix(4) } private func message(for tag: NFCSensor?, displayName: String?) -> String? { - guard let tag = tag, - let displayName = displayName else { + guard let tag, + let displayName + else { return nil } @@ -450,17 +458,19 @@ extension DiscoverPresenter { ruuviOwnershipService.add( sensor: ruuviTag.with(name: displayName) .with(firmwareVersion: firmwareVersion ?? ""), - record: ruuviTag.with(source: .advertisement)) - .on(success: { [weak self] anyRuuviTagSensor in - guard let sSelf = self else { return } - sSelf.output?.ruuvi(discover: sSelf, didAdd: anyRuuviTagSensor) - }, failure: { [weak self] error in - self?.errorPresenter.present(error: error) - }) + record: ruuviTag.with(source: .advertisement) + ) + .on(success: { [weak self] anyRuuviTagSensor in + guard let sSelf = self else { return } + sSelf.output?.ruuvi(discover: sSelf, didAdd: anyRuuviTagSensor) + }, failure: { [weak self] error in + self?.errorPresenter.present(error: error) + }) } private func trimNulls(from string: String) -> String { - return string.replacingOccurrences(of: "\0", with: "") + string.replacingOccurrences(of: "\0", with: "") } } + // swiftlint:enable file_length diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift index 6d4f9a683..d7c4eb5bf 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift @@ -1,7 +1,7 @@ import Foundation -import UIKit -import RuuviOntology import RuuviLocalization +import RuuviOntology +import UIKit protocol DiscoverViewInput: UIViewController { var ruuviTags: [DiscoverRuuviTagViewModel] { get set } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewOutput.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewOutput.swift index dbf1c0bde..ca40c6b1b 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewOutput.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewOutput.swift @@ -1,5 +1,5 @@ -import Foundation import CoreNFC +import Foundation import RuuviOntology protocol DiscoverViewOutput { diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Model/DiscoverRuuviTagViewModel.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Model/DiscoverRuuviTagViewModel.swift index dbbf8eff2..206d497a0 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Model/DiscoverRuuviTagViewModel.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Model/DiscoverRuuviTagViewModel.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviOntology +import UIKit struct DiscoverRuuviTagViewModel { var luid: AnyLocalIdentifier? diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/Cell/DiscoverAddWithMACTableViewCell.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/Cell/DiscoverAddWithMACTableViewCell.swift index 4b10cb9c0..ed5daf9ff 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/Cell/DiscoverAddWithMACTableViewCell.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/Cell/DiscoverAddWithMACTableViewCell.swift @@ -1,5 +1,5 @@ import UIKit class DiscoverAddWithMACTableViewCell: UITableViewCell { - @IBOutlet weak var descriptionLabel: UILabel! + @IBOutlet var descriptionLabel: UILabel! } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/Cell/DiscoverDeviceTableViewCell.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/Cell/DiscoverDeviceTableViewCell.swift index 3d4d91260..9fcbd8959 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/Cell/DiscoverDeviceTableViewCell.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/Cell/DiscoverDeviceTableViewCell.swift @@ -1,7 +1,7 @@ import UIKit class DiscoverDeviceTableViewCell: UITableViewCell { - @IBOutlet weak var identifierLabel: UILabel! - @IBOutlet weak var rssiImageView: UIImageView! - @IBOutlet weak var rssiLabel: UILabel! + @IBOutlet var identifierLabel: UILabel! + @IBOutlet var rssiImageView: UIImageView! + @IBOutlet var rssiLabel: UILabel! } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/Cell/DiscoverNoDevicesTableViewCell.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/Cell/DiscoverNoDevicesTableViewCell.swift index 7a5c3b08e..8edad6887 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/Cell/DiscoverNoDevicesTableViewCell.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/Cell/DiscoverNoDevicesTableViewCell.swift @@ -1,5 +1,5 @@ import UIKit class DiscoverNoDevicesTableViewCell: UITableViewCell { - @IBOutlet weak var descriptionLabel: UILabel! + @IBOutlet var descriptionLabel: UILabel! } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift index 3e6b2dc4d..a3e6d1d77 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift @@ -1,18 +1,17 @@ -import UIKit import CoreBluetooth import CoreNFC +import UIKit protocol DiscoverTableHeaderViewDelegate: NSObjectProtocol { func didTapAddWithNFCButton(sender: DiscoverTableHeaderView) } class DiscoverTableHeaderView: UIView { - weak var delegate: DiscoverTableHeaderViewDelegate? // ----- Private private var isNFCAvailable: Bool { - return NFCNDEFReaderSession.readingAvailable + NFCNDEFReaderSession.readingAvailable } private var isBluetoothPermissionGranted: Bool { @@ -41,7 +40,8 @@ class DiscoverTableHeaderView: UIView { setupView() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -52,7 +52,7 @@ class DiscoverTableHeaderView: UIView { headerView.addSubview(descriptionLabel) - if isBluetoothPermissionGranted && isNFCAvailable { + if isBluetoothPermissionGranted, isNFCAvailable { headerView.addSubview(nfcButton) } @@ -113,7 +113,7 @@ class DiscoverTableHeaderView: UIView { NSLayoutConstraint.activate([ descriptionLabel.topAnchor.constraint(equalTo: headerView.topAnchor), descriptionLabel.leadingAnchor.constraint(equalTo: headerView.leadingAnchor), - descriptionLabel.trailingAnchor.constraint(equalTo: headerView.trailingAnchor) + descriptionLabel.trailingAnchor.constraint(equalTo: headerView.trailingAnchor), ]) // variable constraints @@ -131,16 +131,16 @@ class DiscoverTableHeaderView: UIView { .bottomAnchor .constraint(equalTo: headerView.bottomAnchor) - if isBluetoothPermissionGranted && isNFCAvailable { + if isBluetoothPermissionGranted, isNFCAvailable { NSLayoutConstraint.activate([ nfcButtonTopConstraint, button.leadingAnchor.constraint(equalTo: headerView.leadingAnchor), button.trailingAnchor.constraint(equalTo: headerView.trailingAnchor), - nfcButtonBottomConstraint + nfcButtonBottomConstraint, ]) } else { NSLayoutConstraint.activate([ - descriptionLabelBottomConstraint + descriptionLabelBottomConstraint, ]) } } @@ -152,7 +152,7 @@ class DiscoverTableHeaderView: UIView { extension DiscoverTableHeaderView { func handleNFCButtonViewVisibility(show: Bool) { - if isBluetoothPermissionGranted && isNFCAvailable { + if isBluetoothPermissionGranted, isNFCAvailable { nfcButtonTopConstraint.isActive = show nfcButtonBottomConstraint.isActive = show nfcButton.isHidden = !show @@ -163,7 +163,7 @@ extension DiscoverTableHeaderView { let descriptionString = (show && isBluetoothPermissionGranted && isNFCAvailable) ? (addSensorString + "\n\n" + addSensorViaNFCString) : addSensorString - descriptionLabel.text = descriptionString + descriptionLabel.text = descriptionString } } @@ -172,13 +172,13 @@ extension UIButton { forContentPadding contentPadding: UIEdgeInsets, imageTitlePadding: CGFloat ) { - self.contentEdgeInsets = UIEdgeInsets( + contentEdgeInsets = UIEdgeInsets( top: contentPadding.top, left: contentPadding.left, bottom: contentPadding.bottom, right: contentPadding.right + imageTitlePadding ) - self.titleEdgeInsets = UIEdgeInsets( + titleEdgeInsets = UIEdgeInsets( top: 0, left: imageTitlePadding, bottom: 0, @@ -189,11 +189,11 @@ extension UIButton { extension UIView { func constraints(to view: UIView, padding: UIEdgeInsets = .zero) -> [NSLayoutConstraint] { - return [ - self.topAnchor.constraint(equalTo: view.topAnchor, constant: padding.top), - self.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: padding.left), - self.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -padding.bottom), - self.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -padding.right) + [ + topAnchor.constraint(equalTo: view.topAnchor, constant: padding.top), + leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: padding.left), + bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -padding.bottom), + trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -padding.right), ] } } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift index 186907a46..1ee5ddd3a 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift @@ -1,8 +1,8 @@ -import UIKit import BTKit -import RuuviOntology -import RuuviLocalization import CoreNFC +import RuuviLocalization +import RuuviOntology +import UIKit enum DiscoverTableSection { case device @@ -11,22 +11,21 @@ enum DiscoverTableSection { static var count = 1 // displayed simultaneously static func section(for deviceCount: Int) -> DiscoverTableSection { - return deviceCount > 0 ? .device : .noDevices + deviceCount > 0 ? .device : .noDevices } } class DiscoverTableViewController: UIViewController { - var output: DiscoverViewOutput! - @IBOutlet weak var tableView: UITableView! + @IBOutlet var tableView: UITableView! @IBOutlet var closeBarButtonItem: UIBarButtonItem! - @IBOutlet weak var actionButton: UIButton! + @IBOutlet var actionButton: UIButton! private var discoverTableHeaderView = DiscoverTableHeaderView() private var alertVC: UIAlertController? - var ruuviTags: [DiscoverRuuviTagViewModel] = [DiscoverRuuviTagViewModel]() { + var ruuviTags: [DiscoverRuuviTagViewModel] = .init() { didSet { updateTableView() } @@ -49,8 +48,8 @@ class DiscoverTableViewController: UIViewController { } // MARK: - DiscoverViewInput -extension DiscoverTableViewController: DiscoverViewInput { +extension DiscoverTableViewController: DiscoverViewInput { func localize() { navigationItem.title = "DiscoverTable.NavigationItem.title".localized(for: Self.self) } @@ -61,8 +60,8 @@ extension DiscoverTableViewController: DiscoverViewInput { let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) alertVC.addAction(UIAlertAction(title: "PermissionPresenter.settings".localized(for: Self.self), style: .default, handler: { [weak self] _ in - self?.takeUserToBTSettings(userDeclined: userDeclined) - })) + self?.takeUserToBTSettings(userDeclined: userDeclined) + })) alertVC.addAction(UIAlertAction(title: "OK".localized(for: Self.self), style: .cancel, handler: nil)) present(alertVC, animated: true) } @@ -100,7 +99,7 @@ extension DiscoverTableViewController: DiscoverViewInput { if isDF3 { let df3ErrorMessage = "add_sensor_nfc_df3_error".localized( for: Self.self - ) + ) messageString = "\n\(df3ErrorMessage)\n" + message } @@ -111,7 +110,7 @@ extension DiscoverTableViewController: DiscoverViewInput { attributes: [ NSAttributedString.Key.paragraphStyle: paragraphStyle, NSAttributedString.Key.foregroundColor: UIColor.label, - NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .body) + NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .body), ] ) @@ -119,34 +118,34 @@ extension DiscoverTableViewController: DiscoverViewInput { alertVC.setValue(messageText, forKey: "attributedMessage") if showAddSensor { - alertVC.addAction(UIAlertAction(title: "add_sensor".localized(for: Self.self), - style: .default, handler: { [weak self] _ in - self?.output.viewDidAddDeviceWithNFC(with: tag) - })) + alertVC.addAction(UIAlertAction(title: "add_sensor".localized(for: Self.self), + style: .default, handler: { [weak self] _ in + self?.output.viewDidAddDeviceWithNFC(with: tag) + })) } alertVC.addAction(UIAlertAction(title: "copy_mac_address".localized(for: Self.self), style: .default, handler: { [weak self] _ in - self?.output.viewDidACopyMacAddress(of: tag) - })) + self?.output.viewDidACopyMacAddress(of: tag) + })) alertVC.addAction(UIAlertAction(title: "copy_unique_id".localized(for: Self.self), style: .default, handler: { [weak self] _ in - self?.output.viewDidACopySecret(of: tag) - })) + self?.output.viewDidACopySecret(of: tag) + })) if showGoToSensor { - alertVC.addAction(UIAlertAction(title: "go_to_sensor".localized(for: Self.self), - style: .default, handler: { [weak self] _ in - self?.output.viewDidGoToSensor(with: tag) - })) + alertVC.addAction(UIAlertAction(title: "go_to_sensor".localized(for: Self.self), + style: .default, handler: { [weak self] _ in + self?.output.viewDidGoToSensor(with: tag) + })) } - + if showUpgradeFirmware { alertVC.addAction(UIAlertAction(title: "upgrade_firmware".localized(for: Self.self), style: .default, handler: { [weak self] _ in - self?.output.viewDidAskToUpgradeFirmware(of: tag) - })) + self?.output.viewDidAskToUpgradeFirmware(of: tag) + })) } alertVC.addAction(UIAlertAction(title: "close".localized(for: Self.self), style: .cancel, handler: nil)) @@ -155,26 +154,28 @@ extension DiscoverTableViewController: DiscoverViewInput { } // MARK: - IBActions + extension DiscoverTableViewController { - @IBAction func closeBarButtonItemAction(_ sender: Any) { + @IBAction func closeBarButtonItemAction(_: Any) { output.viewDidTriggerClose() } - @IBAction func handleActionButtonTap(_ sender: Any) { + @IBAction func handleActionButtonTap(_: Any) { output.viewDidTriggerBuySensors() } } // MARK: - DiscoverTableHeaderViewDelegate + extension DiscoverTableViewController: DiscoverTableHeaderViewDelegate { - func didTapAddWithNFCButton(sender: DiscoverTableHeaderView) { + func didTapAddWithNFCButton(sender _: DiscoverTableHeaderView) { output.viewDidTapUseNFC() } } // MARK: - View lifecycle -extension DiscoverTableViewController { +extension DiscoverTableViewController { override func viewDidLoad() { super.viewDidLoad() configureViews() @@ -197,7 +198,6 @@ extension DiscoverTableViewController { super.viewDidLayoutSubviews() if let headerView = tableView.tableHeaderView { - let height = headerView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height var headerFrame = headerView.frame @@ -212,12 +212,13 @@ extension DiscoverTableViewController { } // MARK: - UITableViewDataSource + extension DiscoverTableViewController: UITableViewDataSource { - func numberOfSections(in tableView: UITableView) -> Int { - return DiscoverTableSection.count + func numberOfSections(in _: UITableView) -> Int { + DiscoverTableSection.count } - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { let section = DiscoverTableSection.section(for: ruuviTags.count) switch section { case .device: @@ -246,6 +247,7 @@ extension DiscoverTableViewController: UITableViewDataSource { } // MARK: - UITableViewDelegate { + extension DiscoverTableViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) @@ -265,10 +267,9 @@ extension DiscoverTableViewController: UITableViewDelegate { } // MARK: - Cell configuration -extension DiscoverTableViewController { +extension DiscoverTableViewController { private func configure(cell: DiscoverDeviceTableViewCell, with device: DiscoverRuuviTagViewModel) { - cell.identifierLabel.text = displayName(for: device) // RSSI @@ -289,6 +290,7 @@ extension DiscoverTableViewController { } // MARK: - View configuration + extension DiscoverTableViewController { private func configureViews() { if let muliBold = UIFont(name: "Muli-Bold", size: 18) { @@ -312,6 +314,7 @@ extension DiscoverTableViewController { } // MARK: - Update UI + extension DiscoverTableViewController { private func updateUI() { updateTableView() @@ -340,18 +343,19 @@ extension DiscoverTableViewController { private func displayName(for device: DiscoverRuuviTagViewModel) -> String { // identifier if let mac = device.mac { - return "DiscoverTable.RuuviDevice.prefix".localized(for: Self.self) + "DiscoverTable.RuuviDevice.prefix".localized(for: Self.self) + " " + mac.replacingOccurrences(of: ":", with: "").suffix(4) } else { - return "DiscoverTable.RuuviDevice.prefix".localized(for: Self.self) + "DiscoverTable.RuuviDevice.prefix".localized(for: Self.self) + " " + (device.luid?.value.prefix(4) ?? "") } } private func takeUserToBTSettings(userDeclined: Bool) { guard let url = URL(string: userDeclined ? - UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), - UIApplication.shared.canOpenURL(url) else { + UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), + UIApplication.shared.canOpenURL(url) + else { return } UIApplication.shared.open(url) @@ -359,16 +363,19 @@ extension DiscoverTableViewController { } // MARK: - NFCNDEFReaderSessionDelegate + extension DiscoverTableViewController: NFCNDEFReaderSessionDelegate { - func readerSession(_ session: NFCNDEFReaderSession, - didInvalidateWithError error: Error) { + func readerSession(_: NFCNDEFReaderSession, + didInvalidateWithError _: Error) + { DispatchQueue.main.async { [weak self] in self?.stopNFCSession() } } - func readerSession(_ session: NFCNDEFReaderSession, - didDetectNDEFs messages: [NFCNDEFMessage]) { + func readerSession(_: NFCNDEFReaderSession, + didDetectNDEFs messages: [NFCNDEFMessage]) + { DispatchQueue.main.async { [weak self] in self?.output?.viewDidReceiveNFCMessages(messages: messages) } diff --git a/Modules/RuuviDiscover/Tests/RuuviDiscoverTests/RuuviDiscoverTests.swift b/Modules/RuuviDiscover/Tests/RuuviDiscoverTests/RuuviDiscoverTests.swift index 5bbd240b7..37fdb031e 100644 --- a/Modules/RuuviDiscover/Tests/RuuviDiscoverTests/RuuviDiscoverTests.swift +++ b/Modules/RuuviDiscover/Tests/RuuviDiscoverTests/RuuviDiscoverTests.swift @@ -1,6 +1,5 @@ import XCTest final class RuuviDiscoverTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Modules/RuuviFirmware/Package.swift b/Modules/RuuviFirmware/Package.swift index 51672539a..5ad92cdb0 100644 --- a/Modules/RuuviFirmware/Package.swift +++ b/Modules/RuuviFirmware/Package.swift @@ -9,7 +9,8 @@ let package = Package( // Products define the executables and libraries a package produces, making them visible to other packages. .library( name: "RuuviFirmware", - targets: ["RuuviFirmware"]), + targets: ["RuuviFirmware"] + ), ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. @@ -18,6 +19,7 @@ let package = Package( name: "RuuviFirmware"), .testTarget( name: "RuuviFirmwareTests", - dependencies: ["RuuviFirmware"]), + dependencies: ["RuuviFirmware"] + ), ] ) diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/Feedback.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/Feedback.swift index 0e0210211..e5d7a23b4 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/Feedback.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/Feedback.swift @@ -11,7 +11,7 @@ public extension Feedback { init( effects: @escaping (State) -> Effect ) where Effect.Output == Event, Effect.Failure == Never { - self.run = { state -> AnyPublisher in + run = { state -> AnyPublisher in state .map { effects($0) } .switchToLatest() diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/LargeButtonStyle.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/LargeButtonStyle.swift index dd588a7ee..af008a25c 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/LargeButtonStyle.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/LargeButtonStyle.swift @@ -10,7 +10,7 @@ public struct LargeButtonStyle: ButtonStyle { self.foregroundColor = foregroundColor self.isDisabled = isDisabled } - + public func makeBody(configuration: Self.Configuration) -> some View { let currentForegroundColor = isDisabled || configuration.isPressed diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/ProgressBar.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/ProgressBar.swift index 73d02ad03..f0fc2ad45 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/ProgressBar.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/ProgressBar.swift @@ -2,9 +2,9 @@ import SwiftUI public struct ProgressBar: View { @Binding var value: Double - + public init(value: Binding) { - self._value = value + _value = value } public var body: some View { @@ -20,7 +20,7 @@ public struct ProgressBar: View { Rectangle() .frame( - width: min(CGFloat(self.value) * geometry.size.width, geometry.size.width), + width: min(CGFloat(value) * geometry.size.width, geometry.size.width), height: geometry.size.height ) .foregroundColor(RuuviColor.green) diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/RuuvoBoardView.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/RuuvoBoardView.swift index b2aaddaf2..7831a5f7f 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/RuuvoBoardView.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/RuuvoBoardView.swift @@ -24,10 +24,9 @@ public struct RuuviBoardView: View { .padding() .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in guard let scene = UIApplication.shared.windows.first?.windowScene else { return } - self.isPortrait = scene.interfaceOrientation.isPortrait + isPortrait = scene.interfaceOrientation.isPortrait } } } -private class RuuviFirmwareDummyClass { -} +private class RuuviFirmwareDummyClass {} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/Spinner.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/Spinner.swift index c4c70e6b6..568ad72ac 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/Spinner.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/Spinner.swift @@ -9,14 +9,14 @@ public struct Spinner: UIViewRepresentable { self.isAnimating = isAnimating self.style = style } - - public func makeUIView(context: Context) -> UIActivityIndicatorView { + + public func makeUIView(context _: Context) -> UIActivityIndicatorView { let spinner = UIActivityIndicatorView(style: style) spinner.hidesWhenStopped = true return spinner } - public func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) { + public func updateUIView(_ uiView: UIActivityIndicatorView, context _: Context) { if isAnimating { uiView.startAnimating() } else { diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/URLSession+downloadTaskPublisher.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/URLSession+downloadTaskPublisher.swift index 70d369351..7bda19c6c 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/URLSession+downloadTaskPublisher.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/URLSession+downloadTaskPublisher.swift @@ -1,21 +1,21 @@ -import Foundation import Combine +import Foundation public enum DownloadResponse { case progress(Progress) case response(fileUrl: URL) } -extension URLSession { - public func downloadTaskPublisher(for url: URL, progress: Progress) -> URLSession.DownloadTaskPublisher { - self.downloadTaskPublisher(for: .init(url: url), progress: progress) +public extension URLSession { + func downloadTaskPublisher(for url: URL, progress: Progress) -> URLSession.DownloadTaskPublisher { + downloadTaskPublisher(for: .init(url: url), progress: progress) } - public func downloadTaskPublisher(for request: URLRequest, progress: Progress) -> URLSession.DownloadTaskPublisher { + func downloadTaskPublisher(for request: URLRequest, progress: Progress) -> URLSession.DownloadTaskPublisher { .init(request: request, session: self, progress: progress) } - public struct DownloadTaskPublisher: Publisher { + struct DownloadTaskPublisher: Publisher { public typealias Output = DownloadResponse public typealias Failure = URLError @@ -31,12 +31,13 @@ extension URLSession { public func receive(subscriber: S) where S: Subscriber, DownloadTaskPublisher.Failure == S.Failure, - DownloadTaskPublisher.Output == S.Input { + DownloadTaskPublisher.Output == S.Input + { let subscription = DownloadTaskSubscription( subscriber: subscriber, - session: self.session, - request: self.request, - progress: self.progress + session: session, + request: request, + progress: progress ) subscriber.receive(subscription: subscription) } @@ -46,7 +47,8 @@ extension URLSession { extension URLSession { final class DownloadTaskSubscription: Subscription where SubscriberType.Input == DownloadResponse, - SubscriberType.Failure == URLError { + SubscriberType.Failure == URLError + { private var subscriber: SubscriberType? private weak var session: URLSession? private var request: URLRequest @@ -77,7 +79,7 @@ extension URLSession { guard task == nil else { return } - self.task = self.session?.downloadTask(with: request) { [weak self] url, response, error in + self.task = session?.downloadTask(with: request) { [weak self] url, response, error in if let error = error as? URLError { self?.subscriber?.receive(completion: .failure(error)) return @@ -86,13 +88,13 @@ extension URLSession { self?.subscriber?.receive(completion: .failure(URLError(.badServerResponse))) return } - guard let url = url else { + guard let url else { self?.subscriber?.receive(completion: .failure(URLError(.badURL))) return } do { let cacheDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first! - let fileUrl = cacheDir.appendingPathComponent((UUID().uuidString)) + let fileUrl = cacheDir.appendingPathComponent(UUID().uuidString) try FileManager.default.moveItem(atPath: url.path, toPath: fileUrl.path) _ = self?.subscriber?.receive(.response(fileUrl: fileUrl)) self?.subscriber?.receive(completion: .finished) @@ -100,7 +102,7 @@ extension URLSession { self?.subscriber?.receive(completion: .failure(URLError(.cannotCreateFile))) } } - guard let task = self.task else { return } + guard let task else { return } progress.addChild(task.progress, withPendingUnitCount: 1) observation = progress.observe(\.fractionCompleted) { [weak self] progress, _ in @@ -111,7 +113,7 @@ extension URLSession { } func cancel() { - self.task?.cancel() + task?.cancel() } } } diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift index 5f767ef98..478377534 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift @@ -31,7 +31,7 @@ final class FirmwareInteractor { self.ruuviDFU = ruuviDFU self.firmwareRepository = firmwareRepository } - + func loadLatestGitHubRelease() -> AnyPublisher { let urlString = "https://api.github.com/repos/ruuvi/ruuvi.firmware.c/releases/latest" guard let url = URL(string: urlString) else { @@ -39,32 +39,32 @@ final class FirmwareInteractor { } return URLSession.shared.dataTaskPublisher(for: url) - .map { $0.data } + .map(\.data) .decode(type: GitHubRelease.self, decoder: JSONDecoder()) - .catch { error in Fail(error: error)} + .catch { error in Fail(error: error) } .receive(on: RunLoop.main) .eraseToAnyPublisher() } - + func serveCurrentRelease(uuid: String) -> Future { - return Future { [weak self] promise in + Future { [weak self] promise in guard let self else { return } - self.background.services.gatt.firmwareRevision( + background.services.gatt.firmwareRevision( for: self, uuid: uuid, options: [.connectionTimeout(15)] ) { _, result in switch result { - case .success(let version): + case let .success(version): let currentRelease = CurrentRelease(version: version) promise(.success(currentRelease)) - case .failure(let error): + case let .failure(error): promise(.failure(error)) } } } } - + func read(release: GitHubRelease) -> AnyPublisher<(appUrl: URL, fullUrl: URL), Error> { guard let fullName = release.defaultFullZipName else { return Fail<(appUrl: URL, fullUrl: URL), Error>( @@ -81,17 +81,19 @@ final class FirmwareInteractor { return app .combineLatest(full) .map { app, full in - return (appUrl: app, fullUrl: full) + (appUrl: app, fullUrl: full) }.eraseToAnyPublisher() } - + func download(release: GitHubRelease) -> AnyPublisher { guard let fullName = release.defaultFullZipName, - let fullUrl = release.defaultFullZipUrl else { + let fullUrl = release.defaultFullZipUrl + else { return Fail(error: URLError(.badURL)).eraseToAnyPublisher() } guard let appName = release.defaultAppZipName, - let appUrl = release.defaultAppZipUrl else { + let appUrl = release.defaultAppZipUrl + else { return Fail(error: URLError(.badURL)).eraseToAnyPublisher() } let progress = Progress(totalUnitCount: 2) @@ -99,28 +101,28 @@ final class FirmwareInteractor { let app = download(url: appUrl, name: appName, progress: progress) return app .combineLatest(full) - .map({ app, full in + .map { app, full in switch (app, full) { case let (.progress(appProgress), .progress): - return .progress(appProgress) + .progress(appProgress) case let (.progress(appProgress), .response): - return .progress(appProgress) + .progress(appProgress) case let (.response, .progress(fullProgress)): - return .progress(fullProgress) + .progress(fullProgress) case let (.response(appUrl), .response(fullUrl)): - return .response(appUrl: appUrl, fullUrl: fullUrl) + .response(appUrl: appUrl, fullUrl: fullUrl) } - }).eraseToAnyPublisher() + }.eraseToAnyPublisher() } - + private func download(url: URL, name: String, progress: Progress) -> AnyPublisher { - return URLSession.shared + URLSession.shared .downloadTaskPublisher(for: url, progress: progress) .catch { error in Fail(error: error) } - .map({ [weak self] response in + .map { [weak self] response in guard let sSelf = self else { return response } switch response { - case .response(let fileUrl): + case let .response(fileUrl): if let movedUrl = try? sSelf.firmwareRepository.save( name: name, fileUrl: fileUrl @@ -132,32 +134,31 @@ final class FirmwareInteractor { case .progress: return response } - - }) + } .receive(on: RunLoop.main) .eraseToAnyPublisher() } - + func listen() -> Future { - return Future { [weak self] promise in + Future { [weak self] promise in guard let self else { return } - self.ruuviDFU.scan(self) { _, device in + ruuviDFU.scan(self) { _, device in promise(.success(device.uuid)) } } } - + func observeLost(uuid: String) -> Future { - return Future { [weak self] promise in + Future { [weak self] promise in guard let self else { return } - self.ruuviDFU.lost(self, closure: { _, device in + ruuviDFU.lost(self, closure: { _, device in if device.uuid == uuid { promise(.success(uuid)) } }) } } - + func flash( uuid: String, latestRelease: GitHubRelease, @@ -165,9 +166,8 @@ final class FirmwareInteractor { appUrl: URL, fullUrl: URL ) -> AnyPublisher { - let firmwareUrl: URL - if let currentRelease = currentRelease { + if let currentRelease { let currentMajor = currentRelease.version.drop(while: { !$0.isNumber }).prefix(while: { $0 != "." }) let latestMajor = latestRelease.version.drop(while: { !$0.isNumber }).prefix(while: { $0 != "." }) if currentMajor == latestMajor { @@ -176,7 +176,7 @@ final class FirmwareInteractor { firmwareUrl = fullUrl } } else { - firmwareUrl = fullUrl + firmwareUrl = fullUrl } guard let firmware = ruuviDFU.firmwareFromUrl(url: firmwareUrl) else { diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift index 670f11841..0cdb0ab2e 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift @@ -8,7 +8,7 @@ final class FirmwarePresenter: RuuviFirmware { var router: AnyObject? var viewController: UIViewController { - if let view = self.weakView { + if let view = weakView { return view } else { let viewModel = FirmwareViewModel( @@ -18,10 +18,11 @@ final class FirmwarePresenter: RuuviFirmware { ) viewModel.output = self let view = UIHostingController(rootView: FirmwareView(viewModel: viewModel)) - self.weakView = view + weakView = view return view } } + private weak var weakView: UIViewController? private let interactor: FirmwareInteractor private let uuid: String @@ -36,7 +37,7 @@ final class FirmwarePresenter: RuuviFirmware { ) { self.uuid = uuid self.currentFirmware = currentFirmware - self.interactor = FirmwareInteractor( + interactor = FirmwareInteractor( background: background, ruuviDFU: ruuviDFU, firmwareRepository: firmwareRepository diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Model/GitHubRelease+URL.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Model/GitHubRelease+URL.swift index 379dd8c83..454a092fe 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Model/GitHubRelease+URL.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Model/GitHubRelease+URL.swift @@ -2,42 +2,42 @@ import Foundation extension GitHubRelease { var defaultFullZipName: String? { - return defaultFullZipAsset?.name + defaultFullZipAsset?.name } var defaultFullZipUrl: URL? { if let downloadUrlString = defaultFullZipAsset?.downloadUrlString { - return URL(string: downloadUrlString) + URL(string: downloadUrlString) } else { - return nil + nil } } var defaultAppZipName: String? { - return defaultAppZipAsset?.name + defaultAppZipAsset?.name } var defaultAppZipUrl: URL? { if let downloadUrlString = defaultAppZipAsset?.downloadUrlString { - return URL(string: downloadUrlString) + URL(string: downloadUrlString) } else { - return nil + nil } } - + private var defaultFullZipAsset: GitHubRelease.Asset? { - return assets.first(where: { - $0.name.hasSuffix("zip") - && $0.name.contains("default") - && !$0.name.contains("app") - }) - } + assets.first(where: { + $0.name.hasSuffix("zip") + && $0.name.contains("default") + && !$0.name.contains("app") + }) + } private var defaultAppZipAsset: GitHubRelease.Asset? { - return assets.first(where: { - $0.name.hasSuffix("zip") - && $0.name.contains("default") - && $0.name.contains("app") - }) - } + assets.first(where: { + $0.name.hasSuffix("zip") + && $0.name.contains("default") + && $0.name.contains("app") + }) + } } diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Model/GitHubRelease.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Model/GitHubRelease.swift index 44ae0b56d..8062387c4 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Model/GitHubRelease.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Model/GitHubRelease.swift @@ -16,7 +16,6 @@ struct GitHubRelease: Codable { enum CodingKeys: String, CodingKey { case version = "tag_name" - case assets = "assets" + case assets } } - diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Repository/FirmwareRepository.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Repository/FirmwareRepository.swift index 633d74d7b..90c5f51d5 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Repository/FirmwareRepository.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Repository/FirmwareRepository.swift @@ -1,5 +1,5 @@ -import Foundation import Combine +import Foundation public enum FirmwareRepositoryError: Error { case failedToGetDocumentsDirectory @@ -18,11 +18,12 @@ public final class FirmwareRepositoryImpl: FirmwareRepository { public init() {} public func read(name: String) -> Future { - return Future { [weak self] promise in + Future { [weak self] promise in DispatchQueue.global(qos: .userInitiated).async { [weak self] in do { if let dstUrl = try self?.getFirmwareDirectory().appendingPathComponent(name), - FileManager.default.fileExists(atPath: dstUrl.path) { + FileManager.default.fileExists(atPath: dstUrl.path) + { promise(.success(dstUrl)) } else { promise(.failure(FirmwareRepositoryError.fileNotFound)) @@ -35,7 +36,7 @@ public final class FirmwareRepositoryImpl: FirmwareRepository { } public func save(name: String, fileUrl: URL) throws -> URL { - let dstUrl = try self.getFirmwareDirectory().appendingPathComponent(name) + let dstUrl = try getFirmwareDirectory().appendingPathComponent(name) if FileManager.default.fileExists(atPath: dstUrl.path) { try FileManager.default.removeItem(at: dstUrl) } diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift index 78f2f1c00..cbecc9212 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift @@ -32,17 +32,17 @@ struct FirmwareView: View { private static let fontSize: CGFloat = 16 private let muliBold16 = Font( UIFont(name: "Muli-Bold", size: fontSize.adjustedFontSize()) ?? - UIFont.systemFont(ofSize: fontSize.adjustedFontSize(), weight: .bold)) + UIFont.systemFont(ofSize: fontSize.adjustedFontSize(), weight: .bold)) private let muliRegular16 = Font( UIFont(name: "Muli-Regular", size: fontSize.adjustedFontSize()) ?? - UIFont.systemFont(ofSize: fontSize.adjustedFontSize(), weight: .regular)) - + UIFont.systemFont(ofSize: fontSize.adjustedFontSize(), weight: .regular)) + private var content: some View { switch viewModel.state { case .idle: - return Color.clear.eraseToAnyView() + Color.clear.eraseToAnyView() case .loading: - return VStack(alignment: .leading, spacing: 16) { + VStack(alignment: .leading, spacing: 16) { Text(texts.latestTitle).bold() .font(muliBold16) .foregroundColor(RuuviColor.ruuviTextColorSUI) @@ -55,12 +55,12 @@ struct FirmwareView: View { ) .padding() .eraseToAnyView() - case .error(let error): - return Text(error.localizedDescription) + case let .error(error): + Text(error.localizedDescription) .font(muliRegular16) .eraseToAnyView() case let .loaded(latestRelease): - return VStack(alignment: .leading, spacing: 16) { + VStack(alignment: .leading, spacing: 16) { Text(texts.latestTitle).bold() .font(muliBold16) .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) @@ -78,10 +78,10 @@ struct FirmwareView: View { alignment: .topLeading ) .padding() - .onAppear { self.viewModel.send(event: .onLoaded(latestRelease)) } + .onAppear { viewModel.send(event: .onLoaded(latestRelease)) } .eraseToAnyView() case let .serving(latestRelease): - return VStack(alignment: .leading, spacing: 16) { + VStack(alignment: .leading, spacing: 16) { Text(texts.latestTitle).bold() .font(muliBold16) .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) @@ -101,7 +101,7 @@ struct FirmwareView: View { .padding() .eraseToAnyView() case let .checking(latestRelease, currentRelease): - return VStack(alignment: .leading, spacing: 16) { + VStack(alignment: .leading, spacing: 16) { Text(texts.latestTitle).bold() .font(muliBold16) .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) @@ -127,10 +127,10 @@ struct FirmwareView: View { alignment: .topLeading ) .padding() - .onAppear { self.viewModel.send(event: .onLoadedAndServed(latestRelease, currentRelease)) } + .onAppear { viewModel.send(event: .onLoadedAndServed(latestRelease, currentRelease)) } .eraseToAnyView() case .noNeedToUpgrade: - return VStack { + VStack { Text(texts.alreadyOnLatest) .font(muliRegular16) .foregroundColor(RuuviColor.ruuviTextColorSUI) @@ -142,7 +142,7 @@ struct FirmwareView: View { .padding() Button( action: { - self.viewModel.finish() + viewModel.finish() }, label: { Text(texts.finish) @@ -162,7 +162,7 @@ struct FirmwareView: View { } .eraseToAnyView() case let .isAbleToUpgrade(latestRelease, currentRelease): - return VStack { + VStack { VStack(alignment: .leading, spacing: 16) { Text(texts.latestTitle).bold() .font(muliBold16) @@ -184,7 +184,7 @@ struct FirmwareView: View { } Button( action: { - self.viewModel.send( + viewModel.send( event: .onStartUpgrade(latestRelease, currentRelease) ) }, @@ -214,11 +214,11 @@ struct FirmwareView: View { .padding() .eraseToAnyView() case .reading: - return VStack { + VStack { Spinner(isAnimating: true, style: .medium).eraseToAnyView() }.eraseToAnyView() case .downloading: - return VStack(alignment: .center, spacing: 16) { + VStack(alignment: .center, spacing: 16) { Text(texts.downloadingTitle) .font(muliRegular16) .foregroundColor(RuuviColor.ruuviTextColorSUI) @@ -237,7 +237,7 @@ struct FirmwareView: View { .padding() .eraseToAnyView() case .listening: - return VStack { + VStack { ScrollView(showsIndicators: false) { VStack(spacing: 20) { RuuviBoardView() @@ -296,7 +296,7 @@ struct FirmwareView: View { .padding(EdgeInsets(top: 0, leading: 20, bottom: 20, trailing: 20)) .eraseToAnyView() case let .readyToUpdate(latestRelease, currentRelease, uuid, appUrl, fullUrl): - return VStack { + VStack { ScrollView(showsIndicators: false) { VStack(spacing: 20) { RuuviBoardView() @@ -325,7 +325,7 @@ struct FirmwareView: View { } Button( action: { - self.viewModel.send( + viewModel.send( event: .onUserDidConfirmToFlash( latestRelease, currentRelease, @@ -361,7 +361,7 @@ struct FirmwareView: View { .padding(EdgeInsets(top: 0, leading: 20, bottom: 20, trailing: 20)) .eraseToAnyView() case .flashing: - return VStack(alignment: .center, spacing: 24) { + VStack(alignment: .center, spacing: 24) { Text(texts.updatingTitle) .font(muliRegular16) .foregroundColor(RuuviColor.ruuviTextColorSUI) @@ -375,7 +375,6 @@ struct FirmwareView: View { .bold() .multilineTextAlignment(.center) .foregroundColor(RuuviColor.ruuviTextColorSUI) - } .frame( maxWidth: .infinity, @@ -385,7 +384,7 @@ struct FirmwareView: View { .padding() .eraseToAnyView() case .successfulyFlashed: - return VStack { + VStack { Text(texts.successfulTitle) .font(muliRegular16) .foregroundColor(RuuviColor.ruuviTextColorSUI) @@ -397,7 +396,7 @@ struct FirmwareView: View { .padding() Button( action: { - self.viewModel.finish() + viewModel.finish() }, label: { Text(texts.finish) @@ -418,7 +417,7 @@ struct FirmwareView: View { .eraseToAnyView() } } - + var body: some View { VStack { content @@ -426,13 +425,13 @@ struct FirmwareView: View { .accentColor(.red) .navigationBarBackButtonHidden(true) .onAppear { - self.viewModel.send(event: .onAppear) + viewModel.send(event: .onAppear) } } } private extension CGFloat { func adjustedFontSize() -> CGFloat { - return UIDevice.current.userInterfaceIdiom == .pad ? self + 4 : self + UIDevice.current.userInterfaceIdiom == .pad ? self + 4 : self } } diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift index caeb38507..8ff16d74a 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift @@ -15,7 +15,7 @@ final class FirmwareViewModel: ObservableObject { private var currentFirmware: String? private let interactor: FirmwareInteractor private var bag = Set() - + init( uuid: String, currentFirmware: String?, @@ -29,14 +29,14 @@ final class FirmwareViewModel: ObservableObject { reduce: Self.reduce, scheduler: RunLoop.main, feedbacks: [ - self.whenLoading(), - self.whenServing(), - self.whenReading(), - self.whenDownloading(), - self.whenListening(), - self.whenReadyToUpdate(), - self.whenFlashing(), - self.userInput(input: input.eraseToAnyPublisher()) + whenLoading(), + whenServing(), + whenReading(), + whenDownloading(), + whenListening(), + whenReadyToUpdate(), + whenFlashing(), + userInput(input: input.eraseToAnyPublisher()), ] ) .assign(to: \.state, on: self) @@ -46,17 +46,18 @@ final class FirmwareViewModel: ObservableObject { func send(event: Event) { input.send(event) } - + func finish() { output?.firmwareUpgradeDidFinishSuccessfully() } } // MARK: - Feedbacks + extension FirmwareViewModel { func userInput(input: AnyPublisher) -> Feedback { Feedback { _ in - return input + input } } @@ -65,25 +66,25 @@ extension FirmwareViewModel { guard case .loading = state, let self else { return Empty().eraseToAnyPublisher() } - return self.interactor.loadLatestGitHubRelease() + return interactor.loadLatestGitHubRelease() .receive(on: RunLoop.main) .map(Event.onLoaded) .catch { Just(Event.onDidFailLoading($0)) } .eraseToAnyPublisher() } } - + func whenServing() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in guard case .serving = state, let self else { return Empty().eraseToAnyPublisher() } - if let currentFirmware = self.currentFirmware { + if let currentFirmware { return Just(CurrentRelease(version: currentFirmware)) .map(Event.onServed) .eraseToAnyPublisher() } else { - return self.interactor.serveCurrentRelease(uuid: self.uuid) + return interactor.serveCurrentRelease(uuid: uuid) .receive(on: RunLoop.main) .map(Event.onServed) .catch { _ in Just(Event.onServed(nil)) } @@ -91,17 +92,18 @@ extension FirmwareViewModel { } } } - + func whenReading() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in guard case let .reading(latestRelease, currentRelease) = state, - let sSelf = self else { + let sSelf = self + else { return Empty().eraseToAnyPublisher() } return sSelf.interactor.read(release: latestRelease) .receive(on: RunLoop.main) .map { tuple in - return Event.onRead( + Event.onRead( latestRelease, currentRelease, appUrl: tuple.appUrl, @@ -112,38 +114,39 @@ extension FirmwareViewModel { .eraseToAnyPublisher() } } - + func whenDownloading() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in guard case let .downloading(latestRelease, currentRelease) = state, let self else { return Empty().eraseToAnyPublisher() } - return self.interactor.download(release: latestRelease) + return interactor.download(release: latestRelease) .receive(on: RunLoop.main) - .compactMap({ [weak self] response in + .compactMap { [weak self] response in switch response { case let .response(appUrl, fullUrl): return Event.onDownloaded(latestRelease, currentRelease, appUrl: appUrl, fullUrl: fullUrl) - case .progress(let progress): + case let .progress(progress): self?.downloadProgress = progress.fractionCompleted return nil } - }) + } .catch { Just(Event.onDidFailDownloading($0)) } .eraseToAnyPublisher() } } - + func whenListening() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in guard case let .listening(latestRelease, currentRelease, appUrl, fullUrl) = state, - let sSelf = self else { + let sSelf = self + else { return Empty().eraseToAnyPublisher() } return sSelf.interactor.listen() .receive(on: RunLoop.main) .map { uuid in - return Event.onHeardRuuviBootDevice( + Event.onHeardRuuviBootDevice( latestRelease, currentRelease, uuid: uuid, @@ -154,17 +157,18 @@ extension FirmwareViewModel { .eraseToAnyPublisher() } } - + func whenReadyToUpdate() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in guard case let .readyToUpdate(latestRelease, currentRelease, uuid, appUrl, fullUrl) = state, - let sSelf = self else { + let sSelf = self + else { return Empty().eraseToAnyPublisher() } return sSelf.interactor.observeLost(uuid: uuid) .receive(on: RunLoop.main) .map { uuid in - return Event.onLostRuuviBootDevice( + Event.onLostRuuviBootDevice( latestRelease, currentRelease, uuid: uuid, @@ -175,15 +179,15 @@ extension FirmwareViewModel { .eraseToAnyPublisher() } } - + func whenFlashing() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in guard case let .flashing( - latestRelease, - currentRelease, - uuid, - appUrl, - fullUrl + latestRelease, + currentRelease, + uuid, + appUrl, + fullUrl ) = state, let sSelf = self else { return Empty().eraseToAnyPublisher() } @@ -195,17 +199,17 @@ extension FirmwareViewModel { fullUrl: fullUrl ) .receive(on: RunLoop.main) - .compactMap({ [weak sSelf] response in + .compactMap { [weak sSelf] response in switch response { case .done: return Event.onSuccessfullyFlashedFirmware(latestRelease) - case .progress(let percentage): + case let .progress(percentage): sSelf?.flashProgress = percentage return nil case .log: return nil } - }) + } .catch { Just(Event.onDidFailFlashingFirmware($0)) } .eraseToAnyPublisher() } @@ -302,54 +306,54 @@ extension FirmwareViewModel { case .idle: switch event { case .onAppear: - return .loading + .loading default: - return state + state } case .loading: switch event { case let .onDidFailLoading(error): - return .error(error) + .error(error) case let .onLoaded(latestRelease): - return .loaded(latestRelease) + .loaded(latestRelease) default: - return state + state } case let .loaded(latestRelease): - return .serving(latestRelease) + .serving(latestRelease) case let .serving(latestRelease): switch event { case let .onServed(currentRelease): - return .checking(latestRelease, currentRelease) + .checking(latestRelease, currentRelease) default: - return state + state } case let .checking(latestRelease, currentRelease): if isRecommendedToUpdate( latestRelease: latestRelease, currentRelease: currentRelease ) { - return .isAbleToUpgrade(latestRelease, currentRelease) + .isAbleToUpgrade(latestRelease, currentRelease) } else { - return .noNeedToUpgrade(latestRelease, currentRelease) + .noNeedToUpgrade(latestRelease, currentRelease) } case .noNeedToUpgrade: - return state + state case let .isAbleToUpgrade(latestRelease, currentRelease): - return .reading(latestRelease, currentRelease) + .reading(latestRelease, currentRelease) case .reading: switch event { case let .onRead(latestRelease, currentRelease, appUrl, fullUrl): - return .listening( + .listening( latestRelease, currentRelease, appUrl: appUrl, fullUrl: fullUrl ) case let .onDidFailReading(latestRelease, currentRelease, _): - return .downloading(latestRelease, currentRelease) + .downloading(latestRelease, currentRelease) default: - return state + state } case .downloading: switch event { @@ -359,52 +363,52 @@ extension FirmwareViewModel { appUrl, fullUrl ): - return .listening( + .listening( latestRelease, currentRelease, appUrl: appUrl, fullUrl: fullUrl ) default: - return state + state } case .listening: switch event { case let .onHeardRuuviBootDevice(latestRelease, currentRelease, uuid, appUrl, fullUrl): - return .readyToUpdate(latestRelease, currentRelease, uuid: uuid, appUrl: appUrl, fullUrl: fullUrl) + .readyToUpdate(latestRelease, currentRelease, uuid: uuid, appUrl: appUrl, fullUrl: fullUrl) default: - return state + state } case .readyToUpdate: switch event { case let .onLostRuuviBootDevice(latestRelease, currentRelease, _, appUrl, fullUrl): - return .listening(latestRelease, currentRelease, appUrl: appUrl, fullUrl: fullUrl) + .listening(latestRelease, currentRelease, appUrl: appUrl, fullUrl: fullUrl) case let .onUserDidConfirmToFlash(latestRelease, currentRelease, uuid, appUrl, fullUrl): - return .flashing(latestRelease, currentRelease, uuid: uuid, appUrl: appUrl, fullUrl: fullUrl) + .flashing(latestRelease, currentRelease, uuid: uuid, appUrl: appUrl, fullUrl: fullUrl) default: - return state + state } case .flashing: switch event { - case .onSuccessfullyFlashedFirmware(let latestRelease): - return .successfulyFlashed(latestRelease) - case .onDidFailFlashingFirmware(let error): - return .error(error) + case let .onSuccessfullyFlashedFirmware(latestRelease): + .successfulyFlashed(latestRelease) + case let .onDidFailFlashingFirmware(error): + .error(error) default: - return state + state } case .successfulyFlashed: - return state + state case .error: - return state + state } } - + static func isRecommendedToUpdate( latestRelease: GitHubRelease, currentRelease: CurrentRelease? ) -> Bool { - guard let currentRelease = currentRelease else { return true } + guard let currentRelease else { return true } return !currentRelease.version.contains(latestRelease.version) } } diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift index be1ad1013..ccd444085 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift @@ -1,8 +1,8 @@ import Foundation import UIKit -extension Bundle { - public static func pod(_ clazz: AnyClass) -> Bundle { +public extension Bundle { + static func pod(_ clazz: AnyClass) -> Bundle { if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { if let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), let bundle = Bundle(url: bundleURL) { return bundle @@ -19,12 +19,12 @@ extension Bundle { } } -extension UIImage { - public static func named(_ name: String, for clazz: AnyClass) -> UIImage? { +public extension UIImage { + static func named(_ name: String, for clazz: AnyClass) -> UIImage? { #if SWIFT_PACKAGE - return UIImage(named: name, in: Bundle.module, compatibleWith: nil) + return UIImage(named: name, in: Bundle.module, compatibleWith: nil) #else - return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) + return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) #endif } } @@ -33,16 +33,18 @@ extension String { public func localized(for clazz: AnyClass) -> String { let bundle: Bundle #if SWIFT_PACKAGE - bundle = Bundle.module + bundle = Bundle.module #else - bundle = Bundle.pod(clazz) + bundle = Bundle.pod(clazz) #endif if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), - let bundle = Bundle(path: path) { + let bundle = Bundle(path: path) + { return bundle.localizedString(forKey: self, value: nil, table: module) } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), - let bundle = Bundle(path: path) { + let bundle = Bundle(path: path) + { return bundle.localizedString(forKey: self, value: nil, table: module) } else { assertionFailure() @@ -56,32 +58,32 @@ extension String { private func currentLanguage() -> String { if let preferred = Bundle.main.preferredLocalizations.first { - return preferred + preferred } else { - return "Base" + "Base" } } } -extension UIStoryboard { - public static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { +public extension UIStoryboard { + static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { let bundle: Bundle #if SWIFT_PACKAGE - bundle = Bundle.module + bundle = Bundle.module #else - bundle = Bundle.pod(clazz) + bundle = Bundle.pod(clazz) #endif return UIStoryboard(name: name, bundle: bundle) } } -extension UINib { - public static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { +public extension UINib { + static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { let bundle: Bundle #if SWIFT_PACKAGE - bundle = Bundle.module + bundle = Bundle.module #else - bundle = Bundle.pod(clazz) + bundle = Bundle.pod(clazz) #endif return UINib(nibName: nibName, bundle: bundle) } diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviColor.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviColor.swift index 299f683da..9a01acf6e 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviColor.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviColor.swift @@ -1,6 +1,6 @@ import SwiftUI -struct RuuviColor { +enum RuuviColor { static let green = Color("RuuviGreen") static let ruuviTintColorSUI = Color("RuuviTintColor") static let ruuviTextColorSUI = Color("RuuviTextColor") diff --git a/Modules/RuuviFirmware/Tests/RuuviFirmwareTests/RuuviFirmwareTests.swift b/Modules/RuuviFirmware/Tests/RuuviFirmwareTests/RuuviFirmwareTests.swift index 7bf78dcd8..7adcdcf36 100644 --- a/Modules/RuuviFirmware/Tests/RuuviFirmwareTests/RuuviFirmwareTests.swift +++ b/Modules/RuuviFirmware/Tests/RuuviFirmwareTests/RuuviFirmwareTests.swift @@ -1,5 +1,5 @@ -import XCTest @testable import RuuviFirmware +import XCTest final class RuuviFirmwareTests: XCTestCase { func testExample() throws { diff --git a/Modules/RuuviOnboard/Package.swift b/Modules/RuuviOnboard/Package.swift index f21a142b7..41e8c7576 100644 --- a/Modules/RuuviOnboard/Package.swift +++ b/Modules/RuuviOnboard/Package.swift @@ -10,17 +10,20 @@ let package = Package( products: [ .library( name: "RuuviOnboard", - targets: ["RuuviOnboard"]) + targets: ["RuuviOnboard"] + ), ], dependencies: [ - .package(path: "../../Packages/RuuviUser") + .package(path: "../../Packages/RuuviUser"), ], targets: [ .target( name: "RuuviOnboard", - dependencies: ["RuuviUser"]), + dependencies: ["RuuviUser"] + ), .testTarget( name: "RuuviOnboardTests", - dependencies: ["RuuviOnboard"]) + dependencies: ["RuuviOnboard"] + ), ] ) diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Assests/RuuviAssets.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Assests/RuuviAssets.swift index 06272557f..880d25bda 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Assests/RuuviAssets.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Assests/RuuviAssets.swift @@ -1,6 +1,6 @@ import UIKit -struct RuuviAssets { +enum RuuviAssets { static let bg_layer = "onboarding_bg_layer" static let beaver_start = "onboarding_beaver_start" static let dashboard = "onboarding_dashboard" diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIButton+Extension.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIButton+Extension.swift index 0156370db..fde26ce82 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIButton+Extension.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIButton+Extension.swift @@ -2,8 +2,8 @@ import UIKit extension UIButton { func underline() { - guard let text = self.titleLabel?.text, - let titleColor = self.titleColor(for: .normal) else { return } + guard let text = titleLabel?.text, + let titleColor = titleColor(for: .normal) else { return } let attributedString = NSMutableAttributedString(string: text) attributedString.addAttribute(NSAttributedString.Key.underlineColor, value: titleColor, @@ -15,6 +15,6 @@ extension UIButton { attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: text.count)) - self.setAttributedTitle(attributedString, for: .normal) + setAttributedTitle(attributedString, for: .normal) } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIFont+Extension.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIFont+Extension.swift index d9e36c323..4f965e4c1 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIFont+Extension.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIFont+Extension.swift @@ -19,32 +19,36 @@ extension UIFont { } // MARK: - FUNCTIONS + static func Montserrat(_ type: MontserratStyles = .regular, - size: CGFloat = UIFont.systemFontSize) -> UIFont { - return UIFont(name: "Montserrat-\(type.rawValue)", - size: size.adjustedSize()) ?? - UIFont.systemFont(ofSize: size.adjustedSize()) + size: CGFloat = UIFont.systemFontSize) -> UIFont + { + UIFont(name: "Montserrat-\(type.rawValue)", + size: size.adjustedSize()) ?? + UIFont.systemFont(ofSize: size.adjustedSize()) } static func Muli(_ type: MuliStyles = .regular, - size: CGFloat = UIFont.systemFontSize) -> UIFont { + size: CGFloat = UIFont.systemFontSize) -> UIFont + { let prefix = type == .semiBoldItalic ? "Mulish" : "Muli" return UIFont(name: "\(prefix)-\(type.rawValue)", size: size.adjustedSize()) ?? - UIFont.systemFont(ofSize: size.adjustedSize()) + UIFont.systemFont(ofSize: size.adjustedSize()) } static func Oswald(_ type: OswaldStyles = .extraLight, - size: CGFloat = UIFont.systemFontSize) -> UIFont { - return UIFont(name: "Oswald-\(type.rawValue)", - size: size.adjustedSize()) ?? - UIFont.systemFont(ofSize: size.adjustedSize(), - weight: .ultraLight) + size: CGFloat = UIFont.systemFontSize) -> UIFont + { + UIFont(name: "Oswald-\(type.rawValue)", + size: size.adjustedSize()) ?? + UIFont.systemFont(ofSize: size.adjustedSize(), + weight: .ultraLight) } } extension CGFloat { func adjustedSize() -> CGFloat { - return UIDevice.current.userInterfaceIdiom == .pad ? self + 4 : self + UIDevice.current.userInterfaceIdiom == .pad ? self + 4 : self } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIImageView+Init.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIImageView+Init.swift index 33f2444bd..d13e35b68 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIImageView+Init.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIImageView+Init.swift @@ -4,13 +4,14 @@ extension UIImageView { convenience init(image: UIImage? = nil, backgroundColor: UIColor = .clear, contentMode: ContentMode = .scaleAspectFill, - cornerRadius: CGFloat = 0) { + cornerRadius: CGFloat = 0) + { self.init() self.image = image self.backgroundColor = backgroundColor self.contentMode = contentMode - self.layer.cornerRadius = cornerRadius - self.clipsToBounds = true - self.isUserInteractionEnabled = true + layer.cornerRadius = cornerRadius + clipsToBounds = true + isUserInteractionEnabled = true } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UILabel+Init.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UILabel+Init.swift index 07f2cc6f4..f003dae89 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UILabel+Init.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UILabel+Init.swift @@ -1,18 +1,17 @@ import UIKit extension UILabel { - convenience init(text: String, textColor: UIColor = .label, font: UIFont = .Muli(.regular, size: 16), numberOfLines: Int = 0, - alignment: NSTextAlignment = .left) { + alignment: NSTextAlignment = .left) + { self.init() self.text = text self.textColor = textColor self.font = font self.numberOfLines = numberOfLines - self.textAlignment = alignment + textAlignment = alignment } - } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIView+Init.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIView+Init.swift index 16e947142..046e18f21 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIView+Init.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIView+Init.swift @@ -4,12 +4,13 @@ extension UIView { convenience init(color: UIColor? = .clear, cornerRadius: CGFloat = 0, borderWidth: CGFloat = 0, - borderColor: UIColor = .clear) { + borderColor: UIColor = .clear) + { self.init() - self.layer.cornerRadius = cornerRadius - self.layer.borderWidth = borderWidth - self.layer.borderColor = borderColor.cgColor - self.backgroundColor = color + layer.cornerRadius = cornerRadius + layer.borderWidth = borderWidth + layer.borderColor = borderColor.cgColor + backgroundColor = color clipsToBounds = true } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIView+Layout.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIView+Layout.swift index ae7860024..3369cba98 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIView+Layout.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIView+Layout.swift @@ -4,33 +4,32 @@ import UIKit /// It helps to reduce a lot of redundant code to set constraint for all views extension UIView { - @discardableResult func anchor(top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, - padding: UIEdgeInsets = .zero, size: CGSize = .zero) -> AnchoredConstraints { - + padding: UIEdgeInsets = .zero, size: CGSize = .zero) -> AnchoredConstraints + { translatesAutoresizingMaskIntoConstraints = false var anchoredConstraints = AnchoredConstraints() - if let top = top { + if let top { anchoredConstraints.top = topAnchor.constraint(equalTo: top, constant: padding.top) } - if let leading = leading { + if let leading { anchoredConstraints.leading = leadingAnchor.constraint(equalTo: leading, constant: padding.left) } - if let bottom = bottom { + if let bottom { anchoredConstraints.bottom = bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom) } - if let trailing = trailing { + if let trailing { anchoredConstraints.trailing = trailingAnchor.constraint(equalTo: trailing, constant: -padding.right) } @@ -59,28 +58,28 @@ extension UIView { bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets = .zero, - size: CGSize = .zero) -> AnchoredConstraints { - + size: CGSize = .zero) -> AnchoredConstraints + { translatesAutoresizingMaskIntoConstraints = false var anchoredConstraints = AnchoredConstraints() - if let top = top { + if let top { anchoredConstraints.top = topAnchor.constraint(equalTo: top, constant: padding.top) } - if let leading = leading { + if let leading { anchoredConstraints.leading = leadingAnchor.constraint(greaterThanOrEqualTo: leading, constant: padding.left) } - if let bottom = bottom { + if let bottom { anchoredConstraints.bottom = bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom) } - if let trailing = trailing { + if let trailing { anchoredConstraints.trailing = trailingAnchor.constraint(lessThanOrEqualTo: trailing, constant: -padding.right) @@ -208,10 +207,10 @@ extension UIView { func match(view: UIView) { translatesAutoresizingMaskIntoConstraints = false - self.topAnchor.constraint(equalTo: view.topAnchor).isActive = true - self.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true - self.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true - self.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true + topAnchor.constraint(equalTo: view.topAnchor).isActive = true + bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true + leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true + trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true } } @@ -225,33 +224,32 @@ struct AnchoredConstraints { } extension UIView { - var safeTopAnchor: NSLayoutYAxisAnchor { if #available(iOS 11.0, *) { return self.safeAreaLayoutGuide.topAnchor } - return self.topAnchor + return topAnchor } var safeLeadingAnchor: NSLayoutXAxisAnchor { if #available(iOS 11.0, *) { return self.safeAreaLayoutGuide.leadingAnchor } - return self.leftAnchor + return leftAnchor } var safeTrailingAnchor: NSLayoutXAxisAnchor { if #available(iOS 11.0, *) { return self.safeAreaLayoutGuide.trailingAnchor } - return self.rightAnchor + return rightAnchor } var safeBottomAnchor: NSLayoutYAxisAnchor { if #available(iOS 11.0, *) { return self.safeAreaLayoutGuide.bottomAnchor } - return self.bottomAnchor + return bottomAnchor } var topSafeAreaHeight: CGFloat { diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Helpers.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Helpers.swift index 64becb546..6da970867 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Helpers.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Helpers.swift @@ -2,25 +2,26 @@ import Foundation import UIKit // MARK: - Alert controller extension + public extension UIAlertController { func setMessageAlignment(_ alignment: NSTextAlignment) { let paragraphStyle = NSParagraphStyle.default.mutableCopy() as? NSMutableParagraphStyle paragraphStyle?.alignment = alignment let messageText = NSMutableAttributedString( - string: self.message ?? "", + string: message ?? "", attributes: [ NSAttributedString.Key.paragraphStyle: paragraphStyle, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 15), - NSAttributedString.Key.foregroundColor: UIColor.label + NSAttributedString.Key.foregroundColor: UIColor.label, ] ) - self.setValue(messageText, forKey: "attributedMessage") + setValue(messageText, forKey: "attributedMessage") } } extension UIDevice { static func isTablet() -> Bool { - return UIDevice.current.userInterfaceIdiom == .pad + UIDevice.current.userInterfaceIdiom == .pad } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardCoreFeaturesCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardCoreFeaturesCell.swift index c45acebf3..d058199fc 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardCoreFeaturesCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardCoreFeaturesCell.swift @@ -1,11 +1,9 @@ import UIKit class RuuviOnboardCoreFeaturesCell: UICollectionViewCell { - private lazy var appImageView: UIImageView = { let iv = UIImageView(image: nil, - contentMode: .scaleAspectFit - ) + contentMode: .scaleAspectFit) iv.backgroundColor = .clear return iv }() @@ -33,21 +31,20 @@ class RuuviOnboardCoreFeaturesCell: UICollectionViewCell { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } } -extension RuuviOnboardCoreFeaturesCell { - - fileprivate func setUpUI() { - +private extension RuuviOnboardCoreFeaturesCell { + func setUpUI() { let container = UIView(color: .clear) contentView.addSubview(container) container.fillSuperview() let textStack = UIStackView(arrangedSubviews: [ - subtitleLabel, titleLabel + subtitleLabel, titleLabel, ]) textStack.axis = .vertical textStack.distribution = .fillProportionally @@ -58,7 +55,7 @@ extension RuuviOnboardCoreFeaturesCell { leading: container.safeLeadingAnchor, bottom: nil, trailing: container.safeTrailingAnchor, - padding: .init(top: 44+12, left: 16, + padding: .init(top: 44 + 12, left: 16, bottom: 0, right: 16)) container.addSubview(appImageView) @@ -73,7 +70,6 @@ extension RuuviOnboardCoreFeaturesCell { extension RuuviOnboardCoreFeaturesCell { func configure(with viewModel: OnboardViewModel) { - switch viewModel.pageType { case .sensors: subtitleLabel.font = UIFont.Montserrat(.extraBold, size: 36) diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift index e719d15ff..31a73c2f3 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift @@ -1,11 +1,9 @@ import UIKit class RuuviOnboardGatewayFeaturesCell: UICollectionViewCell { - private lazy var appImageView: UIImageView = { let iv = UIImageView(image: nil, - contentMode: .scaleAspectFit - ) + contentMode: .scaleAspectFit) iv.backgroundColor = .clear return iv }() @@ -31,8 +29,7 @@ class RuuviOnboardGatewayFeaturesCell: UICollectionViewCell { private lazy var gateWayImageView: UIImageView = { let iv = UIImageView(image: UIImage.named(RuuviAssets.gateway, for: Self.self), - contentMode: .scaleAspectFit - ) + contentMode: .scaleAspectFit) iv.backgroundColor = .clear return iv }() @@ -52,22 +49,21 @@ class RuuviOnboardGatewayFeaturesCell: UICollectionViewCell { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } } -extension RuuviOnboardGatewayFeaturesCell { - +private extension RuuviOnboardGatewayFeaturesCell { // swiftlint:disable:next function_body_length - fileprivate func setUpUI() { - + func setUpUI() { let container = UIView(color: .clear) contentView.addSubview(container) container.fillSuperview() let textStack = UIStackView(arrangedSubviews: [ - subtitleLabel, titleLabel + subtitleLabel, titleLabel, ]) textStack.axis = .vertical textStack.distribution = .fillProportionally @@ -78,7 +74,7 @@ extension RuuviOnboardGatewayFeaturesCell { leading: container.safeLeadingAnchor, bottom: nil, trailing: container.safeTrailingAnchor, - padding: .init(top: 44+12, left: 16, + padding: .init(top: 44 + 12, left: 16, bottom: 0, right: 16)) let appImageViewContainer = UIView(color: .clear) @@ -103,7 +99,7 @@ extension RuuviOnboardGatewayFeaturesCell { trailing: container.trailingAnchor) let stackView = UIStackView(arrangedSubviews: [ - gateWayImageView, gatewayRequireLabel + gateWayImageView, gatewayRequireLabel, ]) stackView.distribution = .fillProportionally stackView.spacing = 8 diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardPages.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardPages.swift index 04d122701..7df1292a7 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardPages.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardPages.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviUser +import UIKit public final class RuuviOnboardPages: RuuviOnboard { public weak var output: RuuviOnboardOutput? @@ -12,7 +12,7 @@ public final class RuuviOnboardPages: RuuviOnboard { let view = RuuviOnboardViewController() view.output = self view.ruuviUser = ruuviUser - self.weakView = view + weakView = view return view } } @@ -27,13 +27,15 @@ public final class RuuviOnboardPages: RuuviOnboard { } extension RuuviOnboardPages: RuuviOnboardViewControllerOutput { - func ruuviOnboardPages(_ viewController: RuuviOnboardViewController, - didFinish sender: Any?) { + func ruuviOnboardPages(_: RuuviOnboardViewController, + didFinish _: Any?) + { output?.ruuviOnboardDidFinish(self) } - func ruuviOnboardCloudSignIn(_ viewController: RuuviOnboardViewController, - didPresentSignIn sender: Any?) { + func ruuviOnboardCloudSignIn(_: RuuviOnboardViewController, + didPresentSignIn _: Any?) + { output?.ruuviOnboardDidShowSignIn(self) } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift index 46505891f..340b315bd 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift @@ -5,14 +5,14 @@ protocol RuuviOnboardSignInCellDelegate: NSObjectProtocol { } class RuuviOnboardSignInCell: UICollectionViewCell { - weak var delegate: RuuviOnboardSignInCellDelegate? private lazy var beaverImageView: UIImageView = { let iv = UIImageView( image: UIImage.named( - RuuviAssets.beaver_sign_in, - for: Self.self), + RuuviAssets.beaver_sign_in, + for: Self.self + ), contentMode: .scaleAspectFit ) iv.backgroundColor = .clear @@ -54,21 +54,20 @@ class RuuviOnboardSignInCell: UICollectionViewCell { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } } -extension RuuviOnboardSignInCell { - - fileprivate func setUpUI() { - +private extension RuuviOnboardSignInCell { + func setUpUI() { let container = UIView(color: .clear) contentView.addSubview(container) container.fillSuperview() let textStack = UIStackView(arrangedSubviews: [ - titleLabel, subtitleLabel + titleLabel, subtitleLabel, ]) textStack.axis = .vertical textStack.distribution = .fillProportionally @@ -79,7 +78,7 @@ extension RuuviOnboardSignInCell { leading: container.safeLeadingAnchor, bottom: nil, trailing: container.safeTrailingAnchor, - padding: .init(top: 44+12, left: 16, + padding: .init(top: 44 + 12, left: 16, bottom: 0, right: 16)) container.addSubview(continueButton) @@ -104,13 +103,13 @@ extension RuuviOnboardSignInCell { leading: beaverContainerView.safeLeadingAnchor, bottom: nil, trailing: beaverContainerView.safeTrailingAnchor, - size: .init(width: 0, height: self.bounds.height/2)) + size: .init(width: 0, height: bounds.height / 2)) beaverImageView.centerYInSuperview() } } -extension RuuviOnboardSignInCell { - @objc fileprivate func handleContinueTap() { +private extension RuuviOnboardSignInCell { + @objc func handleContinueTap() { delegate?.didTapContinueButton(sender: self) } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardStartCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardStartCell.swift index ad0e53fd3..2b68288fe 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardStartCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardStartCell.swift @@ -1,12 +1,12 @@ import UIKit class RuuviOnboardStartCell: UICollectionViewCell { - private lazy var beaverImageView: UIImageView = { let iv = UIImageView( image: UIImage.named( - RuuviAssets.beaver_start, - for: Self.self), + RuuviAssets.beaver_start, + for: Self.self + ), contentMode: .scaleAspectFit ) iv.backgroundColor = .clear @@ -45,21 +45,20 @@ class RuuviOnboardStartCell: UICollectionViewCell { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } } -extension RuuviOnboardStartCell { - - fileprivate func setUpUI() { - +private extension RuuviOnboardStartCell { + func setUpUI() { let container = UIView(color: .clear) contentView.addSubview(container) container.fillSuperview() let textStack = UIStackView(arrangedSubviews: [ - titleLabel, subtitleLabel, sub_subtitleLabel + titleLabel, subtitleLabel, sub_subtitleLabel, ]) textStack.axis = .vertical textStack.distribution = .fill @@ -70,7 +69,7 @@ extension RuuviOnboardStartCell { leading: container.safeLeadingAnchor, bottom: nil, trailing: container.safeTrailingAnchor, - padding: .init(top: 44+12, left: 16, + padding: .init(top: 44 + 12, left: 16, bottom: 0, right: 16)) let beaverContainerView = UIView(color: .clear) @@ -85,7 +84,7 @@ extension RuuviOnboardStartCell { leading: beaverContainerView.safeLeadingAnchor, bottom: nil, trailing: beaverContainerView.safeTrailingAnchor, - size: .init(width: 0, height: self.bounds.height/2)) + size: .init(width: 0, height: bounds.height / 2)) beaverImageView.centerYInSuperview() } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift index 4740e9823..0ba34bd93 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviUser +import UIKit // swiftlint:disable file_length @@ -27,8 +27,8 @@ struct OnboardViewModel { var title: String var subtitle: String // swiftlint:disable redundant_optional_initialization - var sub_subtitle: String? = nil - var image: String? = nil + var sub_subtitle: String? + var image: String? // swiftlint:enable redundant_optional_initialization } @@ -40,7 +40,8 @@ class RuuviOnboardViewController: UIViewController { super.init(nibName: nil, bundle: nil) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -106,7 +107,6 @@ class RuuviOnboardViewController: UIViewController { } extension RuuviOnboardViewController { - override func viewDidLoad() { super.viewDidLoad() setUpUI() @@ -117,7 +117,6 @@ extension RuuviOnboardViewController { super.viewWillAppear(animated) navigationController?.setNavigationBarHidden(true, animated: false) } - } extension RuuviOnboardViewController { @@ -159,17 +158,20 @@ extension RuuviOnboardViewController { } extension RuuviOnboardViewController: UICollectionViewDataSource { - func collectionView(_ collectionView: UICollectionView, - numberOfItemsInSection section: Int) -> Int { - return viewModels.count + func collectionView(_: UICollectionView, + numberOfItemsInSection _: Int) -> Int + { + viewModels.count } func collectionView(_ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell + { let viewModel = viewModels[indexPath.item] guard let cell = cell(collectionView: collectionView, indexPath: indexPath, - viewModel: viewModel) else { + viewModel: viewModel) + else { fatalError() } @@ -178,7 +180,6 @@ extension RuuviOnboardViewController: UICollectionViewDataSource { } extension RuuviOnboardViewController: UICollectionViewDelegate { - func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { let xPoint = scrollView.contentOffset.x + scrollView.frame.size.width / 2 let yPoint = scrollView.frame.size.height / 2 @@ -192,25 +193,26 @@ extension RuuviOnboardViewController: UICollectionViewDelegate { extension RuuviOnboardViewController: UICollectionViewDelegateFlowLayout { func collectionView( - _ collectionView: UICollectionView, - layout collectionViewLayout: UICollectionViewLayout, - sizeForItemAt indexPath: IndexPath + _: UICollectionView, + layout _: UICollectionViewLayout, + sizeForItemAt _: IndexPath ) -> CGSize { - return CGSize(width: view.bounds.width, height: view.bounds.height) + CGSize(width: view.bounds.width, height: view.bounds.height) } - func collectionView(_ collectionView: UICollectionView, - layout collectionViewLayout: UICollectionViewLayout, - minimumLineSpacingForSectionAt section: Int) -> CGFloat { - return 0 + func collectionView(_: UICollectionView, + layout _: UICollectionViewLayout, + minimumLineSpacingForSectionAt _: Int) -> CGFloat + { + 0 } } extension RuuviOnboardViewController { - private func cell(collectionView: UICollectionView, indexPath: IndexPath, - viewModel: OnboardViewModel) -> UICollectionViewCell? { + viewModel: OnboardViewModel) -> UICollectionViewCell? + { switch viewModel.pageType { case .measure: let cell = collectionView.dequeueReusableCell( @@ -244,13 +246,11 @@ extension RuuviOnboardViewController { default: return UICollectionViewCell() } - } - } extension RuuviOnboardViewController: RuuviOnboardSignInCellDelegate { - func didTapContinueButton(sender: RuuviOnboardSignInCell) { + func didTapContinueButton(sender _: RuuviOnboardSignInCell) { if let authorized = ruuviUser?.isAuthorized, authorized { showDiscoverPage() } else { @@ -307,12 +307,11 @@ extension RuuviOnboardViewController { } } -extension RuuviOnboardViewController { - - fileprivate static func createLayout() -> UICollectionViewLayout { +private extension RuuviOnboardViewController { + static func createLayout() -> UICollectionViewLayout { let sectionProvider = { (_: Int, _: NSCollectionLayoutEnvironment) - -> NSCollectionLayoutSection? in + -> NSCollectionLayoutSection? in let itemSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1) @@ -339,8 +338,7 @@ extension RuuviOnboardViewController { } // swiftlint:disable:next function_body_length - fileprivate func constructOnboardingPages() -> [OnboardViewModel] { - + func constructOnboardingPages() -> [OnboardViewModel] { let meaureItem = OnboardViewModel( pageType: .measure, title: "onboarding_measure_your_world".localized(for: Self.self), @@ -416,7 +414,7 @@ extension RuuviOnboardViewController { shareItem, widgetItem, webItem, - signInItem + signInItem, ] } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift index be1ad1013..ccd444085 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift @@ -1,8 +1,8 @@ import Foundation import UIKit -extension Bundle { - public static func pod(_ clazz: AnyClass) -> Bundle { +public extension Bundle { + static func pod(_ clazz: AnyClass) -> Bundle { if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { if let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), let bundle = Bundle(url: bundleURL) { return bundle @@ -19,12 +19,12 @@ extension Bundle { } } -extension UIImage { - public static func named(_ name: String, for clazz: AnyClass) -> UIImage? { +public extension UIImage { + static func named(_ name: String, for clazz: AnyClass) -> UIImage? { #if SWIFT_PACKAGE - return UIImage(named: name, in: Bundle.module, compatibleWith: nil) + return UIImage(named: name, in: Bundle.module, compatibleWith: nil) #else - return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) + return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) #endif } } @@ -33,16 +33,18 @@ extension String { public func localized(for clazz: AnyClass) -> String { let bundle: Bundle #if SWIFT_PACKAGE - bundle = Bundle.module + bundle = Bundle.module #else - bundle = Bundle.pod(clazz) + bundle = Bundle.pod(clazz) #endif if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), - let bundle = Bundle(path: path) { + let bundle = Bundle(path: path) + { return bundle.localizedString(forKey: self, value: nil, table: module) } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), - let bundle = Bundle(path: path) { + let bundle = Bundle(path: path) + { return bundle.localizedString(forKey: self, value: nil, table: module) } else { assertionFailure() @@ -56,32 +58,32 @@ extension String { private func currentLanguage() -> String { if let preferred = Bundle.main.preferredLocalizations.first { - return preferred + preferred } else { - return "Base" + "Base" } } } -extension UIStoryboard { - public static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { +public extension UIStoryboard { + static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { let bundle: Bundle #if SWIFT_PACKAGE - bundle = Bundle.module + bundle = Bundle.module #else - bundle = Bundle.pod(clazz) + bundle = Bundle.pod(clazz) #endif return UIStoryboard(name: name, bundle: bundle) } } -extension UINib { - public static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { +public extension UINib { + static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { let bundle: Bundle #if SWIFT_PACKAGE - bundle = Bundle.module + bundle = Bundle.module #else - bundle = Bundle.pod(clazz) + bundle = Bundle.pod(clazz) #endif return UINib(nibName: nibName, bundle: bundle) } diff --git a/Modules/RuuviOnboard/Tests/RuuviOnboardTests/RuuviOnboardTests.swift b/Modules/RuuviOnboard/Tests/RuuviOnboardTests/RuuviOnboardTests.swift index 131f52a77..a26a98994 100644 --- a/Modules/RuuviOnboard/Tests/RuuviOnboardTests/RuuviOnboardTests.swift +++ b/Modules/RuuviOnboard/Tests/RuuviOnboardTests/RuuviOnboardTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviOnboard +import XCTest final class RuuviOnboardTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Packages/RuuviAnalytics/Package.swift b/Packages/RuuviAnalytics/Package.swift index 34f1f2d03..aacc57138 100644 --- a/Packages/RuuviAnalytics/Package.swift +++ b/Packages/RuuviAnalytics/Package.swift @@ -9,10 +9,12 @@ let package = Package( products: [ .library( name: "RuuviAnalytics", - targets: ["RuuviAnalytics"]), + targets: ["RuuviAnalytics"] + ), .library( name: "RuuviAnalyticsImpl", - targets: ["RuuviAnalyticsImpl"]) + targets: ["RuuviAnalyticsImpl"] + ), ], dependencies: [ .package(name: "Firebase", url: "https://github.com/firebase/firebase-ios-sdk", .upToNextMajor(from: "10.0.0")), @@ -20,12 +22,13 @@ let package = Package( .package(path: "../RuuviLocal"), .package(path: "../RuuviOntology"), .package(path: "../RuuviUser"), - .package(path: "../RuuviService") + .package(path: "../RuuviService"), ], targets: [ .target( name: "RuuviAnalytics", - dependencies: []), + dependencies: [] + ), .target( name: "RuuviAnalyticsImpl", dependencies: [ @@ -35,10 +38,12 @@ let package = Package( "RuuviStorage", "RuuviOntology", "RuuviUser", - "RuuviService" - ]), + "RuuviService", + ] + ), .testTarget( name: "RuuviAnalyticsTests", - dependencies: ["RuuviAnalytics"]) + dependencies: ["RuuviAnalytics"] + ), ] ) diff --git a/Packages/RuuviAnalytics/Sources/RuuviAnalyticsImpl/RuuviAnalyticsImpl.swift b/Packages/RuuviAnalytics/Sources/RuuviAnalyticsImpl/RuuviAnalyticsImpl.swift index 13d15b369..721dadff7 100644 --- a/Packages/RuuviAnalytics/Sources/RuuviAnalyticsImpl/RuuviAnalyticsImpl.swift +++ b/Packages/RuuviAnalytics/Sources/RuuviAnalyticsImpl/RuuviAnalyticsImpl.swift @@ -1,13 +1,13 @@ import Foundation #if canImport(FirebaseAnalytics) -import FirebaseAnalytics + import FirebaseAnalytics #endif import RuuviAnalytics +import RuuviLocal import RuuviOntology +import RuuviService import RuuviStorage -import RuuviLocal import RuuviUser -import RuuviService public final class RuuviAnalyticsImpl: RuuviAnalytics { private enum Properties { @@ -67,57 +67,57 @@ public final class RuuviAnalyticsImpl: RuuviAnalytics { var name: String { switch self { case .loggedIn: - return "logged_in" + "logged_in" case .addedTags: - return "added_tags" + "added_tags" case .claimedTags: - return "claimed_tags" + "claimed_tags" case .offlineTags: - return "offline_tags" + "offline_tags" case .df2_tags: - return "use_df2" + "use_df2" case .df3_tags: - return "use_df3" + "use_df3" case .df4_tags: - return "use_df4" + "use_df4" case .df5_tags: - return "use_df5" + "use_df5" case .backgroundScanEnabled: - return "background_scan_enabled" + "background_scan_enabled" case .backgroundScanInterval: - return "background_scan_interval" + "background_scan_interval" case .dashboardEnabled: - return "dashboard_enabled" + "dashboard_enabled" case .gatewayEnabled: - return "gateway_enabled" + "gateway_enabled" case .graphDrawDots: - return "graph_draw_dots" + "graph_draw_dots" case .graphPointInterval: - return "graph_point_interval" + "graph_point_interval" case .graphShowAllPoints: - return "graph_show_all_points" + "graph_show_all_points" case .graphViewPeriod: - return "graph_view_period" + "graph_view_period" case .humidityUnit: - return "humidity_unit" + "humidity_unit" case .pressureUnit: - return "pressure_unit" + "pressure_unit" case .temperatureUnit: - return "temperature_unit" + "temperature_unit" case .language: - return "language" + "language" case .useSimpleWidget: - return "use_simple_widget" + "use_simple_widget" case .alertTemperature: - return "alert_temperature" + "alert_temperature" case .alertHumidity: - return "alert_humidity" + "alert_humidity" case .alertPressure: - return "alert_pressure" + "alert_pressure" case .alertMovement: - return "alert_movement" + "alert_movement" case .alertRSSI: - return "alert_rssi" + "alert_rssi" } } } @@ -141,17 +141,18 @@ public final class RuuviAnalyticsImpl: RuuviAnalytics { public func update() { guard let bundleName = Bundle.main.infoDictionary?["CFBundleName"] as? String, - bundleName != "station_dev" else { + bundleName != "station_dev" + else { return } set(.loggedIn(ruuviUser.isAuthorized)) ruuviStorage.readAll().on(success: { tags in // Version 2/3/4 tags isOwner property was set 'false' in iOS app until version v1.1.0 // So we log them first before filtering - let df2_tags_count = tags.filter({ $0.version == 2 }).count - let df3_tags_count = tags.filter({ $0.version == 3 }).count - let df4_tags_count = tags.filter({ $0.version == 4 }).count - let df5_tags_count = tags.filter({ $0.version == 5 }).count + let df2_tags_count = tags.filter { $0.version == 2 }.count + let df3_tags_count = tags.filter { $0.version == 3 }.count + let df4_tags_count = tags.filter { $0.version == 4 }.count + let df5_tags_count = tags.filter { $0.version == 5 }.count self.set(.df2_tags(df2_tags_count)) self.set(.df3_tags(df3_tags_count)) self.set(.df4_tags(df4_tags_count)) @@ -178,7 +179,7 @@ public final class RuuviAnalyticsImpl: RuuviAnalytics { set(.graphDrawDots(settings.chartDrawDotsOn)) set(.graphPointInterval(settings.chartIntervalSeconds / 60)) set(.graphShowAllPoints(!settings.chartDownsamplingOn)) - set(.graphViewPeriod(settings.dataPruningOffsetHours/24)) + set(.graphViewPeriod(settings.dataPruningOffsetHours / 24)) set(.humidityUnit(settings.humidityUnit)) set(.pressureUnit(settings.pressureUnit)) set(.temperatureUnit(settings.temperatureUnit)) @@ -188,121 +189,128 @@ public final class RuuviAnalyticsImpl: RuuviAnalytics { } private func set(_ property: Properties) { - let value: String - switch property { - case .loggedIn(let isLoggedIn): - value = isLoggedIn.description - case .addedTags(let count), - .claimedTags(let count), - .offlineTags(let count), - .df2_tags(let count), - .df3_tags(let count), - .df4_tags(let count), - .df5_tags(let count), - .alertTemperature(let count), - .alertHumidity(let count), - .alertPressure(let count), - .alertMovement(let count), - .alertRSSI(let count): - value = count > 10 ? "10+" : String(count) - case .backgroundScanEnabled(let isEnabled), - .dashboardEnabled(let isEnabled), - .gatewayEnabled(let isEnabled), - .graphDrawDots(let isEnabled), - .graphShowAllPoints(let isEnabled): - value = isEnabled.description - case .backgroundScanInterval(let intValue), - .graphPointInterval(let intValue), - .graphViewPeriod(let intValue): - value = String(intValue) - case .humidityUnit(let unit): - value = unit.analyticsValue - case .pressureUnit(let unit): - value = unit.analyticsValue - case .temperatureUnit(let unit): - value = unit.analyticsValue - case .language(let language): - value = language.rawValue - case .useSimpleWidget(let isUsing): - value = isUsing.description + let value: String = switch property { + case let .loggedIn(isLoggedIn): + isLoggedIn.description + case let .addedTags(count), + let .claimedTags(count), + let .offlineTags(count), + let .df2_tags(count), + let .df3_tags(count), + let .df4_tags(count), + let .df5_tags(count), + let .alertTemperature(count), + let .alertHumidity(count), + let .alertPressure(count), + let .alertMovement(count), + let .alertRSSI(count): + count > 10 ? "10+" : String(count) + case let .backgroundScanEnabled(isEnabled), + let .dashboardEnabled(isEnabled), + let .gatewayEnabled(isEnabled), + let .graphDrawDots(isEnabled), + let .graphShowAllPoints(isEnabled): + isEnabled.description + case let .backgroundScanInterval(intValue), + let .graphPointInterval(intValue), + let .graphViewPeriod(intValue): + String(intValue) + case let .humidityUnit(unit): + unit.analyticsValue + case let .pressureUnit(unit): + unit.analyticsValue + case let .temperatureUnit(unit): + unit.analyticsValue + case let .language(language): + language.rawValue + case let .useSimpleWidget(isUsing): + isUsing.description } #if canImport(FirebaseAnalytics) - Analytics.setUserProperty(value, forName: property.name) + Analytics.setUserProperty(value, forName: property.name) #endif } // swiftlint:disable:next large_tuple private func calculateAlerts(from tags: [RuuviTagSensor]) -> (temperature: Int, - humidity: Int, - pressure: Int, - movementCounter: Int) { - var temperatureAlertCount: Int = 0 - var humidityAlertCount: Int = 0 - var pressureAlertCount: Int = 0 - var movementAlertCount: Int = 0 + humidity: Int, + pressure: Int, + movementCounter: Int) + { + var temperatureAlertCount = 0 + var humidityAlertCount = 0 + var pressureAlertCount = 0 + var movementAlertCount = 0 for tag in tags { if alertService.isOn(type: .temperature(lower: 0, upper: 0), - for: tag) { + for: tag) + { temperatureAlertCount += 1 } if alertService.isOn(type: .relativeHumidity(lower: 0, upper: 0), - for: tag) { + for: tag) + { humidityAlertCount += 1 } if alertService.isOn(type: .pressure(lower: 0, upper: 0), - for: tag) { + for: tag) + { pressureAlertCount += 1 } if alertService.isOn(type: .movement(last: 0), - for: tag) { + for: tag) + { movementAlertCount += 1 } } return (temperatureAlertCount, humidityAlertCount, pressureAlertCount, movementAlertCount) } } -fileprivate extension HumidityUnit { + +private extension HumidityUnit { // Humidity unit (0-relative, 1-absolute, 2-dew point) var analyticsValue: String { switch self { case .percent: - return "0" + "0" case .gm3: - return "1" + "1" case .dew: - return "2" + "2" } } } -fileprivate extension UnitPressure { + +private extension UnitPressure { // Pressure unit (0-pascal, 1-hectopascal, 2-mmHg, 3-inHg) var analyticsValue: String { switch self { case .hectopascals: - return "1" + "1" case .millimetersOfMercury: - return "2" + "2" case .inchesOfMercury: - return "3" + "3" default: - return "-1" + "-1" } } } -fileprivate extension TemperatureUnit { + +private extension TemperatureUnit { // Temperature unit (C-Celsius, F-Fahrenheit, K-Kelvin) var analyticsValue: String { switch self { case .celsius: - return "C" + "C" case .fahrenheit: - return "F" + "F" case .kelvin: - return "K" + "K" } } } diff --git a/Packages/RuuviAnalytics/Tests/RuuviAnalyticsTests/RuuviAnalyticsTests.swift b/Packages/RuuviAnalytics/Tests/RuuviAnalyticsTests/RuuviAnalyticsTests.swift index 89912fa2c..039749935 100644 --- a/Packages/RuuviAnalytics/Tests/RuuviAnalyticsTests/RuuviAnalyticsTests.swift +++ b/Packages/RuuviAnalytics/Tests/RuuviAnalyticsTests/RuuviAnalyticsTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviAnalytics +import XCTest final class RuuviAnalyticsTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Packages/RuuviCloud/Package.swift b/Packages/RuuviCloud/Package.swift index 37789cee2..44ed50d20 100644 --- a/Packages/RuuviCloud/Package.swift +++ b/Packages/RuuviCloud/Package.swift @@ -9,20 +9,23 @@ let package = Package( products: [ .library( name: "RuuviCloud", - targets: ["RuuviCloud"]), + targets: ["RuuviCloud"] + ), .library( name: "RuuviCloudApi", - targets: ["RuuviCloudApi"]), + targets: ["RuuviCloudApi"] + ), .library( name: "RuuviCloudPure", - targets: ["RuuviCloudPure"]) + targets: ["RuuviCloudPure"] + ), ], dependencies: [ .package(url: "https://github.com/kean/Future", .exact("1.3.0")), .package(url: "https://github.com/ruuvi/BTKit", .upToNextMinor(from: "0.4.3")), .package(path: "../RuuviOntology"), .package(path: "../RuuviUser"), - .package(path: "../RuuviPool") + .package(path: "../RuuviPool"), ], targets: [ .target( @@ -31,7 +34,7 @@ let package = Package( "Future", "RuuviOntology", "RuuviPool", - "RuuviUser" + "RuuviUser", ] ), .target( @@ -40,7 +43,7 @@ let package = Package( "RuuviCloud", "RuuviOntology", "Future", - "BTKit" + "BTKit", ] ), .target( @@ -50,11 +53,12 @@ let package = Package( "RuuviCloudApi", "RuuviOntology", "RuuviUser", - "Future" + "Future", ] ), .testTarget( name: "RuuviCloudTests", - dependencies: ["RuuviCloud"]) + dependencies: ["RuuviCloud"] + ), ] ) diff --git a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift index 2a67edc6c..7f57e3f52 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift @@ -1,7 +1,7 @@ import Foundation -import RuuviPool import Future import RuuviOntology +import RuuviPool import RuuviUser public struct ValidateCodeResponse { @@ -56,8 +56,7 @@ public protocol RuuviCloud { measurements: Bool?, sharedToOthers: Bool?, sharedToMe: Bool?, - alerts: Bool? - ) -> Future<[RuuviCloudSensorDense], RuuviCloudError> + alerts: Bool?) -> Future<[RuuviCloudSensorDense], RuuviCloudError> @discardableResult func loadRecords( @@ -203,9 +202,10 @@ public protocol RuuviCloud { func loadAlerts() -> Future<[RuuviCloudSensorAlerts], RuuviCloudError> // MARK: Queued requests + @discardableResult func executeQueuedRequest(from request: RuuviCloudQueuedRequest) - -> Future + -> Future } public protocol RuuviCloudFactory { diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/Helpers/Reachability.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/Helpers/Reachability.swift index e20073155..c3774c71f 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/Helpers/Reachability.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/Helpers/Reachability.swift @@ -1,7 +1,6 @@ import Network -struct Reachability { - +enum Reachability { private static let monitor = NWPathMonitor() static var active = false @@ -13,8 +12,8 @@ struct Reachability { guard monitor.pathUpdateHandler == nil else { return } monitor.pathUpdateHandler = { update in - Self.active = update.status == .satisfied ? true : false - Self.expensive = update.isExpensive ? true : false + active = update.status == .satisfied ? true : false + expensive = update.isExpensive ? true : false } monitor.start(queue: DispatchQueue(label: "InternetMonitor")) diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/RuuviCloudApi.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/RuuviCloudApi.swift index 3607a95ff..17eb27ef1 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/RuuviCloudApi.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/RuuviCloudApi.swift @@ -1,8 +1,8 @@ +import BTKit import Foundation import Future -import BTKit -import RuuviOntology import RuuviCloud +import RuuviOntology /// https://docs.ruuvi.com/communication/ruuvi-network/backends/serverless/user-api public protocol RuuviCloudApi { diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudApiGetSensorsDenseRequest.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudApiGetSensorsDenseRequest.swift index f33959f43..0cf0113da 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudApiGetSensorsDenseRequest.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudApiGetSensorsDenseRequest.swift @@ -11,7 +11,8 @@ public struct RuuviCloudApiGetSensorsDenseRequest: Encodable { measurements: Bool?, sharedToMe: Bool?, sharedToOthers: Bool?, - alerts: Bool?) { + alerts: Bool?) + { self.sensor = sensor self.measurements = measurements self.sharedToMe = sharedToMe diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudApiUserRequest.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudApiUserRequest.swift index 54327fd61..62c49f4ec 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudApiUserRequest.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudApiUserRequest.swift @@ -1,4 +1,3 @@ import Foundation -public struct RuuviCloudApiUserRequest: Encodable { -} +public struct RuuviCloudApiUserRequest: Encodable {} diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenRegisterRequest.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenRegisterRequest.swift index 56bbb7bcf..69e9ccfe7 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenRegisterRequest.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenRegisterRequest.swift @@ -3,7 +3,7 @@ import Foundation // swiftlint:disable:next type_name public enum RuuviCloudPNTokenRegisterRequestParamsKey: String { case sound = "soundFile" - case language = "language" + case language } public struct RuuviCloudPNTokenRegisterRequest: Encodable { @@ -17,7 +17,8 @@ public struct RuuviCloudPNTokenRegisterRequest: Encodable { type: String, name: String? = nil, data: String? = nil, - params: [String: String]? = nil) { + params: [String: String]? = nil) + { self.token = token self.type = type self.name = name diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenUnregisterRequest.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenUnregisterRequest.swift index e0fa273c4..804c3b0a0 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenUnregisterRequest.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenUnregisterRequest.swift @@ -3,7 +3,7 @@ import Foundation public struct RuuviCloudPNTokenUnregisterRequest: Encodable { let token: String? let id: Int? - + public init(token: String?, id: Int?) { self.token = token self.id = id diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/Upload/RuuviCloudApiSensorImageUploadRequest.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/Upload/RuuviCloudApiSensorImageUploadRequest.swift index 698d655af..af4aa7563 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/Upload/RuuviCloudApiSensorImageUploadRequest.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/Upload/RuuviCloudApiSensorImageUploadRequest.swift @@ -12,7 +12,7 @@ public struct RuuviCloudApiSensorImageUploadRequest: UserApiUploadRequest { ) { self.sensor = sensor self.action = action - self.mimeType = nil + mimeType = nil } public init( diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiBaseResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiBaseResponse.swift index 5ce820977..3e34b5003 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiBaseResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiBaseResponse.swift @@ -6,6 +6,7 @@ public struct RuuviCloudApiBaseResponse: Decodable where T: Decodable { case success case error } + private let status: Status private let data: T? private let errorDescription: String? @@ -21,11 +22,11 @@ public struct RuuviCloudApiBaseResponse: Decodable where T: Decodable { } } -extension RuuviCloudApiBaseResponse { - public var result: Swift.Result { +public extension RuuviCloudApiBaseResponse { + var result: Swift.Result { switch status { case .success: - guard let data = data else { + guard let data else { if let emptyModel = T.emptyModel { return .success(emptyModel) } else { @@ -34,7 +35,7 @@ extension RuuviCloudApiBaseResponse { } return .success(data) case .error: - guard let code = code else { + guard let code else { if errorDescription != nil { return .failure(.api(.erInternal)) } else { @@ -51,11 +52,12 @@ extension RuuviCloudApiBaseResponse { } } -extension Decodable { - public static var emptyModel: Self? { +public extension Decodable { + static var emptyModel: Self? { let emptyString = "{}" if let emptyData = emptyString.data(using: .utf8), - let emptyModel = try? JSONDecoder().decode(self, from: emptyData) { + let emptyModel = try? JSONDecoder().decode(self, from: emptyData) + { return emptyModel } else { return nil diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiClaimResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiClaimResponse.swift index e3c609963..7f19ae8a2 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiClaimResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiClaimResponse.swift @@ -3,5 +3,5 @@ import Foundation public struct RuuviCloudApiClaimResponse: Decodable { public let sensor: String? } -public struct RuuviCloudApiUnclaimResponse: Decodable { -} + +public struct RuuviCloudApiUnclaimResponse: Decodable {} diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetAlertsResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetAlertsResponse.swift index f3bc98850..99edc542b 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetAlertsResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetAlertsResponse.swift @@ -10,7 +10,7 @@ public struct RuuviCloudApiGetAlertSensor: Decodable, RuuviCloudSensorAlerts { public let apiAlerts: [RuuviCloudApiGetAlert]? public var alerts: [RuuviCloudAlert]? { - return apiAlerts + apiAlerts } enum CodingKeys: String, CodingKey { @@ -38,10 +38,11 @@ public struct RuuviCloudApiGetAlert: Decodable, RuuviCloudAlert { let container = try decoder.container(keyedBy: CodingKeys.self) if let typeString = try? container.decode(String.self, forKey: .type), - let type = RuuviCloudAlertType(rawValue: typeString) { + let type = RuuviCloudAlertType(rawValue: typeString) + { self.type = type } else { - self.type = nil + type = nil } enabled = try container.decode(Bool.self, forKey: .enabled) @@ -53,7 +54,7 @@ public struct RuuviCloudApiGetAlert: Decodable, RuuviCloudAlert { if let delay = try? container.decode(Int.self, forKey: .delay) { self.delay = delay } else { - self.delay = nil + delay = nil } triggered = try container.decode(Bool.self, forKey: .triggered) diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSensorResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSensorResponse.swift index 8fd560d56..da3feb9ee 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSensorResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSensorResponse.swift @@ -15,9 +15,9 @@ public struct UserApiSensorRecord: Decodable { public let data: String? } -extension UserApiSensorRecord { - public var date: Date { - guard let timestamp = timestamp else { +public extension UserApiSensorRecord { + var date: Date { + guard let timestamp else { return Date() } return Date(timeIntervalSince1970: timestamp) diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSensorsDenseResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSensorsDenseResponse.swift index 09b5e3f9a..23f5d0023 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSensorsDenseResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSensorsDenseResponse.swift @@ -36,11 +36,11 @@ public struct RuuviCloudApiGetSensorsDenseResponse: Decodable { } public var lastMeasurement: UserApiSensorRecord? { - return measurements?.first + measurements?.first } public var alerts: RuuviCloudSensorAlerts { - return RuuviCloudApiGetAlertSensor( + RuuviCloudApiGetAlertSensor( sensor: sensor, apiAlerts: apiAlerts ?? [] ) } diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSensorsResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSensorsResponse.swift index 081c505c5..fdd428424 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSensorsResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSensorsResponse.swift @@ -22,7 +22,7 @@ public struct RuuviCloudApiGetSensorsResponse: Decodable { } public var shareableSensor: ShareableSensor { - return ShareableSensorStruct( + ShareableSensorStruct( id: sensor, canShare: canShare ?? false, sharedTo: sharedTo ?? [] diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSettingsResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSettingsResponse.swift index 73aa60377..7fbdcab0f 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSettingsResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSettingsResponse.swift @@ -1,6 +1,6 @@ import Foundation -import RuuviOntology import Humidity +import RuuviOntology public struct RuuviCloudApiGetSettingsResponse: Decodable { public let settings: RuuviCloudApiSettings? @@ -8,55 +8,71 @@ public struct RuuviCloudApiGetSettingsResponse: Decodable { public struct RuuviCloudApiSettings: Decodable, RuuviCloudSettings { public var unitTemperature: TemperatureUnit? { - return unitTemperatureString?.ruuviCloudApiSettingUnitTemperature + unitTemperatureString?.ruuviCloudApiSettingUnitTemperature } + public var accuracyTemperature: MeasurementAccuracyType? { - return accuracyTemperatureString?.ruuviCloudApiSettingsMeasurementAccuracyUnit + accuracyTemperatureString?.ruuviCloudApiSettingsMeasurementAccuracyUnit } + public var unitHumidity: HumidityUnit? { - return unitHumidityString?.ruuviCloudApiSettingUnitHumidity + unitHumidityString?.ruuviCloudApiSettingUnitHumidity } + public var accuracyHumidity: MeasurementAccuracyType? { - return accuracyHumidityString?.ruuviCloudApiSettingsMeasurementAccuracyUnit + accuracyHumidityString?.ruuviCloudApiSettingsMeasurementAccuracyUnit } + public var unitPressure: UnitPressure? { - return unitPressureString?.ruuviCloudApiSettingUnitPressure + unitPressureString?.ruuviCloudApiSettingUnitPressure } + public var accuracyPressure: MeasurementAccuracyType? { - return accuracyPressureString?.ruuviCloudApiSettingsMeasurementAccuracyUnit + accuracyPressureString?.ruuviCloudApiSettingsMeasurementAccuracyUnit } + public var chartShowAllPoints: Bool? { - return chartShowAllPointsString?.ruuviCloudApiSettingBoolean + chartShowAllPointsString?.ruuviCloudApiSettingBoolean } + public var chartDrawDots: Bool? { - return chartDrawDotsString?.ruuviCloudApiSettingBoolean + chartDrawDotsString?.ruuviCloudApiSettingBoolean } + public var chartViewPeriod: Int? { - return chartViewPeriodString?.ruuviCloudApiSettingChartViewPeriod + chartViewPeriodString?.ruuviCloudApiSettingChartViewPeriod } + public var chartShowMinMaxAvg: Bool? { - return chartShowMinMaxAverageString?.ruuviCloudApiSettingBoolean + chartShowMinMaxAverageString?.ruuviCloudApiSettingBoolean } + public var cloudModeEnabled: Bool? { - return cloudModeEnabledString?.ruuviCloudApiSettingBoolean + cloudModeEnabledString?.ruuviCloudApiSettingBoolean } + public var dashboardEnabled: Bool? { - return dashboardEnabledString?.ruuviCloudApiSettingBoolean + dashboardEnabledString?.ruuviCloudApiSettingBoolean } + public var dashboardType: DashboardType? { - return dashboardTypeString?.ruuviCloudApiSettingsDashboardType + dashboardTypeString?.ruuviCloudApiSettingsDashboardType } + public var dashboardTapActionType: DashboardTapActionType? { - return dashboardTapActionTypeString?.ruuviCloudApiSettingsDashboardTapActionType + dashboardTapActionTypeString?.ruuviCloudApiSettingsDashboardTapActionType } + public var pushAlertEnabled: Bool? { - return pushAlertEnabledString?.ruuviCloudApiSettingBoolean + pushAlertEnabledString?.ruuviCloudApiSettingBoolean } + public var emailAlertEnabled: Bool? { - return emailAlertEnabledString?.ruuviCloudApiSettingBoolean + emailAlertEnabledString?.ruuviCloudApiSettingBoolean } + public var profileLanguageCode: String? { - return profileLanguageCodeString + profileLanguageCodeString } var unitTemperatureString: String? diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiUserResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiUserResponse.swift index 07b54a89f..cb8c295bf 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiUserResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiUserResponse.swift @@ -31,56 +31,61 @@ public struct RuuviCloudApiSensor: Decodable { extension RuuviCloudApiSensor: CloudSensor { public var offsetTemperature: Double? { - return temperatureOffset + temperatureOffset } + // on cloud in percent, locally in fraction of one public var offsetHumidity: Double? { - if let humidityOffset = humidityOffset { - return humidityOffset / 100.0 + if let humidityOffset { + humidityOffset / 100.0 } else { - return nil + nil } } + // on cloud in Pa, locally in hPa public var offsetPressure: Double? { - if let pressureOffset = pressureOffset { - return pressureOffset / 100.0 + if let pressureOffset { + pressureOffset / 100.0 } else { - return nil + nil } } + /// Returns the background image of the sensor public var picture: URL? { - return URL(string: pictureUrl) + URL(string: pictureUrl) } + /// Returns the email address of the owner of a sensor public var owner: String? { - return sensorOwner + sensorOwner } public var ownersPlan: String? { - return nil + nil } /// Returns status of sensor whether it is already claimed public var isClaimed: Bool { - return isOwner + isOwner } + /// Returns always true since this is a property of sensors returns from the cloud public var isCloudSensor: Bool? { - return true + true } public var canShare: Bool { - return false + false } public var sharedTo: [String] { - return [] + [] } /// Returns the 'id' of the sensor public var id: String { - return sensorId + sensorId } } diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudPNTokenListResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudPNTokenListResponse.swift index d0d9c89ab..f09546ba1 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudPNTokenListResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudPNTokenListResponse.swift @@ -11,15 +11,15 @@ public struct RuuviCloudPNTokenListResponse: Decodable { } public var anyTokens: [RuuviCloudPNToken] { - guard let tokens = tokens else { + guard let tokens else { return [] } - return tokens.map({ + return tokens.map { RuuviCloudPNTokenStruct( id: $0.id, lastAccessed: $0.lastAccessed, name: $0.name ) - }) + } } } diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Settings/RuuviCloudApiSettings.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Settings/RuuviCloudApiSettings.swift index 8c9768f5e..ad1b89aec 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Settings/RuuviCloudApiSettings.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Settings/RuuviCloudApiSettings.swift @@ -21,34 +21,34 @@ public enum RuuviCloudApiSetting: String, CaseIterable, Codable { case profileLanguageCode = "PROFILE_LANGUAGE_CODE" } -extension TemperatureUnit { - public var ruuviCloudApiSettingString: String { +public extension TemperatureUnit { + var ruuviCloudApiSettingString: String { switch self { case .celsius: - return "C" + "C" case .fahrenheit: - return "F" + "F" case .kelvin: - return "K" + "K" } } } -extension HumidityUnit { - public var ruuviCloudApiSettingString: String { +public extension HumidityUnit { + var ruuviCloudApiSettingString: String { switch self { case .percent: - return "0" + "0" case .gm3: - return "1" + "1" case .dew: - return "2" + "2" } } } -extension UnitPressure { - public var ruuviCloudApiSettingString: String { +public extension UnitPressure { + var ruuviCloudApiSettingString: String { switch self { case .hectopascals: return "1" @@ -63,109 +63,109 @@ extension UnitPressure { } } -extension Int { - public var ruuviCloudApiSettingString: String { - return String(self) +public extension Int { + var ruuviCloudApiSettingString: String { + String(self) } } -extension Bool { - public var chartBoolSettingString: String { - return self ? "true" : "false" +public extension Bool { + var chartBoolSettingString: String { + self ? "true" : "false" } } -extension String { - public var ruuviCloudApiSettingUnitTemperature: TemperatureUnit? { +public extension String { + var ruuviCloudApiSettingUnitTemperature: TemperatureUnit? { switch self { case "C": - return .celsius + .celsius case "F": - return .fahrenheit + .fahrenheit case "K": - return .kelvin + .kelvin default: - return nil + nil } } - public var ruuviCloudApiSettingUnitHumidity: HumidityUnit? { + var ruuviCloudApiSettingUnitHumidity: HumidityUnit? { switch self { case "0": - return .percent + .percent case "1": - return .gm3 + .gm3 case "2": - return .dew + .dew default: - return nil + nil } } - public var ruuviCloudApiSettingUnitPressure: UnitPressure? { + var ruuviCloudApiSettingUnitPressure: UnitPressure? { switch self { case "0": // v2.0 -> iOS doesn't support Pa. Instead when Pa // is received from sync we set hPa on iOS. - return .hectopascals + .hectopascals case "1": - return .hectopascals + .hectopascals case "2": - return .millimetersOfMercury + .millimetersOfMercury case "3": - return .inchesOfMercury + .inchesOfMercury default: - return nil + nil } } - public var ruuviCloudApiSettingBoolean: Bool? { + var ruuviCloudApiSettingBoolean: Bool? { switch self { case "true": - return true + true case "false": - return false + false default: - return nil + nil } } - public var ruuviCloudApiSettingChartViewPeriod: Int? { - return Int(self) + var ruuviCloudApiSettingChartViewPeriod: Int? { + Int(self) } - public var ruuviCloudApiSettingsMeasurementAccuracyUnit: MeasurementAccuracyType { + var ruuviCloudApiSettingsMeasurementAccuracyUnit: MeasurementAccuracyType { switch self { case "0": - return .zero + .zero case "1": - return .one + .one case "2": - return .two + .two default: - return .two + .two } } - public var ruuviCloudApiSettingsDashboardType: DashboardType { + var ruuviCloudApiSettingsDashboardType: DashboardType { switch self { case "image": - return .image + .image case "simple": - return .simple + .simple default: - return .image + .image } } - public var ruuviCloudApiSettingsDashboardTapActionType: DashboardTapActionType { + var ruuviCloudApiSettingsDashboardTapActionType: DashboardTapActionType { switch self { case "card": - return .card + .card case "chart": - return .chart + .chart default: - return .card + .card } } } diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiFactoryURLSession.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiFactoryURLSession.swift index 6fe92591d..bedd4e32b 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiFactoryURLSession.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiFactoryURLSession.swift @@ -2,6 +2,6 @@ import Foundation final class RuuviCloudApiFactoryURLSession: RuuviCloudApiFactory { func create(baseUrl: URL) -> RuuviCloudApi { - return RuuviCloudApiURLSession(baseUrl: baseUrl) + RuuviCloudApiURLSession(baseUrl: baseUrl) } } diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiURLSession.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiURLSession.swift index 1b2d9478d..dcf4744be 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiURLSession.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiURLSession.swift @@ -41,6 +41,7 @@ public final class RuuviCloudApiURLSession: NSObject, RuuviCloudApi { delegateQueue: .main ) }() + private var progressHandlersByTaskID = [Int: ProgressHandler]() private let baseUrl: URL @@ -52,135 +53,136 @@ public final class RuuviCloudApiURLSession: NSObject, RuuviCloudApi { public func register( _ requestModel: RuuviCloudApiRegisterRequest ) -> Future { - return request(endpoint: Routes.register, - with: requestModel, - method: .post) + request(endpoint: Routes.register, + with: requestModel, + method: .post) } public func verify( _ requestModel: RuuviCloudApiVerifyRequest ) -> Future { - return request(endpoint: Routes.verify, - with: requestModel) + request(endpoint: Routes.verify, + with: requestModel) } public func deleteAccount(_ requestModel: RuuviCloudApiAccountDeleteRequest, authorization: String) -> - Future { - return request(endpoint: Routes.deleteAccount, - with: requestModel, - method: .post, - authorization: authorization) + Future + { + request(endpoint: Routes.deleteAccount, + with: requestModel, + method: .post, + authorization: authorization) } public func registerPNToken( _ requestModel: RuuviCloudPNTokenRegisterRequest, authorization: String ) -> Future { - return request(endpoint: Routes.registerPNToken, - with: requestModel, - method: .post, - authorization: authorization) + request(endpoint: Routes.registerPNToken, + with: requestModel, + method: .post, + authorization: authorization) } public func unregisterPNToken( _ requestModel: RuuviCloudPNTokenUnregisterRequest, authorization: String? ) -> Future { - return request(endpoint: Routes.unregisterPNToken, - with: requestModel, - method: .post, - authorization: authorization) + request(endpoint: Routes.unregisterPNToken, + with: requestModel, + method: .post, + authorization: authorization) } public func listPNTokens( _ requestModel: RuuviCloudPNTokenListRequest, authorization: String ) -> Future { - return request(endpoint: Routes.PNTokens, - with: requestModel, - method: .get, - authorization: authorization) + request(endpoint: Routes.PNTokens, + with: requestModel, + method: .get, + authorization: authorization) } public func claim( _ requestModel: RuuviCloudApiClaimRequest, authorization: String ) -> Future { - return request(endpoint: Routes.claim, - with: requestModel, - method: .post, - authorization: authorization) + request(endpoint: Routes.claim, + with: requestModel, + method: .post, + authorization: authorization) } public func contest( _ requestModel: RuuviCloudApiContestRequest, authorization: String ) -> Future { - return request(endpoint: Routes.contest, - with: requestModel, - method: .post, - authorization: authorization) + request(endpoint: Routes.contest, + with: requestModel, + method: .post, + authorization: authorization) } public func unclaim( _ requestModel: RuuviCloudApiUnclaimRequest, authorization: String ) -> Future { - return request(endpoint: Routes.unclaim, - with: requestModel, - method: .post, - authorization: authorization) + request(endpoint: Routes.unclaim, + with: requestModel, + method: .post, + authorization: authorization) } public func share( _ requestModel: RuuviCloudApiShareRequest, authorization: String ) -> Future { - return request(endpoint: Routes.share, - with: requestModel, - method: .post, - authorization: authorization) + request(endpoint: Routes.share, + with: requestModel, + method: .post, + authorization: authorization) } public func unshare( _ requestModel: RuuviCloudApiShareRequest, authorization: String ) -> Future { - return request(endpoint: Routes.unshare, - with: requestModel, - method: .post, - authorization: authorization) + request(endpoint: Routes.unshare, + with: requestModel, + method: .post, + authorization: authorization) } public func sensors( _ requestModel: RuuviCloudApiGetSensorsRequest, authorization: String ) -> Future { - return request(endpoint: Routes.sensors, - with: requestModel, - method: .get, - authorization: authorization) + request(endpoint: Routes.sensors, + with: requestModel, + method: .get, + authorization: authorization) } public func owner( _ requestModel: RuuviCloudApiGetSensorsRequest, authorization: String ) -> Future { - return request(endpoint: Routes.check, - with: requestModel, - method: .get, - authorization: authorization) + request(endpoint: Routes.check, + with: requestModel, + method: .get, + authorization: authorization) } public func sensorsDense( _ requestModel: RuuviCloudApiGetSensorsDenseRequest, authorization: String ) -> Future { - return request(endpoint: Routes.sensorsDense, - with: requestModel, - method: .get, - authorization: authorization) + request(endpoint: Routes.sensorsDense, + with: requestModel, + method: .get, + authorization: authorization) } public func user(authorization: String) -> Future { @@ -194,17 +196,17 @@ public final class RuuviCloudApiURLSession: NSObject, RuuviCloudApi { _ requestModel: RuuviCloudApiGetSensorRequest, authorization: String ) -> Future { - return request(endpoint: Routes.getSensorData, - with: requestModel, - method: .get, - authorization: authorization) + request(endpoint: Routes.getSensorData, + with: requestModel, + method: .get, + authorization: authorization) } public func update( _ requestModel: RuuviCloudApiSensorUpdateRequest, authorization: String ) -> Future { - return request( + request( endpoint: Routes.update, with: requestModel, method: .post, @@ -216,7 +218,7 @@ public final class RuuviCloudApiURLSession: NSObject, RuuviCloudApi { _ requestModel: RuuviCloudApiSensorImageUploadRequest, authorization: String ) -> Future { - return request( + request( endpoint: Routes.uploadImage, with: requestModel, method: .post, @@ -228,7 +230,7 @@ public final class RuuviCloudApiURLSession: NSObject, RuuviCloudApi { _ requestModel: RuuviCloudApiGetSettingsRequest, authorization: String ) -> Future { - return request( + request( endpoint: Routes.settings, with: requestModel, method: .get, @@ -240,7 +242,7 @@ public final class RuuviCloudApiURLSession: NSObject, RuuviCloudApi { _ requestModel: RuuviCloudApiPostSettingRequest, authorization: String ) -> Future { - return request( + request( endpoint: Routes.settings, with: requestModel, method: .post, @@ -252,7 +254,7 @@ public final class RuuviCloudApiURLSession: NSObject, RuuviCloudApi { _ requestModel: RuuviCloudApiPostAlertRequest, authorization: String ) -> Future { - return request( + request( endpoint: Routes.alerts, with: requestModel, method: .post, @@ -264,7 +266,7 @@ public final class RuuviCloudApiURLSession: NSObject, RuuviCloudApi { _ requestModel: RuuviCloudApiGetAlertsRequest, authorization: String ) -> Future { - return request( + request( endpoint: Routes.alerts, with: requestModel, method: .get, @@ -287,14 +289,14 @@ public final class RuuviCloudApiURLSession: NSObject, RuuviCloudApi { let url = response.uploadURL self?.upload(url: url, with: imageData, mimeType: .jpg, progress: { percentage in #if DEBUG - debugPrint(percentage) + debugPrint(percentage) #endif uploadProgress?(percentage) }, completion: { result in switch result { case .success: promise.succeed(value: response) - case .failure(let error): + case let .failure(error): promise.fail(error: error) } }) @@ -306,11 +308,12 @@ public final class RuuviCloudApiURLSession: NSObject, RuuviCloudApi { } // MARK: - Private + extension RuuviCloudApiURLSession { // swiftlint:disable:next function_body_length cyclomatic_complexity - private func request( + private func request( endpoint: Routes, - with model: Request, + with model: some Encodable, method: HttpMethod = .get, authorization: String? = nil ) -> Future { @@ -319,7 +322,7 @@ extension RuuviCloudApiURLSession { promise.fail(error: .connection) return promise.future } - var url: URL = self.baseUrl.appendingPathComponent(endpoint.rawValue) + var url: URL = baseUrl.appendingPathComponent(endpoint.rawValue) if method == .get { var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true) urlComponents?.queryItems = try? URLQueryItemEncoder().encode(model) @@ -333,18 +336,18 @@ extension RuuviCloudApiURLSession { if method != .get { request.httpBody = try? JSONEncoder().encode(model) } - if let authorization = authorization { + if let authorization { request.setValue(authorization, forHTTPHeaderField: "Authorization") } request.setValue("application/json", forHTTPHeaderField: "Content-Type") if let buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String { #if DEBUG - request.setValue("Station_iOS_Debug/Build_\(buildNumber)/\(endpoint.rawValue)", - forHTTPHeaderField: "User-Agent") + request.setValue("Station_iOS_Debug/Build_\(buildNumber)/\(endpoint.rawValue)", + forHTTPHeaderField: "User-Agent") #else - request.setValue("Station_iOS/Build_\(buildNumber)/\(endpoint.rawValue)", - forHTTPHeaderField: "User-Agent") + request.setValue("Station_iOS/Build_\(buildNumber)/\(endpoint.rawValue)", + forHTTPHeaderField: "User-Agent") #endif } @@ -353,30 +356,31 @@ extension RuuviCloudApiURLSession { config.waitsForConnectivity = true config.timeoutIntervalForResource = 30 } - let task = URLSession(configuration: config).dataTask(with: request) { (data, _, error) in - if let error = error { + let task = URLSession(configuration: config).dataTask(with: request) { data, _, error in + if let error { promise.fail(error: .networking(error)) } else { - if let data = data { + if let data { #if DEBUG - if let object = try? JSONSerialization.jsonObject(with: data, options: []), - let jsonData = try? JSONSerialization.data(withJSONObject: object, options: [.prettyPrinted]), - let prettyPrintedString = NSString(data: jsonData, encoding: String.Encoding.utf8.rawValue) { - debugPrint("📬 Response of request", dump(request), prettyPrintedString) - } + if let object = try? JSONSerialization.jsonObject(with: data, options: []), + let jsonData = try? JSONSerialization.data(withJSONObject: object, options: [.prettyPrinted]), + let prettyPrintedString = NSString(data: jsonData, encoding: String.Encoding.utf8.rawValue) + { + debugPrint("📬 Response of request", dump(request), prettyPrintedString) + } #endif let decoder = JSONDecoder() do { let baseResponse = try decoder.decode(RuuviCloudApiBaseResponse.self, from: data) switch baseResponse.result { - case .success(let model): + case let .success(model): promise.succeed(value: model) - case .failure(let userApiError): + case let .failure(userApiError): promise.fail(error: userApiError) } - } catch let error { + } catch { #if DEBUG - debugPrint("❌ Parsing Error", dump(error)) + debugPrint("❌ Parsing Error", dump(error)) #endif promise.fail(error: .parsing(error)) } @@ -410,11 +414,11 @@ extension RuuviCloudApiURLSession { with: request, from: data, completionHandler: { data, response, error in - if let error = error { + if let error { completion(.failure(.networking(error))) } else if (response as? HTTPURLResponse)?.statusCode != 200 { completion(.failure(.unexpectedHTTPStatusCode)) - } else if let data = data { + } else if let data { completion(.success(data)) } else { completion(.failure(.failedToGetDataFromResponse)) @@ -428,9 +432,9 @@ extension RuuviCloudApiURLSession { extension RuuviCloudApiURLSession: URLSessionTaskDelegate { public func urlSession( - _ session: URLSession, + _: URLSession, task: URLSessionTask, - didSendBodyData bytesSent: Int64, + didSendBodyData _: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64 ) { diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/ThirdParty/URLQueryItemEncoder.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/ThirdParty/URLQueryItemEncoder.swift index cdba6406e..f83f68ec9 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/ThirdParty/URLQueryItemEncoder.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/ThirdParty/URLQueryItemEncoder.swift @@ -10,7 +10,7 @@ import Foundation protocol URLQueryItemEncoderDateFormatter { - func string(from date: Date) -> String + func string(from date: Date) -> String } extension DateFormatter: URLQueryItemEncoderDateFormatter {} @@ -18,489 +18,491 @@ extension DateFormatter: URLQueryItemEncoderDateFormatter {} extension ISO8601DateFormatter: URLQueryItemEncoderDateFormatter {} let iso8601Formatter: URLQueryItemEncoderDateFormatter = { - #if os(Linux) - let formatter = DateFormatter() - formatter.locale = Locale(identifier: "en_US_POSIX") - formatter.timeZone = TimeZone(identifier: "UTC")! - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" - return formatter - #else - if #available(iOS 11.0, macOS 10.13, *) { - var formatter = ISO8601DateFormatter() - formatter.formatOptions.formUnion([.withFractionalSeconds]) - return formatter - } else { - let formatter = DateFormatter() - formatter.locale = Locale(identifier: "en_US_POSIX") - formatter.timeZone = TimeZone(identifier: "UTC")! - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" - return formatter - } - #endif + #if os(Linux) + let formatter = DateFormatter() + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.timeZone = TimeZone(identifier: "UTC")! + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" + return formatter + #else + if #available(iOS 11.0, macOS 10.13, *) { + var formatter = ISO8601DateFormatter() + formatter.formatOptions.formUnion([.withFractionalSeconds]) + return formatter + } else { + let formatter = DateFormatter() + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.timeZone = TimeZone(identifier: "UTC")! + formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" + return formatter + } + #endif }() /// `URLQueryItemEncoder` facilitates the encoding of `Encodable` values into URLQueryItems. public class URLQueryItemEncoder { - - /// The strategy to use for encoding array indexes. - public enum ArrayIndexEncodingStrategy { - /// Encode any array index as an empty square brackets `[]` - case emptySquareBrackets - /// Encode an array index as index number - case index - } - - fileprivate(set) public var codingPath: [CodingKey] = [] - fileprivate var items: [URLQueryItem] = [] - - /// The strategy to use in encoding array indexes. Defaults to `.emptySquareBrackets`. - public var arrayIndexEncodingStrategy = ArrayIndexEncodingStrategy.emptySquareBrackets - public init() {} - - /// Encodes the given top-level value and returns an array of its URLQueryItem representation. - /// - /// - parameter value: The value to encode. - /// - returns: An array of `URLQueryItem` containing the encoded query item data. - /// - throws: An error if any value throws an error during encoding. - public func encode(_ value: Encodable) throws -> [URLQueryItem] { - items = [] - try value.encode(to: self) - return items - } - - private static let formURLEncodedAllowedCharacters: CharacterSet = { - var characters = CharacterSet.urlQueryAllowed - characters.remove(charactersIn: ":#[]@?/!$&'()*+,;=") - return characters - }() - - /// Encodes the given array of `URLQueryItem` and returns an x-www-urlencoded compatible Data representation. - /// - /// - Parameter queryItems: The URLQueryItems to encode - /// - Returns: A data represents the encoded with an x-www-urlencoded compatible representation - public static func encodeToFormURLEncodedData(queryItems: [URLQueryItem]) -> Data { - var components = URLComponents() - components.queryItems = queryItems.map({ - URLQueryItem( - name: $0.name.addingPercentEncoding( - withAllowedCharacters: URLQueryItemEncoder.formURLEncodedAllowedCharacters - ) ?? $0.name, - value: $0.value?.addingPercentEncoding( - withAllowedCharacters: URLQueryItemEncoder.formURLEncodedAllowedCharacters - ) - ) - }) - - return components.query!.data(using: .utf8)! - } -} - -extension Array where Element == CodingKey { - fileprivate func queryItemKeyForKey(_ key: CodingKey) -> String { - let keysPath = self + [key] - return keysPath.queryItemKey - } - - fileprivate var queryItemKey: String { - guard !isEmpty else { return "" } - var keysPath = self - let firstKey = keysPath.removeFirst() - let tailCodingKeyString = keysPath.reduce(into: "", { - $0 += "[\($1.stringValue)]" - }) - - return firstKey.stringValue + tailCodingKeyString - } -} - -private struct URLQueryItemArrayElementKey: CodingKey { - let encodingStrategy: URLQueryItemEncoder.ArrayIndexEncodingStrategy - - fileprivate var stringValue: String { - switch encodingStrategy { - case .emptySquareBrackets: - return "" - case .index: - return String(index) - } - } - - fileprivate init(index: Int, encodingStrategy: URLQueryItemEncoder.ArrayIndexEncodingStrategy) { - self.index = index - self.encodingStrategy = encodingStrategy - } - - init?(stringValue: String) { - guard let index = Int(stringValue) else { return nil } - self.index = index - encodingStrategy = .index - } - let index: Int - var intValue: Int? { - return index - } - init?(intValue: Int) { - self.index = intValue - encodingStrategy = .index - } -} - -extension URLQueryItemEncoder { - private func pushNil(forKey codingPath: [CodingKey]) throws { - items.append(URLQueryItem(name: codingPath.queryItemKey, value: nil)) - } - - private func push(_ value: DateComponents, forKey codingPath: [CodingKey]) throws { - guard (value.calendar?.identifier ?? Calendar.current.identifier) == .gregorian, - let year = value.year, let month = value.month, let day = value.day else { - throw DecodingError.dataCorrupted( - DecodingError.Context(codingPath: codingPath, debugDescription: "Invalid date components") - ) - } - - items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(year)-\(month)-\(day)")) - } - - private func push(_ value: String, forKey codingPath: [CodingKey]) throws { - items.append(URLQueryItem(name: codingPath.queryItemKey, value: value)) - } - - private func push(_ value: Date, forKey codingPath: [CodingKey]) throws { - items.append(URLQueryItem(name: codingPath.queryItemKey, value: iso8601Formatter.string(from: value))) - } - - private func push(_ value: Bool, forKey codingPath: [CodingKey]) throws { - let boolValue: String - switch value { - case true: - boolValue = "true" - case false: - boolValue = "false" - } - items.append(URLQueryItem(name: codingPath.queryItemKey, value: boolValue)) - } - - private func push(_ value: Int, forKey codingPath: [CodingKey]) throws { - items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) - } - - private func push(_ value: Int8, forKey codingPath: [CodingKey]) throws { - items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) - } - - private func push(_ value: Int16, forKey codingPath: [CodingKey]) throws { - items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) - } - - private func push(_ value: Int32, forKey codingPath: [CodingKey]) throws { - items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) - } - - private func push(_ value: Int64, forKey codingPath: [CodingKey]) throws { - items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) - } - - private func push(_ value: UInt, forKey codingPath: [CodingKey]) throws { - items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) - } - - private func push(_ value: UInt8, forKey codingPath: [CodingKey]) throws { - items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) - } - - private func push(_ value: UInt16, forKey codingPath: [CodingKey]) throws { - items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) - } - - private func push(_ value: UInt32, forKey codingPath: [CodingKey]) throws { - items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) - } - - private func push(_ value: UInt64, forKey codingPath: [CodingKey]) throws { - items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) - } - - private func push(_ value: Double, forKey codingPath: [CodingKey]) throws { - items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) - } - - private func push(_ value: Float, forKey codingPath: [CodingKey]) throws { - items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) - } - - private func push(_ value: URL, forKey codingPath: [CodingKey]) throws { - items.append(URLQueryItem(name: codingPath.queryItemKey, value: value.absoluteString)) - } - - // swiftlint:disable:next cyclomatic_complexity - private func push(_ value: T, forKey codingPath: [CodingKey]) throws { - self.codingPath = codingPath - switch value { - case let value as String: - try push(value, forKey: codingPath) - case let value as Bool: - try push(value, forKey: codingPath) - case let value as Int: - try push(value, forKey: codingPath) - case let value as Int8: - try push(value, forKey: codingPath) - case let value as Int16: - try push(value, forKey: codingPath) - case let value as Int32: - try push(value, forKey: codingPath) - case let value as Int64: - try push(value, forKey: codingPath) - case let value as UInt: - try push(value, forKey: codingPath) - case let value as UInt8: - try push(value, forKey: codingPath) - case let value as UInt16: - try push(value, forKey: codingPath) - case let value as UInt32: - try push(value, forKey: codingPath) - case let value as UInt64: - try push(value, forKey: codingPath) - - case let value as Double: - try push(value, forKey: codingPath) - case let value as Float: - try push(value, forKey: codingPath) - - case let value as Date: - try push(value, forKey: codingPath) - case let value as DateComponents: - try push(value, forKey: codingPath) - - case let value as URL: - try push(value, forKey: codingPath) - - case let value: - try value.encode(to: self) - } - } + /// The strategy to use for encoding array indexes. + public enum ArrayIndexEncodingStrategy { + /// Encode any array index as an empty square brackets `[]` + case emptySquareBrackets + /// Encode an array index as index number + case index + } + + public fileprivate(set) var codingPath: [CodingKey] = [] + fileprivate var items: [URLQueryItem] = [] + + /// The strategy to use in encoding array indexes. Defaults to `.emptySquareBrackets`. + public var arrayIndexEncodingStrategy = ArrayIndexEncodingStrategy.emptySquareBrackets + public init() {} + + /// Encodes the given top-level value and returns an array of its URLQueryItem representation. + /// + /// - parameter value: The value to encode. + /// - returns: An array of `URLQueryItem` containing the encoded query item data. + /// - throws: An error if any value throws an error during encoding. + public func encode(_ value: Encodable) throws -> [URLQueryItem] { + items = [] + try value.encode(to: self) + return items + } + + private static let formURLEncodedAllowedCharacters: CharacterSet = { + var characters = CharacterSet.urlQueryAllowed + characters.remove(charactersIn: ":#[]@?/!$&'()*+,;=") + return characters + }() + + /// Encodes the given array of `URLQueryItem` and returns an x-www-urlencoded compatible Data representation. + /// + /// - Parameter queryItems: The URLQueryItems to encode + /// - Returns: A data represents the encoded with an x-www-urlencoded compatible representation + public static func encodeToFormURLEncodedData(queryItems: [URLQueryItem]) -> Data { + var components = URLComponents() + components.queryItems = queryItems.map { + URLQueryItem( + name: $0.name.addingPercentEncoding( + withAllowedCharacters: URLQueryItemEncoder.formURLEncodedAllowedCharacters + ) ?? $0.name, + value: $0.value?.addingPercentEncoding( + withAllowedCharacters: URLQueryItemEncoder.formURLEncodedAllowedCharacters + ) + ) + } + + return components.query!.data(using: .utf8)! + } } -extension URLQueryItemEncoder: Encoder { - public var userInfo: [CodingUserInfoKey: Any] { return [:] } - - public func container(keyedBy type: Key.Type) -> KeyedEncodingContainer where Key: CodingKey { - return KeyedEncodingContainer(KeyedContainer(encoder: self, codingPath: codingPath)) - } +private extension [CodingKey] { + func queryItemKeyForKey(_ key: CodingKey) -> String { + let keysPath = self + [key] + return keysPath.queryItemKey + } - public func unkeyedContainer() -> UnkeyedEncodingContainer { - return UnkeyedContanier(encoder: self, codingPath: codingPath) - } + var queryItemKey: String { + guard !isEmpty else { return "" } + var keysPath = self + let firstKey = keysPath.removeFirst() + let tailCodingKeyString = keysPath.reduce(into: "") { + $0 += "[\($1.stringValue)]" + } - public func singleValueContainer() -> SingleValueEncodingContainer { - return SingleValueContanier(encoder: self, codingPath: codingPath) - } + return firstKey.stringValue + tailCodingKeyString + } } -extension URLQueryItemEncoder { - fileprivate struct KeyedContainer: KeyedEncodingContainerProtocol { - let encoder: URLQueryItemEncoder - let codingPath: [CodingKey] +private struct URLQueryItemArrayElementKey: CodingKey { + let encodingStrategy: URLQueryItemEncoder.ArrayIndexEncodingStrategy - func encode(_ value: T, forKey key: Key) throws where T: Encodable { - let codingPath = self.codingPath + [key] - encoder.codingPath = codingPath - defer { encoder.codingPath.removeLast() } - try encoder.push(value, forKey: codingPath) + fileprivate var stringValue: String { + switch encodingStrategy { + case .emptySquareBrackets: + "" + case .index: + String(index) + } } - func encodeNil(forKey key: Key) throws { - let codingPath = self.codingPath + [key] - encoder.codingPath = codingPath - defer { encoder.codingPath.removeLast() } - try encoder.pushNil(forKey: codingPath) + fileprivate init(index: Int, encodingStrategy: URLQueryItemEncoder.ArrayIndexEncodingStrategy) { + self.index = index + self.encodingStrategy = encodingStrategy } - func nestedContainer( - keyedBy keyType: NestedKey.Type, - forKey key: Key - ) -> KeyedEncodingContainer where NestedKey: CodingKey { - return KeyedEncodingContainer(KeyedContainer(encoder: encoder, codingPath: codingPath + [key])) + init?(stringValue: String) { + guard let index = Int(stringValue) else { return nil } + self.index = index + encodingStrategy = .index } - func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { - return UnkeyedContanier(encoder: encoder, codingPath: codingPath + [key]) + let index: Int + var intValue: Int? { + index } - func superEncoder() -> Encoder { - return URLQueryItemReferencingEncoder(encoder: encoder, codingPath: codingPath) + init?(intValue: Int) { + index = intValue + encodingStrategy = .index } +} - func superEncoder(forKey key: Key) -> Encoder { - return URLQueryItemReferencingEncoder(encoder: encoder, codingPath: codingPath + [key]) +extension URLQueryItemEncoder { + private func pushNil(forKey codingPath: [CodingKey]) throws { + items.append(URLQueryItem(name: codingPath.queryItemKey, value: nil)) } - } - fileprivate class UnkeyedContanier: UnkeyedEncodingContainer { - var encoder: URLQueryItemEncoder + private func push(_ value: DateComponents, forKey codingPath: [CodingKey]) throws { + guard (value.calendar?.identifier ?? Calendar.current.identifier) == .gregorian, + let year = value.year, let month = value.month, let day = value.day + else { + throw DecodingError.dataCorrupted( + DecodingError.Context(codingPath: codingPath, debugDescription: "Invalid date components") + ) + } - var codingPath: [CodingKey] - - var count: Int { - return encodedItemsCount + items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(year)-\(month)-\(day)")) } - var encodedItemsCount: Int = 0 - - fileprivate init(encoder: URLQueryItemEncoder, codingPath: [CodingKey], encodedItemsCount: Int = 0) { - self.encoder = encoder - self.codingPath = codingPath - self.encodedItemsCount = encodedItemsCount + private func push(_ value: String, forKey codingPath: [CodingKey]) throws { + items.append(URLQueryItem(name: codingPath.queryItemKey, value: value)) } - func nestedContainer( - keyedBy keyType: NestedKey.Type - ) -> KeyedEncodingContainer where NestedKey: CodingKey { - codingPath.append( - URLQueryItemArrayElementKey(index: encodedItemsCount, encodingStrategy: encoder.arrayIndexEncodingStrategy) - ) - defer { codingPath.removeLast() } - return KeyedEncodingContainer(KeyedContainer(encoder: encoder, codingPath: codingPath)) + private func push(_ value: Date, forKey codingPath: [CodingKey]) throws { + items.append(URLQueryItem(name: codingPath.queryItemKey, value: iso8601Formatter.string(from: value))) } - func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { - codingPath.append( - URLQueryItemArrayElementKey(index: encodedItemsCount, encodingStrategy: encoder.arrayIndexEncodingStrategy) - ) - defer { codingPath.removeLast() } - return self + private func push(_ value: Bool, forKey codingPath: [CodingKey]) throws { + let boolValue = switch value { + case true: + "true" + case false: + "false" + } + items.append(URLQueryItem(name: codingPath.queryItemKey, value: boolValue)) } - func superEncoder() -> Encoder { - codingPath.append( - URLQueryItemArrayElementKey( - index: encodedItemsCount, - encodingStrategy: encoder.arrayIndexEncodingStrategy - ) - ) - defer { codingPath.removeLast() } - return UnkeyedURLQueryItemReferencingEncoder(encoder: encoder, codingPath: codingPath, referencing: self) + private func push(_ value: Int, forKey codingPath: [CodingKey]) throws { + items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) } - func encodeNil() throws { - codingPath.append( - URLQueryItemArrayElementKey(index: encodedItemsCount, encodingStrategy: encoder.arrayIndexEncodingStrategy) - ) - defer { codingPath.removeLast() } - try encoder.pushNil(forKey: codingPath) - encodedItemsCount += 1 + private func push(_ value: Int8, forKey codingPath: [CodingKey]) throws { + items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) } - func encode(_ value: T) throws where T: Encodable { - codingPath.append( - URLQueryItemArrayElementKey(index: encodedItemsCount, encodingStrategy: encoder.arrayIndexEncodingStrategy) - ) - defer { codingPath.removeLast() } - try encoder.push(value, forKey: codingPath) - encodedItemsCount += 1 + private func push(_ value: Int16, forKey codingPath: [CodingKey]) throws { + items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) } - } - - fileprivate struct SingleValueContanier: SingleValueEncodingContainer { - let encoder: URLQueryItemEncoder - var codingPath: [CodingKey] - fileprivate init(encoder: URLQueryItemEncoder, codingPath: [CodingKey]) { - self.encoder = encoder - self.codingPath = codingPath + private func push(_ value: Int32, forKey codingPath: [CodingKey]) throws { + items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) } - mutating func encodeNil() throws { - try encoder.pushNil(forKey: codingPath) + private func push(_ value: Int64, forKey codingPath: [CodingKey]) throws { + items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) } - public func encode(_ value: Bool) throws { - try encoder.push(value, forKey: codingPath) + private func push(_ value: UInt, forKey codingPath: [CodingKey]) throws { + items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) } - public func encode(_ value: Int) throws { - try encoder.push(value, forKey: codingPath) + private func push(_ value: UInt8, forKey codingPath: [CodingKey]) throws { + items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) } - public func encode(_ value: Int8) throws { - try encoder.push(value, forKey: codingPath) + private func push(_ value: UInt16, forKey codingPath: [CodingKey]) throws { + items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) } - public func encode(_ value: Int16) throws { - try encoder.push(value, forKey: codingPath) + private func push(_ value: UInt32, forKey codingPath: [CodingKey]) throws { + items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) } - public func encode(_ value: Int32) throws { - try encoder.push(value, forKey: codingPath) + private func push(_ value: UInt64, forKey codingPath: [CodingKey]) throws { + items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) } - public func encode(_ value: Int64) throws { - try encoder.push(value, forKey: codingPath) + private func push(_ value: Double, forKey codingPath: [CodingKey]) throws { + items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) } - public func encode(_ value: UInt) throws { - try encoder.push(value, forKey: codingPath) + private func push(_ value: Float, forKey codingPath: [CodingKey]) throws { + items.append(URLQueryItem(name: codingPath.queryItemKey, value: "\(value)")) } - public func encode(_ value: UInt8) throws { - try encoder.push(value, forKey: codingPath) + private func push(_ value: URL, forKey codingPath: [CodingKey]) throws { + items.append(URLQueryItem(name: codingPath.queryItemKey, value: value.absoluteString)) } - public func encode(_ value: UInt16) throws { - try encoder.push(value, forKey: codingPath) - } + // swiftlint:disable:next cyclomatic_complexity + private func push(_ value: some Encodable, forKey codingPath: [CodingKey]) throws { + self.codingPath = codingPath + switch value { + case let value as String: + try push(value, forKey: codingPath) + case let value as Bool: + try push(value, forKey: codingPath) + case let value as Int: + try push(value, forKey: codingPath) + case let value as Int8: + try push(value, forKey: codingPath) + case let value as Int16: + try push(value, forKey: codingPath) + case let value as Int32: + try push(value, forKey: codingPath) + case let value as Int64: + try push(value, forKey: codingPath) + case let value as UInt: + try push(value, forKey: codingPath) + case let value as UInt8: + try push(value, forKey: codingPath) + case let value as UInt16: + try push(value, forKey: codingPath) + case let value as UInt32: + try push(value, forKey: codingPath) + case let value as UInt64: + try push(value, forKey: codingPath) - public func encode(_ value: UInt32) throws { - try encoder.push(value, forKey: codingPath) - } + case let value as Double: + try push(value, forKey: codingPath) + case let value as Float: + try push(value, forKey: codingPath) - public func encode(_ value: UInt64) throws { - try encoder.push(value, forKey: codingPath) + case let value as Date: + try push(value, forKey: codingPath) + case let value as DateComponents: + try push(value, forKey: codingPath) + + case let value as URL: + try push(value, forKey: codingPath) + + case let value: + try value.encode(to: self) + } } +} + +extension URLQueryItemEncoder: Encoder { + public var userInfo: [CodingUserInfoKey: Any] { [:] } - public func encode(_ value: String) throws { - try encoder.push(value, forKey: codingPath) + public func container(keyedBy _: Key.Type) -> KeyedEncodingContainer where Key: CodingKey { + KeyedEncodingContainer(KeyedContainer(encoder: self, codingPath: codingPath)) } - public func encode(_ value: Float) throws { - try encoder.push(value, forKey: codingPath) + public func unkeyedContainer() -> UnkeyedEncodingContainer { + UnkeyedContanier(encoder: self, codingPath: codingPath) } - public func encode(_ value: Double) throws { - try encoder.push(value, forKey: codingPath) + public func singleValueContainer() -> SingleValueEncodingContainer { + SingleValueContanier(encoder: self, codingPath: codingPath) } +} - mutating func encode(_ value: T) throws where T: Encodable { - encoder.codingPath = self.codingPath - try encoder.push(value, forKey: codingPath) +private extension URLQueryItemEncoder { + struct KeyedContainer: KeyedEncodingContainerProtocol { + let encoder: URLQueryItemEncoder + let codingPath: [CodingKey] + + func encode(_ value: some Encodable, forKey key: Key) throws { + let codingPath = codingPath + [key] + encoder.codingPath = codingPath + defer { encoder.codingPath.removeLast() } + try encoder.push(value, forKey: codingPath) + } + + func encodeNil(forKey key: Key) throws { + let codingPath = codingPath + [key] + encoder.codingPath = codingPath + defer { encoder.codingPath.removeLast() } + try encoder.pushNil(forKey: codingPath) + } + + func nestedContainer( + keyedBy _: NestedKey.Type, + forKey key: Key + ) -> KeyedEncodingContainer where NestedKey: CodingKey { + KeyedEncodingContainer(KeyedContainer(encoder: encoder, codingPath: codingPath + [key])) + } + + func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { + UnkeyedContanier(encoder: encoder, codingPath: codingPath + [key]) + } + + func superEncoder() -> Encoder { + URLQueryItemReferencingEncoder(encoder: encoder, codingPath: codingPath) + } + + func superEncoder(forKey key: Key) -> Encoder { + URLQueryItemReferencingEncoder(encoder: encoder, codingPath: codingPath + [key]) + } + } + + class UnkeyedContanier: UnkeyedEncodingContainer { + var encoder: URLQueryItemEncoder + + var codingPath: [CodingKey] + + var count: Int { + encodedItemsCount + } + + var encodedItemsCount: Int = 0 + + fileprivate init(encoder: URLQueryItemEncoder, codingPath: [CodingKey], encodedItemsCount: Int = 0) { + self.encoder = encoder + self.codingPath = codingPath + self.encodedItemsCount = encodedItemsCount + } + + func nestedContainer( + keyedBy _: NestedKey.Type + ) -> KeyedEncodingContainer where NestedKey: CodingKey { + codingPath.append( + URLQueryItemArrayElementKey(index: encodedItemsCount, encodingStrategy: encoder.arrayIndexEncodingStrategy) + ) + defer { codingPath.removeLast() } + return KeyedEncodingContainer(KeyedContainer(encoder: encoder, codingPath: codingPath)) + } + + func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { + codingPath.append( + URLQueryItemArrayElementKey(index: encodedItemsCount, encodingStrategy: encoder.arrayIndexEncodingStrategy) + ) + defer { codingPath.removeLast() } + return self + } + + func superEncoder() -> Encoder { + codingPath.append( + URLQueryItemArrayElementKey( + index: encodedItemsCount, + encodingStrategy: encoder.arrayIndexEncodingStrategy + ) + ) + defer { codingPath.removeLast() } + return UnkeyedURLQueryItemReferencingEncoder(encoder: encoder, codingPath: codingPath, referencing: self) + } + + func encodeNil() throws { + codingPath.append( + URLQueryItemArrayElementKey(index: encodedItemsCount, encodingStrategy: encoder.arrayIndexEncodingStrategy) + ) + defer { codingPath.removeLast() } + try encoder.pushNil(forKey: codingPath) + encodedItemsCount += 1 + } + + func encode(_ value: some Encodable) throws { + codingPath.append( + URLQueryItemArrayElementKey(index: encodedItemsCount, encodingStrategy: encoder.arrayIndexEncodingStrategy) + ) + defer { codingPath.removeLast() } + try encoder.push(value, forKey: codingPath) + encodedItemsCount += 1 + } + } + + struct SingleValueContanier: SingleValueEncodingContainer { + let encoder: URLQueryItemEncoder + var codingPath: [CodingKey] + + fileprivate init(encoder: URLQueryItemEncoder, codingPath: [CodingKey]) { + self.encoder = encoder + self.codingPath = codingPath + } + + mutating func encodeNil() throws { + try encoder.pushNil(forKey: codingPath) + } + + public func encode(_ value: Bool) throws { + try encoder.push(value, forKey: codingPath) + } + + public func encode(_ value: Int) throws { + try encoder.push(value, forKey: codingPath) + } + + public func encode(_ value: Int8) throws { + try encoder.push(value, forKey: codingPath) + } + + public func encode(_ value: Int16) throws { + try encoder.push(value, forKey: codingPath) + } + + public func encode(_ value: Int32) throws { + try encoder.push(value, forKey: codingPath) + } + + public func encode(_ value: Int64) throws { + try encoder.push(value, forKey: codingPath) + } + + public func encode(_ value: UInt) throws { + try encoder.push(value, forKey: codingPath) + } + + public func encode(_ value: UInt8) throws { + try encoder.push(value, forKey: codingPath) + } + + public func encode(_ value: UInt16) throws { + try encoder.push(value, forKey: codingPath) + } + + public func encode(_ value: UInt32) throws { + try encoder.push(value, forKey: codingPath) + } + + public func encode(_ value: UInt64) throws { + try encoder.push(value, forKey: codingPath) + } + + public func encode(_ value: String) throws { + try encoder.push(value, forKey: codingPath) + } + + public func encode(_ value: Float) throws { + try encoder.push(value, forKey: codingPath) + } + + public func encode(_ value: Double) throws { + try encoder.push(value, forKey: codingPath) + } + + mutating func encode(_ value: some Encodable) throws { + encoder.codingPath = codingPath + try encoder.push(value, forKey: codingPath) + } } - } } private class URLQueryItemReferencingEncoder: URLQueryItemEncoder { - fileprivate let encoder: URLQueryItemEncoder - - init(encoder: URLQueryItemEncoder, codingPath: [CodingKey]) { - self.encoder = encoder - super.init() - self.codingPath = codingPath - self.arrayIndexEncodingStrategy = encoder.arrayIndexEncodingStrategy - } - - deinit { - self.encoder.items.append(contentsOf: self.items) - } + fileprivate let encoder: URLQueryItemEncoder + + init(encoder: URLQueryItemEncoder, codingPath: [CodingKey]) { + self.encoder = encoder + super.init() + self.codingPath = codingPath + arrayIndexEncodingStrategy = encoder.arrayIndexEncodingStrategy + } + + deinit { + self.encoder.items.append(contentsOf: self.items) + } } private class UnkeyedURLQueryItemReferencingEncoder: URLQueryItemReferencingEncoder { - var referencedUnkeyedContainer: UnkeyedContanier + var referencedUnkeyedContainer: UnkeyedContanier - init(encoder: URLQueryItemEncoder, codingPath: [CodingKey], referencing: UnkeyedContanier) { - referencedUnkeyedContainer = referencing - super.init(encoder: encoder, codingPath: codingPath) - } + init(encoder: URLQueryItemEncoder, codingPath: [CodingKey], referencing: UnkeyedContanier) { + referencedUnkeyedContainer = referencing + super.init(encoder: encoder, codingPath: codingPath) + } - deinit { - referencedUnkeyedContainer.encodedItemsCount += items.count - } + deinit { + referencedUnkeyedContainer.encodedItemsCount += items.count + } } + // swiftlint:enable file_length diff --git a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift index 8b43202d4..1e3dc0be8 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift @@ -1,16 +1,17 @@ import Foundation +import RuuviCloud import RuuviPool import RuuviUser -import RuuviCloud #if canImport(RuuviCloudApi) -import RuuviCloudApi + import RuuviCloudApi #endif public final class RuuviCloudFactoryPure: RuuviCloudFactory { public init() {} public func create(baseUrl: URL, user: RuuviUser, - pool: RuuviPool?) -> RuuviCloud { + pool: RuuviPool?) -> RuuviCloud + { let api = RuuviCloudApiURLSession(baseUrl: baseUrl) let cloud = RuuviCloudPure(api: api, user: user, pool: pool) return cloud diff --git a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift index 046e87bdc..b64a2b37d 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift @@ -1,13 +1,13 @@ +import BTKit // swiftlint:disable file_length import Foundation import Future -import RuuviOntology -import BTKit -import RuuviUser import RuuviCloud +import RuuviOntology import RuuviPool +import RuuviUser #if canImport(RuuviCloudApi) -import RuuviCloudApi + import RuuviCloudApi #endif // swiftlint:disable:next type_body_length @@ -18,7 +18,8 @@ public final class RuuviCloudPure: RuuviCloud { public init(api: RuuviCloudApi, user: RuuviUser, - pool: RuuviPool?) { + pool: RuuviPool?) + { self.api = api self.user = user self.pool = pool @@ -426,7 +427,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(dashboardTapActionType: DashboardTapActionType) -> - Future { + Future + { let promise = Promise() guard let apiKey = user.apiKey else { promise.fail(error: .notAuthorized) @@ -590,18 +592,19 @@ public final class RuuviCloudPure: RuuviCloud { authorization: apiKey, uploadProgress: { percentage in progress?(macId, percentage) - }).on(success: { response in - promise.succeed(value: response.uploadURL) - }, failure: { [weak self] error in - let uniqueKey = macId.value + "-uploadImage" - self?.createQueuedRequest( - from: requestModel, - additionalData: imageData, - type: .uploadImage, - uniqueKey: uniqueKey - ) - promise.fail(error: .api(error)) - }) + } + ).on(success: { response in + promise.succeed(value: response.uploadURL) + }, failure: { [weak self] error in + let uniqueKey = macId.value + "-uploadImage" + self?.createQueuedRequest( + from: requestModel, + additionalData: imageData, + type: .uploadImage, + uniqueKey: uniqueKey + ) + promise.fail(error: .api(error)) + }) return promise.future } @@ -691,7 +694,7 @@ public final class RuuviCloudPure: RuuviCloud { let request = RuuviCloudApiGetSensorsRequest(sensor: sensor.id) api.sensors(request, authorization: apiKey) .on(success: { response in - let arrayOfAny = response.sensors?.map({ $0.shareableSensor.any }) + let arrayOfAny = response.sensors?.map(\.shareableSensor.any) let setOfAny = Set(arrayOfAny ?? []) promise.succeed(value: setOfAny) }, failure: { error in @@ -738,7 +741,7 @@ public final class RuuviCloudPure: RuuviCloud { ) api.sensorsDense(request, authorization: apiKey) .on(success: { [weak self] response in - let arrayOfAny = response.sensors?.compactMap({ sensor in + let arrayOfAny = response.sensors?.compactMap { sensor in RuuviCloudSensorDense( sensor: CloudSensorStruct( id: sensor.sensor, @@ -762,7 +765,7 @@ public final class RuuviCloudPure: RuuviCloud { alerts: sensor.alerts, subscription: sensor.subscription ) - }) + } promise.succeed(value: arrayOfAny ?? []) }, failure: { error in promise.fail(error: .api(error)) @@ -801,7 +804,7 @@ public final class RuuviCloudPure: RuuviCloud { .on(success: { _ in promise.succeed(value: macId) }, failure: { [weak self] error in - guard let email = email else { + guard let email else { promise.fail(error: .api(error)) return } @@ -901,7 +904,8 @@ public final class RuuviCloudPure: RuuviCloud { api.verify(request) .on(success: { response in guard let email = response.email, - let accessToken = response.accessToken else { + let accessToken = response.accessToken + else { return promise.fail(error: .api(.api(.erInternal))) } let result = ValidateCodeResponse( @@ -936,7 +940,8 @@ public final class RuuviCloudPure: RuuviCloud { type: String, name: String?, data: String?, - params: [String: String]?) -> Future { + params: [String: String]?) -> Future + { let promise = Promise() guard let apiKey = user.apiKey else { promise.fail(error: .notAuthorized) @@ -950,7 +955,7 @@ public final class RuuviCloudPure: RuuviCloud { params: params ) api.registerPNToken(request, - authorization: apiKey) + authorization: apiKey) .on(success: { response in promise.succeed(value: response.id) }, failure: { error in @@ -960,7 +965,8 @@ public final class RuuviCloudPure: RuuviCloud { } public func unregisterPNToken(token: String?, - tokenId: Int?) -> Future { + tokenId: Int?) -> Future + { let promise = Promise() let request = RuuviCloudPNTokenUnregisterRequest(token: token, id: tokenId) @@ -999,7 +1005,7 @@ public final class RuuviCloudPure: RuuviCloud { } api.user(authorization: apiKey).on(success: { response in let email = response.email - let sensors = response.sensors.map({ $0.with(email: email).any }) + let sensors = response.sensors.map { $0.with(email: email).any } promise.succeed(value: sensors) }, failure: { error in promise.fail(error: .api(error)) @@ -1052,7 +1058,8 @@ public final class RuuviCloudPure: RuuviCloud { // Offset is to check whether we have recent minute data. (Current time + 1 min) let offset = Date().addingTimeInterval(1 * 60) if let lastRecord = fetchedRecords.last, - !records.contains(lastRecord) { + !records.contains(lastRecord) + { let loadable = (until != nil && lastRecord.date < until!) || lastRecord.date > offset if loadable { @@ -1070,14 +1077,15 @@ public final class RuuviCloudPure: RuuviCloud { } else { promise.succeed(value: records + fetchedRecords) } - }, failure: { (error) in + }, failure: { error in promise.fail(error: .api(error)) }) } // swiftlint:disable:next function_body_length cyclomatic_complexity public func executeQueuedRequest(from request: RuuviCloudQueuedRequest) - -> Future { + -> Future + { let promise = Promise() guard let apiKey = user.apiKey else { promise.fail(error: .notAuthorized) @@ -1210,16 +1218,17 @@ public final class RuuviCloudPure: RuuviCloud { guard let measurements = response.measurements else { return [] } - return measurements.compactMap({ measurement in + return measurements.compactMap { measurement in guard let rssi = measurement.rssi, - let data = measurement.data, - let device = decoder.decodeNetwork( - uuid: macId.value, - rssi: rssi, - isConnectable: true, - payload: data - ), - let tag = device.ruuvi?.tag else { + let data = measurement.data, + let device = decoder.decodeNetwork( + uuid: macId.value, + rssi: rssi, + isConnectable: true, + payload: data + ), + let tag = device.ruuvi?.tag + else { return nil } return RuuviTagSensorRecordStruct( @@ -1240,7 +1249,7 @@ public final class RuuviCloudPure: RuuviCloud { humidityOffset: 0.0, pressureOffset: 0.0 ).any - }) + } } private func decodeSensorRecord( @@ -1248,16 +1257,17 @@ public final class RuuviCloudPure: RuuviCloud { record: UserApiSensorRecord? ) -> AnyRuuviTagSensorRecord? { let decoder = Ruuvi.decoder - guard let record = record, + guard let record, let rssi = record.rssi, let data = record.data, let device = decoder.decodeNetwork( - uuid: macId.value, - rssi: rssi, - isConnectable: true, - payload: data + uuid: macId.value, + rssi: rssi, + isConnectable: true, + payload: data ), - let tag = device.ruuvi?.tag else { + let tag = device.ruuvi?.tag + else { return nil } return RuuviTagSensorRecordStruct( @@ -1283,7 +1293,8 @@ public final class RuuviCloudPure: RuuviCloud { private func createQueuedRequest(from request: Codable, additionalData: Data? = nil, type: RuuviCloudQueuedRequestType, - uniqueKey: String) { + uniqueKey: String) + { let encoder = JSONEncoder() guard let data = try? encoder.encode(request) else { return @@ -1302,4 +1313,5 @@ public final class RuuviCloudPure: RuuviCloud { pool?.createQueuedRequest(request) } } + // swiftlint:enable file_length diff --git a/Packages/RuuviCloud/Tests/RuuviCloudTests/RuuviCloudTests.swift b/Packages/RuuviCloud/Tests/RuuviCloudTests/RuuviCloudTests.swift index a98af8a76..776ec88f6 100644 --- a/Packages/RuuviCloud/Tests/RuuviCloudTests/RuuviCloudTests.swift +++ b/Packages/RuuviCloud/Tests/RuuviCloudTests/RuuviCloudTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviCloud +import XCTest final class RuuviCloudTests: XCTestCase { - func testRegister() { - } + func testRegister() {} } diff --git a/Packages/RuuviContext/Package.swift b/Packages/RuuviContext/Package.swift index 589a9745f..5d3a8976f 100644 --- a/Packages/RuuviContext/Package.swift +++ b/Packages/RuuviContext/Package.swift @@ -18,26 +18,26 @@ let package = Package( .library( name: "RuuviContextSQLite", targets: ["RuuviContextSQLite"] - ) + ), ], dependencies: [ .package(name: "Realm", url: "https://github.com/realm/realm-cocoa", .upToNextMajor(from: "10.8.0")), .package(path: "../RuuviOntology"), - .package(name: "GRDB", url: "https://github.com/groue/GRDB.swift", .upToNextMajor(from: "4.14.0")) + .package(name: "GRDB", url: "https://github.com/groue/GRDB.swift", .upToNextMajor(from: "4.14.0")), ], targets: [ .target( name: "RuuviContext", dependencies: [ .product(name: "RealmSwift", package: "Realm"), - .product(name: "GRDB", package: "GRDB") + .product(name: "GRDB", package: "GRDB"), ] ), .target( name: "RuuviContextRealm", dependencies: [ .product(name: "RealmSwift", package: "Realm"), - "RuuviContext" + "RuuviContext", ] ), .target( @@ -46,11 +46,12 @@ let package = Package( .product(name: "GRDB", package: "GRDB"), .product(name: "RuuviOntologySQLite", package: "RuuviOntology"), "RuuviOntology", - "RuuviContext" + "RuuviContext", ] ), .testTarget( name: "RuuviContextTests", - dependencies: ["RuuviContext"]) + dependencies: ["RuuviContext"] + ), ] ) diff --git a/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextFactoryImpl.swift b/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextFactoryImpl.swift index 8b7006b16..68f7bfa62 100644 --- a/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextFactoryImpl.swift +++ b/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextFactoryImpl.swift @@ -4,6 +4,6 @@ public final class RealmContextFactoryImpl: RealmContextFactory { public init() {} public func create() -> RealmContext { - return RealmContextImpl() + RealmContextImpl() } } diff --git a/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextImpl.swift b/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextImpl.swift index 47bdc6a28..6f99a116c 100644 --- a/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextImpl.swift +++ b/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextImpl.swift @@ -1,10 +1,10 @@ -import RuuviContext import RealmSwift +import RuuviContext class RealmContextImpl: RealmContext { var main: Realm = try! Realm() var bg: Realm! - var bgWorker: Worker = Worker() + var bgWorker: Worker = .init() init() { bgWorker.enqueue { diff --git a/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextFactoryGRDB.swift b/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextFactoryGRDB.swift index bd3b5a887..23adfad49 100644 --- a/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextFactoryGRDB.swift +++ b/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextFactoryGRDB.swift @@ -5,6 +5,6 @@ public final class SQLiteContextFactoryGRDB: SQLiteContextFactory { public init() {} public func create() -> SQLiteContext { - return SQLiteContextGRDB() + SQLiteContextGRDB() } } diff --git a/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextGRDB.swift b/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextGRDB.swift index 1dd403631..f1984c4e2 100644 --- a/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextGRDB.swift +++ b/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextGRDB.swift @@ -3,7 +3,7 @@ import GRDB import RuuviContext import RuuviOntology #if canImport(RuuviOntologySQLite) -import RuuviOntologySQLite + import RuuviOntologySQLite #endif class SQLiteContextGRDB: SQLiteContext { @@ -17,7 +17,6 @@ public protocol DatabaseService { } class SQLiteGRDBDatabase: GRDBDatabase { - static let shared: SQLiteGRDBDatabase = { let instance = try! SQLiteGRDBDatabase() return instance @@ -31,7 +30,7 @@ class SQLiteGRDBDatabase: GRDBDatabase { } var dbPath: String { - return Self.databasePath + Self.databasePath } private(set) var dbPool: DatabasePool @@ -79,12 +78,13 @@ extension SQLiteGRDBDatabase { } // v2 - migrator.registerMigration("Add isClaimedColumn column") { (db) in + migrator.registerMigration("Add isClaimedColumn column") { db in guard try db.columns(in: RuuviTagSQLite.databaseTableName) - .contains(where: {$0.name == RuuviTagSQLite.isClaimedColumn.name}) == false else { + .contains(where: { $0.name == RuuviTagSQLite.isClaimedColumn.name }) == false + else { return } - try db.alter(table: RuuviTagSQLite.databaseTableName) { (t) in + try db.alter(table: RuuviTagSQLite.databaseTableName) { t in t.add(column: RuuviTagSQLite.isClaimedColumn.name, .boolean) .notNull() .defaults(to: false) @@ -101,10 +101,11 @@ extension SQLiteGRDBDatabase { try SensorSettingsSQLite.createTable(in: db) guard try db.columns(in: RuuviTagDataSQLite.databaseTableName) - .contains(where: {$0.name == RuuviTagDataSQLite.temperatureOffsetColumn.name}) == false else { + .contains(where: { $0.name == RuuviTagDataSQLite.temperatureOffsetColumn.name }) == false + else { return } - try db.alter(table: RuuviTagDataSQLite.databaseTableName, body: { (t) in + try db.alter(table: RuuviTagDataSQLite.databaseTableName, body: { t in t.add(column: RuuviTagDataSQLite.temperatureOffsetColumn.name, .double) .notNull().defaults(to: 0.0) t.add(column: RuuviTagDataSQLite.humidityOffsetColumn.name, .double) @@ -117,10 +118,11 @@ extension SQLiteGRDBDatabase { // v4 migrator.registerMigration("Create RuuviTagDataSQLite source column") { db in guard try db.columns(in: RuuviTagDataSQLite.databaseTableName) - .contains(where: {$0.name == RuuviTagDataSQLite.sourceColumn.name}) == false else { + .contains(where: { $0.name == RuuviTagDataSQLite.sourceColumn.name }) == false + else { return } - try db.alter(table: RuuviTagDataSQLite.databaseTableName, body: { (t) in + try db.alter(table: RuuviTagDataSQLite.databaseTableName, body: { t in t.add(column: RuuviTagDataSQLite.sourceColumn.name, .text) .notNull().defaults(to: "unknown") }) @@ -129,30 +131,33 @@ extension SQLiteGRDBDatabase { // v5 migrator.registerMigration("Create RuuviTagDataSQLite luid column") { db in guard try db.columns(in: RuuviTagDataSQLite.databaseTableName) - .contains(where: {$0.name == RuuviTagDataSQLite.luidColumn.name}) == false else { + .contains(where: { $0.name == RuuviTagDataSQLite.luidColumn.name }) == false + else { return } - try db.alter(table: RuuviTagDataSQLite.databaseTableName, body: { (t) in + try db.alter(table: RuuviTagDataSQLite.databaseTableName, body: { t in t.add(column: RuuviTagDataSQLite.luidColumn.name, .text) }) } // v6 migrator.registerMigration("Create RuuviTagSQLite isCloudSensor column") { db in guard try db.columns(in: RuuviTagSQLite.databaseTableName) - .contains(where: {$0.name == RuuviTagSQLite.isCloudSensor.name}) == false else { + .contains(where: { $0.name == RuuviTagSQLite.isCloudSensor.name }) == false + else { return } - try db.alter(table: RuuviTagSQLite.databaseTableName, body: { (t) in + try db.alter(table: RuuviTagSQLite.databaseTableName, body: { t in t.add(column: RuuviTagSQLite.isCloudSensor.name, .boolean) }) } // v7 migrator.registerMigration("Create RuuviTagSQLite firmwareVersion column") { db in guard try db.columns(in: RuuviTagSQLite.databaseTableName) - .contains(where: {$0.name == RuuviTagSQLite.firmwareVersionColumn.name}) == false else { + .contains(where: { $0.name == RuuviTagSQLite.firmwareVersionColumn.name }) == false + else { return } - try db.alter(table: RuuviTagSQLite.databaseTableName, body: { (t) in + try db.alter(table: RuuviTagSQLite.databaseTableName, body: { t in t.add(column: RuuviTagSQLite.firmwareVersionColumn.name, .text) }) } @@ -167,12 +172,13 @@ extension SQLiteGRDBDatabase { // v9 migrator.registerMigration("Create RuuviTagSQLite canShare column") { db in guard try db.columns(in: RuuviTagSQLite.databaseTableName) - .contains( - where: { $0.name == RuuviTagSQLite.canShareColumn.name} - ) == false else { + .contains( + where: { $0.name == RuuviTagSQLite.canShareColumn.name } + ) == false + else { return } - try db.alter(table: RuuviTagSQLite.databaseTableName, body: { (t) in + try db.alter(table: RuuviTagSQLite.databaseTableName, body: { t in t.add( column: RuuviTagSQLite.canShareColumn.name, .boolean ).defaults(to: false) @@ -181,12 +187,13 @@ extension SQLiteGRDBDatabase { // v10 migrator.registerMigration("Create RuuviTagSQLite sharedTo column") { db in guard try db.columns(in: RuuviTagSQLite.databaseTableName) - .contains( - where: { $0.name == RuuviTagSQLite.sharedToColumn.name} - ) == false else { + .contains( + where: { $0.name == RuuviTagSQLite.sharedToColumn.name } + ) == false + else { return } - try db.alter(table: RuuviTagSQLite.databaseTableName, body: { (t) in + try db.alter(table: RuuviTagSQLite.databaseTableName, body: { t in t.add(column: RuuviTagSQLite.sharedToColumn.name, .text) .defaults(to: "") }) @@ -194,10 +201,11 @@ extension SQLiteGRDBDatabase { // v11 migrator.registerMigration("Create RuuviTagSQLite ownersPlan column") { db in guard try db.columns(in: RuuviTagSQLite.databaseTableName) - .contains(where: {$0.name == RuuviTagSQLite.ownersPlan.name}) == false else { + .contains(where: { $0.name == RuuviTagSQLite.ownersPlan.name }) == false + else { return } - try db.alter(table: RuuviTagSQLite.databaseTableName, body: { (t) in + try db.alter(table: RuuviTagSQLite.databaseTableName, body: { t in t.add(column: RuuviTagSQLite.ownersPlan.name, .text) }) } diff --git a/Packages/RuuviContext/Tests/RuuviContextTests/RuuviContextTests.swift b/Packages/RuuviContext/Tests/RuuviContextTests/RuuviContextTests.swift index 1e8148553..a2e3e7f68 100644 --- a/Packages/RuuviContext/Tests/RuuviContextTests/RuuviContextTests.swift +++ b/Packages/RuuviContext/Tests/RuuviContextTests/RuuviContextTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviContext +import XCTest final class RuuviContextTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Packages/RuuviCore/Package.swift b/Packages/RuuviCore/Package.swift index 7db1f8f8e..4e7c1ecae 100644 --- a/Packages/RuuviCore/Package.swift +++ b/Packages/RuuviCore/Package.swift @@ -9,25 +9,31 @@ let package = Package( products: [ .library( name: "RuuviCore", - targets: ["RuuviCore"]), + targets: ["RuuviCore"] + ), .library( name: "RuuviCoreImage", - targets: ["RuuviCoreImage"]), + targets: ["RuuviCoreImage"] + ), .library( name: "RuuviCoreLocation", - targets: ["RuuviCoreLocation"]), + targets: ["RuuviCoreLocation"] + ), .library( name: "RuuviCoreDiff", - targets: ["RuuviCoreDiff"]), + targets: ["RuuviCoreDiff"] + ), .library( name: "RuuviCorePN", - targets: ["RuuviCorePN"]), + targets: ["RuuviCorePN"] + ), .library( name: "RuuviCorePermission", - targets: ["RuuviCorePermission"]) + targets: ["RuuviCorePermission"] + ), ], dependencies: [ - .package(url: "https://github.com/kean/Future", .exact("1.3.0")) + .package(url: "https://github.com/kean/Future", .exact("1.3.0")), ], targets: [ .target( @@ -56,6 +62,7 @@ let package = Package( ), .testTarget( name: "RuuviCoreTests", - dependencies: ["RuuviCore"]) + dependencies: ["RuuviCore"] + ), ] ) diff --git a/Packages/RuuviCore/Sources/RuuviCore/RuuviCoreLocation.swift b/Packages/RuuviCore/Sources/RuuviCore/RuuviCoreLocation.swift index 1514d8dda..c436b2110 100644 --- a/Packages/RuuviCore/Sources/RuuviCore/RuuviCoreLocation.swift +++ b/Packages/RuuviCore/Sources/RuuviCore/RuuviCoreLocation.swift @@ -1,5 +1,5 @@ -import Foundation import CoreLocation +import Foundation import Future public protocol RuuviCoreLocation { diff --git a/Packages/RuuviCore/Sources/RuuviCore/RuuviCorePermission.swift b/Packages/RuuviCore/Sources/RuuviCore/RuuviCorePermission.swift index d68e5b8a0..f4f40a9de 100644 --- a/Packages/RuuviCore/Sources/RuuviCore/RuuviCorePermission.swift +++ b/Packages/RuuviCore/Sources/RuuviCore/RuuviCorePermission.swift @@ -1,6 +1,6 @@ -import Foundation -import CoreLocation import AVFoundation +import CoreLocation +import Foundation import Photos public protocol RuuviCorePermission { @@ -10,7 +10,7 @@ public protocol RuuviCorePermission { var isCameraPermissionGranted: Bool { get } #if targetEnvironment(macCatalyst) #else - var cameraAuthorizationStatus: AVAuthorizationStatus { get } + var cameraAuthorizationStatus: AVAuthorizationStatus { get } #endif var isLocationPermissionGranted: Bool { get } var locationAuthorizationStatus: CLAuthorizationStatus { get } diff --git a/Packages/RuuviCore/Sources/RuuviCoreDiff/Impl/DiffCalculatorImpl.swift b/Packages/RuuviCore/Sources/RuuviCoreDiff/Impl/DiffCalculatorImpl.swift index ef01e67f2..6d6f676ab 100644 --- a/Packages/RuuviCore/Sources/RuuviCoreDiff/Impl/DiffCalculatorImpl.swift +++ b/Packages/RuuviCore/Sources/RuuviCoreDiff/Impl/DiffCalculatorImpl.swift @@ -5,7 +5,7 @@ class DiffCalculatorImpl: DiffCalculator { func calculate(oldItems: [ReloadableSection], newItems: [ReloadableSection]) -> SectionChanges { let sectionChanges = SectionChanges() let uniqueSectionKeys = (oldItems + newItems) - .map { $0.key } + .map(\.key) .filterDuplicates() let cellChanges = CellChanges() @@ -13,35 +13,35 @@ class DiffCalculatorImpl: DiffCalculator { for sectionKey in uniqueSectionKeys { let oldSectionItem = ReloadableSectionData(items: oldItems)[sectionKey] let newSectionItem = ReloadableSectionData(items: newItems)[sectionKey] - if let oldSectionItem = oldSectionItem, let newSectionItem = newSectionItem { + if let oldSectionItem, let newSectionItem { if oldSectionItem != newSectionItem { let oldCellIData = ReloadableCellData(items: oldSectionItem.value) let newCellData = ReloadableCellData(items: newSectionItem.value) let uniqueCellKeys = (oldCellIData.items + newCellData.items) - .map { $0.key } + .map(\.key) .filterDuplicates() for cellKey in uniqueCellKeys { let oldCellItem = oldCellIData[cellKey] let newCellItem = newCellData[cellKey] - if let oldCellItem = oldCellItem, let newCelItem = newCellItem { + if let oldCellItem, let newCelItem = newCellItem { if oldCellItem != newCelItem { - let indexPath: IndexPath = IndexPath(row: oldCellItem.index, - section: oldSectionItem.index) + let indexPath: IndexPath = .init(row: oldCellItem.index, + section: oldSectionItem.index) cellChanges.reloads .append(indexPath) } - } else if let oldCellItem = oldCellItem { + } else if let oldCellItem { cellChanges.deletes.append(IndexPath(row: oldCellItem.index, section: oldSectionItem.index)) - } else if let newCellItem = newCellItem { + } else if let newCellItem { cellChanges.inserts.append(IndexPath(row: newCellItem.index, section: newSectionItem.index)) } } } - } else if let oldSectionItem = oldSectionItem { + } else if let oldSectionItem { sectionChanges.deletesInts.append(oldSectionItem.index) - } else if let newSectionItem = newSectionItem { + } else if let newSectionItem { sectionChanges.insertsInts.append(newSectionItem.index) } } @@ -53,25 +53,26 @@ class DiffCalculatorImpl: DiffCalculator { func calculate(oldItems: [ReloadableCell], newItems: [ReloadableCell], - in sectionIndex: Int) -> CellChanges { + in sectionIndex: Int) -> CellChanges + { let cellChanges = CellChanges() let oldCellIData = ReloadableCellData(items: oldItems) let newCellData = ReloadableCellData(items: newItems) let uniqueCellKeys = (oldCellIData.items + newCellData.items) - .map { $0.key } + .map(\.key) .filterDuplicates() for cellKey in uniqueCellKeys { let oldCellItem = oldCellIData[cellKey] let newCellItem = newCellData[cellKey] - if let oldCellItem = oldCellItem, let newCelItem = newCellItem { + if let oldCellItem, let newCelItem = newCellItem { if oldCellItem != newCelItem { cellChanges.reloads.append(IndexPath(row: oldCellItem.index, section: sectionIndex)) } - } else if let oldCellItem = oldCellItem { + } else if let oldCellItem { cellChanges.deletes.append(IndexPath(row: oldCellItem.index, section: sectionIndex)) - } else if let newCellItem = newCellItem { + } else if let newCellItem { cellChanges.inserts.append(IndexPath(row: newCellItem.index, section: sectionIndex)) } } diff --git a/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/ReloadableCell.swift b/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/ReloadableCell.swift index a01acd6c7..3ddebdda2 100644 --- a/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/ReloadableCell.swift +++ b/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/ReloadableCell.swift @@ -6,6 +6,6 @@ public struct ReloadableCell: Equatable { public var index: Int public static func == (lhs: ReloadableCell, rhs: ReloadableCell) -> Bool { - return lhs.key == rhs.key && lhs.value == rhs.value + lhs.key == rhs.key && lhs.value == rhs.value } } diff --git a/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/ReloadableCellData.swift b/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/ReloadableCellData.swift index 00bbf519c..e5d8890cc 100644 --- a/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/ReloadableCellData.swift +++ b/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/ReloadableCellData.swift @@ -4,10 +4,10 @@ struct ReloadableCellData { var items = [ReloadableCell]() subscript(key: String) -> ReloadableCell? { - return items.filter { $0.key == key }.first + items.filter { $0.key == key }.first } subscript(index: Int) -> ReloadableCell? { - return items.filter { $0.index == index }.first + items.filter { $0.index == index }.first } } diff --git a/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/ReloadableSection.swift b/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/ReloadableSection.swift index a0e55b17c..484dee052 100644 --- a/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/ReloadableSection.swift +++ b/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/ReloadableSection.swift @@ -6,6 +6,6 @@ public struct ReloadableSection: Equatable { public var index: Int public static func == (lhs: ReloadableSection, rhs: ReloadableSection) -> Bool { - return lhs.key == rhs.key && lhs.value == rhs.value + lhs.key == rhs.key && lhs.value == rhs.value } } diff --git a/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/ReloadableSectionData.swift b/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/ReloadableSectionData.swift index b505b3f51..e0fad2902 100644 --- a/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/ReloadableSectionData.swift +++ b/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/ReloadableSectionData.swift @@ -4,10 +4,10 @@ struct ReloadableSectionData { var items = [ReloadableSection]() subscript(key: String) -> ReloadableSection? { - return items.filter { $0.key == key }.first + items.filter { $0.key == key }.first } subscript(index: Int) -> ReloadableSection? { - return items.filter { $0.index == index }.first + items.filter { $0.index == index }.first } } diff --git a/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/SectionChanges.swift b/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/SectionChanges.swift index 5cfc8b7b4..d8183edf8 100644 --- a/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/SectionChanges.swift +++ b/Packages/RuuviCore/Sources/RuuviCoreDiff/Models/SectionChanges.swift @@ -6,15 +6,16 @@ public class SectionChanges { public var updates = CellChanges() public var inserts: IndexSet { - return IndexSet(insertsInts) + IndexSet(insertsInts) } + public var deletes: IndexSet { - return IndexSet(deletesInts) + IndexSet(deletesInts) } public init(inserts: [Int] = [], deletes: [Int] = [], updates: CellChanges = CellChanges()) { - self.insertsInts = inserts - self.deletesInts = deletes + insertsInts = inserts + deletesInts = deletes self.updates = updates } } diff --git a/Packages/RuuviCore/Sources/RuuviCoreDiff/Util/Array+Extension.swift b/Packages/RuuviCore/Sources/RuuviCoreDiff/Util/Array+Extension.swift index cee6bc5d1..e5892cdcd 100644 --- a/Packages/RuuviCore/Sources/RuuviCoreDiff/Util/Array+Extension.swift +++ b/Packages/RuuviCore/Sources/RuuviCoreDiff/Util/Array+Extension.swift @@ -10,19 +10,21 @@ extension Array where Element: Hashable { return filteredArray } } + extension String { - subscript (safe range: NSRange) -> String? { - guard self.count > range.location else { + subscript(safe range: NSRange) -> String? { + guard count > range.location else { return nil } - let length = self.count > range.location + range.length ? range.location + range.length : self.count - let startIndex = self.index(self.startIndex, offsetBy: range.location) - let endIndex = self.index(self.startIndex, offsetBy: length) - return String(self[startIndex.. range.location + range.length ? range.location + range.length : count + let startIndex = index(startIndex, offsetBy: range.location) + let endIndex = index(self.startIndex, offsetBy: length) + return String(self[startIndex ..< endIndex]) } } + extension Collection { - subscript (safe index: Index) -> Element? { - return indices.contains(index) ? self[index] : nil + subscript(safe index: Index) -> Element? { + indices.contains(index) ? self[index] : nil } } diff --git a/Packages/RuuviCore/Sources/RuuviCoreImage/RuuviCoreImageImpl.swift b/Packages/RuuviCore/Sources/RuuviCoreImage/RuuviCoreImageImpl.swift index 9ec17b516..5bdb723c7 100644 --- a/Packages/RuuviCore/Sources/RuuviCoreImage/RuuviCoreImageImpl.swift +++ b/Packages/RuuviCore/Sources/RuuviCoreImage/RuuviCoreImageImpl.swift @@ -1,8 +1,8 @@ -import UIKit +import AVFoundation import CoreGraphics import Foundation -import AVFoundation import RuuviCore +import UIKit public final class RuuviCoreImageImpl: RuuviCoreImage { public init() {} @@ -25,12 +25,10 @@ extension UIImage { let imageAspectRatio = self.size.width / self.size.height let canvasAspectRatio = size.width / size.height - var resizeFactor: CGFloat - - if imageAspectRatio > canvasAspectRatio { - resizeFactor = size.width / self.size.width + var resizeFactor: CGFloat = if imageAspectRatio > canvasAspectRatio { + size.width / self.size.width } else { - resizeFactor = size.height / self.size.height + size.height / self.size.height } let scaledSize = CGSize(width: self.size.width * resizeFactor, height: self.size.height * resizeFactor) diff --git a/Packages/RuuviCore/Sources/RuuviCoreLocation/RuuviCoreLocationImpl.swift b/Packages/RuuviCore/Sources/RuuviCoreLocation/RuuviCoreLocationImpl.swift index 61216f277..fe021f5e5 100644 --- a/Packages/RuuviCore/Sources/RuuviCoreLocation/RuuviCoreLocationImpl.swift +++ b/Packages/RuuviCore/Sources/RuuviCoreLocation/RuuviCoreLocationImpl.swift @@ -1,27 +1,26 @@ -import Foundation import CoreLocation +import Foundation import Future import RuuviCore public final class RuuviCoreLocationImpl: NSObject, RuuviCoreLocation { public var isLocationPermissionGranted: Bool { - - return CLLocationManager.locationServicesEnabled() - && (CLLocationManager.authorizationStatus() == .authorizedWhenInUse + CLLocationManager.locationServicesEnabled() + && (CLLocationManager.authorizationStatus() == .authorizedWhenInUse || CLLocationManager.authorizationStatus() == .authorizedAlways) } public var locationAuthorizationStatus: CLAuthorizationStatus { - return CLLocationManager.authorizationStatus() + CLLocationManager.authorizationStatus() } var isLocationPermissionDenied: Bool { - return !CLLocationManager.locationServicesEnabled() + !CLLocationManager.locationServicesEnabled() || CLLocationManager.authorizationStatus() == .denied || CLLocationManager.authorizationStatus() == .denied } var isLocationPermissionNotDetermined: Bool { - return CLLocationManager.authorizationStatus() == .notDetermined + CLLocationManager.authorizationStatus() == .notDetermined } private var locationManager: CLLocationManager @@ -64,11 +63,11 @@ public final class RuuviCoreLocationImpl: NSObject, RuuviCoreLocation { } extension RuuviCoreLocationImpl: CLLocationManagerDelegate { - public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { + public func locationManager(_: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { requestLocationPermissionCallback?(status == .authorizedWhenInUse || status == .authorizedAlways) } - public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { + public func locationManager(_: CLLocationManager, didUpdateLocations locations: [CLLocation]) { locationManager.stopUpdatingLocation() if let location = locations.last { getCurrentLocationPromise?.succeed(value: location) @@ -77,8 +76,7 @@ extension RuuviCoreLocationImpl: CLLocationManagerDelegate { } } - public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { + public func locationManager(_: CLLocationManager, didFailWithError error: Error) { print(error.localizedDescription) } - } diff --git a/Packages/RuuviCore/Sources/RuuviCorePN/RuuviCorePNImpl.swift b/Packages/RuuviCore/Sources/RuuviCorePN/RuuviCorePNImpl.swift index 714197147..29ee43e9b 100644 --- a/Packages/RuuviCore/Sources/RuuviCorePN/RuuviCorePNImpl.swift +++ b/Packages/RuuviCore/Sources/RuuviCorePN/RuuviCorePNImpl.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviCore +import UIKit import UserNotifications public final class RuuviCorePNImpl: NSObject, RuuviCorePN { @@ -9,7 +9,7 @@ public final class RuuviCorePNImpl: NSObject, RuuviCorePN { public var pnTokenData: Data? { get { - return UserDefaults.standard.data(forKey: pnTokenDataUDKey) + UserDefaults.standard.data(forKey: pnTokenDataUDKey) } set { UserDefaults.standard.set(newValue, forKey: pnTokenDataUDKey) @@ -18,7 +18,7 @@ public final class RuuviCorePNImpl: NSObject, RuuviCorePN { public var fcmToken: String? { get { - return UserDefaults.standard.string(forKey: pnFCMTokenUDKey) + UserDefaults.standard.string(forKey: pnFCMTokenUDKey) } set { UserDefaults.standard.set(newValue, forKey: pnFCMTokenUDKey) @@ -27,7 +27,7 @@ public final class RuuviCorePNImpl: NSObject, RuuviCorePN { public var fcmTokenId: Int? { get { - return UserDefaults.standard.integer(forKey: pnFCMTokenIdUDKey) + UserDefaults.standard.integer(forKey: pnFCMTokenIdUDKey) } set { UserDefaults.standard.set(newValue, forKey: pnFCMTokenIdUDKey) @@ -36,7 +36,7 @@ public final class RuuviCorePNImpl: NSObject, RuuviCorePN { public var fcmTokenLastRefreshed: Date? { get { - return UserDefaults + UserDefaults .standard .object(forKey: pnFCMTokenLastRefreshUDKey) as? Date } @@ -47,7 +47,7 @@ public final class RuuviCorePNImpl: NSObject, RuuviCorePN { public func getRemoteNotificationsAuthorizationStatus(completion: @escaping (PNAuthorizationStatus) -> Void) { if #available(iOS 10.0, *) { - UNUserNotificationCenter.current().getNotificationSettings { (settings) in + UNUserNotificationCenter.current().getNotificationSettings { settings in DispatchQueue.main.async { switch settings.authorizationStatus { case .authorized: @@ -78,8 +78,8 @@ public final class RuuviCorePNImpl: NSObject, RuuviCorePN { public func registerForRemoteNotifications() { if #available(iOS 10.0, *) { - let center = UNUserNotificationCenter.current() - center.requestAuthorization(options: [.sound, .alert, .badge]) { (_, error) in + let center = UNUserNotificationCenter.current() + center.requestAuthorization(options: [.sound, .alert, .badge]) { _, error in if error == nil { DispatchQueue.main.async { self.didAskForRemoteNotificationPermission = true @@ -102,10 +102,10 @@ public final class RuuviCorePNImpl: NSObject, RuuviCorePN { private let pnFCMTokenIdUDKey = "PushNotificationsManagerImpl.pnFCMTokenIdUDKey" private let pnFCMTokenLastRefreshUDKey = "PushNotificationsManagerImpl.pnFCMTokenLastRefreshUDKey" private let didAskForRemoteNotificationPermissionUDKey = - "PushNotificationsManagerImpl.didAskForRemoteNotificationPermissionUDKey" + "PushNotificationsManagerImpl.didAskForRemoteNotificationPermissionUDKey" private var didAskForRemoteNotificationPermission: Bool { get { - return UserDefaults.standard.bool(forKey: didAskForRemoteNotificationPermissionUDKey) + UserDefaults.standard.bool(forKey: didAskForRemoteNotificationPermissionUDKey) } set { UserDefaults.standard.set(newValue, forKey: didAskForRemoteNotificationPermissionUDKey) diff --git a/Packages/RuuviCore/Sources/RuuviCorePermission/RuuviCorePermissionImpl.swift b/Packages/RuuviCore/Sources/RuuviCorePermission/RuuviCorePermissionImpl.swift index 74c83966e..b22f45b5d 100644 --- a/Packages/RuuviCore/Sources/RuuviCorePermission/RuuviCorePermissionImpl.swift +++ b/Packages/RuuviCore/Sources/RuuviCorePermission/RuuviCorePermissionImpl.swift @@ -10,58 +10,58 @@ public final class RuuviCorePermissionImpl: RuuviCorePermission { } public var isPhotoLibraryPermissionGranted: Bool { - return PHPhotoLibrary.authorizationStatus() == .authorized + PHPhotoLibrary.authorizationStatus() == .authorized } public var photoLibraryAuthorizationStatus: PHAuthorizationStatus { - return PHPhotoLibrary.authorizationStatus() + PHPhotoLibrary.authorizationStatus() } public var isCameraPermissionGranted: Bool { #if targetEnvironment(macCatalyst) - return false + return false #else - return AVCaptureDevice.authorizationStatus(for: .video) == .authorized + return AVCaptureDevice.authorizationStatus(for: .video) == .authorized #endif } #if targetEnvironment(macCatalyst) #else - public var cameraAuthorizationStatus: AVAuthorizationStatus { - return AVCaptureDevice.authorizationStatus(for: .video) - } + public var cameraAuthorizationStatus: AVAuthorizationStatus { + AVCaptureDevice.authorizationStatus(for: .video) + } #endif public var isLocationPermissionGranted: Bool { - return locationManager.isLocationPermissionGranted + locationManager.isLocationPermissionGranted } public var locationAuthorizationStatus: CLAuthorizationStatus { - return locationManager.locationAuthorizationStatus + locationManager.locationAuthorizationStatus } public func requestPhotoLibraryPermission(completion: ((Bool) -> Void)?) { - PHPhotoLibrary.requestAuthorization({ (status) in + PHPhotoLibrary.requestAuthorization { status in DispatchQueue.main.async { completion?(status == .authorized) } - }) + } } public func requestCameraPermission(completion: ((Bool) -> Void)?) { #if targetEnvironment(macCatalyst) - completion?(false) + completion?(false) #else - AVCaptureDevice.requestAccess(for: .video) { (granted) in - DispatchQueue.main.async { - completion?(granted) + AVCaptureDevice.requestAccess(for: .video) { granted in + DispatchQueue.main.async { + completion?(granted) + } } - } #endif } public func requestLocationPermission(completion: ((Bool) -> Void)?) { - locationManager.requestLocationPermission { (granted) in + locationManager.requestLocationPermission { granted in DispatchQueue.main.async { completion?(granted) } diff --git a/Packages/RuuviCore/Tests/RuuviCoreTests/RuuviCoreTests.swift b/Packages/RuuviCore/Tests/RuuviCoreTests/RuuviCoreTests.swift index 739125486..859cfdb72 100644 --- a/Packages/RuuviCore/Tests/RuuviCoreTests/RuuviCoreTests.swift +++ b/Packages/RuuviCore/Tests/RuuviCoreTests/RuuviCoreTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviCore +import XCTest final class RuuviCoreTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Packages/RuuviDFU/Package.swift b/Packages/RuuviDFU/Package.swift index ba3c61b60..5897c0669 100644 --- a/Packages/RuuviDFU/Package.swift +++ b/Packages/RuuviDFU/Package.swift @@ -9,33 +9,37 @@ let package = Package( products: [ .library( name: "RuuviDFU", - targets: ["RuuviDFU"]), + targets: ["RuuviDFU"] + ), .library( name: "RuuviDFUImpl", - targets: ["RuuviDFUImpl"]) + targets: ["RuuviDFUImpl"] + ), ], dependencies: [ .package( name: "NordicDFU", url: "https://github.com/NordicSemiconductor/IOS-Pods-DFU-Library", - from: "4.10.3") + from: "4.10.3" + ), ], targets: [ .target( name: "RuuviDFU", dependencies: [ - "NordicDFU" + "NordicDFU", ] ), .target( name: "RuuviDFUImpl", dependencies: [ "RuuviDFU", - "NordicDFU" + "NordicDFU", ] ), .testTarget( name: "RuuviDFUTests", - dependencies: ["RuuviDFU"]) + dependencies: ["RuuviDFU"] + ), ] ) diff --git a/Packages/RuuviDFU/Sources/RuuviDFU/DFUDevice.swift b/Packages/RuuviDFU/Sources/RuuviDFU/DFUDevice.swift index 629da8555..41815b2a9 100644 --- a/Packages/RuuviDFU/Sources/RuuviDFU/DFUDevice.swift +++ b/Packages/RuuviDFU/Sources/RuuviDFU/DFUDevice.swift @@ -25,5 +25,5 @@ extension DFUDevice: Equatable, Hashable { } public func == (lhs: DFUDevice, rhs: DFUDevice) -> Bool { - return lhs.uuid == rhs.uuid + lhs.uuid == rhs.uuid } diff --git a/Packages/RuuviDFU/Sources/RuuviDFU/RuuviDFU.swift b/Packages/RuuviDFU/Sources/RuuviDFU/RuuviDFU.swift index 7e87ad731..4a87d23e2 100644 --- a/Packages/RuuviDFU/Sources/RuuviDFU/RuuviDFU.swift +++ b/Packages/RuuviDFU/Sources/RuuviDFU/RuuviDFU.swift @@ -1,10 +1,10 @@ -import Foundation import Combine +import Foundation #if canImport(NordicDFU) -import NordicDFU + import NordicDFU #endif #if canImport(iOSDFULibrary) -import iOSDFULibrary + import iOSDFULibrary #endif public enum FlashResponse { diff --git a/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift b/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift index b61658432..c8702aede 100644 --- a/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift +++ b/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift @@ -1,11 +1,11 @@ +import Combine import Foundation import RuuviDFU -import Combine #if canImport(NordicDFU) -import NordicDFU + import NordicDFU #endif #if canImport(iOSDFULibrary) -import iOSDFULibrary + import iOSDFULibrary #endif class DfuFlasher: NSObject { @@ -44,7 +44,7 @@ class DfuFlasher: NSObject { return subject.eraseToAnyPublisher() } - func stopFlashFirmware(device: DFUDevice) -> Bool { + func stopFlashFirmware(device _: DFUDevice) -> Bool { guard let serviceController = dfuServiceController else { return false } @@ -65,7 +65,7 @@ extension DfuFlasher: DFUServiceDelegate { } } - func dfuError(_ error: DFUError, didOccurWithMessage message: String) { + func dfuError(_: DFUError, didOccurWithMessage message: String) { subject?.send(completion: .failure(RuuviDfuError(description: message))) } } @@ -74,8 +74,9 @@ extension DfuFlasher: DFUProgressDelegate { func dfuProgressDidChange(for part: Int, outOf totalParts: Int, to progress: Int, - currentSpeedBytesPerSecond: Double, - avgSpeedBytesPerSecond: Double) { + currentSpeedBytesPerSecond _: Double, + avgSpeedBytesPerSecond _: Double) + { guard let parts = firmware?.parts else { return } diff --git a/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuScanner.swift b/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuScanner.swift index e933580ad..803f1720d 100644 --- a/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuScanner.swift +++ b/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuScanner.swift @@ -1,5 +1,5 @@ -import Foundation import CoreBluetooth +import Foundation import RuuviDFU import UIKit @@ -15,9 +15,8 @@ class DfuScanner: NSObject { } private let queue = DispatchQueue(label: "DfuScanner", qos: .userInteractive) - private lazy var manager: CBCentralManager = { - return CBCentralManager(delegate: self, queue: queue) - }() + private lazy var manager: CBCentralManager = .init(delegate: self, queue: queue) + private var lastSeen = [DFUDevice: Date]() private var lostTimer: DispatchSourceTimer? @@ -29,33 +28,33 @@ class DfuScanner: NSObject { private let scanServices = [ CBUUID(string: "00001530-1212-EFDE-1523-785FEABCD123"), CBUUID(string: "FE59"), - CBUUID(string: "180A") + CBUUID(string: "180A"), ] deinit { NotificationCenter.default.removeObserver(self) } - required override init() { + override required init() { super.init() NotificationCenter.default.addObserver(self, - selector: #selector(self.willResignActiveNotification(_:)), + selector: #selector(willResignActiveNotification(_:)), name: UIApplication.willResignActiveNotification, object: nil) NotificationCenter.default.addObserver(self, - selector: #selector(self.didBecomeActiveNotification(_:)), + selector: #selector(didBecomeActiveNotification(_:)), name: UIApplication.didBecomeActiveNotification, object: nil) queue.async { [weak self] in self?.startIfNeeded() } } - @objc func willResignActiveNotification(_ notification: Notification) { + @objc func willResignActiveNotification(_: Notification) { queue.async { [weak self] in self?.manager.stopScan() } } - @objc func didBecomeActiveNotification(_ notification: Notification) { + @objc func didBecomeActiveNotification(_: Notification) { queue.async { [weak self] in self?.startIfNeeded() } @@ -76,7 +75,7 @@ class DfuScanner: NSObject { } private func notifyLostDevices() { - observations.lost.values.forEach { (observation) in + observations.lost.values.forEach { observation in var lostDevices = [DFUDevice]() for (device, seen) in lastSeen { let elapsed = Date().timeIntervalSince(seen) @@ -92,12 +91,12 @@ class DfuScanner: NSObject { } private func startIfNeeded() { - if manager.state == .poweredOn && !manager.isScanning { + if manager.state == .poweredOn, !manager.isScanning { manager.scanForPeripherals(withServices: scanServices, options: [CBCentralManagerScanOptionAllowDuplicatesKey: NSNumber(value: true)]) } let shouldObserveLostDevices = observations.lost.count > 0 - if shouldObserveLostDevices && lostTimer == nil { + if shouldObserveLostDevices, lostTimer == nil { startLostDevicesTimer() } } @@ -107,7 +106,7 @@ class DfuScanner: NSObject { manager.stopScan() } let shouldObserveLostDevices = observations.lost.count > 0 - if !shouldObserveLostDevices && lostTimer != nil { + if !shouldObserveLostDevices, lostTimer != nil { stopLostDevicesTimer() } } @@ -117,7 +116,7 @@ class DfuScanner: NSObject { let id = UUID() queue.async { [weak self] in self?.observations.device[id] = { [weak self, weak observer] device in - guard let observer = observer else { + guard let observer else { self?.observations.device.removeValue(forKey: id) self?.stopIfNeeded() return @@ -141,8 +140,8 @@ class DfuScanner: NSObject { func lost(_ observer: T, closure: @escaping (T, DFUDevice) -> Void) -> RuuviDFUToken { let id = UUID() queue.async { [weak self] in - self?.observations.lost[id] = LostObservation(block: { [weak self, weak observer] (device) in - guard let observer = observer else { + self?.observations.lost[id] = LostObservation(block: { [weak self, weak observer] device in + guard let observer else { self?.observations.lost.removeValue(forKey: id) self?.stopIfNeeded() return @@ -164,23 +163,24 @@ class DfuScanner: NSObject { } extension DfuScanner: CBCentralManagerDelegate { - func centralManagerDidUpdateState(_ central: CBCentralManager) { + func centralManagerDidUpdateState(_: CBCentralManager) { queue.async { [weak self] in self?.startIfNeeded() } } - func centralManager(_ central: CBCentralManager, + func centralManager(_: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], - rssi RSSI: NSNumber) { + rssi RSSI: NSNumber) + { guard RSSI.intValue != 127 else { return } let uuid = peripheral.identifier.uuidString let isConnectable = (advertisementData[CBAdvertisementDataIsConnectable] as? NSNumber)?.boolValue ?? false let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String let dfuDevice = DFUDevice(uuid: uuid, rssi: RSSI.intValue, isConnectable: isConnectable, name: name) lastSeen[dfuDevice] = Date() - observations.device.values.forEach { (closure) in + observations.device.values.forEach { closure in closure(dfuDevice) } } diff --git a/Packages/RuuviDFU/Sources/RuuviDFUImpl/RuuviDFUImpl.swift b/Packages/RuuviDFU/Sources/RuuviDFUImpl/RuuviDFUImpl.swift index 6d147af53..27649a9eb 100644 --- a/Packages/RuuviDFU/Sources/RuuviDFUImpl/RuuviDFUImpl.swift +++ b/Packages/RuuviDFU/Sources/RuuviDFUImpl/RuuviDFUImpl.swift @@ -1,11 +1,11 @@ +import Combine import Foundation import RuuviDFU -import Combine #if canImport(NordicDFU) -import NordicDFU + import NordicDFU #endif #if canImport(iOSDFULibrary) -import iOSDFULibrary + import iOSDFULibrary #endif public struct RuuviDFUImpl: RuuviDFU { @@ -19,7 +19,7 @@ public struct RuuviDFUImpl: RuuviDFU { _ observer: T, closure: @escaping (T, DFUDevice) -> Void ) -> RuuviDFUToken { - return scanner.scan(observer, closure: closure) + scanner.scan(observer, closure: closure) } @discardableResult @@ -27,21 +27,21 @@ public struct RuuviDFUImpl: RuuviDFU { _ observer: T, closure: @escaping (T, DFUDevice) -> Void ) -> RuuviDFUToken { - return scanner.lost(observer, closure: closure) + scanner.lost(observer, closure: closure) } public func firmwareFromUrl(url: URL) -> DFUFirmware? { - return try? DFUFirmware(urlToZipFile: url, type: .softdeviceBootloaderApplication) + try? DFUFirmware(urlToZipFile: url, type: .softdeviceBootloaderApplication) } public func flashFirmware( uuid: String, with firmware: DFUFirmware ) -> AnyPublisher { - return flasher.flashFirmware(uuid: uuid, with: firmware) + flasher.flashFirmware(uuid: uuid, with: firmware) } public func stopFlashFirmware(device: DFUDevice) -> Bool { - return flasher.stopFlashFirmware(device: device) + flasher.stopFlashFirmware(device: device) } } diff --git a/Packages/RuuviDFU/Tests/RuuviDFUTests/RuuviDFUTests.swift b/Packages/RuuviDFU/Tests/RuuviDFUTests/RuuviDFUTests.swift index dace63ca0..73dbf66c7 100644 --- a/Packages/RuuviDFU/Tests/RuuviDFUTests/RuuviDFUTests.swift +++ b/Packages/RuuviDFU/Tests/RuuviDFUTests/RuuviDFUTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviDFU +import XCTest final class RuuviDFUTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Packages/RuuviDaemon/Package.swift b/Packages/RuuviDaemon/Package.swift index e7525a35d..9ed7f0b45 100644 --- a/Packages/RuuviDaemon/Package.swift +++ b/Packages/RuuviDaemon/Package.swift @@ -9,19 +9,24 @@ let package = Package( products: [ .library( name: "RuuviDaemon", - targets: ["RuuviDaemon"]), + targets: ["RuuviDaemon"] + ), .library( name: "RuuviDaemonCloudSync", - targets: ["RuuviDaemonCloudSync"]), + targets: ["RuuviDaemonCloudSync"] + ), .library( name: "RuuviDaemonOperation", - targets: ["RuuviDaemonOperation"]), + targets: ["RuuviDaemonOperation"] + ), .library( name: "RuuviDaemonBackground", - targets: ["RuuviDaemonBackground"]), + targets: ["RuuviDaemonBackground"] + ), .library( name: "RuuviDaemonRuuviTag", - targets: ["RuuviDaemonRuuviTag"]), + targets: ["RuuviDaemonRuuviTag"] + ), ], dependencies: [ .package(path: "../RuuviOntology"), @@ -33,7 +38,7 @@ let package = Package( .package(path: "../RuuviPersistence"), .package(path: "../RuuviNotifier"), .package(path: "../RuuviNotification"), - .package(url: "https://github.com/ruuvi/BTKit", .upToNextMinor(from: "0.4.3")) + .package(url: "https://github.com/ruuvi/BTKit", .upToNextMinor(from: "0.4.3")), ], targets: [ .target( @@ -46,7 +51,7 @@ let package = Package( "RuuviPool", "RuuviPersistence", "RuuviNotifier", - "BTKit" + "BTKit", ] ), .target( @@ -54,7 +59,7 @@ let package = Package( dependencies: [ "RuuviDaemon", "RuuviLocal", - "RuuviService" + "RuuviService", ] ), .target( @@ -69,7 +74,7 @@ let package = Package( name: "RuuviDaemonBackground", dependencies: [ "RuuviDaemon", - "RuuviDaemonOperation" + "RuuviDaemonOperation", ] ), .target( @@ -77,11 +82,12 @@ let package = Package( dependencies: [ "RuuviDaemon", "RuuviDaemonOperation", - "RuuviNotification" + "RuuviNotification", ] ), .testTarget( name: "RuuviDaemonTests", - dependencies: ["RuuviDaemon"]) + dependencies: ["RuuviDaemon"] + ), ] ) diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviDaemonError.swift b/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviDaemonError.swift index 3250c5f8e..b12b45f14 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviDaemonError.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviDaemonError.swift @@ -1,9 +1,9 @@ +import BTKit import Foundation -import RuuviStorage -import RuuviReactor -import RuuviPool import RuuviPersistence -import BTKit +import RuuviPool +import RuuviReactor +import RuuviStorage public enum RuuviDaemonError: Error { case ruuviStorage(RuuviStorageError) diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviDaemonWorker.swift b/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviDaemonWorker.swift index 42b5fa3e4..109cd9e77 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviDaemonWorker.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviDaemonWorker.swift @@ -6,7 +6,7 @@ open class RuuviDaemonWorker: NSObject { override public init() {} - @objc internal func runBlock() { + @objc func runBlock() { autoreleasepool { block?() } @@ -23,7 +23,8 @@ open class RuuviDaemonWorker: NSObject { while !(self?.thread.isCancelled ?? true) { RunLoop.current.run( mode: RunLoop.Mode.default, - before: Date.distantFuture) + before: Date.distantFuture + ) } } thread.name = "\(threadName)-\(UUID().uuidString)" diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviTagAdvertisementDaemon.swift b/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviTagAdvertisementDaemon.swift index 5a4ab1bc5..cd3c5e725 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviTagAdvertisementDaemon.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviTagAdvertisementDaemon.swift @@ -1,10 +1,10 @@ import Foundation -extension Notification.Name { - public static let RuuviTagAdvertisementDaemonDidFail = Notification.Name( +public extension Notification.Name { + static let RuuviTagAdvertisementDaemonDidFail = Notification.Name( "RuuviTagAdvertisementDaemonDidFail" ) - public static let RuuviTagAdvertisementDaemonShouldRestart = Notification.Name( + static let RuuviTagAdvertisementDaemonShouldRestart = Notification.Name( "RuuviTagAdvertisementDaemonShouldRestart" ) } diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviTagHeartbeatDaemon.swift b/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviTagHeartbeatDaemon.swift index bb169f982..f28d659cd 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviTagHeartbeatDaemon.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviTagHeartbeatDaemon.swift @@ -1,9 +1,9 @@ import Foundation import Future -extension Notification.Name { - public static let RuuviTagHeartbeatDaemonDidFail = Notification.Name("RuuviTagHeartbeatDaemonDidFail") - public static let RuuviTagHeartBeatDaemonShouldRestart = Notification.Name("RuuviTagHeartBeatDaemonShouldRestart") +public extension Notification.Name { + static let RuuviTagHeartbeatDaemonDidFail = Notification.Name("RuuviTagHeartbeatDaemonDidFail") + static let RuuviTagHeartBeatDaemonShouldRestart = Notification.Name("RuuviTagHeartBeatDaemonShouldRestart") } public enum RuuviTagHeartbeatDaemonDidFailKey: String { diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviTagPropertiesDaemon.swift b/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviTagPropertiesDaemon.swift index baa7f1589..369aa670b 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviTagPropertiesDaemon.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviTagPropertiesDaemon.swift @@ -1,7 +1,7 @@ import Foundation -extension Notification.Name { - public static let RuuviTagPropertiesDaemonDidFail = Notification.Name("RuuviTagPropertiesDaemonDidFail") +public extension Notification.Name { + static let RuuviTagPropertiesDaemonDidFail = Notification.Name("RuuviTagPropertiesDaemonDidFail") } public enum RuuviTagPropertiesDaemonDidFailKey: String { diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift index 2886731e3..ab2a7b609 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift @@ -1,9 +1,9 @@ -import Foundation import BackgroundTasks +import Foundation import Future import RuuviDaemon #if canImport(RuuviDaemonOperation) -import RuuviDaemonOperation + import RuuviDaemonOperation #endif @available(iOS 13, *) @@ -63,5 +63,4 @@ public final class BackgroundProcessServiceiOS13: BackgroundProcessService { task.setTaskCompleted(success: false) }) } - } diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift index f4a528451..890750e4e 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift @@ -1,7 +1,7 @@ import Foundation +import RuuviDaemon import RuuviLocal import RuuviService -import RuuviDaemon class RuuviDaemonCloudSyncWorker: RuuviDaemonWorker, RuuviDaemonCloudSync { private var localSettings: RuuviLocalSettings @@ -39,7 +39,7 @@ class RuuviDaemonCloudSyncWorker: RuuviDaemonWorker, RuuviDaemonCloudSync { } func stop() { - guard let thread = thread else { + guard let thread else { return } perform(#selector(RuuviDaemonCloudSyncWorker.stopDaemon), diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonFactoryCloudSync.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonFactoryCloudSync.swift index 3d28d87b3..3f2284c93 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonFactoryCloudSync.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonFactoryCloudSync.swift @@ -1,7 +1,7 @@ import Foundation +import RuuviDaemon import RuuviLocal import RuuviService -import RuuviDaemon public final class RuuviDaemonFactoryImpl: RuuviDaemonFactory { public init() {} @@ -11,7 +11,7 @@ public final class RuuviDaemonFactoryImpl: RuuviDaemonFactory { localSyncState: RuuviLocalSyncState, cloudSyncService: RuuviServiceCloudSync ) -> RuuviDaemonCloudSync { - return RuuviDaemonCloudSyncWorker( + RuuviDaemonCloudSyncWorker( localSettings: localSettings, localSyncState: localSyncState, cloudSyncService: cloudSyncService diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/AsyncOperation.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/AsyncOperation.swift index e455f1cbe..c57db8777 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/AsyncOperation.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/AsyncOperation.swift @@ -1,55 +1,53 @@ import Foundation class AsyncOperation: Operation { - enum State: String { - case ready, executing, finished + case ready, executing, finished - fileprivate var keyPath: String { - return "is" + rawValue.capitalized + fileprivate var keyPath: String { + "is" + rawValue.capitalized + } } - } - var state = State.ready { - willSet { - willChangeValue(forKey: newValue.keyPath) - willChangeValue(forKey: state.keyPath) - } - didSet { - didChangeValue(forKey: oldValue.keyPath) - didChangeValue(forKey: state.keyPath) + var state = State.ready { + willSet { + willChangeValue(forKey: newValue.keyPath) + willChangeValue(forKey: state.keyPath) + } + didSet { + didChangeValue(forKey: oldValue.keyPath) + didChangeValue(forKey: state.keyPath) + } } - } } extension AsyncOperation { - override var isReady: Bool { - return super.isReady && state == .ready - } - - override var isExecuting: Bool { - return state == .executing - } + override var isReady: Bool { + super.isReady && state == .ready + } - override var isFinished: Bool { - return state == .finished - } + override var isExecuting: Bool { + state == .executing + } - override var isAsynchronous: Bool { - return true - } + override var isFinished: Bool { + state == .finished + } - override func start() { - if isCancelled { - state = .finished - return + override var isAsynchronous: Bool { + true } - main() - state = .executing - } - override func cancel() { - state = .finished - } + override func start() { + if isCancelled { + state = .finished + return + } + main() + state = .executing + } + override func cancel() { + state = .finished + } } diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/DataPruningOperationsManager.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/DataPruningOperationsManager.swift index 1552f81bb..831c9657f 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/DataPruningOperationsManager.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/DataPruningOperationsManager.swift @@ -1,9 +1,9 @@ import Foundation import Future -import RuuviStorage +import RuuviDaemon import RuuviLocal import RuuviPool -import RuuviDaemon +import RuuviStorage public final class DataPruningOperationsManager { private let settings: RuuviLocalSettings @@ -24,18 +24,17 @@ public final class DataPruningOperationsManager { let promise = Promise<[Operation], RuuviDaemonError>() ruuviStorage.readAll().on(success: { [weak self] ruuviTags in guard let sSelf = self else { return } - let ops = ruuviTags.map({ + let ops = ruuviTags.map { RuuviTagDataPruningOperation( id: $0.id, ruuviPool: sSelf.ruuviPool, settings: sSelf.settings ) - }) + } promise.succeed(value: ops) }, failure: { error in promise.fail(error: .ruuviStorage(error)) }) return promise.future } - } diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/RuuviTagDataPruningOperation.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/RuuviTagDataPruningOperation.swift index 881c7a9fe..12c6e7a6f 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/RuuviTagDataPruningOperation.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/RuuviTagDataPruningOperation.swift @@ -3,7 +3,6 @@ import RuuviLocal import RuuviPool class RuuviTagDataPruningOperation: AsyncOperation { - private var id: String private var settings: RuuviLocalSettings private var ruuviPool: RuuviPool diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Advertisement/RuuviTagAdvertisementDaemonBTKit.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Advertisement/RuuviTagAdvertisementDaemonBTKit.swift index cf1de7750..eae63238a 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Advertisement/RuuviTagAdvertisementDaemonBTKit.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Advertisement/RuuviTagAdvertisementDaemonBTKit.swift @@ -1,12 +1,12 @@ import BTKit import Foundation -import RuuviOntology -import RuuviStorage -import RuuviReactor +import RuuviDaemon import RuuviLocal -import RuuviPool +import RuuviOntology import RuuviPersistence -import RuuviDaemon +import RuuviPool +import RuuviReactor +import RuuviStorage // swiftlint:disable:next type_body_length public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTagAdvertisementDaemon { @@ -26,8 +26,9 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag private var cloudModeOnToken: NSObjectProtocol? private var daemonRestartToken: NSObjectProtocol? private var saveInterval: TimeInterval { - return TimeInterval(settings.advertisementDaemonIntervalMinutes * 60) + TimeInterval(settings.advertisementDaemonIntervalMinutes * 60) } + private var advertisementSequence = [String: Int?]() // uuid: int @objc private class RuuviTagWrapper: NSObject { @@ -38,18 +39,18 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag } deinit { - observeTokens.forEach({ $0.invalidate() }) + observeTokens.forEach { $0.invalidate() } observeTokens.removeAll() ruuviTagsToken?.invalidate() - if let isOnToken = isOnToken { + if let isOnToken { NotificationCenter.default.removeObserver(isOnToken) } - sensorSettingsTokens.forEach({ $0.invalidate() }) + sensorSettingsTokens.forEach { $0.invalidate() } sensorSettingsTokens.removeAll() - if let cloudModeOnToken = cloudModeOnToken { + if let cloudModeOnToken { NotificationCenter.default.removeObserver(cloudModeOnToken) } - if let daemonRestartToken = daemonRestartToken { + if let daemonRestartToken { NotificationCenter.default.removeObserver(daemonRestartToken) } } @@ -71,58 +72,61 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag .default .addObserver(forName: .isAdvertisementDaemonOnDidChange, object: nil, - queue: .main) { [weak self] _ in - guard let sSelf = self else { return } - if sSelf.settings.isAdvertisementDaemonOn { - sSelf.start() - } else { - sSelf.stop() - } + queue: .main) + { [weak self] _ in + guard let sSelf = self else { return } + if sSelf.settings.isAdvertisementDaemonOn { + sSelf.start() + } else { + sSelf.stop() } + } cloudModeOnToken = NotificationCenter .default .addObserver(forName: .CloudModeDidChange, object: nil, - queue: .main) { [weak self] _ in - guard let sSelf = self else { return } - sSelf.restartObserving() - } + queue: .main) + { [weak self] _ in + guard let sSelf = self else { return } + sSelf.restartObserving() + } daemonRestartToken = NotificationCenter .default .addObserver(forName: .RuuviTagAdvertisementDaemonShouldRestart, object: nil, - queue: .main) { [weak self] _ in - guard let sSelf = self else { return } - sSelf.restart() - } + queue: .main) + { [weak self] _ in + guard let sSelf = self else { return } + sSelf.restart() + } } public func start() { start { [weak self] in - self?.ruuviTagsToken = self?.ruuviReactor.observe({ [weak self] change in + self?.ruuviTagsToken = self?.ruuviReactor.observe { [weak self] change in guard let sSelf = self else { return } switch change { - case .initial(let ruuviTags): + case let .initial(ruuviTags): sSelf.ruuviTags = ruuviTags sSelf.reloadSensorSettings() sSelf.restartObserving() - case .update(let ruuviTag): + case let .update(ruuviTag): if let index = sSelf.ruuviTags.firstIndex(of: ruuviTag) { sSelf.ruuviTags[index] = ruuviTag } sSelf.restartObserving() - case .insert(let ruuviTag): + case let .insert(ruuviTag): sSelf.ruuviTags.append(ruuviTag) sSelf.restartObserving() - case .delete(let ruuviTag): + case let .delete(ruuviTag): sSelf.ruuviTags.removeAll(where: { $0.id == ruuviTag.id }) sSelf.restartObserving() - case .error(let error): + case let .error(error): sSelf.post(error: .ruuviReactor(error)) } - }) + } } } @@ -142,18 +146,19 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag } @objc private func stopDaemon() { - observeTokens.forEach({ $0.invalidate() }) + observeTokens.forEach { $0.invalidate() } observeTokens.removeAll() - sensorSettingsTokens.forEach({ $0.invalidate() }) + sensorSettingsTokens.forEach { $0.invalidate() } sensorSettingsTokens.removeAll() ruuviTagsToken?.invalidate() stopWork() } + private func reloadSensorSettings() { sensorSettingsList.removeAll() ruuviTags.forEach { ruuviTag in - ruuviStorage.readSensorSettings(ruuviTag).on {[weak self] sensorSettings in - if let sensorSettings = sensorSettings { + ruuviStorage.readSensorSettings(ruuviTag).on { [weak self] sensorSettings in + if let sensorSettings { self?.sensorSettingsList.append(sensorSettings) } } @@ -162,10 +167,10 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag // swiftlint:disable:next cyclomatic_complexity private func restartObserving() { - observeTokens.forEach({ $0.invalidate() }) + observeTokens.forEach { $0.invalidate() } observeTokens.removeAll() - sensorSettingsTokens.forEach({ $0.invalidate() }) + sensorSettingsTokens.forEach { $0.invalidate() } sensorSettingsTokens.removeAll() for ruuviTag in ruuviTags { @@ -176,30 +181,31 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag guard let luid = ruuviTag.luid else { continue } observeTokens.append(foreground.observe(self, uuid: luid.value, - options: [.callbackQueue(.untouch)]) { - [weak self] (_, device) in - guard let sSelf = self else { return } - if let tag = device.ruuvi?.tag, !tag.isConnected { - sSelf.perform(#selector(RuuviTagAdvertisementDaemonBTKit.persist(wrapper:)), - on: sSelf.thread, - with: RuuviTagWrapper(device: tag), - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) - } - }) - sensorSettingsTokens.append(ruuviReactor.observe(ruuviTag, { [weak self] change in + options: [.callbackQueue(.untouch)]) + { + [weak self] _, device in + guard let sSelf = self else { return } + if let tag = device.ruuvi?.tag, !tag.isConnected { + sSelf.perform(#selector(RuuviTagAdvertisementDaemonBTKit.persist(wrapper:)), + on: sSelf.thread, + with: RuuviTagWrapper(device: tag), + waitUntilDone: false, + modes: [RunLoop.Mode.default.rawValue]) + } + }) + sensorSettingsTokens.append(ruuviReactor.observe(ruuviTag) { [weak self] change in switch change { - case .delete(let sensorSettings): + case let .delete(sensorSettings): if let dIndex = self?.sensorSettingsList.firstIndex( where: { $0.id == sensorSettings.id } ) { self?.sensorSettingsList.remove(at: dIndex) } - case .insert(let sensorSettings): + case let .insert(sensorSettings): self?.sensorSettingsList.append(sensorSettings) // remove last update timestamp to force add new record in db self?.savedDate.removeValue(forKey: luid.value) - case .update(let sensorSettings): + case let .update(sensorSettings): if let uIndex = self?.sensorSettingsList.firstIndex( where: { $0.id == sensorSettings.id } ) { @@ -210,7 +216,7 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag self?.savedDate.removeValue(forKey: luid.value) default: break } - })) + }) } } @@ -220,7 +226,7 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag // Otherwise respect the settings guard wrapper.device.luid != nil else { return } if settings.appIsOnForeground { - if let previous = advertisementSequence[uuid], let previous = previous { + if let previous = advertisementSequence[uuid], let previous { if let next = wrapper.device.measurementSequenceNumber, next > previous { persist(wrapper.device, uuid) } @@ -265,7 +271,7 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag ).on(success: { _ in self.createLatestRecord(with: record) }, failure: { [weak self] error in - if case RuuviPoolError.ruuviPersistence(let persistenceError) = error { + if case let RuuviPoolError.ruuviPersistence(persistenceError) = error { switch persistenceError { case .failedToFindRuuviTag: self?.ruuviTags.removeAll(where: { $0.id == uuid }) @@ -281,10 +287,11 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag private func createLatestRecord(with record: RuuviTag) { if let ruuviTag = ruuviTags.first(where: { if let luid = $0.luid?.value, let recordLuid = record.luid?.value, - luid == recordLuid { - return true + luid == recordLuid + { + true } else { - return false + false } }) { ruuviStorage.readLatest(ruuviTag).on(success: { [weak self] localRecord in diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Heartbeat/RuuviTagHeartbeatDaemonBTKit.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Heartbeat/RuuviTagHeartbeatDaemonBTKit.swift index aba8db255..4b56fa948 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Heartbeat/RuuviTagHeartbeatDaemonBTKit.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Heartbeat/RuuviTagHeartbeatDaemonBTKit.swift @@ -1,14 +1,14 @@ -import Foundation import BTKit -import RuuviOntology -import RuuviStorage -import RuuviReactor +import Foundation +import RuuviDaemon import RuuviLocal -import RuuviPool -import RuuviService import RuuviNotification import RuuviNotifier -import RuuviDaemon +import RuuviOntology +import RuuviPool +import RuuviReactor +import RuuviService +import RuuviStorage // swiftlint:disable file_length public final class RuuviTagHeartbeatDaemonBTKit: RuuviDaemonWorker, RuuviTagHeartbeatDaemon { @@ -64,16 +64,17 @@ public final class RuuviTagHeartbeatDaemonBTKit: RuuviDaemonWorker, RuuviTagHear .addObserver(forName: .ConnectionPersistenceDidStartToKeepConnection, object: nil, queue: .main, - using: { [weak self] (notification) in - guard let sSelf = self else { return } - if let userInfo = notification.userInfo, - let uuid = userInfo[CPDidStartToKeepConnectionKey.uuid] as? String { - sSelf.perform(#selector(RuuviTagHeartbeatDaemonBTKit.connect(uuid:)), - on: sSelf.thread, - with: uuid, - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) - } + using: { [weak self] notification in + guard let sSelf = self else { return } + if let userInfo = notification.userInfo, + let uuid = userInfo[CPDidStartToKeepConnectionKey.uuid] as? String + { + sSelf.perform(#selector(RuuviTagHeartbeatDaemonBTKit.connect(uuid:)), + on: sSelf.thread, + with: uuid, + waitUntilDone: false, + modes: [RunLoop.Mode.default.rawValue]) + } }) connectionRemovedToken = NotificationCenter @@ -81,48 +82,51 @@ public final class RuuviTagHeartbeatDaemonBTKit: RuuviDaemonWorker, RuuviTagHear .addObserver(forName: .ConnectionPersistenceDidStopToKeepConnection, object: nil, queue: .main, - using: { [weak self] (notification) in - guard let sSelf = self else { return } - if let userInfo = notification.userInfo, - let uuid = userInfo[CPDidStopToKeepConnectionKey.uuid] as? String { - sSelf.perform(#selector(RuuviTagHeartbeatDaemonBTKit.disconnect(uuid:)), - on: sSelf.thread, - with: uuid, - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) - } + using: { [weak self] notification in + guard let sSelf = self else { return } + if let userInfo = notification.userInfo, + let uuid = userInfo[CPDidStopToKeepConnectionKey.uuid] as? String + { + sSelf.perform(#selector(RuuviTagHeartbeatDaemonBTKit.disconnect(uuid:)), + on: sSelf.thread, + with: uuid, + waitUntilDone: false, + modes: [RunLoop.Mode.default.rawValue]) + } }) cloudModeOnToken = NotificationCenter .default .addObserver(forName: .CloudModeDidChange, object: nil, - queue: .main) { [weak self] _ in - guard let sSelf = self else { return } - sSelf.handleRuuviTagsChange() - } + queue: .main) + { [weak self] _ in + guard let sSelf = self else { return } + sSelf.handleRuuviTagsChange() + } daemonRestartToken = NotificationCenter .default .addObserver(forName: .RuuviTagHeartBeatDaemonShouldRestart, object: nil, - queue: .main) { [weak self] _ in - guard let sSelf = self else { return } - sSelf.handleRuuviTagsChange() - } + queue: .main) + { [weak self] _ in + guard let sSelf = self else { return } + sSelf.handleRuuviTagsChange() + } } deinit { invalidateTokens() - if let connectionAddedToken = connectionAddedToken { + if let connectionAddedToken { NotificationCenter.default.removeObserver(connectionAddedToken) } - if let connectionRemovedToken = connectionRemovedToken { + if let connectionRemovedToken { NotificationCenter.default.removeObserver(connectionRemovedToken) } - if let cloudModeOnToken = cloudModeOnToken { + if let cloudModeOnToken { NotificationCenter.default.removeObserver(cloudModeOnToken) } - if let daemonRestartToken = daemonRestartToken { + if let daemonRestartToken { NotificationCenter.default.removeObserver(daemonRestartToken) } } @@ -130,28 +134,27 @@ public final class RuuviTagHeartbeatDaemonBTKit: RuuviDaemonWorker, RuuviTagHear public func start() { start { [weak self] in self?.invalidateTokens() - self?.ruuviTagsToken = self?.ruuviReactor.observe({ [weak self] change in + self?.ruuviTagsToken = self?.ruuviReactor.observe { [weak self] change in guard let sSelf = self else { return } switch change { - case .initial(let ruuviTags): + case let .initial(ruuviTags): sSelf.ruuviTags = ruuviTags sSelf.handleRuuviTagsChange() - case .update(let ruuviTag): + case let .update(ruuviTag): if let index = sSelf.ruuviTags.firstIndex(of: ruuviTag) { sSelf.ruuviTags[index] = ruuviTag } sSelf.handleRuuviTagsChange() - case .insert(let ruuviTag): + case let .insert(ruuviTag): sSelf.ruuviTags.append(ruuviTag) sSelf.handleRuuviTagsChange() - case .delete(let ruuviTag): + case let .delete(ruuviTag): sSelf.ruuviTags.removeAll(where: { $0.id == ruuviTag.id }) sSelf.handleRuuviTagsChange() - case .error(let error): + case let .error(error): sSelf.post(error: .ruuviReactor(error)) } - }) - + } } } @@ -172,15 +175,16 @@ public final class RuuviTagHeartbeatDaemonBTKit: RuuviDaemonWorker, RuuviTagHear @objc private func stopDaemon() { invalidateTokens() - connectionPersistence.keepConnectionUUIDs.forEach({ disconnect(uuid: $0.value) }) + connectionPersistence.keepConnectionUUIDs.forEach { disconnect(uuid: $0.value) } stopWork() } } // MARK: - Handlers + extension RuuviTagHeartbeatDaemonBTKit { private func connectedHandler(for uuid: String) -> ((RuuviTagHeartbeatDaemonBTKit, BTConnectResult) -> Void)? { - return { observer, result in + { observer, result in switch result { case .already: break // already connected, do nothing @@ -188,7 +192,7 @@ extension RuuviTagHeartbeatDaemonBTKit { if observer.alertService.isOn(type: .connection, for: uuid) { observer.notifyDidConnect(uuid: uuid) } - case .failure(let error): + case let .failure(error): observer.post(error: .btkit(error)) case .disconnected: if observer.alertService.isOn(type: .connection, for: uuid) { @@ -199,18 +203,20 @@ extension RuuviTagHeartbeatDaemonBTKit { } private func heartbeatHandler() -> ((RuuviTagHeartbeatDaemonBTKit, BTDevice) -> Void)? { - return { observer, device in + { observer, device in if let ruuviTag = device.ruuvi?.tag { var sensorSettings: SensorSettings? if let ruuviTagSensor = observer.ruuviTags .first(where: { - ($0.macId?.value != nil && $0.macId?.value == ruuviTag.mac) - || ($0.luid?.any != nil && $0.luid?.any == ruuviTag.luid?.any) }), - let settings = observer.sensorSettingsList + ($0.macId?.value != nil && $0.macId?.value == ruuviTag.mac) + || ($0.luid?.any != nil && $0.luid?.any == ruuviTag.luid?.any) + }), + let settings = observer.sensorSettingsList .first(where: { - ($0.luid?.any != nil && $0.luid?.any == ruuviTagSensor.luid?.any) - || ($0.macId?.any != nil && $0.macId?.any == ruuviTagSensor.macId?.any) - }) { + ($0.luid?.any != nil && $0.luid?.any == ruuviTagSensor.luid?.any) + || ($0.macId?.any != nil && $0.macId?.any == ruuviTagSensor.macId?.any) + }) + { sensorSettings = settings } observer.alertHandler.process( @@ -243,8 +249,9 @@ extension RuuviTagHeartbeatDaemonBTKit { } private func disconnectedHandler(for uuid: String) -> - ((RuuviTagHeartbeatDaemonBTKit, BTDisconnectResult) -> Void)? { - return { observer, result in + ((RuuviTagHeartbeatDaemonBTKit, BTDisconnectResult) -> Void)? + { + { observer, result in switch result { case .stillConnected: break // do nothing @@ -258,7 +265,7 @@ extension RuuviTagHeartbeatDaemonBTKit { if observer.alertService.isOn(type: .connection, for: uuid) { observer.notifyDidDisconnect(uuid: uuid) } - case .failure(let error): + case let .failure(error): observer.post(error: .btkit(error)) } } @@ -266,14 +273,16 @@ extension RuuviTagHeartbeatDaemonBTKit { private func createRecords(observer: RuuviTagHeartbeatDaemonBTKit, ruuviTag: RuuviTag, - uuid: String) { - self.createRecord(observer: observer, ruuviTag: ruuviTag, uuid: uuid) + uuid: String) + { + createRecord(observer: observer, ruuviTag: ruuviTag, uuid: uuid) observer.savedDate[uuid] = Date() } private func createRecord(observer: RuuviTagHeartbeatDaemonBTKit, ruuviTag: RuuviTag, - uuid: String) { + uuid: String) + { observer.ruuviPool.create( ruuviTag .with(source: .heartbeat) @@ -284,12 +293,14 @@ extension RuuviTagHeartbeatDaemonBTKit { private func createLastRecord(observer: RuuviTagHeartbeatDaemonBTKit, ruuviTag: RuuviTag, - uuid: String) { + uuid: String) + { if let tag = ruuviTags.first(where: { $0.luid?.value == uuid }) { ruuviStorage.readLatest(tag).on(success: { localRecord in let record = ruuviTag.with(source: .heartbeat) - if let localRecord = localRecord, - record.macId?.value == localRecord.macId?.value { + if let localRecord, + record.macId?.value == localRecord.macId?.value + { observer.ruuviPool.updateLast(record) } else { observer.ruuviPool.createLast(record) @@ -300,25 +311,28 @@ extension RuuviTagHeartbeatDaemonBTKit { } // MARK: - Private + extension RuuviTagHeartbeatDaemonBTKit { private func handleRuuviTagsChange() { connectionPersistence.keepConnectionUUIDs - .filter { (luid) -> Bool in + .filter { luid -> Bool in ruuviTags.contains(where: { $0.luid?.any != nil - && $0.luid?.any == luid }) + && $0.luid?.any == luid + }) && !connectTokens.keys.contains(luid.value) - }.forEach({ connect(uuid: $0.value) }) + }.forEach { connect(uuid: $0.value) } connectionPersistence.keepConnectionUUIDs - .filter { (luid) -> Bool in + .filter { luid -> Bool in !ruuviTags.contains(where: { $0.luid?.any != nil - && $0.luid?.any == luid }) + && $0.luid?.any == luid + }) && connectTokens.keys.contains(luid.value) - }.forEach({ disconnect(uuid: $0.value) }) + }.forEach { disconnect(uuid: $0.value) } sensorSettingsList.removeAll() ruuviTags.forEach { ruuviTag in - ruuviStorage.readSensorSettings(ruuviTag).on {[weak self] sensorSettings in - if let sensorSettings = sensorSettings { + ruuviStorage.readSensorSettings(ruuviTag).on { [weak self] sensorSettings in + if let sensorSettings { self?.sensorSettingsList.append(sensorSettings) } } @@ -353,11 +367,11 @@ extension RuuviTagHeartbeatDaemonBTKit { private func invalidateTokens() { autoreleasepool { ruuviTagsToken?.invalidate() - connectTokens.values.forEach({ $0.invalidate() }) + connectTokens.values.forEach { $0.invalidate() } connectTokens.removeAll() - disconnectTokens.values.forEach({ $0.invalidate() }) + disconnectTokens.values.forEach { $0.invalidate() } disconnectTokens.removeAll() - sensorSettingsTokens.values.forEach({ $0.invalidate() }) + sensorSettingsTokens.values.forEach { $0.invalidate() } sensorSettingsTokens.removeAll() } } @@ -394,16 +408,17 @@ extension RuuviTagHeartbeatDaemonBTKit { } // MARK: - Sensor Settings + extension RuuviTagHeartbeatDaemonBTKit { private func restartSensorSettingsObservers() { - sensorSettingsTokens.forEach({ $0.value.invalidate() }) + sensorSettingsTokens.forEach { $0.value.invalidate() } sensorSettingsTokens.removeAll() ruuviTags.forEach { ruuviTagSensor in sensorSettingsTokens[ruuviTagSensor.id] = ruuviReactor.observe( ruuviTagSensor, { [weak self] change in switch change { - case .update(let updateSensorSettings): + case let .update(updateSensorSettings): if let updateIndex = self?.sensorSettingsList.firstIndex( where: { $0.id == updateSensorSettings.id } ) { @@ -414,12 +429,12 @@ extension RuuviTagHeartbeatDaemonBTKit { if let luid = ruuviTagSensor.luid?.value { self?.savedDate.removeValue(forKey: luid) } - case .insert(let sensorSettings): + case let .insert(sensorSettings): self?.sensorSettingsList.append(sensorSettings) if let luid = ruuviTagSensor.luid?.value { self?.savedDate.removeValue(forKey: luid) } - case .delete(let deleteSensorSettings): + case let .delete(deleteSensorSettings): if let deleteIndex = self?.sensorSettingsList.firstIndex( where: { $0.id == deleteSensorSettings.id } ) { diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift index f91db2d27..fa2252cf7 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift @@ -1,11 +1,11 @@ -import Foundation import BTKit +import Foundation +import RuuviDaemon +import RuuviLocal import RuuviOntology -import RuuviReactor import RuuviPersistence -import RuuviLocal import RuuviPool -import RuuviDaemon +import RuuviReactor public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPropertiesDaemon { private let ruuviPool: RuuviPool @@ -50,44 +50,45 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro } deinit { - observeTokens.forEach({ $0.invalidate() }) + observeTokens.forEach { $0.invalidate() } observeTokens.removeAll() - scanTokens.forEach({ $0.invalidate() }) + scanTokens.forEach { $0.invalidate() } scanTokens.removeAll() ruuviTagsToken?.invalidate() } public func start() { start { [weak self] in - self?.ruuviTagsToken = self?.ruuviReactor.observe({ [weak self] change in + self?.ruuviTagsToken = self?.ruuviReactor.observe { [weak self] change in guard let sSelf = self else { return } switch change { - case .initial(let ruuviTags): + case let .initial(ruuviTags): sSelf.ruuviTags = ruuviTags sSelf.restartObserving() - case .update(let ruuviTag): + case let .update(ruuviTag): if let index = sSelf.ruuviTags .firstIndex( where: { ($0.macId != nil && $0.macId?.any == ruuviTag.macId?.any) - || ($0.luid != nil && $0.luid?.any == ruuviTag.luid?.any) - }) { + || ($0.luid != nil && $0.luid?.any == ruuviTag.luid?.any) + }) + { sSelf.ruuviTags[index] = ruuviTag } sSelf.restartObserving() - case .insert(let ruuviTag): + case let .insert(ruuviTag): sSelf.ruuviTags.append(ruuviTag) sSelf.restartObserving() - case .delete(let ruuviTag): + case let .delete(ruuviTag): sSelf.ruuviTags.removeAll(where: { ($0.macId != nil && $0.macId?.any == ruuviTag.macId?.any) - || ($0.luid != nil && $0.luid?.any == ruuviTag.luid?.any) + || ($0.luid != nil && $0.luid?.any == ruuviTag.luid?.any) }) sSelf.restartObserving() - case .error(let error): + case let .error(error): sSelf.post(error: .ruuviReactor(error)) } - }) + } } } @@ -106,9 +107,9 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro } private func removeTokens() { - observeTokens.forEach({ $0.invalidate() }) + observeTokens.forEach { $0.invalidate() } observeTokens.removeAll() - scanTokens.forEach({ $0.invalidate() }) + scanTokens.forEach { $0.invalidate() } scanTokens.removeAll() } @@ -118,18 +119,19 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro if let luid = ruuviTag.luid { observeTokens.append(foreground.observe(self, uuid: luid.value, - options: [.callbackQueue(.untouch)]) { - [weak self] (_, device) in - guard let sSelf = self else { return } - if let tag = device.ruuvi?.tag { - let pair = RuuviTagPropertiesDaemonPair(ruuviTag: ruuviTag, device: tag) - sSelf.perform(#selector(RuuviTagPropertiesDaemonBTKit.tryToUpdate(pair:)), - on: sSelf.thread, - with: pair, - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) - } - }) + options: [.callbackQueue(.untouch)]) + { + [weak self] _, device in + guard let sSelf = self else { return } + if let tag = device.ruuvi?.tag { + let pair = RuuviTagPropertiesDaemonPair(ruuviTag: ruuviTag, device: tag) + sSelf.perform(#selector(RuuviTagPropertiesDaemonBTKit.tryToUpdate(pair:)), + on: sSelf.thread, + with: pair, + waitUntilDone: false, + modes: [RunLoop.Mode.default.rawValue]) + } + }) } else if ruuviTag.isCloud { scanRemoteSensor(ruuviTag: ruuviTag) } @@ -160,7 +162,7 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro .with(isOwner: true) ).on(success: { [weak self] _ in self?.realmPersistence.readAll(pair.device.uuid).on(success: { realmRecords in - var records = realmRecords.map({ $0.with(macId: mac.mac) }) + var records = realmRecords.map { $0.with(macId: mac.mac) } self?.sqiltePersistence.create(records).on(success: { _ in self?.realmPersistence.deleteAllRecords(pair.device.uuid).on(success: { _ in self?.idPersistence.set(mac: mac.mac, for: pair.device.uuid.luid) @@ -193,7 +195,7 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro }) }) }) - }, failure: { [weak self] (error) in + }, failure: { [weak self] error in self?.post(error: .ruuviPersistence(error)) self?.isTransitioningFromRealmToSQLite = false }) @@ -202,7 +204,8 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro // this is the case when 2.5.9 tag is returning to data format 3 mode // but we have it in sqlite database already if let mac = idPersistence.mac(for: pair.device.uuid.luid), - pair.device.version != pair.ruuviTag.version { + pair.device.version != pair.ruuviTag.version + { ruuviPool.update(pair.ruuviTag .with(macId: mac) .with(version: pair.device.version)) @@ -223,15 +226,17 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro private func scanRemoteSensor(ruuviTag: AnyRuuviTagSensor) { guard let mac = ruuviTag.macId, - ruuviTag.luid == nil else { + ruuviTag.luid == nil + else { return } - let scanToken = foreground.scan(self, closure: { [weak self] (_, device) in + let scanToken = foreground.scan(self, closure: { [weak self] _, device in guard let sSelf = self, let tag = device.ruuvi?.tag, mac.any == tag.macId?.any, ruuviTag.luid == nil, - !sSelf.processingUUIDs.contains(tag.uuid) else { + !sSelf.processingUUIDs.contains(tag.uuid) + else { return } sSelf.processingUUIDs.insert(tag.uuid) @@ -248,7 +253,8 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro ownersPlan: ruuviTag.ownersPlan, isCloudSensor: ruuviTag.isCloudSensor, canShare: ruuviTag.canShare, - sharedTo: ruuviTag.sharedTo) + sharedTo: ruuviTag.sharedTo + ) sSelf.idPersistence.set(mac: mac, for: device.uuid.luid) sSelf.idPersistence.set(luid: device.uuid.luid, for: mac) sSelf.ruuviPool.update(ruuviSensor) diff --git a/Packages/RuuviDaemon/Tests/RuuviDaemonTests/RuuviDaemonTests.swift b/Packages/RuuviDaemon/Tests/RuuviDaemonTests/RuuviDaemonTests.swift index c08e7bc1e..b33ce8d42 100644 --- a/Packages/RuuviDaemon/Tests/RuuviDaemonTests/RuuviDaemonTests.swift +++ b/Packages/RuuviDaemon/Tests/RuuviDaemonTests/RuuviDaemonTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviDaemon +import XCTest final class RuuviDaemonTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Packages/RuuviLocal/Package.swift b/Packages/RuuviLocal/Package.swift index 2fe57a942..67bca1c34 100644 --- a/Packages/RuuviLocal/Package.swift +++ b/Packages/RuuviLocal/Package.swift @@ -9,31 +9,34 @@ let package = Package( products: [ .library( name: "RuuviLocal", - targets: ["RuuviLocal"]), + targets: ["RuuviLocal"] + ), .library( name: "RuuviLocalUserDefaults", - targets: ["RuuviLocalUserDefaults"]) + targets: ["RuuviLocalUserDefaults"] + ), ], dependencies: [ .package(url: "https://github.com/kean/Future", .exact("1.3.0")), - .package(path: "../RuuviOntology") + .package(path: "../RuuviOntology"), ], targets: [ .target( name: "RuuviLocal", dependencies: [ "RuuviOntology", - "Future" + "Future", ] ), .target( name: "RuuviLocalUserDefaults", dependencies: [ - "RuuviLocal" + "RuuviLocal", ] ), .testTarget( name: "RuuviLocalTests", - dependencies: ["RuuviLocal"]) + dependencies: ["RuuviLocal"] + ), ] ) diff --git a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalConnections.swift b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalConnections.swift index 0671eb8c6..4926950eb 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalConnections.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalConnections.swift @@ -9,10 +9,10 @@ public protocol RuuviLocalConnections { func unpairAllConnection() } -extension Notification.Name { - public static let ConnectionPersistenceDidStartToKeepConnection = +public extension Notification.Name { + static let ConnectionPersistenceDidStartToKeepConnection = Notification.Name("ConnectionPersistenceDidStartToKeepConnection") - public static let ConnectionPersistenceDidStopToKeepConnection = + static let ConnectionPersistenceDidStopToKeepConnection = Notification.Name("ConnectionPersistenceDidStopToKeepConnection") } diff --git a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalImages.swift b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalImages.swift index c99fcb724..1f991b0c8 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalImages.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalImages.swift @@ -1,11 +1,11 @@ -import UIKit import Future import RuuviOntology +import UIKit -extension Notification.Name { - public static let BackgroundPersistenceDidChangeBackground +public extension Notification.Name { + static let BackgroundPersistenceDidChangeBackground = Notification.Name("BackgroundPersistenceDidChangeBackground") - public static let BackgroundPersistenceDidUpdateBackgroundUploadProgress + static let BackgroundPersistenceDidUpdateBackgroundUploadProgress = Notification.Name("BackgroundPersistenceDidUpdateBackgroundUploadProgress") } diff --git a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift index e359b793a..8ead1c1e9 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift @@ -1,28 +1,28 @@ import Foundation import RuuviOntology -extension Notification.Name { - public static let TemperatureUnitDidChange = Notification.Name("Settings.TemperatureUnitDidChange") - public static let TemperatureAccuracyDidChange = Notification.Name("Settings.TemperatureAccuracyDidChange") - public static let HumidityUnitDidChange = Notification.Name("Settings.HumidityUnitDidChange") - public static let HumidityAccuracyDidChange = Notification.Name("Settings.HumidityAccuracyDidChange") - public static let PressureUnitDidChange = Notification.Name("Settings.PressureUnitDidChange") - public static let PressureUnitAccuracyChange = Notification.Name("Settings.PressureUnitAccuracyChange") - public static let LanguageDidChange = Notification.Name("LanguageDidChange") - public static let isAdvertisementDaemonOnDidChange = Notification.Name("isAdvertisementDaemonOnDidChange") - public static let DownsampleOnDidChange = Notification.Name("DownsampleOnDidChange") - public static let ChartDurationHourDidChange = Notification.Name("ChartDurationHourDidChange") - public static let ChartDrawDotsOnDidChange = Notification.Name("ChartDrawDotsOnDidChange") - public static let ChartStatsOnDidChange = Notification.Name("ChartStatsOnDidChange") - public static let CloudModeDidChange = Notification.Name("CloudModeDidChange") - public static let SensorCalibrationDidChange = Notification.Name("CalibrationDidChange") - public static let DashboardTypeDidChange = Notification.Name("DashboardTypeDidChange") - public static let DashboardTapActionTypeDidChange = Notification.Name("DashboardTapActionTypeDidChange") - public static let AppearanceSettingsDidChange = Notification.Name("AppearanceSettingsDidChange") - public static let AlertSoundSettingsDidChange = Notification.Name("AlertSoundSettingsDidChange") - public static let EmailAlertSettingsDidChange = Notification.Name("EmailAlertSettingsDidChange") - public static let PushAlertSettingsDidChange = Notification.Name("PushAlertSettingsDidChange") - public static let LimitAlertNotificationsSettingsDidChange = +public extension Notification.Name { + static let TemperatureUnitDidChange = Notification.Name("Settings.TemperatureUnitDidChange") + static let TemperatureAccuracyDidChange = Notification.Name("Settings.TemperatureAccuracyDidChange") + static let HumidityUnitDidChange = Notification.Name("Settings.HumidityUnitDidChange") + static let HumidityAccuracyDidChange = Notification.Name("Settings.HumidityAccuracyDidChange") + static let PressureUnitDidChange = Notification.Name("Settings.PressureUnitDidChange") + static let PressureUnitAccuracyChange = Notification.Name("Settings.PressureUnitAccuracyChange") + static let LanguageDidChange = Notification.Name("LanguageDidChange") + static let isAdvertisementDaemonOnDidChange = Notification.Name("isAdvertisementDaemonOnDidChange") + static let DownsampleOnDidChange = Notification.Name("DownsampleOnDidChange") + static let ChartDurationHourDidChange = Notification.Name("ChartDurationHourDidChange") + static let ChartDrawDotsOnDidChange = Notification.Name("ChartDrawDotsOnDidChange") + static let ChartStatsOnDidChange = Notification.Name("ChartStatsOnDidChange") + static let CloudModeDidChange = Notification.Name("CloudModeDidChange") + static let SensorCalibrationDidChange = Notification.Name("CalibrationDidChange") + static let DashboardTypeDidChange = Notification.Name("DashboardTypeDidChange") + static let DashboardTapActionTypeDidChange = Notification.Name("DashboardTapActionTypeDidChange") + static let AppearanceSettingsDidChange = Notification.Name("AppearanceSettingsDidChange") + static let AlertSoundSettingsDidChange = Notification.Name("AlertSoundSettingsDidChange") + static let EmailAlertSettingsDidChange = Notification.Name("EmailAlertSettingsDidChange") + static let PushAlertSettingsDidChange = Notification.Name("PushAlertSettingsDidChange") + static let LimitAlertNotificationsSettingsDidChange = Notification.Name("LimitAlertNotificationsSettingsDidChange") } diff --git a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSyncState.swift b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSyncState.swift index 4bd8ce2a6..cd9d34b3a 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSyncState.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSyncState.swift @@ -13,16 +13,16 @@ public enum NetworkSyncStatusKey: String { case status } -extension Notification.Name { - public static let NetworkSyncDidChangeStatus = +public extension Notification.Name { + static let NetworkSyncDidChangeStatus = Notification.Name("NetworkPersistence.DidChangeStatus") - public static let NetworkSyncDidComplete = + static let NetworkSyncDidComplete = Notification.Name("NetworkPersistence.NetworkSyncDidComplete") - public static let NetworkHistorySyncDidCompleteForSensor = + static let NetworkHistorySyncDidCompleteForSensor = Notification.Name("NetworkPersistence.NetworkHistorySyncDidCompleteForSensor") - public static let NetworkSyncDidChangeCommonStatus = + static let NetworkSyncDidChangeCommonStatus = Notification.Name("NetworkPersistence.DidChangeCommonStatus") - public static let NetworkSyncDidFailForAuthorization = + static let NetworkSyncDidFailForAuthorization = Notification.Name("NetworkPersistence.NetworkSyncDidFailForAuthorization") } diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/Documents/ImagePersistenceDocuments.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/Documents/ImagePersistenceDocuments.swift index 4c6c45417..f6a8d5ef5 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/Documents/ImagePersistenceDocuments.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/Documents/ImagePersistenceDocuments.swift @@ -1,10 +1,9 @@ -import UIKit import Future -import RuuviOntology import RuuviLocal +import RuuviOntology +import UIKit class ImagePersistenceDocuments: ImagePersistence { - private let ext = ".png" private let bgDir = "bg" private var isBgDirCreated = false @@ -51,5 +50,4 @@ class ImagePersistenceDocuments: ImagePersistence { } return dir } - } diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/ImagePersistence.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/ImagePersistence.swift index 5f3ced508..905a38ced 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/ImagePersistence.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/ImagePersistence.swift @@ -1,7 +1,7 @@ -import UIKit import Future -import RuuviOntology import RuuviLocal +import RuuviOntology +import UIKit protocol ImagePersistence { func fetchBg(for identifier: Identifier) -> UIImage? diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/RuuviLocalImagesUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/RuuviLocalImagesUserDefaults.swift index 91c4ce2c6..b2a85b517 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/RuuviLocalImagesUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/RuuviLocalImagesUserDefaults.swift @@ -1,7 +1,7 @@ -import UIKit import Future -import RuuviOntology import RuuviLocal +import RuuviOntology +import UIKit final class RuuviLocalImagesUserDefaults: RuuviLocalImages { init(imagePersistence: ImagePersistence) { @@ -22,7 +22,8 @@ final class RuuviLocalImagesUserDefaults: RuuviLocalImages { private var usedBackgrounds: [Int] { if let ub = UserDefaults.standard.array(forKey: usedBackgroundsUDKey) as? [Int], - ub.count == bgMaxIndex { + ub.count == bgMaxIndex + { return ub } else { let ub = Array(repeating: 0, count: bgMaxIndex - bgMinIndex + 1) @@ -37,7 +38,7 @@ final class RuuviLocalImagesUserDefaults: RuuviLocalImages { func setNextDefaultBackground(for identifier: Identifier) -> UIImage? { var id = backgroundId(for: identifier) - if id >= bgMinIndex && id < bgMaxIndex { + if id >= bgMinIndex, id < bgMaxIndex { id += 1 setBackground(id, for: identifier) } else if id >= bgMaxIndex { @@ -52,12 +53,12 @@ final class RuuviLocalImagesUserDefaults: RuuviLocalImages { } func getCustomBackground(for identifier: Identifier) -> UIImage? { - return imagePersistence.fetchBg(for: identifier) + imagePersistence.fetchBg(for: identifier) } func getBackground(for identifier: Identifier) -> UIImage? { let id = backgroundId(for: identifier) - if id >= bgMinIndex && id <= bgMaxIndex { + if id >= bgMinIndex, id <= bgMaxIndex { return UIImage(named: "bg\(id)") } else { return getCustomBackground(for: identifier) @@ -66,7 +67,7 @@ final class RuuviLocalImagesUserDefaults: RuuviLocalImages { func getOrGenerateBackground(for identifier: Identifier) -> UIImage? { var id = backgroundId(for: identifier) - if id >= bgMinIndex && id <= bgMaxIndex { + if id >= bgMinIndex, id <= bgMaxIndex { return UIImage(named: "bg\(id)") } else { if let custom = getCustomBackground(for: identifier) { @@ -98,7 +99,7 @@ final class RuuviLocalImagesUserDefaults: RuuviLocalImages { object: nil, userInfo: [userInfoKey: identifier]) promise.succeed(value: url) - }, failure: { (error) in + }, failure: { error in promise.fail(error: error) }) return promise.future @@ -123,7 +124,7 @@ final class RuuviLocalImagesUserDefaults: RuuviLocalImages { .post(name: .BackgroundPersistenceDidChangeBackground, object: nil, userInfo: [userInfoKey: identifier]) - if id >= bgMinIndex && id <= bgMaxIndex { + if id >= bgMinIndex, id <= bgMaxIndex { var array = usedBackgrounds array[id - bgMinIndex] += 1 UserDefaults.standard.set(array, forKey: usedBackgroundsUDKey) @@ -142,7 +143,7 @@ final class RuuviLocalImagesUserDefaults: RuuviLocalImages { let array = usedBackgrounds var result: Int if let min = array.min() { - let indicies = array.enumerated().compactMap({ $1 == min ? $0 + bgMinIndex : nil }) + let indicies = array.enumerated().compactMap { $1 == min ? $0 + bgMinIndex : nil } if indicies.count == 0 { result = Int(arc4random_uniform(UInt32(bgMaxIndex)) + UInt32(bgMinIndex)) } else { @@ -158,6 +159,7 @@ final class RuuviLocalImagesUserDefaults: RuuviLocalImages { return result } + // swiftlint:enable legacy_random func backgroundUploadProgress(for identifier: Identifier) -> Double? { @@ -183,8 +185,8 @@ final class RuuviLocalImagesUserDefaults: RuuviLocalImages { .post(name: .BackgroundPersistenceDidUpdateBackgroundUploadProgress, object: nil, userInfo: [ - userInfoKey: identifier, - BPDidUpdateBackgroundUploadProgressKey.progress: percentage + userInfoKey: identifier, + BPDidUpdateBackgroundUploadProgressKey.progress: percentage, ]) UserDefaults.standard.setValue(percentage, forKey: key) } diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalConnectionsUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalConnectionsUserDefaults.swift index 7809e2095..773ba96c7 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalConnectionsUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalConnectionsUserDefaults.swift @@ -1,15 +1,14 @@ import Foundation -import RuuviOntology import RuuviLocal +import RuuviOntology final class RuuviLocalConnectionsUserDefaults: RuuviLocalConnections { - private let prefs = UserDefaults.standard private let keepConnectionArrayUDKey = "ConnectionPersistenceUserDefaults.keepConnection.array" var keepConnectionUUIDs: [AnyLocalIdentifier] { let strings = prefs.array(forKey: keepConnectionArrayUDKey) as? [String] - return strings?.map({ $0.luid.any }) ?? [] + return strings?.map(\.luid.any) ?? [] } func keepConnection(to luid: LocalIdentifier) -> Bool { @@ -27,13 +26,14 @@ final class RuuviLocalConnectionsUserDefaults: RuuviLocalConnections { assert(uuid.count == 36) if value { if var array = prefs.array(forKey: keepConnectionArrayUDKey) as? [String], - !array.contains(uuid) { + !array.contains(uuid) + { array.append(uuid) prefs.set(array, forKey: keepConnectionArrayUDKey) NotificationCenter.default.post(name: .ConnectionPersistenceDidStartToKeepConnection, object: nil, userInfo: - [CPDidStartToKeepConnectionKey.uuid: uuid]) + [CPDidStartToKeepConnectionKey.uuid: uuid]) } else { var array = [String]() array.append(uuid) @@ -41,7 +41,7 @@ final class RuuviLocalConnectionsUserDefaults: RuuviLocalConnections { NotificationCenter.default.post(name: .ConnectionPersistenceDidStartToKeepConnection, object: nil, userInfo: - [CPDidStartToKeepConnectionKey.uuid: uuid]) + [CPDidStartToKeepConnectionKey.uuid: uuid]) } } else { if var array = prefs.array(forKey: keepConnectionArrayUDKey) as? [String] { @@ -50,7 +50,7 @@ final class RuuviLocalConnectionsUserDefaults: RuuviLocalConnections { NotificationCenter.default.post(name: .ConnectionPersistenceDidStopToKeepConnection, object: nil, userInfo: - [CPDidStopToKeepConnectionKey.uuid: uuid]) + [CPDidStopToKeepConnectionKey.uuid: uuid]) } } } @@ -61,7 +61,7 @@ final class RuuviLocalConnectionsUserDefaults: RuuviLocalConnections { NotificationCenter.default.post(name: .ConnectionPersistenceDidStopToKeepConnection, object: nil, userInfo: - [CPDidStopToKeepConnectionKey.uuid: uuid]) + [CPDidStopToKeepConnectionKey.uuid: uuid]) } array.removeAll() prefs.set(array, forKey: keepConnectionArrayUDKey) diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalFactoryUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalFactoryUserDefaults.swift index dfc2fa890..44d87be76 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalFactoryUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalFactoryUserDefaults.swift @@ -5,22 +5,22 @@ public final class RuuviLocalFactoryUserDefaults: RuuviLocalFactory { public init() {} public func createLocalSettings() -> RuuviLocalSettings { - return RuuviLocalSettingsUserDefaults() + RuuviLocalSettingsUserDefaults() } public func createLocalIDs() -> RuuviLocalIDs { - return RuuviLocalIDsUserDefaults() + RuuviLocalIDsUserDefaults() } public func createLocalConnections() -> RuuviLocalConnections { - return RuuviLocalConnectionsUserDefaults() + RuuviLocalConnectionsUserDefaults() } public func createLocalSyncState() -> RuuviLocalSyncState { - return RuuviLocalSyncStateUserDefaults() + RuuviLocalSyncStateUserDefaults() } public func createLocalImages() -> RuuviLocalImages { - return RuuviLocalImagesUserDefaults(imagePersistence: ImagePersistenceDocuments()) + RuuviLocalImagesUserDefaults(imagePersistence: ImagePersistenceDocuments()) } } diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalIDsUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalIDsUserDefaults.swift index 4711382bf..80def07c8 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalIDsUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalIDsUserDefaults.swift @@ -1,10 +1,10 @@ import Foundation -import RuuviOntology import RuuviLocal +import RuuviOntology class RuuviLocalIDsUserDefaults: RuuviLocalIDs { func mac(for luid: LocalIdentifier) -> MACIdentifier? { - return UserDefaults.standard.string(forKey: luid.value)?.mac + UserDefaults.standard.string(forKey: luid.value)?.mac } func set(mac: MACIdentifier, for luid: LocalIdentifier) { @@ -12,7 +12,7 @@ class RuuviLocalIDsUserDefaults: RuuviLocalIDs { } func luid(for mac: MACIdentifier) -> LocalIdentifier? { - return UserDefaults.standard.string(forKey: mac.value)?.luid + UserDefaults.standard.string(forKey: mac.value)?.luid } func set(luid: LocalIdentifier, for mac: MACIdentifier) { diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift index e573bd897..3430e04a4 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift @@ -1,10 +1,9 @@ import Foundation -import RuuviOntology import RuuviLocal +import RuuviOntology // swiftlint:disable type_body_length file_length final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { - @UserDefault("SettingsUserDefaults.signedInAtleastOnce", defaultValue: false) var signedInAtleastOnce: Bool @@ -14,7 +13,7 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { private let keepConnectionDialogWasShownUDPrefix = "SettingsUserDegaults.keepConnectionDialogWasShownUDPrefix." func keepConnectionDialogWasShown(for luid: LocalIdentifier) -> Bool { - return UserDefaults.standard.bool(forKey: keepConnectionDialogWasShownUDPrefix + luid.value) + UserDefaults.standard.bool(forKey: keepConnectionDialogWasShownUDPrefix + luid.value) } func setKeepConnectionDialogWasShown(for luid: LocalIdentifier) { @@ -24,7 +23,7 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { private let firmwareUpdateDialogWasShownUDPrefix = "SettingsUserDegaults.firmwareUpdateDialogWasShownUDPrefix." func firmwareUpdateDialogWasShown(for luid: LocalIdentifier) -> Bool { - return UserDefaults.standard.bool(forKey: firmwareUpdateDialogWasShownUDPrefix + luid.value) + UserDefaults.standard.bool(forKey: firmwareUpdateDialogWasShownUDPrefix + luid.value) } func setFirmwareUpdateDialogWasShown(for luid: LocalIdentifier) { @@ -34,7 +33,7 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { // TODO: - Deprecate this after version v1.3.2 private let firmwareVersionPrefix = "SettingsUserDegaults.firmwareVersionPrefix" func firmwareVersion(for luid: LocalIdentifier) -> String? { - return UserDefaults.standard.value(forKey: firmwareVersionPrefix + luid.value) as? String + UserDefaults.standard.value(forKey: firmwareVersionPrefix + luid.value) as? String } func setFirmwareVersion(for luid: LocalIdentifier, value: String?) { @@ -45,11 +44,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { var language: Language { get { if let savedCode = UserDefaults.standard.string(forKey: languageUDKey) { - return Language(rawValue: savedCode) ?? .english + Language(rawValue: savedCode) ?? .english } else if let regionCode = Locale.current.languageCode { - return Language(rawValue: regionCode) ?? .english + Language(rawValue: regionCode) ?? .english } else { - return .english + .english } } set { @@ -63,6 +62,7 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { userInfo: nil) } } + private let languageUDKey = "SettingsUserDegaults.languageUDKey" @UserDefault("SettingsUserDefaults.cardToOpenFromWidgetKey", defaultValue: nil) @@ -72,11 +72,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { get { switch humidityUnitInt { case 1: - return .gm3 + .gm3 case 2: - return .dew + .dew default: - return .percent + .percent } } set { @@ -103,13 +103,13 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { get { switch humidityAccuracyInt { case 0: - return .zero + .zero case 1: - return .one + .one case 2: - return .two + .two default: - return .two + .two } } set { @@ -126,15 +126,15 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { get { switch temperatureUnitInt { case 0: - return useFahrenheit ? .fahrenheit : .celsius + useFahrenheit ? .fahrenheit : .celsius case 1: - return .kelvin + .kelvin case 2: - return .celsius + .celsius case 3: - return .fahrenheit + .fahrenheit default: - return .celsius + .celsius } } set { @@ -162,13 +162,13 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { get { switch temperatureAccuracyInt { case 0: - return .zero + .zero case 1: - return .one + .one case 2: - return .two + .two default: - return .two + .two } } set { @@ -185,11 +185,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { get { switch pressureUnitInt { case UnitPressure.inchesOfMercury.hashValue: - return .inchesOfMercury + .inchesOfMercury case UnitPressure.millimetersOfMercury.hashValue: - return .millimetersOfMercury + .millimetersOfMercury default: - return .hectopascals + .hectopascals } } set { @@ -209,13 +209,13 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { get { switch pressureAccuracyInt { case 0: - return .zero + .zero case 1: - return .one + .one case 2: - return .two + .two default: - return .two + .two } } set { @@ -238,16 +238,16 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { var tagChartsLandscapeSwipeInstructionWasShown: Bool @UserDefault("DashboardScrollViewController.hasShownSwipeAlert", defaultValue: false) - var cardsSwipeHintWasShown: Bool + var cardsSwipeHintWasShown: Bool @UserDefault("SettingsUserDegaults.isAdvertisementDaemonOn", defaultValue: true) var isAdvertisementDaemonOn: Bool { didSet { NotificationCenter - .default - .post(name: .isAdvertisementDaemonOnDidChange, - object: self, - userInfo: nil) + .default + .post(name: .isAdvertisementDaemonOnDidChange, + object: self, + userInfo: nil) } } @@ -296,6 +296,7 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { var networkPruningIntervalHours: Int // MARK: - Private + @UserDefault("SettingsUserDegaults.useFahrenheit", defaultValue: false) private var useFahrenheit: Bool @@ -318,16 +319,18 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { UserDefaults.standard.set(newValue, forKey: temperatureUnitIntUDKey) } } + private let temperatureUnitIntUDKey = "SettingsUserDegaults.temperatureUnitIntUDKey" private var humidityUnitInt: Int { get { - return UserDefaults.standard.integer(forKey: humidityUnitIntUDKey) + UserDefaults.standard.integer(forKey: humidityUnitIntUDKey) } set { UserDefaults.standard.set(newValue, forKey: humidityUnitIntUDKey) } } + private let humidityUnitIntUDKey = "SettingsUserDegaults.humidityUnitInt" @UserDefault("SettingsUserDefaults.chartDownsamplingOn", defaultValue: true) @@ -401,6 +404,7 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { func cardToOpenFromWidget() -> String? { UserDefaults.standard.value(forKey: cardToOpenFromWidgetKey) as? String } + func setCardToOpenFromWidget(for macId: String?) { UserDefaults.standard.set(macId, forKey: cardToOpenFromWidgetKey) } @@ -416,8 +420,8 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { private let ownerCheckDateKey = "SettingsUserDefaults.ownerCheckDate" func setOwnerCheckDate(for macId: MACIdentifier?, value: Date?) { - guard let macId = macId else { return } - if let value = value { + guard let macId else { return } + if let value { UserDefaults.standard.set(value, forKey: ownerCheckDateKey + macId.mac) } else { UserDefaults.standard.removeObject(forKey: ownerCheckDateKey + macId.mac) @@ -425,7 +429,7 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { } func ownerCheckDate(for macId: MACIdentifier?) -> Date? { - guard let macId = macId else { return nil } + guard let macId else { return nil } return UserDefaults.standard.value(forKey: ownerCheckDateKey + macId.mac) as? Date } @@ -435,7 +439,7 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { private let dashboardTypeIdKey = "SettingsUserDefaults.dashboardTypeIdKey" private var dashboardTypeId: Int { get { - return UserDefaults.standard.integer(forKey: dashboardTypeIdKey) + UserDefaults.standard.integer(forKey: dashboardTypeIdKey) } set { UserDefaults.standard.set(newValue, forKey: dashboardTypeIdKey) @@ -446,11 +450,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { get { switch dashboardTypeId { case 0: - return .image + .image case 1: - return .simple + .simple default: - return .image + .image } } set { @@ -472,7 +476,7 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { "SettingsUserDefaults.dashboardTapActionTypeIdKey" private var dashboardTapActionTypeId: Int { get { - return UserDefaults.standard.integer(forKey: dashboardTapActionTypeIdKey) + UserDefaults.standard.integer(forKey: dashboardTapActionTypeIdKey) } set { UserDefaults.standard.set(newValue, forKey: dashboardTapActionTypeIdKey) @@ -483,20 +487,20 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { var dashboardTapActionType: DashboardTapActionType { get { switch dashboardTapActionTypeId { - case 0: - return .card - case 1: - return .chart - default: - return .card + case 0: + .card + case 1: + .chart + default: + .card } } set { switch newValue { - case .card: - dashboardTapActionTypeId = 0 - case .chart: - dashboardTapActionTypeId = 1 + case .card: + dashboardTapActionTypeId = 0 + case .chart: + dashboardTapActionTypeId = 1 } NotificationCenter .default @@ -505,12 +509,13 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { userInfo: [DashboardTapActionTypeKey.type: newValue]) } } + // swiftlint:enable switch_case_alignment private let ruuviThemeIdKey = "SettingsUserDefaults.ruuviThemeIdKey" private var ruuviThemeId: Int { get { - return UserDefaults.standard.integer(forKey: ruuviThemeIdKey) + UserDefaults.standard.integer(forKey: ruuviThemeIdKey) } set { UserDefaults.standard.set(newValue, forKey: ruuviThemeIdKey) @@ -521,13 +526,13 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { get { switch ruuviThemeId { case 0: - return .system + .system case 1: - return .light + .light case 2: - return .dark + .dark default: - return .system + .system } } set { @@ -549,7 +554,7 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { private let syncDialogHiddenKey = "SettingsUserDefaults.syncDialogHiddenKey." func syncDialogHidden(for luid: LocalIdentifier) -> Bool { - return UserDefaults.standard.bool(forKey: syncDialogHiddenKey + luid.value) + UserDefaults.standard.bool(forKey: syncDialogHiddenKey + luid.value) } func setSyncDialogHidden(for luid: LocalIdentifier) { @@ -621,4 +626,5 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { } } } + // swiftlint:enable type_body_length file_length diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSyncStateUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSyncStateUserDefaults.swift index 14eb07e54..8ca53bbfc 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSyncStateUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSyncStateUserDefaults.swift @@ -1,6 +1,6 @@ import Foundation -import RuuviOntology import RuuviLocal +import RuuviOntology final class RuuviLocalSyncStateUserDefaults: RuuviLocalSyncState { private let syncStatusPrefix = "RuuviLocalSyncStateUserDefaults.syncState." @@ -17,15 +17,14 @@ final class RuuviLocalSyncStateUserDefaults: RuuviLocalSyncState { .default .post(name: .NetworkSyncDidChangeStatus, object: nil, userInfo: [ NetworkSyncStatusKey.status: status, - NetworkSyncStatusKey.mac: macId + NetworkSyncStatusKey.mac: macId, ]) } switch status { case .complete, .onError: - DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), - execute: { [weak self] in + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) { [weak self] in self?.setSyncStatus(.none, for: macId) - }) + } case .syncing: DispatchQueue.main.async { [weak self] in self?.syncStatus = .syncing @@ -43,7 +42,7 @@ final class RuuviLocalSyncStateUserDefaults: RuuviLocalSyncState { } func setSyncDate(_ date: Date?, for macId: MACIdentifier?) { - guard let macId = macId else { return } + guard let macId else { return } UserDefaults.standard.set(date, forKey: syncDatePrefix + macId.mac) DispatchQueue.main.async { NotificationCenter @@ -51,23 +50,23 @@ final class RuuviLocalSyncStateUserDefaults: RuuviLocalSyncState { .post(name: .NetworkHistorySyncDidCompleteForSensor, object: nil, userInfo: [ - NetworkSyncStatusKey.mac: macId - ]) + NetworkSyncStatusKey.mac: macId, + ]) } } func getSyncDate(for macId: MACIdentifier?) -> Date? { - guard let macId = macId else { assertionFailure(); return nil } + guard let macId else { assertionFailure(); return nil } return UserDefaults.standard.value(forKey: syncDatePrefix + macId.mac) as? Date } func setGattSyncDate(_ date: Date?, for macId: MACIdentifier?) { - guard let macId = macId else { return } + guard let macId else { return } UserDefaults.standard.set(date, forKey: gattSyncDatePrefix + macId.mac) } func getGattSyncDate(for macId: MACIdentifier?) -> Date? { - guard let macId = macId else { assertionFailure(); return nil } + guard let macId else { assertionFailure(); return nil } return UserDefaults.standard.value(forKey: gattSyncDatePrefix + macId.mac) as? Date } @@ -80,12 +79,12 @@ final class RuuviLocalSyncStateUserDefaults: RuuviLocalSyncState { } func getSyncDate() -> Date? { - return UserDefaults.standard.value(forKey: syncDateAllIDKey) as? Date + UserDefaults.standard.value(forKey: syncDateAllIDKey) as? Date } func setDownloadFullHistory(for macId: MACIdentifier?, downloadFull: Bool?) { - guard let macId = macId else { return } - if let downloadFull = downloadFull { + guard let macId else { return } + if let downloadFull { UserDefaults.standard.set(downloadFull, forKey: fullHistorySyncPrefix + macId.mac) } else { UserDefaults.standard.removeObject(forKey: fullHistorySyncPrefix + macId.mac) @@ -93,7 +92,7 @@ final class RuuviLocalSyncStateUserDefaults: RuuviLocalSyncState { } func downloadFullHistory(for macId: MACIdentifier?) -> Bool? { - guard let macId = macId else { assertionFailure(); return nil } + guard let macId else { assertionFailure(); return nil } return UserDefaults.standard.value(forKey: fullHistorySyncPrefix + macId.mac) as? Bool } @@ -102,14 +101,14 @@ final class RuuviLocalSyncStateUserDefaults: RuuviLocalSyncState { var syncStatus: NetworkSyncStatus { get { - return NetworkSyncStatus(rawValue: syncStatusInt) ?? NetworkSyncStatus.none + NetworkSyncStatus(rawValue: syncStatusInt) ?? NetworkSyncStatus.none } set { syncStatusInt = newValue.rawValue NotificationCenter .default .post(name: .NetworkSyncDidChangeCommonStatus, object: self, userInfo: [ - NetworkSyncStatusKey.status: newValue + NetworkSyncStatusKey.status: newValue, ]) } } diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/UserDefault.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/UserDefault.swift index 3ef972d50..bdd1f1ebe 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/UserDefault.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/UserDefault.swift @@ -12,7 +12,7 @@ struct UserDefault { var wrappedValue: T { get { - return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue + UserDefaults.standard.object(forKey: key) as? T ?? defaultValue } set { UserDefaults.standard.set(newValue, forKey: key) diff --git a/Packages/RuuviLocal/Tests/RuuviLocalTests/RuuviLocalTests.swift b/Packages/RuuviLocal/Tests/RuuviLocalTests/RuuviLocalTests.swift index 0ab9196f3..54899bd1a 100644 --- a/Packages/RuuviLocal/Tests/RuuviLocalTests/RuuviLocalTests.swift +++ b/Packages/RuuviLocal/Tests/RuuviLocalTests/RuuviLocalTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviLocal +import XCTest final class RuuviLocalTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Packages/RuuviMigration/Package.swift b/Packages/RuuviMigration/Package.swift index 2021332b6..fd38be3d3 100644 --- a/Packages/RuuviMigration/Package.swift +++ b/Packages/RuuviMigration/Package.swift @@ -9,10 +9,12 @@ let package = Package( products: [ .library( name: "RuuviMigration", - targets: ["RuuviMigration"]), + targets: ["RuuviMigration"] + ), .library( name: "RuuviMigrationImpl", - targets: ["RuuviMigrationImpl"]) + targets: ["RuuviMigrationImpl"] + ), ], dependencies: [ .package(path: "../RuuviOntology"), @@ -20,12 +22,13 @@ let package = Package( .package(path: "../RuuviPool"), .package(path: "../RuuviContext"), .package(path: "../RuuviStorage"), - .package(path: "../RuuviService") + .package(path: "../RuuviService"), ], targets: [ .target( name: "RuuviMigration", - dependencies: []), + dependencies: [] + ), .target( name: "RuuviMigrationImpl", dependencies: [ @@ -36,9 +39,11 @@ let package = Package( "RuuviStorage", "RuuviService", .product(name: "RuuviOntologyRealm", package: "RuuviOntology"), - ]), + ] + ), .testTarget( name: "RuuviMigrationTests", - dependencies: ["RuuviMigration"]) + dependencies: ["RuuviMigration"] + ), ] ) diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/AlertService/MigrationManagerAlertService.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/AlertService/MigrationManagerAlertService.swift index 71fb0945a..ab6742a00 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/AlertService/MigrationManagerAlertService.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/AlertService/MigrationManagerAlertService.swift @@ -1,10 +1,10 @@ -import Foundation import AVKit -import RuuviOntology +import Foundation import RuuviContext -import RuuviStorage -import RuuviService import RuuviMigration +import RuuviOntology +import RuuviService +import RuuviStorage final class MigrationManagerAlertService: RuuviMigration { private let ruuviStorage: RuuviStorage @@ -22,13 +22,13 @@ final class MigrationManagerAlertService: RuuviMigration { @UserDefault("MigrationManagerAlertService.persistanceVersion", defaultValue: 0) private var persistanceVersion: UInt private let actualServiceVersion: UInt = 1 - private let queue: DispatchQueue = DispatchQueue(label: "MigrationManagerAlertService", qos: .utility) + private let queue: DispatchQueue = .init(label: "MigrationManagerAlertService", qos: .utility) func migrateIfNeeded() { guard persistanceVersion < actualServiceVersion else { return } - for version in persistanceVersion.. Void)) { let group = DispatchGroup() group.enter() fetchRuuviSensors { ruuviTagSensors in self.queue.async { - ruuviTagSensors.forEach({ element in + ruuviTagSensors.forEach { element in group.enter() self.migrateTo1Version(element: element, completion: { group.leave() }) - }) + } group.leave() } } - self.queue.async { + queue.async { group.notify(queue: .main, execute: { completion(true) }) @@ -98,24 +99,26 @@ extension MigrationManagerAlertService { if prefs.bool(forKey: Keys.Ver1.relativeHumidityAlertIsOnUDKeyPrefix + id), let lower = prefs.optionalDouble(forKey: Keys.Ver1.relativeHumidityLowerBoundUDKeyPrefix + id), let upper = prefs.optionalDouble(forKey: Keys.Ver1.relativeHumidityUpperBoundUDKeyPrefix + id), - let temperature = element.1 { + let temperature = element.1 + { prefs.set(false, forKey: Keys.Ver1.relativeHumidityAlertIsOnUDKeyPrefix + id) - let lowerHumidity: Humidity = Humidity(value: lower / 100, - unit: .relative(temperature: temperature)) - let upperHumidity: Humidity = Humidity(value: upper / 100, - unit: .relative(temperature: temperature)) + let lowerHumidity = Humidity(value: lower / 100, + unit: .relative(temperature: temperature)) + let upperHumidity = Humidity(value: upper / 100, + unit: .relative(temperature: temperature)) ruuviAlertService.register( type: .humidity(lower: lowerHumidity, upper: upperHumidity), ruuviTag: element.0 ) } else if prefs.bool(forKey: Keys.Ver1.absoluteHumidityAlertIsOnUDKeyPrefix + id), let lower = prefs.optionalDouble(forKey: Keys.Ver1.absoluteHumidityLowerBoundUDKeyPrefix + id), - let upper = prefs.optionalDouble(forKey: Keys.Ver1.absoluteHumidityUpperBoundUDKeyPrefix + id) { + let upper = prefs.optionalDouble(forKey: Keys.Ver1.absoluteHumidityUpperBoundUDKeyPrefix + id) + { prefs.set(false, forKey: Keys.Ver1.absoluteHumidityAlertIsOnUDKeyPrefix + id) - let lowerHumidity: Humidity = Humidity(value: lower, - unit: .absolute) - let upperHumidity: Humidity = Humidity(value: upper, - unit: .absolute) + let lowerHumidity = Humidity(value: lower, + unit: .absolute) + let upperHumidity = Humidity(value: upper, + unit: .absolute) ruuviAlertService.register( type: .humidity(lower: lowerHumidity, upper: upperHumidity), ruuviTag: element.0 @@ -137,14 +140,14 @@ extension MigrationManagerAlertService { let group = DispatchGroup() group.enter() var result = [(RuuviTagSensor, Temperature?)]() - self.ruuviStorage.readAll().on(success: {sensors in - sensors.forEach({ sensor in + self.ruuviStorage.readAll().on(success: { sensors in + sensors.forEach { sensor in group.enter() self.fetchRecord(for: sensor) { result.append($0) group.leave() } - }) + } group.leave() }, failure: { _ in group.leave() @@ -166,5 +169,4 @@ extension MigrationManagerAlertService { complete((sensor, nil)) }) } - } diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift index 0c86313ba..f0139aa3f 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift @@ -1,9 +1,9 @@ +import RuuviContext import RuuviLocal +import RuuviMigration import RuuviPool -import RuuviContext -import RuuviStorage import RuuviService -import RuuviMigration +import RuuviStorage public final class RuuviMigrationFactoryImpl: RuuviMigrationFactory { private let settings: RuuviLocalSettings diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/SensorSettings/MigrationManagerSensorSettings.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/SensorSettings/MigrationManagerSensorSettings.swift index 876193bcd..13b49201e 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/SensorSettings/MigrationManagerSensorSettings.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/SensorSettings/MigrationManagerSensorSettings.swift @@ -1,7 +1,7 @@ import Foundation -import RuuviStorage -import RuuviService import RuuviMigration +import RuuviService +import RuuviStorage class MigrationManagerSensorSettings: RuuviMigration { private let calibrationPersistence: CalibrationPersistence diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/Util/CalibrationPersistence/UserDefaults/CalibrationPersistenceUserDefaults.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/Util/CalibrationPersistence/UserDefaults/CalibrationPersistenceUserDefaults.swift index 48c354d39..2f4593119 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/Util/CalibrationPersistence/UserDefaults/CalibrationPersistenceUserDefaults.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/Util/CalibrationPersistence/UserDefaults/CalibrationPersistenceUserDefaults.swift @@ -2,11 +2,10 @@ import Foundation import RuuviOntology class CalibrationPersistenceUserDefaults: CalibrationPersistence { - private let humidityOffsetDatePrefixUDKey = - "CalibrationPersistenceUserDefaults.humidityOffsetDate" + "CalibrationPersistenceUserDefaults.humidityOffsetDate" private let humidityOffsetPrefixUDKey = - "CalibrationPersistenceUserDefaults.humidityOffset" + "CalibrationPersistenceUserDefaults.humidityOffset" func humidityOffset(for identifier: Identifier) -> (Double, Date?) { let uuid = identifier.value diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/Util/UserDefault.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/Util/UserDefault.swift index 3ef972d50..bdd1f1ebe 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/Util/UserDefault.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/Util/UserDefault.swift @@ -12,7 +12,7 @@ struct UserDefault { var wrappedValue: T { get { - return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue + UserDefaults.standard.object(forKey: key) as? T ?? defaultValue } set { UserDefaults.standard.set(newValue, forKey: key) diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/fixRHAlerts/RuuviMigrationFixRHAlerts.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/fixRHAlerts/RuuviMigrationFixRHAlerts.swift index b2862d9f7..5d4bf5a4e 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/fixRHAlerts/RuuviMigrationFixRHAlerts.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/fixRHAlerts/RuuviMigrationFixRHAlerts.swift @@ -1,11 +1,11 @@ import Foundation -import UIKit +import RuuviContext import RuuviLocal +import RuuviMigration import RuuviPool -import RuuviContext -import RuuviStorage import RuuviService -import RuuviMigration +import RuuviStorage +import UIKit final class RuuviMigrationFixRHAlerts: RuuviMigration { private let ruuviStorage: RuuviStorage @@ -28,7 +28,8 @@ final class RuuviMigrationFixRHAlerts: RuuviMigration { .on(success: { sensors in sensors.forEach { sensor in if let lower = self.ruuviAlertService.lowerRelativeHumidity(for: sensor), - lower > 1.0 { + lower > 1.0 + { self.ruuviAlertService.setLower( relativeHumidity: lower / 100.0, ruuviTag: sensor diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toRH/MigrationManagerToRH.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toRH/MigrationManagerToRH.swift index 39645d874..e1321efe8 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toRH/MigrationManagerToRH.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toRH/MigrationManagerToRH.swift @@ -1,8 +1,8 @@ import Foundation -import RuuviStorage +import RuuviMigration import RuuviOntology import RuuviService -import RuuviMigration +import RuuviStorage final class MigrationManagerToRH: RuuviMigration { private let ruuviStorage: RuuviStorage @@ -16,7 +16,7 @@ final class MigrationManagerToRH: RuuviMigration { self.ruuviAlertService = ruuviAlertService } - private let queue: DispatchQueue = DispatchQueue(label: "MigrationManagerToRH", qos: .utility) + private let queue: DispatchQueue = .init(label: "MigrationManagerToRH", qos: .utility) private let migratedUdKey = "MigrationManagerToRH.migrated" func migrateIfNeeded() { @@ -24,25 +24,28 @@ final class MigrationManagerToRH: RuuviMigration { fetchRuuviSensors { tuples in self.queue.async { - tuples.forEach({ tuple in + tuples.forEach { tuple in let sensor = tuple.0 let temperature = tuple.1 if let lower = self.ruuviAlertService.lowerHumidity(for: sensor), let upper = self.ruuviAlertService.upperHumidity(for: sensor), - let temperature = temperature { + let temperature + { let humidityType: AlertType = .humidity(lower: lower, upper: upper) if self.ruuviAlertService.isOn(type: humidityType, for: sensor) { self.ruuviAlertService.register( type: .relativeHumidity( lower: lower.converted(to: .relative(temperature: temperature)).value, - upper: upper.converted(to: .relative(temperature: temperature)).value), - ruuviTag: sensor) + upper: upper.converted(to: .relative(temperature: temperature)).value + ), + ruuviTag: sensor + ) } } if let description = self.ruuviAlertService.humidityDescription(for: sensor) { self.ruuviAlertService.setRelativeHumidity(description: description, ruuviTag: sensor) } - }) + } } } @@ -54,14 +57,14 @@ final class MigrationManagerToRH: RuuviMigration { let group = DispatchGroup() group.enter() var result = [(RuuviTagSensor, Temperature?)]() - self.ruuviStorage.readAll().on(success: {sensors in - sensors.forEach({ sensor in + self.ruuviStorage.readAll().on(success: { sensors in + sensors.forEach { sensor in group.enter() self.fetchRecord(for: sensor) { result.append($0) group.leave() } - }) + } group.leave() }, failure: { _ in group.leave() diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift index 378ffff9c..08e4b0f88 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift @@ -1,12 +1,12 @@ import Foundation import RealmSwift -import RuuviOntology import RuuviContext import RuuviLocal -import RuuviPool import RuuviMigration +import RuuviOntology +import RuuviPool #if canImport(RuuviOntologyRealm) -import RuuviOntologyRealm + import RuuviOntologyRealm #endif extension Notification.Name { @@ -35,10 +35,10 @@ class MigrationManagerToSQLite: RuuviMigration { if !didMigrateRuuviTagRealmWithMAC { let realmTags = realmContext.main.objects(RuuviTagRealm.self) let dispatchGroup = DispatchGroup() - realmTags.forEach({ + realmTags.forEach { dispatchGroup.enter() migrate(realmTag: $0, group: dispatchGroup) - }) + } dispatchGroup.notify(queue: .main) { NotificationCenter .default diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift index e993d663e..5767a574a 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift @@ -1,10 +1,10 @@ -import RealmSwift import Foundation -import RuuviOntology +import RealmSwift import RuuviLocal import RuuviMigration +import RuuviOntology #if canImport(RuuviOntologyRealm) -import RuuviOntologyRealm + import RuuviOntologyRealm #endif public final class MigrationManagerToVIPER: RuuviMigration { @@ -32,10 +32,11 @@ public final class MigrationManagerToVIPER: RuuviMigration { } else if oldSchemaVersion < 8 { self?.deleteRuuviTagData(migration) } - }, shouldCompactOnLaunch: { totalBytes, usedBytes in - let fiveHundredMegabytes = 500 * 1024 * 1024 - return (totalBytes > fiveHundredMegabytes) && (Double(usedBytes) / Double(totalBytes)) < 0.5 - }) + }, shouldCompactOnLaunch: { totalBytes, usedBytes in + let fiveHundredMegabytes = 500 * 1024 * 1024 + return (totalBytes > fiveHundredMegabytes) && (Double(usedBytes) / Double(totalBytes)) < 0.5 + } + ) // Tell Realm to use this new configuration object for the default Realm Realm.Configuration.defaultConfiguration = config @@ -71,13 +72,13 @@ public final class MigrationManagerToVIPER: RuuviMigration { } private func from1to2(_ migration: Migration) { - migration.enumerateObjects(ofType: "RuuviTag", { (oldObject, _) in + migration.enumerateObjects(ofType: "RuuviTag") { oldObject, _ in if let uuid = oldObject?["uuid"] as? String, - let name = oldObject?["name"] as? String, - let version = oldObject?["dataFormat"] as? Int, - let mac = oldObject?["mac"] as? String { - + let name = oldObject?["name"] as? String, + let version = oldObject?["dataFormat"] as? Int, + let mac = oldObject?["mac"] as? String + { let realName = real(name, mac, uuid) let ruuviTag = migration.create(RuuviTagRealm.className(), value: ["uuid": uuid, @@ -86,17 +87,18 @@ public final class MigrationManagerToVIPER: RuuviMigration { "mac": mac]) if let temperature = oldObject?["temperature"] as? Double, - let humidity = oldObject?["humidity"] as? Double, - let pressure = oldObject?["pressure"] as? Double, - let accelerationX = oldObject?["accelerationX"] as? Double, - let accelerationY = oldObject?["accelerationY"] as? Double, - let accelerationZ = oldObject?["accelerationZ"] as? Double, - let rssi = oldObject?["rssi"] as? Int, - let voltage = oldObject?["voltage"] as? Double, - let movementCounter = oldObject?["movementCounter"] as? Int, - let measurementSequenceNumber = oldObject?["measurementSequenceNumber"] as? Int, - let txPower = oldObject?["txPower"] as? Int, - let updatedAt = oldObject?["updatedAt"] as? NSDate { + let humidity = oldObject?["humidity"] as? Double, + let pressure = oldObject?["pressure"] as? Double, + let accelerationX = oldObject?["accelerationX"] as? Double, + let accelerationY = oldObject?["accelerationY"] as? Double, + let accelerationZ = oldObject?["accelerationZ"] as? Double, + let rssi = oldObject?["rssi"] as? Int, + let voltage = oldObject?["voltage"] as? Double, + let movementCounter = oldObject?["movementCounter"] as? Int, + let measurementSequenceNumber = oldObject?["measurementSequenceNumber"] as? Int, + let txPower = oldObject?["txPower"] as? Int, + let updatedAt = oldObject?["updatedAt"] as? NSDate + { migration.create(RuuviTagDataRealm.className(), value: ["ruuviTag": ruuviTag, "date": updatedAt, @@ -117,7 +119,7 @@ public final class MigrationManagerToVIPER: RuuviMigration { if let uuid = oldObject?["uuid"] as? String, let id = oldObject?["defaultBackground"] as? Int { localImages.setBackground(id, for: uuid.luid) } - }) + } } private func from2to3(_ migration: Migration) { @@ -143,17 +145,15 @@ public final class MigrationManagerToVIPER: RuuviMigration { } private func real(_ name: String, _ mac: String, _ uuid: String) -> String { - let realName: String - if name.isEmpty { + let realName: String = if name.isEmpty { if mac.isEmpty { - realName = uuid + uuid } else { - realName = mac + mac } } else { - realName = name + name } return realName } - } diff --git a/Packages/RuuviMigration/Tests/RuuviMigrationTests/RuuviMigrationTests.swift b/Packages/RuuviMigration/Tests/RuuviMigrationTests/RuuviMigrationTests.swift index 7af5d7c7b..d68619b1f 100644 --- a/Packages/RuuviMigration/Tests/RuuviMigrationTests/RuuviMigrationTests.swift +++ b/Packages/RuuviMigration/Tests/RuuviMigrationTests/RuuviMigrationTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviMigration +import XCTest final class RuuviMigrationTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Packages/RuuviNotification/Package.swift b/Packages/RuuviNotification/Package.swift index b3ca8eac8..c349896c2 100644 --- a/Packages/RuuviNotification/Package.swift +++ b/Packages/RuuviNotification/Package.swift @@ -9,10 +9,12 @@ let package = Package( products: [ .library( name: "RuuviNotification", - targets: ["RuuviNotification"]), + targets: ["RuuviNotification"] + ), .library( name: "RuuviNotificationLocal", - targets: ["RuuviNotificationLocal"]) + targets: ["RuuviNotificationLocal"] + ), ], dependencies: [ .package(path: "../RuuviOntology"), @@ -23,7 +25,8 @@ let package = Package( targets: [ .target( name: "RuuviNotification", - dependencies: []), + dependencies: [] + ), .target( name: "RuuviNotificationLocal", dependencies: [ @@ -31,10 +34,12 @@ let package = Package( "RuuviService", "RuuviLocal", "RuuviStorage", - "RuuviOntology" - ]), + "RuuviOntology", + ] + ), .testTarget( name: "RuuviNotificationTests", - dependencies: ["RuuviNotification"]) + dependencies: ["RuuviNotification"] + ), ] ) diff --git a/Packages/RuuviNotification/Sources/RuuviNotification/RuuviNotificationLocal.swift b/Packages/RuuviNotification/Sources/RuuviNotification/RuuviNotificationLocal.swift index bcb92a57f..9b8c11973 100644 --- a/Packages/RuuviNotification/Sources/RuuviNotification/RuuviNotificationLocal.swift +++ b/Packages/RuuviNotification/Sources/RuuviNotification/RuuviNotificationLocal.swift @@ -1,8 +1,8 @@ import Foundation import UIKit -extension Notification.Name { - public static let LNMDidReceive = Notification.Name("LNMDidReceive") +public extension Notification.Name { + static let LNMDidReceive = Notification.Name("LNMDidReceive") } public enum LNMDidReceiveKey: String { diff --git a/Packages/RuuviNotification/Sources/RuuviNotificationLocal/RuuviNotificationLocalImpl.swift b/Packages/RuuviNotification/Sources/RuuviNotificationLocal/RuuviNotificationLocalImpl.swift index cf4d877a3..59e8c94ec 100644 --- a/Packages/RuuviNotification/Sources/RuuviNotificationLocal/RuuviNotificationLocalImpl.swift +++ b/Packages/RuuviNotification/Sources/RuuviNotificationLocal/RuuviNotificationLocalImpl.swift @@ -1,12 +1,12 @@ -// swiftlint:disable file_length -import UserNotifications import Foundation -import UIKit -import RuuviOntology -import RuuviStorage import RuuviLocal -import RuuviService import RuuviNotification +import RuuviOntology +import RuuviService +import RuuviStorage +import UIKit +// swiftlint:disable file_length +import UserNotifications struct LocalAlertCategory { var id: String @@ -74,7 +74,8 @@ public final class RuuviNotificationLocalImpl: NSObject, RuuviNotificationLocal public func setup(disableTitle: String, muteTitle: String, - output: RuuviNotificationLocalOutput?) { + output: RuuviNotificationLocalOutput?) + { setupButtons(disableTitle: disableTitle, muteTitle: muteTitle) startObserving() self.output = output @@ -85,11 +86,10 @@ public final class RuuviNotificationLocalImpl: NSObject, RuuviNotificationLocal } private func id(for uuid: String) -> String { - var id: String - if let macId = idPersistence.mac(for: uuid.luid) { - id = macId.value + var id: String = if let macId = idPersistence.mac(for: uuid.luid) { + macId.value } else { - id = uuid + uuid } return id } @@ -99,7 +99,7 @@ public final class RuuviNotificationLocalImpl: NSObject, RuuviNotificationLocal var cache: [String: Date] = connectAlerts if let shownDate = cache[uuid] { - var intervalPassed: Bool = true + var intervalPassed = true if settings.limitAlertNotificationsEnabled { intervalPassed = Date() > lastTriggerOffset(from: shownDate) } @@ -147,7 +147,7 @@ public final class RuuviNotificationLocalImpl: NSObject, RuuviNotificationLocal var cache: [String: Date] = disconnectAlerts if let shownDate = cache[uuid] { - var intervalPassed: Bool = true + var intervalPassed = true if settings.limitAlertNotificationsEnabled { intervalPassed = Date() > lastTriggerOffset(from: shownDate) } @@ -190,12 +190,12 @@ public final class RuuviNotificationLocalImpl: NSObject, RuuviNotificationLocal } } - public func notifyDidMove(for uuid: String, counter: Int, title: String) { + public func notifyDidMove(for uuid: String, counter _: Int, title: String) { var needsToShow: Bool var cache: [String: Date] = movementAlerts if let shownDate = cache[uuid] { - var intervalPassed: Bool = true + var intervalPassed = true if settings.limitAlertNotificationsEnabled { intervalPassed = Date() > lastTriggerOffset(from: shownDate) } @@ -241,48 +241,47 @@ public final class RuuviNotificationLocalImpl: NSObject, RuuviNotificationLocal } // MARK: - Notify -extension RuuviNotificationLocalImpl { +public extension RuuviNotificationLocalImpl { // swiftlint:disable:next cyclomatic_complexity function_body_length - public func notify( + func notify( _ reason: LowHighNotificationReason, _ type: LowHighNotificationType, for uuid: String, title: String ) { var needsToShow: Bool - var cache: [String: Date] - switch reason { + var cache: [String: Date] = switch reason { case .low: switch type { case .temperature: - cache = lowTemperatureAlerts + lowTemperatureAlerts case .relativeHumidity: - cache = lowRelativeHumidityAlerts + lowRelativeHumidityAlerts case .humidity: - cache = lowHumidityAlerts + lowHumidityAlerts case .pressure: - cache = lowPressureAlerts + lowPressureAlerts case .signal: - cache = lowSignalAlerts + lowSignalAlerts } case .high: switch type { case .temperature: - cache = highTemperatureAlerts + highTemperatureAlerts case .relativeHumidity: - cache = highRelativeHumidityAlerts + highRelativeHumidityAlerts case .humidity: - cache = highHumidityAlerts + highHumidityAlerts case .pressure: - cache = highPressureAlerts + highPressureAlerts case .signal: - cache = highSignalAlerts + highSignalAlerts } } if let shownDate = cache[uuid] { - var intervalPassed: Bool = false + var intervalPassed = false if settings.limitAlertNotificationsEnabled { intervalPassed = Date() > lastTriggerOffset(from: shownDate) } else { @@ -315,18 +314,17 @@ extension RuuviNotificationLocalImpl { content.userInfo = [lowHigh.uuidKey: uuid, lowHigh.typeKey: type.rawValue] content.categoryIdentifier = lowHigh.id - let body: String - switch type { + let body: String = switch type { case .temperature: - body = ruuviAlertService.temperatureDescription(for: uuid) ?? "" + ruuviAlertService.temperatureDescription(for: uuid) ?? "" case .relativeHumidity: - body = ruuviAlertService.relativeHumidityDescription(for: uuid) ?? "" + ruuviAlertService.relativeHumidityDescription(for: uuid) ?? "" case .humidity: - body = ruuviAlertService.humidityDescription(for: uuid) ?? "" + ruuviAlertService.humidityDescription(for: uuid) ?? "" case .pressure: - body = ruuviAlertService.pressureDescription(for: uuid) ?? "" + ruuviAlertService.pressureDescription(for: uuid) ?? "" case .signal: - body = ruuviAlertService.signalDescription(for: uuid) ?? "" + ruuviAlertService.signalDescription(for: uuid) ?? "" } content.body = body @@ -371,31 +369,32 @@ extension RuuviNotificationLocalImpl { } // MARK: - Private + extension RuuviNotificationLocalImpl { private static func alertType(from type: LowHighNotificationType) -> AlertType { switch type { case .temperature: - return .temperature(lower: 0, upper: 0) + .temperature(lower: 0, upper: 0) case .relativeHumidity: - return .relativeHumidity(lower: 0, upper: 0) + .relativeHumidity(lower: 0, upper: 0) case .humidity: - return .humidity( + .humidity( lower: Humidity(value: 0, unit: .absolute), upper: Humidity(value: 0, unit: .absolute) ) case .pressure: - return .pressure(lower: 0, upper: 0) + .pressure(lower: 0, upper: 0) case .signal: - return .signal(lower: 0, upper: 0) + .signal(lower: 0, upper: 0) } } private static func alertType(from type: BlastNotificationType) -> AlertType { switch type { case .connection: - return .connection + .connection case .movement: - return .movement(last: 0) + .movement(last: 0) } } @@ -405,14 +404,15 @@ extension RuuviNotificationLocalImpl { .default .addObserver(forName: .RuuviServiceAlertDidChange, object: nil, - queue: .main) { [weak self] (notification) in + queue: .main) + { [weak self] notification in if let userInfo = notification.userInfo, - let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType { - + let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType + { let physicalSensor = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor var isOn = false - if let physicalSensor = physicalSensor { + if let physicalSensor { isOn = self?.ruuviAlertService.isOn(type: type, for: physicalSensor) ?? false } @@ -459,8 +459,8 @@ extension RuuviNotificationLocalImpl { } // MARK: - UNUserNotificationCenterDelegate -extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { +extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { private func setupButtons(disableTitle: String, muteTitle: String) { let nc = UNUserNotificationCenter.current() nc.delegate = self @@ -504,8 +504,8 @@ extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { } public func userNotificationCenter( - _ center: UNUserNotificationCenter, - willPresent notification: UNNotification, + _: UNUserNotificationCenter, + willPresent _: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void ) { completionHandler([.alert, .badge, .sound]) @@ -513,14 +513,15 @@ extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { // swiftlint:disable:next function_body_length public func userNotificationCenter( - _ center: UNUserNotificationCenter, + _: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void ) { let userInfo = response.notification.request.content.userInfo if let uuid = userInfo[lowHigh.uuidKey] as? String, - let typeString = userInfo[lowHigh.typeKey] as? String, - let type = LowHighNotificationType(rawValue: typeString) { + let typeString = userInfo[lowHigh.typeKey] as? String, + let type = LowHighNotificationType(rawValue: typeString) + { switch response.actionIdentifier { case lowHigh.disable: // TODO: @rinat go with sensors instead of pure uuid @@ -547,8 +548,9 @@ extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { } } else if let uuid = userInfo[blast.uuidKey] as? String, - let typeString = userInfo[blast.typeKey] as? String, - let type = BlastNotificationType(rawValue: typeString) { + let typeString = userInfo[blast.typeKey] as? String, + let type = BlastNotificationType(rawValue: typeString) + { switch response.actionIdentifier { case blast.disable: // TODO: @rinat go with sensors instead of pure uuid @@ -576,7 +578,8 @@ extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { } if let uuid = userInfo[lowHigh.uuidKey] as? String - ?? userInfo[blast.uuidKey] as? String { + ?? userInfo[blast.uuidKey] as? String + { NotificationCenter.default.post(name: .LNMDidReceive, object: nil, userInfo: [LNMDidReceiveKey.uuid: uuid]) output?.notificationDidTap(for: uuid) } @@ -650,24 +653,23 @@ extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { } private func muteOffset() -> Date? { - return Calendar.current.date( + Calendar.current.date( byAdding: .minute, - value: self.settings.alertsMuteIntervalMinutes, + value: settings.alertsMuteIntervalMinutes, to: Date() ) } private func lastTriggerOffset(from shown: Date) -> Date { - return Calendar.current.date( + Calendar.current.date( byAdding: .minute, - value: self.settings.alertsMuteIntervalMinutes, + value: settings.alertsMuteIntervalMinutes, to: shown ) ?? Date() } } extension NSObjectProtocol { - func invalidate() { // swiftlint:disable:next notification_center_detachment NotificationCenter @@ -675,4 +677,5 @@ extension NSObjectProtocol { .removeObserver(self) } } + // swiftlint:enable file_length diff --git a/Packages/RuuviNotification/Tests/RuuviNotificationTests/RuuviNotificationTests.swift b/Packages/RuuviNotification/Tests/RuuviNotificationTests/RuuviNotificationTests.swift index a55241083..db9784ad5 100644 --- a/Packages/RuuviNotification/Tests/RuuviNotificationTests/RuuviNotificationTests.swift +++ b/Packages/RuuviNotification/Tests/RuuviNotificationTests/RuuviNotificationTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviNotification +import XCTest final class RuuviNotificationTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Packages/RuuviNotifier/Package.swift b/Packages/RuuviNotifier/Package.swift index 2ea7431fe..76b97422c 100644 --- a/Packages/RuuviNotifier/Package.swift +++ b/Packages/RuuviNotifier/Package.swift @@ -9,32 +9,37 @@ let package = Package( products: [ .library( name: "RuuviNotifier", - targets: ["RuuviNotifier"]), + targets: ["RuuviNotifier"] + ), .library( name: "RuuviNotifierImpl", - targets: ["RuuviNotifierImpl"]) + targets: ["RuuviNotifierImpl"] + ), ], dependencies: [ .package(path: "../RuuviOntology"), .package(path: "../RuuviService"), - .package(path: "../RuuviNotification") + .package(path: "../RuuviNotification"), ], targets: [ .target( name: "RuuviNotifier", dependencies: [ "RuuviOntology", - ]), + ] + ), .target( name: "RuuviNotifierImpl", dependencies: [ "RuuviNotifier", "RuuviOntology", "RuuviService", - "RuuviNotification" - ]), + "RuuviNotification", + ] + ), .testTarget( name: "RuuviNotifierTests", - dependencies: ["RuuviNotifier"]) + dependencies: ["RuuviNotifier"] + ), ] ) diff --git a/Packages/RuuviNotifier/Sources/RuuviNotifier/RuuviNotifier.swift b/Packages/RuuviNotifier/Sources/RuuviNotifier/RuuviNotifier.swift index 7c86af062..ba6c750c9 100644 --- a/Packages/RuuviNotifier/Sources/RuuviNotifier/RuuviNotifier.swift +++ b/Packages/RuuviNotifier/Sources/RuuviNotifier/RuuviNotifier.swift @@ -18,12 +18,12 @@ public protocol RuuviNotifierObserver: AnyObject { for uuid: String) } -extension RuuviNotifierObserver { +public extension RuuviNotifierObserver { // Optional method implementation - public func ruuvi(notifier: RuuviNotifier, - alertType: AlertType, - isTriggered: Bool, - for uuid: String) {} + func ruuvi(notifier _: RuuviNotifier, + alertType _: AlertType, + isTriggered _: Bool, + for _: String) {} } public protocol RuuviNotifierTitles { diff --git a/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl+Process.swift b/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl+Process.swift index 70555af3e..57e9e1e4e 100644 --- a/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl+Process.swift +++ b/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl+Process.swift @@ -1,19 +1,20 @@ // swiftlint:disable file_length import Foundation -import RuuviOntology import RuuviNotifier +import RuuviOntology // MARK: - Process Physical Sensors -extension RuuviNotifierImpl { +public extension RuuviNotifierImpl { // swiftlint:disable:next function_body_length - public func process(record record: RuuviTagSensorRecord, trigger: Bool) { + func process(record record: RuuviTagSensorRecord, trigger: Bool) { guard let luid = record.luid, - ruuviAlertService.hasRegistrations(for: record) else { + ruuviAlertService.hasRegistrations(for: record) + else { return } var isTriggered = false - AlertType.allCases.forEach { (type) in + AlertType.allCases.forEach { type in switch type { case .temperature: let isTemperature = process( @@ -73,23 +74,25 @@ extension RuuviNotifierImpl { } // MARK: - Process Network Sensors -extension RuuviNotifierImpl { + +public extension RuuviNotifierImpl { // swiftlint:disable:next function_body_length - public func processNetwork(record: RuuviTagSensorRecord, - trigger: Bool, - for identifier: MACIdentifier) { + func processNetwork(record: RuuviTagSensorRecord, + trigger: Bool, + for identifier: MACIdentifier) + { guard ruuviAlertService.hasRegistrations(for: record) else { return } var isTriggered = false - AlertType.allCases.forEach { (type) in + AlertType.allCases.forEach { type in switch type { case .temperature: let isTemperature = process(temperature: record.temperature, - alertType: type, - identifier: identifier, - trigger: trigger) + alertType: type, + identifier: identifier, + trigger: trigger) isTriggered = isTriggered || isTemperature notify(alertType: type, uuid: identifier.value, @@ -108,18 +111,18 @@ extension RuuviNotifierImpl { isTriggered: isRelativeHumidity) case .pressure: let isPressure = process(pressure: record.pressure, - alertType: type, - identifier: identifier, - trigger: trigger) + alertType: type, + identifier: identifier, + trigger: trigger) isTriggered = isTriggered || isPressure notify(alertType: type, uuid: identifier.value, isTriggered: isPressure) case .signal: let isSignal = process(signal: record.rssi, - alertType: type, - identifier: identifier, - trigger: trigger) + alertType: type, + identifier: identifier, + trigger: trigger) isTriggered = isTriggered || isSignal notify(alertType: type, uuid: identifier.value, @@ -141,16 +144,19 @@ extension RuuviNotifierImpl { notify(uuid: identifier.value, isTriggered: isTriggered) } } + // MARK: - Notify + extension RuuviNotifierImpl { private func notify(uuid: String, isTriggered: Bool) { DispatchQueue.main.async { [weak self] in guard let sSelf = self else { return } if let observers = sSelf.observations[uuid] { - for i in 0...fromOpaque(pointer).takeUnretainedValue() - as? RuuviNotifierObserver { + let observer = Unmanaged.fromOpaque(pointer).takeUnretainedValue() + as? RuuviNotifierObserver + { observer.ruuvi( notifier: sSelf, isTriggered: isTriggered, @@ -166,10 +172,11 @@ extension RuuviNotifierImpl { DispatchQueue.main.async { [weak self] in guard let sSelf = self else { return } if let observers = sSelf.observations[uuid] { - for i in 0...fromOpaque(pointer).takeUnretainedValue() - as? RuuviNotifierObserver { + let observer = Unmanaged.fromOpaque(pointer).takeUnretainedValue() + as? RuuviNotifierObserver + { observer.ruuvi( notifier: sSelf, alertType: alertType, @@ -182,7 +189,9 @@ extension RuuviNotifierImpl { } } } + // MARK: - Private + extension RuuviNotifierImpl { private func process( temperature: Temperature?, @@ -190,11 +199,12 @@ extension RuuviNotifierImpl { identifier: Identifier?, trigger: Bool = true ) -> Bool { - guard let identifier = identifier else { return false } - if case .temperature(let lower, let upper) = ruuviAlertService.alert(for: identifier.value, of: alertType), + guard let identifier else { return false } + if case let .temperature(lower, upper) = ruuviAlertService.alert(for: identifier.value, of: alertType), let l = Temperature(lower), let u = Temperature(upper), - let t = temperature { + let t = temperature + { let isLower = t < l let isUpper = t > u if trigger { @@ -222,7 +232,7 @@ extension RuuviNotifierImpl { } return isLower || isUpper } else { - return false + return false } } @@ -233,10 +243,11 @@ extension RuuviNotifierImpl { identifier: Identifier?, trigger: Bool = true ) -> Bool { - guard let identifier = identifier else { return false } - if case .relativeHumidity(let lower, let upper) = ruuviAlertService.alert(for: identifier.value, of: alertType), + guard let identifier else { return false } + if case let .relativeHumidity(lower, upper) = ruuviAlertService.alert(for: identifier.value, of: alertType), let t = temperature, - let rh = relativeHumidity?.converted(to: .relative(temperature: t)) { + let rh = relativeHumidity?.converted(to: .relative(temperature: t)) + { let isLower = rh.value < lower let isUpper = rh.value > upper if trigger { @@ -274,11 +285,12 @@ extension RuuviNotifierImpl { identifier: Identifier?, trigger: Bool = true ) -> Bool { - guard let identifier = identifier else { return false } - if case .pressure(let lower, let upper) = ruuviAlertService.alert(for: identifier.value, of: alertType), + guard let identifier else { return false } + if case let .pressure(lower, upper) = ruuviAlertService.alert(for: identifier.value, of: alertType), let l = Pressure(lower), let u = Pressure(upper), - let pressure = pressure { + let pressure + { let isLower = pressure < l let isUpper = pressure > u if trigger { @@ -316,11 +328,12 @@ extension RuuviNotifierImpl { identifier: Identifier?, trigger: Bool = true ) -> Bool { - guard let identifier = identifier else { return false } - if case .signal(let lower, let upper) = ruuviAlertService + guard let identifier else { return false } + if case let .signal(lower, upper) = ruuviAlertService .alert(for: identifier.value, of: alertType), - let signal = signal { + let signal + { let isLower = Double(signal) < lower let isUpper = Double(signal) > upper if trigger { @@ -358,8 +371,9 @@ extension RuuviNotifierImpl { trigger: Bool = true ) -> Bool { guard let luid = record.luid else { return false } - if case .movement(let last) = ruuviAlertService.alert(for: luid.value, of: movement), - let movementCounter = record.movementCounter { + if case let .movement(last) = ruuviAlertService.alert(for: luid.value, of: movement), + let movementCounter = record.movementCounter + { let isGreater = movementCounter > last if trigger { if isGreater { @@ -384,12 +398,12 @@ extension RuuviNotifierImpl { alertType: AlertType, identifier: MACIdentifier? ) -> Bool { - guard let identifier = identifier else { return false } + guard let identifier else { return false } - if case .cloudConnection(let unseenDuration) = ruuviAlertService + if case let .cloudConnection(unseenDuration) = ruuviAlertService .alert(for: identifier.value, - of: alertType) { - + of: alertType) + { let calendar = Calendar.current let thresholdDateTime = calendar.date( byAdding: .second, value: -Int(unseenDuration), to: Date() @@ -413,5 +427,4 @@ extension RuuviNotifierImpl { // Default case, don't trigger alert return false } - } diff --git a/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl.swift b/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl.swift index 1d255850c..39ca726eb 100644 --- a/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl.swift +++ b/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl.swift @@ -1,9 +1,9 @@ import Foundation -import RuuviOntology -import RuuviService +import RuuviLocal import RuuviNotification import RuuviNotifier -import RuuviLocal +import RuuviOntology +import RuuviService public final class RuuviNotifierImpl: RuuviNotifier { var observations = [String: NSPointerArray]() @@ -19,12 +19,12 @@ public final class RuuviNotifierImpl: RuuviNotifier { titles: RuuviNotifierTitles ) { self.ruuviAlertService = ruuviAlertService - self.localNotificationsManager = ruuviNotificationLocal + localNotificationsManager = ruuviNotificationLocal self.localSyncState = localSyncState self.titles = titles } - public func subscribe(_ observer: T, to uuid: String) { + public func subscribe(_ observer: some RuuviNotifierObserver, to uuid: String) { guard !isSubscribed(observer, to: uuid) else { return } let pointer = Unmanaged.passUnretained(observer).toOpaque() if let array = observations[uuid] { @@ -38,10 +38,10 @@ public final class RuuviNotifierImpl: RuuviNotifier { } } - public func isSubscribed(_ observer: T, to uuid: String) -> Bool { + public func isSubscribed(_ observer: some RuuviNotifierObserver, to uuid: String) -> Bool { let observerPointer = Unmanaged.passUnretained(observer).toOpaque() if let array = observations[uuid] { - for i in 0.. [Element] { +public extension Array where Element: Reorderable { + func reorder(by preferredOrder: [Element.OrderElement]) -> [Element] { sorted { guard let first = preferredOrder.firstIndex(of: $0.orderElement) else { return false diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Common/RuuviCloudQueuedRequest.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Common/RuuviCloudQueuedRequest.swift index 0efd95f82..d0a607882 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Common/RuuviCloudQueuedRequest.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Common/RuuviCloudQueuedRequest.swift @@ -27,9 +27,9 @@ public protocol RuuviCloudQueuedRequest { var additionalData: Data? { get } } -extension RuuviCloudQueuedRequest { - public func with(attempts: Int) -> RuuviCloudQueuedRequest { - return RuuviCloudQueuedRequestStruct( +public extension RuuviCloudQueuedRequest { + func with(attempts: Int) -> RuuviCloudQueuedRequest { + RuuviCloudQueuedRequestStruct( id: id, type: type, status: status, @@ -44,7 +44,6 @@ extension RuuviCloudQueuedRequest { } public struct RuuviCloudQueuedRequestStruct: RuuviCloudQueuedRequest { - public var id: Int64? public var type: RuuviCloudQueuedRequestType? public var status: RuuviCloudQueuedRequestStatusType? diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Common/RuuviTheme.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Common/RuuviTheme.swift index fa749eb50..c46560aa9 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Common/RuuviTheme.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Common/RuuviTheme.swift @@ -6,11 +6,11 @@ public enum RuuviTheme: String { public var uiInterfaceStyle: UIUserInterfaceStyle { switch self { case .light: - return .light + .light case .dark: - return .dark + .dark case .system: - return .unspecified + .unspecified } } } diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Common/TemperatureUnit.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Common/TemperatureUnit.swift index 95f49630d..d347b47ab 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Common/TemperatureUnit.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Common/TemperatureUnit.swift @@ -8,24 +8,24 @@ public enum TemperatureUnit { public var unitTemperature: UnitTemperature { switch self { case .celsius: - return .celsius + .celsius case .fahrenheit: - return .fahrenheit + .fahrenheit case .kelvin: - return .kelvin + .kelvin } } public var symbol: String { - return unitTemperature.symbol + unitTemperature.symbol } } // defaults range of temperature -extension TemperatureUnit { - public var alertRange: Range { - let lowerTemp = Temperature(value: -40, unit: .celsius).converted(to: self.unitTemperature).value - let upperTemp = Temperature(value: 85, unit: .celsius).converted(to: self.unitTemperature).value +public extension TemperatureUnit { + var alertRange: Range { + let lowerTemp = Temperature(value: -40, unit: .celsius).converted(to: unitTemperature).value + let upperTemp = Temperature(value: 85, unit: .celsius).converted(to: unitTemperature).value return .init(uncheckedBounds: (lowerTemp, upperTemp)) } } diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Identifier/Identifier.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Identifier/Identifier.swift index 7ef96e402..9cfa8e651 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Identifier/Identifier.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Identifier/Identifier.swift @@ -4,8 +4,7 @@ public protocol Identifier { var value: String { get } } -public protocol LocalIdentifier: Identifier { -} +public protocol LocalIdentifier: Identifier {} public protocol MACIdentifier: Identifier { var mac: String { get } @@ -14,7 +13,7 @@ public protocol MACIdentifier: Identifier { public struct MACIdentifierStruct: MACIdentifier { public var value: String public var mac: String { - return value + value } public init( @@ -28,14 +27,15 @@ public struct AnyMACIdentifier: MACIdentifier, Equatable, Hashable { var object: MACIdentifier public var value: String { - return object.value + object.value } + public var mac: String { - return object.value + object.value } public static func == (lhs: AnyMACIdentifier, rhs: AnyMACIdentifier) -> Bool { - return lhs.value == rhs.value + lhs.value == rhs.value } public func hash(into hasher: inout Hasher) { @@ -55,11 +55,11 @@ public struct AnyLocalIdentifier: LocalIdentifier, Equatable, Hashable { var object: LocalIdentifier public var value: String { - return object.value + object.value } public static func == (lhs: AnyLocalIdentifier, rhs: AnyLocalIdentifier) -> Bool { - return lhs.value == rhs.value + lhs.value == rhs.value } public func hash(into hasher: inout Hasher) { @@ -67,40 +67,40 @@ public struct AnyLocalIdentifier: LocalIdentifier, Equatable, Hashable { } } -extension String { - public var luid: LocalIdentifier { - return LocalIdentifierStruct(value: self).any +public extension String { + var luid: LocalIdentifier { + LocalIdentifierStruct(value: self).any } - public var mac: MACIdentifier { - return MACIdentifierStruct(value: self).any + var mac: MACIdentifier { + MACIdentifierStruct(value: self).any } } -extension Optional where Wrapped == String { - public var luid: LocalIdentifier? { - guard let self = self else { +public extension String? { + var luid: LocalIdentifier? { + guard let self else { return nil } return LocalIdentifierStruct(value: self).any } - public var mac: MACIdentifier? { - guard let self = self else { + var mac: MACIdentifier? { + guard let self else { return nil } return MACIdentifierStruct(value: self).any } } -extension LocalIdentifier { - public var any: AnyLocalIdentifier { - return AnyLocalIdentifier(object: self) +public extension LocalIdentifier { + var any: AnyLocalIdentifier { + AnyLocalIdentifier(object: self) } } -extension MACIdentifier { - public var any: AnyMACIdentifier { - return AnyMACIdentifier(object: self) +public extension MACIdentifier { + var any: AnyMACIdentifier { + AnyMACIdentifier(object: self) } } diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTag+RuuviTagSensor.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTag+RuuviTagSensor.swift index 155648f62..3c64c0312 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTag+RuuviTagSensor.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTag+RuuviTagSensor.swift @@ -1,9 +1,9 @@ -import Foundation import BTKit +import Foundation -extension RuuviTag { - public func with(name: String) -> RuuviTagSensor { - return RuuviTagSensorStruct( +public extension RuuviTag { + func with(name: String) -> RuuviTagSensor { + RuuviTagSensorStruct( version: version, firmwareVersion: nil, luid: uuid.luid, diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTag+RuuviTagSensorRecord.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTag+RuuviTagSensorRecord.swift index e617881cf..0ae310125 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTag+RuuviTagSensorRecord.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTag+RuuviTagSensorRecord.swift @@ -1,66 +1,66 @@ -import Foundation import BTKit +import Foundation import Humidity extension RuuviTag: RuuviTagSensorRecord { public var luid: LocalIdentifier? { - return uuid.luid + uuid.luid } public var macId: MACIdentifier? { - return mac?.mac + mac?.mac } public var date: Date { - return Date() + Date() } public var source: RuuviTagSensorRecordSource { - return .unknown + .unknown } public var temperature: Temperature? { - return Temperature(self.celsius) + Temperature(celsius) } public var humidity: Humidity? { - guard let rH = self.relativeHumidity else { + guard let rH = relativeHumidity else { return nil } return Humidity(relative: rH / 100.0, temperature: temperature) } public var pressure: Pressure? { - guard let hectopascals = self.hectopascals else { + guard let hectopascals else { return nil } return Pressure(value: hectopascals, unit: .hectopascals) } public var acceleration: Acceleration? { - guard let accelerationX = self.accelerationX, - let accelerationY = self.accelerationY, - let accelerationZ = self.accelerationZ else { + guard let accelerationX, + let accelerationY, + let accelerationZ + else { return nil } return Acceleration(x: AccelerationMeasurement(value: accelerationX, unit: .metersPerSecondSquared), - y: + y: AccelerationMeasurement(value: accelerationY, unit: .metersPerSecondSquared), - z: + z: AccelerationMeasurement(value: accelerationZ, - unit: .metersPerSecondSquared) - ) + unit: .metersPerSecondSquared)) } public var voltage: Voltage? { - guard let voltage = self.volts else { return nil } + guard let voltage = volts else { return nil } return Voltage(value: voltage, unit: .volts) } - public var temperatureOffset: Double { return 0.0 } - public var humidityOffset: Double { return 0.0 } - public var pressureOffset: Double { return 0.0 } + public var temperatureOffset: Double { 0.0 } + public var humidityOffset: Double { 0.0 } + public var pressureOffset: Double { 0.0 } } diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTagEnvLogFull+RuuviTagSensorRecord.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTagEnvLogFull+RuuviTagSensorRecord.swift index 17e93caf7..a24a96bee 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTagEnvLogFull+RuuviTagSensorRecord.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTagEnvLogFull+RuuviTagSensorRecord.swift @@ -2,25 +2,28 @@ import BTKit import Humidity extension RuuviTagEnvLogFull { - var unitTemperature: Temperature? { - return Temperature(value: temperature, unit: .celsius) + Temperature(value: temperature, unit: .celsius) } + var unitHumidity: Humidity? { - return Humidity(relative: humidity / 100.0, temperature: unitTemperature) + Humidity(relative: humidity / 100.0, temperature: unitTemperature) } + var unitPressure: Pressure? { - return Pressure(value: pressure, unit: .hectopascals) + Pressure(value: pressure, unit: .hectopascals) } + var acceleration: Acceleration? { - return nil + nil } + var unitVoltage: Voltage? { - return nil + nil } public func ruuviSensorRecord(uuid: String, mac: String?) -> RuuviTagSensorRecord { - return RuuviTagSensorRecordStruct( + RuuviTagSensorRecordStruct( luid: uuid.luid, date: date, source: .log, diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTagSensorRecord+RuuviMeasurement.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTagSensorRecord+RuuviMeasurement.swift index 07f40102e..af99b3476 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTagSensorRecord+RuuviMeasurement.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTagSensorRecord+RuuviMeasurement.swift @@ -1,8 +1,8 @@ import Foundation -extension RuuviTagSensorRecord { - public var measurement: RuuviMeasurement { - return RuuviMeasurement( +public extension RuuviTagSensorRecord { + var measurement: RuuviMeasurement { + RuuviMeasurement( luid: luid, macId: macId, measurementSequenceNumber: measurementSequenceNumber, diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/Measurement.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/Measurement.swift index 7b47960f7..724aa5cef 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/Measurement.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/Measurement.swift @@ -23,8 +23,8 @@ public struct Acceleration { } } -extension Temperature { - public init?(_ value: Double?, unit: UnitTemperature = .celsius) { +public extension Temperature { + init?(_ value: Double?, unit: UnitTemperature = .celsius) { if let temperature = value { self = Temperature(value: temperature, unit: unit) } else { @@ -32,21 +32,21 @@ extension Temperature { } } - public func plus(sensorSettings: SensorSettings?) -> Temperature? { - return Temperature( - self.value + (sensorSettings?.temperatureOffset ?? 0), unit: self.unit + func plus(sensorSettings: SensorSettings?) -> Temperature? { + Temperature( + value + (sensorSettings?.temperatureOffset ?? 0), unit: unit ) } - public func minus(value: Double?) -> Temperature? { - return Temperature( - self.value - (value ?? 0), unit: self.unit + func minus(value: Double?) -> Temperature? { + Temperature( + self.value - (value ?? 0), unit: unit ) } } -extension Pressure { - public init?(_ value: Double?, unit: UnitPressure = .hectopascals) { +public extension Pressure { + init?(_ value: Double?, unit: UnitPressure = .hectopascals) { if let pressure = value { self = Pressure(value: pressure, unit: unit) } else { @@ -54,38 +54,39 @@ extension Pressure { } } - public func plus(sensorSettings: SensorSettings?) -> Pressure? { - return Pressure( - self.value + (sensorSettings?.pressureOffset ?? 0), unit: self.unit + func plus(sensorSettings: SensorSettings?) -> Pressure? { + Pressure( + value + (sensorSettings?.pressureOffset ?? 0), unit: unit ) } - public func minus(value: Double?) -> Pressure? { - return Pressure( - self.value - (value ?? 0), unit: self.unit + func minus(value: Double?) -> Pressure? { + Pressure( + self.value - (value ?? 0), unit: unit ) } } -extension Humidity { - public init?(relative value: Double?, temperature: Temperature?) { +public extension Humidity { + init?(relative value: Double?, temperature: Temperature?) { if let relativeHumidity = value, - let temperature = temperature { + let temperature + { self = Humidity(value: relativeHumidity, unit: .relative(temperature: temperature)) } else { return nil } } - public func plus(sensorSettings: SensorSettings?) -> Humidity? { - return Humidity(value: self.value + (sensorSettings?.humidityOffset ?? 0), unit: self.unit) + func plus(sensorSettings: SensorSettings?) -> Humidity? { + Humidity(value: value + (sensorSettings?.humidityOffset ?? 0), unit: unit) } - public func minus(value: Double?) -> Humidity? { - return Humidity(value: self.value - (value ?? 0), unit: self.unit) + func minus(value: Double?) -> Humidity? { + Humidity(value: self.value - (value ?? 0), unit: unit) } - public static var zeroAbsolute: Humidity { - return Humidity(value: 0, unit: .absolute) + static var zeroAbsolute: Humidity { + Humidity(value: 0, unit: .absolute) } } diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/MeasurementAccuracyType.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/MeasurementAccuracyType.swift index 5d65fc75f..d798c8216 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/MeasurementAccuracyType.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/MeasurementAccuracyType.swift @@ -8,22 +8,22 @@ public enum MeasurementAccuracyType { public var value: Int { switch self { case .zero: - return 0 + 0 case .one: - return 1 + 1 case .two: - return 2 + 2 } } public var displayValue: Double { switch self { case .zero: - return 1 + 1 case .one: - return 0.1 + 0.1 case .two: - return 0.01 + 0.01 } } } diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/RuuviMeasurement.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/RuuviMeasurement.swift index 3b846bb7c..ffaf514b0 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/RuuviMeasurement.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/RuuviMeasurement.swift @@ -3,15 +3,17 @@ import Humidity public struct RuuviMeasurement { public var id: String { - if let macId = macId, - !macId.value.isEmpty { - return macId.value - } else if let luid = luid { - return luid.value + if let macId, + !macId.value.isEmpty + { + macId.value + } else if let luid { + luid.value } else { fatalError() } } + public var luid: LocalIdentifier? public var macId: MACIdentifier? public var measurementSequenceNumber: Int? diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Notification/RuuviCloudPNToken.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Notification/RuuviCloudPNToken.swift index da73f2a51..d1736039b 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Notification/RuuviCloudPNToken.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Notification/RuuviCloudPNToken.swift @@ -13,7 +13,8 @@ public struct RuuviCloudPNTokenStruct: RuuviCloudPNToken { public init(id: Int, lastAccessed: TimeInterval? = nil, - name: String? = nil) { + name: String? = nil) + { self.id = id self.lastAccessed = lastAccessed self.name = name diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/CloudSensor.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/CloudSensor.swift index d81bc01b9..4848b1e68 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/CloudSensor.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/CloudSensor.swift @@ -1,8 +1,8 @@ import Foundation -extension CloudSensor { - public var ruuviTagSensor: RuuviTagSensor { - return RuuviTagSensorStruct( +public extension CloudSensor { + var ruuviTagSensor: RuuviTagSensor { + RuuviTagSensorStruct( version: 5, firmwareVersion: nil, luid: nil, @@ -19,8 +19,8 @@ extension CloudSensor { ) } - public func with(email: String) -> CloudSensor { - return CloudSensorStruct( + func with(email: String) -> CloudSensor { + CloudSensorStruct( id: id, name: name, isClaimed: email == owner, @@ -84,9 +84,9 @@ public struct CloudSensorStruct: CloudSensor { } } -extension CloudSensor { - public var any: AnyCloudSensor { - return AnyCloudSensor(object: self) +public extension CloudSensor { + var any: AnyCloudSensor { + AnyCloudSensor(object: self) } } @@ -98,59 +98,59 @@ public struct AnyCloudSensor: CloudSensor, Equatable, Hashable, Reorderable { } public var id: String { - return object.id + object.id } public var name: String { - return object.name + object.name } public var isClaimed: Bool { - return object.isClaimed + object.isClaimed } public var isOwner: Bool { - return object.isOwner + object.isOwner } public var owner: String? { - return object.owner + object.owner } public var ownersPlan: String? { - return object.ownersPlan + object.ownersPlan } public var picture: URL? { - return object.picture + object.picture } public var offsetTemperature: Double? { - return object.offsetTemperature + object.offsetTemperature } public var offsetHumidity: Double? { - return object.offsetHumidity + object.offsetHumidity } public var offsetPressure: Double? { - return object.offsetPressure + object.offsetPressure } public var isCloudSensor: Bool? { - return object.isCloudSensor + object.isCloudSensor } public var canShare: Bool { - return object.canShare + object.canShare } public var sharedTo: [String] { - return object.sharedTo + object.sharedTo } public static func == (lhs: AnyCloudSensor, rhs: AnyCloudSensor) -> Bool { - return lhs.id == rhs.id + lhs.id == rhs.id } public func hash(into hasher: inout Hasher) { @@ -158,6 +158,6 @@ public struct AnyCloudSensor: CloudSensor, Equatable, Hashable, Reorderable { } public var orderElement: String { - return id + id } } diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/CloudSensorDense.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/CloudSensorDense.swift index 33bca26bc..33774105c 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/CloudSensorDense.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/CloudSensorDense.swift @@ -9,7 +9,8 @@ public struct RuuviCloudSensorDense { public init(sensor: CloudSensor, record: RuuviTagSensorRecord?, alerts: RuuviCloudSensorAlerts, - subscription: CloudSensorSubscription?) { + subscription: CloudSensorSubscription?) + { self.sensor = sensor self.record = record self.alerts = alerts @@ -24,66 +25,67 @@ public struct AnyCloudSensorDense: CloudSensor, Equatable, Hashable, Reorderable public init(sensor: CloudSensor, record: RuuviTagSensorRecord, - subscription: CloudSensorSubscription?) { + subscription: CloudSensorSubscription?) + { self.sensor = sensor self.record = record self.subscription = subscription } public var id: String { - return sensor.id + sensor.id } public var name: String { - return sensor.name + sensor.name } public var isClaimed: Bool { - return sensor.isClaimed + sensor.isClaimed } public var isOwner: Bool { - return sensor.isOwner + sensor.isOwner } public var owner: String? { - return sensor.owner + sensor.owner } public var ownersPlan: String? { - return subscription?.subscriptionName + subscription?.subscriptionName } public var picture: URL? { - return sensor.picture + sensor.picture } public var offsetTemperature: Double? { - return sensor.offsetTemperature + sensor.offsetTemperature } public var offsetHumidity: Double? { - return sensor.offsetHumidity + sensor.offsetHumidity } public var offsetPressure: Double? { - return sensor.offsetPressure + sensor.offsetPressure } public var isCloudSensor: Bool? { - return sensor.isCloudSensor + sensor.isCloudSensor } public var canShare: Bool { - return sensor.canShare + sensor.canShare } public var sharedTo: [String] { - return sensor.sharedTo + sensor.sharedTo } public static func == (lhs: AnyCloudSensorDense, rhs: AnyCloudSensorDense) -> Bool { - return lhs.id == rhs.id + lhs.id == rhs.id } public func hash(into hasher: inout Hasher) { @@ -91,72 +93,72 @@ public struct AnyCloudSensorDense: CloudSensor, Equatable, Hashable, Reorderable } public var orderElement: String { - return id + id } } extension AnyCloudSensorDense: RuuviTagSensorRecord { public var luid: LocalIdentifier? { - return record.luid + record.luid } public var date: Date { - return record.date + record.date } public var source: RuuviTagSensorRecordSource { - return record.source + record.source } public var macId: MACIdentifier? { - return record.macId + record.macId } public var rssi: Int? { - return record.rssi + record.rssi } public var temperature: Temperature? { - return record.temperature + record.temperature } public var humidity: Humidity? { - return record.humidity + record.humidity } public var pressure: Pressure? { - return record.pressure + record.pressure } public var acceleration: Acceleration? { - return record.acceleration + record.acceleration } public var voltage: Voltage? { - return record.voltage + record.voltage } public var movementCounter: Int? { - return record.movementCounter + record.movementCounter } public var measurementSequenceNumber: Int? { - return record.measurementSequenceNumber + record.measurementSequenceNumber } public var txPower: Int? { - return record.txPower + record.txPower } public var temperatureOffset: Double { - return record.temperatureOffset + record.temperatureOffset } public var humidityOffset: Double { - return record.humidityOffset + record.humidityOffset } public var pressureOffset: Double { - return record.pressureOffset + record.pressureOffset } } diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/PhysicalSensor.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/PhysicalSensor.swift index e5c8a0a8d..d7bc4e57a 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/PhysicalSensor.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/PhysicalSensor.swift @@ -7,11 +7,12 @@ public protocol PhysicalSensor: Sensor { public struct PhysicalSensorStruct: PhysicalSensor { public var id: String { - if let macId = macId, - !macId.value.isEmpty { - return macId.value - } else if let luid = luid { - return luid.value + if let macId, + !macId.value.isEmpty + { + macId.value + } else if let luid { + luid.value } else { fatalError() } diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensor.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensor.swift index 0dc92ddcf..4295be8cb 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensor.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensor.swift @@ -3,24 +3,25 @@ import Foundation public protocol RuuviTagSensor: PhysicalSensor, Versionable, Claimable, Connectable, Nameable, Shareable {} -extension RuuviTagSensor { - public var id: String { - if let macId = macId, - !macId.value.isEmpty { - return macId.value - } else if let luid = luid { - return luid.value +public extension RuuviTagSensor { + var id: String { + if let macId, + !macId.value.isEmpty + { + macId.value + } else if let luid { + luid.value } else { fatalError() } } - public var any: AnyRuuviTagSensor { - return AnyRuuviTagSensor(object: self) + var any: AnyRuuviTagSensor { + AnyRuuviTagSensor(object: self) } - public var `struct`: RuuviTagSensorStruct { - return RuuviTagSensorStruct( + var `struct`: RuuviTagSensorStruct { + RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, luid: luid, @@ -37,8 +38,8 @@ extension RuuviTagSensor { ) } - public func with(isClaimed: Bool) -> RuuviTagSensor { - return RuuviTagSensorStruct( + func with(isClaimed: Bool) -> RuuviTagSensor { + RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, luid: luid, @@ -55,8 +56,8 @@ extension RuuviTagSensor { ) } - public func with(isOwner: Bool) -> RuuviTagSensor { - return RuuviTagSensorStruct( + func with(isOwner: Bool) -> RuuviTagSensor { + RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, luid: luid, @@ -73,8 +74,8 @@ extension RuuviTagSensor { ) } - public func with(version: Int) -> RuuviTagSensor { - return RuuviTagSensorStruct( + func with(version: Int) -> RuuviTagSensor { + RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, luid: luid, @@ -91,8 +92,8 @@ extension RuuviTagSensor { ) } - public func with(firmwareVersion: String) -> RuuviTagSensor { - return RuuviTagSensorStruct( + func with(firmwareVersion: String) -> RuuviTagSensor { + RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, luid: luid, @@ -109,8 +110,8 @@ extension RuuviTagSensor { ) } - public func with(name: String) -> RuuviTagSensor { - return RuuviTagSensorStruct( + func with(name: String) -> RuuviTagSensor { + RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, luid: luid, @@ -127,8 +128,8 @@ extension RuuviTagSensor { ) } - public func with(owner: String) -> RuuviTagSensor { - return RuuviTagSensorStruct( + func with(owner: String) -> RuuviTagSensor { + RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, luid: luid, @@ -145,8 +146,8 @@ extension RuuviTagSensor { ) } - public func with(ownersPlan: String) -> RuuviTagSensor { - return RuuviTagSensorStruct( + func with(ownersPlan: String) -> RuuviTagSensor { + RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, luid: luid, @@ -163,8 +164,8 @@ extension RuuviTagSensor { ) } - public func with(macId: MACIdentifier) -> RuuviTagSensor { - return RuuviTagSensorStruct( + func with(macId: MACIdentifier) -> RuuviTagSensor { + RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, luid: luid, @@ -181,8 +182,8 @@ extension RuuviTagSensor { ) } - public func withoutMac() -> RuuviTagSensor { - return RuuviTagSensorStruct( + func withoutMac() -> RuuviTagSensor { + RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, luid: luid, @@ -199,8 +200,8 @@ extension RuuviTagSensor { ) } - public func withoutOwner() -> RuuviTagSensor { - return RuuviTagSensorStruct( + func withoutOwner() -> RuuviTagSensor { + RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, luid: luid, @@ -217,8 +218,8 @@ extension RuuviTagSensor { ) } - public func with(isConnectable: Bool) -> RuuviTagSensor { - return RuuviTagSensorStruct( + func with(isConnectable: Bool) -> RuuviTagSensor { + RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, luid: luid, @@ -235,7 +236,7 @@ extension RuuviTagSensor { ) } - public func with(cloudSensor: CloudSensor) -> RuuviTagSensor { + func with(cloudSensor: CloudSensor) -> RuuviTagSensor { let sensor = RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, @@ -254,8 +255,8 @@ extension RuuviTagSensor { return sensor } - public func with(isCloudSensor: Bool) -> RuuviTagSensor { - return RuuviTagSensorStruct( + func with(isCloudSensor: Bool) -> RuuviTagSensor { + RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, luid: luid, @@ -272,8 +273,8 @@ extension RuuviTagSensor { ) } - public func unclaimed() -> RuuviTagSensor { - return RuuviTagSensorStruct( + func unclaimed() -> RuuviTagSensor { + RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, luid: luid, @@ -290,8 +291,8 @@ extension RuuviTagSensor { ) } - public func with(sharedTo: [String]) -> RuuviTagSensor { - return RuuviTagSensorStruct( + func with(sharedTo: [String]) -> RuuviTagSensor { + RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, luid: luid, @@ -308,8 +309,8 @@ extension RuuviTagSensor { ) } - public func with(canShare: Bool) -> RuuviTagSensor { - return RuuviTagSensorStruct( + func with(canShare: Bool) -> RuuviTagSensor { + RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, luid: luid, @@ -328,8 +329,8 @@ extension RuuviTagSensor { /// This is a computed property to unwrap the optional isCloudSensor property from database /// The property returns false if isCloudSensor is nil, otherwise returns the stored value - public var isCloud: Bool { - return isCloudSensor ?? false + var isCloud: Bool { + isCloudSensor ?? false } } @@ -387,48 +388,61 @@ public struct AnyRuuviTagSensor: RuuviTagSensor, Equatable, Hashable, Reorderabl } public var id: String { - return object.id + object.id } + public var version: Int { - return object.version + object.version } + public var firmwareVersion: String? { - return object.firmwareVersion + object.firmwareVersion } + public var luid: LocalIdentifier? { - return object.luid + object.luid } + public var macId: MACIdentifier? { - return object.macId + object.macId } + public var isConnectable: Bool { - return object.isConnectable + object.isConnectable } + public var name: String { - return object.name + object.name } + public var isClaimed: Bool { - return object.isClaimed + object.isClaimed } + public var isOwner: Bool { - return object.isOwner + object.isOwner } + public var owner: String? { - return object.owner + object.owner } + public var ownersPlan: String? { - return object.ownersPlan + object.ownersPlan } + public var isCloudSensor: Bool? { - return object.isCloudSensor + object.isCloudSensor } + public var canShare: Bool { - return object.canShare + object.canShare } + public var sharedTo: [String] { - return object.sharedTo.filter({ + object.sharedTo.filter { !$0.isEmpty - }) + } } public static func == (lhs: AnyRuuviTagSensor, rhs: AnyRuuviTagSensor) -> Bool { @@ -449,6 +463,6 @@ public struct AnyRuuviTagSensor: RuuviTagSensor, Equatable, Hashable, Reorderabl } public var orderElement: String { - return id + id } } diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensorRecord.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensorRecord.swift index a98dac38e..e0c8b1e72 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensorRecord.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensorRecord.swift @@ -33,35 +33,37 @@ public protocol RuuviTagSensorRecord: PhysicalSensor { var pressureOffset: Double { get } } -extension RuuviTagSensorRecord { - public var id: String { - if let macId = macId, - !macId.value.isEmpty { - return macId.value + "\(date.timeIntervalSince1970)" - } else if let luid = luid { - return luid.value + "\(date.timeIntervalSince1970)" +public extension RuuviTagSensorRecord { + var id: String { + if let macId, + !macId.value.isEmpty + { + macId.value + "\(date.timeIntervalSince1970)" + } else if let luid { + luid.value + "\(date.timeIntervalSince1970)" } else { fatalError() } } - public var uuid: String { - if let macId = macId, - !macId.value.isEmpty { - return macId.value - } else if let luid = luid { - return luid.value + var uuid: String { + if let macId, + !macId.value.isEmpty + { + macId.value + } else if let luid { + luid.value } else { fatalError() } } - public var any: AnyRuuviTagSensorRecord { - return AnyRuuviTagSensorRecord(object: self) + var any: AnyRuuviTagSensorRecord { + AnyRuuviTagSensorRecord(object: self) } - public func with(macId: MACIdentifier) -> RuuviTagSensorRecord { - return RuuviTagSensorRecordStruct( + func with(macId: MACIdentifier) -> RuuviTagSensorRecord { + RuuviTagSensorRecordStruct( luid: luid, date: date, source: source, @@ -81,8 +83,8 @@ extension RuuviTagSensorRecord { ) } - public func with(luid: LocalIdentifier) -> RuuviTagSensorRecord { - return RuuviTagSensorRecordStruct( + func with(luid: LocalIdentifier) -> RuuviTagSensorRecord { + RuuviTagSensorRecordStruct( luid: luid, date: date, source: source, @@ -103,9 +105,9 @@ extension RuuviTagSensorRecord { } } -extension RuuviTagSensorRecord { - public func with(source: RuuviTagSensorRecordSource) -> RuuviTagSensorRecord { - return RuuviTagSensorRecordStruct( +public extension RuuviTagSensorRecord { + func with(source: RuuviTagSensorRecordSource) -> RuuviTagSensorRecord { + RuuviTagSensorRecordStruct( luid: luid, date: date, source: source, @@ -125,8 +127,8 @@ extension RuuviTagSensorRecord { ) } - public func with(sensorSettings: SensorSettings?) -> RuuviTagSensorRecord { - return RuuviTagSensorRecordStruct( + func with(sensorSettings: SensorSettings?) -> RuuviTagSensorRecord { + RuuviTagSensorRecordStruct( luid: luid, date: date, source: source, @@ -220,71 +222,71 @@ public struct AnyRuuviTagSensorRecord: RuuviTagSensorRecord, Equatable, Hashable } public var luid: LocalIdentifier? { - return object.luid + object.luid } public var date: Date { - return object.date + object.date } public var source: RuuviTagSensorRecordSource { - return object.source + object.source } public var macId: MACIdentifier? { - return object.macId + object.macId } public var rssi: Int? { - return object.rssi + object.rssi } public var temperature: Temperature? { - return object.temperature + object.temperature } public var humidity: Humidity? { - return object.humidity + object.humidity } public var pressure: Pressure? { - return object.pressure + object.pressure } public var acceleration: Acceleration? { - return object.acceleration + object.acceleration } public var voltage: Voltage? { - return object.voltage + object.voltage } public var movementCounter: Int? { - return object.movementCounter + object.movementCounter } public var measurementSequenceNumber: Int? { - return object.measurementSequenceNumber + object.measurementSequenceNumber } public var txPower: Int? { - return object.txPower + object.txPower } public var temperatureOffset: Double { - return object.temperatureOffset + object.temperatureOffset } public var humidityOffset: Double { - return object.humidityOffset + object.humidityOffset } public var pressureOffset: Double { - return object.pressureOffset + object.pressureOffset } public static func == (lhs: AnyRuuviTagSensorRecord, rhs: AnyRuuviTagSensorRecord) -> Bool { - return lhs.id == rhs.id + lhs.id == rhs.id } public func hash(into hasher: inout Hasher) { diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/SensorSettings.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/SensorSettings.swift index 8d60cf0da..0a6019d77 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/SensorSettings.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/SensorSettings.swift @@ -12,19 +12,19 @@ public protocol SensorSettings { var pressureOffsetDate: Date? { get } } -extension SensorSettings { - public var id: String { - if let macId = macId { - return "\(macId.value)-settings" - } else if let luid = luid { - return "\(luid.value)-settings" +public extension SensorSettings { + var id: String { + if let macId { + "\(macId.value)-settings" + } else if let luid { + "\(luid.value)-settings" } else { fatalError() } } - public func with(macId: MACIdentifier) -> SensorSettings { - return SensorSettingsStruct( + func with(macId: MACIdentifier) -> SensorSettings { + SensorSettingsStruct( luid: luid, macId: macId, temperatureOffset: temperatureOffset, diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/ShareableSensor.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/ShareableSensor.swift index 5b6d36f92..63908b3bb 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/ShareableSensor.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/ShareableSensor.swift @@ -16,9 +16,9 @@ public struct ShareableSensorStruct: ShareableSensor { } } -extension ShareableSensor { - public var any: AnyShareableSensor { - return AnyShareableSensor(object: self) +public extension ShareableSensor { + var any: AnyShareableSensor { + AnyShareableSensor(object: self) } } @@ -30,19 +30,19 @@ public struct AnyShareableSensor: ShareableSensor, Equatable, Hashable, Reordera } public var id: String { - return object.id + object.id } public var canShare: Bool { - return object.canShare + object.canShare } public var sharedTo: [String] { - return object.sharedTo + object.sharedTo } public static func == (lhs: AnyShareableSensor, rhs: AnyShareableSensor) -> Bool { - return lhs.id == rhs.id + lhs.id == rhs.id } public func hash(into hasher: inout Hasher) { @@ -50,6 +50,6 @@ public struct AnyShareableSensor: ShareableSensor, Equatable, Hashable, Reordera } public var orderElement: String { - return id + id } } diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+Extension.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+Extension.swift index 94cb6e9fa..58a80678e 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+Extension.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+Extension.swift @@ -3,52 +3,58 @@ import Humidity import RealmSwift import RuuviOntology -extension RuuviTagDataRealm { - public var unitTemperature: Temperature? { - guard let celsius = self.celsius.value else { +public extension RuuviTagDataRealm { + var unitTemperature: Temperature? { + guard let celsius = celsius.value else { return nil } return Temperature(value: celsius, unit: .celsius) } - public var unitHumidity: Humidity? { - guard let celsius = self.celsius.value, - let relativeHumidity = self.humidity.value else { + + var unitHumidity: Humidity? { + guard let celsius = celsius.value, + let relativeHumidity = humidity.value + else { return nil } return Humidity(relative: relativeHumidity, temperature: Temperature(value: celsius, unit: .celsius)) } - public var unitPressure: Pressure? { - guard let pressure = self.pressure.value else { + + var unitPressure: Pressure? { + guard let pressure = pressure.value else { return nil } return Pressure(value: pressure, unit: .hectopascals) } - public var acceleration: Acceleration? { - guard let accelerationX = self.accelerationX.value, - let accelerationY = self.accelerationY.value, - let accelerationZ = self.accelerationZ.value else { + + var acceleration: Acceleration? { + guard let accelerationX = accelerationX.value, + let accelerationY = accelerationY.value, + let accelerationZ = accelerationZ.value + else { return nil } return Acceleration(x: AccelerationMeasurement(value: accelerationX, unit: .metersPerSecondSquared), - y: + y: AccelerationMeasurement(value: accelerationY, unit: .metersPerSecondSquared), - z: + z: AccelerationMeasurement(value: accelerationZ, - unit: .metersPerSecondSquared) - ) + unit: .metersPerSecondSquared)) } - public var unitVoltage: Voltage? { - guard let voltage = self.voltage.value else { return nil } + + var unitVoltage: Voltage? { + guard let voltage = voltage.value else { return nil } return Voltage(value: voltage, unit: .volts) } - public var measurement: RuuviMeasurement { - return RuuviMeasurement( + + var measurement: RuuviMeasurement { + RuuviMeasurement( luid: ruuviTag?.luid, macId: ruuviTag?.macId, measurementSequenceNumber: measurementSequenceNumber.value, diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+RuuviTagSensorRecord.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+RuuviTagSensorRecord.swift index 01c6b61d0..26b124928 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+RuuviTagSensorRecord.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+RuuviTagSensorRecord.swift @@ -1,9 +1,9 @@ import Foundation -import RuuviOntology import RealmSwift +import RuuviOntology -extension RuuviTagDataRealm { - public var any: AnyRuuviTagSensorRecord? { +public extension RuuviTagDataRealm { + var any: AnyRuuviTagSensorRecord? { let inner = RuuviTagSensorRecordStruct( luid: ruuviTag?.uuid.luid, date: date, diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm.swift index e4c622234..2d28b0027 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm.swift @@ -1,12 +1,11 @@ +import BTKit import Foundation import RealmSwift -import BTKit import RuuviOntology public final class RuuviTagDataRealm: Object { - @objc public dynamic var ruuviTag: RuuviTagRealm? - @objc public dynamic var date: Date = Date() + @objc public dynamic var date: Date = .init() @objc public dynamic var compoundKey: String = UUID().uuidString @objc public dynamic var sourceString: String = "unknown" @@ -32,19 +31,19 @@ public final class RuuviTagDataRealm: Object { @objc public dynamic var pressureOffset: Double = 0.0 public var fahrenheit: Double? { - return celsius.value?.fahrenheit + celsius.value?.fahrenheit } public var kelvin: Double? { - return celsius.value?.kelvin + celsius.value?.kelvin } public var source: RuuviTagSensorRecordSource { - return RuuviTagSensorRecordSource(rawValue: sourceString) ?? .unknown + RuuviTagSensorRecordSource(rawValue: sourceString) ?? .unknown } - public override static func primaryKey() -> String? { - return "compoundKey" + override public static func primaryKey() -> String? { + "compoundKey" } public convenience init(ruuviTag: RuuviTagRealm, data: RuuviTagProtocol, date: Date) { @@ -55,50 +54,50 @@ public final class RuuviTagDataRealm: Object { public convenience init(ruuviTag: RuuviTagRealm, data: RuuviTagProtocol) { self.init() self.ruuviTag = ruuviTag - self.sourceString = data.source.rawValue - self.rssi.value = data.rssi - self.celsius.value = data.celsius - self.humidity.value = data.relativeHumidity - self.pressure.value = data.hectopascals - self.accelerationX.value = data.accelerationX - self.accelerationY.value = data.accelerationY - self.accelerationZ.value = data.accelerationZ - self.voltage.value = data.volts - self.movementCounter.value = data.movementCounter - self.measurementSequenceNumber.value = data.measurementSequenceNumber - self.txPower.value = data.txPower - self.compoundKey = ruuviTag.uuid + "\(date.timeIntervalSince1970)" + sourceString = data.source.rawValue + rssi.value = data.rssi + celsius.value = data.celsius + humidity.value = data.relativeHumidity + pressure.value = data.hectopascals + accelerationX.value = data.accelerationX + accelerationY.value = data.accelerationY + accelerationZ.value = data.accelerationZ + voltage.value = data.volts + movementCounter.value = data.movementCounter + measurementSequenceNumber.value = data.measurementSequenceNumber + txPower.value = data.txPower + compoundKey = ruuviTag.uuid + "\(date.timeIntervalSince1970)" } public convenience init(ruuviTag: RuuviTagRealm, data: RuuviTagEnvLogFull) { self.init() self.ruuviTag = ruuviTag - self.sourceString = RuuviTagSensorRecordSource.log.rawValue - self.date = data.date - self.celsius.value = data.temperature - self.humidity.value = data.humidity - self.pressure.value = data.pressure - self.compoundKey = ruuviTag.uuid + "\(date.timeIntervalSince1970)" + sourceString = RuuviTagSensorRecordSource.log.rawValue + date = data.date + celsius.value = data.temperature + humidity.value = data.humidity + pressure.value = data.pressure + compoundKey = ruuviTag.uuid + "\(date.timeIntervalSince1970)" } public convenience init(ruuviTag: RuuviTagRealm, record: RuuviTagSensorRecord) { self.init() self.ruuviTag = ruuviTag - self.sourceString = record.source.rawValue - self.rssi.value = record.rssi - self.celsius.value = record.temperature?.converted(to: .celsius).value - self.humidity.value = record.humidity?.value - self.pressure.value = record.pressure?.converted(to: .hectopascals).value - self.accelerationX.value = record.acceleration?.x.value - self.accelerationY.value = record.acceleration?.y.value - self.accelerationZ.value = record.acceleration?.z.value - self.voltage.value = record.voltage?.converted(to: .volts).value - self.movementCounter.value = record.movementCounter - self.measurementSequenceNumber.value = record.measurementSequenceNumber - self.txPower.value = record.txPower - self.compoundKey = record.id - self.temperatureOffset = record.temperatureOffset - self.humidityOffset = record.humidityOffset - self.pressureOffset = record.pressureOffset + sourceString = record.source.rawValue + rssi.value = record.rssi + celsius.value = record.temperature?.converted(to: .celsius).value + humidity.value = record.humidity?.value + pressure.value = record.pressure?.converted(to: .hectopascals).value + accelerationX.value = record.acceleration?.x.value + accelerationY.value = record.acceleration?.y.value + accelerationZ.value = record.acceleration?.z.value + voltage.value = record.voltage?.converted(to: .volts).value + movementCounter.value = record.movementCounter + measurementSequenceNumber.value = record.measurementSequenceNumber + txPower.value = record.txPower + compoundKey = record.id + temperatureOffset = record.temperatureOffset + humidityOffset = record.humidityOffset + pressureOffset = record.pressureOffset } } diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+Extension.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+Extension.swift index 0c62bb020..cce889eb4 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+Extension.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+Extension.swift @@ -3,52 +3,58 @@ import Humidity import RealmSwift import RuuviOntology -extension RuuviTagLatestDataRealm { - public var unitTemperature: Temperature? { - guard let celsius = self.celsius.value else { +public extension RuuviTagLatestDataRealm { + var unitTemperature: Temperature? { + guard let celsius = celsius.value else { return nil } return Temperature(value: celsius, unit: .celsius) } - public var unitHumidity: Humidity? { - guard let celsius = self.celsius.value, - let relativeHumidity = self.humidity.value else { + + var unitHumidity: Humidity? { + guard let celsius = celsius.value, + let relativeHumidity = humidity.value + else { return nil } return Humidity(relative: relativeHumidity, temperature: Temperature(value: celsius, unit: .celsius)) } - public var unitPressure: Pressure? { - guard let pressure = self.pressure.value else { + + var unitPressure: Pressure? { + guard let pressure = pressure.value else { return nil } return Pressure(value: pressure, unit: .hectopascals) } - public var acceleration: Acceleration? { - guard let accelerationX = self.accelerationX.value, - let accelerationY = self.accelerationY.value, - let accelerationZ = self.accelerationZ.value else { + + var acceleration: Acceleration? { + guard let accelerationX = accelerationX.value, + let accelerationY = accelerationY.value, + let accelerationZ = accelerationZ.value + else { return nil } return Acceleration(x: AccelerationMeasurement(value: accelerationX, unit: .metersPerSecondSquared), - y: + y: AccelerationMeasurement(value: accelerationY, unit: .metersPerSecondSquared), - z: + z: AccelerationMeasurement(value: accelerationZ, - unit: .metersPerSecondSquared) - ) + unit: .metersPerSecondSquared)) } - public var unitVoltage: Voltage? { - guard let voltage = self.voltage.value else { return nil } + + var unitVoltage: Voltage? { + guard let voltage = voltage.value else { return nil } return Voltage(value: voltage, unit: .volts) } - public var measurement: RuuviMeasurement { - return RuuviMeasurement( + + var measurement: RuuviMeasurement { + RuuviMeasurement( luid: ruuviTag?.luid, macId: ruuviTag?.macId, measurementSequenceNumber: measurementSequenceNumber.value, diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+RuuviTagSensorRecord.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+RuuviTagSensorRecord.swift index 6e623f5af..8696a7b79 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+RuuviTagSensorRecord.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+RuuviTagSensorRecord.swift @@ -1,9 +1,9 @@ import Foundation -import RuuviOntology import RealmSwift +import RuuviOntology -extension RuuviTagLatestDataRealm { - public var any: AnyRuuviTagSensorRecord? { +public extension RuuviTagLatestDataRealm { + var any: AnyRuuviTagSensorRecord? { let inner = RuuviTagSensorRecordStruct( luid: ruuviTag?.uuid.luid, date: date, diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm.swift index 50bf77acc..032471c19 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm.swift @@ -1,13 +1,12 @@ +import BTKit import Foundation import RealmSwift -import BTKit import RuuviOntology public final class RuuviTagLatestDataRealm: Object { - @objc public dynamic var uuid: String = "" @objc public dynamic var ruuviTag: RuuviTagRealm? - @objc public dynamic var date: Date = Date() + @objc public dynamic var date: Date = .init() @objc public dynamic var sourceString: String = "unknown" // all versions @@ -32,19 +31,19 @@ public final class RuuviTagLatestDataRealm: Object { @objc public dynamic var pressureOffset: Double = 0.0 public var fahrenheit: Double? { - return celsius.value?.fahrenheit + celsius.value?.fahrenheit } public var kelvin: Double? { - return celsius.value?.kelvin + celsius.value?.kelvin } public var source: RuuviTagSensorRecordSource { - return RuuviTagSensorRecordSource(rawValue: sourceString) ?? .unknown + RuuviTagSensorRecordSource(rawValue: sourceString) ?? .unknown } - public override static func primaryKey() -> String? { - return "uuid" + override public static func primaryKey() -> String? { + "uuid" } public convenience init(ruuviTag: RuuviTagRealm, data: RuuviTagProtocol, date: Date) { @@ -54,51 +53,51 @@ public final class RuuviTagLatestDataRealm: Object { public convenience init(ruuviTag: RuuviTagRealm, data: RuuviTagProtocol) { self.init() - self.uuid = ruuviTag.uuid + uuid = ruuviTag.uuid self.ruuviTag = ruuviTag - self.sourceString = data.source.rawValue - self.rssi.value = data.rssi - self.celsius.value = data.celsius - self.humidity.value = data.relativeHumidity - self.pressure.value = data.hectopascals - self.accelerationX.value = data.accelerationX - self.accelerationY.value = data.accelerationY - self.accelerationZ.value = data.accelerationZ - self.voltage.value = data.volts - self.movementCounter.value = data.movementCounter - self.measurementSequenceNumber.value = data.measurementSequenceNumber - self.txPower.value = data.txPower + sourceString = data.source.rawValue + rssi.value = data.rssi + celsius.value = data.celsius + humidity.value = data.relativeHumidity + pressure.value = data.hectopascals + accelerationX.value = data.accelerationX + accelerationY.value = data.accelerationY + accelerationZ.value = data.accelerationZ + voltage.value = data.volts + movementCounter.value = data.movementCounter + measurementSequenceNumber.value = data.measurementSequenceNumber + txPower.value = data.txPower } public convenience init(ruuviTag: RuuviTagRealm, data: RuuviTagEnvLogFull) { self.init() self.ruuviTag = ruuviTag - self.sourceString = RuuviTagSensorRecordSource.log.rawValue - self.date = data.date - self.celsius.value = data.temperature - self.humidity.value = data.humidity - self.pressure.value = data.pressure - self.uuid = ruuviTag.uuid + sourceString = RuuviTagSensorRecordSource.log.rawValue + date = data.date + celsius.value = data.temperature + humidity.value = data.humidity + pressure.value = data.pressure + uuid = ruuviTag.uuid } public convenience init(ruuviTag: RuuviTagRealm, record: RuuviTagSensorRecord) { self.init() self.ruuviTag = ruuviTag - self.sourceString = record.source.rawValue - self.rssi.value = record.rssi - self.celsius.value = record.temperature?.converted(to: .celsius).value - self.humidity.value = record.humidity?.value - self.pressure.value = record.pressure?.converted(to: .hectopascals).value - self.accelerationX.value = record.acceleration?.x.value - self.accelerationY.value = record.acceleration?.y.value - self.accelerationZ.value = record.acceleration?.z.value - self.voltage.value = record.voltage?.converted(to: .volts).value - self.movementCounter.value = record.movementCounter - self.measurementSequenceNumber.value = record.measurementSequenceNumber - self.txPower.value = record.txPower - self.uuid = record.uuid - self.temperatureOffset = record.temperatureOffset - self.humidityOffset = record.humidityOffset - self.pressureOffset = record.pressureOffset + sourceString = record.source.rawValue + rssi.value = record.rssi + celsius.value = record.temperature?.converted(to: .celsius).value + humidity.value = record.humidity?.value + pressure.value = record.pressure?.converted(to: .hectopascals).value + accelerationX.value = record.acceleration?.x.value + accelerationY.value = record.acceleration?.y.value + accelerationZ.value = record.acceleration?.z.value + voltage.value = record.voltage?.converted(to: .volts).value + movementCounter.value = record.movementCounter + measurementSequenceNumber.value = record.measurementSequenceNumber + txPower.value = record.txPower + uuid = record.uuid + temperatureOffset = record.temperatureOffset + humidityOffset = record.humidityOffset + pressureOffset = record.pressureOffset } } diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm+RuuviTagSensor.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm+RuuviTagSensor.swift index df48f6c57..6625335f1 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm+RuuviTagSensor.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm+RuuviTagSensor.swift @@ -1,18 +1,18 @@ import Foundation -import RuuviOntology import RealmSwift +import RuuviOntology extension RuuviTagRealm: RuuviTagSensor { public var luid: LocalIdentifier? { - return uuid.luid + uuid.luid } public var macId: MACIdentifier? { - return mac?.mac + mac?.mac } public var any: AnyRuuviTagSensor { - return AnyRuuviTagSensor( + AnyRuuviTagSensor( object: RuuviTagSensorStruct( version: version, firmwareVersion: firmwareVersion, @@ -32,24 +32,30 @@ extension RuuviTagRealm: RuuviTagSensor { } public var isClaimed: Bool { - return false + false } + public var owner: String? { - return nil + nil } + public var ownersPlan: String? { - return nil + nil } + public var isCloudSensor: Bool? { - return false + false } + public var firmwareVersion: String? { - return nil + nil } + public var canShare: Bool { - return false + false } + public var sharedTo: [String] { - return [] + [] } } diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm.swift index 20dfdf9c1..b5d959f0a 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm.swift @@ -1,6 +1,6 @@ +import BTKit import Foundation import RealmSwift -import BTKit import RuuviOntology public final class RuuviTagRealm: Object, RuuviTagRealmProtocol { @@ -13,37 +13,37 @@ public final class RuuviTagRealm: Object, RuuviTagRealmProtocol { public let data = LinkingObjects(fromType: RuuviTagDataRealm.self, property: "ruuviTag") - public override static func primaryKey() -> String { - return "uuid" + override public static func primaryKey() -> String { + "uuid" } - public convenience required init(mac: String) { + public required convenience init(mac: String) { self.init() - self.uuid = UUID().uuidString + uuid = UUID().uuidString self.mac = mac - self.name = mac - self.version = 5 - self.isConnectable = true - self.isOwner = true + name = mac + version = 5 + isConnectable = true + isOwner = true } - public convenience required init(ruuviTag: RuuviTagProtocol, name: String) { + public required convenience init(ruuviTag: RuuviTagProtocol, name: String) { self.init() - self.uuid = ruuviTag.uuid + uuid = ruuviTag.uuid self.name = name - self.mac = ruuviTag.mac - self.version = ruuviTag.version - self.isConnectable = ruuviTag.isConnectable - self.isOwner = ruuviTag.isOwner + mac = ruuviTag.mac + version = ruuviTag.version + isConnectable = ruuviTag.isConnectable + isOwner = ruuviTag.isOwner } - public convenience required init(ruuviTag: RuuviTagSensor) { + public required convenience init(ruuviTag: RuuviTagSensor) { self.init() - self.uuid = ruuviTag.id - self.name = ruuviTag.name - self.mac = ruuviTag.macId?.value - self.version = ruuviTag.version - self.isConnectable = ruuviTag.isConnectable - self.isOwner = ruuviTag.isOwner + uuid = ruuviTag.id + name = ruuviTag.name + mac = ruuviTag.macId?.value + version = ruuviTag.version + isConnectable = ruuviTag.isConnectable + isOwner = ruuviTag.isOwner } } diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/SensorSettingsRealm.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/SensorSettingsRealm.swift index 8f76aa094..d288ce9fc 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/SensorSettingsRealm.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/SensorSettingsRealm.swift @@ -34,9 +34,9 @@ public class SensorSettingsRealm: Object { } } -extension SensorSettingsRealm { - public var sensorSettings: SensorSettings { - return SensorSettingsStruct( +public extension SensorSettingsRealm { + var sensorSettings: SensorSettings { + SensorSettingsStruct( luid: luid?.luid, macId: macId?.mac, temperatureOffset: temperatureOffset.value, diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviCloudQueuedRequestSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviCloudQueuedRequestSQLite.swift index df5baed1f..af270adc6 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviCloudQueuedRequestSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviCloudQueuedRequestSQLite.swift @@ -22,8 +22,8 @@ public struct RuuviCloudQueuedRequestSQLite: RuuviCloudQueuedRequest { successDate: Date?, attempts: Int?, requestBodyData: Data?, - additionalData: Data?) { - + additionalData: Data? + ) { self.id = id self.type = type self.status = status @@ -36,16 +36,16 @@ public struct RuuviCloudQueuedRequestSQLite: RuuviCloudQueuedRequest { } } -extension RuuviCloudQueuedRequestSQLite { - public static let idColumn = Column("id") - public static let typeColumn = Column("requestType") - public static let statusColumn = Column("statusType") - public static let uniqueKeyColumn = Column("uniqueKey") - public static let requestDateColumn = Column("requestDate") - public static let successDateColumn = Column("successDate") - public static let attemptsColumn = Column("attempts") - public static let requestBodyDataColumn = Column("requestBodyData") - public static let additionalDataColumn = Column("additionalData") +public extension RuuviCloudQueuedRequestSQLite { + static let idColumn = Column("id") + static let typeColumn = Column("requestType") + static let statusColumn = Column("statusType") + static let uniqueKeyColumn = Column("uniqueKey") + static let requestDateColumn = Column("requestDate") + static let successDateColumn = Column("successDate") + static let attemptsColumn = Column("attempts") + static let requestBodyDataColumn = Column("requestBodyData") + static let additionalDataColumn = Column("additionalData") } extension RuuviCloudQueuedRequestSQLite: FetchableRecord { @@ -67,7 +67,7 @@ extension RuuviCloudQueuedRequestSQLite: FetchableRecord { extension RuuviCloudQueuedRequestSQLite: PersistableRecord { public static var databaseTableName: String { - return "cloud_queued_requests" + "cloud_queued_requests" } public func encode(to container: inout PersistenceContainer) { @@ -83,8 +83,8 @@ extension RuuviCloudQueuedRequestSQLite: PersistableRecord { } } -extension RuuviCloudQueuedRequestSQLite { - public static func createTable(in db: Database) throws { +public extension RuuviCloudQueuedRequestSQLite { + static func createTable(in db: Database) throws { try db.create(table: RuuviCloudQueuedRequestSQLite.databaseTableName, body: { table in table.autoIncrementedPrimaryKey(RuuviCloudQueuedRequestSQLite.idColumn.name, onConflict: .fail) @@ -100,8 +100,8 @@ extension RuuviCloudQueuedRequestSQLite { } } -extension RuuviCloudQueuedRequestSQLite { - public var queuedRequest: RuuviCloudQueuedRequest { +public extension RuuviCloudQueuedRequestSQLite { + var queuedRequest: RuuviCloudQueuedRequest { RuuviCloudQueuedRequestStruct( id: id, type: type, @@ -116,9 +116,9 @@ extension RuuviCloudQueuedRequestSQLite { } } -extension RuuviCloudQueuedRequest { - public var sqlite: RuuviCloudQueuedRequestSQLite { - return RuuviCloudQueuedRequestSQLite( +public extension RuuviCloudQueuedRequest { + var sqlite: RuuviCloudQueuedRequestSQLite { + RuuviCloudQueuedRequestSQLite( id: id, type: type, status: status, diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagDataSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagDataSQLite.swift index 45d593346..81641c1ba 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagDataSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagDataSQLite.swift @@ -58,32 +58,32 @@ public struct RuuviTagDataSQLite: RuuviTagSensorRecord { } } -extension RuuviTagDataSQLite { - public static let idColumn = Column("id") - public static let ruuviTagIdColumn = Column("ruuviTagId") - public static let luidColumn = Column("luid") - public static let dateColumn = Column("date") - public static let sourceColumn = Column("source") - public static let macColumn = Column("mac") - public static let rssiColumn = Column("rssi") - public static let celsiusColumn = Column("celsius") - public static let relativeHumidityInPercentColumn = Column("relativeHumidityInPercent") - public static let hectopascalsColumn = Column("hectopascals") - public static let accelerationXColumn = Column("accelerationX") - public static let accelerationYColumn = Column("accelerationY") - public static let accelerationZColumn = Column("accelerationZ") - public static let voltsColumn = Column("volts") - public static let movementCounterColumn = Column("movementCounter") - public static let measurementSequenceNumberColumn = Column("measurementSequenceNumber") - public static let txPowerColumn = Column("txPower") - public static let temperatureOffsetColumn = Column("temperatureOffset") - public static let humidityOffsetColumn = Column("humidityOffset") - public static let pressureOffsetColumn = Column("pressureOffset") +public extension RuuviTagDataSQLite { + static let idColumn = Column("id") + static let ruuviTagIdColumn = Column("ruuviTagId") + static let luidColumn = Column("luid") + static let dateColumn = Column("date") + static let sourceColumn = Column("source") + static let macColumn = Column("mac") + static let rssiColumn = Column("rssi") + static let celsiusColumn = Column("celsius") + static let relativeHumidityInPercentColumn = Column("relativeHumidityInPercent") + static let hectopascalsColumn = Column("hectopascals") + static let accelerationXColumn = Column("accelerationX") + static let accelerationYColumn = Column("accelerationY") + static let accelerationZColumn = Column("accelerationZ") + static let voltsColumn = Column("volts") + static let movementCounterColumn = Column("movementCounter") + static let measurementSequenceNumberColumn = Column("measurementSequenceNumber") + static let txPowerColumn = Column("txPower") + static let temperatureOffsetColumn = Column("temperatureOffset") + static let humidityOffsetColumn = Column("humidityOffset") + static let pressureOffsetColumn = Column("pressureOffset") } extension RuuviTagDataSQLite: Equatable { public static func == (lhs: RuuviTagDataSQLite, rhs: RuuviTagDataSQLite) -> Bool { - return lhs.id == rhs.id + lhs.id == rhs.id } } @@ -91,7 +91,7 @@ extension RuuviTagDataSQLite: FetchableRecord { public init(row: Row) { if let luidValue = String.fromDatabaseValue(row[RuuviTagDataSQLite.luidColumn]) { luid = LocalIdentifierStruct(value: luidValue) - } else if let luidValue = String.fromDatabaseValue(row[RuuviTagDataSQLite.ruuviTagIdColumn]) { + } else if let luidValue = String.fromDatabaseValue(row[RuuviTagDataSQLite.ruuviTagIdColumn]) { luid = LocalIdentifierStruct(value: luidValue) } date = row[RuuviTagDataSQLite.dateColumn] @@ -108,7 +108,8 @@ extension RuuviTagDataSQLite: FetchableRecord { temperature = Temperature(value: celsius, unit: .celsius) if let relativeHumidity = Double.fromDatabaseValue(row[RuuviTagDataSQLite.relativeHumidityInPercentColumn]), - let temperature = temperature { + let temperature + { humidity = Humidity(value: relativeHumidity, unit: .relative(temperature: temperature)) } @@ -117,8 +118,9 @@ extension RuuviTagDataSQLite: FetchableRecord { pressure = Pressure(value: hectopascals, unit: .hectopascals) } if let accelerationX = Double.fromDatabaseValue(row[RuuviTagDataSQLite.accelerationXColumn]), - let accelerationY = Double.fromDatabaseValue(row[RuuviTagDataSQLite.accelerationYColumn]), - let accelerationZ = Double.fromDatabaseValue(row[RuuviTagDataSQLite.accelerationZColumn]) { + let accelerationY = Double.fromDatabaseValue(row[RuuviTagDataSQLite.accelerationYColumn]), + let accelerationZ = Double.fromDatabaseValue(row[RuuviTagDataSQLite.accelerationZColumn]) + { acceleration = Acceleration(x: AccelerationMeasurement(value: accelerationX, unit: .metersPerSecondSquared), y: AccelerationMeasurement(value: accelerationY, unit: .metersPerSecondSquared), z: AccelerationMeasurement(value: accelerationZ, unit: .metersPerSecondSquared)) @@ -137,7 +139,7 @@ extension RuuviTagDataSQLite: FetchableRecord { extension RuuviTagDataSQLite: PersistableRecord { public static var databaseTableName: String { - return "ruuvi_tag_sensor_records" + "ruuvi_tag_sensor_records" } public func encode(to container: inout PersistenceContainer) { @@ -164,8 +166,8 @@ extension RuuviTagDataSQLite: PersistableRecord { } } -extension RuuviTagDataSQLite { - public static func createTable(in db: Database) throws { +public extension RuuviTagDataSQLite { + static func createTable(in db: Database) throws { try db.create(table: RuuviTagDataSQLite.databaseTableName, body: { table in table.column(RuuviTagDataSQLite.idColumn.name, .text).notNull().primaryKey(onConflict: .replace) table.column(RuuviTagDataSQLite.ruuviTagIdColumn.name, .text).notNull() diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagLatestDataSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagLatestDataSQLite.swift index 48d09b42a..1f61d3d6a 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagLatestDataSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagLatestDataSQLite.swift @@ -61,32 +61,32 @@ public struct RuuviTagLatestDataSQLite: RuuviTagSensorRecord { } } -extension RuuviTagLatestDataSQLite { - public static let idColumn = Column("id") - public static let ruuviTagIdColumn = Column("ruuviTagId") - public static let luidColumn = Column("luid") - public static let dateColumn = Column("date") - public static let sourceColumn = Column("source") - public static let macColumn = Column("mac") - public static let rssiColumn = Column("rssi") - public static let celsiusColumn = Column("celsius") - public static let relativeHumidityInPercentColumn = Column("relativeHumidityInPercent") - public static let hectopascalsColumn = Column("hectopascals") - public static let accelerationXColumn = Column("accelerationX") - public static let accelerationYColumn = Column("accelerationY") - public static let accelerationZColumn = Column("accelerationZ") - public static let voltsColumn = Column("volts") - public static let movementCounterColumn = Column("movementCounter") - public static let measurementSequenceNumberColumn = Column("measurementSequenceNumber") - public static let txPowerColumn = Column("txPower") - public static let temperatureOffsetColumn = Column("temperatureOffset") - public static let humidityOffsetColumn = Column("humidityOffset") - public static let pressureOffsetColumn = Column("pressureOffset") +public extension RuuviTagLatestDataSQLite { + static let idColumn = Column("id") + static let ruuviTagIdColumn = Column("ruuviTagId") + static let luidColumn = Column("luid") + static let dateColumn = Column("date") + static let sourceColumn = Column("source") + static let macColumn = Column("mac") + static let rssiColumn = Column("rssi") + static let celsiusColumn = Column("celsius") + static let relativeHumidityInPercentColumn = Column("relativeHumidityInPercent") + static let hectopascalsColumn = Column("hectopascals") + static let accelerationXColumn = Column("accelerationX") + static let accelerationYColumn = Column("accelerationY") + static let accelerationZColumn = Column("accelerationZ") + static let voltsColumn = Column("volts") + static let movementCounterColumn = Column("movementCounter") + static let measurementSequenceNumberColumn = Column("measurementSequenceNumber") + static let txPowerColumn = Column("txPower") + static let temperatureOffsetColumn = Column("temperatureOffset") + static let humidityOffsetColumn = Column("humidityOffset") + static let pressureOffsetColumn = Column("pressureOffset") } extension RuuviTagLatestDataSQLite: Equatable { public static func == (lhs: RuuviTagLatestDataSQLite, rhs: RuuviTagLatestDataSQLite) -> Bool { - return lhs.id == rhs.id + lhs.id == rhs.id } } @@ -95,7 +95,7 @@ extension RuuviTagLatestDataSQLite: FetchableRecord { id = row[RuuviTagLatestDataSQLite.idColumn] if let luidValue = String.fromDatabaseValue(row[RuuviTagLatestDataSQLite.luidColumn]) { luid = LocalIdentifierStruct(value: luidValue) - } else if let luidValue = String.fromDatabaseValue(row[RuuviTagLatestDataSQLite.ruuviTagIdColumn]) { + } else if let luidValue = String.fromDatabaseValue(row[RuuviTagLatestDataSQLite.ruuviTagIdColumn]) { luid = LocalIdentifierStruct(value: luidValue) } date = row[RuuviTagLatestDataSQLite.dateColumn] @@ -112,7 +112,8 @@ extension RuuviTagLatestDataSQLite: FetchableRecord { temperature = Temperature(value: celsius, unit: .celsius) if let relativeHumidity = Double.fromDatabaseValue(row[RuuviTagLatestDataSQLite.relativeHumidityInPercentColumn]), - let temperature = temperature { + let temperature + { humidity = Humidity(value: relativeHumidity, unit: .relative(temperature: temperature)) } @@ -121,8 +122,9 @@ extension RuuviTagLatestDataSQLite: FetchableRecord { pressure = Pressure(value: hectopascals, unit: .hectopascals) } if let accelerationX = Double.fromDatabaseValue(row[RuuviTagLatestDataSQLite.accelerationXColumn]), - let accelerationY = Double.fromDatabaseValue(row[RuuviTagLatestDataSQLite.accelerationYColumn]), - let accelerationZ = Double.fromDatabaseValue(row[RuuviTagLatestDataSQLite.accelerationZColumn]) { + let accelerationY = Double.fromDatabaseValue(row[RuuviTagLatestDataSQLite.accelerationYColumn]), + let accelerationZ = Double.fromDatabaseValue(row[RuuviTagLatestDataSQLite.accelerationZColumn]) + { acceleration = Acceleration(x: AccelerationMeasurement(value: accelerationX, unit: .metersPerSecondSquared), y: AccelerationMeasurement(value: accelerationY, unit: .metersPerSecondSquared), z: AccelerationMeasurement(value: accelerationZ, unit: .metersPerSecondSquared)) @@ -141,7 +143,7 @@ extension RuuviTagLatestDataSQLite: FetchableRecord { extension RuuviTagLatestDataSQLite: PersistableRecord { public static var databaseTableName: String { - return "ruuvi_tag_sensor_record_latest" + "ruuvi_tag_sensor_record_latest" } public func encode(to container: inout PersistenceContainer) { @@ -171,8 +173,8 @@ extension RuuviTagLatestDataSQLite: PersistableRecord { } } -extension RuuviTagLatestDataSQLite { - public static func createTable(in db: Database) throws { +public extension RuuviTagLatestDataSQLite { + static func createTable(in db: Database) throws { try db.create(table: RuuviTagLatestDataSQLite.databaseTableName, body: { table in table.column(RuuviTagLatestDataSQLite.idColumn.name, .text).notNull().primaryKey(onConflict: .replace) table.column(RuuviTagLatestDataSQLite.ruuviTagIdColumn.name, .text).notNull() diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSQLite.swift index fed6d3e59..053f727e8 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSQLite.swift @@ -51,22 +51,22 @@ public struct RuuviTagSQLite: RuuviTagSensor { } } -extension RuuviTagSQLite { - public static let idColumn = Column("id") - public static let macColumn = Column("mac") - public static let luidColumn = Column("luid") - public static let nameColumn = Column("name") - public static let versionColumn = Column("version") - public static let firmwareVersionColumn = Column("firmwareVersion") - public static let isConnectableColumn = Column("isConnectable") - public static let networkProviderColumn = Column("networkProvider") - public static let isClaimedColumn = Column("isClaimed") - public static let isOwnerColumn = Column("isOwner") - public static let owner = Column("owner") - public static let ownersPlan = Column("ownersPlan") - public static let isCloudSensor = Column("isCloudSensor") - public static let canShareColumn = Column("canShare") - public static let sharedToColumn = Column("sharedTo") +public extension RuuviTagSQLite { + static let idColumn = Column("id") + static let macColumn = Column("mac") + static let luidColumn = Column("luid") + static let nameColumn = Column("name") + static let versionColumn = Column("version") + static let firmwareVersionColumn = Column("firmwareVersion") + static let isConnectableColumn = Column("isConnectable") + static let networkProviderColumn = Column("networkProvider") + static let isClaimedColumn = Column("isClaimed") + static let isOwnerColumn = Column("isOwner") + static let owner = Column("owner") + static let ownersPlan = Column("ownersPlan") + static let isCloudSensor = Column("isCloudSensor") + static let canShareColumn = Column("canShare") + static let sharedToColumn = Column("sharedTo") } extension RuuviTagSQLite: FetchableRecord { @@ -98,7 +98,7 @@ extension RuuviTagSQLite: FetchableRecord { extension RuuviTagSQLite: PersistableRecord { public static var databaseTableName: String { - return "ruuvi_tag_sensors" + "ruuvi_tag_sensors" } public func encode(to container: inout PersistenceContainer) { @@ -119,8 +119,8 @@ extension RuuviTagSQLite: PersistableRecord { } } -extension RuuviTagSQLite { - public static func createTable(in db: Database) throws { +public extension RuuviTagSQLite { + static func createTable(in db: Database) throws { try db.create(table: RuuviTagSQLite.databaseTableName, body: { table in table.column(RuuviTagSQLite.idColumn.name, .text).notNull().primaryKey(onConflict: .abort) table.column(RuuviTagSQLite.macColumn.name, .text) diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSensorRecord+RuuviTagDataSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSensorRecord+RuuviTagDataSQLite.swift index a810369b5..101b32791 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSensorRecord+RuuviTagDataSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSensorRecord+RuuviTagDataSQLite.swift @@ -1,9 +1,9 @@ import Foundation import RuuviOntology -extension RuuviTagSensorRecord { - public var sqlite: RuuviTagDataSQLite { - return RuuviTagDataSQLite( +public extension RuuviTagSensorRecord { + var sqlite: RuuviTagDataSQLite { + RuuviTagDataSQLite( luid: luid, date: date, source: source, @@ -23,8 +23,8 @@ extension RuuviTagSensorRecord { ) } - public var latest: RuuviTagLatestDataSQLite { - return RuuviTagLatestDataSQLite( + var latest: RuuviTagLatestDataSQLite { + RuuviTagLatestDataSQLite( id: uuid, luid: luid, date: date, diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/SensorSettingsSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/SensorSettingsSQLite.swift index 0ed673cd5..d6c099b8e 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/SensorSettingsSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/SensorSettingsSQLite.swift @@ -33,16 +33,16 @@ public struct SensorSettingsSQLite: SensorSettings { } } -extension SensorSettingsSQLite { - public static let idColumn = Column("id") - public static let luidColumn = Column("luid") - public static let macIdColumn = Column("macId") - public static let temperatureOffsetColumn = Column("temperatureOffset") - public static let temperatureOffsetDateColumn = Column("temperatureOffsetDate") - public static let humidityOffsetColumn = Column("humidityOffset") - public static let humidityOffsetDateColumn = Column("humidityOffsetDate") - public static let pressureOffsetColumn = Column("pressureOffset") - public static let pressureOffsetDateColumn = Column("pressureOffsetDate") +public extension SensorSettingsSQLite { + static let idColumn = Column("id") + static let luidColumn = Column("luid") + static let macIdColumn = Column("macId") + static let temperatureOffsetColumn = Column("temperatureOffset") + static let temperatureOffsetDateColumn = Column("temperatureOffsetDate") + static let humidityOffsetColumn = Column("humidityOffset") + static let humidityOffsetDateColumn = Column("humidityOffsetDate") + static let pressureOffsetColumn = Column("pressureOffset") + static let pressureOffsetDateColumn = Column("pressureOffsetDate") } extension SensorSettingsSQLite: FetchableRecord { @@ -64,7 +64,7 @@ extension SensorSettingsSQLite: FetchableRecord { extension SensorSettingsSQLite: PersistableRecord { public static var databaseTableName: String { - return "sensor_settings" + "sensor_settings" } public func encode(to container: inout PersistenceContainer) { @@ -80,8 +80,8 @@ extension SensorSettingsSQLite: PersistableRecord { } } -extension SensorSettingsSQLite { - public static func createTable(in db: Database) throws { +public extension SensorSettingsSQLite { + static func createTable(in db: Database) throws { try db.create(table: SensorSettingsSQLite.databaseTableName, body: { table in table.column(RuuviTagDataSQLite.idColumn.name, .text).notNull().primaryKey(onConflict: .replace) table.column(SensorSettingsSQLite.luidColumn.name, .text) @@ -96,9 +96,9 @@ extension SensorSettingsSQLite { } } -extension SensorSettingsSQLite { - public var sensorSettings: SensorSettings { - return SensorSettingsStruct( +public extension SensorSettingsSQLite { + var sensorSettings: SensorSettings { + SensorSettingsStruct( luid: luid, macId: macId, temperatureOffset: temperatureOffset, @@ -111,9 +111,9 @@ extension SensorSettingsSQLite { } } -extension SensorSettings { - public var sqlite: SensorSettingsSQLite { - return SensorSettingsSQLite( +public extension SensorSettings { + var sqlite: SensorSettingsSQLite { + SensorSettingsSQLite( luid: luid, macId: macId, temperatureOffset: temperatureOffset, diff --git a/Packages/RuuviOntology/Tests/RuuviOntologyTests/RuuviOntologyTests.swift b/Packages/RuuviOntology/Tests/RuuviOntologyTests/RuuviOntologyTests.swift index ebaa1dd34..f12adb71a 100644 --- a/Packages/RuuviOntology/Tests/RuuviOntologyTests/RuuviOntologyTests.swift +++ b/Packages/RuuviOntology/Tests/RuuviOntologyTests/RuuviOntologyTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviOntology +import XCTest final class RuuviOntologyTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Packages/RuuviPersistence/Package.swift b/Packages/RuuviPersistence/Package.swift index c311e1131..a66e21321 100644 --- a/Packages/RuuviPersistence/Package.swift +++ b/Packages/RuuviPersistence/Package.swift @@ -9,20 +9,23 @@ let package = Package( products: [ .library( name: "RuuviPersistence", - targets: ["RuuviPersistence"]), + targets: ["RuuviPersistence"] + ), .library( name: "RuuviPersistenceRealm", - targets: ["RuuviPersistenceRealm"]), + targets: ["RuuviPersistenceRealm"] + ), .library( name: "RuuviPersistenceSQLite", - targets: ["RuuviPersistenceSQLite"]) + targets: ["RuuviPersistenceSQLite"] + ), ], dependencies: [ .package(url: "https://github.com/kean/Future", .exact("1.3.0")), .package(name: "Realm", url: "https://github.com/realm/realm-cocoa", .upToNextMajor(from: "10.8.0")), .package(name: "GRDB", url: "https://github.com/groue/GRDB.swift", .upToNextMajor(from: "4.14.0")), .package(path: "../RuuviOntology"), - .package(path: "../RuuviContext") + .package(path: "../RuuviContext"), ], targets: [ .target( @@ -30,7 +33,7 @@ let package = Package( dependencies: [ "RuuviOntology", "RuuviContext", - "Future" + "Future", ] ), .target( @@ -42,7 +45,7 @@ let package = Package( "RuuviPersistence", "RuuviOntology", "RuuviContext", - "Future" + "Future", ] ), .target( @@ -54,11 +57,12 @@ let package = Package( "RuuviPersistence", "RuuviOntology", "RuuviContext", - "Future" + "Future", ] ), .testTarget( name: "RuuviPersistenceTests", - dependencies: ["RuuviPersistence"]) + dependencies: ["RuuviPersistence"] + ), ] ) diff --git a/Packages/RuuviPersistence/Sources/RuuviPersistence/RuuviPersistence.swift b/Packages/RuuviPersistence/Sources/RuuviPersistence/RuuviPersistence.swift index 9743fcac3..09af390cb 100644 --- a/Packages/RuuviPersistence/Sources/RuuviPersistence/RuuviPersistence.swift +++ b/Packages/RuuviPersistence/Sources/RuuviPersistence/RuuviPersistence.swift @@ -1,5 +1,5 @@ -import Future import Foundation +import Future import RuuviOntology public protocol RuuviPersistence { @@ -62,6 +62,7 @@ public protocol RuuviPersistence { func cleanupDBSpace() -> Future // MARK: - Queued cloud requests + @discardableResult func readQueuedRequests() -> Future<[RuuviCloudQueuedRequest], RuuviPersistenceError> diff --git a/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift b/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift index bf7a4429f..c073d9d25 100644 --- a/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift +++ b/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift @@ -1,19 +1,19 @@ -// swiftlint:disable file_length -import RealmSwift -import Future import BTKit import Foundation -import RuuviOntology +import Future +// swiftlint:disable file_length +import RealmSwift import RuuviContext +import RuuviOntology import RuuviPersistence #if canImport(FirebaseCrashlytics) // TODO: @rinat eliminate -import FirebaseCrashlytics + import FirebaseCrashlytics #endif #if canImport(RuuviOntologyRealm) -import RuuviOntologyRealm + import RuuviOntologyRealm #endif #if canImport(RuuviContextRealm) -import RuuviContextRealm + import RuuviContextRealm #endif // swiftlint:disable type_body_length @@ -264,7 +264,7 @@ public class RuuviPersistenceRealm: RuuviPersistence { context.bgWorker.enqueue { let realmEntities = self.context.bg.objects(RuuviTagRealm.self) let result: [AnyRuuviTagSensor] = realmEntities.map { ruuviTagRealm in - return self.constructRuuviTagSensorStruct(from: ruuviTagRealm) + self.constructRuuviTagSensorStruct(from: ruuviTagRealm) } promise.succeed(value: result) } @@ -278,9 +278,9 @@ public class RuuviPersistenceRealm: RuuviPersistence { .filter("ruuviTag.uuid == %@", ruuviTagId) .sorted(byKeyPath: "date") let result: [RuuviTagSensorRecord] = realmRecords.map { realmRecord in - return self.constructRecordStruct(from: realmRecord, - luid: realmRecord.ruuviTag?.luid, - sequenceNumber: realmRecord.measurementSequenceNumber.value) + self.constructRecordStruct(from: realmRecord, + luid: realmRecord.ruuviTag?.luid, + sequenceNumber: realmRecord.measurementSequenceNumber.value) } promise.succeed(value: result) } @@ -306,8 +306,8 @@ public class RuuviPersistenceRealm: RuuviPersistence { previousDate = tagDataRealm.date results.append( self.constructRecordStruct(from: tagDataRealm, - luid: tagDataRealm.ruuviTag?.luid, - sequenceNumber: tagDataRealm.measurementSequenceNumber.value) + luid: tagDataRealm.ruuviTag?.luid, + sequenceNumber: tagDataRealm.measurementSequenceNumber.value) ) } } @@ -335,8 +335,8 @@ public class RuuviPersistenceRealm: RuuviPersistence { previousDate = realmRecord.date results.append( self.constructRecordStruct(from: realmRecord, - luid: realmRecord.ruuviTag?.luid, - sequenceNumber: realmRecord.measurementSequenceNumber.value) + luid: realmRecord.ruuviTag?.luid, + sequenceNumber: realmRecord.measurementSequenceNumber.value) ) } } @@ -365,8 +365,8 @@ public class RuuviPersistenceRealm: RuuviPersistence { previousDate = realmRecord.date results.append( self.constructRecordStruct(from: realmRecord, - luid: realmRecord.ruuviTag?.luid, - sequenceNumber: realmRecord.measurementSequenceNumber.value) + luid: realmRecord.ruuviTag?.luid, + sequenceNumber: realmRecord.measurementSequenceNumber.value) ) } } @@ -376,10 +376,10 @@ public class RuuviPersistenceRealm: RuuviPersistence { } public func readDownsampled( - _ ruuviTagId: String, - after date: Date, - with intervalMinutes: Int, - pick points: Double + _: String, + after _: Date, + with _: Int, + pick _: Double ) -> Future<[RuuviTagSensorRecord], RuuviPersistenceError> { let promise = Promise<[RuuviTagSensorRecord], RuuviPersistenceError>() // No need to implement since the RealmDB will be removed in the future. @@ -399,9 +399,9 @@ public class RuuviPersistenceRealm: RuuviPersistence { Date(timeIntervalSince1970: from)) .sorted(byKeyPath: "date") let result: [RuuviTagSensorRecord] = realmRecords.map { record in - return self.constructRecordStruct(from: record, - luid: record.ruuviTag?.luid, - sequenceNumber: record.measurementSequenceNumber.value) + self.constructRecordStruct(from: record, + luid: record.ruuviTag?.luid, + sequenceNumber: record.measurementSequenceNumber.value) } promise.succeed(value: result) } @@ -411,7 +411,8 @@ public class RuuviPersistenceRealm: RuuviPersistence { public func readLast(_ ruuviTag: RuuviTagSensor) -> Future { let promise = Promise() guard ruuviTag.macId == nil, - let luid = ruuviTag.luid else { + let luid = ruuviTag.luid + else { promise.succeed(value: nil) return promise.future } @@ -419,7 +420,8 @@ public class RuuviPersistenceRealm: RuuviPersistence { if let lastRecord = self.context.bg.objects(RuuviTagDataRealm.self) .filter("ruuviTag.uuid == %@", luid.value) .sorted(byKeyPath: "date", ascending: false) - .first { + .first + { let sequenceNumber = lastRecord.measurementSequenceNumber.value let lastRecordResult = self.constructRecordStruct(from: lastRecord, luid: luid, @@ -435,7 +437,8 @@ public class RuuviPersistenceRealm: RuuviPersistence { public func readLatest(_ ruuviTag: RuuviTagSensor) -> Future { let promise = Promise() guard ruuviTag.macId == nil, - let luid = ruuviTag.luid else { + let luid = ruuviTag.luid + else { promise.succeed(value: nil) return promise.future } @@ -443,7 +446,8 @@ public class RuuviPersistenceRealm: RuuviPersistence { if let lastRecord = self.context.bg.objects(RuuviTagLatestDataRealm.self) .filter("ruuviTag.uuid == %@", luid.value) .sorted(byKeyPath: "date", ascending: false) - .first { + .first + { let sequenceNumber = lastRecord.measurementSequenceNumber.value let lastRecordResult = self.constructRecordStruct(from: lastRecord, luid: luid, @@ -477,7 +481,8 @@ public class RuuviPersistenceRealm: RuuviPersistence { public func readSensorSettings(_ ruuviTag: RuuviTagSensor) -> Future { let promise = Promise() guard ruuviTag.macId == nil, - ruuviTag.luid != nil else { + ruuviTag.luid != nil + else { promise.fail(error: .failedToFindRuuviTag) return promise.future } @@ -486,7 +491,8 @@ public class RuuviPersistenceRealm: RuuviPersistence { .first(where: { ($0.luid != nil && $0.luid == ruuviTag.luid?.value) || ($0.macId != nil && $0.macId == ruuviTag.macId?.value) - }) { + }) + { promise.succeed(value: record.sensorSettings) } else { promise.succeed(value: nil) @@ -517,7 +523,7 @@ public class RuuviPersistenceRealm: RuuviPersistence { type: OffsetCorrectionType, with value: Double?, of ruuviTag: RuuviTagSensor, - lastOriginalRecord record: RuuviTagSensorRecord? + lastOriginalRecord _: RuuviTagSensorRecord? ) -> Future { let promise = Promise() assert(ruuviTag.macId == nil) @@ -528,7 +534,8 @@ public class RuuviPersistenceRealm: RuuviPersistence { .first(where: { ($0.luid != nil && $0.luid == ruuviTag.luid?.value) || ($0.macId != nil && $0.macId == ruuviTag.macId?.value) - }) { + }) + { try self.context.bg.write { switch type { case .humidity: @@ -579,7 +586,8 @@ public class RuuviPersistenceRealm: RuuviPersistence { .first(where: { ($0.luid != nil && $0.luid == ruuviTag.luid?.value) || ($0.macId != nil && $0.macId == ruuviTag.macId?.value) - }) { + }) + { try self.context.bg.write { self.context.bg.delete(sensorSettingRealm) } @@ -602,6 +610,7 @@ public class RuuviPersistenceRealm: RuuviPersistence { } // MARK: - Queued cloud requests + @discardableResult public func readQueuedRequests() -> Future<[RuuviCloudQueuedRequest], RuuviPersistenceError> { let promise = Promise<[RuuviCloudQueuedRequest], RuuviPersistenceError>() @@ -611,7 +620,7 @@ public class RuuviPersistenceRealm: RuuviPersistence { @discardableResult public func readQueuedRequests( - for key: String + for _: String ) -> Future<[RuuviCloudQueuedRequest], RuuviPersistenceError> { let promise = Promise<[RuuviCloudQueuedRequest], RuuviPersistenceError>() // No op for realmDB since this will be deprecated soon. @@ -620,7 +629,7 @@ public class RuuviPersistenceRealm: RuuviPersistence { @discardableResult public func readQueuedRequests( - for type: RuuviCloudQueuedRequestType + for _: RuuviCloudQueuedRequestType ) -> Future<[RuuviCloudQueuedRequest], RuuviPersistenceError> { let promise = Promise<[RuuviCloudQueuedRequest], RuuviPersistenceError>() // No op for realmDB since this will be deprecated soon. @@ -629,7 +638,7 @@ public class RuuviPersistenceRealm: RuuviPersistence { @discardableResult public func createQueuedRequest( - _ request: RuuviCloudQueuedRequest + _: RuuviCloudQueuedRequest ) -> Future { let promise = Promise() // No op for realmDB since this will be deprecated soon. @@ -638,7 +647,7 @@ public class RuuviPersistenceRealm: RuuviPersistence { @discardableResult public func deleteQueuedRequest( - _ request: RuuviCloudQueuedRequest + _: RuuviCloudQueuedRequest ) -> Future { let promise = Promise() // No op for realmDB since this will be deprecated soon. @@ -652,16 +661,19 @@ public class RuuviPersistenceRealm: RuuviPersistence { return promise.future } } + // MARK: - Private + extension RuuviPersistenceRealm { func reportToCrashlytics(error: Error, method: String = #function, line: Int = #line) { #if canImport(FirebaseCrashlytics) - Crashlytics.crashlytics().log("\(method)(line: \(line)") - Crashlytics.crashlytics().record(error: error) + Crashlytics.crashlytics().log("\(method)(line: \(line)") + Crashlytics.crashlytics().record(error: error) #endif } + private func constructRuuviTagSensorStruct(from ruuviTagRealm: RuuviTagRealm) -> AnyRuuviTagSensor { - return RuuviTagSensorStruct( + RuuviTagSensorStruct( version: ruuviTagRealm.version, firmwareVersion: ruuviTagRealm.firmwareVersion, luid: ruuviTagRealm.uuid.luid, @@ -677,9 +689,11 @@ extension RuuviPersistenceRealm { sharedTo: ruuviTagRealm.sharedTo ).any } + private func constructRecordStruct(from lastRecord: RuuviTagDataRealm, luid: LocalIdentifier?, - sequenceNumber: Int?) -> RuuviTagSensorRecordStruct { + sequenceNumber: Int?) -> RuuviTagSensorRecordStruct + { let lastRecordResult = RuuviTagSensorRecordStruct( luid: luid, date: lastRecord.date, @@ -703,7 +717,8 @@ extension RuuviPersistenceRealm { private func constructRecordStruct(from lastRecord: RuuviTagLatestDataRealm, luid: LocalIdentifier, - sequenceNumber: Int?) -> RuuviTagSensorRecordStruct { + sequenceNumber: Int?) -> RuuviTagSensorRecordStruct + { let lastRecordResult = RuuviTagSensorRecordStruct( luid: luid, date: lastRecord.date, @@ -725,4 +740,5 @@ extension RuuviPersistenceRealm { return lastRecordResult } } + // swiftlint:enable file_length type_body_length diff --git a/Packages/RuuviPersistence/Sources/RuuviPersistenceSQLite/RuuviPersistenceSQLite.swift b/Packages/RuuviPersistence/Sources/RuuviPersistenceSQLite/RuuviPersistenceSQLite.swift index 4920f3b66..fe7d2cfa7 100644 --- a/Packages/RuuviPersistence/Sources/RuuviPersistenceSQLite/RuuviPersistenceSQLite.swift +++ b/Packages/RuuviPersistence/Sources/RuuviPersistenceSQLite/RuuviPersistenceSQLite.swift @@ -3,17 +3,17 @@ import BTKit import Foundation import Future import GRDB -import RuuviOntology import RuuviContext +import RuuviOntology import RuuviPersistence #if canImport(FirebaseCrashlytics) -import FirebaseCrashlytics + import FirebaseCrashlytics #endif #if canImport(RuuviOntologySQLite) -import RuuviOntologySQLite + import RuuviOntologySQLite #endif #if canImport(RuuviContextSQLite) -import RuuviContextSQLite + import RuuviContextSQLite #endif // swiftlint:disable type_body_length @@ -25,12 +25,13 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { typealias QueuedRequest = RuuviCloudQueuedRequestSQLite public var database: GRDBDatabase { - return context.database + context.database } + private let context: SQLiteContext private let readQueue: DispatchQueue = - DispatchQueue(label: "RuuviTagPersistenceSQLite.readQueue", - qos: .default) + .init(label: "RuuviTagPersistenceSQLite.readQueue", + qos: .default) public init(context: SQLiteContext) { self.context = context } @@ -137,7 +138,7 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { let request = Entity.order(Entity.versionColumn) sqliteEntities = try request.fetchAll(db) } - promise.succeed(value: sqliteEntities.map({ $0.any })) + promise.succeed(value: sqliteEntities.map(\.any)) } catch { self?.reportToCrashlytics(error: error) promise.fail(error: .grdb(error)) @@ -155,7 +156,7 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { let request = Entity.filter(Entity.luidColumn == ruuviTagId || Entity.macColumn == ruuviTagId) entity = try request.fetchOne(db) } - if let entity = entity { + if let entity { promise.succeed(value: entity.any) } else { promise.fail(error: .failedToFindRuuviTag) @@ -178,7 +179,7 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { .filter(Record.luidColumn == ruuviTagId || Record.macColumn == ruuviTagId) sqliteEntities = try request.fetchAll(db) } - promise.succeed(value: sqliteEntities.map({ $0.any })) + promise.succeed(value: sqliteEntities.map(\.any)) } catch { self?.reportToCrashlytics(error: error) promise.fail(error: .grdb(error)) @@ -209,7 +210,7 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { arguments: [date] ) } - promise.succeed(value: sqliteEntities.map({ $0.any })) + promise.succeed(value: sqliteEntities.map(\.any)) } catch { self?.reportToCrashlytics(error: error) promise.fail(error: .grdb(error)) @@ -242,7 +243,7 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { arguments: [date] ) } - promise.succeed(value: sqliteEntities.map({ $0.any })) + promise.succeed(value: sqliteEntities.map(\.any)) } catch { self?.reportToCrashlytics(error: error) promise.fail(error: .grdb(error)) @@ -287,7 +288,7 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { arguments: [date, highDensityDate, highDensityDate] ) } - promise.succeed(value: sqliteEntities.map({ $0.any })) + promise.succeed(value: sqliteEntities.map(\.any)) } catch { self?.reportToCrashlytics(error: error) promise.fail(error: .grdb(error)) @@ -315,7 +316,7 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { """ sqliteEntities = try Record.fetchAll(db, sql: request) } - promise.succeed(value: sqliteEntities.map({ $0.any })) + promise.succeed(value: sqliteEntities.map(\.any)) } catch { self?.reportToCrashlytics(error: error) promise.fail(error: .grdb(error)) @@ -335,10 +336,10 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { try self?.database.dbPool.read { db in let request = Record.order(Record.dateColumn) .filter((Record.luidColumn == ruuviTagId || Record.macColumn == ruuviTagId) - && Record.dateColumn > Date(timeIntervalSince1970: from)) + && Record.dateColumn > Date(timeIntervalSince1970: from)) sqliteEntities = try request.fetchAll(db) } - promise.succeed(value: sqliteEntities.map({ $0.any })) + promise.succeed(value: sqliteEntities.map(\.any)) } catch { self?.reportToCrashlytics(error: error) promise.fail(error: .grdb(error)) @@ -491,8 +492,8 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { do { var deletedCount = 0 let request = Record.filter( - Record.luidColumn == ruuviTagId - || Record.macColumn == ruuviTagId) + Record.luidColumn == ruuviTagId + || Record.macColumn == ruuviTagId) .filter(Record.dateColumn < date) try database.dbPool.write { db in deletedCount = try request.deleteAll(db) @@ -504,6 +505,7 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { } return promise.future } + public func getStoredTagsCount() -> Future { let promise = Promise() readQueue.async { [weak self] in @@ -520,6 +522,7 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { } return promise.future } + public func getStoredMeasurementsCount() -> Future { let promise = Promise() readQueue.async { [weak self] in @@ -541,7 +544,7 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { let promise = Promise() do { var sqliteSensorSettings: Settings? - try self.database.dbPool.read { db in + try database.dbPool.read { db in let request = Settings.filter( (ruuviTag.luid?.value != nil && Settings.luidColumn == ruuviTag.luid?.value) || (ruuviTag.macId?.value != nil && Settings.macIdColumn == ruuviTag.macId?.value) @@ -550,7 +553,7 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { } promise.succeed(value: sqliteSensorSettings) } catch { - self.reportToCrashlytics(error: error) + reportToCrashlytics(error: error) promise.fail(error: .grdb(error)) } return promise.future @@ -623,7 +626,7 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { if let sqliteSensorRecord = record { try database.dbPool.write { db in try sqliteSensorRecord - .sqlite.insert(db) + .sqlite.insert(db) } } promise.succeed(value: sqliteSensorSettings) @@ -671,9 +674,11 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { } // MARK: - Queued cloud requests + @discardableResult public func readQueuedRequests() - -> Future<[RuuviCloudQueuedRequest], RuuviPersistenceError> { + -> Future<[RuuviCloudQueuedRequest], RuuviPersistenceError> + { let promise = Promise<[RuuviCloudQueuedRequest], RuuviPersistenceError>() readQueue.async { [weak self] in var sqliteEntities = [RuuviCloudQueuedRequest]() @@ -682,7 +687,7 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { let request = QueuedRequest.order(QueuedRequest.requestDateColumn) sqliteEntities = try request.fetchAll(db) } - promise.succeed(value: sqliteEntities.map({ $0 })) + promise.succeed(value: sqliteEntities.map { $0 }) } catch { self?.reportToCrashlytics(error: error) promise.fail(error: .grdb(error)) @@ -697,9 +702,9 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { ) -> Future<[RuuviCloudQueuedRequest], RuuviPersistenceError> { let promise = Promise<[RuuviCloudQueuedRequest], RuuviPersistenceError>() readQueuedRequests().on(success: { reqs in - let requests = reqs.filter({ req in + let requests = reqs.filter { req in req.uniqueKey != nil && req.uniqueKey == key - }) + } promise.succeed(value: requests) }, failure: { error in promise.fail(error: .grdb(error)) @@ -713,9 +718,9 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { ) -> Future<[RuuviCloudQueuedRequest], RuuviPersistenceError> { let promise = Promise<[RuuviCloudQueuedRequest], RuuviPersistenceError>() readQueuedRequests().on(success: { reqs in - let requests = reqs.filter({ req in + let requests = reqs.filter { req in req.type != nil && req.type == type - }) + } promise.succeed(value: requests) }, failure: { error in promise.fail(error: .grdb(error)) @@ -733,8 +738,9 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { readQueuedRequests().on(success: { [weak self] requests in let existingRequest = requests.first( - where: { ($0.uniqueKey != nil && $0.uniqueKey == request.uniqueKey ) - && ($0.type != nil && $0.type == request.type) } + where: { ($0.uniqueKey != nil && $0.uniqueKey == request.uniqueKey) + && ($0.type != nil && $0.type == request.type) + } ) let isCreate = (requests.count == 0) || existingRequest == nil @@ -799,11 +805,12 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { } // MARK: - Private + extension RuuviPersistenceSQLite { func reportToCrashlytics(error: Error, method: String = #function, line: Int = #line) { #if canImport(FirebaseCrashlytics) - Crashlytics.crashlytics().log("\(method)(line: \(line)") - Crashlytics.crashlytics().record(error: error) + Crashlytics.crashlytics().log("\(method)(line: \(line)") + Crashlytics.crashlytics().record(error: error) #endif } @@ -813,7 +820,8 @@ extension RuuviPersistenceSQLite { newRequest: RuuviCloudQueuedRequest, existingRequest: RuuviCloudQueuedRequest? ) - -> Future { + -> Future + { let promise = Promise() if isCreate { do { @@ -827,7 +835,7 @@ extension RuuviPersistenceSQLite { promise.fail(error: .grdb(error)) } } else { - guard let existingRequest = existingRequest else { + guard let existingRequest else { return promise.future } @@ -855,4 +863,5 @@ extension RuuviPersistenceSQLite { return promise.future } } + // swiftlint:enable file_length type_body_length diff --git a/Packages/RuuviPersistence/Tests/RuuviPersistenceTests/RuuviPersistenceTests.swift b/Packages/RuuviPersistence/Tests/RuuviPersistenceTests/RuuviPersistenceTests.swift index cf73955e6..415aff23a 100644 --- a/Packages/RuuviPersistence/Tests/RuuviPersistenceTests/RuuviPersistenceTests.swift +++ b/Packages/RuuviPersistence/Tests/RuuviPersistenceTests/RuuviPersistenceTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviPersistence +import XCTest final class RuuviPersistenceTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Packages/RuuviPool/Package.swift b/Packages/RuuviPool/Package.swift index ceee1a7e7..2c171a58b 100644 --- a/Packages/RuuviPool/Package.swift +++ b/Packages/RuuviPool/Package.swift @@ -9,16 +9,18 @@ let package = Package( products: [ .library( name: "RuuviPool", - targets: ["RuuviPool"]), + targets: ["RuuviPool"] + ), .library( name: "RuuviPoolCoordinator", - targets: ["RuuviPoolCoordinator"]) + targets: ["RuuviPoolCoordinator"] + ), ], dependencies: [ .package(url: "https://github.com/kean/Future", .exact("1.3.0")), .package(path: "../RuuviOntology"), .package(path: "../RuuviPersistence"), - .package(path: "../RuuviLocal") + .package(path: "../RuuviLocal"), ], targets: [ .target( @@ -27,7 +29,7 @@ let package = Package( "RuuviOntology", "RuuviPersistence", "RuuviLocal", - "Future" + "Future", ] ), .target( @@ -37,11 +39,12 @@ let package = Package( "RuuviOntology", "RuuviPersistence", "RuuviLocal", - "Future" + "Future", ] ), .testTarget( name: "RuuviPoolTests", - dependencies: ["RuuviPool"]) + dependencies: ["RuuviPool"] + ), ] ) diff --git a/Packages/RuuviPool/Sources/RuuviPool/RuuviPool.swift b/Packages/RuuviPool/Sources/RuuviPool/RuuviPool.swift index 684d84e41..e534587c2 100644 --- a/Packages/RuuviPool/Sources/RuuviPool/RuuviPool.swift +++ b/Packages/RuuviPool/Sources/RuuviPool/RuuviPool.swift @@ -39,6 +39,7 @@ public protocol RuuviPool { ) -> Future // MARK: - Queued cloud requests + @discardableResult func createQueuedRequest(_ request: RuuviCloudQueuedRequest) -> Future @discardableResult @@ -47,13 +48,13 @@ public protocol RuuviPool { func deleteQueuedRequests() -> Future } -extension RuuviPool { - public func updateOffsetCorrection( +public extension RuuviPool { + func updateOffsetCorrection( type: OffsetCorrectionType, with value: Double?, of ruuviTag: RuuviTagSensor ) -> Future { - return updateOffsetCorrection( + updateOffsetCorrection( type: type, with: value, of: ruuviTag, diff --git a/Packages/RuuviPool/Sources/RuuviPool/RuuviPoolFactory.swift b/Packages/RuuviPool/Sources/RuuviPool/RuuviPoolFactory.swift index 717aea56c..ad33593b1 100644 --- a/Packages/RuuviPool/Sources/RuuviPool/RuuviPoolFactory.swift +++ b/Packages/RuuviPool/Sources/RuuviPool/RuuviPoolFactory.swift @@ -1,6 +1,6 @@ import Foundation -import RuuviPersistence import RuuviLocal +import RuuviPersistence public protocol RuuviPoolFactory { func create( diff --git a/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolCoordinator.swift b/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolCoordinator.swift index 48ef06064..d31bfb3fb 100644 --- a/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolCoordinator.swift +++ b/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolCoordinator.swift @@ -1,8 +1,8 @@ import Foundation import Future +import RuuviLocal import RuuviOntology import RuuviPersistence -import RuuviLocal import RuuviPool // swiftlint:disable:next type_body_length @@ -30,20 +30,22 @@ final class RuuviPoolCoordinator: RuuviPool { func create(_ ruuviTag: RuuviTagSensor) -> Future { let promise = Promise() if let macId = ruuviTag.macId, - let luid = ruuviTag.luid { + let luid = ruuviTag.luid + { idPersistence.set(mac: macId, for: luid) } if ruuviTag.macId != nil, - ruuviTag.macId?.value.isEmpty == false { - sqlite.create(ruuviTag).on(success: { (result) in + ruuviTag.macId?.value.isEmpty == false + { + sqlite.create(ruuviTag).on(success: { result in promise.succeed(value: result) - }, failure: { (error) in + }, failure: { error in promise.fail(error: .ruuviPersistence(error)) }) } else { - realm.create(ruuviTag).on(success: { (result) in + realm.create(ruuviTag).on(success: { result in promise.succeed(value: result) - }, failure: { (error) in + }, failure: { error in promise.fail(error: .ruuviPersistence(error)) }) } @@ -102,7 +104,6 @@ final class RuuviPoolCoordinator: RuuviPool { }) } return promise.future - } func create(_ record: RuuviTagSensorRecord) -> Future { @@ -114,7 +115,8 @@ final class RuuviPoolCoordinator: RuuviPool { promise.fail(error: .ruuviPersistence(error)) }) } else if let luid = record.luid, - let macId = idPersistence.mac(for: luid) { + let macId = idPersistence.mac(for: luid) + { sqlite.create(record.with(macId: macId)).on(success: { success in promise.succeed(value: success) }, failure: { error in @@ -139,7 +141,8 @@ final class RuuviPoolCoordinator: RuuviPool { promise.fail(error: .ruuviPersistence(error)) }) } else if let luid = record.luid, - let macId = idPersistence.mac(for: luid) { + let macId = idPersistence.mac(for: luid) + { sqlite.createLast(record.with(macId: macId)).on(success: { success in promise.succeed(value: success) }, failure: { error in @@ -164,7 +167,8 @@ final class RuuviPoolCoordinator: RuuviPool { promise.fail(error: .ruuviPersistence(error)) }) } else if let luid = record.luid, - let macId = idPersistence.mac(for: luid) { + let macId = idPersistence.mac(for: luid) + { sqlite.updateLast(record.with(macId: macId)).on(success: { success in promise.succeed(value: success) }, failure: { error in @@ -194,8 +198,8 @@ final class RuuviPoolCoordinator: RuuviPool { func create(_ records: [RuuviTagSensorRecord]) -> Future { let promise = Promise() - let sqliteRecords = records.filter({ $0.macId != nil }) - let realmRecords = records.filter({ $0.macId == nil }) + let sqliteRecords = records.filter { $0.macId != nil } + let realmRecords = records.filter { $0.macId == nil } let sqliteOperation = sqlite.create(sqliteRecords) let realmOpearion = realm.create(realmRecords) Future.zip(sqliteOperation, realmOpearion).on(success: { _ in @@ -255,28 +259,31 @@ final class RuuviPoolCoordinator: RuuviPool { type: type, with: value, of: ruuviTag, - lastOriginalRecord: record) - .on(success: { settings in - promise.succeed(value: settings) - }, failure: { error in - promise.fail(error: .ruuviPersistence(error)) - }) + lastOriginalRecord: record + ) + .on(success: { settings in + promise.succeed(value: settings) + }, failure: { error in + promise.fail(error: .ruuviPersistence(error)) + }) } else { realm.updateOffsetCorrection( type: type, with: value, of: ruuviTag, - lastOriginalRecord: record) - .on(success: { settings in - promise.succeed(value: settings) - }, failure: { error in - promise.fail(error: .ruuviPersistence(error)) - }) + lastOriginalRecord: record + ) + .on(success: { settings in + promise.succeed(value: settings) + }, failure: { error in + promise.fail(error: .ruuviPersistence(error)) + }) } return promise.future } // MARK: - Queued cloud requests + func createQueuedRequest( _ request: RuuviCloudQueuedRequest ) -> Future { diff --git a/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolFactoryCoordinator.swift b/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolFactoryCoordinator.swift index cbf0e174f..6d627bca5 100644 --- a/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolFactoryCoordinator.swift +++ b/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolFactoryCoordinator.swift @@ -1,7 +1,7 @@ import Foundation -import RuuviPool import RuuviLocal import RuuviPersistence +import RuuviPool public final class RuuviPoolFactoryCoordinator: RuuviPoolFactory { public init() {} @@ -13,7 +13,7 @@ public final class RuuviPoolFactoryCoordinator: RuuviPoolFactory { settings: RuuviLocalSettings, connectionPersistence: RuuviLocalConnections ) -> RuuviPool { - return RuuviPoolCoordinator( + RuuviPoolCoordinator( sqlite: sqlite, realm: realm, idPersistence: idPersistence, diff --git a/Packages/RuuviPool/Tests/RuuviPoolTests/RuuviPoolTests.swift b/Packages/RuuviPool/Tests/RuuviPoolTests/RuuviPoolTests.swift index bd0017ddb..16206af88 100644 --- a/Packages/RuuviPool/Tests/RuuviPoolTests/RuuviPoolTests.swift +++ b/Packages/RuuviPool/Tests/RuuviPoolTests/RuuviPoolTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviPool +import XCTest final class RuuviPoolTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Packages/RuuviReactor/Package.swift b/Packages/RuuviReactor/Package.swift index 56849b046..1fb89b17c 100644 --- a/Packages/RuuviReactor/Package.swift +++ b/Packages/RuuviReactor/Package.swift @@ -9,22 +9,24 @@ let package = Package( products: [ .library( name: "RuuviReactor", - targets: ["RuuviReactor"]), + targets: ["RuuviReactor"] + ), .library( name: "RuuviReactorImpl", - targets: ["RuuviReactorImpl"]) + targets: ["RuuviReactorImpl"] + ), ], dependencies: [ .package(path: "../RuuviOntology"), .package(path: "../RuuviPersistence"), - .package(path: "../RuuviContext") + .package(path: "../RuuviContext"), ], targets: [ .target( name: "RuuviReactor", dependencies: [ "RuuviOntology", - "RuuviPersistence" + "RuuviPersistence", ] ), .target( @@ -34,11 +36,12 @@ let package = Package( "RuuviContext", "RuuviPersistence", .product(name: "RuuviOntologyRealm", package: "RuuviOntology"), - .product(name: "RuuviOntologySQLite", package: "RuuviOntology") + .product(name: "RuuviOntologySQLite", package: "RuuviOntology"), ] ), .testTarget( name: "RuuviReactorTests", - dependencies: ["RuuviReactor"]) + dependencies: ["RuuviReactor"] + ), ] ) diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLastRecordSubjectCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLastRecordSubjectCombine.swift index f0d742673..2e2ed6999 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLastRecordSubjectCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLastRecordSubjectCombine.swift @@ -1,14 +1,14 @@ +import Combine import Foundation import GRDB -import Combine import RealmSwift -import RuuviOntology import RuuviContext +import RuuviOntology #if canImport(RuuviOntologyRealm) -import RuuviOntologyRealm + import RuuviOntologyRealm #endif #if canImport(RuuviOntologySQLite) -import RuuviOntologySQLite + import RuuviOntologySQLite #endif final class RuuviTagLastRecordSubjectCombine { @@ -40,31 +40,30 @@ final class RuuviTagLastRecordSubjectCombine { } func start() { - self.isServing = true + isServing = true let request = RuuviTagDataSQLite .order(RuuviTagDataSQLite.dateColumn.desc) .filter( (luid?.value != nil && RuuviTagDataSQLite.luidColumn == luid?.value) - || (macId?.value != nil && RuuviTagDataSQLite.macColumn == macId?.value) + || (macId?.value != nil && RuuviTagDataSQLite.macColumn == macId?.value) ) let observation = request.observationForFirst() - self.ruuviTagDataTransactionObserver = try! observation.start(in: sqlite.database.dbPool) { + ruuviTagDataTransactionObserver = try! observation.start(in: sqlite.database.dbPool) { [weak self] record in if let lastRecord = record?.any { self?.subject.send(lastRecord) } } - let results = self.realm.main.objects(RuuviTagDataRealm.self) + let results = realm.main.objects(RuuviTagDataRealm.self) .filter("ruuviTag.uuid == %@ || ruuviTag.mac == %@", luid?.value ?? "invalid", - macId?.value ?? "invalid" - ) + macId?.value ?? "invalid") .sorted(byKeyPath: "date") - self.ruuviTagDataRealmToken = results.observe { [weak self] (change) in + ruuviTagDataRealmToken = results.observe { [weak self] change in guard let sSelf = self else { return } switch change { - case .update(let records, _, _, _): + case let .update(records, _, _, _): if let lastRecord = records.last?.any { sSelf.subject.send(lastRecord) } diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLatestRecordSubjectCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLatestRecordSubjectCombine.swift index 8fa755203..9652486e2 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLatestRecordSubjectCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLatestRecordSubjectCombine.swift @@ -1,14 +1,14 @@ +import Combine import Foundation import GRDB -import Combine import RealmSwift -import RuuviOntology import RuuviContext +import RuuviOntology #if canImport(RuuviOntologyRealm) -import RuuviOntologyRealm + import RuuviOntologyRealm #endif #if canImport(RuuviOntologySQLite) -import RuuviOntologySQLite + import RuuviOntologySQLite #endif final class RuuviTagLatestRecordSubjectCombine { @@ -40,31 +40,30 @@ final class RuuviTagLatestRecordSubjectCombine { } func start() { - self.isServing = true + isServing = true let request = RuuviTagLatestDataSQLite .order(RuuviTagLatestDataSQLite.dateColumn.desc) .filter( (luid?.value != nil && RuuviTagLatestDataSQLite.luidColumn == luid?.value) - || (macId?.value != nil && RuuviTagLatestDataSQLite.macColumn == macId?.value) + || (macId?.value != nil && RuuviTagLatestDataSQLite.macColumn == macId?.value) ) let observation = request.observationForFirst() - self.ruuviTagDataTransactionObserver = try! observation.start(in: sqlite.database.dbPool) { + ruuviTagDataTransactionObserver = try! observation.start(in: sqlite.database.dbPool) { [weak self] record in if let lastRecord = record?.any { self?.subject.send(lastRecord) } } - let results = self.realm.main.objects(RuuviTagLatestDataRealm.self) + let results = realm.main.objects(RuuviTagLatestDataRealm.self) .filter("ruuviTag.uuid == %@ || ruuviTag.mac == %@", luid?.value ?? "invalid", - macId?.value ?? "invalid" - ) + macId?.value ?? "invalid") .sorted(byKeyPath: "date") - self.ruuviTagDataRealmToken = results.observe { [weak self] (change) in + ruuviTagDataRealmToken = results.observe { [weak self] change in guard let sSelf = self else { return } switch change { - case .update(let records, _, _, _): + case let .update(records, _, _, _): if let lastRecord = records.last?.any { sSelf.subject.send(lastRecord) } diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagRecordSubjectCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagRecordSubjectCombine.swift index e169f647e..5afecbba7 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagRecordSubjectCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagRecordSubjectCombine.swift @@ -1,14 +1,14 @@ +import Combine import Foundation import GRDB -import Combine import RealmSwift -import RuuviOntology import RuuviContext +import RuuviOntology #if canImport(RuuviOntologyRealm) -import RuuviOntologyRealm + import RuuviOntologyRealm #endif #if canImport(RuuviOntologySQLite) -import RuuviOntologySQLite + import RuuviOntologySQLite #endif final class RuuviTagRecordSubjectCombine { @@ -41,38 +41,37 @@ final class RuuviTagRecordSubjectCombine { } func start() { - self.isServing = true + isServing = true let request = RuuviTagDataSQLite.order(RuuviTagDataSQLite.dateColumn) .filter( (luid?.value != nil && RuuviTagDataSQLite.luidColumn == luid?.value) - || (macId?.value != nil && RuuviTagDataSQLite.macColumn == macId?.value) + || (macId?.value != nil && RuuviTagDataSQLite.macColumn == macId?.value) ) let observation = ValueObservation.tracking { db -> [RuuviTagDataSQLite] in try! request.fetchAll(db) }.removeDuplicates() - self.ruuviTagDataTransactionObserver = try! observation.start(in: sqlite.database.dbPool) { + ruuviTagDataTransactionObserver = try! observation.start(in: sqlite.database.dbPool) { [weak self] records in - self?.subject.send(records.map({ $0.any })) + self?.subject.send(records.map(\.any)) } - let results = self.realm.main.objects(RuuviTagDataRealm.self) + let results = realm.main.objects(RuuviTagDataRealm.self) .filter("ruuviTag.uuid == %@ || ruuviTag.mac == %@", luid?.value ?? "invalid", - macId?.value ?? "invalid" - ) + macId?.value ?? "invalid") .sorted(byKeyPath: "date") - self.ruuviTagDataRealmCache = results.compactMap({ $0.any }) - self.ruuviTagDataRealmToken = results.observe { [weak self] (change) in + ruuviTagDataRealmCache = results.compactMap(\.any) + ruuviTagDataRealmToken = results.observe { [weak self] change in guard let sSelf = self else { return } switch change { - case .initial(let records): + case let .initial(records): if records.count > 0 { - sSelf.subject.send(records.compactMap({ $0.any })) + sSelf.subject.send(records.compactMap(\.any)) } - case .update(let records, _, _, _): + case let .update(records, _, _, _): if records.count > 0 { - sSelf.subject.send(records.compactMap({ $0.any })) + sSelf.subject.send(records.compactMap(\.any)) } default: break diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagSubjectCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagSubjectCombine.swift index df1ea5123..b44e7b730 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagSubjectCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagSubjectCombine.swift @@ -1,14 +1,14 @@ +import Combine import Foundation import GRDB -import Combine import RealmSwift -import RuuviOntology import RuuviContext +import RuuviOntology #if canImport(RuuviOntologyRealm) -import RuuviOntologyRealm + import RuuviOntologyRealm #endif #if canImport(RuuviOntologySQLite) -import RuuviOntologySQLite + import RuuviOntologySQLite #endif final class RuuviTagSubjectCombine { @@ -33,10 +33,10 @@ final class RuuviTagSubjectCombine { self.realm = realm let request = RuuviTagSQLite.order(RuuviTagSQLite.versionColumn) - self.ruuviTagController = try! FetchedRecordsController(sqlite.database.dbPool, request: request) - try! self.ruuviTagController.performFetch() + ruuviTagController = try! FetchedRecordsController(sqlite.database.dbPool, request: request) + try! ruuviTagController.performFetch() - self.ruuviTagController.trackChanges(onChange: { [weak self] _, record, event in + ruuviTagController.trackChanges(onChange: { [weak self] _, record, event in guard let sSelf = self else { return } switch event { case .insertion: @@ -59,18 +59,18 @@ final class RuuviTagSubjectCombine { DispatchQueue.main.async { [weak self] in guard let sSelf = self else { return } let results = sSelf.realm.main.objects(RuuviTagRealm.self) - sSelf.ruuviTagRealmCache = results.map({ $0.struct.any }) - sSelf.ruuviTagsRealmToken = results.observe { [weak self] (change) in + sSelf.ruuviTagRealmCache = results.map(\.struct.any) + sSelf.ruuviTagsRealmToken = results.observe { [weak self] change in guard let sSelf = self else { return } switch change { - case .update(let ruuviSensors, let deletions, let insertions, let modifications): + case let .update(ruuviSensors, deletions, insertions, modifications): for del in deletions { sSelf.deleteSubject.send(sSelf.ruuviTagRealmCache[del].struct.any) } sSelf.ruuviTagRealmCache = sSelf.ruuviTagRealmCache - .enumerated() - .filter { !deletions.contains($0.offset) } - .map { $0.element } + .enumerated() + .filter { !deletions.contains($0.offset) } + .map(\.element) for ins in insertions { sSelf.insertSubject.send(ruuviSensors[ins].struct.any) // TODO: test if ok with multiple diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/SensorSettingsCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/SensorSettingsCombine.swift index 6c76f1f0f..971b17f83 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/SensorSettingsCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/SensorSettingsCombine.swift @@ -1,14 +1,14 @@ +import Combine import Foundation import GRDB -import Combine import RealmSwift -import RuuviOntology import RuuviContext +import RuuviOntology #if canImport(RuuviOntologyRealm) -import RuuviOntologyRealm + import RuuviOntologyRealm #endif #if canImport(RuuviOntologySQLite) -import RuuviOntologySQLite + import RuuviOntologySQLite #endif final class SensorSettingsCombine { @@ -44,12 +44,12 @@ final class SensorSettingsCombine { let request = SensorSettingsSQLite .filter( (luid?.value != nil && SensorSettingsSQLite.luidColumn == luid?.value) - || (macId?.value != nil && SensorSettingsSQLite.macIdColumn == macId?.value) + || (macId?.value != nil && SensorSettingsSQLite.macIdColumn == macId?.value) ) - self.ruuviTagController = try! FetchedRecordsController(sqlite.database.dbPool, request: request) - try! self.ruuviTagController.performFetch() + ruuviTagController = try! FetchedRecordsController(sqlite.database.dbPool, request: request) + try! ruuviTagController.performFetch() - self.ruuviTagController.trackChanges(onChange: { [weak self] _, record, event in + ruuviTagController.trackChanges(onChange: { [weak self] _, record, event in guard let sSelf = self else { return } switch event { case .insertion: @@ -68,20 +68,19 @@ final class SensorSettingsCombine { let results = sSelf.realm.main.objects(SensorSettingsRealm.self) .filter("luid == %@ || macId == %@", luid?.value ?? "invalid", - macId?.value ?? "invalid" - ) - sSelf.ruuviTagRealmCache = results.map({ $0.sensorSettings }) - sSelf.ruuviTagsRealmToken = results.observe { [weak self] (change) in + macId?.value ?? "invalid") + sSelf.ruuviTagRealmCache = results.map(\.sensorSettings) + sSelf.ruuviTagsRealmToken = results.observe { [weak self] change in guard let sSelf = self else { return } switch change { - case .update(let sensorSettings, let deletions, let insertions, let modifications): + case let .update(sensorSettings, deletions, insertions, modifications): for del in deletions { sSelf.deleteSubject.send(sSelf.ruuviTagRealmCache[del]) } sSelf.ruuviTagRealmCache = sSelf.ruuviTagRealmCache - .enumerated() - .filter { !deletions.contains($0.offset) } - .map { $0.element } + .enumerated() + .filter { !deletions.contains($0.offset) } + .map(\.element) for ins in insertions { sSelf.insertSubject.send(sensorSettings[ins].sensorSettings) // TODO: test if ok with multiple diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorFactoryImpl.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorFactoryImpl.swift index 482df5dbf..3887ce40e 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorFactoryImpl.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorFactoryImpl.swift @@ -12,7 +12,7 @@ public final class RuuviReactorFactoryImpl: RuuviReactorFactory { sqlitePersistence: RuuviPersistence, realmPersistence: RuuviPersistence ) -> RuuviReactor { - return RuuviReactorImpl( + RuuviReactorImpl( sqliteContext: sqliteContext, realmContext: realmContext, sqlitePersistence: sqlitePersistence, diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift index 472c5376a..36ebfabe9 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift @@ -1,15 +1,15 @@ import Foundation -import GRDB import Future -import RuuviOntology +import GRDB import RuuviContext +import RuuviOntology import RuuviPersistence import RuuviReactor #if canImport(RuuviOntologyRealm) -import RuuviOntologyRealm + import RuuviOntologyRealm #endif #if canImport(RuuviOntologySQLite) -import RuuviOntologySQLite + import RuuviOntologySQLite #endif class RuuviReactorImpl: RuuviReactor { @@ -43,7 +43,8 @@ class RuuviReactorImpl: RuuviReactor { private lazy var sensorSettingsCombines = [String: SensorSettingsCombine]() func observe(_ luid: LocalIdentifier, - _ block: @escaping ([AnyRuuviTagSensorRecord]) -> Void) -> RuuviReactorToken { + _ block: @escaping ([AnyRuuviTagSensorRecord]) -> Void) -> RuuviReactorToken + { var recordCombine: RuuviTagRecordSubjectCombine if let combine = recordCombines[luid.value] { recordCombine = combine @@ -73,11 +74,11 @@ class RuuviReactorImpl: RuuviReactor { let realmOperation = realmPersistence.readAll() Future.zip(realmOperation, sqliteOperation) .on(success: { realmEntities, sqliteEntities in - let combinedValues = sqliteEntities + realmEntities - block(.initial(combinedValues)) - }, failure: { error in - block(.error(.ruuviPersistence(error))) - }) + let combinedValues = sqliteEntities + realmEntities + block(.initial(combinedValues)) + }, failure: { error in + block(.error(.ruuviPersistence(error))) + }) let insert = entityCombine.insertSubject.sink { value in block(.insert(value)) @@ -96,11 +97,12 @@ class RuuviReactorImpl: RuuviReactor { } func observeLast(_ ruuviTag: RuuviTagSensor, - _ block: @escaping (RuuviReactorChange) -> Void) -> RuuviReactorToken { + _ block: @escaping (RuuviReactorChange) -> Void) -> RuuviReactorToken + { let sqliteOperation = sqlitePersistence.readLast(ruuviTag) let realmOperation = realmPersistence.readLast(ruuviTag) - Future.zip(realmOperation, sqliteOperation).on(success: { (realmRecord, sqliteRecord) in - let result = [realmRecord, sqliteRecord].compactMap({$0?.any}).last + Future.zip(realmOperation, sqliteOperation).on(success: { realmRecord, sqliteRecord in + let result = [realmRecord, sqliteRecord].compactMap { $0?.any }.last block(.update(result)) }) var recordCombine: RuuviTagLastRecordSubjectCombine @@ -116,7 +118,7 @@ class RuuviReactorImpl: RuuviReactor { lastRecordCombines[ruuviTag.id] = combine recordCombine = combine } - let cancellable = recordCombine.subject.sink { (record) in + let cancellable = recordCombine.subject.sink { record in block(.update(record)) } if !recordCombine.isServing { @@ -128,11 +130,12 @@ class RuuviReactorImpl: RuuviReactor { } func observeLatest(_ ruuviTag: RuuviTagSensor, - _ block: @escaping (RuuviReactorChange) -> Void) -> RuuviReactorToken { + _ block: @escaping (RuuviReactorChange) -> Void) -> RuuviReactorToken + { let sqliteOperation = sqlitePersistence.readLatest(ruuviTag) let realmOperation = realmPersistence.readLatest(ruuviTag) - Future.zip(realmOperation, sqliteOperation).on(success: { (realmRecord, sqliteRecord) in - let result = [realmRecord, sqliteRecord].compactMap({$0?.any}).last + Future.zip(realmOperation, sqliteOperation).on(success: { realmRecord, sqliteRecord in + let result = [realmRecord, sqliteRecord].compactMap { $0?.any }.last block(.update(result)) }) var recordCombine: RuuviTagLatestRecordSubjectCombine @@ -148,7 +151,7 @@ class RuuviReactorImpl: RuuviReactor { latestRecordCombines[ruuviTag.id] = combine recordCombine = combine } - let cancellable = recordCombine.subject.sink { (record) in + let cancellable = recordCombine.subject.sink { record in block(.update(record)) } if !recordCombine.isServing { @@ -160,7 +163,8 @@ class RuuviReactorImpl: RuuviReactor { } func observe(_ ruuviTag: RuuviTagSensor, - _ block: @escaping (RuuviReactorChange) -> Void) -> RuuviReactorToken { + _ block: @escaping (RuuviReactorChange) -> Void) -> RuuviReactorToken + { sqlitePersistence.readSensorSettings(ruuviTag).on { [weak self] sqliteRecord in if let sensorSettings = sqliteRecord { block(.update(sensorSettings)) diff --git a/Packages/RuuviReactor/Tests/RuuviReactorTests/RuuviReactorTests.swift b/Packages/RuuviReactor/Tests/RuuviReactorTests/RuuviReactorTests.swift index 7c376a432..a8666075a 100644 --- a/Packages/RuuviReactor/Tests/RuuviReactorTests/RuuviReactorTests.swift +++ b/Packages/RuuviReactor/Tests/RuuviReactorTests/RuuviReactorTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviReactor +import XCTest final class RuuviReactorTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Packages/RuuviRepository/Package.swift b/Packages/RuuviRepository/Package.swift index df13b9326..8447f3dda 100644 --- a/Packages/RuuviRepository/Package.swift +++ b/Packages/RuuviRepository/Package.swift @@ -9,16 +9,18 @@ let package = Package( products: [ .library( name: "RuuviRepository", - targets: ["RuuviRepository"]), + targets: ["RuuviRepository"] + ), .library( name: "RuuviRepositoryCoordinator", - targets: ["RuuviRepositoryCoordinator"]) + targets: ["RuuviRepositoryCoordinator"] + ), ], dependencies: [ .package(url: "https://github.com/kean/Future", .exact("1.3.0")), .package(path: "../RuuviOntology"), .package(path: "../RuuviPool"), - .package(path: "../RuuviStorage") + .package(path: "../RuuviStorage"), ], targets: [ .target( @@ -27,7 +29,7 @@ let package = Package( "RuuviOntology", "RuuviPool", "RuuviStorage", - "Future" + "Future", ] ), .target( @@ -37,11 +39,12 @@ let package = Package( "RuuviOntology", "RuuviPool", "RuuviStorage", - "Future" + "Future", ] ), .testTarget( name: "RuuviRepositoryTests", - dependencies: ["RuuviRepository"]) + dependencies: ["RuuviRepository"] + ), ] ) diff --git a/Packages/RuuviRepository/Sources/RuuviRepositoryCoordinator/RuuviRepositoryCoordinator.swift b/Packages/RuuviRepository/Sources/RuuviRepositoryCoordinator/RuuviRepositoryCoordinator.swift index 1f688d155..4111e0b94 100644 --- a/Packages/RuuviRepository/Sources/RuuviRepositoryCoordinator/RuuviRepositoryCoordinator.swift +++ b/Packages/RuuviRepository/Sources/RuuviRepositoryCoordinator/RuuviRepositoryCoordinator.swift @@ -1,9 +1,9 @@ import Foundation -import RuuviOntology import Future +import RuuviOntology import RuuviPool -import RuuviStorage import RuuviRepository +import RuuviStorage final class RuuviRepositoryCoordinator: RuuviRepository { private let pool: RuuviPool @@ -19,10 +19,10 @@ final class RuuviRepositoryCoordinator: RuuviRepository { func create( record: RuuviTagSensorRecord, - for sensor: RuuviTagSensor + for _: RuuviTagSensor ) -> Future { let promise = Promise() - self.pool.create(record) + pool.create(record) .on(success: { _ in promise.succeed(value: record.any) }, failure: { error in @@ -33,11 +33,11 @@ final class RuuviRepositoryCoordinator: RuuviRepository { func create( records: [RuuviTagSensorRecord], - for sensor: RuuviTagSensor + for _: RuuviTagSensor ) -> Future<[AnyRuuviTagSensorRecord], RuuviRepositoryError> { let promise = Promise<[AnyRuuviTagSensorRecord], RuuviRepositoryError>() - let mappedRecords = records.map({ $0.any }) - self.pool.create(mappedRecords) + let mappedRecords = records.map(\.any) + pool.create(mappedRecords) .on(success: { _ in promise.succeed(value: mappedRecords) }, failure: { error in diff --git a/Packages/RuuviRepository/Sources/RuuviRepositoryCoordinator/RuuviRepositoryFactoryCoordinator.swift b/Packages/RuuviRepository/Sources/RuuviRepositoryCoordinator/RuuviRepositoryFactoryCoordinator.swift index ca58ab8c5..ae7382e58 100644 --- a/Packages/RuuviRepository/Sources/RuuviRepositoryCoordinator/RuuviRepositoryFactoryCoordinator.swift +++ b/Packages/RuuviRepository/Sources/RuuviRepositoryCoordinator/RuuviRepositoryFactoryCoordinator.swift @@ -1,7 +1,7 @@ import Foundation import RuuviPool -import RuuviStorage import RuuviRepository +import RuuviStorage public final class RuuviRepositoryFactoryCoordinator: RuuviRepositoryFactory { public init() {} @@ -10,7 +10,7 @@ public final class RuuviRepositoryFactoryCoordinator: RuuviRepositoryFactory { pool: RuuviPool, storage: RuuviStorage ) -> RuuviRepository { - return RuuviRepositoryCoordinator( + RuuviRepositoryCoordinator( pool: pool, storage: storage ) diff --git a/Packages/RuuviRepository/Tests/RuuviRepositoryTests/RuuviRepositoryTests.swift b/Packages/RuuviRepository/Tests/RuuviRepositoryTests/RuuviRepositoryTests.swift index 7c58389b1..63101d55c 100644 --- a/Packages/RuuviRepository/Tests/RuuviRepositoryTests/RuuviRepositoryTests.swift +++ b/Packages/RuuviRepository/Tests/RuuviRepositoryTests/RuuviRepositoryTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviRepository +import XCTest final class RuuviRepositoryTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Packages/RuuviService/Package.swift b/Packages/RuuviService/Package.swift index 9a617e608..dad58263d 100644 --- a/Packages/RuuviService/Package.swift +++ b/Packages/RuuviService/Package.swift @@ -9,47 +9,60 @@ let package = Package( products: [ .library( name: "RuuviService", - targets: ["RuuviService"]), + targets: ["RuuviService"] + ), .library( name: "RuuviServiceAlert", - targets: ["RuuviServiceAlert"]), + targets: ["RuuviServiceAlert"] + ), .library( name: "RuuviServiceAuth", - targets: ["RuuviServiceAuth"]), + targets: ["RuuviServiceAuth"] + ), .library( name: "RuuviServiceCloudNotification", - targets: ["RuuviServiceCloudNotification"]), + targets: ["RuuviServiceCloudNotification"] + ), .library( name: "RuuviServiceAppSettings", - targets: ["RuuviServiceAppSettings"]), + targets: ["RuuviServiceAppSettings"] + ), .library( name: "RuuviServiceCloudSync", - targets: ["RuuviServiceCloudSync"]), + targets: ["RuuviServiceCloudSync"] + ), .library( name: "RuuviServiceOffsetCalibration", - targets: ["RuuviServiceOffsetCalibration"]), + targets: ["RuuviServiceOffsetCalibration"] + ), .library( name: "RuuviServiceOwnership", - targets: ["RuuviServiceOwnership"]), + targets: ["RuuviServiceOwnership"] + ), .library( name: "RuuviServiceSensorProperties", - targets: ["RuuviServiceSensorProperties"]), + targets: ["RuuviServiceSensorProperties"] + ), .library( name: "RuuviServiceSensorRecords", - targets: ["RuuviServiceSensorRecords"]), + targets: ["RuuviServiceSensorRecords"] + ), .library( name: "RuuviServiceMeasurement", - targets: ["RuuviServiceMeasurement"]), + targets: ["RuuviServiceMeasurement"] + ), .library( name: "RuuviServiceExport", - targets: ["RuuviServiceExport"]), + targets: ["RuuviServiceExport"] + ), .library( name: "RuuviServiceGATT", - targets: ["RuuviServiceGATT"]), + targets: ["RuuviServiceGATT"] + ), .library( name: "RuuviServiceFactory", targets: ["RuuviServiceFactory"] - ) + ), ], dependencies: [ .package(url: "https://github.com/kean/Future", .exact("1.3.0")), @@ -61,7 +74,7 @@ let package = Package( .package(path: "../RuuviPool"), .package(path: "../RuuviLocal"), .package(path: "../RuuviRepository"), - .package(path: "../RuuviCore") + .package(path: "../RuuviCore"), ], targets: [ .target( @@ -74,19 +87,19 @@ let package = Package( "RuuviPool", "RuuviLocal", "RuuviRepository", - "RuuviCore" + "RuuviCore", ] ), .target( name: "RuuviServiceAlert", dependencies: [ - "RuuviService" + "RuuviService", ] ), .target( name: "RuuviServiceAuth", dependencies: [ - "RuuviService" + "RuuviService", ] ), .target( @@ -96,56 +109,56 @@ let package = Package( .product( name: "RuuviCloudApi", package: "RuuviCloud" - ) + ), ] ), .target( name: "RuuviServiceAppSettings", dependencies: [ - "RuuviService" + "RuuviService", ] ), .target( name: "RuuviServiceCloudSync", dependencies: [ - "RuuviService" + "RuuviService", ] ), .target( name: "RuuviServiceOffsetCalibration", dependencies: [ - "RuuviService" + "RuuviService", ] ), .target( name: "RuuviServiceOwnership", dependencies: [ - "RuuviService" + "RuuviService", ] ), .target( name: "RuuviServiceSensorProperties", dependencies: [ - "RuuviService" + "RuuviService", ] ), .target( name: "RuuviServiceSensorRecords", dependencies: [ - "RuuviService" + "RuuviService", ] ), .target( name: "RuuviServiceExport", dependencies: [ - "RuuviService" + "RuuviService", ] ), .target( name: "RuuviServiceGATT", dependencies: [ "RuuviService", - "BTKit" + "BTKit", ] ), .target( @@ -154,7 +167,7 @@ let package = Package( "RuuviService", "RuuviLocal", "RuuviOntology", - "Humidity" + "Humidity", ] ), .target( @@ -169,11 +182,12 @@ let package = Package( "RuuviServiceOwnership", "RuuviServiceSensorProperties", "RuuviServiceSensorRecords", - "RuuviServiceCloudNotification" + "RuuviServiceCloudNotification", ] ), .testTarget( name: "RuuviServiceTests", - dependencies: ["RuuviService"]) + dependencies: ["RuuviService"] + ), ] ) diff --git a/Packages/RuuviService/Sources/RuuviService/AsyncOperation.swift b/Packages/RuuviService/Sources/RuuviService/AsyncOperation.swift index cccd179ae..785688885 100644 --- a/Packages/RuuviService/Sources/RuuviService/AsyncOperation.swift +++ b/Packages/RuuviService/Sources/RuuviService/AsyncOperation.swift @@ -1,55 +1,53 @@ import Foundation open class AsyncOperation: Operation { + public enum State: String { + case ready, executing, finished - public enum State: String { - case ready, executing, finished - - fileprivate var keyPath: String { - return "is" + rawValue.capitalized + fileprivate var keyPath: String { + "is" + rawValue.capitalized + } } - } - open var state = State.ready { - willSet { - willChangeValue(forKey: newValue.keyPath) - willChangeValue(forKey: state.keyPath) - } - didSet { - didChangeValue(forKey: oldValue.keyPath) - didChangeValue(forKey: state.keyPath) + open var state = State.ready { + willSet { + willChangeValue(forKey: newValue.keyPath) + willChangeValue(forKey: state.keyPath) + } + didSet { + didChangeValue(forKey: oldValue.keyPath) + didChangeValue(forKey: state.keyPath) + } } - } } extension AsyncOperation { - override open var isReady: Bool { - return super.isReady && state == .ready - } - - override open var isExecuting: Bool { - return state == .executing - } + override open var isReady: Bool { + super.isReady && state == .ready + } - override open var isFinished: Bool { - return state == .finished - } + override open var isExecuting: Bool { + state == .executing + } - override open var isAsynchronous: Bool { - return true - } + override open var isFinished: Bool { + state == .finished + } - override open func start() { - if isCancelled { - state = .finished - return + override open var isAsynchronous: Bool { + true } - main() - state = .executing - } - override open func cancel() { - state = .finished - } + override open func start() { + if isCancelled { + state = .finished + return + } + main() + state = .executing + } + override open func cancel() { + state = .finished + } } diff --git a/Packages/RuuviService/Sources/RuuviService/GATTService.swift b/Packages/RuuviService/Sources/RuuviService/GATTService.swift index 62a15cf6f..310dfd005 100644 --- a/Packages/RuuviService/Sources/RuuviService/GATTService.swift +++ b/Packages/RuuviService/Sources/RuuviService/GATTService.swift @@ -1,13 +1,13 @@ +import BTKit import Foundation import Future -import BTKit import RuuviOntology -extension Notification.Name { - public static let RuuviTagReadLogsOperationDidStart = Notification.Name("RuuviTagReadLogsOperationDidStart") - public static let RuuviTagReadLogsOperationDidFail = Notification.Name("RuuviTagReadLogsOperationDidFail") - public static let RuuviTagReadLogsOperationProgress = Notification.Name("RuuviTagReadLogsOperationProgress") - public static let RuuviTagReadLogsOperationDidFinish = Notification.Name("RuuviTagReadLogsOperationDidFinish") +public extension Notification.Name { + static let RuuviTagReadLogsOperationDidStart = Notification.Name("RuuviTagReadLogsOperationDidStart") + static let RuuviTagReadLogsOperationDidFail = Notification.Name("RuuviTagReadLogsOperationDidFail") + static let RuuviTagReadLogsOperationProgress = Notification.Name("RuuviTagReadLogsOperationProgress") + static let RuuviTagReadLogsOperationDidFinish = Notification.Name("RuuviTagReadLogsOperationDidFinish") } public enum RuuviTagReadLogsOperationDidStartKey: String { @@ -49,15 +49,15 @@ public protocol GATTService { func stopGattSync(for uuid: String) -> Future } -extension GATTService { +public extension GATTService { @discardableResult - public func syncLogs( + func syncLogs( uuid: String, mac: String?, from: Date, settings: SensorSettings? ) -> Future { - return syncLogs( + syncLogs( uuid: uuid, mac: mac, from: from, @@ -69,7 +69,7 @@ extension GATTService { } @discardableResult - public func stopGattSync(for uuid: String) -> Future { - return stopGattSync(for: uuid) + func stopGattSync(for uuid: String) -> Future { + stopGattSync(for: uuid) } } diff --git a/Packages/RuuviService/Sources/RuuviService/RuuviServiceAlert.swift b/Packages/RuuviService/Sources/RuuviService/RuuviServiceAlert.swift index 80372ac00..defdf0022 100644 --- a/Packages/RuuviService/Sources/RuuviService/RuuviServiceAlert.swift +++ b/Packages/RuuviService/Sources/RuuviService/RuuviServiceAlert.swift @@ -2,9 +2,9 @@ import Foundation import Future import RuuviOntology -extension Notification.Name { - public static let RuuviServiceAlertDidChange = Notification.Name("RuuviServiceAlertDidChange") - public static let RuuviServiceAlertTriggerDidChange = +public extension Notification.Name { + static let RuuviServiceAlertDidChange = Notification.Name("RuuviServiceAlertDidChange") + static let RuuviServiceAlertTriggerDidChange = Notification.Name("RuuviServiceAlertTriggerDidChange") } @@ -14,9 +14,9 @@ public enum RuuviServiceAlertDidChangeKey: String { } public protocol RuuviServiceAlert: RuuviServiceAlertRuuviTag, - RuuviServiceAlertPhysicalSensor, - RuuviServiceAlertCloud, - RuuviServiceAlertDeprecated {} + RuuviServiceAlertPhysicalSensor, + RuuviServiceAlertCloud, + RuuviServiceAlertDeprecated {} public protocol RuuviServiceAlertRuuviTag { func register(type: AlertType, ruuviTag: RuuviTagSensor) diff --git a/Packages/RuuviService/Sources/RuuviService/RuuviServiceCloudNotification.swift b/Packages/RuuviService/Sources/RuuviService/RuuviServiceCloudNotification.swift index a589c4045..dffb3d0bb 100644 --- a/Packages/RuuviService/Sources/RuuviService/RuuviServiceCloudNotification.swift +++ b/Packages/RuuviService/Sources/RuuviService/RuuviServiceCloudNotification.swift @@ -3,7 +3,6 @@ import Future import RuuviOntology public protocol RuuviServiceCloudNotification { - @discardableResult func set(token: String?, name: String?, diff --git a/Packages/RuuviService/Sources/RuuviService/RuuviServiceError.swift b/Packages/RuuviService/Sources/RuuviService/RuuviServiceError.swift index 6260e16ce..f22d468b7 100644 --- a/Packages/RuuviService/Sources/RuuviService/RuuviServiceError.swift +++ b/Packages/RuuviService/Sources/RuuviService/RuuviServiceError.swift @@ -1,10 +1,10 @@ +import BTKit import Foundation -import RuuviStorage import RuuviCloud -import RuuviPool import RuuviLocal +import RuuviPool import RuuviRepository -import BTKit +import RuuviStorage public enum RuuviServiceError: Error { case ruuviRepository(RuuviRepositoryError) diff --git a/Packages/RuuviService/Sources/RuuviService/RuuviServiceMeasurement.swift b/Packages/RuuviService/Sources/RuuviService/RuuviServiceMeasurement.swift index 44bce4a89..52c1f8a08 100644 --- a/Packages/RuuviService/Sources/RuuviService/RuuviServiceMeasurement.swift +++ b/Packages/RuuviService/Sources/RuuviService/RuuviServiceMeasurement.swift @@ -68,19 +68,21 @@ public protocol RuuviServiceMeasurement { func string(for measurement: Double?) -> String } -extension RuuviServiceMeasurement { - public func double(for temperature: Temperature?) -> Double? { - guard let temperature = temperature else { +public extension RuuviServiceMeasurement { + func double(for temperature: Temperature?) -> Double? { + guard let temperature else { return nil } return double(for: temperature) } - public func double(for humidity: Humidity?, - temperature: Temperature?, - isDecimal: Bool) -> Double? { - guard let temperature = temperature, - let humidity = humidity else { + func double(for humidity: Humidity?, + temperature: Temperature?, + isDecimal: Bool) -> Double? + { + guard let temperature, + let humidity + else { return nil } return double(for: humidity, @@ -88,53 +90,53 @@ extension RuuviServiceMeasurement { isDecimal: isDecimal) } - public func double(for pressure: Pressure?) -> Double? { - guard let pressure = pressure else { + func double(for pressure: Pressure?) -> Double? { + guard let pressure else { return nil } return double(for: pressure) } - public func double(for voltage: Voltage?) -> Double? { - guard let voltage = voltage else { + func double(for voltage: Voltage?) -> Double? { + guard let voltage else { return nil } return double(for: voltage) } } -extension Language { - public var locale: Locale { +public extension Language { + var locale: Locale { switch self { case .english: - return Locale(identifier: "en_US") + Locale(identifier: "en_US") case .russian: - return Locale(identifier: "ru_RU") + Locale(identifier: "ru_RU") case .finnish: - return Locale(identifier: "fi") + Locale(identifier: "fi") case .french: - return Locale(identifier: "fr") + Locale(identifier: "fr") case .swedish: - return Locale(identifier: "sv") + Locale(identifier: "sv") case .german: - return Locale(identifier: "de") + Locale(identifier: "de") } } - public var humidityLanguage: HumiditySettings.Language { + var humidityLanguage: HumiditySettings.Language { switch self { case .german: - return .en + .en case .russian: - return .ru + .ru case .finnish: - return .fi + .fi case .french: - return .en + .en case .swedish: - return .sv + .sv case .english: - return .en + .en } } } diff --git a/Packages/RuuviService/Sources/RuuviService/RuuviServiceOffsetCalibration.swift b/Packages/RuuviService/Sources/RuuviService/RuuviServiceOffsetCalibration.swift index 2735ff0e0..7bea2caba 100644 --- a/Packages/RuuviService/Sources/RuuviService/RuuviServiceOffsetCalibration.swift +++ b/Packages/RuuviService/Sources/RuuviService/RuuviServiceOffsetCalibration.swift @@ -12,14 +12,14 @@ public protocol RuuviServiceOffsetCalibration { ) -> Future } -extension RuuviServiceOffsetCalibration { +public extension RuuviServiceOffsetCalibration { @discardableResult - public func set( + func set( offset: Double?, of type: OffsetCorrectionType, for sensor: RuuviTagSensor ) -> Future { - return set( + set( offset: offset, of: type, for: sensor, diff --git a/Packages/RuuviService/Sources/RuuviService/RuuviServiceOwnership.swift b/Packages/RuuviService/Sources/RuuviService/RuuviServiceOwnership.swift index 610acd4ad..26062a374 100644 --- a/Packages/RuuviService/Sources/RuuviService/RuuviServiceOwnership.swift +++ b/Packages/RuuviService/Sources/RuuviService/RuuviServiceOwnership.swift @@ -1,7 +1,7 @@ import Foundation import Future -import RuuviOntology import RuuviCloud +import RuuviOntology public protocol RuuviServiceOwnership { @discardableResult diff --git a/Packages/RuuviService/Sources/RuuviService/RuuviServiceSensorProperties.swift b/Packages/RuuviService/Sources/RuuviService/RuuviServiceSensorProperties.swift index 3b9ced0ee..d129aa99c 100644 --- a/Packages/RuuviService/Sources/RuuviService/RuuviServiceSensorProperties.swift +++ b/Packages/RuuviService/Sources/RuuviService/RuuviServiceSensorProperties.swift @@ -1,7 +1,7 @@ -import UIKit import Foundation import Future import RuuviOntology +import UIKit public protocol RuuviServiceSensorProperties { @discardableResult @@ -26,12 +26,12 @@ public protocol RuuviServiceSensorProperties { func removeImage(for sensor: RuuviTagSensor) } -extension RuuviServiceSensorProperties { - public func set( +public extension RuuviServiceSensorProperties { + func set( image: UIImage, for sensor: RuuviTagSensor ) -> Future { - return set( + set( image: image, for: sensor, progress: nil, diff --git a/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/AlertPersistenceUserDefaults.swift b/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/AlertPersistenceUserDefaults.swift index 2a36f68b3..814514115 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/AlertPersistenceUserDefaults.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/AlertPersistenceUserDefaults.swift @@ -126,99 +126,106 @@ class AlertPersistenceUserDefaults: AlertPersistence { switch type { case .temperature: if prefs.bool(forKey: temperatureAlertIsOnUDKeyPrefix + uuid), - let lower = prefs.optionalDouble(forKey: temperatureLowerBoundUDKeyPrefix + uuid), - let upper = prefs.optionalDouble(forKey: temperatureUpperBoundUDKeyPrefix + uuid) { - return .temperature(lower: lower, upper: upper) + let lower = prefs.optionalDouble(forKey: temperatureLowerBoundUDKeyPrefix + uuid), + let upper = prefs.optionalDouble(forKey: temperatureUpperBoundUDKeyPrefix + uuid) + { + .temperature(lower: lower, upper: upper) } else { - return nil + nil } case .relativeHumidity: if prefs.bool(forKey: relativeHumidityAlertIsOnUDKeyPrefix + uuid), - let lower = prefs.optionalDouble(forKey: relativeHumidityLowerBoundUDKeyPrefix + uuid), - let upper = prefs.optionalDouble(forKey: relativeHumidityUpperBoundUDKeyPrefix + uuid) { - return .relativeHumidity(lower: lower, upper: upper) + let lower = prefs.optionalDouble(forKey: relativeHumidityLowerBoundUDKeyPrefix + uuid), + let upper = prefs.optionalDouble(forKey: relativeHumidityUpperBoundUDKeyPrefix + uuid) + { + .relativeHumidity(lower: lower, upper: upper) } else { - return nil + nil } case .humidity: if prefs.bool(forKey: humidityAlertIsOnUDKeyPrefix + uuid), let lower = prefs.data(forKey: humidityLowerBoundUDKeyPrefix + uuid), let upper = prefs.data(forKey: humidityUpperBoundUDKeyPrefix + uuid), - let lowerHumidity = KeyedArchiver.unarchive(lower, with: Humidity.self), - let upperHumidity = KeyedArchiver.unarchive(upper, with: Humidity.self) { - return .humidity(lower: lowerHumidity, upper: upperHumidity) + let lowerHumidity = KeyedArchiver.unarchive(lower, with: Humidity.self), + let upperHumidity = KeyedArchiver.unarchive(upper, with: Humidity.self) + { + .humidity(lower: lowerHumidity, upper: upperHumidity) } else { - return nil + nil } case .pressure: if prefs.bool(forKey: pressureAlertIsOnUDKeyPrefix + uuid), - let lower = prefs.optionalDouble(forKey: pressureLowerBoundUDKeyPrefix + uuid), - let upper = prefs.optionalDouble(forKey: pressureUpperBoundUDKeyPrefix + uuid) { - return .pressure(lower: lower, upper: upper) + let lower = prefs.optionalDouble(forKey: pressureLowerBoundUDKeyPrefix + uuid), + let upper = prefs.optionalDouble(forKey: pressureUpperBoundUDKeyPrefix + uuid) + { + .pressure(lower: lower, upper: upper) } else { - return nil + nil } case .signal: if prefs.bool(forKey: signalAlertIsOnUDKeyPrefix + uuid), - let lower = prefs.optionalDouble(forKey: signalLowerBoundUDKeyPrefix + uuid), - let upper = prefs.optionalDouble(forKey: signalUpperBoundUDKeyPrefix + uuid) { - return .signal(lower: lower, upper: upper) + let lower = prefs.optionalDouble(forKey: signalLowerBoundUDKeyPrefix + uuid), + let upper = prefs.optionalDouble(forKey: signalUpperBoundUDKeyPrefix + uuid) + { + .signal(lower: lower, upper: upper) } else { - return nil + nil } case .connection: if prefs.bool(forKey: connectionAlertIsOnUDKeyPrefix + uuid) { - return .connection + .connection } else { - return nil + nil } case .cloudConnection: if prefs.bool(forKey: cloudConnectionAlertIsOnUDKeyPrefix + uuid), let unseenDuration = prefs.optionalDouble( - forKey: cloudConnectionAlertUnseenDurationUDPrefix + uuid - ) { - return .cloudConnection(unseenDuration: unseenDuration) + forKey: cloudConnectionAlertUnseenDurationUDPrefix + uuid + ) + { + .cloudConnection(unseenDuration: unseenDuration) } else { - return nil + nil } case .movement: if prefs.bool(forKey: movementAlertIsOnUDKeyPrefix + uuid), - let counter = prefs.optionalInt(forKey: movementAlertCounterUDPrefix + uuid) { - return .movement(last: counter) + let counter = prefs.optionalInt(forKey: movementAlertCounterUDPrefix + uuid) + { + .movement(last: counter) } else { - return nil + nil } } } func register(type: AlertType, for uuid: String) { switch type { - case .temperature(let lower, let upper): + case let .temperature(lower, upper): prefs.set(true, forKey: temperatureAlertIsOnUDKeyPrefix + uuid) prefs.set(lower, forKey: temperatureLowerBoundUDKeyPrefix + uuid) prefs.set(upper, forKey: temperatureUpperBoundUDKeyPrefix + uuid) - case .relativeHumidity(let lower, let upper): + case let .relativeHumidity(lower, upper): prefs.set(true, forKey: relativeHumidityAlertIsOnUDKeyPrefix + uuid) prefs.set(lower, forKey: relativeHumidityLowerBoundUDKeyPrefix + uuid) prefs.set(upper, forKey: relativeHumidityUpperBoundUDKeyPrefix + uuid) - case .humidity(let lower, let upper): + case let .humidity(lower, upper): prefs.set(true, forKey: humidityAlertIsOnUDKeyPrefix + uuid) prefs.set(KeyedArchiver.archive(object: lower), forKey: humidityLowerBoundUDKeyPrefix + uuid) prefs.set(KeyedArchiver.archive(object: upper), forKey: humidityUpperBoundUDKeyPrefix + uuid) - case .pressure(let lower, let upper): + case let .pressure(lower, upper): prefs.set(true, forKey: pressureAlertIsOnUDKeyPrefix + uuid) prefs.set(lower, forKey: pressureLowerBoundUDKeyPrefix + uuid) prefs.set(upper, forKey: pressureUpperBoundUDKeyPrefix + uuid) - case .signal(let lower, let upper): + case let .signal(lower, upper): prefs.set(true, forKey: signalAlertIsOnUDKeyPrefix + uuid) prefs.set(lower, forKey: signalLowerBoundUDKeyPrefix + uuid) prefs.set(upper, forKey: signalUpperBoundUDKeyPrefix + uuid) case .connection: prefs.set(true, forKey: connectionAlertIsOnUDKeyPrefix + uuid) - case .cloudConnection(let unseenDuration): + case let .cloudConnection(unseenDuration): prefs.set(true, forKey: cloudConnectionAlertIsOnUDKeyPrefix + uuid) prefs.set(unseenDuration, forKey: cloudConnectionAlertUnseenDurationUDPrefix + uuid) - case .movement(let last): + case let .movement(last): prefs.set(true, forKey: movementAlertIsOnUDKeyPrefix + uuid) prefs.set(last, forKey: movementAlertCounterUDPrefix + uuid) } @@ -226,31 +233,31 @@ class AlertPersistenceUserDefaults: AlertPersistence { func unregister(type: AlertType, for uuid: String) { switch type { - case .temperature(let lower, let upper): + case let .temperature(lower, upper): prefs.set(false, forKey: temperatureAlertIsOnUDKeyPrefix + uuid) prefs.set(lower, forKey: temperatureLowerBoundUDKeyPrefix + uuid) prefs.set(upper, forKey: temperatureUpperBoundUDKeyPrefix + uuid) prefs.set(false, forKey: temperatureAlertIsTriggeredUDKeyPrefix + uuid) prefs.set(nil, forKey: temperatureAlertTriggeredAtUDKeyPrefix + uuid) - case .relativeHumidity(let lower, let upper): + case let .relativeHumidity(lower, upper): prefs.set(false, forKey: relativeHumidityAlertIsOnUDKeyPrefix + uuid) prefs.set(lower, forKey: relativeHumidityLowerBoundUDKeyPrefix + uuid) prefs.set(upper, forKey: relativeHumidityUpperBoundUDKeyPrefix + uuid) prefs.set(false, forKey: relativeHumidityAlertIsTriggeredUDKeyPrefix + uuid) prefs.set(nil, forKey: relativeHumidityAlertTriggeredAtUDKeyPrefix + uuid) - case .humidity(let lower, let upper): + case let .humidity(lower, upper): prefs.set(false, forKey: humidityAlertIsOnUDKeyPrefix + uuid) prefs.set(KeyedArchiver.archive(object: lower), forKey: humidityLowerBoundUDKeyPrefix + uuid) prefs.set(KeyedArchiver.archive(object: upper), forKey: humidityUpperBoundUDKeyPrefix + uuid) prefs.set(false, forKey: humidityAlertIsTriggeredUDKeyPrefix + uuid) prefs.set(nil, forKey: humidityAlertTriggeredAtUDKeyPrefix + uuid) - case .pressure(let lower, let upper): + case let .pressure(lower, upper): prefs.set(false, forKey: pressureAlertIsOnUDKeyPrefix + uuid) prefs.set(lower, forKey: pressureLowerBoundUDKeyPrefix + uuid) prefs.set(upper, forKey: pressureUpperBoundUDKeyPrefix + uuid) prefs.set(false, forKey: pressureAlertIsTriggeredUDKeyPrefix + uuid) prefs.set(nil, forKey: pressureAlertTriggeredAtUDKeyPrefix + uuid) - case .signal(let lower, let upper): + case let .signal(lower, upper): prefs.set(false, forKey: signalAlertIsOnUDKeyPrefix + uuid) prefs.set(lower, forKey: signalLowerBoundUDKeyPrefix + uuid) prefs.set(upper, forKey: signalUpperBoundUDKeyPrefix + uuid) @@ -258,12 +265,12 @@ class AlertPersistenceUserDefaults: AlertPersistence { prefs.set(nil, forKey: signalAlertTriggeredAtUDKeyPrefix + uuid) case .connection: prefs.set(false, forKey: connectionAlertIsOnUDKeyPrefix + uuid) - case .cloudConnection(let unseenDuration): + case let .cloudConnection(unseenDuration): prefs.set(false, forKey: cloudConnectionAlertIsOnUDKeyPrefix + uuid) prefs.set(unseenDuration, forKey: cloudConnectionAlertUnseenDurationUDPrefix + uuid) prefs.set(false, forKey: cloudConnectionAlertIsTriggeredUDKeyPrefix + uuid) prefs.set(nil, forKey: cloudConnectionAlertTriggeredAtUDKeyPrefix + uuid) - case .movement(let last): + case let .movement(last): prefs.set(false, forKey: movementAlertIsOnUDKeyPrefix + uuid) prefs.set(last, forKey: movementAlertCounterUDPrefix + uuid) prefs.set(false, forKey: movementAlertIsTriggeredUDKeyPrefix + uuid) @@ -273,31 +280,31 @@ class AlertPersistenceUserDefaults: AlertPersistence { func remove(type: AlertType, for uuid: String) { switch type { - case .temperature(let lower, let upper): + case let .temperature(lower, upper): prefs.removeObject(forKey: temperatureAlertIsOnUDKeyPrefix + uuid) prefs.removeObject(forKey: temperatureLowerBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: temperatureUpperBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: temperatureAlertIsTriggeredUDKeyPrefix + uuid) prefs.removeObject(forKey: temperatureAlertTriggeredAtUDKeyPrefix + uuid) - case .relativeHumidity(let lower, let upper): + case let .relativeHumidity(lower, upper): prefs.removeObject(forKey: relativeHumidityAlertIsOnUDKeyPrefix + uuid) prefs.removeObject(forKey: relativeHumidityLowerBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: relativeHumidityUpperBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: relativeHumidityAlertIsTriggeredUDKeyPrefix + uuid) prefs.removeObject(forKey: relativeHumidityAlertTriggeredAtUDKeyPrefix + uuid) - case .humidity(let lower, let upper): + case let .humidity(lower, upper): prefs.removeObject(forKey: humidityAlertIsOnUDKeyPrefix + uuid) prefs.removeObject(forKey: humidityLowerBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: humidityUpperBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: humidityAlertIsTriggeredUDKeyPrefix + uuid) prefs.removeObject(forKey: humidityAlertTriggeredAtUDKeyPrefix + uuid) - case .pressure(let lower, let upper): + case let .pressure(lower, upper): prefs.removeObject(forKey: pressureAlertIsOnUDKeyPrefix + uuid) prefs.removeObject(forKey: pressureLowerBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: pressureUpperBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: pressureAlertIsTriggeredUDKeyPrefix + uuid) prefs.removeObject(forKey: pressureAlertTriggeredAtUDKeyPrefix + uuid) - case .signal(let lower, let upper): + case let .signal(lower, upper): prefs.removeObject(forKey: signalAlertIsOnUDKeyPrefix + uuid) prefs.removeObject(forKey: signalLowerBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: signalUpperBoundUDKeyPrefix + uuid) @@ -305,12 +312,12 @@ class AlertPersistenceUserDefaults: AlertPersistence { prefs.removeObject(forKey: signalAlertTriggeredAtUDKeyPrefix + uuid) case .connection: prefs.removeObject(forKey: connectionAlertIsOnUDKeyPrefix + uuid) - case .cloudConnection(let unseenDuration): + case let .cloudConnection(unseenDuration): prefs.removeObject(forKey: cloudConnectionAlertIsOnUDKeyPrefix + uuid) prefs.removeObject(forKey: cloudConnectionAlertUnseenDurationUDPrefix + uuid) prefs.removeObject(forKey: cloudConnectionAlertIsTriggeredUDKeyPrefix + uuid) prefs.removeObject(forKey: cloudConnectionAlertTriggeredAtUDKeyPrefix + uuid) - case .movement(let last): + case let .movement(last): prefs.removeObject(forKey: movementAlertIsOnUDKeyPrefix + uuid) prefs.removeObject(forKey: movementAlertCounterUDPrefix + uuid) prefs.removeObject(forKey: movementAlertIsTriggeredUDKeyPrefix + uuid) @@ -412,54 +419,55 @@ class AlertPersistenceUserDefaults: AlertPersistence { func triggered(for uuid: String, of type: AlertType) -> Bool? { switch type { case .temperature: - return prefs.bool(forKey: temperatureAlertIsTriggeredUDKeyPrefix + uuid) + prefs.bool(forKey: temperatureAlertIsTriggeredUDKeyPrefix + uuid) case .relativeHumidity: - return prefs.bool(forKey: relativeHumidityAlertIsTriggeredUDKeyPrefix + uuid) + prefs.bool(forKey: relativeHumidityAlertIsTriggeredUDKeyPrefix + uuid) case .humidity: - return prefs.bool(forKey: humidityAlertIsTriggeredUDKeyPrefix + uuid) + prefs.bool(forKey: humidityAlertIsTriggeredUDKeyPrefix + uuid) case .pressure: - return prefs.bool(forKey: pressureAlertIsTriggeredUDKeyPrefix + uuid) + prefs.bool(forKey: pressureAlertIsTriggeredUDKeyPrefix + uuid) case .signal: - return prefs.bool(forKey: signalAlertIsTriggeredUDKeyPrefix + uuid) + prefs.bool(forKey: signalAlertIsTriggeredUDKeyPrefix + uuid) case .cloudConnection: - return prefs.bool(forKey: cloudConnectionAlertIsTriggeredUDKeyPrefix + uuid) + prefs.bool(forKey: cloudConnectionAlertIsTriggeredUDKeyPrefix + uuid) case .movement: - return prefs.bool(forKey: movementAlertIsTriggeredUDKeyPrefix + uuid) + prefs.bool(forKey: movementAlertIsTriggeredUDKeyPrefix + uuid) case .connection: - return nil + nil } } func triggeredAt(for uuid: String, of type: AlertType) -> String? { switch type { case .temperature: - return prefs.string(forKey: temperatureAlertTriggeredAtUDKeyPrefix + uuid) + prefs.string(forKey: temperatureAlertTriggeredAtUDKeyPrefix + uuid) case .relativeHumidity: - return prefs.string(forKey: relativeHumidityAlertTriggeredAtUDKeyPrefix + uuid) + prefs.string(forKey: relativeHumidityAlertTriggeredAtUDKeyPrefix + uuid) case .humidity: - return prefs.string(forKey: humidityAlertTriggeredAtUDKeyPrefix + uuid) + prefs.string(forKey: humidityAlertTriggeredAtUDKeyPrefix + uuid) case .pressure: - return prefs.string(forKey: pressureAlertTriggeredAtUDKeyPrefix + uuid) + prefs.string(forKey: pressureAlertTriggeredAtUDKeyPrefix + uuid) case .signal: - return prefs.string(forKey: signalAlertTriggeredAtUDKeyPrefix + uuid) + prefs.string(forKey: signalAlertTriggeredAtUDKeyPrefix + uuid) case .cloudConnection: - return prefs.string(forKey: cloudConnectionAlertTriggeredAtUDKeyPrefix + uuid) + prefs.string(forKey: cloudConnectionAlertTriggeredAtUDKeyPrefix + uuid) case .movement: - return prefs.string(forKey: movementAlertTriggeredAtUDKeyPrefix + uuid) + prefs.string(forKey: movementAlertTriggeredAtUDKeyPrefix + uuid) case .connection: - return nil + nil } } } // MARK: - Temperature + extension AlertPersistenceUserDefaults { func lowerCelsius(for uuid: String) -> Double? { - return prefs.optionalDouble(forKey: temperatureLowerBoundUDKeyPrefix + uuid) + prefs.optionalDouble(forKey: temperatureLowerBoundUDKeyPrefix + uuid) } func upperCelsius(for uuid: String) -> Double? { - return prefs.optionalDouble(forKey: temperatureUpperBoundUDKeyPrefix + uuid) + prefs.optionalDouble(forKey: temperatureUpperBoundUDKeyPrefix + uuid) } func setLower(celsius: Double?, for uuid: String) { @@ -471,7 +479,7 @@ extension AlertPersistenceUserDefaults { } func temperatureDescription(for uuid: String) -> String? { - return prefs.string(forKey: temperatureAlertDescriptionUDKeyPrefix + uuid) + prefs.string(forKey: temperatureAlertDescriptionUDKeyPrefix + uuid) } func setTemperature(description: String?, for uuid: String) { @@ -480,9 +488,10 @@ extension AlertPersistenceUserDefaults { } // MARK: - Relative Humidity + extension AlertPersistenceUserDefaults { func lowerRelativeHumidity(for uuid: String) -> Double? { - return prefs.optionalDouble(forKey: relativeHumidityLowerBoundUDKeyPrefix + uuid) + prefs.optionalDouble(forKey: relativeHumidityLowerBoundUDKeyPrefix + uuid) } func setLower(relativeHumidity: Double?, for uuid: String) { @@ -490,7 +499,7 @@ extension AlertPersistenceUserDefaults { } func upperRelativeHumidity(for uuid: String) -> Double? { - return prefs.optionalDouble(forKey: relativeHumidityUpperBoundUDKeyPrefix + uuid) + prefs.optionalDouble(forKey: relativeHumidityUpperBoundUDKeyPrefix + uuid) } func setUpper(relativeHumidity: Double?, for uuid: String) { @@ -498,7 +507,7 @@ extension AlertPersistenceUserDefaults { } func relativeHumidityDescription(for uuid: String) -> String? { - return prefs.string(forKey: relativeHumidityAlertDescriptionUDKeyPrefix + uuid) + prefs.string(forKey: relativeHumidityAlertDescriptionUDKeyPrefix + uuid) } func setRelativeHumidity(description: String?, for uuid: String) { @@ -507,6 +516,7 @@ extension AlertPersistenceUserDefaults { } // MARK: - Humidity + extension AlertPersistenceUserDefaults { func lowerHumidity(for uuid: String) -> Humidity? { guard let data = prefs.data(forKey: humidityLowerBoundUDKeyPrefix + uuid) else { @@ -516,7 +526,7 @@ extension AlertPersistenceUserDefaults { } func setLower(humidity: Humidity?, for uuid: String) { - if let humidity = humidity { + if let humidity { prefs.set(KeyedArchiver.archive(object: humidity), forKey: humidityLowerBoundUDKeyPrefix + uuid) } else { prefs.set(nil, forKey: humidityLowerBoundUDKeyPrefix + uuid) @@ -531,7 +541,7 @@ extension AlertPersistenceUserDefaults { } func setUpper(humidity: Humidity?, for uuid: String) { - if let humidity = humidity { + if let humidity { prefs.set(KeyedArchiver.archive(object: humidity), forKey: humidityUpperBoundUDKeyPrefix + uuid) } else { prefs.set(nil, forKey: humidityUpperBoundUDKeyPrefix + uuid) @@ -539,7 +549,7 @@ extension AlertPersistenceUserDefaults { } func humidityDescription(for uuid: String) -> String? { - return prefs.string(forKey: humidityAlertDescriptionUDKeyPrefix + uuid) + prefs.string(forKey: humidityAlertDescriptionUDKeyPrefix + uuid) } func setHumidity(description: String?, for uuid: String) { @@ -548,9 +558,10 @@ extension AlertPersistenceUserDefaults { } // MARK: - Pressure + extension AlertPersistenceUserDefaults { func lowerPressure(for uuid: String) -> Double? { - return prefs.optionalDouble(forKey: pressureLowerBoundUDKeyPrefix + uuid) + prefs.optionalDouble(forKey: pressureLowerBoundUDKeyPrefix + uuid) } func setLower(pressure: Double?, for uuid: String) { @@ -558,7 +569,7 @@ extension AlertPersistenceUserDefaults { } func upperPressure(for uuid: String) -> Double? { - return prefs.optionalDouble(forKey: pressureUpperBoundUDKeyPrefix + uuid) + prefs.optionalDouble(forKey: pressureUpperBoundUDKeyPrefix + uuid) } func setUpper(pressure: Double?, for uuid: String) { @@ -566,7 +577,7 @@ extension AlertPersistenceUserDefaults { } func pressureDescription(for uuid: String) -> String? { - return prefs.string(forKey: pressureAlertDescriptionUDKeyPrefix + uuid) + prefs.string(forKey: pressureAlertDescriptionUDKeyPrefix + uuid) } func setPressure(description: String?, for uuid: String) { @@ -575,9 +586,10 @@ extension AlertPersistenceUserDefaults { } // MARK: - RSSI + extension AlertPersistenceUserDefaults { func lowerSignal(for uuid: String) -> Double? { - return prefs.optionalDouble(forKey: signalLowerBoundUDKeyPrefix + uuid) + prefs.optionalDouble(forKey: signalLowerBoundUDKeyPrefix + uuid) } func setLower(signal: Double?, for uuid: String) { @@ -585,7 +597,7 @@ extension AlertPersistenceUserDefaults { } func upperSignal(for uuid: String) -> Double? { - return prefs.optionalDouble(forKey: signalUpperBoundUDKeyPrefix + uuid) + prefs.optionalDouble(forKey: signalUpperBoundUDKeyPrefix + uuid) } func setUpper(signal: Double?, for uuid: String) { @@ -593,7 +605,7 @@ extension AlertPersistenceUserDefaults { } func signalDescription(for uuid: String) -> String? { - return prefs.string(forKey: signalAlertDescriptionUDKeyPrefix + uuid) + prefs.string(forKey: signalAlertDescriptionUDKeyPrefix + uuid) } func setSignal(description: String?, for uuid: String) { @@ -602,9 +614,10 @@ extension AlertPersistenceUserDefaults { } // MARK: - Connection + extension AlertPersistenceUserDefaults { func connectionDescription(for uuid: String) -> String? { - return prefs.string(forKey: connectionAlertDescriptionUDKeyPrefix + uuid) + prefs.string(forKey: connectionAlertDescriptionUDKeyPrefix + uuid) } func setConnection(description: String?, for uuid: String) { @@ -613,9 +626,10 @@ extension AlertPersistenceUserDefaults { } // MARK: - Cloud Connection + extension AlertPersistenceUserDefaults { func cloudConnectionUnseenDuration(for uuid: String) -> Double? { - return prefs.optionalDouble(forKey: cloudConnectionAlertUnseenDurationUDPrefix + uuid) + prefs.optionalDouble(forKey: cloudConnectionAlertUnseenDurationUDPrefix + uuid) } func setCloudConnection(unseenDuration: Double?, for uuid: String) { @@ -623,7 +637,7 @@ extension AlertPersistenceUserDefaults { } func cloudConnectionDescription(for uuid: String) -> String? { - return prefs.string(forKey: cloudConnectionAlertDescriptionUDKeyPrefix + uuid) + prefs.string(forKey: cloudConnectionAlertDescriptionUDKeyPrefix + uuid) } func setCloudConnection(description: String?, for uuid: String) { @@ -632,9 +646,10 @@ extension AlertPersistenceUserDefaults { } // MARK: - Movement + extension AlertPersistenceUserDefaults { func movementCounter(for uuid: String) -> Int? { - return prefs.optionalInt(forKey: movementAlertCounterUDPrefix + uuid) + prefs.optionalInt(forKey: movementAlertCounterUDPrefix + uuid) } func setMovement(counter: Int?, for uuid: String) { @@ -642,11 +657,12 @@ extension AlertPersistenceUserDefaults { } func movementDescription(for uuid: String) -> String? { - return prefs.string(forKey: movementAlertDescriptionUDKeyPrefix + uuid) + prefs.string(forKey: movementAlertDescriptionUDKeyPrefix + uuid) } func setMovement(description: String?, for uuid: String) { prefs.set(description, forKey: movementAlertDescriptionUDKeyPrefix + uuid) } } + // swiftlint:enable file_length type_body_length diff --git a/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/KeyedArchiver.swift b/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/KeyedArchiver.swift index 837f83501..0706b7031 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/KeyedArchiver.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/KeyedArchiver.swift @@ -1,15 +1,15 @@ import Foundation -struct KeyedArchiver { +enum KeyedArchiver { static func archive(object: Any) -> Data? { if #available(iOS 12.0, *) { - return try? NSKeyedArchiver.archivedData(withRootObject: object, requiringSecureCoding: false) + try? NSKeyedArchiver.archivedData(withRootObject: object, requiringSecureCoding: false) } else { - return NSKeyedArchiver.archivedData(withRootObject: object) + NSKeyedArchiver.archivedData(withRootObject: object) } } - static func unarchive(_ data: Data, with type: T.Type) -> T? { + static func unarchive(_ data: Data, with _: T.Type) -> T? { if #available(iOS 12.0, *) { return try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? T } else { diff --git a/Packages/RuuviService/Sources/RuuviServiceAlert/RuuviServiceAlertImpl.swift b/Packages/RuuviService/Sources/RuuviServiceAlert/RuuviServiceAlertImpl.swift index 0d90c8dec..a2fa95419 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAlert/RuuviServiceAlertImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAlert/RuuviServiceAlertImpl.swift @@ -1,19 +1,20 @@ // swiftlint:disable file_length import Foundation import Future -import RuuviOntology import RuuviCloud import RuuviLocal +import RuuviOntology import RuuviService // MARK: - RuuviTag -extension RuuviServiceAlertImpl { + +public extension RuuviServiceAlertImpl { // swiftlint:disable:next function_body_length - public func register(type: AlertType, ruuviTag: RuuviTagSensor) { + func register(type: AlertType, ruuviTag: RuuviTagSensor) { register(type: type, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { switch type { - case .temperature(let lower, let upper): + case let .temperature(lower, upper): cloud.setAlert( type: .temperature, settingType: .state, @@ -25,7 +26,7 @@ extension RuuviServiceAlertImpl { description: temperatureDescription(for: ruuviTag), for: macId ) - case .relativeHumidity(let lower, let upper): + case let .relativeHumidity(lower, upper): cloud.setAlert( type: .humidity, settingType: .state, @@ -39,7 +40,7 @@ extension RuuviServiceAlertImpl { ) case .humidity: break // absolute is not on cloud yet (11.06.2021) - case .pressure(let lower, let upper): + case let .pressure(lower, upper): cloud.setAlert( type: .pressure, settingType: .state, @@ -51,7 +52,7 @@ extension RuuviServiceAlertImpl { description: pressureDescription(for: ruuviTag), for: macId ) - case .signal(let lower, let upper): + case let .signal(lower, upper): cloud.setAlert( type: .signal, settingType: .state, @@ -65,7 +66,7 @@ extension RuuviServiceAlertImpl { ) case .connection: break - case .cloudConnection(let unseenDuration): + case let .cloudConnection(unseenDuration): cloud.setAlert( type: .offline, settingType: .state, @@ -77,7 +78,7 @@ extension RuuviServiceAlertImpl { description: cloudConnectionDescription(for: ruuviTag), for: macId ) - case .movement(let last): + case let .movement(last): cloud.setAlert( type: .movement, settingType: .state, @@ -94,11 +95,11 @@ extension RuuviServiceAlertImpl { } // swiftlint:disable:next function_body_length - public func unregister(type: AlertType, ruuviTag: RuuviTagSensor) { + func unregister(type: AlertType, ruuviTag: RuuviTagSensor) { unregister(type: type, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { switch type { - case .temperature(let lower, let upper): + case let .temperature(lower, upper): cloud.setAlert( type: .temperature, settingType: .state, @@ -110,7 +111,7 @@ extension RuuviServiceAlertImpl { description: temperatureDescription(for: ruuviTag), for: macId ) - case .relativeHumidity(let lower, let upper): + case let .relativeHumidity(lower, upper): cloud.setAlert( type: .humidity, settingType: .state, @@ -124,7 +125,7 @@ extension RuuviServiceAlertImpl { ) case .humidity: break // absolute is not on cloud yet (11.06.2021) - case .pressure(let lower, let upper): + case let .pressure(lower, upper): cloud.setAlert( type: .pressure, settingType: .state, @@ -136,7 +137,7 @@ extension RuuviServiceAlertImpl { description: pressureDescription(for: ruuviTag), for: macId ) - case .signal(let lower, let upper): + case let .signal(lower, upper): cloud.setAlert( type: .signal, settingType: .state, @@ -150,7 +151,7 @@ extension RuuviServiceAlertImpl { ) case .connection: break - case .cloudConnection(let unseenDuration): + case let .cloudConnection(unseenDuration): cloud.setAlert( type: .offline, settingType: .state, @@ -162,7 +163,7 @@ extension RuuviServiceAlertImpl { description: cloudConnectionDescription(for: ruuviTag), for: macId ) - case .movement(let last): + case let .movement(last): cloud.setAlert( type: .movement, settingType: .state, @@ -178,7 +179,7 @@ extension RuuviServiceAlertImpl { } } - public func setLower(celsius: Double?, ruuviTag: RuuviTagSensor) { + func setLower(celsius: Double?, ruuviTag: RuuviTagSensor) { setLower(celsius: celsius, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { cloud.setAlert( @@ -195,7 +196,7 @@ extension RuuviServiceAlertImpl { } } - public func setUpper(celsius: Double?, ruuviTag: RuuviTagSensor) { + func setUpper(celsius: Double?, ruuviTag: RuuviTagSensor) { setUpper(celsius: celsius, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { cloud.setAlert( @@ -212,7 +213,7 @@ extension RuuviServiceAlertImpl { } } - public func setTemperature(description: String?, ruuviTag: RuuviTagSensor) { + func setTemperature(description: String?, ruuviTag: RuuviTagSensor) { setTemperature(description: description, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { cloud.setAlert( @@ -229,7 +230,7 @@ extension RuuviServiceAlertImpl { } } - public func setLower(relativeHumidity: Double?, ruuviTag: RuuviTagSensor) { + func setLower(relativeHumidity: Double?, ruuviTag: RuuviTagSensor) { setLower(relativeHumidity: relativeHumidity, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { cloud.setAlert( @@ -246,7 +247,7 @@ extension RuuviServiceAlertImpl { } } - public func setUpper(relativeHumidity: Double?, ruuviTag: RuuviTagSensor) { + func setUpper(relativeHumidity: Double?, ruuviTag: RuuviTagSensor) { setUpper(relativeHumidity: relativeHumidity, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { cloud.setAlert( @@ -263,7 +264,7 @@ extension RuuviServiceAlertImpl { } } - public func setRelativeHumidity(description: String?, ruuviTag: RuuviTagSensor) { + func setRelativeHumidity(description: String?, ruuviTag: RuuviTagSensor) { setRelativeHumidity(description: description, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { cloud.setAlert( @@ -280,7 +281,7 @@ extension RuuviServiceAlertImpl { } } - public func setLower(pressure: Double?, ruuviTag: RuuviTagSensor) { + func setLower(pressure: Double?, ruuviTag: RuuviTagSensor) { setLower(pressure: pressure, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { cloud.setAlert( @@ -297,7 +298,7 @@ extension RuuviServiceAlertImpl { } } - public func setUpper(pressure: Double?, ruuviTag: RuuviTagSensor) { + func setUpper(pressure: Double?, ruuviTag: RuuviTagSensor) { setUpper(pressure: pressure, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { cloud.setAlert( @@ -314,7 +315,7 @@ extension RuuviServiceAlertImpl { } } - public func setPressure(description: String?, ruuviTag: RuuviTagSensor) { + func setPressure(description: String?, ruuviTag: RuuviTagSensor) { setPressure(description: description, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { cloud.setAlert( @@ -331,7 +332,7 @@ extension RuuviServiceAlertImpl { } } - public func setLower(signal: Double?, ruuviTag: RuuviTagSensor) { + func setLower(signal: Double?, ruuviTag: RuuviTagSensor) { setLower(signal: signal, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { cloud.setAlert( @@ -339,8 +340,8 @@ extension RuuviServiceAlertImpl { settingType: .lowerBound, isEnabled: isOn(type: .signal(lower: 0, upper: 0), for: ruuviTag), - min: (signal ?? 0), - max: (upperSignal(for: ruuviTag) ?? 0), + min: signal ?? 0, + max: upperSignal(for: ruuviTag) ?? 0, counter: nil, delay: nil, description: signalDescription(for: ruuviTag), @@ -349,7 +350,7 @@ extension RuuviServiceAlertImpl { } } - public func setUpper(signal: Double?, ruuviTag: RuuviTagSensor) { + func setUpper(signal: Double?, ruuviTag: RuuviTagSensor) { setUpper(signal: signal, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { cloud.setAlert( @@ -357,8 +358,8 @@ extension RuuviServiceAlertImpl { settingType: .upperBound, isEnabled: isOn(type: .signal(lower: 0, upper: 0), for: ruuviTag), - min: (lowerSignal(for: ruuviTag) ?? 0), - max: (signal ?? 0), + min: lowerSignal(for: ruuviTag) ?? 0, + max: signal ?? 0, counter: nil, delay: nil, description: signalDescription(for: ruuviTag), @@ -367,7 +368,7 @@ extension RuuviServiceAlertImpl { } } - public func setSignal(description: String?, ruuviTag: RuuviTagSensor) { + func setSignal(description: String?, ruuviTag: RuuviTagSensor) { setSignal(description: description, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { cloud.setAlert( @@ -375,8 +376,8 @@ extension RuuviServiceAlertImpl { settingType: .description, isEnabled: isOn(type: .signal(lower: 0, upper: 0), for: ruuviTag), - min: (lowerSignal(for: ruuviTag) ?? 0), - max: (upperSignal(for: ruuviTag) ?? 0), + min: lowerSignal(for: ruuviTag) ?? 0, + max: upperSignal(for: ruuviTag) ?? 0, counter: nil, delay: nil, description: description, @@ -385,7 +386,7 @@ extension RuuviServiceAlertImpl { } } - public func setMovement(description: String?, ruuviTag: RuuviTagSensor) { + func setMovement(description: String?, ruuviTag: RuuviTagSensor) { setMovement(description: description, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { cloud.setAlert( @@ -402,7 +403,7 @@ extension RuuviServiceAlertImpl { } } - public func setCloudConnection(unseenDuration: Double?, ruuviTag: RuuviTagSensor) { + func setCloudConnection(unseenDuration: Double?, ruuviTag: RuuviTagSensor) { setCloudConnection(unseenDuration: unseenDuration, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { cloud.setAlert( @@ -419,7 +420,7 @@ extension RuuviServiceAlertImpl { } } - public func setCloudConnection(description: String?, ruuviTag: RuuviTagSensor) { + func setCloudConnection(description: String?, ruuviTag: RuuviTagSensor) { setCloudConnection(description: description, for: ruuviTag) if ruuviTag.isCloud, let macId = ruuviTag.macId { cloud.setAlert( @@ -449,7 +450,7 @@ public final class RuuviServiceAlertImpl: RuuviServiceAlert { ) { self.cloud = cloud self.localIDs = localIDs - self.alertPersistence = AlertPersistenceUserDefaults() + alertPersistence = AlertPersistenceUserDefaults() } // RuuviCloudAlert @@ -498,7 +499,7 @@ public final class RuuviServiceAlertImpl: RuuviServiceAlert { default: break } - if let type = type { + if let type { if let enabled = cloudAlert.enabled, enabled { register(type: type, for: physicalSensor) trigger( @@ -517,11 +518,11 @@ public final class RuuviServiceAlertImpl: RuuviServiceAlert { // Physical Sensor public func hasRegistrations(for sensor: PhysicalSensor) -> Bool { - return AlertType.allCases.contains(where: { isOn(type: $0, for: sensor) }) + AlertType.allCases.contains(where: { isOn(type: $0, for: sensor) }) } public func isOn(type: AlertType, for sensor: PhysicalSensor) -> Bool { - return alert(for: sensor, of: type) != nil + alert(for: sensor, of: type) != nil } public func alert(for sensor: PhysicalSensor, of type: AlertType) -> AlertType? { @@ -696,15 +697,15 @@ public final class RuuviServiceAlertImpl: RuuviServiceAlert { // UUID func hasRegistrations(for uuid: String) -> Bool { - return AlertType.allCases.contains(where: { isOn(type: $0, for: uuid) }) + AlertType.allCases.contains(where: { isOn(type: $0, for: uuid) }) } public func isOn(type: AlertType, for uuid: String) -> Bool { - return alert(for: uuid, of: type) != nil + alert(for: uuid, of: type) != nil } public func alert(for uuid: String, of type: AlertType) -> AlertType? { - return alertPersistence.alert(for: uuid, of: type) + alertPersistence.alert(for: uuid, of: type) } public func mutedTill(type: AlertType, for uuid: String) -> Date? { @@ -719,7 +720,7 @@ public final class RuuviServiceAlertImpl: RuuviServiceAlert { object: nil, userInfo: [ RuuviServiceAlertDidChangeKey.physicalSensor: sensor, - RuuviServiceAlertDidChangeKey.type: type + RuuviServiceAlertDidChangeKey.type: type, ] ) } @@ -732,15 +733,16 @@ public final class RuuviServiceAlertImpl: RuuviServiceAlert { object: nil, userInfo: [ RuuviServiceAlertDidChangeKey.physicalSensor: sensor, - RuuviServiceAlertDidChangeKey.type: type + RuuviServiceAlertDidChangeKey.type: type, ] ) } } // MARK: - Temperature -extension RuuviServiceAlertImpl { - public func lowerCelsius(for sensor: PhysicalSensor) -> Double? { + +public extension RuuviServiceAlertImpl { + func lowerCelsius(for sensor: PhysicalSensor) -> Double? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.lowerCelsius(for: luid.value) ?? alertPersistence.lowerCelsius(for: macId.value) @@ -754,7 +756,7 @@ extension RuuviServiceAlertImpl { } } - public func setLower(celsius: Double?, for sensor: PhysicalSensor) { + func setLower(celsius: Double?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setLower(celsius: celsius, for: luid.value) alertPersistence.setLower(celsius: celsius, for: macId.value) @@ -771,7 +773,7 @@ extension RuuviServiceAlertImpl { } } - public func upperCelsius(for sensor: PhysicalSensor) -> Double? { + func upperCelsius(for sensor: PhysicalSensor) -> Double? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.upperCelsius(for: luid.value) ?? alertPersistence.upperCelsius(for: macId.value) @@ -785,7 +787,7 @@ extension RuuviServiceAlertImpl { } } - public func setUpper(celsius: Double?, for sensor: PhysicalSensor) { + func setUpper(celsius: Double?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setUpper(celsius: celsius, for: luid.value) alertPersistence.setUpper(celsius: celsius, for: macId.value) @@ -802,7 +804,7 @@ extension RuuviServiceAlertImpl { } } - public func temperatureDescription(for sensor: PhysicalSensor) -> String? { + func temperatureDescription(for sensor: PhysicalSensor) -> String? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.temperatureDescription(for: luid.value) ?? alertPersistence.temperatureDescription(for: macId.value) @@ -816,7 +818,7 @@ extension RuuviServiceAlertImpl { } } - public func setTemperature(description: String?, for sensor: PhysicalSensor) { + func setTemperature(description: String?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setTemperature(description: description, for: luid.value) alertPersistence.setTemperature(description: description, for: macId.value) @@ -833,22 +835,23 @@ extension RuuviServiceAlertImpl { } } - public func lowerCelsius(for uuid: String) -> Double? { - return alertPersistence.lowerCelsius(for: uuid) + func lowerCelsius(for uuid: String) -> Double? { + alertPersistence.lowerCelsius(for: uuid) } - public func upperCelsius(for uuid: String) -> Double? { - return alertPersistence.upperCelsius(for: uuid) + func upperCelsius(for uuid: String) -> Double? { + alertPersistence.upperCelsius(for: uuid) } - public func temperatureDescription(for uuid: String) -> String? { - return alertPersistence.temperatureDescription(for: uuid) + func temperatureDescription(for uuid: String) -> String? { + alertPersistence.temperatureDescription(for: uuid) } } // MARK: - Relative Humidity -extension RuuviServiceAlertImpl { - public func lowerRelativeHumidity(for sensor: PhysicalSensor) -> Double? { + +public extension RuuviServiceAlertImpl { + func lowerRelativeHumidity(for sensor: PhysicalSensor) -> Double? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.lowerRelativeHumidity(for: luid.value) ?? alertPersistence.lowerRelativeHumidity(for: macId.value) @@ -862,7 +865,7 @@ extension RuuviServiceAlertImpl { } } - public func setLower(relativeHumidity: Double?, for sensor: PhysicalSensor) { + func setLower(relativeHumidity: Double?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setLower(relativeHumidity: relativeHumidity, for: luid.value) alertPersistence.setLower(relativeHumidity: relativeHumidity, for: macId.value) @@ -878,7 +881,7 @@ extension RuuviServiceAlertImpl { } } - public func upperRelativeHumidity(for sensor: PhysicalSensor) -> Double? { + func upperRelativeHumidity(for sensor: PhysicalSensor) -> Double? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.upperRelativeHumidity(for: luid.value) ?? alertPersistence.upperRelativeHumidity(for: macId.value) @@ -892,7 +895,7 @@ extension RuuviServiceAlertImpl { } } - public func setUpper(relativeHumidity: Double?, for sensor: PhysicalSensor) { + func setUpper(relativeHumidity: Double?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setUpper(relativeHumidity: relativeHumidity, for: luid.value) alertPersistence.setUpper(relativeHumidity: relativeHumidity, for: macId.value) @@ -908,7 +911,7 @@ extension RuuviServiceAlertImpl { } } - public func relativeHumidityDescription(for sensor: PhysicalSensor) -> String? { + func relativeHumidityDescription(for sensor: PhysicalSensor) -> String? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.relativeHumidityDescription(for: luid.value) ?? alertPersistence.relativeHumidityDescription(for: macId.value) @@ -922,7 +925,7 @@ extension RuuviServiceAlertImpl { } } - public func setRelativeHumidity(description: String?, for sensor: PhysicalSensor) { + func setRelativeHumidity(description: String?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setRelativeHumidity(description: description, for: luid.value) alertPersistence.setRelativeHumidity(description: description, for: macId.value) @@ -939,22 +942,23 @@ extension RuuviServiceAlertImpl { } } - public func lowerRelativeHumidity(for uuid: String) -> Double? { - return alertPersistence.lowerRelativeHumidity(for: uuid) + func lowerRelativeHumidity(for uuid: String) -> Double? { + alertPersistence.lowerRelativeHumidity(for: uuid) } - public func upperRelativeHumidity(for uuid: String) -> Double? { - return alertPersistence.upperRelativeHumidity(for: uuid) + func upperRelativeHumidity(for uuid: String) -> Double? { + alertPersistence.upperRelativeHumidity(for: uuid) } - public func relativeHumidityDescription(for uuid: String) -> String? { - return alertPersistence.relativeHumidityDescription(for: uuid) + func relativeHumidityDescription(for uuid: String) -> String? { + alertPersistence.relativeHumidityDescription(for: uuid) } } // MARK: - Humidity -extension RuuviServiceAlertImpl { - public func lowerHumidity(for sensor: PhysicalSensor) -> Humidity? { + +public extension RuuviServiceAlertImpl { + func lowerHumidity(for sensor: PhysicalSensor) -> Humidity? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.lowerHumidity(for: luid.value) ?? alertPersistence.lowerHumidity(for: macId.value) @@ -968,7 +972,7 @@ extension RuuviServiceAlertImpl { } } - public func setLower(humidity: Humidity?, for sensor: PhysicalSensor) { + func setLower(humidity: Humidity?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setLower(humidity: humidity, for: luid.value) alertPersistence.setLower(humidity: humidity, for: macId.value) @@ -984,7 +988,7 @@ extension RuuviServiceAlertImpl { } } - public func upperHumidity(for sensor: PhysicalSensor) -> Humidity? { + func upperHumidity(for sensor: PhysicalSensor) -> Humidity? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.upperHumidity(for: luid.value) ?? alertPersistence.upperHumidity(for: macId.value) @@ -998,7 +1002,7 @@ extension RuuviServiceAlertImpl { } } - public func setUpper(humidity: Humidity?, for sensor: PhysicalSensor) { + func setUpper(humidity: Humidity?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setUpper(humidity: humidity, for: luid.value) alertPersistence.setUpper(humidity: humidity, for: macId.value) @@ -1014,7 +1018,7 @@ extension RuuviServiceAlertImpl { } } - public func humidityDescription(for sensor: PhysicalSensor) -> String? { + func humidityDescription(for sensor: PhysicalSensor) -> String? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.humidityDescription(for: luid.value) ?? alertPersistence.humidityDescription(for: macId.value) @@ -1028,7 +1032,7 @@ extension RuuviServiceAlertImpl { } } - public func setHumidity(description: String?, for sensor: PhysicalSensor) { + func setHumidity(description: String?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setHumidity(description: description, for: luid.value) alertPersistence.setHumidity(description: description, for: macId.value) @@ -1041,27 +1045,29 @@ extension RuuviServiceAlertImpl { } if let l = lowerHumidity(for: sensor), - let u = upperHumidity(for: sensor) { + let u = upperHumidity(for: sensor) + { postAlertDidChange(with: sensor, of: .humidity(lower: l, upper: u)) } } - public func lowerHumidity(for uuid: String) -> Humidity? { - return alertPersistence.lowerHumidity(for: uuid) + func lowerHumidity(for uuid: String) -> Humidity? { + alertPersistence.lowerHumidity(for: uuid) } - public func upperHumidity(for uuid: String) -> Humidity? { - return alertPersistence.upperHumidity(for: uuid) + func upperHumidity(for uuid: String) -> Humidity? { + alertPersistence.upperHumidity(for: uuid) } - public func humidityDescription(for uuid: String) -> String? { - return alertPersistence.humidityDescription(for: uuid) + func humidityDescription(for uuid: String) -> String? { + alertPersistence.humidityDescription(for: uuid) } } // MARK: - Pressure -extension RuuviServiceAlertImpl { - public func lowerPressure(for sensor: PhysicalSensor) -> Double? { + +public extension RuuviServiceAlertImpl { + func lowerPressure(for sensor: PhysicalSensor) -> Double? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.lowerPressure(for: luid.value) ?? alertPersistence.lowerPressure(for: macId.value) @@ -1075,7 +1081,7 @@ extension RuuviServiceAlertImpl { } } - public func setLower(pressure: Double?, for sensor: PhysicalSensor) { + func setLower(pressure: Double?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setLower(pressure: pressure, for: luid.value) alertPersistence.setLower(pressure: pressure, for: macId.value) @@ -1092,7 +1098,7 @@ extension RuuviServiceAlertImpl { } } - public func upperPressure(for sensor: PhysicalSensor) -> Double? { + func upperPressure(for sensor: PhysicalSensor) -> Double? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.upperPressure(for: luid.value) ?? alertPersistence.upperPressure(for: macId.value) @@ -1106,7 +1112,7 @@ extension RuuviServiceAlertImpl { } } - public func setUpper(pressure: Double?, for sensor: PhysicalSensor) { + func setUpper(pressure: Double?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setUpper(pressure: pressure, for: luid.value) alertPersistence.setUpper(pressure: pressure, for: macId.value) @@ -1123,7 +1129,7 @@ extension RuuviServiceAlertImpl { } } - public func pressureDescription(for sensor: PhysicalSensor) -> String? { + func pressureDescription(for sensor: PhysicalSensor) -> String? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.pressureDescription(for: luid.value) ?? alertPersistence.pressureDescription(for: macId.value) @@ -1137,7 +1143,7 @@ extension RuuviServiceAlertImpl { } } - public func setPressure(description: String?, for sensor: PhysicalSensor) { + func setPressure(description: String?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setPressure(description: description, for: luid.value) alertPersistence.setPressure(description: description, for: macId.value) @@ -1154,22 +1160,23 @@ extension RuuviServiceAlertImpl { } } - public func lowerPressure(for uuid: String) -> Double? { - return alertPersistence.lowerPressure(for: uuid) + func lowerPressure(for uuid: String) -> Double? { + alertPersistence.lowerPressure(for: uuid) } - public func upperPressure(for uuid: String) -> Double? { - return alertPersistence.upperPressure(for: uuid) + func upperPressure(for uuid: String) -> Double? { + alertPersistence.upperPressure(for: uuid) } - public func pressureDescription(for uuid: String) -> String? { - return alertPersistence.pressureDescription(for: uuid) + func pressureDescription(for uuid: String) -> String? { + alertPersistence.pressureDescription(for: uuid) } } // MARK: - Signal -extension RuuviServiceAlertImpl { - public func lowerSignal(for sensor: PhysicalSensor) -> Double? { + +public extension RuuviServiceAlertImpl { + func lowerSignal(for sensor: PhysicalSensor) -> Double? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.lowerSignal(for: luid.value) ?? alertPersistence.lowerSignal(for: macId.value) @@ -1183,7 +1190,7 @@ extension RuuviServiceAlertImpl { } } - public func setLower(signal: Double?, for sensor: PhysicalSensor) { + func setLower(signal: Double?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setLower(signal: signal, for: luid.value) alertPersistence.setLower(signal: signal, for: macId.value) @@ -1200,7 +1207,7 @@ extension RuuviServiceAlertImpl { } } - public func upperSignal(for sensor: PhysicalSensor) -> Double? { + func upperSignal(for sensor: PhysicalSensor) -> Double? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.upperSignal(for: luid.value) ?? alertPersistence.upperSignal(for: macId.value) @@ -1214,7 +1221,7 @@ extension RuuviServiceAlertImpl { } } - public func setUpper(signal: Double?, for sensor: PhysicalSensor) { + func setUpper(signal: Double?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setUpper(signal: signal, for: luid.value) alertPersistence.setUpper(signal: signal, for: macId.value) @@ -1231,7 +1238,7 @@ extension RuuviServiceAlertImpl { } } - public func signalDescription(for sensor: PhysicalSensor) -> String? { + func signalDescription(for sensor: PhysicalSensor) -> String? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.signalDescription(for: luid.value) ?? alertPersistence.signalDescription(for: macId.value) @@ -1245,7 +1252,7 @@ extension RuuviServiceAlertImpl { } } - public func setSignal(description: String?, for sensor: PhysicalSensor) { + func setSignal(description: String?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setSignal(description: description, for: luid.value) alertPersistence.setSignal(description: description, for: macId.value) @@ -1262,22 +1269,23 @@ extension RuuviServiceAlertImpl { } } - public func lowerSignal(for uuid: String) -> Double? { - return alertPersistence.lowerSignal(for: uuid) + func lowerSignal(for uuid: String) -> Double? { + alertPersistence.lowerSignal(for: uuid) } - public func upperSignal(for uuid: String) -> Double? { - return alertPersistence.upperSignal(for: uuid) + func upperSignal(for uuid: String) -> Double? { + alertPersistence.upperSignal(for: uuid) } - public func signalDescription(for uuid: String) -> String? { - return signalDescription(for: uuid) + func signalDescription(for uuid: String) -> String? { + signalDescription(for: uuid) } } // MARK: - Connection -extension RuuviServiceAlertImpl { - public func connectionDescription(for sensor: PhysicalSensor) -> String? { + +public extension RuuviServiceAlertImpl { + func connectionDescription(for sensor: PhysicalSensor) -> String? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.connectionDescription(for: luid.value) ?? alertPersistence.connectionDescription(for: macId.value) @@ -1291,7 +1299,7 @@ extension RuuviServiceAlertImpl { } } - public func setConnection(description: String?, for sensor: PhysicalSensor) { + func setConnection(description: String?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setConnection(description: description, for: luid.value) alertPersistence.setConnection(description: description, for: macId.value) @@ -1305,14 +1313,15 @@ extension RuuviServiceAlertImpl { postAlertDidChange(with: sensor, of: .connection) } - public func connectionDescription(for uuid: String) -> String? { - return alertPersistence.connectionDescription(for: uuid) + func connectionDescription(for uuid: String) -> String? { + alertPersistence.connectionDescription(for: uuid) } } // MARK: - Cloud Connection -extension RuuviServiceAlertImpl { - public func cloudConnectionDescription(for sensor: PhysicalSensor) -> String? { + +public extension RuuviServiceAlertImpl { + func cloudConnectionDescription(for sensor: PhysicalSensor) -> String? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.cloudConnectionDescription(for: luid.value) ?? alertPersistence.cloudConnectionDescription(for: macId.value) @@ -1326,7 +1335,7 @@ extension RuuviServiceAlertImpl { } } - public func setCloudConnection(description: String?, for sensor: PhysicalSensor) { + func setCloudConnection(description: String?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setCloudConnection(description: description, for: luid.value) alertPersistence.setCloudConnection(description: description, for: macId.value) @@ -1339,7 +1348,7 @@ extension RuuviServiceAlertImpl { } } - public func setCloudConnection(unseenDuration: Double?, for sensor: PhysicalSensor) { + func setCloudConnection(unseenDuration: Double?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setCloudConnection(unseenDuration: unseenDuration, for: luid.value) alertPersistence.setCloudConnection(unseenDuration: unseenDuration, for: macId.value) @@ -1350,12 +1359,12 @@ extension RuuviServiceAlertImpl { } else { assertionFailure() } - if let unseenDuration = unseenDuration { + if let unseenDuration { postAlertDidChange(with: sensor, of: .cloudConnection(unseenDuration: unseenDuration)) } } - public func cloudConnectionUnseenDuration(for sensor: PhysicalSensor) -> Double? { + func cloudConnectionUnseenDuration(for sensor: PhysicalSensor) -> Double? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.cloudConnectionUnseenDuration(for: luid.value) ?? alertPersistence.cloudConnectionUnseenDuration(for: macId.value) @@ -1371,8 +1380,9 @@ extension RuuviServiceAlertImpl { } // MARK: - Movement -extension RuuviServiceAlertImpl { - public func movementCounter(for sensor: PhysicalSensor) -> Int? { + +public extension RuuviServiceAlertImpl { + func movementCounter(for sensor: PhysicalSensor) -> Int? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.movementCounter(for: luid.value) ?? alertPersistence.movementCounter(for: macId.value) @@ -1386,7 +1396,7 @@ extension RuuviServiceAlertImpl { } } - public func setMovement(counter: Int?, for sensor: PhysicalSensor) { + func setMovement(counter: Int?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setMovement(counter: counter, for: luid.value) alertPersistence.setMovement(counter: counter, for: macId.value) @@ -1400,7 +1410,7 @@ extension RuuviServiceAlertImpl { // no need to post an update, this is not user initiated action } - public func movementDescription(for sensor: PhysicalSensor) -> String? { + func movementDescription(for sensor: PhysicalSensor) -> String? { if let luid = sensor.luid, let macId = sensor.macId { return alertPersistence.movementDescription(for: luid.value) ?? alertPersistence.movementDescription(for: macId.value) @@ -1414,7 +1424,7 @@ extension RuuviServiceAlertImpl { } } - public func setMovement(description: String?, for sensor: PhysicalSensor) { + func setMovement(description: String?, for sensor: PhysicalSensor) { if let luid = sensor.luid, let macId = sensor.macId { alertPersistence.setMovement(description: description, for: luid.value) alertPersistence.setMovement(description: description, for: macId.value) @@ -1431,17 +1441,18 @@ extension RuuviServiceAlertImpl { } } - public func movementCounter(for uuid: String) -> Int? { - return alertPersistence.movementCounter(for: uuid) + func movementCounter(for uuid: String) -> Int? { + alertPersistence.movementCounter(for: uuid) } - public func setMovement(counter: Int?, for uuid: String) { + func setMovement(counter: Int?, for uuid: String) { alertPersistence.setMovement(counter: counter, for: uuid) // no need to post an update, this is not user initiated action } - public func movementDescription(for uuid: String) -> String? { - return alertPersistence.movementDescription(for: uuid) + func movementDescription(for uuid: String) -> String? { + alertPersistence.movementDescription(for: uuid) } } + // swiftlint:enable file_length diff --git a/Packages/RuuviService/Sources/RuuviServiceAppSettings/RuuviServiceAppSettingsImpl.swift b/Packages/RuuviService/Sources/RuuviServiceAppSettings/RuuviServiceAppSettingsImpl.swift index e192f19f8..852d676e3 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAppSettings/RuuviServiceAppSettingsImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAppSettings/RuuviServiceAppSettingsImpl.swift @@ -1,8 +1,8 @@ import Foundation import Future -import RuuviOntology import RuuviCloud import RuuviLocal +import RuuviOntology import RuuviService public final class RuuviServiceAppSettingsImpl: RuuviServiceAppSettings { @@ -187,15 +187,16 @@ public final class RuuviServiceAppSettingsImpl: RuuviServiceAppSettings { @discardableResult public func set(dashboardTapActionType: DashboardTapActionType) -> - Future { - let promise = Promise() - cloud.set(dashboardTapActionType: dashboardTapActionType) - .on(success: { type in - promise.succeed(value: type) - }, failure: { error in - promise.fail(error: .ruuviCloud(error)) - }) - return promise.future + Future + { + let promise = Promise() + cloud.set(dashboardTapActionType: dashboardTapActionType) + .on(success: { type in + promise.succeed(value: type) + }, failure: { error in + promise.fail(error: .ruuviCloud(error)) + }) + return promise.future } @discardableResult diff --git a/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift b/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift index f0b7d5a86..f963cb946 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift @@ -1,11 +1,11 @@ import Foundation import Future -import RuuviUser -import RuuviStorage -import RuuviPool import RuuviLocal import RuuviOntology +import RuuviPool import RuuviService +import RuuviStorage +import RuuviUser public final class RuuviServiceAuthImpl: RuuviServiceAuth { private let ruuviUser: RuuviUser @@ -44,7 +44,7 @@ public final class RuuviServiceAuthImpl: RuuviServiceAuth { promise.succeed(value: true) return } - localSensors.filter({ $0.isClaimed || $0.isCloud }).forEach { sensor in + localSensors.filter { $0.isClaimed || $0.isCloud }.forEach { sensor in let deleteSensorOperation = sSelf.pool.delete(sensor) let deleteRecordsOperation = sSelf.pool.deleteAllRecords(sensor.id) let deleteLatestRecordOperation = sSelf.pool.deleteLast(sensor.id) @@ -55,7 +55,7 @@ public final class RuuviServiceAuthImpl: RuuviServiceAuth { sSelf.localSyncState.setSyncDate(nil, for: sensor.macId) sSelf.localSyncState.setSyncDate(nil) sSelf.localSyncState.setGattSyncDate(nil, for: sensor.macId) - AlertType.allCases.forEach { (type) in + AlertType.allCases.forEach { type in sSelf.alertService.remove(type: type, ruuviTag: sensor) } diff --git a/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift b/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift index 41b2d8a6f..8033fa8b8 100644 --- a/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift @@ -1,19 +1,18 @@ import Foundation import Future -import RuuviOntology -import RuuviStorage import RuuviCloud -import RuuviPool +import RuuviCore import RuuviLocal +import RuuviOntology +import RuuviPool import RuuviService +import RuuviStorage import RuuviUser -import RuuviCore #if canImport(RuuviCloudApi) -import RuuviCloudApi + import RuuviCloudApi #endif public final class RuuviServiceCloudNotificationImpl: RuuviServiceCloudNotification { - private let cloud: RuuviCloud private let pool: RuuviPool private let storage: RuuviStorage @@ -39,16 +38,18 @@ public final class RuuviServiceCloudNotificationImpl: RuuviServiceCloudNotificat name: String?, data: String?, language: Language, - sound: RuuviAlertSound) -> Future { + sound: RuuviAlertSound) -> Future + { let promise = Promise() - guard ruuviUser.isAuthorized, let token = token else { + guard ruuviUser.isAuthorized, let token else { return promise.future } - var refreshable: Bool = false + var refreshable = false if let lastRefreshed = pnManager.fcmTokenLastRefreshed { if let daysFromNow = lastRefreshed.numberOfDaysFromNow(), - daysFromNow > 7 { + daysFromNow > 7 + { refreshable = true } } else { @@ -66,7 +67,7 @@ public final class RuuviServiceCloudNotificationImpl: RuuviServiceCloudNotificat data: data, params: [ RuuviCloudPNTokenRegisterRequestParamsKey.sound.rawValue: sound.rawValue, - RuuviCloudPNTokenRegisterRequestParamsKey.language.rawValue: language.rawValue + RuuviCloudPNTokenRegisterRequestParamsKey.language.rawValue: language.rawValue, ] ) .on(success: { [weak self] tokenId in @@ -83,7 +84,8 @@ public final class RuuviServiceCloudNotificationImpl: RuuviServiceCloudNotificat @discardableResult public func set(sound: RuuviAlertSound, language: Language, - deviceName: String?) -> Future { + deviceName: String?) -> Future + { let promise = Promise() guard ruuviUser.isAuthorized, let token = pnManager.fcmToken else { return promise.future @@ -96,7 +98,7 @@ public final class RuuviServiceCloudNotificationImpl: RuuviServiceCloudNotificat data: nil, params: [ RuuviCloudPNTokenRegisterRequestParamsKey.sound.rawValue: sound.rawValue, - RuuviCloudPNTokenRegisterRequestParamsKey.language.rawValue: language.rawValue + RuuviCloudPNTokenRegisterRequestParamsKey.language.rawValue: language.rawValue, ] ) .on(success: { [weak self] tokenId in @@ -115,32 +117,34 @@ public final class RuuviServiceCloudNotificationImpl: RuuviServiceCloudNotificat type: String, name: String?, data: String?, - params: [String: String]?) -> Future { + params: [String: String]?) -> Future + { let promise = Promise() cloud.registerPNToken(token: token, type: type, name: name, data: data, params: params) - .on(success: { tokenId in - promise.succeed(value: tokenId) - }, failure: { error in - promise.fail(error: .ruuviCloud(error)) - }) + .on(success: { tokenId in + promise.succeed(value: tokenId) + }, failure: { error in + promise.fail(error: .ruuviCloud(error)) + }) return promise.future } @discardableResult public func unregister(token: String?, - tokenId: Int?) -> Future { + tokenId: Int?) -> Future + { let promise = Promise() cloud.unregisterPNToken(token: token, tokenId: tokenId) - .on(success: { success in - promise.succeed(value: success) - }, failure: { error in - promise.fail(error: .ruuviCloud(error)) - }) + .on(success: { success in + promise.succeed(value: success) + }, failure: { error in + promise.fail(error: .ruuviCloud(error)) + }) return promise.future } @@ -148,11 +152,11 @@ public final class RuuviServiceCloudNotificationImpl: RuuviServiceCloudNotificat public func listTokens() -> Future<[RuuviCloudPNToken], RuuviServiceError> { let promise = Promise<[RuuviCloudPNToken], RuuviServiceError>() cloud.listPNTokens() - .on(success: { tokens in - promise.succeed(value: tokens) - }, failure: { error in - promise.fail(error: .ruuviCloud(error)) - }) + .on(success: { tokens in + promise.succeed(value: tokens) + }, failure: { error in + promise.fail(error: .ruuviCloud(error)) + }) return promise.future } } diff --git a/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift b/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift index f4090e181..d856e3dea 100644 --- a/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift @@ -1,13 +1,13 @@ import Foundation -import UIKit import Future -import RuuviOntology -import RuuviStorage import RuuviCloud -import RuuviPool import RuuviLocal +import RuuviOntology +import RuuviPool import RuuviRepository import RuuviService +import RuuviStorage +import UIKit // swiftlint:disable file_length // swiftlint:disable:next type_body_length public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { @@ -42,7 +42,7 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { self.ruuviLocalImages = ruuviLocalImages self.ruuviRepository = ruuviRepository self.ruuviLocalIDs = ruuviLocalIDs - self.alertService = ruuviAlertService + alertService = ruuviAlertService self.ruuviAppSettingsService = ruuviAppSettingsService } @@ -52,72 +52,88 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { let promise = Promise() ruuviCloud.getCloudSettings() .on(success: { [weak self] cloudSettings in - guard let cloudSettings = cloudSettings, let sSelf = self else { return } + guard let cloudSettings, let sSelf = self else { return } if let unitTemperature = cloudSettings.unitTemperature, - unitTemperature != sSelf.ruuviLocalSettings.temperatureUnit { + unitTemperature != sSelf.ruuviLocalSettings.temperatureUnit + { sSelf.ruuviLocalSettings.temperatureUnit = unitTemperature } if let accuracyTemperature = cloudSettings.accuracyTemperature, - accuracyTemperature != sSelf.ruuviLocalSettings.temperatureAccuracy { + accuracyTemperature != sSelf.ruuviLocalSettings.temperatureAccuracy + { sSelf.ruuviLocalSettings.temperatureAccuracy = accuracyTemperature } if let unitHumidity = cloudSettings.unitHumidity, - unitHumidity != sSelf.ruuviLocalSettings.humidityUnit { + unitHumidity != sSelf.ruuviLocalSettings.humidityUnit + { sSelf.ruuviLocalSettings.humidityUnit = unitHumidity } if let accuracyHumidity = cloudSettings.accuracyHumidity, - accuracyHumidity != sSelf.ruuviLocalSettings.humidityAccuracy { + accuracyHumidity != sSelf.ruuviLocalSettings.humidityAccuracy + { sSelf.ruuviLocalSettings.humidityAccuracy = accuracyHumidity } if let unitPressure = cloudSettings.unitPressure, - unitPressure != sSelf.ruuviLocalSettings.pressureUnit { + unitPressure != sSelf.ruuviLocalSettings.pressureUnit + { sSelf.ruuviLocalSettings.pressureUnit = unitPressure } if let accuracyPressure = cloudSettings.accuracyPressure, - accuracyPressure != sSelf.ruuviLocalSettings.pressureAccuracy { + accuracyPressure != sSelf.ruuviLocalSettings.pressureAccuracy + { sSelf.ruuviLocalSettings.pressureAccuracy = accuracyPressure } if let chartShowAllData = cloudSettings.chartShowAllPoints, - chartShowAllData != !sSelf.ruuviLocalSettings.chartDownsamplingOn { + chartShowAllData != !sSelf.ruuviLocalSettings.chartDownsamplingOn + { sSelf.ruuviLocalSettings.chartDownsamplingOn = !chartShowAllData } if let chartDrawDots = cloudSettings.chartDrawDots, - chartDrawDots != sSelf.ruuviLocalSettings.chartDrawDotsOn { + chartDrawDots != sSelf.ruuviLocalSettings.chartDrawDotsOn + { // Draw dots feature is disabled from v1.3.0 onwards to // maintain better performance until we find a better approach to do it. sSelf.ruuviLocalSettings.chartDrawDotsOn = false } if let chartShowMinMaxAvg = cloudSettings.chartShowMinMaxAvg, - chartShowMinMaxAvg != sSelf.ruuviLocalSettings.chartStatsOn { + chartShowMinMaxAvg != sSelf.ruuviLocalSettings.chartStatsOn + { sSelf.ruuviLocalSettings.chartStatsOn = chartShowMinMaxAvg } if let cloudModeEnabled = cloudSettings.cloudModeEnabled, - cloudModeEnabled != sSelf.ruuviLocalSettings.cloudModeEnabled { + cloudModeEnabled != sSelf.ruuviLocalSettings.cloudModeEnabled + { sSelf.ruuviLocalSettings.cloudModeEnabled = cloudModeEnabled } if let dashboardEnabled = cloudSettings.dashboardEnabled, - dashboardEnabled != sSelf.ruuviLocalSettings.dashboardEnabled { + dashboardEnabled != sSelf.ruuviLocalSettings.dashboardEnabled + { sSelf.ruuviLocalSettings.dashboardEnabled = dashboardEnabled } if let dashboardType = cloudSettings.dashboardType, - dashboardType != sSelf.ruuviLocalSettings.dashboardType { + dashboardType != sSelf.ruuviLocalSettings.dashboardType + { sSelf.ruuviLocalSettings.dashboardType = dashboardType } if let dashboardTapActionType = cloudSettings.dashboardTapActionType, - dashboardTapActionType != sSelf.ruuviLocalSettings.dashboardTapActionType { + dashboardTapActionType != sSelf.ruuviLocalSettings.dashboardTapActionType + { sSelf.ruuviLocalSettings.dashboardTapActionType = dashboardTapActionType } if let pushAlertEnabled = cloudSettings.pushAlertEnabled, - pushAlertEnabled != sSelf.ruuviLocalSettings.pushAlertEnabled { + pushAlertEnabled != sSelf.ruuviLocalSettings.pushAlertEnabled + { sSelf.ruuviLocalSettings.pushAlertEnabled = pushAlertEnabled } if let emailAlertEnabled = cloudSettings.emailAlertEnabled, - emailAlertEnabled != sSelf.ruuviLocalSettings.emailAlertEnabled { + emailAlertEnabled != sSelf.ruuviLocalSettings.emailAlertEnabled + { sSelf.ruuviLocalSettings.emailAlertEnabled = emailAlertEnabled } if let cloudProfileLanguageCode = cloudSettings.profileLanguageCode { if cloudProfileLanguageCode != - sSelf.ruuviLocalSettings.cloudProfileLanguageCode { + sSelf.ruuviLocalSettings.cloudProfileLanguageCode + { sSelf.ruuviLocalSettings.cloudProfileLanguageCode = cloudProfileLanguageCode } } else { @@ -145,9 +161,9 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { URLSession .shared .dataTask(with: pictureUrl, completionHandler: { data, _, error in - if let error = error { + if let error { promise.fail(error: .networking(error)) - } else if let data = data { + } else if let data { if let image = UIImage(data: data) { DispatchQueue.main.async { self.ruuviLocalImages @@ -213,7 +229,7 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { promise.succeed(value: true) }, failure: { [weak self] error in switch error { - case .ruuviCloud(let cloudError): + case let .ruuviCloud(cloudError): switch cloudError { case let .api(.unauthorized): self?.postNotification() @@ -234,9 +250,9 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { return promise.succeed(value: true) } - let queuedRequests = requests.flatMap({ request in + let queuedRequests = requests.flatMap { request in self?.syncQueuedRequest(request: request) - }) + } Future.zip(queuedRequests).on(completion: { promise.succeed(value: true) @@ -251,47 +267,50 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { ) -> [Future] { let temperatureSyncs: [Future] = cloudSensors.compactMap { cloudSensor in - if let updatedSensor = updatedSensors - .first(where: { $0.id == cloudSensor.id }) { - return self.ruuviPool.updateOffsetCorrection( - type: .temperature, - with: cloudSensor.offsetTemperature, - of: updatedSensor - ) - } else { - return nil + if let updatedSensor = updatedSensors + .first(where: { $0.id == cloudSensor.id }) + { + self.ruuviPool.updateOffsetCorrection( + type: .temperature, + with: cloudSensor.offsetTemperature, + of: updatedSensor + ) + } else { + nil + } } - } let humiditySyncs: [Future] = cloudSensors.compactMap { cloudSensor in if let updatedSensor = updatedSensors .first(where: { $0.id == cloudSensor.id }), - let offsetHumidity = cloudSensor.offsetHumidity { - return self.ruuviPool.updateOffsetCorrection( + let offsetHumidity = cloudSensor.offsetHumidity + { + self.ruuviPool.updateOffsetCorrection( type: .humidity, with: offsetHumidity / 100, of: updatedSensor ) } else { - return nil + nil } } let pressureSyncs: [Future] = cloudSensors.compactMap { cloudSensor in - if let updatedSensor = updatedSensors - .first(where: { $0.id == cloudSensor.id }), - let offsetPressure = cloudSensor.offsetPressure { - return self.ruuviPool.updateOffsetCorrection( - type: .pressure, - with: offsetPressure / 100, - of: updatedSensor - ) - } else { - return nil + if let updatedSensor = updatedSensors + .first(where: { $0.id == cloudSensor.id }), + let offsetPressure = cloudSensor.offsetPressure + { + self.ruuviPool.updateOffsetCorrection( + type: .pressure, + with: offsetPressure / 100, + of: updatedSensor + ) + } else { + nil + } } - } return temperatureSyncs + humiditySyncs + pressureSyncs } @@ -303,9 +322,10 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { let networkPuningDate = Date(timeIntervalSinceNow: networkPruningOffset) let lastSynDate = ruuviLocalSyncState.getSyncDate(for: sensor.macId) - var syncFullHistory: Bool = false + var syncFullHistory = false if let syncFull = ruuviLocalSyncState.downloadFullHistory(for: sensor.macId), - syncFull { + syncFull + { syncFullHistory = true } @@ -318,9 +338,9 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { for: sensor.macId ) promise.succeed(value: result) - }, failure: { error in + }, failure: { error in promise.fail(error: error) - }) + }) return promise.future } @@ -365,8 +385,8 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { guard let sSelf = self else { return } for sensor in localSensors { let skip = !sensor.isClaimed || - (sensor.isOwner && sensor.isClaimed && - !sSelf.ruuviLocalSettings.cloudModeEnabled) + (sensor.isOwner && sensor.isClaimed && + !sSelf.ruuviLocalSettings.cloudModeEnabled) if let macId = sensor.macId, !skip { sSelf.ruuviLocalSyncState.setSyncStatus(.syncing, for: macId) } @@ -388,14 +408,14 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { return } - let alerts = denseSensors.compactMap({ sensor in + let alerts = denseSensors.compactMap { sensor in sensor.alerts - }) + } sSelf.alertService.sync(cloudAlerts: alerts) - let cloudSensors = denseSensors.compactMap({ sensor in + let cloudSensors = denseSensors.compactMap { sensor in sensor.sensor.any - }) + } let sensors = sSelf.syncSensors(cloudSensors: cloudSensors) sensors.on(success: { updatedSensors in @@ -415,33 +435,33 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { // Store the latest measurement record date for the sensors without history // as the sync date. For the rest this value will be set after successful sync. - filteredDenseSensorsWithoutHistory.forEach({ [weak self] + filteredDenseSensorsWithoutHistory.forEach { [weak self] ruuviTag in - self?.ruuviLocalSyncState.setSyncDate( - ruuviTag.record?.date, - for: ruuviTag.sensor.ruuviTagSensor.macId - ) - }) + self?.ruuviLocalSyncState.setSyncDate( + ruuviTag.record?.date, + for: ruuviTag.sensor.ruuviTagSensor.macId + ) + } let updatedSensorsEligibleForHistory = updatedSensors.filter { updatedSensor in - return filteredDenseSensorsWithHistory.contains { denseSensor in + filteredDenseSensorsWithHistory.contains { denseSensor in denseSensor.sensor.any.id == updatedSensor.id } } - let syncHistory = updatedSensorsEligibleForHistory.map({ sSelf.sync(sensor: $0) }) - let syncLatestPoint = denseSensors.map({ + let syncHistory = updatedSensorsEligibleForHistory.map { sSelf.sync(sensor: $0) } + let syncLatestPoint = denseSensors.map { sSelf.updateLatestRecord( ruuviTag: $0.sensor.ruuviTagSensor, cloudRecord: $0.record ) - }) - let addLatestPointToHistory = denseSensors.map({ + } + let addLatestPointToHistory = denseSensors.map { sSelf.addLatestRecordToHistory( ruuviTag: $0.sensor.ruuviTagSensor, cloudRecord: $0.record ) - }) + } Future.zip(syncLatestPoint).on(success: { _ in Future.zip(addLatestPointToHistory).on(success: { _ in @@ -467,15 +487,16 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { var updatedSensors = Set() ruuviStorage.readAll().on(success: { localSensors in let updateSensors: [Future] = localSensors - .compactMap({ localSensor in - if let cloudSensor = cloudSensors.first(where: {$0.id == localSensor.id }) { + .compactMap { localSensor in + if let cloudSensor = cloudSensors.first(where: { $0.id == localSensor.id }) { updatedSensors.insert(localSensor) // Update the local sensor data with cloud data // if there's a match of sensor in local storage and cloud // TODO: @priyonto - Need to improve this once backend flattens and improves the plans // If user goes from free to pro or above plan, download full history - if localSensor.ownersPlan?.lowercased() == "free" && - localSensor.ownersPlan?.lowercased() != cloudSensor.ownersPlan?.lowercased() { + if localSensor.ownersPlan?.lowercased() == "free", + localSensor.ownersPlan?.lowercased() != cloudSensor.ownersPlan?.lowercased() + { self.ruuviLocalSyncState.setDownloadFullHistory(for: localSensor.macId, downloadFull: true) } @@ -501,7 +522,7 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { } } } - }) + } let createSensors: [Future] = cloudSensors .filter { cloudSensor in !localSensors.contains(where: { $0.id == cloudSensor.id }) @@ -512,8 +533,8 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { } let syncImages = cloudSensors - .filter({ !self.ruuviLocalImages.isPictureCached(for: $0) }) - .map({ self.syncImage(sensor: $0) }) + .filter { !self.ruuviLocalImages.isPictureCached(for: $0) } + .map { self.syncImage(sensor: $0) } Future.zip([Future.zip(createSensors), Future.zip(updateSensors)]) .on(success: { _ in @@ -544,9 +565,10 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { /// Otherwise it creates a new record. private func updateLatestRecord(ruuviTag: RuuviTagSensor, cloudRecord: RuuviTagSensorRecord?) - -> Future { + -> Future + { let promise = Promise() - guard let cloudRecord = cloudRecord else { + guard let cloudRecord else { // If there's no cloud record return // It is possible that a sensor doesn't have a record if it's a few years old ruuviLocalSyncState.setSyncStatus(.complete, for: ruuviTag.id.mac) @@ -557,8 +579,9 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { ruuviStorage.readLatest(ruuviTag).on(success: { [weak self] record in guard let sSelf = self else { return } // If the latest table already have a data point for the mac update that record - if let record = record, - record.macId?.value == cloudRecord.macId?.value { + if let record, + record.macId?.value == cloudRecord.macId?.value + { // Store cloud point only if the cloud data is newer than the local data let isMeasurementNew = cloudRecord.date > record.date if sSelf.ruuviLocalSettings.cloudModeEnabled || isMeasurementNew { @@ -594,9 +617,10 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { /// This method writes the latest data point to the history/records table private func addLatestRecordToHistory(ruuviTag: RuuviTagSensor, cloudRecord: RuuviTagSensorRecord?) - -> Future { + -> Future + { let promise = Promise() - guard let cloudRecord = cloudRecord else { + guard let cloudRecord else { // If there's no cloud record return // It is possible that a sensor doesn't have a record if it's a few years old promise.succeed(value: false) diff --git a/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncRecordsOperation.swift b/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncRecordsOperation.swift index 40c9fb7b8..88b2b84b9 100644 --- a/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncRecordsOperation.swift +++ b/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncRecordsOperation.swift @@ -1,8 +1,8 @@ import Foundation -import RuuviRepository import RuuviCloud import RuuviLocal import RuuviOntology +import RuuviRepository import RuuviService final class RuuviServiceCloudSyncRecordsOperation: AsyncOperation { @@ -20,9 +20,9 @@ final class RuuviServiceCloudSyncRecordsOperation: AsyncOperation { until: Date? = nil, ruuviCloud: RuuviCloud, ruuviRepository: RuuviRepository, - syncState: RuuviLocalSyncState, - ruuviLocalIDs: RuuviLocalIDs - ) { + syncState _: RuuviLocalSyncState, + ruuviLocalIDs: RuuviLocalIDs) + { self.sensor = sensor self.since = since self.until = until @@ -44,15 +44,16 @@ final class RuuviServiceCloudSyncRecordsOperation: AsyncOperation { sSelf.state = .finished return } - let recordsWithLuid: [AnyRuuviTagSensorRecord] = loadedRecords.map({ record in + let recordsWithLuid: [AnyRuuviTagSensorRecord] = loadedRecords.map { record in if record.luid == nil, let macId = record.macId, - let luid = sSelf.ruuviLocalIDs.luid(for: macId) { - return record.with(luid: luid).any + let luid = sSelf.ruuviLocalIDs.luid(for: macId) + { + record.with(luid: luid).any } else { - return record + record } - }) + } let persist = sSelf.ruuviRepository.create( records: recordsWithLuid, for: sSelf.sensor diff --git a/Packages/RuuviService/Sources/RuuviServiceExport/RuuviServiceExportImpl.swift b/Packages/RuuviService/Sources/RuuviServiceExport/RuuviServiceExportImpl.swift index 5357d67dd..db884708f 100644 --- a/Packages/RuuviService/Sources/RuuviServiceExport/RuuviServiceExportImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceExport/RuuviServiceExportImpl.swift @@ -1,10 +1,10 @@ import Foundation -import Humidity import Future +import Humidity +import RuuviLocal import RuuviOntology -import RuuviStorage import RuuviService -import RuuviLocal +import RuuviStorage public final class RuuviServiceExportImpl: RuuviServiceExport { private let ruuviStorage: RuuviStorage @@ -37,7 +37,7 @@ public final class RuuviServiceExportImpl: RuuviServiceExport { ruuviTag.on(success: { [weak self] ruuviTag in let recordsOperation = self?.ruuviStorage.readAll(uuid, after: networkPuningDate) recordsOperation?.on(success: { [weak self] records in - let offsetedLogs = records.compactMap({ $0.with(sensorSettings: settings)}) + let offsetedLogs = records.compactMap { $0.with(sensorSettings: settings) } self?.csvLog(for: ruuviTag, with: offsetedLogs).on(success: { url in promise.succeed(value: url) }, failure: { error in @@ -55,6 +55,7 @@ public final class RuuviServiceExportImpl: RuuviServiceExport { } // MARK: - Ruuvi Tag + extension RuuviServiceExportImpl { // swiftlint:disable:next function_body_length private func csvLog( @@ -109,11 +110,10 @@ extension RuuviServiceExportImpl { pressure = toString(p, format: "%.2f") } - var rssi: String - if let rssiValue = log.rssi { - rssi = "\(rssiValue)" + var rssi: String = if let rssiValue = log.rssi { + "\(rssiValue)" } else { - rssi = self.emptyValueString + self.emptyValueString } let accelerationX: String = toString(log.acceleration?.x.value, format: "%.3f") @@ -122,25 +122,22 @@ extension RuuviServiceExportImpl { let voltage: String = toString(log.voltage?.converted(to: .volts).value, format: "%.3f") - let movementCounter: String - if let mc = log.movementCounter { - movementCounter = "\(mc)" + let movementCounter: String = if let mc = log.movementCounter { + "\(mc)" } else { - movementCounter = self.emptyValueString + self.emptyValueString } - var measurementSequenceNumber: String - if let msn = log.measurementSequenceNumber { - measurementSequenceNumber = "\(msn)" + var measurementSequenceNumber: String = if let msn = log.measurementSequenceNumber { + "\(msn)" } else { - measurementSequenceNumber = self.emptyValueString + self.emptyValueString } - var txPower: String - if let tx = log.txPower { - txPower = "\(tx)" + var txPower: String = if let tx = log.txPower { + "\(tx)" } else { - txPower = self.emptyValueString + self.emptyValueString } let newLine = "\(date)" + "," + "\(temperature)" + "," diff --git a/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift b/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift index 3b64feb21..122e273d8 100644 --- a/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift +++ b/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift @@ -1,38 +1,38 @@ import Foundation -import RuuviStorage import RuuviCloud -import RuuviPool -import RuuviLocal import RuuviCore +import RuuviLocal +import RuuviPool import RuuviRepository import RuuviService +import RuuviStorage import RuuviUser #if canImport(RuuviServiceCloudSync) -import RuuviServiceCloudSync + import RuuviServiceCloudSync #endif #if canImport(RuuviServiceOwnership) -import RuuviServiceOwnership + import RuuviServiceOwnership #endif #if canImport(RuuviServiceSensorProperties) -import RuuviServiceSensorProperties + import RuuviServiceSensorProperties #endif #if canImport(RuuviServiceSensorRecords) -import RuuviServiceSensorRecords + import RuuviServiceSensorRecords #endif #if canImport(RuuviServiceAppSettings) -import RuuviServiceAppSettings + import RuuviServiceAppSettings #endif #if canImport(RuuviServiceOffsetCalibration) -import RuuviServiceOffsetCalibration + import RuuviServiceOffsetCalibration #endif #if canImport(RuuviServiceAlert) -import RuuviServiceAlert + import RuuviServiceAlert #endif #if canImport(RuuviServiceAuth) -import RuuviServiceAuth + import RuuviServiceAuth #endif #if canImport(RuuviServiceCloudNotification) -import RuuviServiceCloudNotification + import RuuviServiceCloudNotification #endif public protocol RuuviServiceFactory { @@ -125,7 +125,7 @@ public final class RuuviServiceFactoryImpl: RuuviServiceFactory { ruuviAlertService: RuuviServiceAlert, ruuviAppSettingsService: RuuviServiceAppSettings ) -> RuuviServiceCloudSync { - return RuuviServiceCloudSyncImpl( + RuuviServiceCloudSyncImpl( ruuviStorage: ruuviStorage, ruuviCloud: ruuviCloud, ruuviPool: ruuviPool, @@ -150,7 +150,7 @@ public final class RuuviServiceFactoryImpl: RuuviServiceFactory { alertService: RuuviServiceAlert, ruuviUser: RuuviUser ) -> RuuviServiceOwnership { - return RuuviServiceOwnershipImpl( + RuuviServiceOwnershipImpl( cloud: ruuviCloud, pool: ruuviPool, propertiesService: propertiesService, @@ -168,7 +168,7 @@ public final class RuuviServiceFactoryImpl: RuuviServiceFactory { ruuviCoreImage: RuuviCoreImage, ruuviLocalImages: RuuviLocalImages ) -> RuuviServiceSensorProperties { - return RuuviServiceSensorPropertiesImpl( + RuuviServiceSensorPropertiesImpl( pool: ruuviPool, cloud: ruuviCloud, coreImage: ruuviCoreImage, @@ -180,7 +180,7 @@ public final class RuuviServiceFactoryImpl: RuuviServiceFactory { ruuviPool: RuuviPool, ruuviLocalSyncState: RuuviLocalSyncState ) -> RuuviServiceSensorRecords { - return RuuviServiceSensorRecordsImpl( + RuuviServiceSensorRecordsImpl( pool: ruuviPool, localSyncState: ruuviLocalSyncState ) @@ -190,7 +190,7 @@ public final class RuuviServiceFactoryImpl: RuuviServiceFactory { ruuviCloud: RuuviCloud, ruuviLocalSettings: RuuviLocalSettings ) -> RuuviServiceAppSettings { - return RuuviServiceAppSettingsImpl( + RuuviServiceAppSettingsImpl( cloud: ruuviCloud, localSettings: ruuviLocalSettings ) @@ -200,7 +200,7 @@ public final class RuuviServiceFactoryImpl: RuuviServiceFactory { ruuviCloud: RuuviCloud, ruuviPool: RuuviPool ) -> RuuviServiceOffsetCalibration { - return RuuviServiceAppOffsetCalibrationImpl( + RuuviServiceAppOffsetCalibrationImpl( cloud: ruuviCloud, pool: ruuviPool ) @@ -210,7 +210,7 @@ public final class RuuviServiceFactoryImpl: RuuviServiceFactory { ruuviCloud: RuuviCloud, ruuviLocalIDs: RuuviLocalIDs ) -> RuuviServiceAlert { - return RuuviServiceAlertImpl( + RuuviServiceAlertImpl( cloud: ruuviCloud, localIDs: ruuviLocalIDs ) @@ -226,7 +226,7 @@ public final class RuuviServiceFactoryImpl: RuuviServiceFactory { localSyncState: RuuviLocalSyncState, alertService: RuuviServiceAlert ) -> RuuviServiceAuth { - return RuuviServiceAuthImpl( + RuuviServiceAuthImpl( ruuviUser: ruuviUser, pool: pool, storage: storage, @@ -244,7 +244,7 @@ public final class RuuviServiceFactoryImpl: RuuviServiceFactory { ruuviUser: RuuviUser, pnManager: RuuviCorePN ) -> RuuviServiceCloudNotification { - return RuuviServiceCloudNotificationImpl( + RuuviServiceCloudNotificationImpl( cloud: ruuviCloud, pool: ruuviPool, storage: storage, diff --git a/Packages/RuuviService/Sources/RuuviServiceGATT/Operations/RuuviTagReadLogsOperation.swift b/Packages/RuuviService/Sources/RuuviServiceGATT/Operations/RuuviTagReadLogsOperation.swift index 2519cc041..f7bc77536 100644 --- a/Packages/RuuviService/Sources/RuuviServiceGATT/Operations/RuuviTagReadLogsOperation.swift +++ b/Packages/RuuviService/Sources/RuuviServiceGATT/Operations/RuuviTagReadLogsOperation.swift @@ -1,5 +1,5 @@ -import Foundation import BTKit +import Foundation import RuuviOntology import RuuviPool import RuuviService @@ -31,7 +31,7 @@ final class RuuviTagReadLogsOperation: AsyncOperation { self.uuid = uuid self.mac = mac self.from = from - self.sensorSettings = settings + sensorSettings = settings self.ruuviPool = ruuviPool self.background = background self.progress = progress @@ -47,17 +47,18 @@ final class RuuviTagReadLogsOperation: AsyncOperation { options: [.callbackQueue(.untouch), .connectionTimeout(connectionTimeout ?? 0), .serviceTimeout(serviceTimeout ?? 0)], - progress: progress) { (observer, result) in + progress: progress) + { observer, result in switch result { - case .success(let logResult): + case let .success(logResult): switch logResult { - case .points(let points): + case let .points(points): observer.post(points: points, with: observer.uuid) - case .logs(let logs): - let records = logs.compactMap({ $0.ruuviSensorRecord(uuid: observer.uuid, mac: observer.mac) + case let .logs(logs): + let records = logs.compactMap { $0.ruuviSensorRecord(uuid: observer.uuid, mac: observer.mac) .with(source: .log) .any - }) + } let opLogs = observer.ruuviPool.create(records) opLogs.on(success: { _ in observer.post(logs: logs, with: observer.uuid) @@ -68,7 +69,7 @@ final class RuuviTagReadLogsOperation: AsyncOperation { observer.state = .finished }) } - case .failure(let error): + case let .failure(error): observer.post(error: error, with: observer.uuid) observer.error = .btkit(error) observer.state = .finished @@ -81,7 +82,8 @@ final class RuuviTagReadLogsOperation: AsyncOperation { for: self, uuid: uuid, options: [], - result: { _, _ in }) + result: { _, _ in } + ) } private func post(started date: Date, with uuid: String) { @@ -89,8 +91,8 @@ final class RuuviTagReadLogsOperation: AsyncOperation { NotificationCenter.default.post(name: .RuuviTagReadLogsOperationDidStart, object: nil, userInfo: - [RuuviTagReadLogsOperationDidStartKey.uuid: uuid, - RuuviTagReadLogsOperationDidStartKey.fromDate: date]) + [RuuviTagReadLogsOperationDidStartKey.uuid: uuid, + RuuviTagReadLogsOperationDidStartKey.fromDate: date]) } } @@ -99,8 +101,8 @@ final class RuuviTagReadLogsOperation: AsyncOperation { NotificationCenter.default.post(name: .RuuviTagReadLogsOperationProgress, object: nil, userInfo: - [RuuviTagReadLogsOperationProgressKey.uuid: uuid, - RuuviTagReadLogsOperationProgressKey.progress: points]) + [RuuviTagReadLogsOperationProgressKey.uuid: uuid, + RuuviTagReadLogsOperationProgressKey.progress: points]) } } @@ -109,8 +111,8 @@ final class RuuviTagReadLogsOperation: AsyncOperation { NotificationCenter.default.post(name: .RuuviTagReadLogsOperationDidFinish, object: nil, userInfo: - [RuuviTagReadLogsOperationDidFinishKey.uuid: uuid, - RuuviTagReadLogsOperationDidFinishKey.logs: logs]) + [RuuviTagReadLogsOperationDidFinishKey.uuid: uuid, + RuuviTagReadLogsOperationDidFinishKey.logs: logs]) } } @@ -119,8 +121,8 @@ final class RuuviTagReadLogsOperation: AsyncOperation { NotificationCenter.default.post(name: .RuuviTagReadLogsOperationDidFail, object: nil, userInfo: - [RuuviTagReadLogsOperationDidFailKey.uuid: uuid, - RuuviTagReadLogsOperationDidFailKey.error: error]) + [RuuviTagReadLogsOperationDidFailKey.uuid: uuid, + RuuviTagReadLogsOperationDidFailKey.error: error]) } } } diff --git a/Packages/RuuviService/Sources/RuuviServiceGATT/Queue/GATTServiceQueue.swift b/Packages/RuuviService/Sources/RuuviServiceGATT/Queue/GATTServiceQueue.swift index c07289043..7f7613e91 100644 --- a/Packages/RuuviService/Sources/RuuviServiceGATT/Queue/GATTServiceQueue.swift +++ b/Packages/RuuviService/Sources/RuuviServiceGATT/Queue/GATTServiceQueue.swift @@ -1,5 +1,5 @@ -import Foundation import BTKit +import Foundation import Future import RuuviOntology import RuuviPool @@ -60,10 +60,11 @@ public final class GATTServiceQueue: GATTService { } return promise.future } + // swiftlint:enable function_parameter_count public func isSyncingLogs(with uuid: String) -> Bool { - return queue.operations.contains(where: { ($0 as? RuuviTagReadLogsOperation)?.uuid == uuid }) + queue.operations.contains(where: { ($0 as? RuuviTagReadLogsOperation)?.uuid == uuid }) } @discardableResult diff --git a/Packages/RuuviService/Sources/RuuviServiceMeasurement/RuuviServiceMeasurementImpl.swift b/Packages/RuuviService/Sources/RuuviServiceMeasurement/RuuviServiceMeasurementImpl.swift index 95def71f0..3af524168 100644 --- a/Packages/RuuviService/Sources/RuuviServiceMeasurement/RuuviServiceMeasurementImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceMeasurement/RuuviServiceMeasurementImpl.swift @@ -1,8 +1,8 @@ // swiftlint:disable file_length import Foundation import Humidity -import RuuviOntology import RuuviLocal +import RuuviOntology import RuuviService // TODO: - @priyonto - Improve the number formatter instances. public final class RuuviServiceMeasurementImpl: NSObject { @@ -33,7 +33,7 @@ public final class RuuviServiceMeasurementImpl: NSObject { self.settings = settings self.emptyValueString = emptyValueString self.percentString = percentString - self.units = RuuviServiceMeasurementSettingsUnit( + units = RuuviServiceMeasurementSettingsUnit( temperatureUnit: settings.temperatureUnit.unitTemperature, humidityUnit: settings.humidityUnit, pressureUnit: settings.pressureUnit @@ -48,7 +48,7 @@ public final class RuuviServiceMeasurementImpl: NSObject { .HumidityUnitDidChange, .HumidityAccuracyDidChange, .PressureUnitDidChange, - .PressureUnitAccuracyChange + .PressureUnitAccuracyChange, ] private var observers: [NSObjectProtocol] = [] @@ -68,7 +68,7 @@ public final class RuuviServiceMeasurementImpl: NSObject { let measurementFormatter = MeasurementFormatter() measurementFormatter.locale = Locale.autoupdatingCurrent measurementFormatter.unitOptions = .providedUnit - measurementFormatter.numberFormatter = self.commonNumberFormatter + measurementFormatter.numberFormatter = commonNumberFormatter return measurementFormatter } @@ -87,7 +87,7 @@ public final class RuuviServiceMeasurementImpl: NSObject { let measurementFormatter = MeasurementFormatter() measurementFormatter.locale = Locale.current measurementFormatter.unitOptions = .providedUnit - measurementFormatter.numberFormatter = self.tempereatureNumberFormatter + measurementFormatter.numberFormatter = tempereatureNumberFormatter return measurementFormatter } @@ -104,8 +104,8 @@ public final class RuuviServiceMeasurementImpl: NSObject { private var humidityFormatter: HumidityFormatter { let humidityFormatter = HumidityFormatter() - humidityFormatter.numberFormatter = self.humidityNumberFormatter - HumiditySettings.setLanguage(self.settings.language.humidityLanguage) + humidityFormatter.numberFormatter = humidityNumberFormatter + HumiditySettings.setLanguage(settings.language.humidityLanguage) return humidityFormatter } @@ -124,7 +124,7 @@ public final class RuuviServiceMeasurementImpl: NSObject { let measurementFormatter = MeasurementFormatter() measurementFormatter.locale = Locale.current measurementFormatter.unitOptions = .providedUnit - measurementFormatter.numberFormatter = self.pressureNumberFormatter + measurementFormatter.numberFormatter = pressureNumberFormatter return measurementFormatter } @@ -135,18 +135,19 @@ public final class RuuviServiceMeasurementImpl: NSObject { listeners.add(listener) } } + // MARK: - MeasurementsService -extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { +extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { public func double(for temperature: Temperature) -> Double { - return temperature + temperature .converted(to: units.temperatureUnit) .value .round(to: commonNumberFormatter.maximumFractionDigits) } public func string(for temperature: Temperature?, allowSettings: Bool) -> String { - guard let temperature = temperature else { + guard let temperature else { return emptyValueString } let value = temperature.converted(to: units.temperatureUnit).value @@ -163,7 +164,8 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } if temperatureFormatter.unitStyle == .medium, settings.language == .english, - let valueString = numberFormatter.string(from: number) { + let valueString = numberFormatter.string(from: number) + { return String(format: "%@\(String.nbsp)%@", valueString, units.temperatureUnit.symbol) @@ -173,7 +175,7 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } public func stringWithoutSign(for temperature: Temperature?) -> String { - guard let temperature = temperature else { + guard let temperature else { return emptyValueString } let value = temperature.converted(to: units.temperatureUnit).value @@ -183,7 +185,7 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } public func stringWithoutSign(temperature: Double?) -> String { - guard let temperature = temperature else { + guard let temperature else { return emptyValueString } let number = NSNumber(value: temperature) @@ -202,8 +204,9 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } public func string(for pressure: Pressure?, - allowSettings: Bool) -> String { - guard let pressure = pressure else { + allowSettings: Bool) -> String + { + guard let pressure else { return emptyValueString } if allowSettings { @@ -214,7 +217,7 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } public func stringWithoutSign(for pressure: Pressure?) -> String { - guard let pressure = pressure else { + guard let pressure else { return emptyValueString } let pressureValue = pressure.converted(to: units.pressureUnit).value @@ -222,7 +225,7 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } public func stringWithoutSign(pressure: Double?) -> String { - guard let pressure = pressure else { + guard let pressure else { return emptyValueString } let number = NSNumber(value: pressure) @@ -230,14 +233,14 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } public func double(for voltage: Voltage) -> Double { - return voltage + voltage .converted(to: .volts) .value .round(to: commonNumberFormatter.maximumFractionDigits) } public func string(for voltage: Voltage?) -> String { - guard let voltage = voltage else { + guard let voltage else { return emptyValueString } return commonFormatter.string(from: voltage.converted(to: .volts)) @@ -245,7 +248,8 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { public func double(for humidity: Humidity, temperature: Temperature, - isDecimal: Bool) -> Double? { + isDecimal: Bool) -> Double? + { let humidityWithTemperature = Humidity( value: humidity.value, unit: .relative(temperature: temperature) @@ -254,9 +258,9 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { case .percent: let value = humidityWithTemperature.value return isDecimal - ? value + ? value .round(to: commonNumberFormatter.maximumFractionDigits) - : (value * 100) + : (value * 100) .round(to: commonNumberFormatter.maximumFractionDigits) case .gm3: return humidityWithTemperature.converted(to: .absolute) @@ -272,9 +276,11 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { public func string(for humidity: Humidity?, temperature: Temperature?, - allowSettings: Bool) -> String { - guard let humidity = humidity, - let temperature = temperature else { + allowSettings: Bool) -> String + { + guard let humidity, + let temperature + else { return emptyValueString } @@ -305,9 +311,11 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } public func stringWithoutSign(for humidity: Humidity?, - temperature: Temperature?) -> String { - guard let humidity = humidity, - let temperature = temperature else { + temperature: Temperature?) -> String + { + guard let humidity, + let temperature + else { return emptyValueString } @@ -335,7 +343,7 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } public func stringWithoutSign(humidity: Double?) -> String { - guard let humidity = humidity else { + guard let humidity else { return emptyValueString } let number = NSNumber(value: humidity) @@ -343,23 +351,25 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } public func string(for measurement: Double?) -> String { - guard let measurement = measurement else { + guard let measurement else { return "" } let number = NSNumber(value: measurement) return commonNumberFormatter.string(from: number) ?? "" } } + // MARK: - Private + extension RuuviServiceMeasurementImpl { private func notifyListeners() { listeners .allObjects - .compactMap({ + .compactMap { $0 as? RuuviServiceMeasurementDelegate - }).forEach({ + }.forEach { $0.measurementServiceDidUpdateUnit() - }) + } } private func updateCache() { @@ -374,42 +384,43 @@ extension RuuviServiceMeasurementImpl { } private func startSettingsObserving() { - notificationsNamesToObserve.forEach({ + notificationsNamesToObserve.forEach { let observer = NotificationCenter .default .addObserver(forName: $0, object: nil, - queue: .main) { [weak self] (_) in - self?.updateCache() - } + queue: .main) + { [weak self] _ in + self?.updateCache() + } self.observers.append(observer) - }) + } } } -extension RuuviServiceMeasurementImpl { - public func temperatureOffsetCorrection(for temperature: Double) -> Double { +public extension RuuviServiceMeasurementImpl { + func temperatureOffsetCorrection(for temperature: Double) -> Double { switch units.temperatureUnit { case .fahrenheit: - return temperature * 1.8 + temperature * 1.8 default: - return temperature + temperature } } - public func temperatureOffsetCorrectionString(for temperature: Double) -> String { - return string(for: Temperature( + func temperatureOffsetCorrectionString(for temperature: Double) -> String { + string(for: Temperature( temperatureOffsetCorrection(for: temperature), unit: units.temperatureUnit ), allowSettings: false) } - public func humidityOffsetCorrection(for humidity: Double) -> Double { - return humidity + func humidityOffsetCorrection(for humidity: Double) -> Double { + humidity } - public func humidityOffsetCorrectionString(for humidity: Double) -> String { - return commonFormatter.string( + func humidityOffsetCorrectionString(for humidity: Double) -> String { + commonFormatter.string( from: Humidity( value: humidityOffsetCorrection(for: humidity) * 100, unit: UnitHumidity.relative( @@ -420,12 +431,12 @@ extension RuuviServiceMeasurementImpl { ) } - public func pressureOffsetCorrection(for pressure: Double) -> Double { - return double(for: Pressure.init(value: pressure, unit: .hectopascals)) + func pressureOffsetCorrection(for pressure: Double) -> Double { + double(for: Pressure(value: pressure, unit: .hectopascals)) } - public func pressureOffsetCorrectionString(for pressure: Double) -> String { - return string(for: Pressure( + func pressureOffsetCorrectionString(for pressure: Double) -> String { + string(for: Pressure( pressureOffsetCorrection(for: pressure), unit: units.pressureUnit ), allowSettings: false) @@ -438,11 +449,13 @@ extension String { public extension Double { var stringValue: String { - return self == 0.0 ? formattedStringValue(places: 0) : String(self) + self == 0.0 ? formattedStringValue(places: 0) : String(self) } + func formattedStringValue(places: Int) -> String { - return String(format: "%.\(places)f", self) + String(format: "%.\(places)f", self) } + func round(to places: Int) -> Double { let divisor = pow(10.0, Double(places)) let rounded = (self * divisor).rounded(.toNearestOrAwayFromZero) / divisor diff --git a/Packages/RuuviService/Sources/RuuviServiceOffsetCalibration/RuuviServiceAppOffsetCalibrationImpl.swift b/Packages/RuuviService/Sources/RuuviServiceOffsetCalibration/RuuviServiceAppOffsetCalibrationImpl.swift index 60111a66a..e69151f42 100644 --- a/Packages/RuuviService/Sources/RuuviServiceOffsetCalibration/RuuviServiceAppOffsetCalibrationImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceOffsetCalibration/RuuviServiceAppOffsetCalibrationImpl.swift @@ -1,7 +1,7 @@ import Foundation import Future -import RuuviOntology import RuuviCloud +import RuuviOntology import RuuviPool import RuuviService @@ -46,24 +46,23 @@ public final class RuuviServiceAppOffsetCalibrationImpl: RuuviServiceOffsetCalib of type: OffsetCorrectionType, for sensor: RuuviTagSensor ) -> Future { - let cloudUpdate: Future - switch type { + let cloudUpdate: Future = switch type { case .temperature: - cloudUpdate = cloud.update( + cloud.update( temperatureOffset: offset ?? 0, humidityOffset: nil, pressureOffset: nil, for: sensor ) case .humidity: - cloudUpdate = cloud.update( + cloud.update( temperatureOffset: nil, humidityOffset: (offset ?? 0) * 100, // fraction locally, % on cloud pressureOffset: nil, for: sensor ) case .pressure: - cloudUpdate = cloud.update( + cloud.update( temperatureOffset: nil, humidityOffset: nil, pressureOffset: (offset ?? 0) * 100, // hPA locally, Pa on cloud diff --git a/Packages/RuuviService/Sources/RuuviServiceOwnership/RuuviServiceOwnershipImpl.swift b/Packages/RuuviService/Sources/RuuviServiceOwnership/RuuviServiceOwnershipImpl.swift index 9208d0ff9..ca16ec663 100644 --- a/Packages/RuuviService/Sources/RuuviServiceOwnership/RuuviServiceOwnershipImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceOwnership/RuuviServiceOwnershipImpl.swift @@ -1,15 +1,15 @@ import Foundation import Future -import RuuviOntology -import RuuviStorage import RuuviCloud -import RuuviPool import RuuviLocal +import RuuviOntology +import RuuviPool import RuuviService +import RuuviStorage import RuuviUser -extension Notification.Name { - public static let RuuviTagOwnershipCheckDidEnd = Notification.Name("RuuviTagOwnershipCheckDidEnd") +public extension Notification.Name { + static let RuuviTagOwnershipCheckDidEnd = Notification.Name("RuuviTagOwnershipCheckDidEnd") } public enum RuuviTagOwnershipCheckResultKey: String { @@ -132,7 +132,8 @@ public final class RuuviServiceOwnershipImpl: RuuviServiceOwnership { sensor: sensor, owner: owner, macId: macId, - promise: promise) + promise: promise + ) }, failure: { error in promise.fail(error: .ruuviCloud(error)) }) @@ -204,7 +205,8 @@ public final class RuuviServiceOwnershipImpl: RuuviServiceOwnership { var unshareOperation: Future? var unclaimOperation: Future? if let macId = sensor.macId, - sensor.isCloud { + sensor.isCloud + { if sensor.isOwner { unclaimOperation = unclaim( sensor: sensor, @@ -220,10 +222,10 @@ public final class RuuviServiceOwnershipImpl: RuuviServiceOwnership { deleteRecordsOperation, deleteLastRecordOperation]) .on(success: { _ in - if let unclaimOperation = unclaimOperation { + if let unclaimOperation { unclaimOperation.on() promise.succeed(value: sensor.any) - } else if let unshareOperation = unshareOperation { + } else if let unshareOperation { unshareOperation.on() promise.succeed(value: sensor.any) } else { diff --git a/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift b/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift index b1803d881..c74111a3d 100644 --- a/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift @@ -1,12 +1,12 @@ import Foundation -import UIKit import Future -import RuuviOntology -import RuuviPool import RuuviCloud -import RuuviLocal import RuuviCore +import RuuviLocal +import RuuviOntology +import RuuviPool import RuuviService +import UIKit public final class RuuviServiceSensorPropertiesImpl: RuuviServiceSensorProperties { private let pool: RuuviPool @@ -68,7 +68,7 @@ public final class RuuviServiceSensorPropertiesImpl: RuuviServiceSensorPropertie ) -> Future { let promise = Promise() let identifier = macId ?? luid - if let identifier = identifier { + if let identifier { if let image = localImages.setNextDefaultBackground(for: identifier) { promise.succeed(value: image) } else { @@ -113,7 +113,7 @@ public final class RuuviServiceSensorPropertiesImpl: RuuviServiceSensorPropertie for: mac ) local = localImages.setCustomBackground(image: image, for: mac) - } else if let luid = luid { + } else if let luid { local = localImages.setCustomBackground(image: image, for: luid) } else { promise.fail(error: .bothLuidAndMacAreNil) @@ -122,7 +122,7 @@ public final class RuuviServiceSensorPropertiesImpl: RuuviServiceSensorPropertie } else { if let mac = macId { local = localImages.setCustomBackground(image: image, for: mac) - } else if let luid = luid { + } else if let luid { local = localImages.setCustomBackground(image: image, for: luid) } else { promise.fail(error: .bothLuidAndMacAreNil) @@ -130,11 +130,11 @@ public final class RuuviServiceSensorPropertiesImpl: RuuviServiceSensorPropertie } } - if let local = local, let remote = remote { + if let local, let remote { if let mac = macId { localImages.setBackgroundUploadProgress(percentage: 0.0, for: mac) } - remote.on(success: {_ in + remote.on(success: { _ in local.on(success: { localUrl in if let mac = macId { self.localImages.deleteBackgroundUploadProgress(for: mac) @@ -146,7 +146,7 @@ public final class RuuviServiceSensorPropertiesImpl: RuuviServiceSensorPropertie }, failure: { error in promise.fail(error: .ruuviCloud(error)) }) - } else if let local = local { + } else if let local { local.on(success: { url in promise.succeed(value: url) }, failure: { error in @@ -160,7 +160,7 @@ public final class RuuviServiceSensorPropertiesImpl: RuuviServiceSensorPropertie } public func getImage(for sensor: RuuviTagSensor) -> Future { - return getImage(luid: sensor.luid, macId: sensor.macId) + getImage(luid: sensor.luid, macId: sensor.macId) } public func removeImage(for sensor: RuuviTagSensor) { @@ -194,17 +194,17 @@ public final class RuuviServiceSensorPropertiesImpl: RuuviServiceSensorPropertie private func getImage(luid: LocalIdentifier?, macId: MACIdentifier?) -> Future { let promise = Promise() - if let macId = macId { + if let macId { if let image = localImages.getBackground(for: macId) { promise.succeed(value: image) - } else if let luid = luid, let image = localImages.getOrGenerateBackground(for: luid) { + } else if let luid, let image = localImages.getOrGenerateBackground(for: luid) { promise.succeed(value: image) } else if let image = localImages.getOrGenerateBackground(for: macId) { promise.succeed(value: image) } else { promise.fail(error: .failedToFindOrGenerateBackgroundImage) } - } else if let luid = luid { + } else if let luid { if let image = localImages.getOrGenerateBackground(for: luid) { promise.succeed(value: image) } else { diff --git a/Packages/RuuviService/Sources/RuuviServiceSensorRecords/RuuviServiceSensorRecordsImpl.swift b/Packages/RuuviService/Sources/RuuviServiceSensorRecords/RuuviServiceSensorRecordsImpl.swift index a2cafd2b1..046c3ec41 100644 --- a/Packages/RuuviService/Sources/RuuviServiceSensorRecords/RuuviServiceSensorRecordsImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceSensorRecords/RuuviServiceSensorRecordsImpl.swift @@ -1,8 +1,8 @@ import Foundation import Future +import RuuviLocal import RuuviOntology import RuuviPool -import RuuviLocal import RuuviService public final class RuuviServiceSensorRecordsImpl: RuuviServiceSensorRecords { diff --git a/Packages/RuuviService/Tests/RuuviServiceTests/RuuviServiceTests.swift b/Packages/RuuviService/Tests/RuuviServiceTests/RuuviServiceTests.swift index dc5dd554d..eb161e91e 100644 --- a/Packages/RuuviService/Tests/RuuviServiceTests/RuuviServiceTests.swift +++ b/Packages/RuuviService/Tests/RuuviServiceTests/RuuviServiceTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviService +import XCTest final class RuuviServiceTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Packages/RuuviStorage/Package.swift b/Packages/RuuviStorage/Package.swift index 01d7a9fc0..52223ec26 100644 --- a/Packages/RuuviStorage/Package.swift +++ b/Packages/RuuviStorage/Package.swift @@ -9,15 +9,17 @@ let package = Package( products: [ .library( name: "RuuviStorage", - targets: ["RuuviStorage"]), + targets: ["RuuviStorage"] + ), .library( name: "RuuviStorageCoordinator", - targets: ["RuuviStorageCoordinator"]) + targets: ["RuuviStorageCoordinator"] + ), ], dependencies: [ .package(url: "https://github.com/kean/Future", .exact("1.3.0")), .package(path: "../RuuviOntology"), - .package(path: "../RuuviPersistence") + .package(path: "../RuuviPersistence"), ], targets: [ .target( @@ -25,7 +27,7 @@ let package = Package( dependencies: [ "Future", "RuuviOntology", - "RuuviPersistence" + "RuuviPersistence", ] ), .target( @@ -34,11 +36,12 @@ let package = Package( "RuuviStorage", "Future", "RuuviOntology", - "RuuviPersistence" + "RuuviPersistence", ] ), .testTarget( name: "RuuviStorageTests", - dependencies: ["RuuviStorage"]) + dependencies: ["RuuviStorage"] + ), ] ) diff --git a/Packages/RuuviStorage/Sources/RuuviStorage/RuuviStorage.swift b/Packages/RuuviStorage/Sources/RuuviStorage/RuuviStorage.swift index 295c671da..06d9e8f2e 100644 --- a/Packages/RuuviStorage/Sources/RuuviStorage/RuuviStorage.swift +++ b/Packages/RuuviStorage/Sources/RuuviStorage/RuuviStorage.swift @@ -30,6 +30,7 @@ public protocol RuuviStorage { func readSensorSettings(_ ruuviTag: RuuviTagSensor) -> Future // MARK: - Queued cloud requests + func readQueuedRequests() -> Future<[RuuviCloudQueuedRequest], RuuviStorageError> func readQueuedRequests( for key: String diff --git a/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageCoordinator.swift b/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageCoordinator.swift index 29fbe1d70..c65119efd 100644 --- a/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageCoordinator.swift +++ b/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageCoordinator.swift @@ -1,6 +1,6 @@ import Foundation -import RuuviOntology import Future +import RuuviOntology import RuuviPersistence import RuuviStorage @@ -42,11 +42,11 @@ final class RuuviStorageCoordinator: RuuviStorage { let realmOperation = realm.readAll() Future.zip(sqliteOperation, realmOperation) .on(success: { sqliteEntities, realmEntities in - let combinedValues = sqliteEntities + realmEntities - promise.succeed(value: combinedValues.map({ $0.any })) - }, failure: { error in - promise.fail(error: .ruuviPersistence(error)) - }) + let combinedValues = sqliteEntities + realmEntities + promise.succeed(value: combinedValues.map(\.any)) + }, failure: { error in + promise.fail(error: .ruuviPersistence(error)) + }) return promise.future } @@ -175,7 +175,7 @@ final class RuuviStorageCoordinator: RuuviStorage { let promise = Promise() let allTags = readAll() allTags.on(success: { tags in - let claimedTags = tags.filter({ $0.isClaimed && $0.isOwner }) + let claimedTags = tags.filter { $0.isClaimed && $0.isOwner } promise.succeed(value: claimedTags.count) }) return promise.future @@ -185,7 +185,7 @@ final class RuuviStorageCoordinator: RuuviStorage { let promise = Promise() let allTags = readAll() allTags.on(success: { tags in - let claimedTags = tags.filter({ !$0.isCloud }) + let claimedTags = tags.filter { !$0.isCloud } promise.succeed(value: claimedTags.count) }) return promise.future @@ -222,8 +222,10 @@ final class RuuviStorageCoordinator: RuuviStorage { } // MARK: - Queued cloud requests + func readQueuedRequests() - -> Future<[RuuviCloudQueuedRequest], RuuviStorageError> { + -> Future<[RuuviCloudQueuedRequest], RuuviStorageError> + { let promise = Promise<[RuuviCloudQueuedRequest], RuuviStorageError>() sqlite.readQueuedRequests().on(success: { requests in promise.succeed(value: requests) diff --git a/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageFactoryCoordinator.swift b/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageFactoryCoordinator.swift index 36c8b0d2b..467af6a59 100644 --- a/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageFactoryCoordinator.swift +++ b/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageFactoryCoordinator.swift @@ -6,6 +6,6 @@ public final class RuuviStorageFactoryCoordinator: RuuviStorageFactory { public init() {} public func create(realm: RuuviPersistence, sqlite: RuuviPersistence) -> RuuviStorage { - return RuuviStorageCoordinator(sqlite: sqlite, realm: realm) + RuuviStorageCoordinator(sqlite: sqlite, realm: realm) } } diff --git a/Packages/RuuviStorage/Tests/RuuviStorageTests/RuuviStorageTests.swift b/Packages/RuuviStorage/Tests/RuuviStorageTests/RuuviStorageTests.swift index a7a43002b..974203d70 100644 --- a/Packages/RuuviStorage/Tests/RuuviStorageTests/RuuviStorageTests.swift +++ b/Packages/RuuviStorage/Tests/RuuviStorageTests/RuuviStorageTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviStorage +import XCTest final class RuuviStorageTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/Packages/RuuviUser/Package.swift b/Packages/RuuviUser/Package.swift index dce01ebd6..c1a1caf3a 100644 --- a/Packages/RuuviUser/Package.swift +++ b/Packages/RuuviUser/Package.swift @@ -9,13 +9,15 @@ let package = Package( products: [ .library( name: "RuuviUser", - targets: ["RuuviUser"]), + targets: ["RuuviUser"] + ), .library( name: "RuuviUserCoordinator", - targets: ["RuuviUserCoordinator"]) + targets: ["RuuviUserCoordinator"] + ), ], dependencies: [ - .package(url: "https://github.com/kishikawakatsumi/KeychainAccess", from: "4.2.1") + .package(url: "https://github.com/kishikawakatsumi/KeychainAccess", from: "4.2.1"), ], targets: [ .target( @@ -24,11 +26,12 @@ let package = Package( .target( name: "RuuviUserCoordinator", dependencies: [ - "KeychainAccess" + "KeychainAccess", ] ), .testTarget( name: "RuuviUserTests", - dependencies: ["RuuviUser"]) + dependencies: ["RuuviUser"] + ), ] ) diff --git a/Packages/RuuviUser/Sources/RuuviUser/RuuviUser.swift b/Packages/RuuviUser/Sources/RuuviUser/RuuviUser.swift index f4ad0e5c5..199c20225 100644 --- a/Packages/RuuviUser/Sources/RuuviUser/RuuviUser.swift +++ b/Packages/RuuviUser/Sources/RuuviUser/RuuviUser.swift @@ -1,7 +1,7 @@ import Foundation -extension Notification.Name { - public static let RuuviUserDidAuthorized = Notification.Name("RuuviUser.AuthorizationSuccessful") +public extension Notification.Name { + static let RuuviUserDidAuthorized = Notification.Name("RuuviUser.AuthorizationSuccessful") } public protocol RuuviUser { diff --git a/Packages/RuuviUser/Sources/RuuviUserCoordinator/Keychain/Impl/KeychainServiceImpl.swift b/Packages/RuuviUser/Sources/RuuviUserCoordinator/Keychain/Impl/KeychainServiceImpl.swift index e440194b4..398dd1192 100644 --- a/Packages/RuuviUser/Sources/RuuviUserCoordinator/Keychain/Impl/KeychainServiceImpl.swift +++ b/Packages/RuuviUser/Sources/RuuviUserCoordinator/Keychain/Impl/KeychainServiceImpl.swift @@ -2,7 +2,7 @@ import Foundation import KeychainAccess final class KeychainServiceImpl { - private let keychain: Keychain = Keychain( + private let keychain: Keychain = .init( service: "com.ruuvi.station", accessGroup: "4MUYJ4YYH4.com.ruuvi.station" ) @@ -15,7 +15,9 @@ final class KeychainServiceImpl { case userApiEmail } } + // MARK: - Public + extension KeychainServiceImpl: KeychainService { var ruuviUserApiKey: String? { get { @@ -74,7 +76,7 @@ extension KeychainServiceImpl: KeychainService { } var userIsAuthorized: Bool { - return !((ruuviUserApiKey ?? "").isEmpty) + !((ruuviUserApiKey ?? "").isEmpty) && !((userApiEmail ?? "").isEmpty) } } diff --git a/Packages/RuuviUser/Sources/RuuviUserCoordinator/RuuviUserCoordinator.swift b/Packages/RuuviUser/Sources/RuuviUserCoordinator/RuuviUserCoordinator.swift index 8e6267871..fe7b81468 100644 --- a/Packages/RuuviUser/Sources/RuuviUserCoordinator/RuuviUserCoordinator.swift +++ b/Packages/RuuviUser/Sources/RuuviUserCoordinator/RuuviUserCoordinator.swift @@ -5,7 +5,7 @@ import WidgetKit final class RuuviUserCoordinator: RuuviUser { var apiKey: String? { get { - return keychainService.ruuviUserApiKey + keychainService.ruuviUserApiKey } set { keychainService.ruuviUserApiKey = newValue @@ -14,7 +14,7 @@ final class RuuviUserCoordinator: RuuviUser { var email: String? { get { - return keychainService.userApiEmail + keychainService.userApiEmail } set { keychainService.userApiEmail = newValue @@ -23,7 +23,7 @@ final class RuuviUserCoordinator: RuuviUser { var isAuthorized: Bool { get { - return UserDefaults.standard.bool(forKey: isAuthorizedUDKey) + UserDefaults.standard.bool(forKey: isAuthorizedUDKey) } set { UserDefaults.standard.set(newValue, forKey: isAuthorizedUDKey) @@ -41,7 +41,7 @@ final class RuuviUserCoordinator: RuuviUser { func login(apiKey: String) { self.apiKey = apiKey - self.isAuthorized = true + isAuthorized = true NotificationCenter .default .post(name: .RuuviUserDidAuthorized, diff --git a/Packages/RuuviUser/Tests/RuuviUserTests/RuuviUserTests.swift b/Packages/RuuviUser/Tests/RuuviUserTests/RuuviUserTests.swift index 3250ede25..a162f9949 100644 --- a/Packages/RuuviUser/Tests/RuuviUserTests/RuuviUserTests.swift +++ b/Packages/RuuviUser/Tests/RuuviUserTests/RuuviUserTests.swift @@ -1,7 +1,6 @@ -import XCTest @testable import RuuviUser +import XCTest final class RuuviUserTests: XCTestCase { - func testExample() { - } + func testExample() {} } diff --git a/intents/IntentHandler.swift b/intents/IntentHandler.swift index ee8d35ae0..5a4476dcf 100644 --- a/intents/IntentHandler.swift +++ b/intents/IntentHandler.swift @@ -2,14 +2,15 @@ import Intents class IntentHandler: INExtension, RuuviTagSelectionIntentHandling { private let viewModel = WidgetViewModel() - func provideRuuviWidgetTagOptionsCollection(for intent: RuuviTagSelectionIntent, + func provideRuuviWidgetTagOptionsCollection(for _: RuuviTagSelectionIntent, with completion: @escaping (INObjectCollection?, - Error?) -> Void) { + Error?) -> Void) + { viewModel.fetchRuuviTags(completion: { response in - let newValues = response.compactMap({ sensor in + let newValues = response.compactMap { sensor in RuuviWidgetTag(identifier: sensor.sensor.id, display: sensor.sensor.name) - }).sorted(by: { first, second in - return first.displayString.lowercased() < second.displayString.lowercased() + }.sorted(by: { first, second in + first.displayString.lowercased() < second.displayString.lowercased() }) let items = INObjectCollection(items: newValues) completion(items, nil) diff --git a/pnservice/NotificationService.swift b/pnservice/NotificationService.swift index 19b4270f0..2c05b14b9 100644 --- a/pnservice/NotificationService.swift +++ b/pnservice/NotificationService.swift @@ -1,21 +1,21 @@ import UserNotifications class NotificationService: UNNotificationServiceExtension { - // swiftlint:disable redundant_string_enum_value private enum AlertType: String { - case temperature = "temperature" - case humidity = "humidity" - case pressure = "pressure" - case signal = "signal" - case movement = "movement" - case offline = "offline" + case temperature + case humidity + case pressure + case signal + case movement + case offline } private enum TriggerType: String { - case under = "under" - case over = "over" + case under + case over } + // swiftlint:enable redundant_string_enum_value private let notificationServiceAppGroup = UserDefaults(suiteName: "group.com.ruuvi.station.pnservice") @@ -25,9 +25,9 @@ class NotificationService: UNNotificationServiceExtension { var currentRequest: UNNotificationRequest? override func didReceive(_ request: UNNotificationRequest, - withContentHandler - contentHandler: - @escaping (UNNotificationContent) -> Void) { + withContentHandler contentHandler: + @escaping (UNNotificationContent) -> Void) + { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) currentRequest = request @@ -39,10 +39,10 @@ class NotificationService: UNNotificationServiceExtension { } private func processNotification() { - - if let contentHandler = contentHandler, + if let contentHandler, let userInfo = currentRequest?.content.userInfo, - let bestAttemptContent = bestAttemptContent { + let bestAttemptContent + { // If this value is not available on data, show formatted message. // Otherwise don't do anything. let showLocallyFormattedMessage = userInfo["showLocallyFormatted"] as? Bool ?? true @@ -51,7 +51,8 @@ class NotificationService: UNNotificationServiceExtension { let alertType = userInfo["alertType"] as? String, let triggerType = userInfo["triggerType"] as? String, let threshold = userInfo["thresholdValue"] as? String, - let alertMessage = userInfo["alertData"] as? String { + let alertMessage = userInfo["alertData"] as? String + { let title = titleForAlert(from: triggerType, alertType: alertType, threshold: threshold) @@ -70,48 +71,50 @@ extension NotificationService { private func getAlertType(from value: String) -> AlertType? { switch value.lowercased() { case "temperature": - return .temperature + .temperature case "humidity": - return .humidity + .humidity case "pressure": - return .pressure + .pressure case "signal": - return .signal + .signal case "movement": - return .movement + .movement default: - return nil + nil } } private func getTriggerType(from value: String) -> TriggerType? { switch value.lowercased() { case "under": - return .under + .under case "over": - return .over + .over default: - return nil + nil } } // swiftlint:disable:next cyclomatic_complexity private func titleForAlert(from triggerType: String, alertType: String, - threshold: String) -> String { + threshold: String) -> String + { guard let triggerType = getTriggerType(from: triggerType), - let alertType = getAlertType(from: alertType) else { + let alertType = getAlertType(from: alertType) + else { return "" } - var format: String = "" + var format = "" switch triggerType { case .under: switch alertType { case .temperature: format = "alert_notification_temperature_low_threshold" case .humidity: - format = "alert_notification_humidity_low_threshold" + format = "alert_notification_humidity_low_threshold" case .pressure: format = "alert_notification_pressure_low_threshold" case .signal: @@ -127,7 +130,7 @@ extension NotificationService { case .temperature: format = "alert_notification_temperature_high_threshold" case .humidity: - format = "alert_notification_humidity_high_threshold" + format = "alert_notification_humidity_high_threshold" case .pressure: format = "alert_notification_pressure_high_threshold" case .signal: @@ -147,10 +150,11 @@ extension NotificationService { let languageUDKey = "SettingsUserDegaults.languageUDKey" guard let languageCode = notificationServiceAppGroup?.string(forKey: languageUDKey), let bundle = Bundle.main.path( - forResource: languageCode, - ofType: "lproj" - ), - let languageBundle = Bundle(path: bundle) else { + forResource: languageCode, + ofType: "lproj" + ), + let languageBundle = Bundle(path: bundle) + else { return NSLocalizedString(value, comment: value) } diff --git a/ruuvi-widgets/Assembly/WidgetAssembly.swift b/ruuvi-widgets/Assembly/WidgetAssembly.swift index 036fec8d1..7b06a4f90 100644 --- a/ruuvi-widgets/Assembly/WidgetAssembly.swift +++ b/ruuvi-widgets/Assembly/WidgetAssembly.swift @@ -1,12 +1,12 @@ import Foundation -import Swinject import RuuviCloud import RuuviUser +import Swinject #if canImport(RuuviCloudPure) -import RuuviCloudPure + import RuuviCloudPure #endif #if canImport(RuuviUserCoordinator) -import RuuviUserCoordinator + import RuuviUserCoordinator #endif final class WidgetAssembly { @@ -16,14 +16,13 @@ final class WidgetAssembly { init() { assembler = Assembler( [ - NetworkingAssembly() + NetworkingAssembly(), ]) } } private final class NetworkingAssembly: Assembly { func assemble(container: Container) { - let appGroupDefaults = UserDefaults( suiteName: Constants.appGroupBundleId.rawValue ) @@ -45,17 +44,16 @@ private final class NetworkingAssembly: Assembly { } container.register(RuuviCloudFactory.self) { _ in - return RuuviCloudFactoryPure() + RuuviCloudFactoryPure() } container.register(RuuviUserFactory.self) { _ in - return RuuviUserFactoryCoordinator() + RuuviUserFactoryCoordinator() } container.register(RuuviUser.self) { r in let factory = r.resolve(RuuviUserFactory.self)! return factory.createUser() }.inObjectScope(.container) - } } diff --git a/ruuvi-widgets/Enum/WidgetSensorEnum.swift b/ruuvi-widgets/Enum/WidgetSensorEnum.swift index 264577c98..3b57dd031 100644 --- a/ruuvi-widgets/Enum/WidgetSensorEnum.swift +++ b/ruuvi-widgets/Enum/WidgetSensorEnum.swift @@ -12,23 +12,22 @@ public enum WidgetSensorEnum: Int { } extension WidgetSensorEnum { - func unit(from settings: MeasurementServiceSettings) -> String { switch self { case .temperature: - return settings.temperatureUnit.symbol + settings.temperatureUnit.symbol case .humidity: - return settings.humidityUnit.symbol + settings.humidityUnit.symbol case .pressure: - return settings.pressureUnit.symbol + settings.pressureUnit.symbol case .movement_counter: - return "Cards.Movements.title".localized + "Cards.Movements.title".localized case .battery_voltage: - return "v" + "v" case .acceleration_x, - .acceleration_y, - .acceleration_z: - return "g" + .acceleration_y, + .acceleration_z: + "g" } } } diff --git a/ruuvi-widgets/Helper/Constants.swift b/ruuvi-widgets/Helper/Constants.swift index b58ce5500..3f5026018 100644 --- a/ruuvi-widgets/Helper/Constants.swift +++ b/ruuvi-widgets/Helper/Constants.swift @@ -10,15 +10,15 @@ public enum Constants: String { case simpleWidgetDisplayName = "Ruuvi Widget" case isAuthorizedUDKey = "RuuviUserCoordinator.isAuthorizedUDKey" - case hasCloudSensorsKey = "hasCloudSensorsKey" - case languageKey = "languageKey" - case temperatureUnitKey = "temperatureUnitKey" - case temperatureAccuracyKey = "temperatureAccuracyKey" - case humidityUnitKey = "humidityUnitKey" - case humidityAccuracyKey = "humidityAccuracyKey" - case pressureUnitKey = "pressureUnitKey" - case pressureAccuracyKey = "pressureAccuracyKey" - case useDevServerKey = "useDevServerKey" + case hasCloudSensorsKey + case languageKey + case temperatureUnitKey + case temperatureAccuracyKey + case humidityUnitKey + case humidityAccuracyKey + case pressureUnitKey + case pressureAccuracyKey + case useDevServerKey case ruuviLogo = "ruuvi_logo" case ruuviLogoEye = "eye_circle" diff --git a/ruuvi-widgets/Helper/Extensions.swift b/ruuvi-widgets/Helper/Extensions.swift index 59be7fa17..7707dfe01 100644 --- a/ruuvi-widgets/Helper/Extensions.swift +++ b/ruuvi-widgets/Helper/Extensions.swift @@ -1,8 +1,9 @@ -import SwiftUI import Humidity import RuuviOntology +import SwiftUI // MARK: - COLORS + // Necessary colors used on the widgets extension Color { static let logoColor = Color("LogoColor") @@ -14,38 +15,39 @@ extension Color { } // MARK: - LANGUAGE -extension Language { - public var locale: Locale { + +public extension Language { + var locale: Locale { switch self { case .english: - return Locale(identifier: "en_US") + Locale(identifier: "en_US") case .russian: - return Locale(identifier: "ru_RU") + Locale(identifier: "ru_RU") case .finnish: - return Locale(identifier: "fi") + Locale(identifier: "fi") case .french: - return Locale(identifier: "fr") + Locale(identifier: "fr") case .swedish: - return Locale(identifier: "sv") + Locale(identifier: "sv") case .german: - return Locale(identifier: "de") + Locale(identifier: "de") } } - public var humidityLanguage: HumiditySettings.Language { + var humidityLanguage: HumiditySettings.Language { switch self { case .german: - return .en + .en case .russian: - return .ru + .ru case .finnish: - return .fi + .fi case .french: - return .en + .en case .swedish: - return .sv + .sv case .english: - return .en + .en } } } @@ -56,16 +58,17 @@ extension HumidityUnit { var symbol: String { switch self { case .percent: - return "%" + "%" case .gm3: - return "g/m³" + "g/m³" default: - return "°" + "°" } } } // MARK: - NUMBERS + extension Double { func round(to places: Int) -> Double { let divisor = pow(10.0, Double(places)) @@ -74,59 +77,60 @@ extension Double { } var clean: String { - return self.truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", self) : String(self) + truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", self) : String(self) } var value: String { - return String(self) + String(self) } var nsNumber: NSNumber { - return NSNumber(value: self) + NSNumber(value: self) } } extension Int { var value: String { - return String(self) + String(self) } var double: Double { - return Double(self) + Double(self) } } + // MARK: - String -extension Optional where Wrapped == String { + +extension String? { var unwrapped: String { - return self ?? "" + self ?? "" } } extension String { var localized: String { - return NSLocalizedString(self, comment: "") + NSLocalizedString(self, comment: "") } } extension String { - var length: Int { - return count + count } - subscript (i: Int) -> String { - return self[i ..< i + 1] + subscript(i: Int) -> String { + self[i ..< i + 1] } func substring(fromIndex: Int) -> String { - return self[min(fromIndex, length) ..< length] + self[min(fromIndex, length) ..< length] } func substring(toIndex: Int) -> String { - return self[0 ..< max(0, toIndex)] + self[0 ..< max(0, toIndex)] } - subscript (r: Range) -> String { + subscript(r: Range) -> String { let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)), upper: min(length, max(0, r.upperBound)))) let start = index(startIndex, offsetBy: range.lowerBound) diff --git a/ruuvi-widgets/Helper/MeasurementService.swift b/ruuvi-widgets/Helper/MeasurementService.swift index 232750e15..ef330f95e 100644 --- a/ruuvi-widgets/Helper/MeasurementService.swift +++ b/ruuvi-widgets/Helper/MeasurementService.swift @@ -31,7 +31,6 @@ public struct MeasurementServiceSettings { } final class MeasurementService: NSObject { - public var settings: MeasurementServiceSettings private var commonFormatter: NumberFormatter { @@ -73,10 +72,10 @@ final class MeasurementService: NSObject { } // MARK: - MeasurementsService -extension MeasurementService { +extension MeasurementService { public func temperature(for temperature: Temperature?) -> String { - guard let temperature = temperature else { + guard let temperature else { return emptyValueString } let value = temperature @@ -89,7 +88,7 @@ extension MeasurementService { } public func pressure(for pressure: Pressure?) -> String { - guard let pressure = pressure else { + guard let pressure else { return emptyValueString } let value = pressure @@ -102,7 +101,7 @@ extension MeasurementService { } public func voltage(for voltage: Voltage?) -> String { - guard let voltage = voltage else { + guard let voltage else { return emptyValueString } let value = voltage @@ -114,9 +113,11 @@ extension MeasurementService { public func humidity(for humidity: Humidity?, temperature: Temperature?, - isDecimal: Bool) -> String { - guard let humidity = humidity, - let temperature = temperature else { + isDecimal: Bool) -> String + { + guard let humidity, + let temperature + else { return emptyValueString } let humidityWithTemperature = Humidity( @@ -130,9 +131,9 @@ extension MeasurementService { case .percent: let value = humidityWithTemperature.value humidityValue = isDecimal - ? value + ? value .round(to: settings.humidityAccuracy.value) - : (value * 100) + : (value * 100) .round(to: settings.humidityAccuracy.value) case .gm3: humidityValue = humidityWithTemperature.converted(to: .absolute) @@ -150,7 +151,7 @@ extension MeasurementService { } public func acceleration(for acceleration: Double?) -> String { - guard let acceleration = acceleration else { + guard let acceleration else { return emptyValueString } let value = acceleration.round(to: commonFormatter.maximumFractionDigits) @@ -158,18 +159,22 @@ extension MeasurementService { } public func movements(for movements: Int?) -> String { - guard let movements = movements else { + guard let movements else { return emptyValueString } return movements.value } } + // MARK: - MeasurementService Helper methods + extension MeasurementService { private func formattedValue(from value: Double?, - formatter: NumberFormatter) -> String { - guard let value = value, - let formattedValue = formatter.string(from: value.nsNumber) else { + formatter: NumberFormatter) -> String + { + guard let value, + let formattedValue = formatter.string(from: value.nsNumber) + else { return emptyValueString } return formattedValue diff --git a/ruuvi-widgets/Model/Model+Extension.swift b/ruuvi-widgets/Model/Model+Extension.swift index aab6b455f..bb905e0fb 100644 --- a/ruuvi-widgets/Model/Model+Extension.swift +++ b/ruuvi-widgets/Model/Model+Extension.swift @@ -10,47 +10,43 @@ extension RuuviTagSelectionIntent { extension RuuviTagSensorRecordStruct { static func preview() -> RuuviTagSensorRecordStruct { - return RuuviTagSensorRecordStruct(luid: nil, - date: Date(), - source: .ruuviNetwork, - macId: nil, - rssi: nil, - temperature: Temperature(69.50), - humidity: nil, - pressure: nil, - acceleration: nil, - voltage: nil, - movementCounter: nil, - measurementSequenceNumber: nil, - txPower: nil, - temperatureOffset: 0, - humidityOffset: 0, - pressureOffset: 0) + RuuviTagSensorRecordStruct(luid: nil, + date: Date(), + source: .ruuviNetwork, + macId: nil, + rssi: nil, + temperature: Temperature(69.50), + humidity: nil, + pressure: nil, + acceleration: nil, + voltage: nil, + movementCounter: nil, + measurementSequenceNumber: nil, + txPower: nil, + temperatureOffset: 0, + humidityOffset: 0, + pressureOffset: 0) } } extension RuuviWidgetTag { - static var preview: RuuviWidgetTag = { - return RuuviWidgetTag(identifier: nil, - display: "Sauna") - }() + static var preview: RuuviWidgetTag = .init(identifier: nil, + display: "Sauna") } extension WidgetSensor { - static var preview: WidgetSensor = { - return .temperature - }() + static var preview: WidgetSensor = .temperature } extension SensorSettingsStruct { static func settings(from ruuviTag: AnyCloudSensor) -> SensorSettingsStruct { - return SensorSettingsStruct(luid: ruuviTag.ruuviTagSensor.luid, - macId: ruuviTag.ruuviTagSensor.macId, - temperatureOffset: ruuviTag.offsetTemperature, - temperatureOffsetDate: nil, - humidityOffset: ruuviTag.offsetHumidity, - humidityOffsetDate: nil, - pressureOffset: ruuviTag.offsetPressure, - pressureOffsetDate: nil) + SensorSettingsStruct(luid: ruuviTag.ruuviTagSensor.luid, + macId: ruuviTag.ruuviTagSensor.macId, + temperatureOffset: ruuviTag.offsetTemperature, + temperatureOffsetDate: nil, + humidityOffset: ruuviTag.offsetHumidity, + humidityOffsetDate: nil, + pressureOffset: ruuviTag.offsetPressure, + pressureOffsetDate: nil) } } diff --git a/ruuvi-widgets/Model/WidgetEntry.swift b/ruuvi-widgets/Model/WidgetEntry.swift index 7e3028df0..c8b07ef61 100644 --- a/ruuvi-widgets/Model/WidgetEntry.swift +++ b/ruuvi-widgets/Model/WidgetEntry.swift @@ -1,6 +1,6 @@ import Intents -import WidgetKit import RuuviOntology +import WidgetKit struct WidgetEntry: TimelineEntry { let date: Date @@ -13,39 +13,40 @@ struct WidgetEntry: TimelineEntry { extension WidgetEntry { static func placeholder() -> WidgetEntry { - return WidgetEntry(date: Date(), - isAuthorized: true, - tag: .preview, - record: RuuviTagSensorRecordStruct.preview(), - settings: nil, - config: .preview) + WidgetEntry(date: Date(), + isAuthorized: true, + tag: .preview, + record: RuuviTagSensorRecordStruct.preview(), + settings: nil, + config: .preview) } static func unauthorized() -> WidgetEntry { - return WidgetEntry(date: Date(), - isAuthorized: false, - tag: .preview, - record: nil, - settings: nil, - config: .preview) + WidgetEntry(date: Date(), + isAuthorized: false, + tag: .preview, + record: nil, + settings: nil, + config: .preview) } static func empty() -> WidgetEntry { - return WidgetEntry(date: Date(), - isAuthorized: true, - tag: .preview, - record: nil, - settings: nil, - config: .preview) + WidgetEntry(date: Date(), + isAuthorized: true, + tag: .preview, + record: nil, + settings: nil, + config: .preview) } static func empty(with configuration: RuuviTagSelectionIntent, - authorized: Bool = false) -> WidgetEntry { - return WidgetEntry(date: Date(), - isAuthorized: authorized, - tag: .preview, - record: nil, - settings: nil, - config: authorized ? configuration : .preview) + authorized: Bool = false) -> WidgetEntry + { + WidgetEntry(date: Date(), + isAuthorized: authorized, + tag: .preview, + record: nil, + settings: nil, + config: authorized ? configuration : .preview) } } diff --git a/ruuvi-widgets/Provider/WidgetProvider.swift b/ruuvi-widgets/Provider/WidgetProvider.swift index 6045bc692..a92c882a3 100644 --- a/ruuvi-widgets/Provider/WidgetProvider.swift +++ b/ruuvi-widgets/Provider/WidgetProvider.swift @@ -1,25 +1,27 @@ -import WidgetKit -import SwiftUI import Intents import RuuviOntology +import SwiftUI +import WidgetKit final class WidgetProvider: IntentTimelineProvider { @ObservedObject private var networkManager = NetworkManager() private let viewModel = WidgetViewModel() - func placeholder(in context: Context) -> WidgetEntry { - return WidgetEntry.placeholder() + func placeholder(in _: Context) -> WidgetEntry { + WidgetEntry.placeholder() } - func getSnapshot(for configuration: RuuviTagSelectionIntent, - in context: Context, - completion: @escaping (WidgetEntry) -> Void) { - return completion(.placeholder()) + func getSnapshot(for _: RuuviTagSelectionIntent, + in _: Context, + completion: @escaping (WidgetEntry) -> Void) + { + completion(.placeholder()) } func getTimeline(for configuration: RuuviTagSelectionIntent, - in context: Context, - completion: @escaping (Timeline) -> Void) { + in _: Context, + completion: @escaping (Timeline) -> Void) + { guard networkManager.isConnected, viewModel.isAuthorized() else { return emptyTimeline(for: configuration, completion: completion) @@ -27,11 +29,12 @@ final class WidgetProvider: IntentTimelineProvider { viewModel.fetchRuuviTags(completion: { [weak self] tags in guard let sSelf = self else { return } guard let configuredTag = configuration.ruuviWidgetTag, - let tag = tags.first(where: { result in - result.sensor.id == configuredTag.identifier - }) else { + let tag = tags.first(where: { result in + result.sensor.id == configuredTag.identifier + }) + else { return sSelf.emptyTimeline(for: configuration, - completion: completion) + completion: completion) } guard let record = tag.record else { @@ -48,7 +51,8 @@ final class WidgetProvider: IntentTimelineProvider { extension WidgetProvider { private func emptyTimeline(for configuration: RuuviTagSelectionIntent, - completion: @escaping (Timeline) -> Void) { + completion: @escaping (Timeline) -> Void) + { var entries: [WidgetEntry] = [] let entry = WidgetEntry.empty(with: configuration, @@ -62,7 +66,8 @@ extension WidgetProvider { private func timeline(from ruuviTag: AnyCloudSensor, configuration: RuuviTagSelectionIntent, record: RuuviTagSensorRecord, - completion: @escaping (Timeline) -> Void) { + completion: @escaping (Timeline) -> Void) + { var entries: [WidgetEntry] = [] let settings = SensorSettingsStruct.settings(from: ruuviTag) diff --git a/ruuvi-widgets/RuuviWidgets.swift b/ruuvi-widgets/RuuviWidgets.swift index 703b0cf4a..05fcaf83b 100644 --- a/ruuvi-widgets/RuuviWidgets.swift +++ b/ruuvi-widgets/RuuviWidgets.swift @@ -1,6 +1,6 @@ -import WidgetKit -import SwiftUI import Intents +import SwiftUI +import WidgetKit struct RuuviWidgetEntryView: View { @Environment(\.widgetFamily) private var family @@ -37,15 +37,15 @@ struct RuuviWidgets: Widget { let viewModel = WidgetViewModel() private var supportedFamilies: [WidgetFamily] { if #available(iOSApplicationExtension 16.0, *) { - return [ + [ .systemSmall, .accessoryRectangular, .accessoryInline, - .accessoryCircular + .accessoryCircular, ] } else { - return [ - .systemSmall + [ + .systemSmall, ] } } @@ -68,9 +68,11 @@ struct RuuviWidgets: Widget { extension WidgetConfiguration { func contentMarginsDisabledIfAvailable() -> some WidgetConfiguration { if #available(iOSApplicationExtension 17.0, *) { + // swiftformat:disable all return self.contentMarginsDisabled() } else { return self + // swiftformat:enable all } } } diff --git a/ruuvi-widgets/View Model/WidgetViewModel.swift b/ruuvi-widgets/View Model/WidgetViewModel.swift index e7b313c5f..e5c8bcf82 100644 --- a/ruuvi-widgets/View Model/WidgetViewModel.swift +++ b/ruuvi-widgets/View Model/WidgetViewModel.swift @@ -1,8 +1,8 @@ import Foundation -import SwiftUI import RuuviCloud import RuuviOntology import RuuviUser +import SwiftUI public final class WidgetViewModel: ObservableObject { private let widgetAssembly = WidgetAssembly.shared.assembler.resolver @@ -18,10 +18,10 @@ public final class WidgetViewModel: ObservableObject { } // MARK: - Network calls -extension WidgetViewModel { - public func fetchRuuviTags(completion: @escaping ([RuuviCloudSensorDense]) -> Void) { - guard isAuthorized() && hasCloudSensors() else { +public extension WidgetViewModel { + func fetchRuuviTags(completion: @escaping ([RuuviCloudSensorDense]) -> Void) { + guard isAuthorized(), hasCloudSensors() else { return } ruuviCloud.loadSensorsDense(for: nil, @@ -29,25 +29,27 @@ extension WidgetViewModel { sharedToOthers: nil, sharedToMe: true, alerts: nil).on(success: { sensors in - let sensorsWithRecord = sensors.filter({ $0.record != nil }) + let sensorsWithRecord = sensors.filter { $0.record != nil } completion(sensorsWithRecord) }) } } // MARK: - Public methods -extension WidgetViewModel { - public func isAuthorized() -> Bool { - return appGroupDefaults?.bool(forKey: Constants.isAuthorizedUDKey.rawValue) ?? false +public extension WidgetViewModel { + func isAuthorized() -> Bool { + appGroupDefaults?.bool(forKey: Constants.isAuthorizedUDKey.rawValue) ?? false } - public func getValue(from record: RuuviTagSensorRecord?, - settings: SensorSettings?, - config: RuuviTagSelectionIntent) -> String { + func getValue(from record: RuuviTagSensorRecord?, + settings: SensorSettings?, + config: RuuviTagSelectionIntent) -> String + { let measurementService = MeasurementService(settings: getAppSettings()) guard let sensor = WidgetSensorEnum(rawValue: config.sensor.rawValue), - let record = record else { + let record + else { return "69.50" // Default value to show on the preview } switch sensor { @@ -76,20 +78,20 @@ extension WidgetViewModel { } } - public func getUnit(for sensor: WidgetSensorEnum?) -> String { - guard let sensor = sensor else { + func getUnit(for sensor: WidgetSensorEnum?) -> String { + guard let sensor else { return "°C" // Default unit to show on the preview } let settings = getAppSettings() return sensor.unit(from: settings) } - public func locale() -> Locale { - return getLanguage().locale + func locale() -> Locale { + getLanguage().locale } /// Returns value for inline widget - func getInlineWidgetValue(from entry: WidgetEntry) -> String { + internal func getInlineWidgetValue(from entry: WidgetEntry) -> String { let value = getValue(from: entry.record, settings: entry.settings, config: entry.config) @@ -99,7 +101,7 @@ extension WidgetViewModel { /// Returns SF Symbol based on sensor since we /// can not use Image in inline widget - func symbol(from entry: WidgetEntry) -> Image { + internal func symbol(from entry: WidgetEntry) -> Image { guard let sensor = WidgetSensorEnum(rawValue: entry.config.sensor.rawValue) else { return Image(systemName: "thermometer.medium.slash") } @@ -113,15 +115,15 @@ extension WidgetViewModel { case .movement_counter: return Image(systemName: "repeat.circle") case .acceleration_x, - .acceleration_y, - .acceleration_z: + .acceleration_y, + .acceleration_z: return Image(systemName: "move.3d") case .battery_voltage: return Image(systemName: "bolt.circle.fill") } } - func measurementTime(from entry: WidgetEntry) -> String { + internal func measurementTime(from entry: WidgetEntry) -> String { let formatter = DateFormatter() formatter.locale = Locale.autoupdatingCurrent formatter.dateStyle = .none @@ -131,10 +133,10 @@ extension WidgetViewModel { } // MARK: - Private methods -extension WidgetViewModel { +extension WidgetViewModel { private func hasCloudSensors() -> Bool { - return appGroupDefaults?.bool(forKey: Constants.hasCloudSensorsKey.rawValue) ?? false + appGroupDefaults?.bool(forKey: Constants.hasCloudSensorsKey.rawValue) ?? false } private func getAppSettings() -> MeasurementServiceSettings { @@ -156,7 +158,8 @@ extension WidgetViewModel { private func getLanguage() -> Language { let languageCode = Bundle.main.preferredLocalizations[0] guard - let language = Language(rawValue: languageCode) else { + let language = Language(rawValue: languageCode) + else { return .english } return language diff --git a/ruuvi-widgets/View/EmptyWidgetView.swift b/ruuvi-widgets/View/EmptyWidgetView.swift index 836613b51..815c6a6d1 100644 --- a/ruuvi-widgets/View/EmptyWidgetView.swift +++ b/ruuvi-widgets/View/EmptyWidgetView.swift @@ -9,6 +9,7 @@ struct EmptyWidgetView: View { let messageInline = "Widgets.Unconfigured.Inline.message" let loading = "Widgets.Loading.message" } + private let texts = Texts() var entry: WidgetProvider.Entry @@ -42,9 +43,9 @@ struct EmptyWidgetView: View { .cornerRadius(8) VStack { Text(entry.config.ruuviWidgetTag == nil ? - (isSimple ? texts.messageSimple.localized : + (isSimple ? texts.messageSimple.localized : texts.messageRectangular.localized) - : texts.loading.localized) + : texts.loading.localized) .font(.custom(Constants.muliBold.rawValue, size: family == .systemSmall ? 16 : 10, relativeTo: .subheadline)) @@ -74,7 +75,7 @@ struct EmptyWidgetView: View { bottom: -4, trailing: 8)) Text(entry.config.ruuviWidgetTag == nil ? - texts.messageCircular.localized : texts.loading.localized) + texts.messageCircular.localized : texts.loading.localized) .font(.custom(Constants.muliBold.rawValue, size: 8, relativeTo: .headline)) @@ -94,7 +95,7 @@ struct EmptyWidgetView: View { Color.backgroundColor.edgesIgnoringSafeArea(.all) } Text(entry.config.ruuviWidgetTag == nil ? - texts.messageInline.localized : texts.loading.localized) + texts.messageInline.localized : texts.loading.localized) } } } diff --git a/ruuvi-widgets/View/SimpleWidgetView.swift b/ruuvi-widgets/View/SimpleWidgetView.swift index ab9b1605a..d6b3cacd4 100644 --- a/ruuvi-widgets/View/SimpleWidgetView.swift +++ b/ruuvi-widgets/View/SimpleWidgetView.swift @@ -34,7 +34,8 @@ struct SimpleWidgetView: View { .font(.custom( Constants.muliBold.rawValue, size: canShowBackground ? 16 : 22, - relativeTo: .headline) + relativeTo: .headline + ) ) .frame(maxWidth: .infinity, alignment: .leading) .fixedSize(horizontal: false, vertical: true) @@ -43,8 +44,8 @@ struct SimpleWidgetView: View { HStack(spacing: 2) { Text(viewModel.getValue(from: entry.record, - settings: entry.settings, - config: entry.config)) + settings: entry.settings, + config: entry.config)) .environment(\.locale, viewModel.locale()) .foregroundColor(.bodyTextColor) .font(.custom(Constants.oswaldBold.rawValue, @@ -69,9 +70,9 @@ struct SimpleWidgetView: View { extension EnvironmentValues { var canShowWidgetContainerBackground: Bool { if #available(iOSApplicationExtension 15.0, *) { - return self.showsWidgetContainerBackground + self.showsWidgetContainerBackground } else { - return false + false } } } diff --git a/ruuvi-widgets/View/SimpleWidgetViewCircular.swift b/ruuvi-widgets/View/SimpleWidgetViewCircular.swift index 656377cc1..2ee89931a 100644 --- a/ruuvi-widgets/View/SimpleWidgetViewCircular.swift +++ b/ruuvi-widgets/View/SimpleWidgetViewCircular.swift @@ -19,13 +19,13 @@ struct SimpleWidgetViewCircular: View { Text(viewModel.getValue(from: entry.record, settings: entry.settings, config: entry.config)) - .environment(\.locale, viewModel.locale()) - .foregroundColor(.white) - .font(.custom(Constants.oswaldBold.rawValue, - size: 18, - relativeTo: .subheadline)) - .minimumScaleFactor(0.6) - .padding(.top, -4) + .environment(\.locale, viewModel.locale()) + .foregroundColor(.white) + .font(.custom(Constants.oswaldBold.rawValue, + size: 18, + relativeTo: .subheadline)) + .minimumScaleFactor(0.6) + .padding(.top, -4) Text(viewModel.getUnit(for: WidgetSensorEnum( rawValue: entry.config.sensor.rawValue))) diff --git a/ruuvi-widgets/View/SimpleWidgetViewRectangle.swift b/ruuvi-widgets/View/SimpleWidgetViewRectangle.swift index 17c64fbd4..1c19bce89 100644 --- a/ruuvi-widgets/View/SimpleWidgetViewRectangle.swift +++ b/ruuvi-widgets/View/SimpleWidgetViewRectangle.swift @@ -19,11 +19,11 @@ struct SimpleWidgetViewRectangle: View { Text(viewModel.getValue(from: entry.record, settings: entry.settings, config: entry.config)) - .environment(\.locale, viewModel.locale()) - .foregroundColor(.bodyTextColor) - .font(.custom(Constants.oswaldBold.rawValue, - size: 36, - relativeTo: .title)) + .environment(\.locale, viewModel.locale()) + .foregroundColor(.bodyTextColor) + .font(.custom(Constants.oswaldBold.rawValue, + size: 36, + relativeTo: .title)) Text(viewModel.getUnit(for: WidgetSensorEnum(rawValue: entry.config.sensor.rawValue))) .foregroundColor(Color.unitTextColor) .font(.custom(Constants.oswaldExtraLight.rawValue, @@ -33,11 +33,11 @@ struct SimpleWidgetViewRectangle: View { Spacer() } .padding(EdgeInsets(top: -20, - leading: 4, - bottom: 8, - trailing: 4)) + leading: 4, + bottom: 8, + trailing: 4)) } }.edgesIgnoringSafeArea(.all) - .widgetURL(URL(string: "\(entry.tag.identifier.unwrapped)")) + .widgetURL(URL(string: "\(entry.tag.identifier.unwrapped)")) } } diff --git a/ruuvi-widgets/View/UnauthorizedView.swift b/ruuvi-widgets/View/UnauthorizedView.swift index 9633a2894..97563af65 100644 --- a/ruuvi-widgets/View/UnauthorizedView.swift +++ b/ruuvi-widgets/View/UnauthorizedView.swift @@ -7,6 +7,7 @@ struct UnauthorizedView: View { let unauthorizedSmall = "SignIn.Title.text" let unauthorizedInline = "Widgets.Unauthorized.Inline.message" } + private let texts = Texts() var body: some View { diff --git a/station/Classes/Application/AppAssembly.swift b/station/Classes/Application/AppAssembly.swift index 495ef02f6..b257c2cbf 100644 --- a/station/Classes/Application/AppAssembly.swift +++ b/station/Classes/Application/AppAssembly.swift @@ -1,119 +1,119 @@ -// swiftlint:disable file_length -import Swinject -import Foundation import BTKit -import RuuviLocal -import RuuviPool +import Foundation +import RuuviCloud import RuuviContext -import RuuviStorage -import RuuviService +import RuuviCore +import RuuviDaemon import RuuviDFU +import RuuviDiscover +import RuuviFirmware +import RuuviLocal +import RuuviLocalization import RuuviMigration +import RuuviNotification +import RuuviNotifier import RuuviPersistence +import RuuviPool +import RuuviPresenters import RuuviReactor -import RuuviCloud -import RuuviUser -import RuuviDaemon -import RuuviLocalization -import RuuviNotifier -import RuuviNotification import RuuviRepository -import RuuviCore -import RuuviFirmware -import RuuviDiscover -import RuuviPresenters +import RuuviService +import RuuviStorage +import RuuviUser +// swiftlint:disable file_length +import Swinject #if canImport(RuuviCloudPure) -import RuuviCloudPure + import RuuviCloudPure #endif #if canImport(RuuviContextRealm) -import RuuviContextRealm + import RuuviContextRealm #endif #if canImport(RuuviContextSQLite) -import RuuviContextSQLite + import RuuviContextSQLite #endif #if canImport(RuuviPersistenceRealm) -import RuuviPersistenceRealm + import RuuviPersistenceRealm #endif #if canImport(RuuviPersistenceSQLite) -import RuuviPersistenceSQLite + import RuuviPersistenceSQLite #endif #if canImport(RuuviStorageCoordinator) -import RuuviStorageCoordinator + import RuuviStorageCoordinator #endif #if canImport(RuuviPoolCoordinator) -import RuuviPoolCoordinator + import RuuviPoolCoordinator #endif #if canImport(RuuviLocalUserDefaults) -import RuuviLocalUserDefaults + import RuuviLocalUserDefaults #endif #if canImport(RuuviPoolCoordinator) -import RuuviPoolCoordinator + import RuuviPoolCoordinator #endif #if canImport(RuuviReactorImpl) -import RuuviReactorImpl + import RuuviReactorImpl #endif #if canImport(RuuviDFUImpl) -import RuuviDFUImpl + import RuuviDFUImpl #endif #if canImport(RuuviMigrationImpl) -import RuuviMigrationImpl + import RuuviMigrationImpl #endif #if canImport(RuuviDaemonOperation) -import RuuviDaemonOperation + import RuuviDaemonOperation #endif #if canImport(RuuviDaemonBackground) -import RuuviDaemonBackground + import RuuviDaemonBackground #endif #if canImport(RuuviDaemonRuuviTag) -import RuuviDaemonRuuviTag + import RuuviDaemonRuuviTag #endif #if canImport(RuuviServiceGATT) -import RuuviServiceGATT + import RuuviServiceGATT #endif #if canImport(RuuviAnalytics) -import RuuviAnalytics + import RuuviAnalytics #endif #if canImport(RuuviAnalyticsImpl) -import RuuviAnalyticsImpl + import RuuviAnalyticsImpl #endif #if canImport(RuuviServiceExport) -import RuuviServiceExport + import RuuviServiceExport #endif #if canImport(RuuviNotifierImpl) -import RuuviNotifierImpl + import RuuviNotifierImpl #endif #if canImport(RuuviServiceFactory) -import RuuviServiceFactory + import RuuviServiceFactory #endif #if canImport(RuuviDaemonCloudSync) -import RuuviDaemonCloudSync + import RuuviDaemonCloudSync #endif #if canImport(RuuviRepositoryCoordinator) -import RuuviRepositoryCoordinator + import RuuviRepositoryCoordinator #endif #if canImport(RuuviUserCoordinator) -import RuuviUserCoordinator + import RuuviUserCoordinator #endif #if canImport(RuuviCoreLocation) -import RuuviCoreLocation + import RuuviCoreLocation #endif #if canImport(RuuviNotificationLocal) -import RuuviNotificationLocal + import RuuviNotificationLocal #endif #if canImport(RuuviCoreImage) -import RuuviCoreImage + import RuuviCoreImage #endif #if canImport(RuuviCoreLocation) -import RuuviCoreLocation + import RuuviCoreLocation #endif #if canImport(RuuviCorePN) -import RuuviCorePN + import RuuviCorePN #endif #if canImport(RuuviCorePermission) -import RuuviCorePermission + import RuuviCorePermission #endif #if canImport(RuuviServiceMeasurement) -import RuuviServiceMeasurement + import RuuviServiceMeasurement #endif final class AppAssembly { @@ -139,7 +139,7 @@ final class AppAssembly { private final class DfuAssembly: Assembly { func assemble(container: Container) { container.register(RuuviDFU.self) { _ in - return RuuviDFUImpl.shared + RuuviDFUImpl.shared }.inObjectScope(.container) } } @@ -202,7 +202,7 @@ private final class PersistenceAssembly: Assembly { }.inObjectScope(.container) container.register(RuuviPoolFactory.self) { _ in - return RuuviPoolFactoryCoordinator() + RuuviPoolFactoryCoordinator() } container.register(RuuviPool.self) { r in @@ -222,7 +222,7 @@ private final class PersistenceAssembly: Assembly { } container.register(RuuviReactorFactory.self) { _ in - return RuuviReactorFactoryImpl() + RuuviReactorFactoryImpl() } container.register(RuuviReactor.self) { r in @@ -285,13 +285,11 @@ private final class PersistenceAssembly: Assembly { let factory = r.resolve(SQLiteContextFactory.self)! return factory.create() }.inObjectScope(.container) - } } private final class NetworkingAssembly: Assembly { func assemble(container: Container) { - let appGroupDefaults = UserDefaults( suiteName: AppGroupConstants.appGroupSuiteIdentifier ) @@ -314,7 +312,7 @@ private final class NetworkingAssembly: Assembly { } container.register(RuuviCloudFactory.self) { _ in - return RuuviCloudFactoryPure() + RuuviCloudFactoryPure() } } } @@ -431,7 +429,7 @@ private final class BusinessAssembly: Assembly { service.ruuviUser = r.resolve(RuuviUser.self) service.backgroundProcessService = r.resolve(BackgroundProcessService.self) #if canImport(RuuviAnalytics) - service.userPropertiesService = r.resolve(RuuviAnalytics.self) + service.userPropertiesService = r.resolve(RuuviAnalytics.self) #endif service.universalLinkCoordinator = r.resolve(UniversalLinkCoordinator.self) return service @@ -491,7 +489,7 @@ private final class BusinessAssembly: Assembly { }.inObjectScope(.container) container.register(RuuviDaemonFactory.self) { _ in - return RuuviDaemonFactoryImpl() + RuuviDaemonFactoryImpl() } container.register(RuuviDaemonCloudSync.self) { r in @@ -507,7 +505,7 @@ private final class BusinessAssembly: Assembly { }.inObjectScope(.container) container.register(RuuviRepositoryFactory.self) { _ in - return RuuviRepositoryFactoryCoordinator() + RuuviRepositoryFactoryCoordinator() } container.register(RuuviRepository.self) { r in @@ -521,7 +519,7 @@ private final class BusinessAssembly: Assembly { } container.register(RuuviServiceFactory.self) { _ in - return RuuviServiceFactoryImpl() + RuuviServiceFactoryImpl() } container.register(RuuviServiceAlert.self) { r in @@ -647,7 +645,7 @@ private final class BusinessAssembly: Assembly { } container.register(RuuviUserFactory.self) { _ in - return RuuviUserFactoryCoordinator() + RuuviUserFactoryCoordinator() } container.register(RuuviUser.self) { r in @@ -656,19 +654,19 @@ private final class BusinessAssembly: Assembly { }.inObjectScope(.container) #if canImport(RuuviAnalytics) - container.register(RuuviAnalytics.self) { r in - let ruuviUser = r.resolve(RuuviUser.self)! - let ruuviStorage = r.resolve(RuuviStorage.self)! - let settings = r.resolve(RuuviLocalSettings.self)! - let alertService = r.resolve(RuuviServiceAlert.self)! - let service = RuuviAnalyticsImpl( - ruuviUser: ruuviUser, - ruuviStorage: ruuviStorage, - settings: settings, - alertService: alertService - ) - return service - } + container.register(RuuviAnalytics.self) { r in + let ruuviUser = r.resolve(RuuviUser.self)! + let ruuviStorage = r.resolve(RuuviStorage.self)! + let settings = r.resolve(RuuviLocalSettings.self)! + let alertService = r.resolve(RuuviServiceAlert.self)! + let service = RuuviAnalyticsImpl( + ruuviUser: ruuviUser, + ruuviStorage: ruuviStorage, + settings: settings, + alertService: alertService + ) + return service + } #endif container.register(UniversalLinkCoordinator.self, factory: { r in let coordinator = UniversalLinkCoordinatorImpl() @@ -698,14 +696,13 @@ private final class BusinessAssembly: Assembly { } private final class CoreAssembly: Assembly { - func assemble(container: Container) { container.register(BTForeground.self) { _ in - return BTKit.foreground + BTKit.foreground }.inObjectScope(.container) container.register(BTBackground.self) { _ in - return BTKit.background + BTKit.background }.inObjectScope(.container) container.register(InfoProvider.self) { _ in @@ -744,7 +741,7 @@ private final class CoreAssembly: Assembly { } container.register(RuuviCoreImage.self) { _ in - return RuuviCoreImageImpl() + RuuviCoreImageImpl() } container.register(RuuviServiceMeasurement.self, factory: { r in diff --git a/station/Classes/Application/AppAssemblyConstants.swift b/station/Classes/Application/AppAssemblyConstants.swift index f842cc017..a01aa429d 100644 --- a/station/Classes/Application/AppAssemblyConstants.swift +++ b/station/Classes/Application/AppAssemblyConstants.swift @@ -6,7 +6,7 @@ struct Networking: Codable { var RuuviCloudURLDev: String } -final class AppAssemblyConstants { +enum AppAssemblyConstants { static let networkingPath = Bundle.main.path(forResource: "Networking", ofType: "plist")! static let xml = FileManager.default.contents(atPath: networkingPath)! static let networkingPlist = try! PropertyListDecoder().decode(Networking.self, from: xml) diff --git a/station/Classes/Application/AppDelegate.swift b/station/Classes/Application/AppDelegate.swift index 871230e57..29308149a 100644 --- a/station/Classes/Application/AppDelegate.swift +++ b/station/Classes/Application/AppDelegate.swift @@ -1,20 +1,20 @@ -import UIKit import FirebaseCore import FirebaseMessaging +import UIKit #if DEBUG && canImport(FLEX) -import FLEX + import FLEX #endif -import UserNotifications -import RuuviLocal +import RuuviContext import RuuviCore -import RuuviNotification +import RuuviLocal +import RuuviLocalization import RuuviMigration -import RuuviContext -import RuuviService +import RuuviNotification import RuuviOntology -import RuuviLocalization +import RuuviService +import UserNotifications -@UIApplicationMain +@main class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? var appStateService: AppStateService! @@ -28,9 +28,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { private var appRouter: AppRouter? func application(_ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool + { let r = AppAssembly.shared.assembler.resolver - self.settings = r.resolve(RuuviLocalSettings.self) + settings = r.resolve(RuuviLocalSettings.self) setPreferrerdLanguage() FirebaseApp.configure() @@ -48,7 +49,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { .migrateIfNeeded() r.resolve(RuuviMigrationFactory.self)? .createAllOrdered() - .forEach({ $0.migrateIfNeeded() }) + .forEach { $0.migrateIfNeeded() } appStateService = r.resolve(AppStateService.self) appStateService.application(application, didFinishLaunchingWithOptions: launchOptions) @@ -64,20 +65,20 @@ class AppDelegate: UIResponder, UIApplicationDelegate { cloudNotificationService = r.resolve(RuuviServiceCloudNotification.self) #if DEBUG && canImport(FLEX) - FLEXManager.shared.registerGlobalEntry( - withName: "Feature Toggles", - viewControllerFutureBlock: { r.resolve(FeatureTogglesViewController.self) ?? UIViewController() - } - ) + FLEXManager.shared.registerGlobalEntry( + withName: "Feature Toggles", + viewControllerFutureBlock: { r.resolve(FeatureTogglesViewController.self) ?? UIViewController() + } + ) #endif - self.window = UIWindow(frame: UIScreen.main.bounds) + window = UIWindow(frame: UIScreen.main.bounds) let appRouter = AppRouter() appRouter.settings = r.resolve(RuuviLocalSettings.self) - self.window?.rootViewController = appRouter.viewController - self.window?.makeKeyAndVisible() + window?.rootViewController = appRouter.viewController + window?.makeKeyAndVisible() self.appRouter = appRouter - self.window?.overrideUserInterfaceStyle = settings.theme.uiInterfaceStyle + window?.overrideUserInterfaceStyle = settings.theme.uiInterfaceStyle return true } @@ -98,17 +99,17 @@ class AppDelegate: UIResponder, UIApplicationDelegate { appStateService.applicationDidBecomeActive(application) } - func application(_ application: UIApplication, - supportedInterfaceOrientationsFor window: UIWindow? - ) -> UIInterfaceOrientationMask { - return orientationLock - } + func application(_: UIApplication, + supportedInterfaceOrientationsFor _: UIWindow?) -> UIInterfaceOrientationMask + { + orientationLock + } } // MARK: - Push Notifications -extension AppDelegate { - func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { +extension AppDelegate { + func application(_: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { Messaging.messaging().apnsToken = deviceToken pnManager.pnTokenData = deviceToken @@ -117,14 +118,14 @@ extension AppDelegate { } } - func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { + func application(_: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { print(error.localizedDescription) } } extension AppDelegate: MessagingDelegate { func messaging( - _ messaging: Messaging, + _: Messaging, didReceiveRegistrationToken fcmToken: String? ) { register(with: fcmToken) @@ -132,8 +133,9 @@ extension AppDelegate: MessagingDelegate { private func register(with fcmToken: String?) { guard !UIDevice.isSimulator, - let fcmToken = fcmToken, - cloudNotificationService != nil else { + let fcmToken, + cloudNotificationService != nil + else { return } @@ -146,7 +148,8 @@ extension AppDelegate: MessagingDelegate { fileprivate func setPreferrerdLanguage() { if let languageCode = Bundle.main.preferredLocalizations.first, - let language = Language(rawValue: languageCode) { + let language = Language(rawValue: languageCode) + { if settings.language != language { settings.language = language } @@ -154,17 +157,19 @@ extension AppDelegate: MessagingDelegate { settings.language = .english } } - } // MARK: - UniversalLins + extension AppDelegate { func application(_ application: UIApplication, continue userActivity: NSUserActivity, - restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { + restorationHandler _: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool + { guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, - let url = userActivity.webpageURL else { - return false + let url = userActivity.webpageURL + else { + return false } appStateService.applicationDidOpenWithUniversalLink(application, url: url) return true @@ -172,10 +177,12 @@ extension AppDelegate { } // MARK: - Widget Deeplink Handler + extension AppDelegate { func application(_ app: UIApplication, open url: URL, - options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { + options _: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool + { let macId = url.absoluteString openSelectedCard(for: macId, application: app) return true @@ -183,6 +190,7 @@ extension AppDelegate { } // MARK: - Notification tap handler + extension AppDelegate: RuuviNotificationLocalOutput { func notificationDidTap(for uuid: String) { openSelectedCard(for: uuid) @@ -192,12 +200,14 @@ extension AppDelegate: RuuviNotificationLocalOutput { // TODO: - SEE IF WE CAN MOVE THIS TO APP_STATE_SERVICE extension AppDelegate { private func openSelectedCard(for uuid: String, - application: UIApplication? = nil) { + application _: UIApplication? = nil) + { appRouter?.prepareRootViewControllerWidgets() window?.rootViewController = appRouter?.viewController if let navigationController = appRouter?.viewController as? UINavigationController, - let controller = navigationController.viewControllers.last as? DashboardViewController { + let controller = navigationController.viewControllers.last as? DashboardViewController + { if let viewModel = controller.viewModels.first(where: { viewModel in viewModel.mac.value?.value == uuid || viewModel.luid.value == uuid.luid.any }) { diff --git a/station/Classes/Application/AppGroupConstants.swift b/station/Classes/Application/AppGroupConstants.swift index 1e11ab5c9..14a751cbc 100644 --- a/station/Classes/Application/AppGroupConstants.swift +++ b/station/Classes/Application/AppGroupConstants.swift @@ -1,6 +1,6 @@ import Foundation -struct AppGroupConstants { +enum AppGroupConstants { static let appGroupSuiteIdentifier = "group.com.ruuvi.station.widgets" static let isAuthorizedUDKey = "RuuviUserCoordinator.isAuthorizedUDKey" static let hasCloudSensorsKey = "hasCloudSensorsKey" diff --git a/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift b/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift index e6ca74f8b..af57c64ac 100644 --- a/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift +++ b/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift @@ -1,13 +1,13 @@ -import UIKit -import RuuviLocal import RuuviDaemon -import RuuviUser +import RuuviLocal import RuuviOntology +import RuuviUser +import UIKit #if canImport(RuuviAnalytics) -import RuuviAnalytics + import RuuviAnalytics #endif #if canImport(WidgetKit) -import WidgetKit + import WidgetKit #endif class AppStateServiceImpl: AppStateService { @@ -19,12 +19,13 @@ class AppStateServiceImpl: AppStateService { var cloudSyncDaemon: RuuviDaemonCloudSync! var settings: RuuviLocalSettings! #if canImport(RuuviAnalytics) - var userPropertiesService: RuuviAnalytics! + var userPropertiesService: RuuviAnalytics! #endif var universalLinkCoordinator: UniversalLinkCoordinator! - func application(_ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) { + func application(_: UIApplication, + didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) + { if settings.isAdvertisementDaemonOn { advertisementDaemon.start() } @@ -43,22 +44,22 @@ class AppStateServiceImpl: AppStateService { settings.appIsOnForeground = true observeWidgetKind() #if canImport(RuuviAnalytics) - DispatchQueue.main.async { - self.userPropertiesService.update() - } - settings.appOpenedCount += 1 + DispatchQueue.main.async { + self.userPropertiesService.update() + } + settings.appOpenedCount += 1 #endif } - func applicationWillResignActive(_ application: UIApplication) { + func applicationWillResignActive(_: UIApplication) { // do nothing yet } - func applicationDidBecomeActive(_ application: UIApplication) { + func applicationDidBecomeActive(_: UIApplication) { // do nothing yet } - func applicationDidEnterBackground(_ application: UIApplication) { + func applicationDidEnterBackground(_: UIApplication) { if settings.isAdvertisementDaemonOn { advertisementDaemon.stop() } @@ -71,7 +72,7 @@ class AppStateServiceImpl: AppStateService { settings.appIsOnForeground = false } - func applicationWillEnterForeground(_ application: UIApplication) { + func applicationWillEnterForeground(_: UIApplication) { if settings.isAdvertisementDaemonOn { advertisementDaemon.start() } @@ -82,20 +83,20 @@ class AppStateServiceImpl: AppStateService { settings.appIsOnForeground = true } - func applicationDidOpenWithUniversalLink(_ application: UIApplication, url: URL) { + func applicationDidOpenWithUniversalLink(_: UIApplication, url: URL) { universalLinkCoordinator.processUniversalLink(url: url) } - func applicationDidOpenWithWidgetDeepLink(_ application: UIApplication, macId: String) { + func applicationDidOpenWithWidgetDeepLink(_: UIApplication, macId: String) { universalLinkCoordinator.processWidgetLink(macId: macId) } } -extension AppStateServiceImpl { - fileprivate func observeWidgetKind() { +private extension AppStateServiceImpl { + func observeWidgetKind() { WidgetCenter.shared.getCurrentConfigurations { [weak self] widgetInfos in - guard case .success(let infos) = widgetInfos else { return } - let simpleWidgets = infos.filter({ $0.kind == AppAssemblyConstants.simpleWidgetKindId }) + guard case let .success(infos) = widgetInfos else { return } + let simpleWidgets = infos.filter { $0.kind == AppAssemblyConstants.simpleWidgetKindId } self?.settings.useSimpleWidget = simpleWidgets.count > 0 } } diff --git a/station/Classes/Application/Features/FeatureToggleService.swift b/station/Classes/Application/Features/FeatureToggleService.swift index cf178a61b..294cc0087 100644 --- a/station/Classes/Application/Features/FeatureToggleService.swift +++ b/station/Classes/Application/Features/FeatureToggleService.swift @@ -4,9 +4,9 @@ public final class FeatureToggleService { public var source: FeatureSource { get { if let rawValue = UserDefaults.standard.string(forKey: sourceUDKey) { - return FeatureSource(rawValue: rawValue) ?? .remote + FeatureSource(rawValue: rawValue) ?? .remote } else { - return .remote + .remote } } set { @@ -21,10 +21,11 @@ public final class FeatureToggleService { private var remoteToggles: [FeatureToggle] { get { if let storedRemoteToggles = UserDefaults.standard.object(forKey: remoteTogglesUDKey) as? Data, - let toggles = try? JSONDecoder().decode([FeatureToggle].self, from: storedRemoteToggles) { - return toggles + let toggles = try? JSONDecoder().decode([FeatureToggle].self, from: storedRemoteToggles) + { + toggles } else { - return [] + [] } } set { @@ -34,6 +35,7 @@ public final class FeatureToggleService { } } } + private var localToggles: [FeatureToggle] = [] private let sourceUDKey = "FeatureToggleService.sourceUDKey" private let remoteTogglesUDKey = "FeatureToggleService.remoteTogglesUDKey" diff --git a/station/Classes/Application/Features/Providers/FallbackFeatureToggleProvider.swift b/station/Classes/Application/Features/Providers/FallbackFeatureToggleProvider.swift index e55dfc0e3..cdabe3873 100644 --- a/station/Classes/Application/Features/Providers/FallbackFeatureToggleProvider.swift +++ b/station/Classes/Application/Features/Providers/FallbackFeatureToggleProvider.swift @@ -15,16 +15,19 @@ extension FallbackFeatureToggleProvider { static func loadConfiguration() -> [FeatureToggle]? { guard let configurationURL = bundledConfigurationURL(), - let data = try? Data(contentsOf: configurationURL) else { + let data = try? Data(contentsOf: configurationURL) + else { return nil } return parseConfiguration(data: data) } + static func parseConfiguration(data: Data) -> ParsingServiceResult? { - return JSONParsingService().parse(data, containerName: jsonContainerName) + JSONParsingService().parse(data, containerName: jsonContainerName) } + static func bundledConfigurationURL() -> URL? { - return Bundle.main.url(forResource: configurationName, withExtension: configurationType) + Bundle.main.url(forResource: configurationName, withExtension: configurationType) } } @@ -33,15 +36,17 @@ typealias ParsingServiceResult = [FeatureToggle] protocol ParsingService { func parse(_ data: Data, containerName: String) -> ParsingServiceResult? } + public struct JSONParsingService: ParsingService { func parse(_ data: Data, containerName: String) -> ParsingServiceResult? { var toggleData = data if let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments), - let jsonContainer = json as? [String: Any], - let featureToggles = jsonContainer[containerName], - let featureTogglesData = try? JSONSerialization.data(withJSONObject: featureToggles) { - toggleData = featureTogglesData + let jsonContainer = json as? [String: Any], + let featureToggles = jsonContainer[containerName], + let featureTogglesData = try? JSONSerialization.data(withJSONObject: featureToggles) + { + toggleData = featureTogglesData } return try? JSONDecoder().decode([FeatureToggle].self, from: toggleData) diff --git a/station/Classes/Application/Features/Providers/FirebaseFeatureToggleProvider.swift b/station/Classes/Application/Features/Providers/FirebaseFeatureToggleProvider.swift index c52f0e01a..eaf65b97a 100644 --- a/station/Classes/Application/Features/Providers/FirebaseFeatureToggleProvider.swift +++ b/station/Classes/Application/Features/Providers/FirebaseFeatureToggleProvider.swift @@ -1,5 +1,5 @@ -import Foundation import FirebaseRemoteConfig +import Foundation public final class FirebaseFeatureToggleProvider: FeatureToggleProvider { var remoteConfigService: RemoteConfigService! @@ -13,21 +13,20 @@ public final class FirebaseFeatureToggleProvider: FeatureToggleProvider { let keys = remoteConfig.allKeys(from: .remote) let featureToggles: [FeatureToggle] = keys.compactMap { if let feature = Feature(rawValue: $0) { - return FeatureToggle( + FeatureToggle( feature: feature, enabled: remoteConfig[$0].boolValue, source: .remote ) } else { - return nil + nil } } completion(featureToggles) - case .failure(let error): + case let .failure(error): print(error.localizedDescription) completion([]) } } - } } diff --git a/station/Classes/Application/Features/RemoteConfig/Firebase/FirebaseRemoteConfigService.swift b/station/Classes/Application/Features/RemoteConfig/Firebase/FirebaseRemoteConfigService.swift index c43d1cd01..df278773f 100644 --- a/station/Classes/Application/Features/RemoteConfig/Firebase/FirebaseRemoteConfigService.swift +++ b/station/Classes/Application/Features/RemoteConfig/Firebase/FirebaseRemoteConfigService.swift @@ -1,5 +1,5 @@ -import Foundation import FirebaseRemoteConfig +import Foundation final class FirebaseRemoteConfigService: RemoteConfigService { let remoteConfig = RemoteConfig.remoteConfig() @@ -13,7 +13,7 @@ final class FirebaseRemoteConfigService: RemoteConfigService { case .successFetchedFromRemote, .successUsingPreFetchedData: completion?(.success(true)) case .error: - if let error = error { + if let error { completion?(.failure(error)) } else { completion?(.success(false)) diff --git a/station/Classes/Application/Features/RemoteConfig/RemoteConfigService.swift b/station/Classes/Application/Features/RemoteConfig/RemoteConfigService.swift index c5f476b7d..1a8e4e692 100644 --- a/station/Classes/Application/Features/RemoteConfig/RemoteConfigService.swift +++ b/station/Classes/Application/Features/RemoteConfig/RemoteConfigService.swift @@ -1,5 +1,5 @@ -import Foundation import FirebaseRemoteConfig +import Foundation protocol RemoteConfigService { var remoteConfig: RemoteConfig { get } diff --git a/station/Classes/Application/Info/Impl/InfoProviderImpl.swift b/station/Classes/Application/Info/Impl/InfoProviderImpl.swift index e9756c22b..818da833f 100644 --- a/station/Classes/Application/Info/Impl/InfoProviderImpl.swift +++ b/station/Classes/Application/Info/Impl/InfoProviderImpl.swift @@ -1,11 +1,11 @@ -import UIKit -import Photos import CoreLocation +import Photos +import UIKit import UserNotifications class InfoProviderImpl: InfoProvider { var deviceModel: String { - return UIDevice.modelName + UIDevice.modelName } var appVersion: String { @@ -15,15 +15,15 @@ class InfoProviderImpl: InfoProvider { } var appName: String { - return Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String ?? "unknown|" + Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String ?? "unknown|" } var systemName: String { - return UIDevice.current.systemName + UIDevice.current.systemName } var systemVersion: String { - return UIDevice.current.systemVersion + UIDevice.current.systemVersion } var locationPermission: String { @@ -67,20 +67,20 @@ class InfoProviderImpl: InfoProvider { var cameraPermission: String { var result = "Camera: " #if targetEnvironment(macCatalyst) - result += "unknown" - #else - switch AVCaptureDevice.authorizationStatus(for: .video) { - case .authorized: - result += "authorized" - case .denied: - result += "denied" - case .notDetermined: - result += notDetermined - case .restricted: - result += "restricted" - @unknown default: result += "unknown" - } + #else + switch AVCaptureDevice.authorizationStatus(for: .video) { + case .authorized: + result += "authorized" + case .denied: + result += "denied" + case .notDetermined: + result += notDetermined + case .restricted: + result += "restricted" + @unknown default: + result += "unknown" + } #endif return result } @@ -102,7 +102,7 @@ class InfoProviderImpl: InfoProvider { result += cameraPermission + "\n" result += "Notifications: " - UNUserNotificationCenter.current().getNotificationSettings { (settings) in + UNUserNotificationCenter.current().getNotificationSettings { settings in DispatchQueue.main.async { switch settings.authorizationStatus { case .authorized: @@ -123,5 +123,4 @@ class InfoProviderImpl: InfoProvider { } } } - } diff --git a/station/Classes/Application/UniversalLinks/Coordinator/Impl/UniversalLinkCoordinatormpl.swift b/station/Classes/Application/UniversalLinks/Coordinator/Impl/UniversalLinkCoordinatormpl.swift index 43a3ef397..1898a1d1a 100644 --- a/station/Classes/Application/UniversalLinks/Coordinator/Impl/UniversalLinkCoordinatormpl.swift +++ b/station/Classes/Application/UniversalLinks/Coordinator/Impl/UniversalLinkCoordinatormpl.swift @@ -1,6 +1,6 @@ -import UIKit -import RuuviUser import RuuviLocal +import RuuviUser +import UIKit enum UniversalLinkType: String { case verify = "/verify" @@ -9,9 +9,9 @@ enum UniversalLinkType: String { var handlerType: UIViewController.Type { switch self { case .verify: - return SignInViewController.self + SignInViewController.self case .dashboard: - return DashboardViewController.self + DashboardViewController.self } } } @@ -23,13 +23,15 @@ class UniversalLinkCoordinatorImpl { private var urlComponents: URLComponents! } + // MARK: - UniversalLinkInteractorInput extension UniversalLinkCoordinatorImpl: UniversalLinkCoordinator { func processUniversalLink(url: URL) { guard let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false), - let path = UniversalLinkType(rawValue: urlComponents.path) else { + let path = UniversalLinkType(rawValue: urlComponents.path) + else { return } self.urlComponents = urlComponents @@ -47,7 +49,6 @@ extension UniversalLinkCoordinatorImpl: UniversalLinkCoordinator { // MARK: - Private extension UniversalLinkCoordinatorImpl { - private func detectViewController(for path: UniversalLinkType) { DispatchQueue.main.async { [weak self] in guard let topViewController = UIApplication.shared.topViewController() else { @@ -68,29 +69,30 @@ extension UniversalLinkCoordinatorImpl { private func openVerify(from topViewController: UIViewController) { guard let token = urlComponents.queryItems? - .first(where: { $0.name == "token" })? - .value, - !ruuviUser.isAuthorized else { - NotificationCenter.default.post(name: .DidOpenWithUniversalLink, - object: nil, - userInfo: nil) + .first(where: { $0.name == "token" })? + .value, + !ruuviUser.isAuthorized + else { + NotificationCenter.default.post(name: .DidOpenWithUniversalLink, + object: nil, + userInfo: nil) return } router.openSignInVerify(with: token, from: topViewController) } - private func openDashboard(from topViewController: UIViewController) { + private func openDashboard(from _: UIViewController) { // No action needed here since root view controller is dashboard, and // we will be opening dashboard anyway on deeplink tap. } private func postNotification(with path: UniversalLinkType) { var userInfo: [String: Any] = [ - "path": path + "path": path, ] - urlComponents.queryItems?.forEach({ + urlComponents.queryItems?.forEach { userInfo[$0.name] = $0.value - }) + } NotificationCenter.default.post(name: .DidOpenWithUniversalLink, object: nil, userInfo: userInfo) diff --git a/station/Classes/Application/UniversalLinks/Router/Impl/UniversalLinkRouterImpl.swift b/station/Classes/Application/UniversalLinks/Router/Impl/UniversalLinkRouterImpl.swift index c82e7ed91..9616996bf 100644 --- a/station/Classes/Application/UniversalLinks/Router/Impl/UniversalLinkRouterImpl.swift +++ b/station/Classes/Application/UniversalLinks/Router/Impl/UniversalLinkRouterImpl.swift @@ -1,5 +1,5 @@ -import UIKit import LightRoute +import UIKit class UniversalLinkRouterImpl: UniversalLinkRouter { func openSignInVerify(with code: String, from transitionHandler: TransitionHandler) { diff --git a/station/Classes/Application/UniversalLinks/Router/UniversalLinkRouter.swift b/station/Classes/Application/UniversalLinks/Router/UniversalLinkRouter.swift index b613f8a00..7ba32f08d 100644 --- a/station/Classes/Application/UniversalLinks/Router/UniversalLinkRouter.swift +++ b/station/Classes/Application/UniversalLinks/Router/UniversalLinkRouter.swift @@ -1,5 +1,5 @@ -import UIKit import LightRoute +import UIKit protocol UniversalLinkRouter { func openSignInVerify(with code: String, from transitionHandler: TransitionHandler) diff --git a/station/Classes/Presentation/Assembly/PresentationAssembly.swift b/station/Classes/Presentation/Assembly/PresentationAssembly.swift index e4d2aef23..2dfec48f1 100644 --- a/station/Classes/Presentation/Assembly/PresentationAssembly.swift +++ b/station/Classes/Presentation/Assembly/PresentationAssembly.swift @@ -1,6 +1,6 @@ -import Swinject import RuuviCore import RuuviPresenters +import Swinject class PresentationAssembly: Assembly { func assemble(container: Container) { diff --git a/station/Classes/Presentation/Assembly/PresentationConstants.swift b/station/Classes/Presentation/Assembly/PresentationConstants.swift index 506def0ff..944e62be6 100644 --- a/station/Classes/Presentation/Assembly/PresentationConstants.swift +++ b/station/Classes/Presentation/Assembly/PresentationConstants.swift @@ -5,7 +5,7 @@ struct Presentation: Codable { var FeedbackSubject: String } -final class PresentationConstants { +enum PresentationConstants { static let presentationPath = Bundle.main.path(forResource: "Presentation", ofType: "plist")! static let xml = FileManager.default.contents(atPath: presentationPath)! static let presentationPlist = try! PropertyListDecoder().decode(Presentation.self, from: xml) diff --git a/station/Classes/Presentation/Binding/NSObject+Observable.swift b/station/Classes/Presentation/Binding/NSObject+Observable.swift index 41a145203..015dbdbff 100644 --- a/station/Classes/Presentation/Binding/NSObject+Observable.swift +++ b/station/Classes/Presentation/Binding/NSObject+Observable.swift @@ -1,19 +1,18 @@ import Foundation extension NSObjectProtocol where Self: NSObject { - func bind(_ observable: Observable, fire: Bool = true, - block: @escaping (Self, T.WrappedType?) -> Void) { + block: @escaping (Self, T.WrappedType?) -> Void) + { if fire { block(self, observable.value) } - observable.bind { [weak self] _, value in + observable.bind { [weak self] _, value in DispatchQueue.main.async { [weak self] in guard let sSelf = self else { return } block(sSelf, value) } } } - } diff --git a/station/Classes/Presentation/Binding/Observable.swift b/station/Classes/Presentation/Binding/Observable.swift index 5823e1a21..a15cfef37 100644 --- a/station/Classes/Presentation/Binding/Observable.swift +++ b/station/Classes/Presentation/Binding/Observable.swift @@ -17,11 +17,11 @@ class Observable { } func bind(observer: @escaping Observer) { - self.observers.append(observer) + observers.append(observer) } private func notifyObservers(_ value: ObservedType.WrappedType?) { - self.observers.forEach { [unowned self] (observer) in + observers.forEach { [unowned self] observer in observer(self, value) } } diff --git a/station/Classes/Presentation/Binding/Optional.swift b/station/Classes/Presentation/Binding/Optional.swift index b429ecc67..82d610e7c 100644 --- a/station/Classes/Presentation/Binding/Optional.swift +++ b/station/Classes/Presentation/Binding/Optional.swift @@ -7,22 +7,23 @@ public protocol OptionalType: ExpressibleByNilLiteral { extension Optional: OptionalType { public var asOptional: Wrapped? { - return self + self } } -extension Optional where Wrapped == Bool { +extension Bool? { var _bound: Bool? { get { - return self + self } set { self = newValue } } + public var bound: Bool { get { - return _bound ?? true + _bound ?? true } set { _bound = newValue @@ -30,18 +31,19 @@ extension Optional where Wrapped == Bool { } } -extension Optional where Wrapped == Int { +extension Int? { var _bound: Int? { get { - return self + self } set { self = newValue } } + public var bound: Int { get { - return _bound ?? 0 + _bound ?? 0 } set { _bound = newValue @@ -49,18 +51,19 @@ extension Optional where Wrapped == Int { } } -extension Optional where Wrapped == String { +extension String? { var _bound: String? { get { - return self + self } set { self = newValue } } + public var bound: String { get { - return _bound ?? "" + _bound ?? "" } set { _bound = newValue @@ -68,18 +71,19 @@ extension Optional where Wrapped == String { } } -extension Optional where Wrapped == Double { +extension Double? { var _bound: Double? { get { - return self + self } set { self = newValue } } + public var bound: Double { get { - return _bound ?? 0.0 + _bound ?? 0.0 } set { _bound = newValue diff --git a/station/Classes/Presentation/Colors/RuuviColor.swift b/station/Classes/Presentation/Colors/RuuviColor.swift index ce6070a8a..75c0ca8a3 100644 --- a/station/Classes/Presentation/Colors/RuuviColor.swift +++ b/station/Classes/Presentation/Colors/RuuviColor.swift @@ -1,6 +1,6 @@ import SwiftUI -struct RuuviColor { +enum RuuviColor { static let purple = Color("RuuviPurple") static let green = Color("RuuviGreen") static let dustyBlue = Color("RuuviDustyBlue") diff --git a/station/Classes/Presentation/Contract/ViewInput.swift b/station/Classes/Presentation/Contract/ViewInput.swift index 5e241e176..1ea26e9a7 100644 --- a/station/Classes/Presentation/Contract/ViewInput.swift +++ b/station/Classes/Presentation/Contract/ViewInput.swift @@ -1,4 +1,3 @@ import Foundation -protocol ViewInput: AnyObject { -} +protocol ViewInput: AnyObject {} diff --git a/station/Classes/Presentation/FLEX/FeatureTogglesViewController.swift b/station/Classes/Presentation/FLEX/FeatureTogglesViewController.swift index aefad6bb5..732492390 100644 --- a/station/Classes/Presentation/FLEX/FeatureTogglesViewController.swift +++ b/station/Classes/Presentation/FLEX/FeatureTogglesViewController.swift @@ -4,14 +4,14 @@ final class FeatureTogglesViewController: UITableViewController { var featureToggleService: FeatureToggleService! init() { - self.headerView = UIView() - self.sourceSwitch = RuuviUISwitch() - self.sourceLabel = Self.makeSourceLabel() + headerView = UIView() + sourceSwitch = RuuviUISwitch() + sourceLabel = Self.makeSourceLabel() super.init(nibName: nil, bundle: nil) } @available(*, unavailable) - required init?(coder: NSCoder) { + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -22,31 +22,31 @@ final class FeatureTogglesViewController: UITableViewController { private static let featureCellReuseIdentifier = "FeatureCellReuseIdentifier" private func setupViews() { - self.view.backgroundColor = RuuviColor.ruuviPrimary - self.headerView.addSubview(self.sourceSwitch) - self.headerView.addSubview(self.sourceLabel) - self.tableView.tableHeaderView = self.headerView - self.sourceSwitch.addTarget(self, action: #selector(sourceSwitchValueChanged(_:)), for: .valueChanged) + view.backgroundColor = RuuviColor.ruuviPrimary + headerView.addSubview(sourceSwitch) + headerView.addSubview(sourceLabel) + tableView.tableHeaderView = headerView + sourceSwitch.addTarget(self, action: #selector(sourceSwitchValueChanged(_:)), for: .valueChanged) } @objc - private func sourceSwitchValueChanged(_ sender: Any) { - if self.sourceSwitch.isOn { - self.featureToggleService.source = .local + private func sourceSwitchValueChanged(_: Any) { + if sourceSwitch.isOn { + featureToggleService.source = .local } else { - self.featureToggleService.source = .remote + featureToggleService.source = .remote } - self.tableView.reloadData() + tableView.reloadData() } private func layoutViews() { - let headerView = self.headerView + let headerView = headerView - let sourceSwitch = self.sourceSwitch + let sourceSwitch = sourceSwitch sourceSwitch.onTintColor = .clear sourceSwitch.thumbTintColor = RuuviColor.ruuviTintColor - let sourceLabel = self.sourceLabel + let sourceLabel = sourceLabel headerView.translatesAutoresizingMaskIntoConstraints = false sourceSwitch.translatesAutoresizingMaskIntoConstraints = false sourceLabel.translatesAutoresizingMaskIntoConstraints = false @@ -57,7 +57,7 @@ final class FeatureTogglesViewController: UITableViewController { sourceSwitch.leadingAnchor.constraint(equalTo: sourceLabel.trailingAnchor, constant: 8), sourceLabel.centerYAnchor.constraint(equalTo: sourceSwitch.centerYAnchor), sourceLabel.leadingAnchor.constraint(equalTo: headerView.leadingAnchor, constant: 8), - self.tableView.widthAnchor.constraint(equalTo: headerView.widthAnchor) + tableView.widthAnchor.constraint(equalTo: headerView.widthAnchor), ]) headerView.setNeedsLayout() @@ -66,46 +66,48 @@ final class FeatureTogglesViewController: UITableViewController { var frame = headerView.frame frame.size.height = height headerView.frame = frame - self.tableView.tableHeaderView = headerView + tableView.tableHeaderView = headerView } override func viewDidLoad() { super.viewDidLoad() - self.setupViews() - self.layoutViews() - self.sourceSwitch.isOn = self.featureToggleService.source == .local + setupViews() + layoutViews() + sourceSwitch.isOn = featureToggleService.source == .local } } // MARK: - UITableViewDelegate + extension FeatureTogglesViewController { override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) - guard self.sourceSwitch.isOn else { return } - let feature = self.features[indexPath.row] - if self.featureToggleService.isEnabled(feature) { - self.featureToggleService.disableLocal(feature) + guard sourceSwitch.isOn else { return } + let feature = features[indexPath.row] + if featureToggleService.isEnabled(feature) { + featureToggleService.disableLocal(feature) } else { - self.featureToggleService.enableLocal(feature) + featureToggleService.enableLocal(feature) } self.tableView.reloadData() } } // MARK: - UITableViewDataSource + extension FeatureTogglesViewController { - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return self.features.count + override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { + features.count } - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + override func tableView(_: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = UITableViewCell(style: .default, reuseIdentifier: Self.featureCellReuseIdentifier) cell.backgroundColor = .clear - let feature = self.features[indexPath.row] + let feature = features[indexPath.row] cell.textLabel?.text = Self.title(for: feature) cell.textLabel?.font = UIFont.Muli(.bold, size: 16) cell.textLabel?.textColor = RuuviColor.ruuviMenuTextColor - if self.featureToggleService.isEnabled(feature) { + if featureToggleService.isEnabled(feature) { cell.accessoryType = .checkmark cell.tintColor = RuuviColor.ruuviTintColor } else { @@ -116,16 +118,18 @@ extension FeatureTogglesViewController { } // MARK: - Helpers + extension FeatureTogglesViewController { private static func title(for feature: Feature) -> String { switch feature { case .legacyFirmwareUpdatePopup: - return "Legacy Firmware Update Alert" + "Legacy Firmware Update Alert" } } } // MARK: - Factory + extension FeatureTogglesViewController { private static func makeSourceLabel() -> UILabel { let label = UILabel() diff --git a/station/Classes/Presentation/Modules/About/Assembly/AboutInitializer.swift b/station/Classes/Presentation/Modules/About/Assembly/AboutInitializer.swift index f0bb1f2e6..ead14b936 100644 --- a/station/Classes/Presentation/Modules/About/Assembly/AboutInitializer.swift +++ b/station/Classes/Presentation/Modules/About/Assembly/AboutInitializer.swift @@ -1,7 +1,7 @@ import UIKit class AboutInitializer: NSObject { - @IBOutlet weak var viewController: AboutViewController! + @IBOutlet var viewController: AboutViewController! override func awakeFromNib() { super.awakeFromNib() diff --git a/station/Classes/Presentation/Modules/About/Presenter/AboutModuleInput.swift b/station/Classes/Presentation/Modules/About/Presenter/AboutModuleInput.swift index fbefbd42a..15d37d178 100644 --- a/station/Classes/Presentation/Modules/About/Presenter/AboutModuleInput.swift +++ b/station/Classes/Presentation/Modules/About/Presenter/AboutModuleInput.swift @@ -1,5 +1,3 @@ import Foundation -protocol AboutModuleInput: AnyObject { - -} +protocol AboutModuleInput: AnyObject {} diff --git a/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift b/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift index 7179d2ae5..43dcffad1 100644 --- a/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift +++ b/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift @@ -12,11 +12,12 @@ final class AboutPresenter: AboutModuleInput { var sqliteContext: SQLiteContext! private var viewModel: AboutViewModel { - return view.viewModel + view.viewModel } } // MARK: - AboutViewOutput + extension AboutPresenter: AboutViewOutput { func viewDidLoad() { syncViewModel() @@ -32,8 +33,8 @@ extension AboutPresenter: AboutViewOutput { } // MARK: - Private -extension AboutPresenter { +extension AboutPresenter { private func syncViewModel() { viewModel.version.value = appVersion obtainTagsCount() @@ -43,7 +44,8 @@ extension AboutPresenter { private var appVersion: NSMutableAttributedString? { guard let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String, - let buildVersion = Bundle.main.infoDictionary?["CFBundleVersion"] as? String else { + let buildVersion = Bundle.main.infoDictionary?["CFBundleVersion"] as? String + else { return nil } let changelogString = RuuviLocalization.changelog @@ -107,12 +109,13 @@ extension AboutPresenter { } func getSQLiteFileSize() -> Int64 { - return fileSize(at: sqliteContext.database.dbPath) + fileSize(at: sqliteContext.database.dbPath) } func fileSize(at path: String) -> Int64 { guard let attributes = try? FileManager.default.attributesOfItem(atPath: path), - let fileSize = attributes[FileAttributeKey.size] as? Int64 else { + let fileSize = attributes[FileAttributeKey.size] as? Int64 + else { return 0 } return fileSize diff --git a/station/Classes/Presentation/Modules/About/View/AboutViewController.swift b/station/Classes/Presentation/Modules/About/View/AboutViewController.swift index 8c964b011..0e7a05adc 100644 --- a/station/Classes/Presentation/Modules/About/View/AboutViewController.swift +++ b/station/Classes/Presentation/Modules/About/View/AboutViewController.swift @@ -4,20 +4,21 @@ import UIKit class AboutViewController: UIViewController { var output: AboutViewOutput! - @IBOutlet weak var headerTitleLabel: UILabel! - @IBOutlet weak var aboutTextView: UITextView! - @IBOutlet weak var versionLabel: UILabel! - @IBOutlet weak var addedTagsLabel: UILabel! - @IBOutlet weak var storedMeasurementsLabel: UILabel! - @IBOutlet weak var databaseSizeLable: UILabel! + @IBOutlet var headerTitleLabel: UILabel! + @IBOutlet var aboutTextView: UITextView! + @IBOutlet var versionLabel: UILabel! + @IBOutlet var addedTagsLabel: UILabel! + @IBOutlet var storedMeasurementsLabel: UILabel! + @IBOutlet var databaseSizeLable: UILabel! private let twoNewlines = "\n\n" private let fourNewlines = "\n\n\n\n" - var viewModel: AboutViewModel = AboutViewModel() + var viewModel: AboutViewModel = .init() } // MARK: - AboutViewInput + extension AboutViewController: AboutViewInput { func localize() { configureTextView() @@ -26,15 +27,15 @@ extension AboutViewController: AboutViewInput { } // MARK: - IBActions -extension AboutViewController { - @IBAction func backButtonTouchUpInside(_ sender: Any) { +extension AboutViewController { + @IBAction func backButtonTouchUpInside(_: Any) { output.viewDidTriggerClose() } - } // MARK: - View lifecycle + extension AboutViewController { override func viewDidLoad() { super.viewDidLoad() @@ -59,7 +60,7 @@ extension AboutViewController { override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) - coordinator.animate(alongsideTransition: { (_) in + coordinator.animate(alongsideTransition: { _ in UIView.setAnimationsEnabled(false) self.aboutTextView.scrollRangeToVisible(NSRange(location: 0, length: 0)) UIView.setAnimationsEnabled(true) @@ -68,17 +69,20 @@ extension AboutViewController { } // MARK: - UITextViewDelegate + extension AboutViewController: UITextViewDelegate { - func textView(_ textView: UITextView, + func textView(_: UITextView, shouldInteractWith URL: URL, - in characterRange: NSRange, - interaction: UITextItemInteraction) -> Bool { + in _: NSRange, + interaction _: UITextItemInteraction) -> Bool + { UIApplication.shared.open(URL, options: [:]) return false } } // MARK: - View configuration + extension AboutViewController { private func configureViews() { headerTitleLabel.text = RuuviLocalization.About.AboutHelp.header @@ -102,19 +106,18 @@ extension AboutViewController { } private func configureTextView() { - let text = - RuuviLocalization.About.AboutHelp.contents + fourNewlines + - RuuviLocalization.About.OperationsManual.header + twoNewlines + - RuuviLocalization.About.OperationsManual.contents + fourNewlines + - RuuviLocalization.About.Troubleshooting.header + twoNewlines + - RuuviLocalization.About.Troubleshooting.contents + fourNewlines + - RuuviLocalization.About.OpenSource.header + twoNewlines + - RuuviLocalization.About.OpenSource.contents + fourNewlines + - RuuviLocalization.About.More.header + twoNewlines + - RuuviLocalization.About.More.contents + fourNewlines + - RuuviLocalization.About.Privacy.header + twoNewlines + - RuuviLocalization.About.Privacy.contents + "\n" + RuuviLocalization.About.AboutHelp.contents + fourNewlines + + RuuviLocalization.About.OperationsManual.header + twoNewlines + + RuuviLocalization.About.OperationsManual.contents + fourNewlines + + RuuviLocalization.About.Troubleshooting.header + twoNewlines + + RuuviLocalization.About.Troubleshooting.contents + fourNewlines + + RuuviLocalization.About.OpenSource.header + twoNewlines + + RuuviLocalization.About.OpenSource.contents + fourNewlines + + RuuviLocalization.About.More.header + twoNewlines + + RuuviLocalization.About.More.contents + fourNewlines + + RuuviLocalization.About.Privacy.header + twoNewlines + + RuuviLocalization.About.Privacy.contents + "\n" let attrString = NSMutableAttributedString(string: text) let range = NSString(string: attrString.string).range(of: attrString.string) @@ -152,7 +155,7 @@ extension AboutViewController { private func setUpChangelogTapGesture() { versionLabel.isUserInteractionEnabled = true - let tapGesture = UITapGestureRecognizer.init( + let tapGesture = UITapGestureRecognizer( target: self, action: #selector(handleChangelogTap(_:)) ) @@ -160,7 +163,7 @@ extension AboutViewController { versionLabel.addGestureRecognizer(tapGesture) } - @objc func handleChangelogTap(_ gesture: UITapGestureRecognizer) { + @objc func handleChangelogTap(_: UITapGestureRecognizer) { output.viewDidTapChangelog() } } @@ -169,10 +172,11 @@ private extension String { func ranges(of substring: String, options: CompareOptions = [], locale: Locale? = nil) -> [Range] { var ranges: [Range] = [] while ranges.last.map({ $0.upperBound < self.endIndex }) ?? true, - let range = self.range(of: substring, - options: options, - range: (ranges.last?.upperBound ?? self.startIndex).. BackgroundSelectionModuleInput diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift index 702ad1901..03deb696d 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift @@ -1,23 +1,23 @@ import Foundation +import RuuviLocal import RuuviOntology -import RuuviService import RuuviPresenters -import RuuviLocal +import RuuviService import UIKit final class BackgroundSelectionPresenter: BackgroundSelectionModuleInput { var viewController: UIViewController { - if let view = self.weakView { + if let view = weakView { return view } else { let view = BackgroundSelectionViewController() view.output = self - view.viewModel = self.viewModel - self.weakView = view + view.viewModel = viewModel + weakView = view return view } - } + private weak var weakView: UIViewController? private let ruuviTag: RuuviTagSensor? private var viewModel: BackgroundSelectionViewModel! { @@ -25,6 +25,7 @@ final class BackgroundSelectionPresenter: BackgroundSelectionModuleInput { prepareDefaultImages() } } + private var backgroundUploadProgressToken: NSObjectProtocol? private var backgroundToken: NSObjectProtocol? // TODO: Find out why backgroundToken is getting notification twice. @@ -36,6 +37,7 @@ final class BackgroundSelectionPresenter: BackgroundSelectionModuleInput { photoPickerPresenter.delegate = self } } + var ruuviSensorPropertiesService: RuuviServiceSensorProperties! var ruuviLocalImages: RuuviLocalImages! var errorPresenter: ErrorPresenter! @@ -63,7 +65,7 @@ extension BackgroundSelectionPresenter: BackgroundSelectionViewOutput { func viewDidSelectDefaultPhoto(model: DefaultBackgroundModel) { if let photo = model.image { - if let ruuviTag = ruuviTag { + if let ruuviTag { performPhotoUpload(with: photo, ruuviTag: ruuviTag) } } @@ -85,66 +87,70 @@ extension BackgroundSelectionPresenter { .default .addObserver(forName: .BackgroundPersistenceDidUpdateBackgroundUploadProgress, object: nil, - queue: .main) { [weak self] notification in - guard let sSelf = self else { return } - if let userInfo = notification.userInfo, let ruuviTag = sSelf.ruuviTag { - let luid = userInfo[BPDidUpdateBackgroundUploadProgressKey.luid] as? LocalIdentifier - let macId = userInfo[BPDidUpdateBackgroundUploadProgressKey.macId] as? MACIdentifier - if (ruuviTag.luid?.value != nil && ruuviTag.luid?.value == luid?.value) - || (ruuviTag.macId?.value != nil && ruuviTag.macId?.value == macId?.value) { - if let percentage = userInfo[BPDidUpdateBackgroundUploadProgressKey.progress] as? Double { - sSelf.viewModel.uploadingBackgroundPercentage.value = percentage - sSelf.viewModel.isUploadingBackground.value = percentage < 1.0 - if percentage == 1.0 { - if let weakView = sSelf.weakView as? BackgroundSelectionViewController { - weakView.viewShouldDismiss() - } + queue: .main) + { [weak self] notification in + guard let sSelf = self else { return } + if let userInfo = notification.userInfo, let ruuviTag = sSelf.ruuviTag { + let luid = userInfo[BPDidUpdateBackgroundUploadProgressKey.luid] as? LocalIdentifier + let macId = userInfo[BPDidUpdateBackgroundUploadProgressKey.macId] as? MACIdentifier + if (ruuviTag.luid?.value != nil && ruuviTag.luid?.value == luid?.value) + || (ruuviTag.macId?.value != nil && ruuviTag.macId?.value == macId?.value) + { + if let percentage = userInfo[BPDidUpdateBackgroundUploadProgressKey.progress] as? Double { + sSelf.viewModel.uploadingBackgroundPercentage.value = percentage + sSelf.viewModel.isUploadingBackground.value = percentage < 1.0 + if percentage == 1.0 { + if let weakView = sSelf.weakView as? BackgroundSelectionViewController { + weakView.viewShouldDismiss() } - } else { - sSelf.viewModel.uploadingBackgroundPercentage.value = nil - sSelf.viewModel.isUploadingBackground.value = false } + } else { + sSelf.viewModel.uploadingBackgroundPercentage.value = nil + sSelf.viewModel.isUploadingBackground.value = false } } } + } backgroundToken = NotificationCenter .default .addObserver(forName: .BackgroundPersistenceDidChangeBackground, object: nil, - queue: .main) { [weak self] notification in - - guard let sSelf = self else { return } - if let userInfo = notification.userInfo, let ruuviTag = sSelf.ruuviTag { - let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier - let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier - if (ruuviTag.luid?.value != nil && ruuviTag.luid?.value == luid?.value) - || (ruuviTag.macId?.value != nil && ruuviTag.macId?.value == macId?.value) { - sSelf.ruuviSensorPropertiesService.getImage(for: ruuviTag) - .on(success: { [weak sSelf] image in - guard let sSelf = sSelf else { return } - sSelf.viewModel.background.value = image - var isLocalSensor: Bool = true - if let isCloudSensor = sSelf.ruuviTag?.isCloudSensor { - isLocalSensor = !isCloudSensor - } + queue: .main) + { [weak self] notification in + + guard let sSelf = self else { return } + if let userInfo = notification.userInfo, let ruuviTag = sSelf.ruuviTag { + let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier + let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier + if (ruuviTag.luid?.value != nil && ruuviTag.luid?.value == luid?.value) + || (ruuviTag.macId?.value != nil && ruuviTag.macId?.value == macId?.value) + { + sSelf.ruuviSensorPropertiesService.getImage(for: ruuviTag) + .on(success: { [weak sSelf] image in + guard let sSelf else { return } + sSelf.viewModel.background.value = image + var isLocalSensor: Bool = true + if let isCloudSensor = sSelf.ruuviTag?.isCloudSensor { + isLocalSensor = !isCloudSensor + } - if isLocalSensor && !sSelf.didUploadBackground { - sSelf.didUploadBackground = true - if let weakView = sSelf.weakView as? BackgroundSelectionViewController { - weakView.viewShouldDismiss() - } + if isLocalSensor, !sSelf.didUploadBackground { + sSelf.didUploadBackground = true + if let weakView = sSelf.weakView as? BackgroundSelectionViewController { + weakView.viewShouldDismiss() } - }, failure: { [weak sSelf] error in - sSelf?.errorPresenter.present(error: error) - }) - } + } + }, failure: { [weak sSelf] error in + sSelf?.errorPresenter.present(error: error) + }) } } + } } private func prepareDefaultImages() { var defaultImages: [DefaultBackgroundModel] = [] - for i in (1...16).reversed() { + for i in (1 ... 16).reversed() { let image = UIImage(named: "bg\(i)") let model = DefaultBackgroundModel(id: i, image: image, @@ -156,8 +162,8 @@ extension BackgroundSelectionPresenter { } extension BackgroundSelectionPresenter: PhotoPickerPresenterDelegate { - func photoPicker(presenter: PhotoPickerPresenter, didPick photo: UIImage) { - if let ruuviTag = ruuviTag { + func photoPicker(presenter _: PhotoPickerPresenter, didPick photo: UIImage) { + if let ruuviTag { performPhotoUpload(with: photo, ruuviTag: ruuviTag) } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewModel.swift b/station/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewModel.swift index 5de08bc2d..1d3ed1101 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewModel.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewModel.swift @@ -7,8 +7,8 @@ struct DefaultBackgroundModel { } struct BackgroundSelectionViewModel { - let background: Observable = Observable() - let isUploadingBackground: Observable = Observable() - let uploadingBackgroundPercentage: Observable = Observable() - let defaultImages: Observable<[DefaultBackgroundModel]?> = Observable<[DefaultBackgroundModel]?>() + let background: Observable = .init() + let isUploadingBackground: Observable = .init() + let uploadingBackgroundPercentage: Observable = .init() + let defaultImages: Observable<[DefaultBackgroundModel]?> = .init() } diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewOutput.swift b/station/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewOutput.swift index b26ae65c6..0026c9fec 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewOutput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewOutput.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviOntology +import UIKit protocol BackgroundSelectionViewOutput { func viewDidLoad() diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift index fbff4496a..0b27a9481 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift @@ -5,8 +5,7 @@ protocol BackgroundSelectionButtonViewDelegate: NSObjectProtocol { } class BackgroundSelectionButtonView: UIView { - - weak private var delegate: BackgroundSelectionButtonViewDelegate? + private weak var delegate: BackgroundSelectionButtonViewDelegate? // UI private lazy var titleLabel: UILabel = { @@ -34,21 +33,23 @@ class BackgroundSelectionButtonView: UIView { convenience init(title: String, icon: String, - delegate: BackgroundSelectionButtonViewDelegate? = nil) { + delegate: BackgroundSelectionButtonViewDelegate? = nil) + { self.init() - self.titleLabel.text = title - self.buttonIcon.image = UIImage(systemName: icon) + titleLabel.text = title + buttonIcon.image = UIImage(systemName: icon) self.delegate = delegate setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } } -extension BackgroundSelectionButtonView { - fileprivate func setUpUI() { +private extension BackgroundSelectionButtonView { + func setUpUI() { backgroundColor = .clear addSubview(titleLabel) @@ -86,8 +87,8 @@ extension BackgroundSelectionButtonView { } } -extension BackgroundSelectionButtonView { - @objc fileprivate func handleTap() { +private extension BackgroundSelectionButtonView { + @objc func handleTap() { delegate?.didTapButton(self) } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift index d09395efe..b0f8bda0d 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift @@ -6,7 +6,6 @@ protocol BackgroundSelectionUploadProgressViewDelegate: NSObjectProtocol { } class BackgroundSelectionUploadProgressView: UIView { - weak var delegate: BackgroundSelectionUploadProgressViewDelegate? lazy var progressLabel: UILabel = { @@ -35,37 +34,38 @@ class BackgroundSelectionUploadProgressView: UIView { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } } -extension BackgroundSelectionUploadProgressView { - fileprivate func setUpUI() { +private extension BackgroundSelectionUploadProgressView { + func setUpUI() { backgroundColor = RuuviColor.ruuviGraphBGColor layer.cornerRadius = 4 clipsToBounds = true addSubview(progressLabel) progressLabel.anchor(top: topAnchor, - leading: safeLeftAnchor, - bottom: bottomAnchor, - trailing: nil, - padding: .init(top: 8, - left: 8, - bottom: 8, - right: 0)) + leading: safeLeftAnchor, + bottom: bottomAnchor, + trailing: nil, + padding: .init(top: 8, + left: 8, + bottom: 8, + right: 0)) addSubview(cancelButton) cancelButton.anchor(top: nil, - leading: progressLabel.trailingAnchor, - bottom: nil, - trailing: safeRightAnchor, - padding: .init(top: 0, - left: 24, - bottom: 8, - right: 8), - size: .init(width: 24, height: 24)) + leading: progressLabel.trailingAnchor, + bottom: nil, + trailing: safeRightAnchor, + padding: .init(top: 0, + left: 24, + bottom: 8, + right: 8), + size: .init(width: 24, height: 24)) cancelButton.centerYInSuperview() } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewCell.swift b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewCell.swift index 79c262b3d..71f7e94f8 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewCell.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewCell.swift @@ -1,7 +1,6 @@ import UIKit class BackgroundSelectionViewCell: UICollectionViewCell { - private lazy var imageView: UIImageView = { let iv = UIImageView() iv.contentMode = .scaleAspectFill @@ -15,7 +14,8 @@ class BackgroundSelectionViewCell: UICollectionViewCell { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift index ed7e849a0..e8731fab9 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviLocalization +import UIKit class BackgroundSelectionViewController: UIViewController { // View configure @@ -12,7 +12,7 @@ class BackgroundSelectionViewController: UIViewController { // UI Componenets starts private lazy var backButton: UIButton = { - let button = UIButton() + let button = UIButton() button.tintColor = .label let buttonImage = RuuviAssets.backButtonImage button.setImage(buttonImage, for: .normal) @@ -47,6 +47,7 @@ class BackgroundSelectionViewController: UIViewController { } // MARK: - View lifecycle + extension BackgroundSelectionViewController { override func viewDidLoad() { super.viewDidLoad() @@ -56,32 +57,31 @@ extension BackgroundSelectionViewController { } } -extension BackgroundSelectionViewController { - fileprivate func updateUI() { +private extension BackgroundSelectionViewController { + func updateUI() { DispatchQueue.main.async { [weak self] in self?.collectionView.reloadData() } } - @objc fileprivate func backButtonDidTap() { + @objc func backButtonDidTap() { _ = navigationController?.popViewController(animated: true) } } -extension BackgroundSelectionViewController { - fileprivate func setUpUI() { +private extension BackgroundSelectionViewController { + func setUpUI() { setUpBaseView() setUpHeaderView() setUpContentView() setUpUploadProgressView() } - fileprivate func setUpBaseView() { + func setUpBaseView() { view.backgroundColor = RuuviColor.dashboardBGColor } - fileprivate func setUpHeaderView() { - + func setUpHeaderView() { let leftBarButtonView = UIView(color: .clear) leftBarButtonView.addSubview(backButton) @@ -95,8 +95,7 @@ extension BackgroundSelectionViewController { navigationItem.leftBarButtonItem = UIBarButtonItem(customView: leftBarButtonView) } - fileprivate func setUpContentView() { - + func setUpContentView() { view.addSubview(collectionView) collectionView.anchor(top: view.safeTopAnchor, leading: view.safeLeftAnchor, @@ -115,7 +114,7 @@ extension BackgroundSelectionViewController { withReuseIdentifier: sectionHeaderIdentifier) } - fileprivate func setUpUploadProgressView() { + func setUpUploadProgressView() { view.addSubview(uploadProgressView) uploadProgressView.anchor(top: nil, leading: nil, @@ -128,10 +127,10 @@ extension BackgroundSelectionViewController { uploadProgressView.isHidden = true } - fileprivate func createLayout() -> UICollectionViewLayout { + func createLayout() -> UICollectionViewLayout { let sectionProvider = { [weak self] (_: Int, _: NSCollectionLayoutEnvironment) - -> NSCollectionLayoutSection? in + -> NSCollectionLayoutSection? in guard let sSelf = self else { return nil } let widthMultiplier = sSelf.itemWidthMultiplier() @@ -174,33 +173,33 @@ extension BackgroundSelectionViewController { return layout } - fileprivate func itemWidthMultiplier() -> CGFloat { + func itemWidthMultiplier() -> CGFloat { if GlobalHelpers.isDeviceTablet() { - return GlobalHelpers.isDeviceLandscape() ? 0.125 : 0.20 + GlobalHelpers.isDeviceLandscape() ? 0.125 : 0.20 } else { - return GlobalHelpers.isDeviceLandscape() ? 0.20 : 0.33333333 + GlobalHelpers.isDeviceLandscape() ? 0.20 : 0.33333333 } } - fileprivate func itemEstimatedHeight() -> CGFloat { + func itemEstimatedHeight() -> CGFloat { if GlobalHelpers.isDeviceTablet() { - return GlobalHelpers.isDeviceLandscape() ? 200 : 190 + GlobalHelpers.isDeviceLandscape() ? 200 : 190 } else { - return GlobalHelpers.isDeviceLandscape() ? 190 : 170 + GlobalHelpers.isDeviceLandscape() ? 190 : 170 } } } extension BackgroundSelectionViewController { private func bindViewModel() { - guard isViewLoaded, let viewModel = viewModel else { return } + guard isViewLoaded, let viewModel else { return } collectionView.bind(viewModel.defaultImages) { [weak self] _, _ in self?.updateUI() } uploadProgressView.bind(viewModel.isUploadingBackground) { v, isUploading in - if let isUploading = isUploading { + if let isUploading { v.isHidden = !isUploading } else { v.isHidden = true @@ -208,7 +207,7 @@ extension BackgroundSelectionViewController { } uploadProgressView.progressLabel.bind(viewModel.uploadingBackgroundPercentage) { lb, percentage in - if let percentage = percentage { + if let percentage { lb.text = RuuviLocalization.uploadingProgress(Float(percentage) * 100) } } @@ -217,7 +216,7 @@ extension BackgroundSelectionViewController { extension BackgroundSelectionViewController: BackgroundSelectionViewInput { func localize() { - self.title = RuuviLocalization.changeBackground + title = RuuviLocalization.changeBackground } func viewShouldDismiss() { @@ -226,12 +225,13 @@ extension BackgroundSelectionViewController: BackgroundSelectionViewInput { } extension BackgroundSelectionViewController: UICollectionViewDataSource { - func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return viewModel?.defaultImages.value?.count ?? 0 + func collectionView(_: UICollectionView, numberOfItemsInSection _: Int) -> Int { + viewModel?.defaultImages.value?.count ?? 0 } func collectionView(_ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell + { guard let cell = collectionView.dequeueReusableCell( withReuseIdentifier: cvCellIdentifier, for: indexPath @@ -246,20 +246,22 @@ extension BackgroundSelectionViewController: UICollectionViewDataSource { } extension BackgroundSelectionViewController: UICollectionViewDelegate { - - func collectionView(_ collectionView: UICollectionView, - didSelectItemAt indexPath: IndexPath) { + func collectionView(_: UICollectionView, + didSelectItemAt indexPath: IndexPath) + { if let model = viewModel?.defaultImages.value?[indexPath.item] { output.viewDidSelectDefaultPhoto(model: model) } } - func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, - at indexPath: IndexPath) -> UICollectionReusableView { + func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind _: String, + at indexPath: IndexPath) -> UICollectionReusableView + { guard let headerView = collectionView .dequeueReusableSupplementaryView(ofKind: sectionHeaderKind, withReuseIdentifier: sectionHeaderIdentifier, - for: indexPath) as? BackgroundSelectionViewHeader else { + for: indexPath) as? BackgroundSelectionViewHeader + else { fatalError() } headerView.delegate = self diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift index 996d6cf34..f0b2ce740 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviLocalization +import UIKit enum SelectionMode { case camera @@ -11,7 +11,6 @@ protocol BackgroundSelectionViewHeaderDelegate: NSObjectProtocol { } class BackgroundSelectionViewHeader: UICollectionReusableView { - weak var delegate: BackgroundSelectionViewHeaderDelegate? private lazy var descriptionLabel: UILabel = { @@ -28,11 +27,13 @@ class BackgroundSelectionViewHeader: UICollectionReusableView { lazy var takePhotoButton = BackgroundSelectionButtonView( title: RuuviLocalization.takePhoto, icon: "camera.fill", - delegate: self) + delegate: self + ) lazy var selectFromGalleryButton = BackgroundSelectionButtonView( title: RuuviLocalization.selectFromGallery, icon: "photo", - delegate: self) + delegate: self + ) private lazy var selectFromDefaultLabel: UILabel = { let label = UILabel() @@ -49,13 +50,14 @@ class BackgroundSelectionViewHeader: UICollectionReusableView { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } } -extension BackgroundSelectionViewHeader { - fileprivate func setUpUI() { +private extension BackgroundSelectionViewHeader { + func setUpUI() { backgroundColor = .clear addSubview(descriptionLabel) @@ -92,10 +94,10 @@ extension BackgroundSelectionViewHeader { addSubview(selectFromDefaultLabel) selectFromDefaultLabel.anchor(top: selectFromGalleryButton.bottomAnchor, - leading: seprator.leadingAnchor, - bottom: safeBottomAnchor, - trailing: seprator.trailingAnchor, - size: .init(width: 0, height: 44)) + leading: seprator.leadingAnchor, + bottom: safeBottomAnchor, + trailing: seprator.trailingAnchor, + size: .init(width: 0, height: 44)) } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Assembly/CardsViewModuleFactory.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Assembly/CardsViewModuleFactory.swift index 1773de5e5..6f74879d8 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Assembly/CardsViewModuleFactory.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Assembly/CardsViewModuleFactory.swift @@ -1,16 +1,16 @@ -import UIKit import BTKit import RuuviContext -import RuuviStorage -import RuuviReactor -import RuuviLocal -import RuuviService import RuuviCore +import RuuviDaemon +import RuuviLocal import RuuviNotifier +import RuuviPool import RuuviPresenters +import RuuviReactor +import RuuviService +import RuuviStorage import RuuviUser -import RuuviDaemon -import RuuviPool +import UIKit protocol CardsViewModuleFactory { func create() -> CardsViewController diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractor.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractor.swift index ecf4e39a0..f501b74ec 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractor.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractor.swift @@ -1,8 +1,8 @@ +import BTKit import Foundation -import RuuviOntology -import RuuviLocal import Future -import BTKit +import RuuviLocal +import RuuviOntology import RuuviPool class CardsInteractor { @@ -13,10 +13,12 @@ class CardsInteractor { extension CardsInteractor: CardsInteractorInput { func checkAndUpdateFirmwareVersion(for ruuviTag: RuuviTagSensor, - settings: RuuviLocalSettings) { + settings _: RuuviLocalSettings) + { guard let luid = ruuviTag.luid, ruuviTag.firmwareVersion == nil || - !ruuviTag.firmwareVersion.hasText() else { + !ruuviTag.firmwareVersion.hasText() + else { return } @@ -26,7 +28,7 @@ extension CardsInteractor: CardsInteractorInput { options: [.connectionTimeout(15)] ) { [weak self] _, result in switch result { - case .success(let version): + case let .success(version): let tagWithVersion = ruuviTag.with(firmwareVersion: version) self?.ruuviPool.update(tagWithVersion) default: diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractorInput.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractorInput.swift index e59e765d1..f4fc637cd 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractorInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractorInput.swift @@ -1,7 +1,7 @@ import Foundation import Future -import RuuviOntology import RuuviLocal +import RuuviOntology protocol CardsInteractorInput: AnyObject { func checkAndUpdateFirmwareVersion(for ruuviTag: RuuviTagSensor, diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift index 368708bd7..9f7035c44 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift @@ -1,17 +1,17 @@ +import BTKit +import CoreBluetooth // swiftlint:disable file_length trailing_whitespace import Foundation -import CoreBluetooth -import BTKit -import RuuviOntology -import RuuviStorage -import RuuviReactor +import RuuviCore +import RuuviDaemon import RuuviLocal -import RuuviService import RuuviNotification import RuuviNotifier +import RuuviOntology import RuuviPresenters -import RuuviDaemon -import RuuviCore +import RuuviReactor +import RuuviService +import RuuviStorage import UIKit class CardsPresenter { @@ -34,13 +34,14 @@ class CardsPresenter { var permissionsManager: RuuviCorePermission! // MARK: - PRIVATE VARIABLES + /// Collection of the sensor private var ruuviTags = [AnyRuuviTagSensor]() private var sensorSettings = [SensorSettings]() /// Collection of the card view model. private var viewModels: [CardsViewModel] = [] { didSet { - guard let view = view else { return } + guard let view else { return } view.viewModels = viewModels } } @@ -48,14 +49,14 @@ class CardsPresenter { /// Index for visible card private var visibleViewModelIndex: Int = 0 { didSet { - guard let view = view, shouldTriggerScroll else { return } + guard let view, shouldTriggerScroll else { return } view.scrollIndex = visibleViewModelIndex } } /// Whether bluetooth permission is already granted. private var isBluetoothPermissionGranted: Bool { - return CBCentralManager.authorization == .allowedAlways + CBCentralManager.authorization == .allowedAlways } private var mutedTillTimer: Timer? @@ -67,6 +68,7 @@ class CardsPresenter { private weak var output: CardsModuleOutput? // MARK: - OBSERVERS + private var ruuviTagToken: RuuviReactorToken? private var ruuviTagObserveLastRecordTokens = [RuuviReactorToken]() private var advertisementTokens = [ObservationToken]() @@ -98,6 +100,7 @@ class CardsPresenter { } // MARK: - CardsModuleInput + extension CardsPresenter: CardsModuleInput { func configure( viewModels: [CardsViewModel], @@ -105,7 +108,7 @@ extension CardsPresenter: CardsModuleInput { sensorSettings: [SensorSettings] ) { self.viewModels = viewModels - self.ruuviTags = ruuviTagSensors + ruuviTags = ruuviTagSensors self.sensorSettings = sensorSettings } @@ -114,7 +117,8 @@ extension CardsPresenter: CardsModuleInput { } func configure(scrollTo: CardsViewModel?, - openChart: Bool) { + openChart: Bool) + { updateVisibleCard(from: scrollTo, openChart: openChart, triggerScroll: true) @@ -151,10 +155,11 @@ extension CardsPresenter { private func updateVisibleCard(from viewModel: CardsViewModel?, openChart: Bool = false, - triggerScroll: Bool = false) { + triggerScroll: Bool = false) + { if let index = viewModels.firstIndex(where: { ($0.luid.value != nil && $0.luid.value == viewModel?.luid.value) || - ($0.mac.value != nil && $0.mac.value == viewModel?.mac.value) + ($0.mac.value != nil && $0.mac.value == viewModel?.mac.value) }) { shouldTriggerScroll = triggerScroll visibleViewModelIndex = index @@ -170,35 +175,36 @@ extension CardsPresenter { // swiftlint:disable:next cyclomatic_complexity function_body_length private func startObservingRuuviTags() { ruuviTagToken?.invalidate() - ruuviTagToken = ruuviReactor.observe { [weak self] (change) in + ruuviTagToken = ruuviReactor.observe { [weak self] change in guard let sSelf = self else { return } switch change { - case .insert(let sensor): + case let .insert(sensor): sSelf.notifyRestartAdvertisementDaemon() sSelf.notifyRestartHeartBeatDaemon() sSelf.checkFirmwareVersion(for: sensor) sSelf.ruuviTags.append(sensor.any) sSelf.syncViewModels() if let viewModel = sSelf.viewModels.first(where: { - return ($0.luid.value != nil && $0.luid.value == sensor.luid?.any) + ($0.luid.value != nil && $0.luid.value == sensor.luid?.any) || ($0.mac.value != nil && $0.mac.value == sensor.macId?.any) }) { sSelf.updateVisibleCard(from: viewModel, triggerScroll: true) sSelf.view?.scroll(to: sSelf.visibleViewModelIndex) } - case .update(let sensor): + case let .update(sensor): guard let sSelf = self else { return } if let index = sSelf.ruuviTags .firstIndex( where: { ($0.macId != nil && $0.macId?.any == sensor.macId?.any) - || ($0.luid != nil && $0.luid?.any == sensor.luid?.any) - }) { + || ($0.luid != nil && $0.luid?.any == sensor.luid?.any) + }) + { sSelf.ruuviTags[index] = sensor sSelf.syncViewModels() if let viewModel = sSelf.viewModels.first(where: { - return ($0.luid.value != nil && $0.luid.value == sensor.luid?.any) + ($0.luid.value != nil && $0.luid.value == sensor.luid?.any) || ($0.mac.value != nil && $0.mac.value == sensor.macId?.any) }) { sSelf.updateVisibleCard(from: viewModel, @@ -207,7 +213,7 @@ extension CardsPresenter { } } - case .delete(let sensor): + case let .delete(sensor): sSelf.ruuviTags.removeAll(where: { $0.id == sensor.id }) sSelf.syncViewModels() // If a sensor is deleted, and there's no more sensor take @@ -225,7 +231,7 @@ extension CardsPresenter { sSelf.updateVisibleCard(from: first, triggerScroll: true) sSelf.view?.scroll(to: sSelf.visibleViewModelIndex) } - case .error(let error): + case let .error(error): sSelf.errorPresenter.present(error: error) default: break } @@ -233,23 +239,25 @@ extension CardsPresenter { } private func startListeningLatestRecords() { - ruuviTagObserveLastRecordTokens.forEach({ $0.invalidate() }) + ruuviTagObserveLastRecordTokens.forEach { $0.invalidate() } ruuviTagObserveLastRecordTokens.removeAll() for viewModel in viewModels { if viewModel.type == .ruuvi, - let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) { - let token = ruuviReactor.observeLatest(ruuviTagSensor) { [weak self] (changes) in - if case .update(let anyRecord) = changes, + let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) + { + let token = ruuviReactor.observeLatest(ruuviTagSensor) { [weak self] changes in + if case let .update(anyRecord) = changes, let viewModel = self?.viewModels - .first(where: { - ($0.luid.value != nil && ($0.luid.value == anyRecord?.luid?.any)) - || ($0.mac.value != nil && ($0.mac.value == anyRecord?.macId?.any)) - }), - let record = anyRecord { + .first(where: { + ($0.luid.value != nil && ($0.luid.value == anyRecord?.luid?.any)) + || ($0.mac.value != nil && ($0.mac.value == anyRecord?.macId?.any)) + }), + let record = anyRecord + { let sensorSettings = self?.sensorSettings .first(where: { - ($0.luid?.any != nil && $0.luid?.any == viewModel.luid.value) - || ($0.macId?.any != nil && $0.macId?.any == viewModel.mac.value) + ($0.luid?.any != nil && $0.luid?.any == viewModel.luid.value) + || ($0.macId?.any != nil && $0.macId?.any == viewModel.mac.value) }) let sensorRecord = record.with(sensorSettings: sensorSettings) viewModel.update(sensorRecord) @@ -264,7 +272,7 @@ extension CardsPresenter { } private func startListeningToRuuviTagsAlertStatus() { - ruuviTags.forEach({ (ruuviTag) in + ruuviTags.forEach { ruuviTag in if ruuviTag.isCloud { if let macId = ruuviTag.macId { alertHandler.subscribe(self, to: macId.value) @@ -276,7 +284,7 @@ extension CardsPresenter { alertHandler.subscribe(self, to: macId.value) } } - }) + } } // swiftlint:disable:next function_body_length @@ -287,36 +295,37 @@ extension CardsPresenter { .addObserver(forName: .RuuviServiceAlertDidChange, object: nil, queue: .main, - using: { [weak self] (notification) in - guard let sSelf = self else { return } - if let userInfo = notification.userInfo { - if let physicalSensor - = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor, - let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType { - sSelf.viewModels.filter({ - ($0.luid.value != nil && ($0.luid.value == physicalSensor.luid?.any)) - || ($0.mac.value != nil && ($0.mac.value == physicalSensor.macId?.any)) - }).forEach({ (viewModel) in - if sSelf.alertService.hasRegistrations(for: physicalSensor) { - viewModel.alertState.value = .registered - } else { - viewModel.alertState.value = .empty - } - sSelf.updateIsOnState(of: type, - for: physicalSensor.id, - viewModel: viewModel) - sSelf.updateMutedTill(of: type, - for: physicalSensor.id, - viewModel: viewModel) - self?.notifyUpdate(for: viewModel) - }) - } - } - }) + using: { [weak self] notification in + guard let sSelf = self else { return } + if let userInfo = notification.userInfo { + if let physicalSensor + = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor, + let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType + { + sSelf.viewModels.filter { + ($0.luid.value != nil && ($0.luid.value == physicalSensor.luid?.any)) + || ($0.mac.value != nil && ($0.mac.value == physicalSensor.macId?.any)) + }.forEach { viewModel in + if sSelf.alertService.hasRegistrations(for: physicalSensor) { + viewModel.alertState.value = .registered + } else { + viewModel.alertState.value = .empty + } + sSelf.updateIsOnState(of: type, + for: physicalSensor.id, + viewModel: viewModel) + sSelf.updateMutedTill(of: type, + for: physicalSensor.id, + viewModel: viewModel) + self?.notifyUpdate(for: viewModel) + } + } + } + }) } private func startMutedTillTimer() { - self.mutedTillTimer = Timer + mutedTillTimer = Timer .scheduledTimer( withTimeInterval: 5, repeats: true @@ -327,9 +336,9 @@ extension CardsPresenter { } private func observeRuuviTagBTMesurements() { - advertisementTokens.forEach({ $0.invalidate() }) + advertisementTokens.forEach { $0.invalidate() } advertisementTokens.removeAll() - heartbeatTokens.forEach({ $0.invalidate() }) + heartbeatTokens.forEach { $0.invalidate() } heartbeatTokens.removeAll() for viewModel in viewModels { @@ -338,40 +347,42 @@ extension CardsPresenter { continue } if viewModel.type == .ruuvi, - let luid = viewModel.luid.value { + let luid = viewModel.luid.value + { advertisementTokens.append(foreground.observe(self, uuid: luid.value, - closure: { [weak self] (_, device) in - if let tag = device.ruuvi?.tag { - self?.handleMeasurementPoint(tag: tag, - source: .advertisement) - } - })) + closure: { [weak self] _, device in + if let tag = device.ruuvi?.tag { + self?.handleMeasurementPoint(tag: tag, + source: .advertisement) + } + })) heartbeatTokens.append(background.observe(self, uuid: luid.value, - closure: { [weak self] (_, device) in - if let tag = device.ruuvi?.tag { - self?.handleMeasurementPoint(tag: tag, - source: .heartbeat) - } - })) + closure: { [weak self] _, device in + if let tag = device.ruuvi?.tag { + self?.handleMeasurementPoint(tag: tag, + source: .heartbeat) + } + })) } } } private func handleMeasurementPoint(tag: RuuviTag, - source: RuuviTagSensorRecordSource) { + source: RuuviTagSensorRecordSource) + { guard let viewModel = viewModels.first( where: { $0.luid.value == tag.uuid.luid.any } ) else { return } let sensorSettings = sensorSettings - .first(where: { - ($0.luid?.any != nil && $0.luid?.any == viewModel.luid.value) - || ($0.macId?.any != nil && $0.macId?.any == viewModel.mac.value) - }) + .first(where: { + ($0.luid?.any != nil && $0.luid?.any == viewModel.luid.value) + || ($0.macId?.any != nil && $0.macId?.any == viewModel.mac.value) + }) let record = tag .with(source: source) .with(sensorSettings: sensorSettings) @@ -384,16 +395,17 @@ extension CardsPresenter { // swiftlint:disable:next function_body_length cyclomatic_complexity private func observeSensorSettings() { - sensorSettingsTokens.forEach({ $0.invalidate() }) + sensorSettingsTokens.forEach { $0.invalidate() } sensorSettingsTokens.removeAll() for viewModel in viewModels { if viewModel.type == .ruuvi, - let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) { + let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) + { sensorSettingsTokens.append( - ruuviReactor.observe(ruuviTagSensor, { [weak self] change in + ruuviReactor.observe(ruuviTagSensor) { [weak self] change in guard let sSelf = self else { return } switch change { - case .insert(let sensorSettings): + case let .insert(sensorSettings): self?.sensorSettings.append(sensorSettings) if let viewModel = sSelf.viewModels.first(where: { $0.id.value == ruuviTagSensor.id @@ -403,7 +415,7 @@ extension CardsPresenter { viewModel: viewModel ) } - case .update(let updateSensorSettings): + case let .update(updateSensorSettings): if let updateIndex = self?.sensorSettings.firstIndex( where: { $0.id == updateSensorSettings.id } ) { @@ -419,7 +431,7 @@ extension CardsPresenter { } else { self?.sensorSettings.append(updateSensorSettings) } - case .delete(let deleteSensorSettings): + case let .delete(deleteSensorSettings): if let deleteIndex = self?.sensorSettings.firstIndex( where: { $0.id == deleteSensorSettings.id } ) { @@ -435,7 +447,7 @@ extension CardsPresenter { } default: break } - }) + } ) } } @@ -446,7 +458,7 @@ extension CardsPresenter { ) { let currentRecord = viewModel.latestMeasurement.value let updatedRecord = currentRecord?.with(sensorSettings: sensorSettings) - guard let updatedRecord = updatedRecord else { + guard let updatedRecord else { return } viewModel.update(updatedRecord) @@ -454,7 +466,7 @@ extension CardsPresenter { } private func startObservingBluetoothState() { - stateToken = foreground.state(self, closure: { (observer, state) in + stateToken = foreground.state(self, closure: { observer, state in if state != .poweredOn || !self.isBluetoothPermissionGranted { observer.view?.showBluetoothDisabled( userDeclined: !self.isBluetoothPermissionGranted) @@ -472,34 +484,35 @@ extension CardsPresenter { .default .addObserver(forName: .BackgroundPersistenceDidChangeBackground, object: nil, - queue: .main) { [weak self] notification in + queue: .main) + { [weak self] notification in - guard let sSelf = self else { return } - if let userInfo = notification.userInfo { - let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier - let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier - - let viewModel = sSelf.view?.viewModels - .first(where: { $0.luid.value != nil && $0.luid.value == luid?.any }) - ?? sSelf.view?.viewModels - .first(where: { $0.mac.value != nil && $0.mac.value == macId?.any }) - if let viewModel = viewModel { - let ruuviTag = sSelf.ruuviTags - .first(where: { $0.luid != nil && $0.luid?.any == luid?.any }) + guard let sSelf = self else { return } + if let userInfo = notification.userInfo { + let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier + let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier + + let viewModel = sSelf.view?.viewModels + .first(where: { $0.luid.value != nil && $0.luid.value == luid?.any }) + ?? sSelf.view?.viewModels + .first(where: { $0.mac.value != nil && $0.mac.value == macId?.any }) + if let viewModel { + let ruuviTag = sSelf.ruuviTags + .first(where: { $0.luid != nil && $0.luid?.any == luid?.any }) ?? sSelf.ruuviTags - .first(where: { $0.macId != nil && $0.macId?.any == macId?.any }) - if let ruuviTag = ruuviTag { - sSelf.ruuviSensorPropertiesService.getImage(for: ruuviTag) - .on(success: { image in - viewModel.background.value = image - self?.view?.changeCardBackground(of: viewModel, to: image) - }, failure: { [weak self] error in - self?.errorPresenter.present(error: error) - }) - } + .first(where: { $0.macId != nil && $0.macId?.any == macId?.any }) + if let ruuviTag { + sSelf.ruuviSensorPropertiesService.getImage(for: ruuviTag) + .on(success: { image in + viewModel.background.value = image + self?.view?.changeCardBackground(of: viewModel, to: image) + }, failure: { [weak self] error in + self?.errorPresenter.present(error: error) + }) } } } + } } // swiftlint:disable:next cyclomatic_complexity function_body_length @@ -510,11 +523,12 @@ extension CardsPresenter { .addObserver(forName: .RuuviTagAdvertisementDaemonDidFail, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let error = userInfo[RuuviTagAdvertisementDaemonDidFailKey.error] as? RUError { - self?.errorPresenter.present(error: error) - } + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let error = userInfo[RuuviTagAdvertisementDaemonDidFailKey.error] as? RUError + { + self?.errorPresenter.present(error: error) + } }) ruuviTagPropertiesDaemonFailureToken?.invalidate() ruuviTagPropertiesDaemonFailureToken = NotificationCenter @@ -522,11 +536,12 @@ extension CardsPresenter { .addObserver(forName: .RuuviTagPropertiesDaemonDidFail, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let error = userInfo[RuuviTagPropertiesDaemonDidFailKey.error] as? RUError { - self?.errorPresenter.present(error: error) - } + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let error = userInfo[RuuviTagPropertiesDaemonDidFailKey.error] as? RUError + { + self?.errorPresenter.present(error: error) + } }) ruuviTagHeartbeatDaemonFailureToken?.invalidate() ruuviTagHeartbeatDaemonFailureToken = NotificationCenter @@ -534,11 +549,12 @@ extension CardsPresenter { .addObserver(forName: .RuuviTagHeartbeatDaemonDidFail, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let error = userInfo[RuuviTagHeartbeatDaemonDidFailKey.error] as? RUError { - self?.errorPresenter.present(error: error) - } + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let error = userInfo[RuuviTagHeartbeatDaemonDidFailKey.error] as? RUError + { + self?.errorPresenter.present(error: error) + } }) ruuviTagReadLogsOperationFailureToken?.invalidate() ruuviTagReadLogsOperationFailureToken = NotificationCenter @@ -546,11 +562,12 @@ extension CardsPresenter { .addObserver(forName: .RuuviTagReadLogsOperationDidFail, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let error = userInfo[RuuviTagReadLogsOperationDidFailKey.error] as? RUError { - self?.errorPresenter.present(error: error) - } + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let error = userInfo[RuuviTagReadLogsOperationDidFailKey.error] as? RUError + { + self?.errorPresenter.present(error: error) + } }) } @@ -561,13 +578,14 @@ extension CardsPresenter { .addObserver(forName: .BTBackgroundDidConnect, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let uuid = userInfo[BTBackgroundDidConnectKey.uuid] as? String, - let viewModel = self?.viewModels.first(where: { $0.luid.value == uuid.luid.any }) { - viewModel.isConnected.value = true - self?.notifyUpdate(for: viewModel) - } + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let uuid = userInfo[BTBackgroundDidConnectKey.uuid] as? String, + let viewModel = self?.viewModels.first(where: { $0.luid.value == uuid.luid.any }) + { + viewModel.isConnected.value = true + self?.notifyUpdate(for: viewModel) + } }) didDisconnectToken?.invalidate() didDisconnectToken = NotificationCenter @@ -575,13 +593,14 @@ extension CardsPresenter { .addObserver(forName: .BTBackgroundDidDisconnect, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let uuid = userInfo[BTBackgroundDidDisconnectKey.uuid] as? String, - let viewModel = self?.viewModels.first(where: { $0.luid.value == uuid.luid.any }) { - viewModel.isConnected.value = false - self?.notifyUpdate(for: viewModel) - } + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let uuid = userInfo[BTBackgroundDidDisconnectKey.uuid] as? String, + let viewModel = self?.viewModels.first(where: { $0.luid.value == uuid.luid.any }) + { + viewModel.isConnected.value = false + self?.notifyUpdate(for: viewModel) + } }) } @@ -593,15 +612,15 @@ extension CardsPresenter { object: nil, queue: .main, using: { [weak self] _ in - self?.handleCloudModeState() - }) + self?.handleCloudModeState() + }) } /// The method handles all the operations when cloud mode toggle is turned on/off private func handleCloudModeState() { // Sync with cloud if cloud mode is turned on if settings.cloudModeEnabled { - for viewModel in viewModels where (viewModel.isCloud.value ?? false) { + for viewModel in viewModels where viewModel.isCloud.value ?? false { viewModel.isConnected.value = false notifyUpdate(for: viewModel) } @@ -611,7 +630,7 @@ extension CardsPresenter { // ACTIONS // swiftlint:disable:next function_body_length private func syncViewModels() { - let ruuviViewModels = ruuviTags.compactMap({ (ruuviTag) -> CardsViewModel in + let ruuviViewModels = ruuviTags.compactMap { ruuviTag -> CardsViewModel in let viewModel = CardsViewModel(ruuviTag) ruuviSensorPropertiesService.getImage(for: ruuviTag) .on(success: { [weak self] image in @@ -637,7 +656,7 @@ extension CardsPresenter { syncAlerts(ruuviTag: ruuviTag, viewModel: viewModel) let op = ruuviStorage.readLatest(ruuviTag) op.on { [weak self] record in - if let record = record { + if let record { viewModel.update(record) self?.notifyUpdate(for: viewModel) self?.processAlert(record: record, viewModel: viewModel) @@ -645,7 +664,7 @@ extension CardsPresenter { } return viewModel - }) + } viewModels = reorder(ruuviViewModels) @@ -658,13 +677,14 @@ extension CardsPresenter { private func reorder(_ viewModels: [CardsViewModel]) -> [CardsViewModel] { let sortedAndUniqueArray = viewModels.reduce( into: [CardsViewModel]() - ) { (result, element) in + ) { result, element in if !result.contains(element) { // Insert the element into the result array while maintaining the sorted order if let index = result.firstIndex( where: { $0.name.value?.lowercased() ?? "" > - element.name.value?.lowercased() ?? "" } + element.name.value?.lowercased() ?? "" + } ) { result.insert(element, at: index) } else { @@ -678,28 +698,31 @@ extension CardsPresenter { private func openTagSettingsScreens(viewModel: CardsViewModel) { let sensorSettings = sensorSettings - .first(where: { - ($0.luid?.any != nil && $0.luid?.any == viewModel.luid.value) - || ($0.macId?.any != nil && $0.macId?.any == viewModel.mac.value) - }) + .first(where: { + ($0.luid?.any != nil && $0.luid?.any == viewModel.luid.value) + || ($0.macId?.any != nil && $0.macId?.any == viewModel.mac.value) + }) if let ruuviTag = ruuviTags.first(where: { $0.id == viewModel.id.value }) { - self.router.openTagSettings( + router.openTagSettings( ruuviTag: ruuviTag, latestMeasurement: viewModel.latestMeasurement.value, sensorSettings: sensorSettings, - output: self) + output: self + ) } } private func showTagCharts(for viewModel: CardsViewModel?) { - guard let viewModel = viewModel else { return } + guard let viewModel else { return } viewDidTriggerShowChart(for: viewModel) } private func processAlert(record: RuuviTagSensorRecord, - viewModel: CardsViewModel) { + viewModel: CardsViewModel) + { if let isCloud = viewModel.isCloud.value, isCloud, - let macId = viewModel.mac.value { + let macId = viewModel.mac.value + { alertHandler.processNetwork(record: record, trigger: false, for: macId) @@ -721,10 +744,10 @@ extension CardsPresenter { private func shutdownModule() { ruuviTagToken?.invalidate() - ruuviTagObserveLastRecordTokens.forEach({ $0.invalidate() }) - advertisementTokens.forEach({ $0.invalidate() }) - heartbeatTokens.forEach({ $0.invalidate() }) - sensorSettingsTokens.forEach({ $0.invalidate() }) + ruuviTagObserveLastRecordTokens.forEach { $0.invalidate() } + advertisementTokens.forEach { $0.invalidate() } + heartbeatTokens.forEach { $0.invalidate() } + sensorSettingsTokens.forEach { $0.invalidate() } stateToken?.invalidate() backgroundToken?.invalidate() alertDidChangeToken?.invalidate() @@ -750,12 +773,13 @@ extension CardsPresenter { } // MARK: - CardsViewOutput + extension CardsPresenter: CardsViewOutput { func viewDidLoad() { startObservingAppState() startMutedTillTimer() } - + func viewWillAppear() { guard viewModels.count > 0 else { return @@ -779,7 +803,8 @@ extension CardsPresenter: CardsViewOutput { || background.isConnected(uuid: luid.value) || !viewModel.isConnectable.value.bound || !viewModel.isOwner.value.bound - || (settings.cloudModeEnabled && viewModel.isCloud.value.bound) { + || (settings.cloudModeEnabled && viewModel.isCloud.value.bound) + { openTagSettingsScreens(viewModel: viewModel) } else { view?.showKeepConnectionDialogSettings(for: viewModel) @@ -796,11 +821,13 @@ extension CardsPresenter: CardsViewOutput { || background.isConnected(uuid: luid.value) || !viewModel.isConnectable.value.bound || !viewModel.isOwner.value.bound - || (settings.cloudModeEnabled && viewModel.isCloud.value.bound) { + || (settings.cloudModeEnabled && viewModel.isCloud.value.bound) + { if let sensor = ruuviTags .first(where: { - ($0.macId != nil && ($0.macId?.any == viewModel.mac.value)) - }) { + $0.macId != nil && ($0.macId?.any == viewModel.mac.value) + }) + { showCharts(for: sensor) } } else { @@ -809,8 +836,9 @@ extension CardsPresenter: CardsViewOutput { } else if viewModel.mac.value != nil { if let sensor = ruuviTags .first(where: { - ($0.macId != nil && ($0.macId?.any == viewModel.mac.value)) - }) { + $0.macId != nil && ($0.macId?.any == viewModel.mac.value) + }) + { showCharts(for: sensor) } } else { @@ -819,16 +847,18 @@ extension CardsPresenter: CardsViewOutput { } func viewDidTriggerNavigateChart(to viewModel: CardsViewModel) { - if let tagCharts = tagCharts, let sensor = ruuviTags + if let tagCharts, let sensor = ruuviTags .first(where: { - ($0.macId != nil && ($0.macId?.any == viewModel.mac.value)) - }) { + $0.macId != nil && ($0.macId?.any == viewModel.mac.value) + }) + { tagCharts.scrollTo(ruuviTag: sensor) } } - func viewDidTriggerDismissChart(for viewModel: CardsViewModel, - dismissParent: Bool) { + func viewDidTriggerDismissChart(for _: CardsViewModel, + dismissParent: Bool) + { tagCharts?.notifyDismissInstruction(dismissParent: dismissParent) } @@ -843,29 +873,31 @@ extension CardsPresenter: CardsViewOutput { } view?.showChart(module: module) } - + func viewDidDismissKeepConnectionDialogChart(for viewModel: CardsViewModel) { if let luid = viewModel.luid.value { settings.setKeepConnectionDialogWasShown(for: luid) if let sensor = ruuviTags .first(where: { - ($0.macId != nil && ($0.macId?.any == viewModel.mac.value)) - }) { + $0.macId != nil && ($0.macId?.any == viewModel.mac.value) + }) + { showCharts(for: sensor) } } else { errorPresenter.present(error: UnexpectedError.viewModelUUIDIsNil) } } - + func viewDidConfirmToKeepConnectionChart(to viewModel: CardsViewModel) { if let luid = viewModel.luid.value { connectionPersistence.setKeepConnection(true, for: luid) settings.setKeepConnectionDialogWasShown(for: luid) if let sensor = ruuviTags .first(where: { - ($0.macId != nil && ($0.macId?.any == viewModel.mac.value)) - }) { + $0.macId != nil && ($0.macId?.any == viewModel.mac.value) + }) + { showCharts(for: sensor) } } else { @@ -881,7 +913,7 @@ extension CardsPresenter: CardsViewOutput { errorPresenter.present(error: UnexpectedError.viewModelUUIDIsNil) } } - + func viewDidConfirmToKeepConnectionSettings(to viewModel: CardsViewModel) { if let luid = viewModel.luid.value { connectionPersistence.setKeepConnection(true, for: luid) @@ -896,7 +928,8 @@ extension CardsPresenter: CardsViewOutput { guard let luid = viewModel.luid.value, let version = viewModel.version.value, version < 5, viewModel.isOwner.value.bound, - featureToggleService.isEnabled(.legacyFirmwareUpdatePopup) else { + featureToggleService.isEnabled(.legacyFirmwareUpdatePopup) + else { return } if !settings.firmwareUpdateDialogWasShown(for: luid) { @@ -907,8 +940,9 @@ extension CardsPresenter: CardsViewOutput { func viewDidConfirmFirmwareUpdate(for viewModel: CardsViewModel) { if let sensor = ruuviTags .first(where: { - ($0.luid != nil && ($0.luid?.any == viewModel.luid.value)) - }) { + $0.luid != nil && ($0.luid?.any == viewModel.luid.value) + }) + { router.openUpdateFirmware(ruuviTag: sensor) } } @@ -916,7 +950,7 @@ extension CardsPresenter: CardsViewOutput { func viewDidIgnoreFirmwareUpdateDialog(for viewModel: CardsViewModel) { view?.showFirmwareDismissConfirmationUpdateDialog(for: viewModel) } - + func viewDidDismissFirmwareUpdateDialog(for viewModel: CardsViewModel) { guard let luid = viewModel.luid.value else { return } settings.setFirmwareUpdateDialogWasShown(for: luid) @@ -926,8 +960,9 @@ extension CardsPresenter: CardsViewOutput { if let sensor = ruuviTags .first(where: { ($0.luid != nil && ($0.luid?.any == viewModel.luid.value)) - || ($0.macId != nil && ($0.macId?.any == viewModel.mac.value)) - }) { + || ($0.macId != nil && ($0.macId?.any == viewModel.mac.value)) + }) + { updateVisibleCard(from: viewModel) checkFirmwareVersion(for: sensor) } @@ -940,9 +975,11 @@ extension CardsPresenter: CardsViewOutput { } // MARK: - TagChartsModuleOutput + extension CardsPresenter: TagChartsViewModuleOutput { func tagChartSafeToClose(module: TagChartsViewModuleInput, - dismissParent: Bool) { + dismissParent: Bool) + { module.dismiss(completion: { [weak self] in if dismissParent { self?.viewShouldDismiss() @@ -953,53 +990,57 @@ extension CardsPresenter: TagChartsViewModuleOutput { } func tagChartSafeToSwipe( - to ruuviTag: AnyRuuviTagSensor, module: TagChartsViewModuleInput + to ruuviTag: AnyRuuviTagSensor, module _: TagChartsViewModuleInput ) { if let viewModel = viewModels.first(where: { - return ($0.luid.value != nil && $0.luid.value == ruuviTag.luid?.any) + ($0.luid.value != nil && $0.luid.value == ruuviTag.luid?.any) || ($0.mac.value != nil && $0.mac.value == ruuviTag.macId?.any) }) { updateVisibleCard(from: viewModel, - triggerScroll: true) + triggerScroll: true) view?.scroll(to: visibleViewModelIndex) } } } // MARK: - RuuviNotifierObserver + extension CardsPresenter: RuuviNotifierObserver { - func ruuvi(notifier: RuuviNotifier, isTriggered: Bool, for uuid: String) { + func ruuvi(notifier _: RuuviNotifier, isTriggered: Bool, for uuid: String) { viewModels - .filter({ $0.luid.value?.value == uuid || $0.mac.value?.value == uuid}) - .forEach({ viewModel in + .filter { $0.luid.value?.value == uuid || $0.mac.value?.value == uuid } + .forEach { viewModel in let newValue: AlertState = isTriggered ? .firing : .registered viewModel.alertState.value = newValue notifyUpdate(for: viewModel) - }) + } } } // MARK: - TagSettingsModuleOutput + extension CardsPresenter: TagSettingsModuleOutput { func tagSettingsDidDeleteTag(module: TagSettingsModuleInput, - ruuviTag: RuuviTagSensor) { + ruuviTag: RuuviTagSensor) + { module.dismiss(completion: { [weak self] in - guard let self = self else { return } - self.view?.dismissChart() - self.output?.cardsViewDidRefresh(module: self) - if let index = self.viewModels.firstIndex(where: { + guard let self else { return } + view?.dismissChart() + output?.cardsViewDidRefresh(module: self) + if let index = viewModels.firstIndex(where: { ($0.luid.value != nil && $0.luid.value == ruuviTag.luid?.any) || - ($0.mac.value != nil && $0.mac.value == ruuviTag.macId?.any) + ($0.mac.value != nil && $0.mac.value == ruuviTag.macId?.any) }) { - self.viewModels.remove(at: index) - self.view?.viewModels = self.viewModels + viewModels.remove(at: index) + view?.viewModels = viewModels } - if self.viewModels.count > 0, - let first = self.viewModels.first { - self.updateVisibleCard(from: first, triggerScroll: true) + if viewModels.count > 0, + let first = viewModels.first + { + updateVisibleCard(from: first, triggerScroll: true) } else { - self.viewShouldDismiss() + viewShouldDismiss() } }) } @@ -1010,8 +1051,8 @@ extension CardsPresenter: TagSettingsModuleOutput { } // MARK: - Private -extension CardsPresenter { +extension CardsPresenter { private func checkFirmwareVersion(for ruuviTag: RuuviTagSensor) { DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let sSelf = self else { return } @@ -1021,7 +1062,7 @@ extension CardsPresenter { } private func syncAlerts(ruuviTag: RuuviTagSensor, viewModel: CardsViewModel) { - AlertType.allCases.forEach { (type) in + AlertType.allCases.forEach { type in switch type { case .temperature: sync(temperature: type, @@ -1049,7 +1090,7 @@ extension CardsPresenter { viewModel.signalAlertState.value, viewModel.connectionAlertState.value, viewModel.movementAlertState.value, - viewModel.cloudConnectionAlertState.value + viewModel.cloudConnectionAlertState.value, ] if alertService.hasRegistrations(for: ruuviTag) { @@ -1069,10 +1110,11 @@ extension CardsPresenter { private func sync(temperature: AlertType, ruuviTag: RuuviTagSensor, - viewModel: CardsViewModel) { - + viewModel: CardsViewModel) + { if case .temperature = alertService.alert(for: ruuviTag, - of: temperature) { + of: temperature) + { viewModel.isTemperatureAlertOn.value = true } else { viewModel.isTemperatureAlertOn.value = false @@ -1082,8 +1124,8 @@ extension CardsPresenter { private func sync(relativeHumidity: AlertType, ruuviTag: RuuviTagSensor, - viewModel: CardsViewModel) { - + viewModel: CardsViewModel) + { if case .relativeHumidity = alertService.alert( for: ruuviTag, of: relativeHumidity @@ -1099,10 +1141,11 @@ extension CardsPresenter { private func sync(pressure: AlertType, ruuviTag: RuuviTagSensor, - viewModel: CardsViewModel) { - + viewModel: CardsViewModel) + { if case .pressure = alertService.alert(for: ruuviTag, - of: pressure) { + of: pressure) + { viewModel.isPressureAlertOn.value = true } else { viewModel.isPressureAlertOn.value = false @@ -1114,10 +1157,11 @@ extension CardsPresenter { private func sync(signal: AlertType, ruuviTag: RuuviTagSensor, - viewModel: CardsViewModel) { - + viewModel: CardsViewModel) + { if case .signal = alertService.alert(for: ruuviTag, - of: signal) { + of: signal) + { viewModel.isSignalAlertOn.value = true } else { viewModel.isSignalAlertOn.value = false @@ -1129,8 +1173,8 @@ extension CardsPresenter { private func sync(connection: AlertType, ruuviTag: RuuviTagSensor, - viewModel: CardsViewModel) { - + viewModel: CardsViewModel) + { if case .connection = alertService.alert(for: ruuviTag, of: connection) { viewModel.isConnectionAlertOn.value = true } else { @@ -1143,8 +1187,8 @@ extension CardsPresenter { private func sync(movement: AlertType, ruuviTag: RuuviTagSensor, - viewModel: CardsViewModel) { - + viewModel: CardsViewModel) + { if case .movement = alertService.alert(for: ruuviTag, of: movement) { viewModel.isMovementAlertOn.value = true } else { @@ -1157,7 +1201,8 @@ extension CardsPresenter { private func sync(cloudConnection: AlertType, ruuviTag: PhysicalSensor, - viewModel: CardsViewModel) { + viewModel: CardsViewModel) + { if case .cloudConnection = alertService.alert(for: ruuviTag, of: cloudConnection) { viewModel.isCloudConnectionAlertOn.value = true } else { @@ -1168,32 +1213,38 @@ extension CardsPresenter { private func reloadMutedTill() { for viewModel in viewModels { if let mutedTill = viewModel.temperatureAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.temperatureAlertMutedTill.value = nil } if let mutedTill = viewModel.relativeHumidityAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.relativeHumidityAlertMutedTill.value = nil } if let mutedTill = viewModel.pressureAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.pressureAlertMutedTill.value = nil } if let mutedTill = viewModel.signalAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.signalAlertMutedTill.value = nil } if let mutedTill = viewModel.connectionAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.connectionAlertMutedTill.value = nil } if let mutedTill = viewModel.movementAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.movementAlertMutedTill.value = nil } } @@ -1201,25 +1252,24 @@ extension CardsPresenter { private func updateMutedTill(of type: AlertType, for uuid: String, - viewModel: CardsViewModel) { - - var observable: Observable - switch type { + viewModel: CardsViewModel) + { + var observable: Observable = switch type { case .temperature: - observable = viewModel.temperatureAlertMutedTill + viewModel.temperatureAlertMutedTill case .relativeHumidity: - observable = viewModel.relativeHumidityAlertMutedTill + viewModel.relativeHumidityAlertMutedTill case .pressure: - observable = viewModel.pressureAlertMutedTill + viewModel.pressureAlertMutedTill case .signal: - observable = viewModel.signalAlertMutedTill + viewModel.signalAlertMutedTill case .connection: - observable = viewModel.connectionAlertMutedTill + viewModel.connectionAlertMutedTill case .movement: - observable = viewModel.movementAlertMutedTill + viewModel.movementAlertMutedTill default: // Should never be here - observable = viewModel.temperatureAlertMutedTill + viewModel.temperatureAlertMutedTill } let date = alertService.mutedTill(type: type, for: uuid) @@ -1230,27 +1280,26 @@ extension CardsPresenter { private func updateIsOnState(of type: AlertType, for uuid: String, - viewModel: CardsViewModel) { - - var observable: Observable - switch type { + viewModel: CardsViewModel) + { + var observable: Observable = switch type { case .temperature: - observable = viewModel.isTemperatureAlertOn + viewModel.isTemperatureAlertOn case .relativeHumidity: - observable = viewModel.isRelativeHumidityAlertOn + viewModel.isRelativeHumidityAlertOn case .pressure: - observable = viewModel.isPressureAlertOn + viewModel.isPressureAlertOn case .signal: - observable = viewModel.isSignalAlertOn + viewModel.isSignalAlertOn case .connection: - observable = viewModel.isConnectionAlertOn + viewModel.isConnectionAlertOn case .movement: - observable = viewModel.isMovementAlertOn + viewModel.isMovementAlertOn case .cloudConnection: - observable = viewModel.isCloudConnectionAlertOn + viewModel.isCloudConnectionAlertOn default: // Should never be here - observable = viewModel.isTemperatureAlertOn + viewModel.isTemperatureAlertOn } let isOn = alertService.isOn(type: type, for: uuid) @@ -1260,16 +1309,16 @@ extension CardsPresenter { } private func notifyRestartAdvertisementDaemon() { - // Notify daemon to restart + // Notify daemon to restart NotificationCenter .default .post(name: .RuuviTagAdvertisementDaemonShouldRestart, object: nil, userInfo: nil) } - + private func notifyRestartHeartBeatDaemon() { - // Notify daemon to restart + // Notify daemon to restart NotificationCenter .default .post(name: .RuuviTagHeartBeatDaemonShouldRestart, @@ -1277,4 +1326,5 @@ extension CardsPresenter { userInfo: nil) } } + // swiftlint:enable file_length trailing_whitespace diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift index 1f383728b..9b4a86590 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift @@ -1,8 +1,8 @@ -import LightRoute import Foundation -import UIKit -import RuuviOntology +import LightRoute import RuuviLocal +import RuuviOntology +import UIKit class CardsRouter: NSObject, CardsRouterInput { weak var transitionHandler: UIViewController? @@ -17,7 +17,8 @@ class CardsRouter: NSObject, CardsRouterInput { func openTagSettings(ruuviTag: RuuviTagSensor, latestMeasurement: RuuviTagSensorRecord?, sensorSettings: SensorSettings?, - output: TagSettingsModuleOutput) { + output: TagSettingsModuleOutput) + { let factory: TagSettingsModuleFactory = TagSettingsModuleFactoryImpl() let module = factory.create() transitionHandler? @@ -29,15 +30,15 @@ class CardsRouter: NSObject, CardsRouterInput { if let presenter = module.output as? TagSettingsModuleInput { presenter.configure(output: output) presenter.configure(ruuviTag: ruuviTag, - latestMeasurement: latestMeasurement, - sensorSettings: sensorSettings) + latestMeasurement: latestMeasurement, + sensorSettings: sensorSettings) } } func openUpdateFirmware(ruuviTag: RuuviTagSensor) { let factory: DFUModuleFactory = DFUModuleFactoryImpl() let module = factory.create(for: ruuviTag) - self.dfuModule = module + dfuModule = module transitionHandler? .navigationController? .pushViewController( @@ -45,7 +46,6 @@ class CardsRouter: NSObject, CardsRouterInput { animated: true ) } - } extension CardsRouter: DiscoverRouterDelegate { @@ -55,7 +55,7 @@ extension CardsRouter: DiscoverRouterDelegate { func discoverRouterWantsCloseWithRuuviTagNavigation( _ router: DiscoverRouter, - ruuviTag: RuuviTagSensor + ruuviTag _: RuuviTagSensor ) { router.viewController.dismiss(animated: true) } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift index 2e434a2a9..41614629f 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift @@ -1,5 +1,5 @@ -import Foundation import BTKit +import Foundation import RuuviOntology import UIKit @@ -22,6 +22,6 @@ protocol CardsViewInput: ViewInput { } extension CardsViewInput { - func showChart(module: UIViewController) {} + func showChart(module _: UIViewController) {} func dismissChart() {} } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift index d3d02a34c..aafdcb6e1 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift @@ -1,8 +1,8 @@ -import UIKit import BTKit import Humidity -import RuuviOntology import RuuviLocal +import RuuviOntology +import UIKit enum CardType { case ruuvi @@ -11,66 +11,66 @@ enum CardType { struct CardsViewModel { var type: CardType = .ruuvi - var id: Observable = Observable() - var luid: Observable = Observable() - var mac: Observable = Observable() - var name: Observable = Observable() - var source: Observable = Observable() - var temperature: Observable = Observable() - var humidity: Observable = Observable() - var pressure: Observable = Observable() - var rssi: Observable = Observable() - var version: Observable = Observable() - var voltage: Observable = Observable() - let batteryNeedsReplacement: Observable = Observable() - var background: Observable = Observable() - var date: Observable = Observable() - var location: Observable = Observable() - var currentLocation: Observable = Observable() - var animateRSSI: Observable = Observable() - var isConnectable: Observable = Observable() - var isConnected: Observable = Observable() - var isCloud: Observable = Observable() - var isOwner: Observable = Observable() - var canShareTag: Observable = Observable(false) - var alertState: Observable = Observable() - var rhAlertLowerBound: Observable = Observable() - var rhAlertUpperBound: Observable = Observable() + var id: Observable = .init() + var luid: Observable = .init() + var mac: Observable = .init() + var name: Observable = .init() + var source: Observable = .init() + var temperature: Observable = .init() + var humidity: Observable = .init() + var pressure: Observable = .init() + var rssi: Observable = .init() + var version: Observable = .init() + var voltage: Observable = .init() + let batteryNeedsReplacement: Observable = .init() + var background: Observable = .init() + var date: Observable = .init() + var location: Observable = .init() + var currentLocation: Observable = .init() + var animateRSSI: Observable = .init() + var isConnectable: Observable = .init() + var isConnected: Observable = .init() + var isCloud: Observable = .init() + var isOwner: Observable = .init() + var canShareTag: Observable = .init(false) + var alertState: Observable = .init() + var rhAlertLowerBound: Observable = .init() + var rhAlertUpperBound: Observable = .init() var networkSyncStatus: Observable = .init(NetworkSyncStatus.none) - var movementCounter: Observable = Observable() - var isChartAvailable: Observable = Observable(false) - var isAlertAvailable: Observable = Observable(false) + var movementCounter: Observable = .init() + var isChartAvailable: Observable = .init(false) + var isAlertAvailable: Observable = .init(false) - var latestMeasurement: Observable = Observable() + var latestMeasurement: Observable = .init() - let isTemperatureAlertOn: Observable = Observable(false) - let temperatureAlertState: Observable = Observable() - let temperatureAlertMutedTill: Observable = Observable(nil) + let isTemperatureAlertOn: Observable = .init(false) + let temperatureAlertState: Observable = .init() + let temperatureAlertMutedTill: Observable = .init(nil) - let isRelativeHumidityAlertOn: Observable = Observable(false) - let relativeHumidityAlertState: Observable = Observable() - let relativeHumidityAlertMutedTill: Observable = Observable(nil) + let isRelativeHumidityAlertOn: Observable = .init(false) + let relativeHumidityAlertState: Observable = .init() + let relativeHumidityAlertMutedTill: Observable = .init(nil) - let isPressureAlertOn: Observable = Observable(false) - let pressureAlertState: Observable = Observable() - let pressureAlertMutedTill: Observable = Observable(nil) + let isPressureAlertOn: Observable = .init(false) + let pressureAlertState: Observable = .init() + let pressureAlertMutedTill: Observable = .init(nil) - let isSignalAlertOn: Observable = Observable(false) - let signalAlertState: Observable = Observable() - let signalAlertMutedTill: Observable = Observable(nil) + let isSignalAlertOn: Observable = .init(false) + let signalAlertState: Observable = .init() + let signalAlertMutedTill: Observable = .init(nil) - let isMovementAlertOn: Observable = Observable(false) - let movementAlertState: Observable = Observable() - let movementAlertMutedTill: Observable = Observable(nil) + let isMovementAlertOn: Observable = .init(false) + let movementAlertState: Observable = .init() + let movementAlertMutedTill: Observable = .init(nil) - let isConnectionAlertOn: Observable = Observable(false) - let connectionAlertState: Observable = Observable() - let connectionAlertMutedTill: Observable = Observable(nil) + let isConnectionAlertOn: Observable = .init(false) + let connectionAlertState: Observable = .init() + let connectionAlertMutedTill: Observable = .init(nil) - let isCloudConnectionAlertOn: Observable = Observable(false) - let cloudConnectionAlertState: Observable = Observable() + let isCloudConnectionAlertOn: Observable = .init(false) + let cloudConnectionAlertState: Observable = .init() - private var lastUpdateRssi: Observable = Observable(CFAbsoluteTimeGetCurrent()) + private var lastUpdateRssi: Observable = .init(CFAbsoluteTimeGetCurrent()) private let batteryStatusProvider = RuuviTagBatteryStatusProvider() @@ -89,7 +89,7 @@ struct CardsViewModel { isCloud.value = ruuviTag.isCloud isOwner.value = ruuviTag.isOwner canShareTag.value = - (ruuviTag.isOwner && ruuviTag.isClaimed) || ruuviTag.canShare + (ruuviTag.isOwner && ruuviTag.isClaimed) || ruuviTag.canShare } func update(_ record: RuuviTagSensorRecord) { @@ -106,8 +106,8 @@ struct CardsViewModel { source.value = record.source batteryNeedsReplacement.value = batteryStatusProvider - .batteryNeedsReplacement(temperature: record.temperature, - voltage: record.voltage) + .batteryNeedsReplacement(temperature: record.temperature, + voltage: record.voltage) isAlertAvailable.value = isCloud.value ?? false || isConnected.value ?? false } @@ -116,7 +116,8 @@ struct CardsViewModel { isConnectable.value = ruuviTag.isConnectable if let isChart = isChartAvailable.value, !isChart, - ruuviTag.isConnectable { + ruuviTag.isConnectable + { isChartAvailable.value = true } } @@ -144,12 +145,12 @@ extension CardsViewModel: Hashable { extension CardsViewModel: Equatable { public static func == (lhs: CardsViewModel, rhs: CardsViewModel) -> Bool { - return lhs.luid.value == rhs.luid.value && lhs.mac.value == rhs.mac.value + lhs.luid.value == rhs.luid.value && lhs.mac.value == rhs.mac.value } } extension CardsViewModel: Reorderable { var orderElement: String { - return id.value ?? UUID().uuidString + id.value ?? UUID().uuidString } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift index 26fb23009..da2e85f4f 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift @@ -1,7 +1,6 @@ import UIKit class CardsBackgroundView: UIView { - private lazy var cardImageView: UIImageView = { let iv = UIImageView() iv.contentMode = .scaleAspectFill @@ -22,7 +21,8 @@ class CardsBackgroundView: UIView { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -39,14 +39,15 @@ class CardsBackgroundView: UIView { extension CardsBackgroundView { func setBackgroundImage(with image: UIImage?, - withAnimation: Bool = true) { + withAnimation: Bool = true) + { if withAnimation { UIView.transition(with: cardImageView, duration: 0.3, options: .transitionCrossDissolve, animations: { [weak self] in - self?.cardImageView.image = image - }, completion: nil) + self?.cardImageView.image = image + }, completion: nil) } else { cardImageView.image = image } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsIndicatorView.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsIndicatorView.swift index 01b4790cd..2c72ce66c 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsIndicatorView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsIndicatorView.swift @@ -1,7 +1,6 @@ import UIKit class CardsIndicatorView: UIView { - private lazy var indicatorIconView: UIImageView = { let iv = UIImageView() iv.contentMode = .scaleAspectFit @@ -32,13 +31,14 @@ class CardsIndicatorView: UIView { super.init(frame: frame) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } convenience init(icon: UIImage?) { self.init() - self.indicatorIconView.image = icon + indicatorIconView.image = icon setUpUI() } @@ -83,7 +83,7 @@ class CardsIndicatorView: UIView { .topAnchor .constraint( lessThanOrEqualTo: indicatorValueLabel.topAnchor, - constant: 3 + constant: 3 ).isActive = true indicatorUnitLabel.trailingAnchor diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift index 5ce64fcaf..06c2cb737 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift @@ -1,12 +1,11 @@ -// swiftlint:disable file_length -import UIKit -import RuuviService import RuuviLocal import RuuviLocalization import RuuviOntology +import RuuviService +// swiftlint:disable file_length +import UIKit class CardsLargeImageCell: UICollectionViewCell { - private lazy var temperatureLabel: UILabel = { let label = UILabel() label.textColor = .white @@ -72,7 +71,8 @@ class CardsLargeImageCell: UICollectionViewCell { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -218,11 +218,10 @@ extension CardsLargeImageCell { } extension CardsLargeImageCell { - // swiftlint:disable:next function_body_length cyclomatic_complexity func configure(with viewModel: CardsViewModel, - measurementService: RuuviServiceMeasurement?) { - + measurementService: RuuviServiceMeasurement?) + { // Temp if let temp = measurementService?.stringWithoutSign(for: viewModel.temperature.value) { temperatureLabel.text = temp.components(separatedBy: String.nbsp).first @@ -238,7 +237,8 @@ extension CardsLargeImageCell { // Humidity if let humidity = viewModel.humidity.value, - let measurementService = measurementService { + let measurementService + { hideHumidityView(hide: false) let humidityValue = measurementService.stringWithoutSign( for: humidity, @@ -247,7 +247,7 @@ extension CardsLargeImageCell { let humidityUnit = measurementService.units.humidityUnit let humidityUnitSymbol = humidityUnit.symbol let temperatureUnitSymbol = measurementService.units.temperatureUnit.symbol - let unit = humidityUnit == .dew ? temperatureUnitSymbol + let unit = humidityUnit == .dew ? temperatureUnitSymbol : humidityUnitSymbol humidityView.setValue(with: humidityValue, unit: unit) @@ -309,7 +309,8 @@ extension CardsLargeImageCell { // Battery stat if let batteryLow = viewModel.batteryNeedsReplacement.value, - batteryLow { + batteryLow + { batteryLevelView.isHidden = false batteryLevelViewHeight.constant = 24 } else { @@ -332,9 +333,9 @@ extension CardsLargeImageCell { timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, - block: { [weak self] (_) in - self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message - }) + block: { [weak self] _ in + self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message + }) } private func startObservingNetworkSyncNotification(for macId: AnyMACIdentifier) { @@ -347,13 +348,14 @@ extension CardsLargeImageCell { object: nil, queue: .main, using: { [weak self] notification in - guard let mac = notification.userInfo?[NetworkSyncStatusKey.mac] as? MACIdentifier, - let status = notification.userInfo?[NetworkSyncStatusKey.status] as? NetworkSyncStatus, - mac.any == macId else { - return - } - self?.updateSyncLabel(with: status) - }) + guard let mac = notification.userInfo?[NetworkSyncStatusKey.mac] as? MACIdentifier, + let status = notification.userInfo?[NetworkSyncStatusKey.status] as? NetworkSyncStatus, + mac.any == macId + else { + return + } + self?.updateSyncLabel(with: status) + }) } private func updateSyncLabel(with status: NetworkSyncStatus) { diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift index b4a5e7da9..e72b1f337 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift @@ -1,13 +1,12 @@ -// swiftlint:disable file_length -import UIKit import Humidity -import RuuviOntology import RuuviLocal -import RuuviService import RuuviLocalization +import RuuviOntology +import RuuviService +// swiftlint:disable file_length +import UIKit class CardsViewController: UIViewController { - // Configuration var output: CardsViewOutput! var measurementService: RuuviServiceMeasurement! { @@ -21,6 +20,7 @@ class CardsViewController: UIViewController { updateUI() } } + var scrollIndex: Int = 0 private var currentPage: Int = 0 { @@ -28,11 +28,13 @@ class CardsViewController: UIViewController { setArrowButtonsVisibility(with: currentPage) } } + private static let reuseIdentifier: String = "reuseIdentifier" func cell(collectionView: UICollectionView, indexPath: IndexPath, - viewModel: CardsViewModel) -> UICollectionViewCell? { + viewModel: CardsViewModel) -> UICollectionViewCell? + { let cell = collectionView.dequeueReusableCell( withReuseIdentifier: Self.reuseIdentifier, for: indexPath @@ -66,7 +68,7 @@ class CardsViewController: UIViewController { // Action Buttons private lazy var backButton: UIButton = { - let button = UIButton() + let button = UIButton() button.tintColor = .white let buttonImage = RuuviAssets.backButtonImage button.setImage(buttonImage, for: .normal) @@ -86,7 +88,7 @@ class CardsViewController: UIViewController { /// This button is used to be able to tap the alert button when /// the alert icon is blinking. private lazy var alertButtonHidden: UIButton = { - let button = UIButton() + let button = UIButton() button.backgroundColor = .clear button.addTarget(self, action: #selector(alertButtonDidTap), for: .touchUpInside) return button @@ -186,7 +188,7 @@ class CardsViewController: UIViewController { private var isChartsShowing: Bool = false override var preferredStatusBarStyle: UIStatusBarStyle { - return .lightContent + .lightContent } deinit { @@ -195,6 +197,7 @@ class CardsViewController: UIViewController { } // MARK: - View lifecycle + extension CardsViewController { override func viewDidLoad() { super.viewDidLoad() @@ -242,14 +245,14 @@ extension CardsViewController { } } -extension CardsViewController { - fileprivate func setUpUI() { +private extension CardsViewController { + func setUpUI() { setUpBaseView() setUpHeaderView() setUpContentView() } - fileprivate func setUpBaseView() { + func setUpBaseView() { view.backgroundColor = RuuviColor.ruuviPrimary view.addSubview(cardBackgroundView) @@ -260,7 +263,7 @@ extension CardsViewController { chartViewBackground.alpha = 0 } - fileprivate func setUpHeaderView() { + func setUpHeaderView() { let leftBarButtonView = UIView(color: .clear) leftBarButtonView.addSubview(backButton) @@ -311,8 +314,8 @@ extension CardsViewController { navigationItem.rightBarButtonItem = UIBarButtonItem(customView: rightBarButtonView) } - fileprivate func setUpContentView() { - let swipeToolbarView = UIView(color: .clear) + func setUpContentView() { + let swipeToolbarView = UIView(color: .clear) // Arrow buttons should stay above of collection view swipeToolbarView.addSubview(cardLeftArrowButton) cardLeftArrowButton.anchor( @@ -354,10 +357,10 @@ extension CardsViewController { trailing: view.safeRightAnchor) } - fileprivate func createLayout() -> UICollectionViewLayout { + func createLayout() -> UICollectionViewLayout { let sectionProvider = { (_: Int, _: NSCollectionLayoutEnvironment) - -> NSCollectionLayoutSection? in + -> NSCollectionLayoutSection? in let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0)) let item = NSCollectionLayoutItem(layoutSize: itemSize) @@ -387,8 +390,9 @@ extension CardsViewController { .default .addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, - queue: .main) { [weak self] _ in - self?.restartAnimations() + queue: .main) + { [weak self] _ in + self?.restartAnimations() } } } @@ -405,13 +409,15 @@ extension CardsViewController: UICollectionViewDelegate { } extension CardsViewController: UICollectionViewDataSource { - func collectionView(_ collectionView: UICollectionView, - numberOfItemsInSection section: Int) -> Int { - return viewModels.count + func collectionView(_: UICollectionView, + numberOfItemsInSection _: Int) -> Int + { + viewModels.count } func collectionView(_ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell + { guard let cell = cell( collectionView: collectionView, indexPath: indexPath, @@ -424,7 +430,7 @@ extension CardsViewController: UICollectionViewDataSource { } extension CardsViewController { - @objc fileprivate func backButtonDidTap() { + @objc private func backButtonDidTap() { // TODO: Handle the case when chart visible and sync ongoing. if isChartsShowing { guard let viewModel = currentVisibleItem else { @@ -437,14 +443,14 @@ extension CardsViewController { } } - @objc fileprivate func alertButtonDidTap() { + @objc private func alertButtonDidTap() { guard let viewModel = currentVisibleItem else { return } output.viewDidTriggerSettings(for: viewModel) } - @objc fileprivate func chartButtonDidTap() { + @objc private func chartButtonDidTap() { guard let viewModel = currentVisibleItem else { return } @@ -472,16 +478,16 @@ extension CardsViewController { func dismissChart() { chartButton.image = RuuviAssets.chartsIcon chartViewBackground.alpha = 0 - children.forEach({ + children.forEach { $0.willMove(toParent: nil) $0.view.removeFromSuperview() $0.removeFromParent() - }) + } isChartsShowing = false collectionView.isHidden = false } - @objc fileprivate func settingsButtonDidTap() { + @objc private func settingsButtonDidTap() { guard let viewModel = currentVisibleItem else { return } @@ -489,26 +495,26 @@ extension CardsViewController { output.viewDidTriggerSettings(for: viewModel) } - @objc fileprivate func cardLeftArrowButtonDidTap() { + @objc private func cardLeftArrowButtonDidTap() { guard viewModels.count > 0 else { return } let scrollToPageIndex = currentPage - 1 - if scrollToPageIndex >= 0 && scrollToPageIndex < viewModels.count { + if scrollToPageIndex >= 0, scrollToPageIndex < viewModels.count { performPostScrollActions(with: scrollToPageIndex, scroll: true) } } - @objc fileprivate func cardRightArrowButtonDidTap() { + @objc private func cardRightArrowButtonDidTap() { guard viewModels.count > 0 else { return } let scrollToPageIndex = currentPage + 1 - if scrollToPageIndex >= 0 && scrollToPageIndex < viewModels.count { + if scrollToPageIndex >= 0, scrollToPageIndex < viewModels.count { performPostScrollActions(with: scrollToPageIndex, scroll: true) } } } // MARK: - CardsViewInput -extension CardsViewController: CardsViewInput { +extension CardsViewController: CardsViewInput { func viewShouldDismiss() { output.viewShouldDismiss() } @@ -516,11 +522,12 @@ extension CardsViewController: CardsViewInput { func applyUpdate(to viewModel: CardsViewModel) { if let index = viewModels.firstIndex(where: { vm in vm.luid.value != nil && vm.luid.value == viewModel.luid.value || - vm.mac.value != nil && vm.mac.value == viewModel.mac.value + vm.mac.value != nil && vm.mac.value == viewModel.mac.value }) { let indexPath = IndexPath(item: index, section: 0) if let cell = collectionView - .cellForItem(at: indexPath) as? CardsLargeImageCell { + .cellForItem(at: indexPath) as? CardsLargeImageCell + { cell.configure( with: viewModel, measurementService: measurementService ) @@ -531,7 +538,8 @@ extension CardsViewController: CardsViewInput { } func changeCardBackground(of viewModel: CardsViewModel, - to image: UIImage?) { + to image: UIImage?) + { if viewModel == currentVisibleItem { updateCardInfo(with: viewModel.name.value, image: image) } @@ -547,20 +555,22 @@ extension CardsViewController: CardsViewInput { let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) alertVC.addAction(UIAlertAction(title: RuuviLocalization.PermissionPresenter.settings, style: .default, handler: { _ in - guard let url = URL(string: userDeclined ? - UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), - UIApplication.shared.canOpenURL(url) else { - return - } - UIApplication.shared.open(url) - })) + guard let url = URL(string: userDeclined ? + UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), + UIApplication.shared.canOpenURL(url) + else { + return + } + UIApplication.shared.open(url) + })) alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) } func scroll(to index: Int) { guard viewModels.count > 0, - index < viewModels.count else { + index < viewModels.count + else { return } let viewModel = viewModels[index] @@ -649,7 +659,8 @@ extension CardsViewController: CardsViewInput { extension CardsViewController: RuuviServiceMeasurementDelegate { func measurementServiceDidUpdateUnit() { guard isViewLoaded, - let viewModel = currentVisibleItem else { + let viewModel = currentVisibleItem + else { return } applyUpdate(to: viewModel) @@ -657,7 +668,7 @@ extension CardsViewController: RuuviServiceMeasurementDelegate { } extension CardsViewController { - fileprivate func updateUI() { + private func updateUI() { applySnapshot() if scrollIndex < viewModels.count { @@ -667,51 +678,51 @@ extension CardsViewController { } private func bindCurrentVisibleItem() { - guard let currentVisibleItem = currentVisibleItem else { + guard let currentVisibleItem else { return } - view.bind(currentVisibleItem.name) { [weak self] (_, name) in + view.bind(currentVisibleItem.name) { [weak self] _, name in self?.updateCardInfo(with: name, image: currentVisibleItem.background.value) } - view.bind(currentVisibleItem.temperatureAlertMutedTill) { [weak self] (_, _) in + view.bind(currentVisibleItem.temperatureAlertMutedTill) { [weak self] _, _ in self?.restartAnimations() } - view.bind(currentVisibleItem.relativeHumidityAlertMutedTill) { [weak self] (_, _) in + view.bind(currentVisibleItem.relativeHumidityAlertMutedTill) { [weak self] _, _ in self?.restartAnimations() } - view.bind(currentVisibleItem.pressureAlertMutedTill) { [weak self] (_, _) in + view.bind(currentVisibleItem.pressureAlertMutedTill) { [weak self] _, _ in self?.restartAnimations() } - view.bind(currentVisibleItem.signalAlertMutedTill) { [weak self] (_, _) in + view.bind(currentVisibleItem.signalAlertMutedTill) { [weak self] _, _ in self?.restartAnimations() } - view.bind(currentVisibleItem.movementAlertMutedTill) { [weak self] (_, _) in + view.bind(currentVisibleItem.movementAlertMutedTill) { [weak self] _, _ in self?.restartAnimations() } - view.bind(currentVisibleItem.connectionAlertMutedTill) { [weak self] (_, _) in + view.bind(currentVisibleItem.connectionAlertMutedTill) { [weak self] _, _ in self?.restartAnimations() } - view.bind(currentVisibleItem.alertState) { [weak self] (_, _) in + view.bind(currentVisibleItem.alertState) { [weak self] _, _ in self?.restartAnimations() } - view.bind(currentVisibleItem.isChartAvailable) { [weak self] (_, _) in + view.bind(currentVisibleItem.isChartAvailable) { [weak self] _, _ in self?.updateTopActionButtonVisibility() } - view.bind(currentVisibleItem.isAlertAvailable) { [weak self] (_, _) in + view.bind(currentVisibleItem.isAlertAvailable) { [weak self] _, _ in self?.updateTopActionButtonVisibility() } - view.bind(currentVisibleItem.isConnected) { [weak self] (_, _) in + view.bind(currentVisibleItem.isConnected) { [weak self] _, _ in self?.updateTopActionButtonVisibility() } } @@ -730,7 +741,7 @@ extension CardsViewController { currentVisibleItem?.pressureAlertMutedTill.value, currentVisibleItem?.signalAlertMutedTill.value, currentVisibleItem?.movementAlertMutedTill.value, - currentVisibleItem?.connectionAlertMutedTill.value + currentVisibleItem?.connectionAlertMutedTill.value, ] if mutedTills.first(where: { $0 != nil }) != nil { @@ -750,15 +761,15 @@ extension CardsViewController { case .firing: alertButton.alpha = 1.0 alertButton.image = RuuviAssets.alertActiveImage - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { UIView.animate(withDuration: 0.5, delay: 0, options: [.repeat, .autoreverse], animations: { [weak self] in - self?.alertButton.alpha = 0.0 - }) - }) + self?.alertButton.alpha = 0.0 + }) + } } } else { alertButton.image = nil @@ -767,11 +778,10 @@ extension CardsViewController { } func removeAlertAnimations(alpha: Double = 1) { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, - execute: { [weak self] in + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in self?.alertButton.layer.removeAllAnimations() self?.alertButton.alpha = alpha - }) + } } private func updateTopActionButtonVisibility() { @@ -828,7 +838,7 @@ extension CardsViewController { output.viewDidTriggerNavigateChart(to: currentItem) } else { currentPage = index - self.currentVisibleItem = currentItem + currentVisibleItem = currentItem restartAnimations() output.viewDidScroll(to: currentItem) output.viewDidTriggerFirmwareUpdateDialog(for: currentItem) diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsModuleFactory.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsModuleFactory.swift index c34e526b0..75345a253 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsModuleFactory.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsModuleFactory.swift @@ -1,20 +1,19 @@ -import Foundation -import RuuviOntology import BTKit -import RuuviStorage -import RuuviReactor +import Foundation import RuuviLocal -import RuuviPool -import RuuviService import RuuviNotifier +import RuuviOntology +import RuuviPool import RuuviPresenters +import RuuviReactor +import RuuviService +import RuuviStorage protocol TagChartsModuleFactory { func create() -> TagChartsViewController } final class TagChartsModuleFactoryImpl: TagChartsModuleFactory { - func create() -> TagChartsViewController { let r = AppAssembly.shared.assembler.resolver diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsViewConfigurator.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsViewConfigurator.swift index a16a4bf3f..0aeb856e0 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsViewConfigurator.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsViewConfigurator.swift @@ -1,17 +1,18 @@ -import Foundation -import RuuviOntology import BTKit -import RuuviStorage -import RuuviReactor +import Foundation import RuuviLocal -import RuuviPool -import RuuviService import RuuviNotifier +import RuuviOntology +import RuuviPool import RuuviPresenters +import RuuviReactor +import RuuviService +import RuuviStorage class TagChartsViewConfigurator { func configure(view: TagChartsViewController, - ruuviTag: AnyRuuviTagSensor) { + ruuviTag: AnyRuuviTagSensor) + { let r = AppAssembly.shared.assembler.resolver let interactor = TagChartsViewInteractor() diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift index 74aeb0069..2d228f932 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift @@ -1,18 +1,18 @@ -import Foundation import Charts +import Foundation import RuuviOntology public class CustomXAxisRenderer: XAxisRenderer { - private var from: Double = 0 convenience init(from time: Double, viewPortHandler: ViewPortHandler, axis: XAxis, transformer: Transformer?) { self.init(viewPortHandler: viewPortHandler, axis: axis, transformer: transformer) - self.from = time + from = time } - public override func computeAxisValues(min: Double, - max: Double) { + override public func computeAxisValues(min: Double, + max: Double) + { let labelCount = axis.labelCount let range = abs(max - min) @@ -20,8 +20,7 @@ public class CustomXAxisRenderer: XAxisRenderer { labelCount != 0, range > 0, range.isFinite - else - { + else { axis.entries = [] axis.centeredEntries = [] return @@ -49,7 +48,7 @@ public class CustomXAxisRenderer: XAxisRenderer { axis.entries.reserveCapacity(numberOfPoints) axis.entries = [Double](repeating: 0, count: numberOfPoints) - for i in 0.. 3600) ? TimeZone.autoupdatingCurrent.secondsFromGMT(for: date) : 0 @@ -60,34 +59,34 @@ public class CustomXAxisRenderer: XAxisRenderer { } private func getClosestPredefinedInterval(from rawInterval: Double) -> Int64 { - return intervals().min(by: { + intervals().min(by: { abs($0 - Int64(rawInterval)) < abs($1 - Int64(rawInterval)) }) ?? 0 } private func intervals() -> [Int64] { let intervals: [Int64] = [ - 60, // 1m - 120, // 2m - 180, // 3m - 300, // 5m - 600, // 10m - 900, // 15m - 1800, // 30m - 3600, // 1h - 7200, // 2h - 10800, // 3h - 21600, // 6h - 43200, // 12h - 86400, // 1d - 172800 // 2d + 60, // 1m + 120, // 2m + 180, // 3m + 300, // 5m + 600, // 10m + 900, // 15m + 1800, // 30m + 3600, // 1h + 7200, // 2h + 10800, // 3h + 21600, // 6h + 43200, // 12h + 86400, // 1d + 172_800, // 2d ] return intervals } - } + extension Double { func toLong() -> Int64 { - return Int64(self) + Int64(self) } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift index b1272a2c0..70aa2f3a2 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift @@ -1,5 +1,5 @@ -import UIKit import Charts +import UIKit class CustomYAxisRenderer: YAxisRenderer { private let intervals = [ @@ -28,11 +28,11 @@ class CustomYAxisRenderer: YAxisRenderer { 20000.0, 25000.0, 50000.0, - 100000.0, - 200000.0, - 250000.0, - 500000.0, - 1000000.0 + 100_000.0, + 200_000.0, + 250_000.0, + 500_000.0, + 1_000_000.0, ] override func computeAxisValues(min: Double, max: Double) { @@ -75,6 +75,6 @@ class CustomYAxisRenderer: YAxisRenderer { } private func getClosestPredefinedInterval(_ rawInterval: Double) -> Double { - return intervals.min(by: { abs($0 - rawInterval) < abs($1 - rawInterval) }) ?? 0.0 + intervals.min(by: { abs($0 - rawInterval) < abs($1 - rawInterval) }) ?? 0.0 } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift index 0c283b855..9ff1ac9f7 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift @@ -1,7 +1,7 @@ -import Foundation import Charts +import Foundation -struct TagChartsHelper { +enum TagChartsHelper { static func newDataSet(entries: [ChartDataEntry] = []) -> LineChartDataSet { let lineChartDataSet = LineChartDataSet(entries: entries) lineChartDataSet.axisDependency = .left diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/XAxisValueFormatter.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/XAxisValueFormatter.swift index 40eb77ad6..719d702bb 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/XAxisValueFormatter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/XAxisValueFormatter.swift @@ -1,10 +1,9 @@ -import Foundation import Charts +import Foundation import RuuviOntology public class XAxisValueFormatter: NSObject, AxisValueFormatter { - - public func stringForValue(_ value: Double, axis: AxisBase?) -> String { + public func stringForValue(_ value: Double, axis _: AxisBase?) -> String { let date = Date(timeIntervalSince1970: value) if date.isStartOfTheDay() { diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift index 99ad45f71..a95d2543b 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift @@ -1,5 +1,5 @@ -import Foundation import Charts +import Foundation public class YAxisValueFormatter: NSObject, AxisValueFormatter { private let numberFormatter = NumberFormatter() @@ -12,7 +12,7 @@ public class YAxisValueFormatter: NSObject, AxisValueFormatter { numberFormatter.maximumFractionDigits = 1 } - public func stringForValue(_ value: Double, axis: AxisBase?) -> String { + public func stringForValue(_ value: Double, axis _: AxisBase?) -> String { guard let value = numberFormatter.string(from: NSNumber(value: value)) else { return "" } diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractor.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractor.swift index beaec1da6..f04545e5c 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractor.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractor.swift @@ -1,12 +1,12 @@ +import BTKit import Foundation import Future -import BTKit -import RuuviOntology -import RuuviStorage -import RuuviReactor import RuuviLocal +import RuuviOntology import RuuviPool +import RuuviReactor import RuuviService +import RuuviStorage class TagChartsViewInteractor { weak var presenter: TagChartsViewInteractorOutput! @@ -44,23 +44,27 @@ class TagChartsViewInteractor { timer?.invalidate() } } + // MARK: - TagChartsInteractorInput + extension TagChartsViewInteractor: TagChartsViewInteractorInput { func restartObservingTags() { ruuviTagSensorObservationToken?.invalidate() - ruuviTagSensorObservationToken = ruuviReactor.observe({ [weak self] change in + ruuviTagSensorObservationToken = ruuviReactor.observe { [weak self] change in switch change { - case .initial(let sensors): + case let .initial(sensors): self?.sensors = sensors if let id = self?.ruuviTagSensor.id, - let sensor = sensors.first(where: {$0.id == id}) { + let sensor = sensors.first(where: { $0.id == id }) + { self?.ruuviTagSensor = sensor } - case .insert(let sensor): + case let .insert(sensor): self?.sensors.append(sensor) - case .update(let sensor): + case let .update(sensor): if self?.ruuviTagSensor.id == sensor.id, - let index = self?.sensors.firstIndex(where: {$0.id == sensor.id}) { + let index = self?.sensors.firstIndex(where: { $0.id == sensor.id }) + { self?.ruuviTagSensor = sensor self?.sensors[index] = sensor self?.presenter.interactorDidUpdate(sensor: sensor) @@ -68,7 +72,7 @@ extension TagChartsViewInteractor: TagChartsViewInteractorInput { default: return } - }) + } } func stopObservingTags() { @@ -77,7 +81,8 @@ extension TagChartsViewInteractor: TagChartsViewInteractorInput { } func configure(withTag ruuviTag: AnyRuuviTagSensor, - andSettings settings: SensorSettings?) { + andSettings settings: SensorSettings?) + { ruuviTagSensor = ruuviTag sensorSettings = settings lastMeasurement = nil @@ -87,8 +92,8 @@ extension TagChartsViewInteractor: TagChartsViewInteractorInput { DispatchQueue.global(qos: .userInitiated).async { [weak self] in self?.fetchPoints { [weak self] in - guard let self = self else { return } - self.presenter.interactorDidUpdate(sensor: self.ruuviTagSensor) + guard let self else { return } + presenter.interactorDidUpdate(sensor: ruuviTagSensor) } } } @@ -112,13 +117,13 @@ extension TagChartsViewInteractor: TagChartsViewInteractorInput { func export() -> Future { let promise = Promise() - guard let sensorSettings = sensorSettings else { + guard let sensorSettings else { return promise.future } let op = exportService.csvLog(for: ruuviTagSensor.id, settings: sensorSettings) - op.on(success: { (url) in + op.on(success: { url in promise.succeed(value: url) - }, failure: { (error) in + }, failure: { error in promise.fail(error: .ruuviService(error)) }) return promise.future @@ -152,8 +157,9 @@ extension TagChartsViewInteractor: TagChartsViewInteractorInput { if syncFrom == nil { syncFrom = historyLength } else if let from = syncFrom, - let history = historyLength, - from < history { + let history = historyLength, + from < history + { syncFrom = history } @@ -170,7 +176,7 @@ extension TagChartsViewInteractor: TagChartsViewInteractorInput { } self?.gattSyncInterruptedByUser = false promise.succeed(value: ()) - }, failure: {error in + }, failure: { error in promise.fail(error: .ruuviService(error)) }) return promise.future @@ -185,8 +191,8 @@ extension TagChartsViewInteractor: TagChartsViewInteractorInput { let op = gattService.stopGattSync(for: luid.value) op.on(success: { [weak self] response in self?.gattSyncInterruptedByUser = true - promise.succeed(value: (response)) - }, failure: {error in + promise.succeed(value: response) + }, failure: { error in promise.fail(error: .ruuviService(error)) }) return promise.future @@ -195,7 +201,7 @@ extension TagChartsViewInteractor: TagChartsViewInteractorInput { func deleteAllRecords(for sensor: RuuviTagSensor) -> Future { let promise = Promise() ruuviSensorRecords.clear(for: sensor) - .on(failure: {(error) in + .on(failure: { error in promise.fail(error: .ruuviService(error)) }, completion: { [weak self] in self?.localSyncState.setSyncDate(nil, for: self?.ruuviTagSensor.macId) @@ -213,6 +219,7 @@ extension TagChartsViewInteractor: TagChartsViewInteractorInput { } // MARK: - Private + extension TagChartsViewInteractor { private func restartScheduler() { let timerInterval = settings.appIsOnForeground ? 2 : settings.chartIntervalSeconds @@ -220,21 +227,22 @@ extension TagChartsViewInteractor { timer = Timer.scheduledTimer( withTimeInterval: TimeInterval(timerInterval), repeats: true, - block: { [weak self] (_) in + block: { [weak self] _ in self?.fetchLastFromDate() self?.removeFirst() - }) + } + ) } private func removeFirst() { - guard !self.settings.chartDownsamplingOn else { return } + guard !settings.chartDownsamplingOn else { return } let cropDate = Calendar.autoupdatingCurrent.date( byAdding: .hour, value: -settings.dataPruningOffsetHours, to: Date() ) ?? Date.distantPast - let prunedResults = self.ruuviTagData.filter({ $0.date < cropDate}) - self.ruuviTagData.removeFirst(prunedResults.count) + let prunedResults = ruuviTagData.filter { $0.date < cropDate } + ruuviTagData.removeFirst(prunedResults.count) } private func fetchLast() { @@ -242,9 +250,9 @@ extension TagChartsViewInteractor { return } let op = ruuviStorage.readLatest(ruuviTagSensor) - op.on(success: { [weak self] (record) in + op.on(success: { [weak self] record in guard let sSelf = self else { return } - guard let record = record else { + guard let record else { sSelf.presenter.createChartModules(from: []) return } @@ -258,23 +266,25 @@ extension TagChartsViewInteractor { } sSelf.presenter.createChartModules(from: chartsCases) sSelf.presenter.updateLatestRecord(record) - }, failure: {[weak self] (error) in + }, failure: { [weak self] error in self?.presenter.interactorDidError(.ruuviStorage(error)) }) } private func fetchLastFromDate() { - guard let lastMeasurement = lastMeasurement, - let lastMeasurementRecord = lastMeasurementRecord else { + guard let lastMeasurement, + let lastMeasurementRecord + else { return } let op = ruuviStorage.readLast( ruuviTagSensor.id, from: lastMeasurement.date.timeIntervalSince1970 ) - op.on(success: { [weak self] (results) in + op.on(success: { [weak self] results in guard results.count > 0, - let last = results.last else { + let last = results.last + else { self?.presenter.updateLatestRecord(lastMeasurementRecord) return } @@ -284,7 +294,7 @@ extension TagChartsViewInteractor { sSelf.ruuviTagData.append(last.measurement) sSelf.insertMeasurements([last.measurement]) sSelf.presenter.updateLatestRecord(last) - }, failure: {[weak self] (error) in + }, failure: { [weak self] error in self?.presenter.updateLatestRecord(lastMeasurementRecord) self?.presenter.interactorDidError(.ruuviStorage(error)) }) @@ -293,13 +303,13 @@ extension TagChartsViewInteractor { private func fetchPoints(_ completion: (() -> Void)? = nil) { if settings.chartDownsamplingOn { fetchAll { [weak self] in - guard let self = self else { + guard let self else { return } - if self.ruuviTagData.count < self.minimumDownsampleThreshold { + if ruuviTagData.count < minimumDownsampleThreshold { completion?() } else { - self.fetchDownSampled(completion) + fetchDownSampled(completion) } } } else { @@ -322,9 +332,9 @@ extension TagChartsViewInteractor { after: date, with: TimeInterval(2) ) - op.on(success: { [weak self] (results) in - self?.ruuviTagData = results.map({ $0.measurement }) - }, failure: {[weak self] (error) in + op.on(success: { [weak self] results in + self?.ruuviTagData = results.map(\.measurement) + }, failure: { [weak self] error in self?.presenter.interactorDidError(.ruuviStorage(error)) }, completion: completion) } @@ -345,14 +355,15 @@ extension TagChartsViewInteractor { with: highDensityIntervalMinutes, pick: maximumPointsCount ) - op.on(success: { [weak self] (results) in - self?.ruuviTagData = results.map({ $0.measurement }) - }, failure: {[weak self] (error) in + op.on(success: { [weak self] results in + self?.ruuviTagData = results.map(\.measurement) + }, failure: { [weak self] error in self?.presenter.interactorDidError(.ruuviStorage(error)) }, completion: competion) } // MARK: - Charts + private func insertMeasurements(_ newValues: [RuuviMeasurement]) { presenter.insertMeasurements(newValues) } diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorInput.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorInput.swift index b85a7b307..eb4c587d3 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorInput.swift @@ -1,6 +1,6 @@ +import BTKit import Foundation import Future -import BTKit import RuuviOntology protocol TagChartsViewInteractorInput: AnyObject { diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleInput.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleInput.swift index b1b550fee..fea291a3b 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleInput.swift @@ -8,6 +8,7 @@ protocol TagChartsViewModuleInput: AnyObject { func notifyDismissInstruction(dismissParent: Bool) func dismiss(completion: (() -> Void)?) } + extension TagChartsViewModuleInput { func dismiss() { dismiss(completion: nil) diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift index a78385146..24e2ab955 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift @@ -1,33 +1,33 @@ -// swiftlint:disable file_length -import RuuviLocalization -import Foundation import BTKit -import UIKit import Charts +import CoreBluetooth +import Foundation import Future -import RuuviOntology -import RuuviStorage -import RuuviReactor import RuuviLocal -import RuuviService +// swiftlint:disable file_length +import RuuviLocalization import RuuviNotification import RuuviNotifier +import RuuviOntology import RuuviPresenters -import CoreBluetooth +import RuuviReactor +import RuuviService +import RuuviStorage +import UIKit class TagChartViewData: NSObject { var chartType: MeasurementType var chartData: LineChartData? init(chartType: MeasurementType, - chartData: LineChartData?) { + chartData: LineChartData?) + { self.chartType = chartType self.chartData = chartData } } class TagChartsViewPresenter: NSObject, TagChartsViewModuleInput { - weak var view: TagChartsViewInput? var interactor: TagChartsViewInteractorInput! @@ -89,15 +89,15 @@ class TagChartsViewPresenter: NSObject, TagChartsViewModuleInput { private var viewModel = TagChartsViewModel(type: .ruuvi) { didSet { - self.view?.viewModel = self.viewModel - self.view?.historyLengthInHours = self.settings.chartDurationHours - self.view?.showChartStat = self.settings.chartStatsOn - self.view?.showChartAll = self.settings.chartShowAll + view?.viewModel = viewModel + view?.historyLengthInHours = settings.chartDurationHours + view?.showChartStat = settings.chartStatsOn + view?.showChartAll = settings.chartShowAll } } private var isBluetoothPermissionGranted: Bool { - return CBCentralManager.authorization == .allowedAlways + CBCentralManager.authorization == .allowedAlways } var ruuviTagData: [RuuviMeasurement] = [] @@ -126,7 +126,7 @@ class TagChartsViewPresenter: NSObject, TagChartsViewModuleInput { output?.tagChartSafeToSwipe(to: ruuviTag, module: self) self.ruuviTag = ruuviTag - self.restartObserving() + restartObserving() } func notifyDismissInstruction(dismissParent: Bool) { @@ -146,7 +146,6 @@ class TagChartsViewPresenter: NSObject, TagChartsViewModuleInput { } extension TagChartsViewPresenter: TagChartsViewOutput { - func viewDidLoad() { startObservingBackgroundChanges() startObservingAlertChanges() @@ -192,14 +191,14 @@ extension TagChartsViewPresenter: TagChartsViewOutput { func viewDidStartSync(for viewModel: TagChartsViewModel) { // Check bluetooth - guard foreground.bluetoothState == .poweredOn || !isBluetoothPermissionGranted else { + guard foreground.bluetoothState == .poweredOn || !isBluetoothPermissionGranted else { view?.showBluetoothDisabled(userDeclined: !isBluetoothPermissionGranted) return } isSyncing = true let op = interactor.syncRecords { [weak self] progress in DispatchQueue.main.async { [weak self] in - guard let syncing = self?.isSyncing, syncing else { + guard let syncing = self?.isSyncing, syncing else { self?.view?.setSync(progress: nil, for: viewModel) return } @@ -218,7 +217,7 @@ extension TagChartsViewPresenter: TagChartsViewOutput { }) } - func viewDidTriggerStopSync(for viewModel: TagChartsViewModel) { + func viewDidTriggerStopSync(for _: TagChartsViewModel) { view?.showSyncAbortAlert(dismiss: false) } @@ -226,10 +225,10 @@ extension TagChartsViewPresenter: TagChartsViewOutput { view?.showClearConfirmationDialog(for: viewModel) } - func viewDidConfirmToClear(for viewModel: TagChartsViewModel) { + func viewDidConfirmToClear(for _: TagChartsViewModel) { activityPresenter.show(with: .loading(message: nil)) interactor.deleteAllRecords(for: ruuviTag) - .on(failure: {[weak self] (error) in + .on(failure: { [weak self] error in self?.errorPresenter.present(error: error) }, completion: { [weak self] in self?.activityPresenter.dismiss(immediately: true) @@ -250,7 +249,7 @@ extension TagChartsViewPresenter: TagChartsViewOutput { exportService.csvLog(for: ruuviTag.id, settings: sensorSettings) .on(success: { [weak self] url in self?.view?.showExportSheet(with: url) - }, failure: { [weak self] (error) in + }, failure: { [weak self] error in self?.errorPresenter.present(error: error) }, completion: { [weak self] in self?.activityPresenter.dismiss(immediately: true) @@ -277,7 +276,9 @@ extension TagChartsViewPresenter: TagChartsViewOutput { interactor.updateChartShowMinMaxAvgSetting(with: show) } } + // MARK: - TagChartsInteractorOutput + extension TagChartsViewPresenter: TagChartsViewInteractorOutput { func createChartModules(from: [MeasurementType]) { guard view != nil else { return } @@ -292,13 +293,14 @@ extension TagChartsViewPresenter: TagChartsViewInteractorOutput { func interactorDidUpdate(sensor: AnyRuuviTagSensor) { ruuviTag = sensor ruuviTagData = interactor.ruuviTagData - self.createChartData() + createChartData() } } // MARK: - RuuviNotifierObserver + extension TagChartsViewPresenter: RuuviNotifierObserver { - func ruuvi(notifier: RuuviNotifier, isTriggered: Bool, for uuid: String) { + func ruuvi(notifier _: RuuviNotifier, isTriggered: Bool, for uuid: String) { guard uuid == viewModel.uuid.value || uuid == viewModel.mac.value else { return } let newValue: AlertState = isTriggered ? .firing : .registered if newValue != viewModel.alertState.value { @@ -308,6 +310,7 @@ extension TagChartsViewPresenter: RuuviNotifierObserver { } // MARK: - Private + extension TagChartsViewPresenter { private func restartObserving() { shutDownModule() @@ -352,15 +355,17 @@ extension TagChartsViewPresenter { return } if let lastOpenedChart = settings.lastOpenedChart(), - lastOpenedChart != ruuviTag.id { + lastOpenedChart != ruuviTag.id + { view?.clearChartHistory() } settings.setLastOpenedChart(with: ruuviTag.id) } private func tryToShowSwipeUpHint() { - if UIWindow.isLandscape - && !settings.tagChartsLandscapeSwipeInstructionWasShown { + if UIWindow.isLandscape, + !settings.tagChartsLandscapeSwipeInstructionWasShown + { settings.tagChartsLandscapeSwipeInstructionWasShown = true view?.showSwipeUpInstruction() } @@ -404,13 +409,13 @@ extension TagChartsViewPresenter { guard let luid = ruuviTag.luid else { return } - advertisementToken = foreground.observe(self, uuid: luid.value, closure: { [weak self] (_, device) in + advertisementToken = foreground.observe(self, uuid: luid.value, closure: { [weak self] _, device in if let tag = device.ruuvi?.tag { self?.sync(device: tag, source: .advertisement) } }) - heartbeatToken = background.observe(self, uuid: luid.value, closure: { [weak self] (_, device) in + heartbeatToken = background.observe(self, uuid: luid.value, closure: { [weak self] _, device in if let tag = device.ruuvi?.tag { self?.sync(device: tag, source: .heartbeat) } @@ -418,7 +423,8 @@ extension TagChartsViewPresenter { } private func sync(device: RuuviTag, - source: RuuviTagSensorRecordSource) { + source: RuuviTagSensorRecordSource) + { if device.isConnected { if source == .heartbeat { if viewModel.isConnectable.value != device.isConnectable { @@ -442,7 +448,8 @@ extension TagChartsViewPresenter { .default .addObserver(forName: .TemperatureUnitDidChange, object: nil, - queue: .main) { [weak self] _ in + queue: .main) + { [weak self] _ in self?.interactor.restartObservingData() } humidityUnitToken = NotificationCenter @@ -451,52 +458,52 @@ extension TagChartsViewPresenter { object: nil, queue: .main, using: { [weak self] _ in - self?.interactor.restartObservingData() - }) + self?.interactor.restartObservingData() + }) pressureUnitToken = NotificationCenter .default .addObserver(forName: .PressureUnitDidChange, object: nil, queue: .main, using: { [weak self] _ in - self?.interactor.restartObservingData() - }) + self?.interactor.restartObservingData() + }) downsampleDidChangeToken = NotificationCenter .default .addObserver(forName: .DownsampleOnDidChange, object: nil, queue: .main, using: { [weak self] _ in - self?.interactor.restartObservingData() - }) + self?.interactor.restartObservingData() + }) chartDurationHourDidChangeToken = NotificationCenter .default .addObserver(forName: .ChartDurationHourDidChange, object: nil, queue: .main, using: { [weak self] _ in - guard let sSelf = self else { return } - sSelf.interactor.restartObservingData() - }) + guard let sSelf = self else { return } + sSelf.interactor.restartObservingData() + }) chartShowStatsStateDidChangeToken = NotificationCenter .default .addObserver(forName: .ChartStatsOnDidChange, object: nil, queue: .main, using: { [weak self] _ in - guard let sSelf = self else { return } - DispatchQueue.main.async { - sSelf.view?.showChartStat = sSelf.settings.chartStatsOn - } - }) + guard let sSelf = self else { return } + DispatchQueue.main.async { + sSelf.view?.showChartStat = sSelf.settings.chartStatsOn + } + }) chartDrawDotsDidChangeToken = NotificationCenter .default .addObserver(forName: .ChartDrawDotsOnDidChange, object: nil, queue: .main, using: { _ in - // TODO: Add this implemention when draw dots is back. - }) + // TODO: Add this implemention when draw dots is back. + }) } private func startObservingBackgroundChanges() { @@ -504,25 +511,26 @@ extension TagChartsViewPresenter { .default .addObserver(forName: .BackgroundPersistenceDidChangeBackground, object: nil, - queue: .main) { [weak self] notification in - guard let sSelf = self else { return } - if let userInfo = notification.userInfo { - let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier - let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier - if sSelf.viewModel.uuid.value == luid?.value || sSelf.viewModel.mac.value == macId?.value { - sSelf.ruuviSensorPropertiesService.getImage(for: sSelf.ruuviTag) - .on(success: { [weak sSelf] image in - sSelf?.viewModel.background.value = image - }, failure: { [weak sSelf] error in - sSelf?.errorPresenter.present(error: error) - }) - } + queue: .main) + { [weak self] notification in + guard let sSelf = self else { return } + if let userInfo = notification.userInfo { + let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier + let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier + if sSelf.viewModel.uuid.value == luid?.value || sSelf.viewModel.mac.value == macId?.value { + sSelf.ruuviSensorPropertiesService.getImage(for: sSelf.ruuviTag) + .on(success: { [weak sSelf] image in + sSelf?.viewModel.background.value = image + }, failure: { [weak sSelf] error in + sSelf?.errorPresenter.present(error: error) + }) } + } } } private func startObservingBluetoothState() { - stateToken = foreground.state(self, closure: { [weak self] (observer, state) in + stateToken = foreground.state(self, closure: { [weak self] observer, state in guard let sSelf = self else { return } if state != .poweredOn || !sSelf.isBluetoothPermissionGranted { observer.view?.showBluetoothDisabled(userDeclined: !sSelf.isBluetoothPermissionGranted) @@ -540,18 +548,19 @@ extension TagChartsViewPresenter { .addObserver(forName: .RuuviServiceAlertDidChange, object: nil, queue: .main, - using: { [weak self] (notification) in - if let sSelf = self, - let userInfo = notification.userInfo, - let physicalSensor = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor, - self?.viewModel.mac.value == physicalSensor.macId?.value { - if sSelf.alertService.hasRegistrations(for: physicalSensor) { - self?.viewModel.alertState.value = .registered - } else { - self?.viewModel.alertState.value = .empty - } - } - }) + using: { [weak self] notification in + if let sSelf = self, + let userInfo = notification.userInfo, + let physicalSensor = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor, + self?.viewModel.mac.value == physicalSensor.macId?.value + { + if sSelf.alertService.hasRegistrations(for: physicalSensor) { + self?.viewModel.alertState.value = .registered + } else { + self?.viewModel.alertState.value = .empty + } + } + }) } private func startListeningToAlertStatus() { @@ -570,40 +579,42 @@ extension TagChartsViewPresenter { .addObserver(forName: .BTBackgroundDidConnect, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, + using: { [weak self] notification in + if let userInfo = notification.userInfo, let uuid = userInfo[BTBackgroundDidConnectKey.uuid] as? String, - self?.viewModel.uuid.value == uuid { - self?.viewModel.isConnected.value = true - } - }) + self?.viewModel.uuid.value == uuid + { + self?.viewModel.isConnected.value = true + } + }) didDisconnectToken = NotificationCenter .default .addObserver(forName: .BTBackgroundDidDisconnect, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, + using: { [weak self] notification in + if let userInfo = notification.userInfo, let uuid = userInfo[BTBackgroundDidDisconnectKey.uuid] as? String, - self?.viewModel.uuid.value == uuid { - self?.viewModel.isConnected.value = false - } - }) + self?.viewModel.uuid.value == uuid + { + self?.viewModel.isConnected.value = false + } + }) } private func startObservingSensorSettingsChanges() { - sensorSettingsToken = ruuviReactor.observe(ruuviTag, { (reactorChange) in + sensorSettingsToken = ruuviReactor.observe(ruuviTag) { reactorChange in switch reactorChange { - case .update(let settings): + case let .update(settings): self.sensorSettings = settings self.reloadChartsWithSensorSettingsChanges(with: settings) - case .insert(let sensorSettings): + case let .insert(sensorSettings): self.sensorSettings = sensorSettings self.reloadChartsWithSensorSettingsChanges(with: sensorSettings) default: break } - }) + } } private func startObservingLocalNotificationsManager() { @@ -612,12 +623,13 @@ extension TagChartsViewPresenter { .addObserver(forName: .LNMDidReceive, object: nil, queue: .main, - using: { [weak self] (notification) in - if let uuid = notification.userInfo?[LNMDidReceiveKey.uuid] as? String, - self?.viewModel.uuid.value != uuid { - self?.dismiss() - } - }) + using: { [weak self] notification in + if let uuid = notification.userInfo?[LNMDidReceiveKey.uuid] as? String, + self?.viewModel.uuid.value != uuid + { + self?.dismiss() + } + }) } private func startObservingCloudSyncNotification() { @@ -627,15 +639,16 @@ extension TagChartsViewPresenter { object: nil, queue: .main, using: { [weak self] notification in - guard let mac = notification.userInfo?[NetworkSyncStatusKey.mac] as? MACIdentifier, - mac.any == self?.ruuviTag.macId?.any else { - return - } - self?.interactor.restartObservingData() - }) + guard let mac = notification.userInfo?[NetworkSyncStatusKey.mac] as? MACIdentifier, + mac.any == self?.ruuviTag.macId?.any + else { + return + } + self?.interactor.restartObservingData() + }) } - private func reloadChartsWithSensorSettingsChanges(with settings: SensorSettings) { + private func reloadChartsWithSensorSettingsChanges(with _: SensorSettings) { interactor.restartObservingData() } @@ -648,7 +661,6 @@ extension TagChartsViewPresenter { } extension TagChartsViewPresenter { - func insertMeasurements(_ newValues: [RuuviMeasurement]) { guard view != nil else { return } ruuviTagData = interactor.ruuviTagData @@ -676,10 +688,10 @@ extension TagChartsViewPresenter { // Update new measurements on the chart view?.updateChartViewData(temperatureEntries: temparatureData, - humidityEntries: humidityData, - pressureEntries: pressureData, - isFirstEntry: ruuviTagData.count == 1, - settings: settings) + humidityEntries: humidityData, + pressureEntries: pressureData, + isFirstEntry: ruuviTagData.count == 1, + settings: settings) // Update the latest measurement label. if let lastMeasurement = newValues.last { @@ -735,14 +747,14 @@ extension TagChartsViewPresenter { if humidityData.count > 0 { let humidityChartDataSet = TagChartsHelper.newDataSet(entries: humidityData) let humidityChartData = TagChartViewData(chartType: .humidity, - chartData: LineChartData(dataSet: humidityChartDataSet)) + chartData: LineChartData(dataSet: humidityChartDataSet)) datasource.append(humidityChartData) } if pressureData.count > 0 { let pressureChartDataSet = TagChartsHelper.newDataSet(entries: pressureData) let pressureChartData = TagChartViewData(chartType: .pressure, - chartData: LineChartData(dataSet: pressureChartDataSet)) + chartData: LineChartData(dataSet: pressureChartDataSet)) datasource.append(pressureChartData) } @@ -766,11 +778,10 @@ extension TagChartsViewPresenter { // Draw dots is disabled for v1.3.0 onwards until further notice. private func drawCirclesIfNeeded(for chartData: LineChartData?, entriesCount: Int? = nil) { if let dataSet = chartData?.dataSets.first as? LineChartDataSet { - let count: Int - if let entriesCount = entriesCount { - count = entriesCount + let count: Int = if let entriesCount { + entriesCount } else { - count = dataSet.entries.count + dataSet.entries.count } switch count { case 1: @@ -788,43 +799,46 @@ extension TagChartsViewPresenter { switch type { case .temperature: var temp: Temperature? - // Backword compatibility for the users who used earlier versions than 0.7.7 - // 1: If local record has temperature offset added, calculate and get original temp data - // 2: Apply current sensor settings - if let offset = data.temperatureOffset, offset != 0 { - temp = data.temperature? + // Backword compatibility for the users who used earlier versions than 0.7.7 + // 1: If local record has temperature offset added, calculate and get original temp data + // 2: Apply current sensor settings + = if let offset = data.temperatureOffset, offset != 0 + { + data.temperature? .minus(value: offset)? .plus(sensorSettings: sensorSettings) } else { - temp = data.temperature?.plus(sensorSettings: sensorSettings) + data.temperature?.plus(sensorSettings: sensorSettings) } value = measurementService.double(for: temp) ?? 0 case .humidity: var humidity: Humidity? - // Backword compatibility for the users who used earlier versions than 0.7.7 - // 1: If local record has humidity offset added, calculate and get original humidity data - // 2: Apply current sensor settings - if let offset = data.humidityOffset, offset != 0 { - humidity = data.humidity? + // Backword compatibility for the users who used earlier versions than 0.7.7 + // 1: If local record has humidity offset added, calculate and get original humidity data + // 2: Apply current sensor settings + = if let offset = data.humidityOffset, offset != 0 + { + data.humidity? .minus(value: offset)? .plus(sensorSettings: sensorSettings) } else { - humidity = data.humidity?.plus(sensorSettings: sensorSettings) + data.humidity?.plus(sensorSettings: sensorSettings) } value = measurementService.double(for: humidity, - temperature: data.temperature, + temperature: data.temperature, isDecimal: false) case .pressure: var pressure: Pressure? - // Backword compatibility for the users who used earlier versions than 0.7.7 - // 1: If local record has pressure offset added, calculate and get original pressure data - // 2: Apply current sensor settings - if let offset = data.pressureOffset, offset != 0 { - pressure = data.pressure? + // Backword compatibility for the users who used earlier versions than 0.7.7 + // 1: If local record has pressure offset added, calculate and get original pressure data + // 2: Apply current sensor settings + = if let offset = data.pressureOffset, offset != 0 + { + data.pressure? .minus(value: offset)? .plus(sensorSettings: sensorSettings) } else { - pressure = data.pressure?.plus(sensorSettings: sensorSettings) + data.pressure?.plus(sensorSettings: sensorSettings) } if let value = measurementService.double(for: pressure) { return ChartDataEntry(x: data.date.timeIntervalSince1970, y: value) @@ -840,4 +854,5 @@ extension TagChartsViewPresenter { return ChartDataEntry(x: data.date.timeIntervalSince1970, y: y) } } + // swiftlint:enable file_length diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift index a8895271a..360638c60 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift @@ -1,6 +1,6 @@ -import Foundation import BTKit import Charts +import Foundation import RuuviLocal import RuuviOntology diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift index 9232c84f0..4b61643dc 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift @@ -1,7 +1,7 @@ -import UIKit -import Humidity import Charts +import Humidity import RuuviOntology +import UIKit enum TagChartsType { case ruuvi @@ -9,15 +9,15 @@ enum TagChartsType { struct TagChartsViewModel { var type: TagChartsType = .ruuvi - var uuid: Observable = Observable(UUID().uuidString) - var mac: Observable = Observable() - var name: Observable = Observable() - var background: Observable = Observable() - var isConnectable: Observable = Observable(false) - var isCloud: Observable = Observable() - var alertState: Observable = Observable() - var isConnected: Observable = Observable() - var isHandleInitialResult: Observable = Observable(false) + var uuid: Observable = .init(UUID().uuidString) + var mac: Observable = .init() + var name: Observable = .init() + var background: Observable = .init() + var isConnectable: Observable = .init(false) + var isCloud: Observable = .init() + var alertState: Observable = .init() + var isConnected: Observable = .init() + var isHandleInitialResult: Observable = .init(false) init(type: TagChartsType) { self.type = type diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift index a550f368a..de04792b4 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift @@ -1,12 +1,11 @@ -import UIKit import Charts import RuuviService +import UIKit class TagChartsMarkerView: MarkerImage { - - private (set) var color: UIColor - private (set) var font: UIFont - private (set) var textColor: UIColor + private(set) var color: UIColor + private(set) var font: UIFont + private(set) var textColor: UIColor private var labelText: String = "" private var attrs: [NSAttributedString.Key: AnyObject]! @@ -23,8 +22,9 @@ class TagChartsMarkerView: MarkerImage { init(color: UIColor? = RuuviColor.ruuviGraphMarkerColor, font: UIFont = UIFont.Muli(.regular, size: 8), - textColor: UIColor = .white) { - if let color = color { + textColor: UIColor = .white) + { + if let color { self.color = color } else { self.color = .darkGray @@ -36,14 +36,14 @@ class TagChartsMarkerView: MarkerImage { let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = .center attrs = [.font: font, - .paragraphStyle: paragraphStyle, - .foregroundColor: textColor, - .baselineOffset: NSNumber(value: baselineOffset)] + .paragraphStyle: paragraphStyle, + .foregroundColor: textColor, + .baselineOffset: NSNumber(value: baselineOffset)] super.init() } override func draw(context: CGContext, point: CGPoint) { - guard let attrs = attrs else { + guard let attrs else { return } // Padding for the label. @@ -59,7 +59,7 @@ class TagChartsMarkerView: MarkerImage { if (point.x + rectangle.width) >= screenSize.width { rectangle.origin.x -= rectangle.width } else { - rectangle.origin.x -= rectangle.width/2 + rectangle.origin.x -= rectangle.width / 2 } let distanceFromTop = point.y - rectangle.height @@ -69,11 +69,11 @@ class TagChartsMarkerView: MarkerImage { // place to to minimum Y-position. And, otherwise for the maximum Y-position. // For rest of the cases place it near to the touch point. if distanceFromTop <= 0 { - rectangle.origin.y = rectangle.height/2 + rectangle.origin.y = rectangle.height / 2 } else if distanceFromBottom >= (parentFrame.height - yBottomPadding) { rectangle.origin.y -= (rectangle.height + yBottomPadding) } else { - rectangle.origin.y -= rectangle.height/2 + yBottomPadding + rectangle.origin.y -= rectangle.height / 2 + yBottomPadding } // Rounded corner @@ -92,8 +92,8 @@ class TagChartsMarkerView: MarkerImage { context: nil) } - override func refreshContent(entry: ChartDataEntry, highlight: Highlight) { - var value: String = "" + override func refreshContent(entry: ChartDataEntry, highlight _: Highlight) { + var value = "" switch type { case .temperature: value = measurementService.stringWithoutSign(temperature: entry.y) @@ -114,7 +114,8 @@ extension TagChartsMarkerView { func initialise(with unit: String, type: MeasurementType, measurementService: RuuviServiceMeasurement, - parentFrame: CGRect) { + parentFrame: CGRect) + { self.unit = unit self.type = type self.measurementService = measurementService diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift index 829c82fc4..0d0ed4657 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift @@ -1,9 +1,9 @@ -import RuuviLocalization -import UIKit import Charts import RuuviLocal +import RuuviLocalization import RuuviOntology import RuuviService +import UIKit protocol TagChartsViewDelegate: NSObjectProtocol { func chartDidTranslate(_ chartView: TagChartsView) @@ -36,6 +36,7 @@ class TagChartsView: LineChartView { private lazy var markerView = TagChartsMarkerView() // MARK: - LifeCycle + override init(frame: CGRect) { super.init(frame: frame) delegate = self @@ -43,13 +44,15 @@ class TagChartsView: LineChartView { configure() } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } // MARK: - Layout + private func addSubviews() { - self.addSubview(chartNameLabel) + addSubview(chartNameLabel) chartNameLabel.anchor( top: nil, leading: nil, @@ -63,7 +66,7 @@ class TagChartsView: LineChartView { ) ) - self.addSubview(chartMinMaxAvgLabel) + addSubview(chartMinMaxAvgLabel) chartMinMaxAvgLabel.anchor( top: nil, leading: nil, @@ -77,6 +80,7 @@ class TagChartsView: LineChartView { } // MARK: - Private + private func configure() { chartDescription.enabled = false dragEnabled = true @@ -126,7 +130,7 @@ class TagChartsView: LineChartView { drawMarkers = true markerView.chartView = self - self.marker = markerView + marker = markerView setExtraOffsets(left: 2, top: 4, right: 0, bottom: 2) } @@ -137,33 +141,35 @@ class TagChartsView: LineChartView { } extension TagChartsView: ChartViewDelegate { - func chartTranslated(_ chartView: ChartViewBase, - dX: CGFloat, - dY: CGFloat) { + func chartTranslated(_: ChartViewBase, + dX _: CGFloat, + dY _: CGFloat) + { chartDelegate?.chartDidTranslate(self) } - func chartScaled(_ chartView: ChartViewBase, - scaleX: CGFloat, - scaleY: CGFloat) { + func chartScaled(_: ChartViewBase, + scaleX _: CGFloat, + scaleY _: CGFloat) + { chartDelegate?.chartDidTranslate(self) } - func chartValueSelected(_ chartView: ChartViewBase, + func chartValueSelected(_: ChartViewBase, entry: ChartDataEntry, - highlight: Highlight) { + highlight: Highlight) + { chartDelegate?.chartValueDidSelect(self, entry: entry, highlight: highlight) } - func chartValueNothingSelected(_ chartView: ChartViewBase) { + func chartValueNothingSelected(_: ChartViewBase) { chartDelegate?.chartValueDidDeselect(self) } } extension TagChartsView { - func localize() { xAxis.valueFormatter = XAxisValueFormatter() leftAxis.valueFormatter = YAxisValueFormatter() @@ -217,8 +223,10 @@ extension TagChartsView { } // MARK: - UpdateUI + func updateDataSet(with newData: [ChartDataEntry], - isFirstEntry: Bool) { + isFirstEntry: Bool) + { if isFirstEntry { let emptyDataSet = LineChartData(dataSet: TagChartsHelper.newDataSet()) data = emptyDataSet @@ -234,8 +242,9 @@ extension TagChartsView { func updateLatest(with entry: ChartDataEntry?, type: MeasurementType, measurementService: RuuviServiceMeasurement, - unit: String) { - guard let entry = entry else { return } + unit: String) + { + guard let entry else { return } switch type { case .temperature: let tempValue = measurementService.stringWithoutSign(temperature: entry.y) @@ -253,14 +262,15 @@ extension TagChartsView { func setChartLabel(with name: String, type: MeasurementType, measurementService: RuuviServiceMeasurement, - unit: String) { + unit: String) + { chartName = name chartNameLabel.text = name if let marker = marker as? TagChartsMarkerView { marker.initialise(with: unit, type: type, measurementService: measurementService, - parentFrame: self.frame) + parentFrame: frame) } } @@ -272,15 +282,15 @@ extension TagChartsView { min: Double, max: Double, avg: Double, - type: MeasurementType + type _: MeasurementType ) { - let roundedTo: Int = 2 + let roundedTo = 2 let minText = RuuviLocalization.chartStatMin + ": " + - GlobalHelpers().formattedString(from: min.round(to: roundedTo)) + GlobalHelpers().formattedString(from: min.round(to: roundedTo)) let maxText = RuuviLocalization.chartStatMax + ": " + - GlobalHelpers().formattedString(from: max.round(to: roundedTo)) + GlobalHelpers().formattedString(from: max.round(to: roundedTo)) let avgText = RuuviLocalization.chartStatAvg + ": " + - GlobalHelpers().formattedString(from: avg.round(to: roundedTo)) + GlobalHelpers().formattedString(from: avg.round(to: roundedTo)) chartMinMaxAvgLabel.text = minText + " " + maxText + " " + avgText } diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift index 4c4b78a51..90a3b8f16 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift @@ -1,21 +1,21 @@ +import BTKit +import Charts // swiftlint:disable file_length import Foundation -import UIKit -import Charts -import RuuviOntology -import RuuviStorage -import RuuviLocal -import BTKit -import RuuviService import GestureInstructions +import RuuviLocal import RuuviLocalization +import RuuviOntology +import RuuviService +import RuuviStorage +import UIKit // swiftlint:disable type_body_length class TagChartsViewController: UIViewController { var output: TagChartsViewOutput! private var chartModules: [MeasurementType] = [] - var viewModel: TagChartsViewModel = TagChartsViewModel(type: .ruuvi) + var viewModel: TagChartsViewModel = .init(type: .ruuvi) var historyLengthInDay: Int = 1 { didSet { @@ -61,9 +61,11 @@ class TagChartsViewController: UIViewController { } // MARK: - CONSTANTS + private let cellId: String = "CellId" // MARK: - UI COMPONENTS DECLARATION + // Body lazy var noDataLabel: UILabel = { let label = UILabel() @@ -77,17 +79,17 @@ class TagChartsViewController: UIViewController { // Chart toolbar private lazy var historySelectionButton: RuuviContextMenuButton = - RuuviContextMenuButton(menu: historyLengthOptions(), - titleColor: .white, - title: RuuviLocalization.day1, - icon: RuuviAssets.dropDownArrowImage, - iconTintColor: RuuviColor.logoTintColor, - iconSize: .init(width: 14, height: 14), - preccedingIcon: false) + .init(menu: historyLengthOptions(), + titleColor: .white, + title: RuuviLocalization.day1, + icon: RuuviAssets.dropDownArrowImage, + iconTintColor: RuuviColor.logoTintColor, + iconSize: .init(width: 14, height: 14), + preccedingIcon: false) // Chart toolbar private lazy var moreButton: UIButton = { - let button = UIButton() + let button = UIButton() button.tintColor = .white button.setImage(RuuviAssets.threeDotMoreImage, for: .normal) button.imageView?.contentMode = .scaleAspectFit @@ -145,7 +147,7 @@ class TagChartsViewController: UIViewController { }() lazy var syncCancelButton: UIButton = { - let button = UIButton() + let button = UIButton() let closeImage = UIImage(systemName: "xmark") button.tintColor = .white button.setImage(closeImage, for: .normal) @@ -170,6 +172,7 @@ class TagChartsViewController: UIViewController { iv.tintColor = .white.withAlphaComponent(0.8) return iv }() + // UI END private let historyHoursOptions: [Int] = [1, 2, 3, 12] @@ -182,6 +185,7 @@ class TagChartsViewController: UIViewController { } // MARK: - LIFECYCLE + override func viewDidLoad() { super.viewDidLoad() setUpUI() @@ -210,7 +214,7 @@ class TagChartsViewController: UIViewController { override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { coordinator.animate(alongsideTransition: { _ in - }, completion: { [weak self] (_) in + }, completion: { [weak self] _ in self?.updateScrollviewBehaviour() self?.updateChartsCollectionConstaints(from: self?.chartModules ?? [], withAnimation: true) @@ -284,10 +288,10 @@ class TagChartsViewController: UIViewController { syncProgressView.addSubview(syncStatusLabel) syncStatusLabel.anchor(top: nil, - leading: syncCancelButton.trailingAnchor, - bottom: nil, - trailing: syncProgressView.trailingAnchor, - padding: .init(top: 0, left: 6, bottom: 0, right: 0)) + leading: syncCancelButton.trailingAnchor, + bottom: nil, + trailing: syncProgressView.trailingAnchor, + padding: .init(top: 0, left: 6, bottom: 0, right: 0)) syncStatusLabel.centerYInSuperview() chartToolbarView.addSubview(syncButton) @@ -320,9 +324,9 @@ class TagChartsViewController: UIViewController { scrollView.addSubview(humidityChartView) humidityChartView.anchor(top: temperatureChartView.bottomAnchor, - leading: scrollView.leadingAnchor, - bottom: nil, - trailing: scrollView.trailingAnchor) + leading: scrollView.leadingAnchor, + bottom: nil, + trailing: scrollView.trailingAnchor) humidityChartView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true humidityChartViewHeight = humidityChartView.heightAnchor.constraint(equalToConstant: 0) humidityChartViewHeight.isActive = true @@ -330,9 +334,9 @@ class TagChartsViewController: UIViewController { scrollView.addSubview(pressureChartView) pressureChartView.anchor(top: humidityChartView.bottomAnchor, - leading: scrollView.leadingAnchor, + leading: scrollView.leadingAnchor, bottom: scrollView.bottomAnchor, - trailing: scrollView.trailingAnchor) + trailing: scrollView.trailingAnchor) pressureChartView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true pressureChartViewHeight = pressureChartView.heightAnchor.constraint(equalToConstant: 0) pressureChartViewHeight.isActive = true @@ -379,7 +383,6 @@ class TagChartsViewController: UIViewController { right: 0), size: .init(width: 22, height: 22)) dataSourceIconView.centerYInSuperview() - } @objc fileprivate func syncButtonDidTap() { @@ -406,20 +409,20 @@ class TagChartsViewController: UIViewController { ) { [weak self] _ in self?.handleHistoryLengthSelection(hours: hour) } - if hour == historyLengthInHours && !showChartAll { + if hour == historyLengthInHours, !showChartAll { action.state = .on - } else { + } else { action.state = .off - } + } actions.append(action) } - for day in minimumHistoryLimit...maximumHistoryLimit { + for day in minimumHistoryLimit ... maximumHistoryLimit { let action = UIAction(title: day.days) { [weak self] _ in - self?.handleHistoryLengthSelection(hours: day*24) + self?.handleHistoryLengthSelection(hours: day * 24) } - if day == historyLengthInHours / 24 && !showChartAll { + if day == historyLengthInHours / 24, !showChartAll { action.state = .on } else { action.state = .off @@ -438,14 +441,14 @@ class TagChartsViewController: UIViewController { } fileprivate func handleHistoryLengthSelection(hours: Int?) { - if let hours = hours { + if let hours { if hours >= 24 { - historySelectionButton.updateTitle(with: "\((hours/24).days)") + historySelectionButton.updateTitle(with: "\((hours / 24).days)") historySelectionButton.updateMenu(with: historyLengthOptions()) } else { let unit = hours == 1 ? RuuviLocalization.hour : RuuviLocalization.hours historySelectionButton.updateTitle( - with: "\(hours) " + unit.lowercased() + with: "\(hours) " + unit.lowercased() ) } output.viewDidSelectChartHistoryLength(hours: hours) @@ -478,9 +481,9 @@ class TagChartsViewController: UIViewController { [weak self] _ in guard let sSelf = self else { return } sSelf.output.viewDidSelectTriggerChartStat(show: !showChartStat) - sSelf.chartViews.forEach({ chartView in + sSelf.chartViews.forEach { chartView in chartView.setChartStatVisible(show: !showChartStat) - }) + } } return UIMenu( @@ -488,7 +491,7 @@ class TagChartsViewController: UIViewController { children: [ exportHistoryAction, clearViewHistory, - minMaxAvgAction + minMaxAvgAction, ] ) } @@ -501,7 +504,7 @@ extension TagChartsViewController: TagChartsViewDelegate { return } let sourceMatrix = chartView.viewPortHandler.touchMatrix - chartViews.filter({ $0 != chartView }).forEach { otherChart in + chartViews.filter { $0 != chartView }.forEach { otherChart in var targetMatrix = otherChart.viewPortHandler.touchMatrix targetMatrix.a = sourceMatrix.a targetMatrix.tx = sourceMatrix.tx @@ -518,18 +521,19 @@ extension TagChartsViewController: TagChartsViewDelegate { } func chartValueDidSelect(_ chartView: TagChartsView, - entry: ChartDataEntry, - highlight: Highlight) { + entry _: ChartDataEntry, + highlight: Highlight) + { guard chartViews.count > 1 else { return } - chartViews.filter({ $0 != chartView }).forEach { otherChart in + chartViews.filter { $0 != chartView }.forEach { otherChart in otherChart.highlightValue(highlight) } } - func chartValueDidDeselect(_ chartView: TagChartsView) { + func chartValueDidDeselect(_: TagChartsView) { guard chartViews.count > 1 else { return } @@ -541,9 +545,10 @@ extension TagChartsViewController: TagChartsViewDelegate { } // MARK: - TagChartsViewInput + extension TagChartsViewController: TagChartsViewInput { var viewIsVisible: Bool { - return self.isViewLoaded && self.view.window != nil + isViewLoaded && view.window != nil } func clearChartHistory() { @@ -556,7 +561,8 @@ extension TagChartsViewController: TagChartsViewInput { } func setChartViewData(from chartViewData: [TagChartViewData], - settings: RuuviLocalSettings) { + settings: RuuviLocalSettings) + { if chartViewData.count == 0 { clearChartData() showNoDataLabel() @@ -600,7 +606,8 @@ extension TagChartsViewController: TagChartsViewInput { humidityEntries: [ChartDataEntry], pressureEntries: [ChartDataEntry], isFirstEntry: Bool, - settings: RuuviLocalSettings) { + settings: RuuviLocalSettings) + { hideNoDataLabel() showChartViews() @@ -620,7 +627,8 @@ extension TagChartsViewController: TagChartsViewInput { func updateLatestMeasurement(temperature: ChartDataEntry?, humidity: ChartDataEntry?, pressure: ChartDataEntry?, - settings: RuuviLocalSettings) { + settings: RuuviLocalSettings) + { temperatureChartView.updateLatest(with: temperature, type: .temperature, measurementService: measurementService, @@ -629,8 +637,8 @@ extension TagChartsViewController: TagChartsViewInput { type: .humidity, measurementService: measurementService, unit: settings.humidityUnit == .dew ? - settings.temperatureUnit.symbol : - settings.humidityUnit.symbol) + settings.temperatureUnit.symbol : + settings.humidityUnit.symbol) pressureChartView.updateLatest(with: pressure, type: .pressure, measurementService: measurementService, @@ -669,13 +677,14 @@ extension TagChartsViewController: TagChartsViewInput { let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) alertVC.addAction(UIAlertAction(title: RuuviLocalization.PermissionPresenter.settings, style: .default, handler: { _ in - guard let url = URL(string: userDeclined ? - UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), - UIApplication.shared.canOpenURL(url) else { - return - } - UIApplication.shared.open(url) - })) + guard let url = URL(string: userDeclined ? + UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), + UIApplication.shared.canOpenURL(url) + else { + return + } + UIApplication.shared.open(url) + })) alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) } @@ -693,15 +702,15 @@ extension TagChartsViewController: TagChartsViewInput { present(alertVC, animated: true) } - func setSync(progress: BTServiceProgress?, for viewModel: TagChartsViewModel) { - if let progress = progress { + func setSync(progress: BTServiceProgress?, for _: TagChartsViewModel) { + if let progress { showSyncStatusLabel(show: true) switch progress { case .connecting: syncStatusLabel.text = RuuviLocalization.TagCharts.Status.connecting case .serving: syncStatusLabel.text = RuuviLocalization.TagCharts.Status.serving - case .reading(let points): + case let .reading(points): let format = RuuviLocalization.readingHistoryX syncStatusLabel.text = String(format: format, Float(points)) case .disconnecting: @@ -728,9 +737,9 @@ extension TagChartsViewController: TagChartsViewInput { alertVC.addAction(UIAlertAction(title: RuuviLocalization.TagCharts.TryAgain.title, style: .default, handler: { [weak self] _ in - guard let self = self else { return } - self.output.viewDidTriggerSync(for: self.viewModel) - })) + guard let self else { return } + output.viewDidTriggerSync(for: viewModel) + })) present(alertVC, animated: true) } @@ -738,7 +747,7 @@ extension TagChartsViewController: TagChartsViewInput { gestureInstructor.show(.swipeUp, after: 0.1) } - func showSyncConfirmationDialog(for viewModel: TagChartsViewModel) { + func showSyncConfirmationDialog(for _: TagChartsViewModel) { let title = RuuviLocalization.synchronisation let message = RuuviLocalization.gattSyncDescription let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) @@ -747,19 +756,19 @@ extension TagChartsViewController: TagChartsViewInput { alertVC.addAction(UIAlertAction(title: actionTitle, style: .default, handler: { [weak self] _ in - self?.output.viewDidTriggerDoNotShowSyncDialog() + self?.output.viewDidTriggerDoNotShowSyncDialog() - })) + })) present(alertVC, animated: true) } func showSyncAbortAlert(dismiss: Bool) { - let title = RuuviLocalization.TagCharts.DeleteHistoryConfirmationDialog.title - let message = dismiss ? RuuviLocalization.TagCharts.Dismiss.Alert.message : + let title = RuuviLocalization.TagCharts.DeleteHistoryConfirmationDialog.title + let message = dismiss ? RuuviLocalization.TagCharts.Dismiss.Alert.message : RuuviLocalization.TagCharts.AbortSync.Alert.message let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) - let actionTitle = RuuviLocalization.TagCharts.AbortSync.Button.title + let actionTitle = RuuviLocalization.TagCharts.AbortSync.Button.title alertVC.addAction(UIAlertAction(title: actionTitle, style: .destructive, handler: { [weak self] _ in self?.output.viewDidConfirmAbortSync(dismiss: dismiss) })) @@ -767,11 +776,11 @@ extension TagChartsViewController: TagChartsViewInput { } func showSyncAbortAlertForSwipe() { - let title = RuuviLocalization.TagCharts.DeleteHistoryConfirmationDialog.title - let message = RuuviLocalization.TagCharts.Dismiss.Alert.message + let title = RuuviLocalization.TagCharts.DeleteHistoryConfirmationDialog.title + let message = RuuviLocalization.TagCharts.Dismiss.Alert.message let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) - let actionTitle = RuuviLocalization.TagCharts.AbortSync.Button.title + let actionTitle = RuuviLocalization.TagCharts.AbortSync.Button.title alertVC.addAction(UIAlertAction(title: actionTitle, style: .destructive, handler: { [weak self] _ in self?.output.viewDidConfirmAbortSync(dismiss: false) })) @@ -789,7 +798,7 @@ extension TagChartsViewController: TagChartsViewInput { UIActivity.ActivityType.postToTencentWeibo, UIActivity.ActivityType.postToTwitter, UIActivity.ActivityType.postToFacebook, - UIActivity.ActivityType.openInIBooks + UIActivity.ActivityType.openInIBooks, ] vc.popoverPresentationController?.permittedArrowDirections = .up vc.popoverPresentationController?.sourceView = moreButton @@ -810,10 +819,10 @@ extension TagChartsViewController: TagChartsViewInput { } extension TagChartsViewController { - // swiftlint:disable:next cyclomatic_complexity function_body_length private func updateChartsCollectionConstaints(from: [MeasurementType], - withAnimation: Bool = false) { + withAnimation: Bool = false) + { if from.count == 0 { noDataLabel.alpha = 1 return @@ -822,7 +831,7 @@ extension TagChartsViewController { noDataLabel.alpha = 0 chartViews.removeAll() let scrollViewHeight = scrollView.frame.height - guard viewIsVisible && scrollViewHeight > 0 && from.count > 0 else { + guard viewIsVisible, scrollViewHeight > 0, from.count > 0 else { return } updateScrollviewBehaviour() @@ -877,12 +886,12 @@ extension TagChartsViewController { private func getItemHeight(from totalHeight: CGFloat, count: CGFloat) -> CGFloat { if UIWindow.isLandscape { - return totalHeight + totalHeight } else { if count == 1 { - return totalHeight/2 + totalHeight / 2 } else { - return totalHeight/count + totalHeight / count } } } @@ -900,7 +909,8 @@ extension TagChartsViewController { private func updateChartViewConstaints(constaint: NSLayoutConstraint, totalHeight: CGFloat, itemCount: Int, - withAnimation: Bool) { + withAnimation: Bool) + { if withAnimation { UIView.animate(withDuration: 0.2, animations: { [weak self] in guard let sSelf = self else { return } @@ -920,7 +930,8 @@ extension TagChartsViewController { type: MeasurementType, unit: String, settings: RuuviLocalSettings, - view: TagChartsView) { + view: TagChartsView) + { view.setChartLabel(with: title, type: type, measurementService: measurementService, @@ -954,6 +965,7 @@ extension TagChartsViewController { } // MARK: - UI RELATED METHODS + private func showSyncStatusLabel(show: Bool) { syncProgressView.alpha = show ? 1 : 0 syncButton.alpha = show ? 0 : 1 @@ -989,15 +1001,15 @@ extension TagChartsViewController { timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, - block: { [weak self] (_) in - self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message - }) + block: { [weak self] _ in + self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message + }) } private func calculateMinMaxForChart(for view: TagChartsView) { if let data = view.data, - let dataSet = data.dataSets.first as? LineChartDataSet { - + let dataSet = data.dataSets.first as? LineChartDataSet + { let lowestVisibleX = view.lowestVisibleX let highestVisibleX = view.highestVisibleX @@ -1005,7 +1017,7 @@ extension TagChartsViewController { var maxVisibleYValue = -Double.greatestFiniteMagnitude dataSet.entries.forEach { entry in - if entry.x >= lowestVisibleX && entry.x <= highestVisibleX { + if entry.x >= lowestVisibleX, entry.x <= highestVisibleX { minVisibleYValue = min(minVisibleYValue, entry.y) maxVisibleYValue = max(maxVisibleYValue, entry.y) } @@ -1027,32 +1039,31 @@ extension TagChartsViewController { avg: averageYValue, type: type ) - } } /** - Calculate the average value of visible data points on a `LineChartView`. - This function computes the average by considering the area under the curve - formed by the visible data points and then divides it by the width of the visible x-range. - The area under the curve is approximated using the trapezoidal rule. - - - Parameters: - - chartView: The `LineChartView` instance whose visible range's average needs to be calculated. - - dataSet: The `LineChartDataSet` containing data points to be considered. - - - Returns: The average value of visible data points. - - - Note: - The function uses the trapezoidal rule for approximation. The formula for the trapezoidal rule is: - A = (b - a) * (f(a) + f(b)) / 2 - Where: - - A is the area of the trapezium. - - a and b are the x-coordinates of the two data points. - - f(a) and f(b) are the y-coordinates (or values) of the two data points. - - The average is then computed as the total area divided by the width of the visible x-range. - */ + Calculate the average value of visible data points on a `LineChartView`. + This function computes the average by considering the area under the curve + formed by the visible data points and then divides it by the width of the visible x-range. + The area under the curve is approximated using the trapezoidal rule. + + - Parameters: + - chartView: The `LineChartView` instance whose visible range's average needs to be calculated. + - dataSet: The `LineChartDataSet` containing data points to be considered. + + - Returns: The average value of visible data points. + + - Note: + The function uses the trapezoidal rule for approximation. The formula for the trapezoidal rule is: + A = (b - a) * (f(a) + f(b)) / 2 + Where: + - A is the area of the trapezium. + - a and b are the x-coordinates of the two data points. + - f(a) and f(b) are the y-coordinates (or values) of the two data points. + + The average is then computed as the total area divided by the width of the visible x-range. + */ private func calculateVisibleAverage(chartView: LineChartView, dataSet: LineChartDataSet) -> Double { // Get the x-values defining the visible range of the chart. let lowestVisibleX = chartView.lowestVisibleX @@ -1066,9 +1077,9 @@ extension TagChartsViewController { var totalArea = 0.0 // Compute the area under the curve for each pair of consecutive points. - for i in 1.. UIViewController } final class DashboardModuleFactoryImpl: DashboardModuleFactory { - // swiftlint:disable:next function_body_length func create() -> UIViewController { let r = AppAssembly.shared.assembler.resolver @@ -70,10 +69,11 @@ final class DashboardModuleFactoryImpl: DashboardModuleFactory { presenter.interactor = interactor // MARK: - MENU + // swiftlint:disable force_cast let menu = UIStoryboard(name: "Menu", bundle: .main) - .instantiateInitialViewController() as! UINavigationController + .instantiateInitialViewController() as! UINavigationController menu.modalPresentationStyle = .custom let menuTable = menu.topViewController as! MenuTableViewController let menuPresenter = menuTable.output as! MenuPresenter @@ -89,6 +89,7 @@ final class DashboardModuleFactoryImpl: DashboardModuleFactory { view.menuDismissInteractiveTransition = menuTransition.dismiss // MARK: VIEW + view.measurementService = r.resolve(RuuviServiceMeasurement.self) view.output = presenter diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift index 44b276435..8813a6805 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift @@ -1,12 +1,12 @@ +import BTKit import Foundation -import RuuviOntology -import RuuviLocal import Future -import BTKit +import RuuviLocal +import RuuviOntology import RuuviPool import RuuviService #if canImport(RuuviServiceOwnership) -import RuuviServiceOwnership + import RuuviServiceOwnership #endif import RuuviUser @@ -23,13 +23,13 @@ extension DashboardInteractor: DashboardInteractorInput { func checkAndUpdateFirmwareVersion(for ruuviTag: RuuviTagSensor) { guard let luid = ruuviTag.luid, ruuviTag.firmwareVersion == nil || - !ruuviTag.firmwareVersion.hasText() else { + !ruuviTag.firmwareVersion.hasText() + else { // Trigger the method after 2 seconds so that sensor settings page can - // be set and start observing for owner check notification. - DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2), - execute: { [weak self] in + // be set and start observing for owner check notification. + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) { [weak self] in self?.checkOwner(for: ruuviTag) - }) + } return } @@ -39,7 +39,7 @@ extension DashboardInteractor: DashboardInteractorInput { options: [.connectionTimeout(15)] ) { [weak self] _, result in switch result { - case .success(let version): + case let .success(version): let tagWithVersion = ruuviTag.with(firmwareVersion: version) self?.ruuviPool.update(tagWithVersion) self?.checkOwner(for: tagWithVersion) @@ -51,13 +51,15 @@ extension DashboardInteractor: DashboardInteractorInput { private func checkOwner(for ruuviTag: RuuviTagSensor) { guard let macId = ruuviTag.macId, - ruuviTag.owner == nil else { + ruuviTag.owner == nil + else { return } // Check in every 15 days if the tag doesn't have any owner. if let checkedDate = settings.ownerCheckDate(for: macId), - let days = checkedDate.numberOfDaysFromNow(), days < 15 { + let days = checkedDate.numberOfDaysFromNow(), days < 15 + { return } @@ -66,7 +68,7 @@ extension DashboardInteractor: DashboardInteractorInput { guard let sSelf = self else { return } - guard let owner = owner, !owner.isEmpty else { + guard let owner, !owner.isEmpty else { NotificationCenter.default.post( name: .RuuviTagOwnershipCheckDidEnd, object: nil, diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractorInput.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractorInput.swift index 800a8e44c..22393921b 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractorInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractorInput.swift @@ -1,7 +1,7 @@ import Foundation import Future -import RuuviOntology import RuuviLocal +import RuuviOntology protocol DashboardInteractorInput: AnyObject { func checkAndUpdateFirmwareVersion(for ruuviTag: RuuviTagSensor) diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardModuleInput.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardModuleInput.swift index 328b32ecd..3b3318940 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardModuleInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardModuleInput.swift @@ -1,5 +1,3 @@ import Foundation -protocol DashboardModuleInput: AnyObject { - -} +protocol DashboardModuleInput: AnyObject {} diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift index e203939e5..1075c53bb 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift @@ -1,23 +1,23 @@ +import BTKit +import CoreBluetooth // swiftlint:disable file_length trailing_whitespace import Foundation -import BTKit +import Future import Humidity -import RuuviOntology import RuuviContext -import RuuviStorage -import RuuviReactor -import RuuviLocal -import RuuviService import RuuviCore +import RuuviDaemon +import RuuviLocal import RuuviNotification import RuuviNotifier -import RuuviDaemon +import RuuviOntology import RuuviPresenters +import RuuviReactor +import RuuviService +import RuuviStorage import RuuviUser -import WidgetKit -import CoreBluetooth -import Future import UIKit +import WidgetKit class DashboardPresenter: DashboardModuleInput { weak var view: DashboardViewInput? @@ -91,20 +91,21 @@ class DashboardPresenter: DashboardModuleInput { view?.viewModels = viewModels } } + private var didLoadInitialRuuviTags = false private let appGroupDefaults = UserDefaults( suiteName: AppGroupConstants.appGroupSuiteIdentifier ) private var isBluetoothPermissionGranted: Bool { - return CBCentralManager.authorization == .allowedAlways + CBCentralManager.authorization == .allowedAlways } - + deinit { ruuviTagToken?.invalidate() - ruuviTagObserveLastRecordTokens.forEach({ $0.invalidate() }) - advertisementTokens.forEach({ $0.invalidate() }) - heartbeatTokens.forEach({ $0.invalidate() }) - sensorSettingsTokens.forEach({ $0.invalidate() }) + ruuviTagObserveLastRecordTokens.forEach { $0.invalidate() } + advertisementTokens.forEach { $0.invalidate() } + heartbeatTokens.forEach { $0.invalidate() } + sensorSettingsTokens.forEach { $0.invalidate() } stateToken?.invalidate() backgroundToken?.invalidate() ruuviTagAdvertisementDaemonFailureToken?.invalidate() @@ -142,6 +143,7 @@ class DashboardPresenter: DashboardModuleInput { } // MARK: - DashboardViewOutput + extension DashboardPresenter: DashboardViewOutput { func viewDidLoad() { startObservingRuuviTags() @@ -157,13 +159,13 @@ extension DashboardPresenter: DashboardViewOutput { startObservingCloudSyncFailTokenState() pushNotificationsManager.registerForRemoteNotifications() } - + func viewWillAppear() { startObservingUniversalLinks() startObservingBluetoothState() syncAppSettingsToAppGroupContainer() } - + func viewWillDisappear() { stopObservingBluetoothState() } @@ -191,7 +193,8 @@ extension DashboardPresenter: DashboardViewOutput { || background.isConnected(uuid: luid.value) || !viewModel.isConnectable.value.bound || !viewModel.isOwner.value.bound - || (settings.cloudModeEnabled && viewModel.isCloud.value.bound) { + || (settings.cloudModeEnabled && viewModel.isCloud.value.bound) + { openTagSettingsScreens(viewModel: viewModel) } else { view?.showKeepConnectionDialogSettings(for: viewModel) @@ -208,7 +211,8 @@ extension DashboardPresenter: DashboardViewOutput { || background.isConnected(uuid: luid.value) || !viewModel.isConnectable.value.bound || !viewModel.isOwner.value.bound - || (settings.cloudModeEnabled && viewModel.isCloud.value.bound) { + || (settings.cloudModeEnabled && viewModel.isCloud.value.bound) + { openCardView(viewModel: viewModel, showCharts: true) } else { view?.showKeepConnectionDialogChart(for: viewModel) @@ -221,19 +225,20 @@ extension DashboardPresenter: DashboardViewOutput { } func viewDidTriggerOpenCardImageView(for viewModel: CardsViewModel?) { - guard let viewModel = viewModel else { return } + guard let viewModel else { return } openCardView(viewModel: viewModel, showCharts: false) } // swiftlint:disable switch_case_alignment func viewDidTriggerDashboardCard(for viewModel: CardsViewModel) { switch settings.dashboardTapActionType { - case .card: - viewDidTriggerOpenCardImageView(for: viewModel) - case .chart: - viewDidTriggerChart(for: viewModel) + case .card: + viewDidTriggerOpenCardImageView(for: viewModel) + case .chart: + viewDidTriggerChart(for: viewModel) } } + // swiftlint:enable switch_case_alignment func viewDidTriggerChangeBackground(for viewModel: CardsViewModel) { @@ -242,7 +247,6 @@ extension DashboardPresenter: DashboardViewOutput { router.openBackgroundSelectionView(ruuviTag: ruuviTagSensor) } } - } func viewDidTriggerRename(for viewModel: CardsViewModel) { @@ -263,7 +267,7 @@ extension DashboardPresenter: DashboardViewOutput { errorPresenter.present(error: UnexpectedError.viewModelUUIDIsNil) } } - + func viewDidConfirmToKeepConnectionChart(to viewModel: CardsViewModel) { if let luid = viewModel.luid.value { connectionPersistence.setKeepConnection(true, for: luid) @@ -282,7 +286,7 @@ extension DashboardPresenter: DashboardViewOutput { errorPresenter.present(error: UnexpectedError.viewModelUUIDIsNil) } } - + func viewDidConfirmToKeepConnectionSettings(to viewModel: CardsViewModel) { if let luid = viewModel.luid.value { connectionPersistence.setKeepConnection(true, for: luid) @@ -328,33 +332,34 @@ extension DashboardPresenter: DashboardViewOutput { } // MARK: - MenuModuleOutput + extension DashboardPresenter: MenuModuleOutput { - func menu(module: MenuModuleInput, didSelectAddRuuviTag sender: Any?) { + func menu(module: MenuModuleInput, didSelectAddRuuviTag _: Any?) { module.dismiss() router.openDiscover(delegate: self) } - - func menu(module: MenuModuleInput, didSelectSettings sender: Any?) { + + func menu(module: MenuModuleInput, didSelectSettings _: Any?) { module.dismiss() router.openSettings() } - - func menu(module: MenuModuleInput, didSelectAbout sender: Any?) { + + func menu(module: MenuModuleInput, didSelectAbout _: Any?) { module.dismiss() router.openAbout() } - func menu(module: MenuModuleInput, didSelectWhatToMeasure sender: Any?) { + func menu(module: MenuModuleInput, didSelectWhatToMeasure _: Any?) { module.dismiss() router.openWhatToMeasurePage() } - - func menu(module: MenuModuleInput, didSelectGetMoreSensors sender: Any?) { + + func menu(module: MenuModuleInput, didSelectGetMoreSensors _: Any?) { module.dismiss() router.openRuuviProductsPageFromMenu() } - func menu(module: MenuModuleInput, didSelectFeedback sender: Any?) { + func menu(module: MenuModuleInput, didSelectFeedback _: Any?) { module.dismiss() infoProvider.summary { [weak self] summary in guard let sSelf = self else { return } @@ -364,25 +369,27 @@ extension DashboardPresenter: MenuModuleOutput { } } - func menu(module: MenuModuleInput, didSelectSignIn sender: Any?) { + func menu(module: MenuModuleInput, didSelectSignIn _: Any?) { module.dismiss() router.openSignIn(output: self) } - func menu(module: MenuModuleInput, didSelectOpenConfig sender: Any?) { + func menu(module: MenuModuleInput, didSelectOpenConfig _: Any?) { module.dismiss() } - - func menu(module: MenuModuleInput, didSelectOpenMyRuuviAccount sender: Any?) { + + func menu(module: MenuModuleInput, didSelectOpenMyRuuviAccount _: Any?) { module.dismiss() router.openMyRuuviAccount() } } // MARK: - SignInBenefitsModuleOutput + extension DashboardPresenter: SignInBenefitsModuleOutput { func signIn(module: SignInBenefitsModuleInput, - didSuccessfulyLogin sender: Any?) { + didSuccessfulyLogin _: Any?) + { startObservingRuuviTags() startObservingCloudModeNotification() module.dismiss(completion: { @@ -391,14 +398,16 @@ extension DashboardPresenter: SignInBenefitsModuleOutput { } func signIn(module: SignInBenefitsModuleInput, - didCloseSignInWithoutAttempt sender: Any?) { + didCloseSignInWithoutAttempt _: Any?) + { module.dismiss(completion: { AppUtility.lockOrientation(.all) }) } func signIn(module: SignInBenefitsModuleInput, - didSelectUseWithoutAccount sender: Any?) { + didSelectUseWithoutAccount _: Any?) + { module.dismiss(completion: { AppUtility.lockOrientation(.all) }) @@ -419,39 +428,41 @@ extension DashboardPresenter: DiscoverRouterDelegate { $0.id.value == ruuviTag.id }) { self.router.openCardImageView(with: viewModels, - ruuviTagSensors: ruuviTags, - sensorSettings: sensorSettingsList, - scrollTo: viewModel, - showCharts: false, - output: self) + ruuviTagSensors: ruuviTags, + sensorSettings: sensorSettingsList, + scrollTo: viewModel, + showCharts: false, + output: self) } } } // MARK: - DashboardRouterDelegate + extension DashboardPresenter: DashboardRouterDelegate { func shouldDismissDiscover() -> Bool { - return viewModels.count > 0 + viewModels.count > 0 } } // MARK: - RuuviNotifierObserver + extension DashboardPresenter: RuuviNotifierObserver { - func ruuvi(notifier: RuuviNotifier, isTriggered: Bool, for uuid: String) { + func ruuvi(notifier _: RuuviNotifier, isTriggered _: Bool, for _: String) { // No op here. } // swiftlint:disable:next function_body_length - func ruuvi(notifier: RuuviNotifier, + func ruuvi(notifier _: RuuviNotifier, alertType: AlertType, isTriggered: Bool, - for uuid: String) { - + for uuid: String) + { viewModels - .filter({ $0.luid.value?.value == uuid || $0.mac.value?.value == uuid}) - .forEach({ viewModel in + .filter { $0.luid.value?.value == uuid || $0.mac.value?.value == uuid } + .forEach { viewModel in let isFireable = viewModel.isCloud.value ?? false || - viewModel.isConnected.value ?? false + viewModel.isConnected.value ?? false switch alertType { case .temperature: let isTriggered = isTriggered && isFireable @@ -491,7 +502,7 @@ extension DashboardPresenter: RuuviNotifierObserver { viewModel.signalAlertState.value, viewModel.connectionAlertState.value, viewModel.movementAlertState.value, - viewModel.cloudConnectionAlertState.value + viewModel.cloudConnectionAlertState.value, ] if alertStates.first(where: { alert in alert == .firing @@ -502,25 +513,28 @@ extension DashboardPresenter: RuuviNotifierObserver { } notifyViewModelUpdate(for: viewModel) - }) + } } } // MARK: - CardsModuleOutput + extension DashboardPresenter: CardsModuleOutput { func cardsViewDidDismiss(module: CardsModuleInput) { module.dismiss(completion: nil) } - func cardsViewDidRefresh(module: CardsModuleInput) { + func cardsViewDidRefresh(module _: CardsModuleInput) { // No op. } } // MARK: - TagSettingsModuleOutput + extension DashboardPresenter: TagSettingsModuleOutput { func tagSettingsDidDeleteTag(module: TagSettingsModuleInput, - ruuviTag: RuuviTagSensor) { + ruuviTag _: RuuviTagSensor) + { module.dismiss(completion: { [weak self] in self?.startObservingRuuviTags() }) @@ -532,19 +546,18 @@ extension DashboardPresenter: TagSettingsModuleOutput { } // MARK: - Private -extension DashboardPresenter { +extension DashboardPresenter { // swiftlint:disable:next function_body_length private func syncViewModels() { - view?.userSignedInOnce = settings.signedInAtleastOnce view?.dashboardType = settings.dashboardType view?.dashboardTapActionType = settings.dashboardTapActionType - let ruuviViewModels = ruuviTags.compactMap({ (ruuviTag) -> CardsViewModel in + let ruuviViewModels = ruuviTags.compactMap { ruuviTag -> CardsViewModel in let viewModel = CardsViewModel(ruuviTag) ruuviSensorPropertiesService.getImage(for: ruuviTag) - .on(success: {[weak self] image in + .on(success: { [weak self] image in viewModel.background.value = image self?.notifyViewModelUpdate(for: viewModel) }, failure: { [weak self] error in @@ -565,7 +578,7 @@ extension DashboardPresenter { syncAlerts(ruuviTag: ruuviTag, viewModel: viewModel) let op = ruuviStorage.readLatest(ruuviTag) op.on { [weak self] record in - if let record = record { + if let record { viewModel.update(record) self?.notifyViewModelUpdate(for: viewModel) self?.processAlert(record: record, viewModel: viewModel) @@ -573,22 +586,22 @@ extension DashboardPresenter { } return viewModel - }) + } let vms = reorder(ruuviViewModels) - if didLoadInitialRuuviTags{ + if didLoadInitialRuuviTags { view?.showNoSensorsAddedMessage(show: vms.isEmpty) askAppStoreReview(with: vms.count) } - self.viewModels = vms + viewModels = vms } private func syncViewModel(ruuviTagSensor: RuuviTagSensor?) { if let ruuviTag = ruuviTagSensor { let viewModel = CardsViewModel(ruuviTag) ruuviSensorPropertiesService.getImage(for: ruuviTag) - .on(success: {[weak self] image in + .on(success: { [weak self] image in viewModel.background.value = image self?.notifyViewModelUpdate(for: viewModel) }, failure: { [weak self] error in @@ -609,7 +622,7 @@ extension DashboardPresenter { syncAlerts(ruuviTag: ruuviTag, viewModel: viewModel) let op = ruuviStorage.readLatest(ruuviTag) op.on { [weak self] record in - if let record = record { + if let record { viewModel.update(record) self?.notifyViewModelUpdate(for: viewModel) self?.processAlert(record: record, viewModel: viewModel) @@ -622,9 +635,11 @@ extension DashboardPresenter { } private func processAlert(record: RuuviTagSensorRecord, - viewModel: CardsViewModel) { + viewModel: CardsViewModel) + { if let isCloud = viewModel.isCloud.value, isCloud, - let macId = viewModel.mac.value { + let macId = viewModel.mac.value + { alertHandler.processNetwork(record: record, trigger: false, for: macId) @@ -643,13 +658,14 @@ extension DashboardPresenter { private func reorder(_ viewModels: [CardsViewModel]) -> [CardsViewModel] { let sortedAndUniqueArray = viewModels.reduce( into: [CardsViewModel]() - ) { (result, element) in + ) { result, element in if !result.contains(element) { // Insert the element into the result array while maintaining the sorted order if let index = result.firstIndex( where: { $0.name.value?.lowercased() ?? "" > - element.name.value?.lowercased() ?? "" } + element.name.value?.lowercased() ?? "" + } ) { result.insert(element, at: index) } else { @@ -668,7 +684,7 @@ extension DashboardPresenter { ) // Temperature - var temperatureUnitInt: Int = 2 + var temperatureUnitInt = 2 switch settings.temperatureUnit { case .kelvin: temperatureUnitInt = 1 @@ -688,7 +704,7 @@ extension DashboardPresenter { ) // Humidity - var humidityUnitInt: Int = 0 + var humidityUnitInt = 0 switch settings.humidityUnit { case .percent: humidityUnitInt = 0 @@ -704,7 +720,8 @@ extension DashboardPresenter { appGroupDefaults?.set( settings.humidityAccuracy.value, - forKey: AppGroupConstants.humidityAccuracyKey) + forKey: AppGroupConstants.humidityAccuracyKey + ) // Pressure appGroupDefaults?.set( @@ -724,7 +741,7 @@ extension DashboardPresenter { } private func syncHasCloudSensorToAppGroupContainer(with sensors: [AnyRuuviTagSensor]) { - let cloudSensors = sensors.filter({ $0.isCloudSensor ?? false }) + let cloudSensors = sensors.filter { $0.isCloudSensor ?? false } appGroupDefaults?.set( cloudSensors.count > 0, forKey: AppGroupConstants.hasCloudSensorsKey @@ -733,7 +750,7 @@ extension DashboardPresenter { } private func startObservingBluetoothState() { - stateToken = foreground.state(self, closure: { (observer, state) in + stateToken = foreground.state(self, closure: { observer, state in if state != .poweredOn || !self.isBluetoothPermissionGranted { observer.view?.showBluetoothDisabled( userDeclined: !self.isBluetoothPermissionGranted @@ -753,19 +770,20 @@ extension DashboardPresenter { } private func observeRuuviTagHeartbeats() { - heartbeatTokens.forEach({ $0.invalidate() }) + heartbeatTokens.forEach { $0.invalidate() } heartbeatTokens.removeAll() - connectionPersistence.keepConnectionUUIDs.filter { (luid) -> Bool in - ruuviTags.filter({ !(settings.cloudModeEnabled && $0.isCloud) && $0.isOwner }) + connectionPersistence.keepConnectionUUIDs.filter { luid -> Bool in + ruuviTags.filter { !(settings.cloudModeEnabled && $0.isCloud) && $0.isOwner } .contains(where: { $0.luid?.any != nil && $0.luid?.any == luid }) - }.forEach { (luid) in - heartbeatTokens.append(background.observe(self, uuid: luid.value) { [weak self] (_, device) in + }.forEach { luid in + heartbeatTokens.append(background.observe(self, uuid: luid.value) { [weak self] _, device in if let ruuviTag = device.ruuvi?.tag, - let viewModel = self?.viewModels.first(where: { $0.luid.value == ruuviTag.uuid.luid.any }) { + let viewModel = self?.viewModels.first(where: { $0.luid.value == ruuviTag.uuid.luid.any }) + { let sensorSettings = self?.sensorSettingsList .first(where: { - ($0.luid?.any != nil && $0.luid?.any == viewModel.luid.value) - || ($0.macId?.any != nil && $0.macId?.any == viewModel.mac.value) + ($0.luid?.any != nil && $0.luid?.any == viewModel.luid.value) + || ($0.macId?.any != nil && $0.macId?.any == viewModel.mac.value) }) let record = ruuviTag .with(source: .heartbeat) @@ -781,7 +799,7 @@ extension DashboardPresenter { } private func restartObserveRuuviTagAdvertisements() { - advertisementTokens.forEach({ $0.invalidate() }) + advertisementTokens.forEach { $0.invalidate() } advertisementTokens.removeAll() for viewModel in viewModels { let shouldAvoidObserving = @@ -792,14 +810,16 @@ extension DashboardPresenter { continue } if viewModel.type == .ruuvi, - let luid = viewModel.luid.value { - advertisementTokens.append(foreground.observe(self, uuid: luid.value) { [weak self] (_, device) in + let luid = viewModel.luid.value + { + advertisementTokens.append(foreground.observe(self, uuid: luid.value) { [weak self] _, device in if let ruuviTag = device.ruuvi?.tag, - let viewModel = self?.viewModels.first(where: { $0.luid.value == ruuviTag.uuid.luid.any }) { + let viewModel = self?.viewModels.first(where: { $0.luid.value == ruuviTag.uuid.luid.any }) + { let sensorSettings = self?.sensorSettingsList .first(where: { ($0.luid?.any != nil && $0.luid?.any == viewModel.luid.value) - || ($0.macId?.any != nil && $0.macId?.any == viewModel.mac.value) + || ($0.macId?.any != nil && $0.macId?.any == viewModel.mac.value) }) let record = ruuviTag .with(source: .advertisement) @@ -815,16 +835,17 @@ extension DashboardPresenter { // swiftlint:disable:next function_body_length cyclomatic_complexity private func observeSensorSettings() { - sensorSettingsTokens.forEach({ $0.invalidate() }) + sensorSettingsTokens.forEach { $0.invalidate() } sensorSettingsTokens.removeAll() for viewModel in viewModels { if viewModel.type == .ruuvi, - let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) { + let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) + { sensorSettingsTokens.append( - ruuviReactor.observe(ruuviTagSensor, { [weak self] change in + ruuviReactor.observe(ruuviTagSensor) { [weak self] change in guard let sSelf = self else { return } switch change { - case .insert(let sensorSettings): + case let .insert(sensorSettings): self?.sensorSettingsList.append(sensorSettings) if let viewModel = sSelf.viewModels.first(where: { $0.id.value == ruuviTagSensor.id @@ -834,7 +855,7 @@ extension DashboardPresenter { viewModel: viewModel ) } - case .update(let updateSensorSettings): + case let .update(updateSensorSettings): if let updateIndex = self?.sensorSettingsList.firstIndex( where: { $0.id == updateSensorSettings.id } ) { @@ -850,7 +871,7 @@ extension DashboardPresenter { } else { self?.sensorSettingsList.append(updateSensorSettings) } - case .delete(let deleteSensorSettings): + case let .delete(deleteSensorSettings): if let deleteIndex = self?.sensorSettingsList.firstIndex( where: { $0.id == deleteSensorSettings.id } ) { @@ -866,7 +887,7 @@ extension DashboardPresenter { } default: break } - }) + } ) } } @@ -877,7 +898,7 @@ extension DashboardPresenter { ) { let currentRecord = viewModel.latestMeasurement.value let updatedRecord = currentRecord?.with(sensorSettings: sensorSettings) - guard let updatedRecord = updatedRecord else { + guard let updatedRecord else { return } viewModel.update(updatedRecord) @@ -885,23 +906,25 @@ extension DashboardPresenter { } private func restartObservingRuuviTagLastRecords() { - ruuviTagObserveLastRecordTokens.forEach({ $0.invalidate() }) + ruuviTagObserveLastRecordTokens.forEach { $0.invalidate() } ruuviTagObserveLastRecordTokens.removeAll() for viewModel in viewModels { if viewModel.type == .ruuvi, - let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) { - let token = ruuviReactor.observeLatest(ruuviTagSensor) { [weak self] (changes) in - if case .update(let anyRecord) = changes, + let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) + { + let token = ruuviReactor.observeLatest(ruuviTagSensor) { [weak self] changes in + if case let .update(anyRecord) = changes, let viewModel = self?.viewModels - .first(where: { - ($0.luid.value != nil && ($0.luid.value == anyRecord?.luid?.any)) - || ($0.mac.value != nil && ($0.mac.value == anyRecord?.macId?.any)) - }), - let record = anyRecord { + .first(where: { + ($0.luid.value != nil && ($0.luid.value == anyRecord?.luid?.any)) + || ($0.mac.value != nil && ($0.mac.value == anyRecord?.macId?.any)) + }), + let record = anyRecord + { let sensorSettings = self?.sensorSettingsList .first(where: { - ($0.luid?.any != nil && $0.luid?.any == viewModel.luid.value) - || ($0.macId?.any != nil && $0.macId?.any == viewModel.mac.value) + ($0.luid?.any != nil && $0.luid?.any == viewModel.luid.value) + || ($0.macId?.any != nil && $0.macId?.any == viewModel.mac.value) }) let sensorRecord = record.with(sensorSettings: sensorSettings) viewModel.update(sensorRecord) @@ -918,10 +941,10 @@ extension DashboardPresenter { // swiftlint:disable:next function_body_length cyclomatic_complexity private func startObservingRuuviTags() { ruuviTagToken?.invalidate() - ruuviTagToken = ruuviReactor.observe { [weak self] (change) in + ruuviTagToken = ruuviReactor.observe { [weak self] change in guard let sSelf = self else { return } switch change { - case .initial(let ruuviTags): + case let .initial(ruuviTags): let ruuviTags = ruuviTags.reordered() sSelf.didLoadInitialRuuviTags = true sSelf.ruuviTags = ruuviTags @@ -930,7 +953,7 @@ extension DashboardPresenter { sSelf.observeRuuviTags() sSelf.restartObservingRuuviTagLastRecords() sSelf.syncHasCloudSensorToAppGroupContainer(with: ruuviTags) - case .insert(let sensor): + case let .insert(sensor): sSelf.notifyRestartAdvertisementDaemon() sSelf.notifyRestartHeartBeatDaemon() sSelf.checkFirmwareVersion(for: sensor) @@ -946,18 +969,19 @@ extension DashboardPresenter { sSelf.startListeningToRuuviTagsAlertStatus() sSelf.observeRuuviTags() if !sSelf.settings.isSyncing, - let viewModel = sSelf.viewModels.first(where: { - return ($0.luid.value != nil && $0.luid.value == sensor.luid?.any) - || ($0.mac.value != nil && $0.mac.value == sensor.macId?.any) - }) { + let viewModel = sSelf.viewModels.first(where: { + ($0.luid.value != nil && $0.luid.value == sensor.luid?.any) + || ($0.mac.value != nil && $0.mac.value == sensor.macId?.any) + }) + { let op = sSelf.ruuviStorage.readLatest(sensor.any) op.on { [weak self] record in - if let record = record { + if let record { viewModel.update(record) sSelf.openTagSettingsForNewSensor(viewModel: viewModel) } else { self?.ruuviStorage.readLast(sensor).on(success: { record in - if let record = record { + if let record { viewModel.update(record) } sSelf.openTagSettingsForNewSensor(viewModel: viewModel) @@ -966,23 +990,24 @@ extension DashboardPresenter { } sSelf.restartObservingRuuviTagLastRecords() } - case .delete(let sensor): + case let .delete(sensor): sSelf.ruuviTags.removeAll(where: { $0.id == sensor.id }) sSelf.syncViewModels() sSelf.startListeningToRuuviTagsAlertStatus() sSelf.observeRuuviTags() sSelf.restartObservingRuuviTagLastRecords() sSelf.syncHasCloudSensorToAppGroupContainer(with: sSelf.ruuviTags) - case .error(let error): + case let .error(error): sSelf.errorPresenter.present(error: error) - case .update(let sensor): + case let .update(sensor): guard let sSelf = self else { return } if let index = sSelf.ruuviTags .firstIndex( where: { ($0.macId != nil && $0.macId?.any == sensor.macId?.any) - || ($0.luid != nil && $0.luid?.any == sensor.luid?.any) - }) { + || ($0.luid != nil && $0.luid?.any == sensor.luid?.any) + }) + { sSelf.ruuviTags[index] = sensor sSelf.syncViewModels() sSelf.restartObserveRuuviTagAdvertisements() @@ -991,39 +1016,41 @@ extension DashboardPresenter { } } } + private func startObservingBackgroundChanges() { backgroundToken?.invalidate() backgroundToken = NotificationCenter .default .addObserver(forName: .BackgroundPersistenceDidChangeBackground, object: nil, - queue: .main) { [weak self] notification in + queue: .main) + { [weak self] notification in - guard let sSelf = self else { return } - if let userInfo = notification.userInfo { - let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier - let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier - let viewModel = sSelf.view?.viewModels - .first(where: { $0.luid.value != nil && $0.luid.value == luid?.any }) - ?? sSelf.view?.viewModels - .first(where: { $0.mac.value != nil && $0.mac.value == macId?.any }) - if let viewModel = viewModel { - let ruuviTag = sSelf.ruuviTags - .first(where: { $0.luid != nil && $0.luid?.any == luid?.any }) - ?? sSelf.ruuviTags - .first(where: { $0.macId != nil && $0.macId?.any == macId?.any }) - if let ruuviTag = ruuviTag { - sSelf.ruuviSensorPropertiesService.getImage(for: ruuviTag) - .on(success: { image in - viewModel.background.value = image - self?.notifyViewModelUpdate(for: viewModel) - }, failure: { [weak self] error in - self?.errorPresenter.present(error: error) - }) - } + guard let sSelf = self else { return } + if let userInfo = notification.userInfo { + let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier + let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier + let viewModel = sSelf.view?.viewModels + .first(where: { $0.luid.value != nil && $0.luid.value == luid?.any }) + ?? sSelf.view?.viewModels + .first(where: { $0.mac.value != nil && $0.mac.value == macId?.any }) + if let viewModel { + let ruuviTag = sSelf.ruuviTags + .first(where: { $0.luid != nil && $0.luid?.any == luid?.any }) + ?? sSelf.ruuviTags + .first(where: { $0.macId != nil && $0.macId?.any == macId?.any }) + if let ruuviTag { + sSelf.ruuviSensorPropertiesService.getImage(for: ruuviTag) + .on(success: { image in + viewModel.background.value = image + self?.notifyViewModelUpdate(for: viewModel) + }, failure: { [weak self] error in + self?.errorPresenter.present(error: error) + }) } } } + } } // swiftlint:disable:next cyclomatic_complexity function_body_length @@ -1034,11 +1061,12 @@ extension DashboardPresenter { .addObserver(forName: .RuuviTagAdvertisementDaemonDidFail, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let error = userInfo[RuuviTagAdvertisementDaemonDidFailKey.error] as? RUError { - self?.errorPresenter.present(error: error) - } + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let error = userInfo[RuuviTagAdvertisementDaemonDidFailKey.error] as? RUError + { + self?.errorPresenter.present(error: error) + } }) ruuviTagPropertiesDaemonFailureToken?.invalidate() ruuviTagPropertiesDaemonFailureToken = NotificationCenter @@ -1046,11 +1074,12 @@ extension DashboardPresenter { .addObserver(forName: .RuuviTagPropertiesDaemonDidFail, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let error = userInfo[RuuviTagPropertiesDaemonDidFailKey.error] as? RUError { - self?.errorPresenter.present(error: error) - } + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let error = userInfo[RuuviTagPropertiesDaemonDidFailKey.error] as? RUError + { + self?.errorPresenter.present(error: error) + } }) ruuviTagHeartbeatDaemonFailureToken?.invalidate() ruuviTagHeartbeatDaemonFailureToken = NotificationCenter @@ -1058,11 +1087,12 @@ extension DashboardPresenter { .addObserver(forName: .RuuviTagHeartbeatDaemonDidFail, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let error = userInfo[RuuviTagHeartbeatDaemonDidFailKey.error] as? RUError { - self?.errorPresenter.present(error: error) - } + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let error = userInfo[RuuviTagHeartbeatDaemonDidFailKey.error] as? RUError + { + self?.errorPresenter.present(error: error) + } }) ruuviTagReadLogsOperationFailureToken?.invalidate() ruuviTagReadLogsOperationFailureToken = NotificationCenter @@ -1070,11 +1100,12 @@ extension DashboardPresenter { .addObserver(forName: .RuuviTagReadLogsOperationDidFail, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let error = userInfo[RuuviTagReadLogsOperationDidFailKey.error] as? RUError { - self?.errorPresenter.present(error: error) - } + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let error = userInfo[RuuviTagReadLogsOperationDidFailKey.error] as? RUError + { + self?.errorPresenter.present(error: error) + } }) } @@ -1086,7 +1117,7 @@ extension DashboardPresenter { object: nil, queue: .main, using: { [weak self] _ in - self?.observeRuuviTagHeartbeats() + self?.observeRuuviTagHeartbeats() }) stopKeepingConnectionToken?.invalidate() stopKeepingConnectionToken = NotificationCenter @@ -1095,7 +1126,7 @@ extension DashboardPresenter { object: nil, queue: .main, using: { [weak self] _ in - self?.observeRuuviTagHeartbeats() + self?.observeRuuviTagHeartbeats() }) } @@ -1106,17 +1137,18 @@ extension DashboardPresenter { .addObserver(forName: .BTBackgroundDidConnect, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let uuid = userInfo[BTBackgroundDidConnectKey.uuid] as? String, - let viewModel = self?.viewModels.first(where: { $0.luid.value == uuid.luid.any }) { - viewModel.isConnected.value = true - self?.notifyViewModelUpdate(for: viewModel) - if let latestRecord = viewModel.latestMeasurement.value { - self?.processAlert(record: latestRecord, - viewModel: viewModel) - } - } + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let uuid = userInfo[BTBackgroundDidConnectKey.uuid] as? String, + let viewModel = self?.viewModels.first(where: { $0.luid.value == uuid.luid.any }) + { + viewModel.isConnected.value = true + self?.notifyViewModelUpdate(for: viewModel) + if let latestRecord = viewModel.latestMeasurement.value { + self?.processAlert(record: latestRecord, + viewModel: viewModel) + } + } }) didDisconnectToken?.invalidate() didDisconnectToken = NotificationCenter @@ -1124,17 +1156,18 @@ extension DashboardPresenter { .addObserver(forName: .BTBackgroundDidDisconnect, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let uuid = userInfo[BTBackgroundDidDisconnectKey.uuid] as? String, - let viewModel = self?.viewModels.first(where: { $0.luid.value == uuid.luid.any }) { - viewModel.isConnected.value = false - self?.notifyViewModelUpdate(for: viewModel) - if let latestRecord = viewModel.latestMeasurement.value { - self?.processAlert(record: latestRecord, - viewModel: viewModel) - } - } + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let uuid = userInfo[BTBackgroundDidDisconnectKey.uuid] as? String, + let viewModel = self?.viewModels.first(where: { $0.luid.value == uuid.luid.any }) + { + viewModel.isConnected.value = false + self?.notifyViewModelUpdate(for: viewModel) + if let latestRecord = viewModel.latestMeasurement.value { + self?.processAlert(record: latestRecord, + viewModel: viewModel) + } + } }) } @@ -1146,43 +1179,44 @@ extension DashboardPresenter { .addObserver(forName: .RuuviServiceAlertDidChange, object: nil, queue: .main, - using: { [weak self] (notification) in - guard let sSelf = self else { return } - if let userInfo = notification.userInfo { - if let physicalSensor - = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor, - let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType { - sSelf.viewModels.filter({ - ($0.luid.value != nil && ($0.luid.value == physicalSensor.luid?.any)) - || ($0.mac.value != nil && ($0.mac.value == physicalSensor.macId?.any)) - }).forEach({ (viewModel) in - if sSelf.alertService.hasRegistrations(for: physicalSensor) { - viewModel.rhAlertLowerBound.value = sSelf.alertService - .lowerRelativeHumidity(for: physicalSensor) - viewModel.rhAlertUpperBound.value = sSelf.alertService - .upperRelativeHumidity(for: physicalSensor) - - } else { - viewModel.rhAlertLowerBound.value = 0 - viewModel.rhAlertUpperBound.value = 100 - } - sSelf.syncAlerts(ruuviTag: physicalSensor, - viewModel: viewModel) - sSelf.updateIsOnState(of: type, - for: physicalSensor.id, - viewModel: viewModel) - sSelf.updateMutedTill(of: type, - for: physicalSensor.id, - viewModel: viewModel) - sSelf.triggerAlertsIfNeeded() - }) - } - } - }) + using: { [weak self] notification in + guard let sSelf = self else { return } + if let userInfo = notification.userInfo { + if let physicalSensor + = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor, + let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType + { + sSelf.viewModels.filter { + ($0.luid.value != nil && ($0.luid.value == physicalSensor.luid?.any)) + || ($0.mac.value != nil && ($0.mac.value == physicalSensor.macId?.any)) + }.forEach { viewModel in + if sSelf.alertService.hasRegistrations(for: physicalSensor) { + viewModel.rhAlertLowerBound.value = sSelf.alertService + .lowerRelativeHumidity(for: physicalSensor) + viewModel.rhAlertUpperBound.value = sSelf.alertService + .upperRelativeHumidity(for: physicalSensor) + + } else { + viewModel.rhAlertLowerBound.value = 0 + viewModel.rhAlertUpperBound.value = 100 + } + sSelf.syncAlerts(ruuviTag: physicalSensor, + viewModel: viewModel) + sSelf.updateIsOnState(of: type, + for: physicalSensor.id, + viewModel: viewModel) + sSelf.updateMutedTill(of: type, + for: physicalSensor.id, + viewModel: viewModel) + sSelf.triggerAlertsIfNeeded() + } + } + } + }) } private func startListeningToRuuviTagsAlertStatus() { - ruuviTags.forEach({ (ruuviTag) in + ruuviTags.forEach { ruuviTag in if ruuviTag.isCloud { if let macId = ruuviTag.macId { alertHandler.subscribe(self, to: macId.value) @@ -1194,26 +1228,27 @@ extension DashboardPresenter { alertHandler.subscribe(self, to: macId.value) } } - }) + } } private func openTagSettingsScreens(viewModel: CardsViewModel) { if let ruuviTag = ruuviTags.first(where: { $0.id == viewModel.id.value }) { - self.router.openTagSettings( + router.openTagSettings( ruuviTag: ruuviTag, latestMeasurement: viewModel.latestMeasurement.value, sensorSettings: sensorSettingsList .first(where: { ($0.luid != nil && $0.luid?.any == viewModel.luid.value) - || ($0.macId != nil && $0.macId?.any == viewModel.mac.value) + || ($0.macId != nil && $0.macId?.any == viewModel.mac.value) }), - output: self) + output: self + ) } } private func openTagSettingsForNewSensor(viewModel: CardsViewModel) { if let ruuviTag = ruuviTags.first(where: { $0.id == viewModel.id.value }) { - self.router.openTagSettings( + router.openTagSettings( with: viewModels, ruuviTagSensors: ruuviTags, sensorSettings: sensorSettingsList, @@ -1223,7 +1258,7 @@ extension DashboardPresenter { sensorSetting: sensorSettingsList .first(where: { ($0.luid != nil && $0.luid?.any == viewModel.luid.value) - || ($0.macId != nil && $0.macId?.any == viewModel.mac.value) + || ($0.macId != nil && $0.macId?.any == viewModel.mac.value) }), output: self ) @@ -1245,15 +1280,16 @@ extension DashboardPresenter { .addObserver(forName: .DidOpenWithUniversalLink, object: nil, queue: .main, - using: { [weak self] (notification) in - guard let self = self, - let userInfo = notification.userInfo else { - guard let email = self?.ruuviUser.email else { return } - self?.view?.showAlreadyLoggedInAlert(with: email) - return - } - self.processLink(userInfo) - }) + using: { [weak self] notification in + guard let self, + let userInfo = notification.userInfo + else { + guard let email = self?.ruuviUser.email else { return } + self?.view?.showAlreadyLoggedInAlert(with: email) + return + } + processLink(userInfo) + }) } private func processLink(_ userInfo: [AnyHashable: Any]) { @@ -1271,8 +1307,8 @@ extension DashboardPresenter { object: nil, queue: .main, using: { [weak self] _ in - self?.handleCloudModeState() - }) + self?.handleCloudModeState() + }) } /// The method handles all the operations when cloud mode toggle is turned on/off @@ -1286,11 +1322,11 @@ extension DashboardPresenter { } private func removeConnectionsForCloudTags() { - connectionPersistence.keepConnectionUUIDs.filter { (luid) -> Bool in - ruuviTags.filter({ $0.isCloud }).contains(where: { + connectionPersistence.keepConnectionUUIDs.filter { luid -> Bool in + ruuviTags.filter(\.isCloud).contains(where: { $0.luid?.any != nil && $0.luid?.any == luid }) - }.forEach { (luid) in + }.forEach { luid in connectionPersistence.setKeepConnection(false, for: luid) } } @@ -1301,15 +1337,17 @@ extension DashboardPresenter { .default .addObserver(forName: .TemperatureUnitDidChange, object: nil, - queue: .main) { [weak self] _ in - self?.syncAppSettingsToAppGroupContainer() + queue: .main) + { [weak self] _ in + self?.syncAppSettingsToAppGroupContainer() } temperatureAccuracyToken = NotificationCenter .default .addObserver(forName: .TemperatureAccuracyDidChange, object: nil, - queue: .main) { [weak self] _ in - self?.syncAppSettingsToAppGroupContainer() + queue: .main) + { [weak self] _ in + self?.syncAppSettingsToAppGroupContainer() } humidityUnitToken = NotificationCenter .default @@ -1317,72 +1355,74 @@ extension DashboardPresenter { object: nil, queue: .main, using: { [weak self] _ in - self?.syncAppSettingsToAppGroupContainer() - }) + self?.syncAppSettingsToAppGroupContainer() + }) humidityAccuracyToken = NotificationCenter .default .addObserver(forName: .HumidityAccuracyDidChange, object: nil, queue: .main, using: { [weak self] _ in - self?.syncAppSettingsToAppGroupContainer() - }) + self?.syncAppSettingsToAppGroupContainer() + }) pressureUnitToken = NotificationCenter .default .addObserver(forName: .PressureUnitDidChange, object: nil, queue: .main, using: { [weak self] _ in - self?.syncAppSettingsToAppGroupContainer() - }) + self?.syncAppSettingsToAppGroupContainer() + }) pressureAccuracyToken = NotificationCenter .default .addObserver(forName: .PressureUnitAccuracyChange, object: nil, queue: .main, using: { [weak self] _ in - self?.syncAppSettingsToAppGroupContainer() - }) + self?.syncAppSettingsToAppGroupContainer() + }) languageToken = NotificationCenter .default .addObserver(forName: .LanguageDidChange, object: nil, queue: .main, using: { [weak self] _ in - self?.syncAppSettingsToAppGroupContainer() - }) + self?.syncAppSettingsToAppGroupContainer() + }) systemLanguageChangeToken = NotificationCenter .default .addObserver(forName: NSLocale.currentLocaleDidChangeNotification, object: nil, queue: .main, using: { [weak self] _ in - self?.systemLocaleDidChange() - }) + self?.systemLocaleDidChange() + }) dashboardTypeToken = NotificationCenter .default .addObserver(forName: .DashboardTypeDidChange, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let type = userInfo[DashboardTypeKey.type] as? DashboardType { - self?.view?.dashboardType = type - } - }) + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let type = userInfo[DashboardTypeKey.type] as? DashboardType + { + self?.view?.dashboardType = type + } + }) dashboardTapActionTypeToken = NotificationCenter .default .addObserver(forName: .DashboardTapActionTypeDidChange, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let type = userInfo[DashboardTapActionTypeKey.type] as? - DashboardTapActionType { - self?.view?.dashboardTapActionType = type - } - }) + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let type = userInfo[DashboardTapActionTypeKey.type] as? + DashboardTapActionType + { + self?.view?.dashboardTapActionType = type + } + }) } private func startObservingCloudSyncSuccessTokenState() { @@ -1394,8 +1434,8 @@ extension DashboardPresenter { object: nil, queue: .main, using: { [weak self] _ in - self?.triggerAlertsIfNeeded() - }) + self?.triggerAlertsIfNeeded() + }) } private func startObservingCloudSyncFailTokenState() { @@ -1407,21 +1447,22 @@ extension DashboardPresenter { object: nil, queue: .main, using: { [weak self] _ in - self?.forceLogoutUser() - }) + self?.forceLogoutUser() + }) } - + @objc private func systemLocaleDidChange() { syncAppSettingsToAppGroupContainer() } - fileprivate func askAppStoreReview(with sensorsCount: Int) { + private func askAppStoreReview(with sensorsCount: Int) { guard let dayDifference = Calendar.current.dateComponents( [.day], from: FileManager().appInstalledDate, to: Date() ).day, dayDifference > 7, - sensorsCount > 0 else { + sensorsCount > 0 + else { return } AppStoreReviewHelper.askForReview(settings: settings) @@ -1434,9 +1475,9 @@ extension DashboardPresenter { object: nil, queue: .main, using: { [weak self] _ in - guard let sSelf = self else { return } - sSelf.restartObservingRuuviTagLastRecords() - }) + guard let sSelf = self else { return } + sSelf.restartObservingRuuviTagLastRecords() + }) } private func checkFirmwareVersion(for ruuviTag: RuuviTagSensor) { @@ -1447,7 +1488,7 @@ extension DashboardPresenter { } private func syncAlerts(ruuviTag: PhysicalSensor, viewModel: CardsViewModel) { - AlertType.allCases.forEach { (type) in + AlertType.allCases.forEach { type in switch type { case .temperature: sync(temperature: type, ruuviTag: ruuviTag, viewModel: viewModel) @@ -1474,7 +1515,7 @@ extension DashboardPresenter { viewModel.signalAlertState.value, viewModel.connectionAlertState.value, viewModel.movementAlertState.value, - viewModel.cloudConnectionAlertState.value + viewModel.cloudConnectionAlertState.value, ] if alertService.hasRegistrations(for: ruuviTag) { @@ -1495,9 +1536,11 @@ extension DashboardPresenter { private func sync(temperature: AlertType, ruuviTag: PhysicalSensor, - viewModel: CardsViewModel) { + viewModel: CardsViewModel) + { if case .temperature = alertService - .alert(for: ruuviTag, of: temperature) { + .alert(for: ruuviTag, of: temperature) + { viewModel.isTemperatureAlertOn.value = true } else { viewModel.isTemperatureAlertOn.value = false @@ -1509,9 +1552,11 @@ extension DashboardPresenter { private func sync(relativeHumidity: AlertType, ruuviTag: PhysicalSensor, - viewModel: CardsViewModel) { + viewModel: CardsViewModel) + { if case .relativeHumidity = alertService.alert(for: ruuviTag, - of: relativeHumidity) { + of: relativeHumidity) + { viewModel.isRelativeHumidityAlertOn.value = true } else { viewModel.isRelativeHumidityAlertOn.value = false @@ -1523,7 +1568,8 @@ extension DashboardPresenter { private func sync(pressure: AlertType, ruuviTag: PhysicalSensor, - viewModel: CardsViewModel) { + viewModel: CardsViewModel) + { if case .pressure = alertService.alert(for: ruuviTag, of: pressure) { viewModel.isPressureAlertOn.value = true } else { @@ -1536,7 +1582,8 @@ extension DashboardPresenter { private func sync(signal: AlertType, ruuviTag: PhysicalSensor, - viewModel: CardsViewModel) { + viewModel: CardsViewModel) + { if case .signal = alertService.alert(for: ruuviTag, of: signal) { viewModel.isSignalAlertOn.value = true } else { @@ -1549,7 +1596,8 @@ extension DashboardPresenter { private func sync(connection: AlertType, ruuviTag: PhysicalSensor, - viewModel: CardsViewModel) { + viewModel: CardsViewModel) + { if case .connection = alertService.alert(for: ruuviTag, of: connection) { viewModel.isConnectionAlertOn.value = true } else { @@ -1562,7 +1610,8 @@ extension DashboardPresenter { private func sync(movement: AlertType, ruuviTag: PhysicalSensor, - viewModel: CardsViewModel) { + viewModel: CardsViewModel) + { if case .movement = alertService.alert(for: ruuviTag, of: movement) { viewModel.isMovementAlertOn.value = true } else { @@ -1575,7 +1624,8 @@ extension DashboardPresenter { private func sync(cloudConnection: AlertType, ruuviTag: PhysicalSensor, - viewModel: CardsViewModel) { + viewModel: CardsViewModel) + { if case .cloudConnection = alertService.alert(for: ruuviTag, of: cloudConnection) { viewModel.isCloudConnectionAlertOn.value = true } else { @@ -1586,32 +1636,38 @@ extension DashboardPresenter { private func reloadMutedTill() { for viewModel in viewModels { if let mutedTill = viewModel.temperatureAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.temperatureAlertMutedTill.value = nil } if let mutedTill = viewModel.relativeHumidityAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.relativeHumidityAlertMutedTill.value = nil } if let mutedTill = viewModel.pressureAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.pressureAlertMutedTill.value = nil } if let mutedTill = viewModel.signalAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.signalAlertMutedTill.value = nil } if let mutedTill = viewModel.connectionAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.connectionAlertMutedTill.value = nil } if let mutedTill = viewModel.movementAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.movementAlertMutedTill.value = nil } @@ -1621,24 +1677,24 @@ extension DashboardPresenter { private func updateMutedTill(of type: AlertType, for uuid: String, - viewModel: CardsViewModel) { - var observable: Observable - switch type { + viewModel: CardsViewModel) + { + var observable: Observable = switch type { case .temperature: - observable = viewModel.temperatureAlertMutedTill + viewModel.temperatureAlertMutedTill case .relativeHumidity: - observable = viewModel.relativeHumidityAlertMutedTill + viewModel.relativeHumidityAlertMutedTill case .pressure: - observable = viewModel.pressureAlertMutedTill + viewModel.pressureAlertMutedTill case .signal: - observable = viewModel.signalAlertMutedTill + viewModel.signalAlertMutedTill case .connection: - observable = viewModel.connectionAlertMutedTill + viewModel.connectionAlertMutedTill case .movement: - observable = viewModel.movementAlertMutedTill + viewModel.movementAlertMutedTill default: // Should never be here - observable = viewModel.temperatureAlertMutedTill + viewModel.temperatureAlertMutedTill } let date = alertService.mutedTill(type: type, for: uuid) @@ -1650,26 +1706,26 @@ extension DashboardPresenter { private func updateIsOnState(of type: AlertType, for uuid: String, - viewModel: CardsViewModel) { - var observable: Observable - switch type { + viewModel: CardsViewModel) + { + var observable: Observable = switch type { case .temperature: - observable = viewModel.isTemperatureAlertOn + viewModel.isTemperatureAlertOn case .relativeHumidity: - observable = viewModel.isRelativeHumidityAlertOn + viewModel.isRelativeHumidityAlertOn case .pressure: - observable = viewModel.isPressureAlertOn + viewModel.isPressureAlertOn case .signal: - observable = viewModel.isSignalAlertOn + viewModel.isSignalAlertOn case .connection: - observable = viewModel.isConnectionAlertOn + viewModel.isConnectionAlertOn case .movement: - observable = viewModel.isMovementAlertOn + viewModel.isMovementAlertOn case .cloudConnection: - observable = viewModel.isCloudConnectionAlertOn + viewModel.isCloudConnectionAlertOn default: // Should never be here - observable = viewModel.isTemperatureAlertOn + viewModel.isTemperatureAlertOn } let isOn = alertService.isOn(type: type, for: uuid) @@ -1718,7 +1774,7 @@ extension DashboardPresenter { } private func notifyRestartAdvertisementDaemon() { - // Notify daemon to restart + // Notify daemon to restart NotificationCenter .default .post(name: .RuuviTagAdvertisementDaemonShouldRestart, @@ -1727,7 +1783,7 @@ extension DashboardPresenter { } private func notifyRestartHeartBeatDaemon() { - // Notify daemon to restart + // Notify daemon to restart NotificationCenter .default .post(name: .RuuviTagHeartBeatDaemonShouldRestart, @@ -1749,4 +1805,5 @@ extension DashboardPresenter { } } } + // swiftlint:enable file_length trailing_whitespace diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift index 838065c0e..664730b1a 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift @@ -1,9 +1,9 @@ -import LightRoute import Foundation -import UIKit -import RuuviOntology +import LightRoute import RuuviLocal import RuuviLocalization +import RuuviOntology +import UIKit class DashboardRouter: NSObject, DashboardRouterInput { weak var transitionHandler: UIViewController! @@ -23,15 +23,15 @@ class DashboardRouter: NSObject, DashboardRouterInput { let factory = StoryboardFactory(storyboardName: "Menu") try! transitionHandler .forStoryboard(factory: factory, to: MenuModuleInput.self) - .apply(to: { (viewController) in + .apply(to: { viewController in viewController.modalPresentationStyle = .custom let manager = MenuTableTransitionManager(container: self.transitionHandler, menu: viewController) self.menuTableTransition = MenuTableTransitioningDelegate(manager: manager) }) .add(transitioningDelegate: menuTableTransition) - .then({ (module) -> Any? in + .then { module -> Any? in module.configure(output: output) - }) + } } func openDiscover(delegate: DiscoverRouterDelegate) { @@ -95,7 +95,8 @@ class DashboardRouter: NSObject, DashboardRouterInput { func openTagSettings(ruuviTag: RuuviTagSensor, latestMeasurement: RuuviTagSensorRecord?, sensorSettings: SensorSettings?, - output: TagSettingsModuleOutput) { + output: TagSettingsModuleOutput) + { let factory: TagSettingsModuleFactory = TagSettingsModuleFactoryImpl() let module = factory.create() transitionHandler @@ -107,17 +108,19 @@ class DashboardRouter: NSObject, DashboardRouterInput { if let presenter = module.output as? TagSettingsModuleInput { presenter.configure(output: output) presenter.configure(ruuviTag: ruuviTag, - latestMeasurement: latestMeasurement, - sensorSettings: sensorSettings) + latestMeasurement: latestMeasurement, + sensorSettings: sensorSettings) } } + // swiftlint:disable:next function_parameter_count func openCardImageView(with viewModels: [CardsViewModel], ruuviTagSensors: [AnyRuuviTagSensor], sensorSettings: [SensorSettings], scrollTo: CardsViewModel?, showCharts: Bool, - output: CardsModuleOutput) { + output: CardsModuleOutput) + { let factory: CardsViewModuleFactory = CardsViewModuleFactoryImpl() let module = factory.create() if let output = module.output as? CardsModuleInput { @@ -126,8 +129,9 @@ class DashboardRouter: NSObject, DashboardRouterInput { // Remove any cards view controller from stack if exists already if let navigationController = transitionHandler.navigationController, - navigationController - .containsViewController(ofKind: CardsViewController.self) { + navigationController + .containsViewController(ofKind: CardsViewController.self) + { transitionHandler .navigationController? .removeAnyViewControllers(ofKind: CardsViewController.self) @@ -139,7 +143,7 @@ class DashboardRouter: NSObject, DashboardRouterInput { module, animated: true ) - if let cards = cards { + if let cards { cards.configure(output: output) cards.configure(viewModels: viewModels, ruuviTagSensors: ruuviTagSensors, @@ -157,7 +161,8 @@ class DashboardRouter: NSObject, DashboardRouterInput { ruuviTag: RuuviTagSensor, latestMeasurement: RuuviTagSensorRecord?, sensorSetting: SensorSettings?, - output: CardsModuleOutput) { + output: CardsModuleOutput) + { let cardsFactory: CardsViewModuleFactory = CardsViewModuleFactoryImpl() let cardsModule = cardsFactory.create() @@ -166,32 +171,33 @@ class DashboardRouter: NSObject, DashboardRouterInput { if let cardsPresenter = cardsModule.output as? CardsModuleInput, let cardsPresenterOutput = cardsPresenter as? TagSettingsModuleOutput, - let settingsPresenter = settingsModule.output as? TagSettingsModuleInput { + let settingsPresenter = settingsModule.output as? TagSettingsModuleInput + { cardsPresenter.configure(output: output) cardsPresenter.configure(viewModels: viewModels, - ruuviTagSensors: ruuviTagSensors, - sensorSettings: sensorSettings) + ruuviTagSensors: ruuviTagSensors, + sensorSettings: sensorSettings) cardsPresenter.configure(scrollTo: scrollTo, - openChart: false) + openChart: false) if let cardsOutput = cardsModule as? CardsViewOutput { cardsOutput.viewDidLoad() } settingsPresenter.configure(output: cardsPresenterOutput) settingsPresenter.configure(ruuviTag: ruuviTag, - latestMeasurement: latestMeasurement, - sensorSettings: sensorSetting) + latestMeasurement: latestMeasurement, + sensorSettings: sensorSetting) } transitionHandler.navigationController?.setViewControllers([ - transitionHandler, cardsModule, settingsModule + transitionHandler, cardsModule, settingsModule, ], animated: true) } func openUpdateFirmware(ruuviTag: RuuviTagSensor) { let factory: DFUModuleFactory = DFUModuleFactoryImpl() let module = factory.create(for: ruuviTag) - self.dfuModule = module + dfuModule = module transitionHandler .navigationController? .pushViewController( @@ -214,14 +220,13 @@ class DashboardRouter: NSObject, DashboardRouterInput { func openBackgroundSelectionView(ruuviTag: RuuviTagSensor) { let factory: BackgroundSelectionModuleFactory = BackgroundSelectionModuleFactoryImpl() let module = factory.create(for: ruuviTag) - self.backgroundSelectionModule = module + backgroundSelectionModule = module transitionHandler .navigationController? .pushViewController( module.viewController, animated: true ) - } func openShare(for sensor: RuuviTagSensor) { @@ -231,17 +236,16 @@ class DashboardRouter: NSObject, DashboardRouterInput { .forStoryboard(factory: factory, to: ShareModuleInput.self) .to(preferred: .navigation(style: .push)) - .then({ (module) -> Any? in + .then { module -> Any? in module.configure(sensor: sensor) - }) + } } - } extension DashboardRouter: UIAdaptivePresentationControllerDelegate { func presentationControllerShouldDismiss( - _ presentationController: UIPresentationController + _: UIPresentationController ) -> Bool { - return delegate.shouldDismissDiscover() + delegate.shouldDismissDiscover() } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift index 751313f8c..21b3c4425 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift @@ -1,12 +1,11 @@ -// swiftlint:disable file_length -import UIKit -import RuuviService import RuuviLocal import RuuviLocalization import RuuviOntology +import RuuviService +// swiftlint:disable file_length +import UIKit class DashboardImageCell: UICollectionViewCell { - private lazy var cardBackgroundView = CardsBackgroundView() private lazy var ruuviTagNameLabel: UILabel = { @@ -119,13 +118,13 @@ class DashboardImageCell: UICollectionViewCell { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } // swiftlint:disable:next function_body_length fileprivate func setUpUI() { - let container = UIView(color: RuuviColor.dashboardCardBGColor, cornerRadius: 8) contentView.addSubview(container) @@ -252,7 +251,7 @@ class DashboardImageCell: UICollectionViewCell { .isActive = true let sourceAndUpdateStack = UIStackView(arrangedSubviews: [ - dataSourceIconView, updatedAtLabel + dataSourceIconView, updatedAtLabel, ]) sourceAndUpdateStack.axis = .horizontal sourceAndUpdateStack.spacing = 6 @@ -264,7 +263,7 @@ class DashboardImageCell: UICollectionViewCell { dataSourceIconViewWidthConstraint.isActive = true let footerStack = UIStackView(arrangedSubviews: [ - sourceAndUpdateStack, batteryLevelView + sourceAndUpdateStack, batteryLevelView, ]) footerStack.spacing = 4 footerStack.axis = .horizontal @@ -272,13 +271,13 @@ class DashboardImageCell: UICollectionViewCell { container.addSubview(footerStack) footerStack.anchor(top: leftContainerView.bottomAnchor, - leading: ruuviTagNameLabel.leadingAnchor, - bottom: container.bottomAnchor, - trailing: container.trailingAnchor, - padding: .init(top: 4, - left: 0, - bottom: 6, - right: 12)) + leading: ruuviTagNameLabel.leadingAnchor, + bottom: container.bottomAnchor, + trailing: container.trailingAnchor, + padding: .init(top: 4, + left: 0, + bottom: 6, + right: 12)) batteryLevelView.isHidden = true } } @@ -304,10 +303,10 @@ extension DashboardImageCell { } extension DashboardImageCell { - // swiftlint:disable:next function_body_length cyclomatic_complexity func configure(with viewModel: CardsViewModel, - measurementService: RuuviServiceMeasurement?) { + measurementService: RuuviServiceMeasurement?) + { self.viewModel = viewModel cardBackgroundView @@ -332,7 +331,8 @@ extension DashboardImageCell { // Humidity if let humidity = viewModel.humidity.value, - let measurementService = measurementService { + let measurementService + { hideHumidityView(hide: false) let humidityValue = measurementService.stringWithoutSign( for: humidity, @@ -341,7 +341,7 @@ extension DashboardImageCell { let humidityUnit = measurementService.units.humidityUnit let humidityUnitSymbol = humidityUnit.symbol let temperatureUnitSymbol = measurementService.units.temperatureUnit.symbol - let unit = humidityUnit == .dew ? temperatureUnitSymbol + let unit = humidityUnit == .dew ? temperatureUnitSymbol : humidityUnitSymbol humidityView.setValue(with: humidityValue, unit: unit) @@ -412,7 +412,8 @@ extension DashboardImageCell { // Battery state if let batteryLow = viewModel.batteryNeedsReplacement.value, - batteryLow { + batteryLow + { batteryLevelView.isHidden = false } else { batteryLevelView.isHidden = true @@ -421,7 +422,6 @@ extension DashboardImageCell { // swiftlint:disable:next function_body_length cyclomatic_complexity func restartAlertAnimation(for viewModel: CardsViewModel) { - // Alert let alertVisible = viewModel.isCloud.value ?? false || viewModel.isConnected.value ?? false @@ -431,7 +431,7 @@ extension DashboardImageCell { viewModel.pressureAlertMutedTill.value, viewModel.signalAlertMutedTill.value, viewModel.movementAlertMutedTill.value, - viewModel.connectionAlertMutedTill.value + viewModel.connectionAlertMutedTill.value, ] if mutedTills.first(where: { $0 != nil }) != nil || !alertVisible { @@ -442,28 +442,32 @@ extension DashboardImageCell { } if let isOn = viewModel.isTemperatureAlertOn.value, isOn, - let temperatureAlertState = viewModel.temperatureAlertState.value { + let temperatureAlertState = viewModel.temperatureAlertState.value + { highlightTemperatureValues(highlight: temperatureAlertState == .firing) } else { highlightTemperatureValues(highlight: false) } if let isOn = viewModel.isRelativeHumidityAlertOn.value, isOn, - let rhAlertState = viewModel.relativeHumidityAlertState.value { + let rhAlertState = viewModel.relativeHumidityAlertState.value + { humidityView.changeColor(highlight: rhAlertState == .firing) } else { humidityView.changeColor(highlight: false) } if let isOn = viewModel.isPressureAlertOn.value, isOn, - let pressureAlertState = viewModel.pressureAlertState.value { + let pressureAlertState = viewModel.pressureAlertState.value + { pressureView.changeColor(highlight: pressureAlertState == .firing) } else { pressureView.changeColor(highlight: false) } if let isOn = viewModel.isMovementAlertOn.value, isOn, - let movementAlertState = viewModel.movementAlertState.value { + let movementAlertState = viewModel.movementAlertState.value + { movementView.changeColor(highlight: movementAlertState == .firing) } else { movementView.changeColor(highlight: false) @@ -493,15 +497,15 @@ extension DashboardImageCell { if alertIcon.image != RuuviAssets.alertActiveImage { alertIcon.image = RuuviAssets.alertActiveImage } - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { UIView.animate(withDuration: 0.5, delay: 0, options: [.repeat, .autoreverse], animations: { [weak self] in - self?.alertIcon.alpha = 0.0 - }) - }) + self?.alertIcon.alpha = 0.0 + }) + } } } else { alertIcon.image = nil @@ -511,11 +515,10 @@ extension DashboardImageCell { } func removeAlertAnimations(alpha: Double = 1) { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, - execute: { [weak self] in + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in self?.alertIcon.layer.removeAllAnimations() self?.alertIcon.alpha = alpha - }) + } } } @@ -526,13 +529,13 @@ extension DashboardImageCell { timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, - block: { [weak self] (_) in - if let date = date?.ruuviAgo() { - self?.updatedAtLabel.text = date - } else { - self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message - } - }) + block: { [weak self] _ in + if let date = date?.ruuviAgo() { + self?.updatedAtLabel.text = date + } else { + self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message + } + }) } private func hideHumidityView(hide: Bool) { @@ -566,11 +569,11 @@ extension DashboardImageCell { } private func indicatorViewHeight() -> CGFloat { - return GlobalHelpers.isDeviceTablet() ? 24 : 18 + GlobalHelpers.isDeviceTablet() ? 24 : 18 } @objc private func alertButtonDidTap() { - guard let viewModel = viewModel else { + guard let viewModel else { return } delegate?.didTapAlertButton(for: viewModel) diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift index a306d10fc..3d12fe7b9 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift @@ -1,7 +1,6 @@ import UIKit class DashboardIndicatorView: UIView { - private lazy var indicatorValueLabel: UILabel = { let label = UILabel() label.textColor = RuuviColor.dashboardIndicatorTextColor @@ -27,12 +26,12 @@ class DashboardIndicatorView: UIView { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } fileprivate func setUpUI() { - addSubview(indicatorValueLabel) indicatorValueLabel.anchor(top: topAnchor, leading: leadingAnchor, @@ -52,7 +51,7 @@ class DashboardIndicatorView: UIView { .topAnchor .constraint( lessThanOrEqualTo: indicatorValueLabel.topAnchor, - constant: 2 + constant: 2 ).isActive = true indicatorUnitLabel.trailingAnchor diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift index 47e93eac6..0d9d52a73 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift @@ -1,12 +1,11 @@ -// swiftlint:disable file_length -import UIKit -import RuuviService import RuuviLocal import RuuviLocalization import RuuviOntology +import RuuviService +// swiftlint:disable file_length +import UIKit class DashboardPlainCell: UICollectionViewCell { - private lazy var ruuviTagNameLabel: UILabel = { let label = UILabel() label.textColor = RuuviColor.dashboardIndicatorBigTextColor @@ -100,7 +99,8 @@ class DashboardPlainCell: UICollectionViewCell { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -154,7 +154,8 @@ class DashboardPlainCell: UICollectionViewCell { .topAnchor .constraint( greaterThanOrEqualTo: ruuviTagNameLabel.bottomAnchor, - constant: 4) + constant: 4 + ) .isActive = true let emptySpacer = UIView() @@ -169,9 +170,9 @@ class DashboardPlainCell: UICollectionViewCell { leftContainerView.addSubview(temperatureView) temperatureView.anchor(top: emptySpacer.bottomAnchor, - leading: leftContainerView.leadingAnchor, - bottom: nil, - trailing: leftContainerView.trailingAnchor) + leading: leftContainerView.leadingAnchor, + bottom: nil, + trailing: leftContainerView.trailingAnchor) temperatureViewHeight = temperatureView .heightAnchor .constraint(equalToConstant: indicatorViewHeight()) @@ -218,7 +219,7 @@ class DashboardPlainCell: UICollectionViewCell { .isActive = true let sourceAndUpdateStack = UIStackView(arrangedSubviews: [ - dataSourceIconView, updatedAtLabel + dataSourceIconView, updatedAtLabel, ]) sourceAndUpdateStack.axis = .horizontal sourceAndUpdateStack.spacing = 6 @@ -230,7 +231,7 @@ class DashboardPlainCell: UICollectionViewCell { dataSourceIconViewWidthConstraint.isActive = true let footerStack = UIStackView(arrangedSubviews: [ - sourceAndUpdateStack, batteryLevelView + sourceAndUpdateStack, batteryLevelView, ]) footerStack.spacing = 4 footerStack.axis = .horizontal @@ -238,13 +239,13 @@ class DashboardPlainCell: UICollectionViewCell { container.addSubview(footerStack) footerStack.anchor(top: leftContainerView.bottomAnchor, - leading: ruuviTagNameLabel.leadingAnchor, - bottom: container.bottomAnchor, - trailing: container.trailingAnchor, - padding: .init(top: 4, - left: 0, - bottom: 6, - right: 12)) + leading: ruuviTagNameLabel.leadingAnchor, + bottom: container.bottomAnchor, + trailing: container.trailingAnchor, + padding: .init(top: 4, + left: 0, + bottom: 6, + right: 12)) batteryLevelView.isHidden = true } } @@ -269,11 +270,10 @@ extension DashboardPlainCell { } extension DashboardPlainCell { - // swiftlint:disable:next function_body_length cyclomatic_complexity func configure(with viewModel: CardsViewModel, - measurementService: RuuviServiceMeasurement?) { - + measurementService: RuuviServiceMeasurement?) + { self.viewModel = viewModel // Name @@ -281,7 +281,8 @@ extension DashboardPlainCell { // Temp if let temp = measurementService?.stringWithoutSign(for: viewModel.temperature.value), - let temperatureUnit = measurementService?.units.temperatureUnit { + let temperatureUnit = measurementService?.units.temperatureUnit + { temperatureView.setValue(with: temp, unit: temperatureUnit.symbol) } else { temperatureView.setValue(with: RuuviLocalization.na) @@ -289,7 +290,8 @@ extension DashboardPlainCell { // Humidity if let humidity = viewModel.humidity.value, - let measurementService = measurementService { + let measurementService + { hideHumidityView(hide: false) let humidityValue = measurementService.stringWithoutSign( for: humidity, @@ -298,7 +300,7 @@ extension DashboardPlainCell { let humidityUnit = measurementService.units.humidityUnit let humidityUnitSymbol = humidityUnit.symbol let temperatureUnitSymbol = measurementService.units.temperatureUnit.symbol - let unit = humidityUnit == .dew ? temperatureUnitSymbol + let unit = humidityUnit == .dew ? temperatureUnitSymbol : humidityUnitSymbol humidityView.setValue(with: humidityValue, unit: unit) @@ -370,7 +372,8 @@ extension DashboardPlainCell { // Battery stat if let batteryLow = viewModel.batteryNeedsReplacement.value, - batteryLow { + batteryLow + { batteryLevelView.isHidden = false } else { batteryLevelView.isHidden = true @@ -379,7 +382,6 @@ extension DashboardPlainCell { // swiftlint:disable:next function_body_length cyclomatic_complexity func restartAlertAnimation(for viewModel: CardsViewModel) { - // Alert let alertVisible = viewModel.isCloud.value ?? false || viewModel.isConnected.value ?? false @@ -390,7 +392,7 @@ extension DashboardPlainCell { viewModel.pressureAlertMutedTill.value, viewModel.signalAlertMutedTill.value, viewModel.movementAlertMutedTill.value, - viewModel.connectionAlertMutedTill.value + viewModel.connectionAlertMutedTill.value, ] if mutedTills.first(where: { $0 != nil }) != nil || !alertVisible { @@ -401,28 +403,32 @@ extension DashboardPlainCell { } if let isOn = viewModel.isTemperatureAlertOn.value, isOn, - let temperatureAlertState = viewModel.temperatureAlertState.value { + let temperatureAlertState = viewModel.temperatureAlertState.value + { temperatureView.changeColor(highlight: temperatureAlertState == .firing) } else { temperatureView.changeColor(highlight: false) } if let isOn = viewModel.isRelativeHumidityAlertOn.value, isOn, - let rhAlertState = viewModel.relativeHumidityAlertState.value { + let rhAlertState = viewModel.relativeHumidityAlertState.value + { humidityView.changeColor(highlight: rhAlertState == .firing) } else { humidityView.changeColor(highlight: false) } if let isOn = viewModel.isPressureAlertOn.value, isOn, - let pressureAlertState = viewModel.pressureAlertState.value { + let pressureAlertState = viewModel.pressureAlertState.value + { pressureView.changeColor(highlight: pressureAlertState == .firing) } else { pressureView.changeColor(highlight: false) } if let isOn = viewModel.isMovementAlertOn.value, isOn, - let movementAlertState = viewModel.movementAlertState.value { + let movementAlertState = viewModel.movementAlertState.value + { movementView.changeColor(highlight: movementAlertState == .firing) } else { movementView.changeColor(highlight: false) @@ -452,16 +458,16 @@ extension DashboardPlainCell { if alertIcon.image != RuuviAssets.alertActiveImage { alertIcon.image = RuuviAssets.alertActiveImage } - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { UIView.animate(withDuration: 0.5, delay: 0, options: [.repeat, .autoreverse, .beginFromCurrentState], animations: { [weak self] in - self?.alertIcon.alpha = 0.0 - }) - }) + self?.alertIcon.alpha = 0.0 + }) + } } } else { alertIcon.image = nil @@ -471,11 +477,10 @@ extension DashboardPlainCell { } func removeAlertAnimations(alpha: Double = 1) { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, - execute: { [weak self] in + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in self?.alertIcon.layer.removeAllAnimations() self?.alertIcon.alpha = alpha - }) + } } } @@ -486,13 +491,13 @@ extension DashboardPlainCell { timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, - block: { [weak self] (_) in - if let date = date?.ruuviAgo() { - self?.updatedAtLabel.text = date - } else { - self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message - } - }) + block: { [weak self] _ in + if let date = date?.ruuviAgo() { + self?.updatedAtLabel.text = date + } else { + self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message + } + }) } private func hideHumidityView(hide: Bool) { @@ -526,11 +531,11 @@ extension DashboardPlainCell { } private func indicatorViewHeight() -> CGFloat { - return GlobalHelpers.isDeviceTablet() ? 24 : 18 + GlobalHelpers.isDeviceTablet() ? 24 : 18 } @objc private func alertButtonDidTap() { - guard let viewModel = viewModel else { + guard let viewModel else { return } delegate?.didTapAlertButton(for: viewModel) diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift index 3507ab71e..dc52af0cd 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift @@ -1,13 +1,12 @@ -// swiftlint:disable file_length -import UIKit import Humidity -import RuuviOntology import RuuviLocal import RuuviLocalization +import RuuviOntology import RuuviService +// swiftlint:disable file_length +import UIKit class DashboardViewController: UIViewController { - // Configuration var output: DashboardViewOutput! var menuPresentInteractiveTransition: UIViewControllerInteractiveTransitioning! @@ -45,7 +44,8 @@ class DashboardViewController: UIViewController { private func cell(collectionView: UICollectionView, indexPath: IndexPath, - viewModel: CardsViewModel) -> UICollectionViewCell? { + viewModel: CardsViewModel) -> UICollectionViewCell? + { switch dashboardType { case .image: let cell = collectionView.dequeueReusableCell( @@ -74,7 +74,7 @@ class DashboardViewController: UIViewController { // UI private lazy var noSensorView: NoSensorView = { - let view = NoSensorView() + let view = NoSensorView() view.backgroundColor = RuuviColor.dashboardCardBGColor view.layer.cornerRadius = 12 view.clipsToBounds = true @@ -95,7 +95,7 @@ class DashboardViewController: UIViewController { // Action Buttons private lazy var menuButton: UIButton = { - let button = UIButton() + let button = UIButton() button.tintColor = RuuviColor.menuButtonTintColor let menuImage = UIImage(named: "baseline_menu_white_48pt") button.setImage(menuImage, for: .normal) @@ -108,13 +108,13 @@ class DashboardViewController: UIViewController { }() private lazy var viewButton: RuuviContextMenuButton = - RuuviContextMenuButton(menu: viewToggleMenuOptions(), - titleColor: RuuviColor.dashboardIndicatorTextColor, - title: RuuviLocalization.view, - icon: RuuviAssets.dropDownArrowImage, - iconTintColor: RuuviColor.logoTintColor, - iconSize: .init(width: 14, height: 14), - preccedingIcon: false) + .init(menu: viewToggleMenuOptions(), + titleColor: RuuviColor.dashboardIndicatorTextColor, + title: RuuviLocalization.view, + icon: RuuviAssets.dropDownArrowImage, + iconTintColor: RuuviColor.logoTintColor, + iconSize: .init(width: 14, height: 14), + preccedingIcon: false) // BODY private lazy var collectionView: UICollectionView = { @@ -139,6 +139,7 @@ class DashboardViewController: UIViewController { rc.addTarget(self, action: #selector(didPullToRefresh), for: .valueChanged) return rc }() + private var tagNameTextField = UITextField() private let tagNameCharaterLimit: Int = 32 @@ -155,6 +156,7 @@ class DashboardViewController: UIViewController { } // MARK: - View lifecycle + extension DashboardViewController { override func viewDidLoad() { super.viewDidLoad() @@ -183,31 +185,32 @@ extension DashboardViewController { override func viewWillTransition(to size: CGSize, with coordinator: - UIViewControllerTransitionCoordinator) { + UIViewControllerTransitionCoordinator) + { super.viewWillTransition(to: size, with: coordinator) reloadCollectionView(redrawLayout: true) } } -extension DashboardViewController { - @objc fileprivate func handleMenuButtonTap() { +private extension DashboardViewController { + @objc func handleMenuButtonTap() { output.viewDidTriggerMenu() } private func reloadCollectionView(redrawLayout: Bool = false) { DispatchQueue.main.async { [weak self] in if redrawLayout { - guard let self = self else { return } - let flowLayout = self.createLayout() - self.collectionView.setCollectionViewLayout( + guard let self else { return } + let flowLayout = createLayout() + collectionView.setCollectionViewLayout( flowLayout, animated: false, completion: { _ in guard self.viewModels.count > 0 else { return } let indexPath = IndexPath(item: 0, section: 0) self.collectionView.scrollToItem(at: indexPath, - at: .top, - animated: false) + at: .top, + animated: false) self.collectionView.contentOffset.y = -8 } ) @@ -216,19 +219,19 @@ extension DashboardViewController { } } - @objc fileprivate func didPullToRefresh() { + @objc func didPullToRefresh() { guard !isRefreshing else { - refresher.endRefreshing() - return + refresher.endRefreshing() + return } refresher.fadeIn() isRefreshing = true output.viewDidTriggerPullToRefresh() - DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1), execute: { [weak self] in + DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) { [weak self] in self?.refresher.endRefreshing() self?.isRefreshing = false self?.refresher.fadeOut() - }) + } } } @@ -255,8 +258,8 @@ extension DashboardViewController { let cardTypeMenu = UIMenu(title: RuuviLocalization.cardType, options: .displayInline, children: [ - imageViewTypeAction, simpleViewTypeAction - ]) + imageViewTypeAction, simpleViewTypeAction, + ]) // Card action let openSensorViewAction = UIAction(title: RuuviLocalization.openSensorView) { @@ -277,13 +280,13 @@ extension DashboardViewController { let cardActionMenu = UIMenu(title: RuuviLocalization.cardAction, options: .displayInline, children: [ - openSensorViewAction, openHistoryViewAction - ]) + openSensorViewAction, openHistoryViewAction, + ]) return UIMenu( title: "", children: [ - cardTypeMenu, cardActionMenu + cardTypeMenu, cardActionMenu, ] ) } @@ -332,37 +335,38 @@ extension DashboardViewController { } var contextMenuActions: [UIAction] = [ - fullImageViewAction, - historyViewAction, - settingsAction, - changeBackgroundAction, - renameAction + fullImageViewAction, + historyViewAction, + settingsAction, + changeBackgroundAction, + renameAction, ] let viewModel = viewModels[index] if let canShare = viewModel.canShareTag.value, - canShare { - contextMenuActions.append(shareSensorAction) + canShare + { + contextMenuActions.append(shareSensorAction) } return UIMenu(title: "", children: contextMenuActions) } } -extension DashboardViewController { - fileprivate func setUpUI() { +private extension DashboardViewController { + func setUpUI() { updateNavBarTitleFont() setUpBaseView() setUpHeaderView() setUpContentView() } - fileprivate func updateNavBarTitleFont() { + func updateNavBarTitleFont() { navigationController?.navigationBar.titleTextAttributes = [NSAttributedString.Key.font: UIFont.Muli(.bold, size: 18)] } - fileprivate func setUpBaseView() { + func setUpBaseView() { view.backgroundColor = RuuviColor.dashboardBGColor view.addSubview(noSensorView) @@ -377,8 +381,7 @@ extension DashboardViewController { noSensorView.isHidden = true } - fileprivate func setUpHeaderView() { - + func setUpHeaderView() { let leftBarButtonView = UIView(color: .clear) leftBarButtonView.addSubview(menuButton) @@ -412,8 +415,7 @@ extension DashboardViewController { navigationItem.rightBarButtonItem = UIBarButtonItem(customView: rightBarButtonView) } - fileprivate func setUpContentView() { - + func setUpContentView() { view.addSubview(collectionView) collectionView.anchor(top: view.safeTopAnchor, leading: view.safeLeftAnchor, @@ -430,7 +432,7 @@ extension DashboardViewController { } // swiftlint:disable:next function_body_length - fileprivate func createLayout() -> UICollectionViewLayout { + func createLayout() -> UICollectionViewLayout { var itemEstimatedHeight: CGFloat = 144 switch dashboardType { case .image: @@ -443,7 +445,7 @@ extension DashboardViewController { let sectionProvider = { (_: Int, _: NSCollectionLayoutEnvironment) - -> NSCollectionLayoutSection? in + -> NSCollectionLayoutSection? in let widthMultiplier = GlobalHelpers.isDeviceTablet() ? (!GlobalHelpers.isDeviceLandscape() ? 0.5 : 0.3333) : (GlobalHelpers.isDeviceLandscape() ? 0.5 : 1.0) @@ -494,20 +496,23 @@ extension DashboardViewController { .default .addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, - queue: .main) { [weak self] _ in - self?.reloadCollectionView() + queue: .main) + { [weak self] _ in + self?.reloadCollectionView() } } } extension DashboardViewController: UICollectionViewDataSource { - func collectionView(_ collectionView: UICollectionView, - numberOfItemsInSection section: Int) -> Int { - return viewModels.count + func collectionView(_: UICollectionView, + numberOfItemsInSection _: Int) -> Int + { + viewModels.count } func collectionView(_ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + cellForItemAt indexPath: IndexPath) -> UICollectionViewCell + { guard let cell = cell( collectionView: collectionView, indexPath: indexPath, @@ -520,43 +525,46 @@ extension DashboardViewController: UICollectionViewDataSource { } extension DashboardViewController: UICollectionViewDelegate { - func collectionView(_ collectionView: UICollectionView, + func collectionView(_: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, - point: CGPoint) -> UIContextMenuConfiguration? { + point _: CGPoint) -> UIContextMenuConfiguration? + { configureContextMenu(index: indexPath.row) } func configureContextMenu(index: Int) -> UIContextMenuConfiguration { let context = UIContextMenuConfiguration(identifier: nil, - previewProvider: nil) { [weak self] - (_) -> UIMenu? in - self?.highlightedViewModel = self?.viewModels[index] - return self?.cardContextMenuOption(for: index) + previewProvider: nil) + { [weak self] + _ -> UIMenu? in + self?.highlightedViewModel = self?.viewModels[index] + return self?.cardContextMenuOption(for: index) } return context } - func collectionView(_ collectionView: UICollectionView, - willEndContextMenuInteraction - configuration: UIContextMenuConfiguration, - animator: UIContextMenuInteractionAnimating? - ) { + func collectionView(_: UICollectionView, + willEndContextMenuInteraction _: UIContextMenuConfiguration, + + animator _: UIContextMenuInteractionAnimating?) + { highlightedViewModel = nil } - func collectionView(_ collectionView: UICollectionView, - didSelectItemAt indexPath: IndexPath) { + func collectionView(_: UICollectionView, + didSelectItemAt indexPath: IndexPath) + { let viewModel = viewModels[indexPath.item] output.viewDidTriggerDashboardCard(for: viewModel) } func collectionView( - _ collectionView: UICollectionView, + _: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath ) { guard viewModels.count > 0, - indexPath.item < viewModels.count else { return } + indexPath.item < viewModels.count else { return } let viewModel = viewModels[indexPath.item] if let cell = cell as? DashboardImageCell { cell.restartAlertAnimation(for: viewModel) @@ -576,19 +584,20 @@ extension DashboardViewController: UICollectionViewDelegate { } } - func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { + func scrollViewDidEndScrollingAnimation(_: UIScrollView) { NSObject.cancelPreviousPerformRequests(withTarget: self) isListRefreshable = true } } // MARK: - DashboardViewInput -extension DashboardViewController: DashboardViewInput { +extension DashboardViewController: DashboardViewInput { func applyUpdate(to viewModel: CardsViewModel) { - if let highlightedViewModel = highlightedViewModel, - (highlightedViewModel.luid.value != nil && highlightedViewModel.luid.value == viewModel.luid.value || - highlightedViewModel.mac.value != nil && highlightedViewModel.mac.value == viewModel.mac.value) { + if let highlightedViewModel, + highlightedViewModel.luid.value != nil && highlightedViewModel.luid.value == viewModel.luid.value || + highlightedViewModel.mac.value != nil && highlightedViewModel.mac.value == viewModel.mac.value + { return } @@ -598,17 +607,19 @@ extension DashboardViewController: DashboardViewInput { if let index = viewModels.firstIndex(where: { vm in vm.luid.value != nil && vm.luid.value == viewModel.luid.value || - vm.mac.value != nil && vm.mac.value == viewModel.mac.value + vm.mac.value != nil && vm.mac.value == viewModel.mac.value }) { let indexPath = IndexPath(item: index, section: 0) if let cell = collectionView - .cellForItem(at: indexPath) as? DashboardImageCell { + .cellForItem(at: indexPath) as? DashboardImageCell + { cell.configure( with: viewModel, measurementService: measurementService ) cell.restartAlertAnimation(for: viewModel) } else if let cell = collectionView - .cellForItem(at: indexPath) as? DashboardPlainCell { + .cellForItem(at: indexPath) as? DashboardPlainCell + { cell.configure( with: viewModel, measurementService: measurementService ) @@ -627,13 +638,14 @@ extension DashboardViewController: DashboardViewInput { let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) alertVC.addAction(UIAlertAction(title: RuuviLocalization.PermissionPresenter.settings, style: .default, handler: { _ in - guard let url = URL(string: userDeclined ? - UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), - UIApplication.shared.canOpenURL(url) else { - return - } - UIApplication.shared.open(url) - })) + guard let url = URL(string: userDeclined ? + UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), + UIApplication.shared.canOpenURL(url) + else { + return + } + UIApplication.shared.open(url) + })) alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) } @@ -695,18 +707,18 @@ extension DashboardViewController: DashboardViewInput { message: RuuviLocalization.TagSettings.TagNameTitleLabel.Rename.text, preferredStyle: .alert) alert.addTextField { [weak self] alertTextField in - guard let self = self else { return } + guard let self else { return } alertTextField.delegate = self alertTextField.text = (defaultName == viewModel.name.value) ? nil : viewModel.name.value alertTextField.placeholder = defaultName - self.tagNameTextField = alertTextField + tagNameTextField = alertTextField } let action = UIAlertAction(title: RuuviLocalization.ok, style: .default) { [weak self] _ in - guard let self = self else { return } - if let name = self.tagNameTextField.text, !name.isEmpty { - self.output.viewDidRenameTag(to: name, viewModel: viewModel) + guard let self else { return } + if let name = tagNameTextField.text, !name.isEmpty { + output.viewDidRenameTag(to: name, viewModel: viewModel) } else { - self.output.viewDidRenameTag(to: defaultName, viewModel: viewModel) + output.viewDidRenameTag(to: defaultName, viewModel: viewModel) } } let cancelAction = UIAlertAction(title: RuuviLocalization.cancel, style: .cancel) @@ -732,31 +744,33 @@ extension DashboardViewController: DashboardCellDelegate { } extension DashboardViewController: NoSensorViewDelegate { - func didTapSignInButton(sender: NoSensorView) { + func didTapSignInButton(sender _: NoSensorView) { output.viewDidTriggerSignIn() } - func didTapAddSensorButton(sender: NoSensorView) { + func didTapAddSensorButton(sender _: NoSensorView) { output.viewDidTriggerAddSensors() } - func didTapBuySensorButton(sender: NoSensorView) { + func didTapBuySensorButton(sender _: NoSensorView) { output.viewDidTriggerBuySensors() } } -extension DashboardViewController { - fileprivate func updateUI() { +private extension DashboardViewController { + func updateUI() { showNoSensorsAddedMessage(show: viewModels.isEmpty) collectionView.reloadWithoutAnimation() } } - // MARK: - UITextFieldDelegate +// MARK: - UITextFieldDelegate + extension DashboardViewController: UITextFieldDelegate { - func textField(_ textField: UITextField, shouldChangeCharactersIn - range: NSRange, - replacementString string: String) -> Bool { + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, + + replacementString string: String) -> Bool + { guard let text = textField.text else { return true } diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift index e622a2939..aa33aa7a3 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift @@ -1,5 +1,5 @@ -import Foundation import BTKit +import Foundation import RuuviOntology protocol DashboardViewInput: ViewInput { diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift index 63bd821e6..5b40c6653 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift @@ -2,7 +2,6 @@ import RuuviLocalization import UIKit class BatteryLevelView: UIView { - private lazy var batteryLevelLabel: UILabel = { let label = UILabel() label.textColor = RuuviColor @@ -35,7 +34,8 @@ class BatteryLevelView: UIView { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -43,7 +43,7 @@ class BatteryLevelView: UIView { clipsToBounds = true let stack = UIStackView(arrangedSubviews: [ - batteryLevelLabel, batteryLevelIcon + batteryLevelLabel, batteryLevelIcon, ]) stack.spacing = 4 stack.axis = .horizontal diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift index 7be2a5595..d9279393c 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviLocalization +import UIKit protocol NoSensorViewDelegate: NSObjectProtocol { func didTapSignInButton(sender: NoSensorView) @@ -8,13 +8,13 @@ protocol NoSensorViewDelegate: NSObjectProtocol { } class NoSensorView: UIView { - override init(frame: CGRect) { super.init(frame: frame) setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -101,11 +101,11 @@ extension NoSensorView { } // MARK: - Public + extension NoSensorView { func updateView(userSignInOnce: Bool) { - if centerButtonStackView.subviews.count > 0 { - centerButtonStackView.subviews.forEach({ $0.removeFromSuperview() }) + centerButtonStackView.subviews.forEach { $0.removeFromSuperview() } } let buttons = userSignInOnce ? [signInButton, addSensorButton] : [addSensorButton] @@ -113,8 +113,8 @@ extension NoSensorView { centerButtonStackView.addArrangedSubview(button) } messageLabel.text = userSignInOnce ? - RuuviLocalization.dashboardNoSensorsMessageSignedOut : - RuuviLocalization.dashboardNoSensorsMessage + RuuviLocalization.dashboardNoSensorsMessageSignedOut : + RuuviLocalization.dashboardNoSensorsMessage centerButtonCenterYAnchor.isActive = userSignInOnce ? activateCenterButtonStackConstraint() : true } @@ -145,8 +145,8 @@ extension NoSensorView { container .widthAnchor .constraint( - equalTo: self.widthAnchor - ).isActive = true + equalTo: widthAnchor + ).isActive = true container.addSubview(messageLabel) messageLabel.anchor(top: nil, @@ -168,10 +168,10 @@ extension NoSensorView { addSensorButton.constrainHeight(constant: UIDevice.isiPhoneSE() ? 40 : 50) if UIDevice.isiPhoneSE() { centerButtonStackView.anchor(top: nil, - leading: container.leadingAnchor, - bottom: nil, - trailing: container.trailingAnchor, - padding: .init(top: 0, left: 8, bottom: 0, right: 8)) + leading: container.leadingAnchor, + bottom: nil, + trailing: container.trailingAnchor, + padding: .init(top: 0, left: 8, bottom: 0, right: 8)) } else { centerButtonStackView.widthAnchor.constraint( greaterThanOrEqualToConstant: 300 @@ -187,7 +187,7 @@ extension NoSensorView { centerButtonCenterYAnchor = centerButtonStackView .centerYAnchor .constraint( - equalTo: self.centerYAnchor + equalTo: centerYAnchor ) centerButtonCenterYAnchor.priority = .defaultLow centerButtonCenterYAnchor.isActive = activateCenterButtonStackConstraint() diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviContextMenuButton.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviContextMenuButton.swift index d0d72f4b5..4ee7c4665 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviContextMenuButton.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviContextMenuButton.swift @@ -1,7 +1,6 @@ import UIKit class RuuviContextMenuButton: UIView { - lazy var button: UIButton = { let button = UIButton() button.backgroundColor = .clear @@ -30,7 +29,8 @@ class RuuviContextMenuButton: UIView { super.init(frame: frame) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -41,33 +41,34 @@ class RuuviContextMenuButton: UIView { iconTintColor: UIColor?, iconSize: CGSize = .init(width: 16, height: 16), interimSpacing: CGFloat = 6.0, - preccedingIcon: Bool = false) { + preccedingIcon: Bool = false) + { self.init() self.preccedingIcon = preccedingIcon - self.button.menu = menu - self.buttonTitleLabel.text = title - self.buttonTitleLabel.textColor = titleColor - self.buttonIconView.tintColor = iconTintColor - self.buttonIconView.image = icon + button.menu = menu + buttonTitleLabel.text = title + buttonTitleLabel.textColor = titleColor + buttonIconView.tintColor = iconTintColor + buttonIconView.image = icon self.iconSize = iconSize self.interimSpacing = interimSpacing - self.setUpUI() + setUpUI() } } -extension RuuviContextMenuButton { - fileprivate func setUpUI() { +private extension RuuviContextMenuButton { + func setUpUI() { var stackView = UIStackView() if preccedingIcon { buttonTitleLabel.textAlignment = .left stackView = UIStackView(arrangedSubviews: [ - buttonIconView, buttonTitleLabel + buttonIconView, buttonTitleLabel, ]) } else { buttonTitleLabel.textAlignment = .right stackView = UIStackView(arrangedSubviews: [ - buttonTitleLabel, buttonIconView + buttonTitleLabel, buttonIconView, ]) } buttonIconView.heightAnchor.constraint( @@ -89,10 +90,10 @@ extension RuuviContextMenuButton { extension RuuviContextMenuButton { func updateMenu(with menu: UIMenu?) { - self.button.menu = menu + button.menu = menu } func updateTitle(with string: String?) { - self.buttonTitleLabel.text = string + buttonTitleLabel.text = string } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviSimpleViewCompositionalLayout.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviSimpleViewCompositionalLayout.swift index b088f4249..7623a81e5 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviSimpleViewCompositionalLayout.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviSimpleViewCompositionalLayout.swift @@ -10,7 +10,8 @@ class RuuviSimpleViewCompositionalLayout: UICollectionViewCompositionalLayout { super.init(section: section) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -18,7 +19,7 @@ class RuuviSimpleViewCompositionalLayout: UICollectionViewCompositionalLayout { let attributes = super.layoutAttributesForElements(in: rect) if #unavailable(iOS 15) { - if let attributes = attributes { + if let attributes { for attribute in attributes { updateLayoutAttributesHeight(layoutAttributes: attribute) } diff --git a/station/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableConfigurator.swift b/station/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableConfigurator.swift index 339570258..6a958add8 100644 --- a/station/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableConfigurator.swift +++ b/station/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableConfigurator.swift @@ -1,8 +1,8 @@ import Foundation -import RuuviService import RuuviLocal -import RuuviUser import RuuviPresenters +import RuuviService +import RuuviUser class MenuTableConfigurator { func configure(view: MenuTableViewController) { diff --git a/station/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableInitializer.swift b/station/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableInitializer.swift index 20012679c..280e52533 100644 --- a/station/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableInitializer.swift +++ b/station/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableInitializer.swift @@ -1,7 +1,7 @@ import UIKit class MenuTableInitializer: NSObject { - @IBOutlet weak var viewController: MenuTableViewController! + @IBOutlet var viewController: MenuTableViewController! override func awakeFromNib() { super.awakeFromNib() diff --git a/station/Classes/Presentation/Modules/Menu/Presenter/MenuPresenter.swift b/station/Classes/Presentation/Modules/Menu/Presenter/MenuPresenter.swift index 412845543..139bacdf3 100644 --- a/station/Classes/Presentation/Modules/Menu/Presenter/MenuPresenter.swift +++ b/station/Classes/Presentation/Modules/Menu/Presenter/MenuPresenter.swift @@ -1,10 +1,10 @@ -import UIKit -import RuuviService import RuuviLocal -import RuuviUser import RuuviPresenters +import RuuviService +import RuuviUser +import UIKit #if canImport(WidgetKit) -import WidgetKit + import WidgetKit #endif class MenuPresenter: MenuModuleInput { @@ -30,15 +30,14 @@ class MenuPresenter: MenuModuleInput { } extension MenuPresenter: MenuViewOutput { - func viewWillAppear() {} var userIsAuthorized: Bool { - return ruuviUser.isAuthorized + ruuviUser.isAuthorized } var userEmail: String? { - return ruuviUser.email + ruuviUser.email } func viewDidTapOnDimmingView() { diff --git a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableDismissTransitionAnimation.swift b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableDismissTransitionAnimation.swift index e69d3ed38..4a8bc2b05 100644 --- a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableDismissTransitionAnimation.swift +++ b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableDismissTransitionAnimation.swift @@ -1,14 +1,13 @@ import UIKit class MenuTableDismissTransitionAnimation: UIPercentDrivenInteractiveTransition, UIViewControllerAnimatedTransitioning { - var manager: MenuTableTransitionManager init(manager: MenuTableTransitionManager) { self.manager = manager } - @objc internal func handleHideMenuPan(_ pan: UIPanGestureRecognizer) { + @objc func handleHideMenuPan(_ pan: UIPanGestureRecognizer) { let translation = pan.translation(in: pan.view!) let direction: CGFloat = manager.presentDirection == .left ? -1 : 1 let distance = translation.x / MenuTableTransitionManager.appScreenRect.width * direction @@ -33,8 +32,8 @@ class MenuTableDismissTransitionAnimation: UIPercentDrivenInteractiveTransition, } } - func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { - return 0.35 + func transitionDuration(using _: UIViewControllerContextTransitioning?) -> TimeInterval { + 0.35 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { @@ -56,12 +55,12 @@ class MenuTableDismissTransitionAnimation: UIPercentDrivenInteractiveTransition, initialSpringVelocity: 1, options: .curveEaseInOut, animations: { - fromView.frame = finalFrame - }, completion: { _ -> Void in - if !transitionContext.transitionWasCancelled { - fromView.removeFromSuperview() - } - transitionContext.completeTransition(!transitionContext.transitionWasCancelled) - }) + fromView.frame = finalFrame + }, completion: { _ in + if !transitionContext.transitionWasCancelled { + fromView.removeFromSuperview() + } + transitionContext.completeTransition(!transitionContext.transitionWasCancelled) + }) } } diff --git a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentTransitionAnimation.swift b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentTransitionAnimation.swift index 2730bbba1..b0e982671 100644 --- a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentTransitionAnimation.swift +++ b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentTransitionAnimation.swift @@ -1,20 +1,19 @@ import UIKit class MenuTablePresentTransitionAnimation: UIPercentDrivenInteractiveTransition, UIViewControllerAnimatedTransitioning { - var manager: MenuTableTransitionManager init(manager: MenuTableTransitionManager) { self.manager = manager } - @objc internal func handlePresentMenuLeftScreenEdge(_ edge: UIScreenEdgePanGestureRecognizer) { + @objc func handlePresentMenuLeftScreenEdge(_ edge: UIScreenEdgePanGestureRecognizer) { manager.presentDirection = .left handlePresentMenuPan(edge) } - func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { - return 0.35 + func transitionDuration(using _: UIViewControllerContextTransitioning?) -> TimeInterval { + 0.35 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { @@ -39,10 +38,10 @@ class MenuTablePresentTransitionAnimation: UIPercentDrivenInteractiveTransition, initialSpringVelocity: 1, options: .curveEaseInOut, animations: { - toView.frame = finalFrame - }, completion: { _ -> Void in - transitionContext.completeTransition(!transitionContext.transitionWasCancelled) - }) + toView.frame = finalFrame + }, completion: { _ in + transitionContext.completeTransition(!transitionContext.transitionWasCancelled) + }) } func handlePresentMenuPan(_ pan: UIPanGestureRecognizer) { diff --git a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentationController.swift b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentationController.swift index 5c36878a9..baec4aac7 100644 --- a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentationController.swift +++ b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentationController.swift @@ -1,7 +1,6 @@ import UIKit class MenuTablePresentationController: UIPresentationController { - var menuWidth: CGFloat = 0 var dismissTransition: MenuTableDismissTransitionAnimation! @@ -44,16 +43,17 @@ class MenuTablePresentationController: UIPresentationController { }() override var shouldPresentInFullscreen: Bool { - return true + true } override var adaptivePresentationStyle: UIModalPresentationStyle { - return .overFullScreen + .overFullScreen } - override func size(forChildContentContainer container: UIContentContainer, - withParentContainerSize parentSize: CGSize) -> CGSize { - return CGSize(width: menuWidth, height: parentSize.height) + override func size(forChildContentContainer _: UIContentContainer, + withParentContainerSize parentSize: CGSize) -> CGSize + { + CGSize(width: menuWidth, height: parentSize.height) } override var frameOfPresentedViewInContainerView: CGRect { @@ -70,7 +70,7 @@ class MenuTablePresentationController: UIPresentationController { } override func presentationTransitionWillBegin() { - if let containerView = containerView { + if let containerView { dimmingView.bounds = containerView.bounds dimmingView.alpha = 0 @@ -86,7 +86,7 @@ class MenuTablePresentationController: UIPresentationController { self.dimmingView.alpha = 1.0 }, completion: nil) } else { - self.dimmingView.alpha = 1.0 + dimmingView.alpha = 1.0 } } @@ -97,7 +97,7 @@ class MenuTablePresentationController: UIPresentationController { self.shadowView.frame = self.presentedView?.frame ?? .zero }, completion: nil) } else { - self.dimmingView.alpha = 0 + dimmingView.alpha = 0 } } @@ -108,9 +108,10 @@ class MenuTablePresentationController: UIPresentationController { presentedView?.frame = frameOfPresentedViewInContainerView } - @objc func dimmingViewTapped(_ tap: UITapGestureRecognizer) { - if let navigationController = self.presentedViewController as? UINavigationController, - let menuTable = navigationController.topViewController as? MenuTableViewController { + @objc func dimmingViewTapped(_: UITapGestureRecognizer) { + if let navigationController = presentedViewController as? UINavigationController, + let menuTable = navigationController.topViewController as? MenuTableViewController + { menuTable.output.viewDidTapOnDimmingView() } } diff --git a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitionManager.swift b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitionManager.swift index f03f61798..ffb077290 100644 --- a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitionManager.swift +++ b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitionManager.swift @@ -1,8 +1,7 @@ import UIKit class MenuTableTransitionManager: NSObject { - - var menuWidth: CGFloat = min(round(min((appScreenRect.width), (appScreenRect.height)) * 0.75), 260) + var menuWidth: CGFloat = min(round(min(appScreenRect.width, appScreenRect.height) * 0.75), 260) var container: UIViewController var menu: UIViewController var isInteractive: Bool = false @@ -17,5 +16,4 @@ class MenuTableTransitionManager: NSObject { self.container = container self.menu = menu } - } diff --git a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitioningDelegate.swift b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitioningDelegate.swift index 0d2346146..0d9dc21aa 100644 --- a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitioningDelegate.swift +++ b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitioningDelegate.swift @@ -1,15 +1,11 @@ import UIKit class MenuTableTransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate { - var manager: MenuTableTransitionManager - lazy var present: MenuTablePresentTransitionAnimation = { - return MenuTablePresentTransitionAnimation(manager: manager) - }() - lazy var dismiss: MenuTableDismissTransitionAnimation = { - return MenuTableDismissTransitionAnimation(manager: manager) - }() + lazy var present: MenuTablePresentTransitionAnimation = .init(manager: manager) + + lazy var dismiss: MenuTableDismissTransitionAnimation = .init(manager: manager) init(manager: MenuTableTransitionManager) { self.manager = manager @@ -17,31 +13,34 @@ class MenuTableTransitioningDelegate: NSObject, UIViewControllerTransitioningDel func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, - source: UIViewController) -> UIPresentationController? { + source _: UIViewController) -> UIPresentationController? + { let controller = MenuTablePresentationController(presentedViewController: presented, presenting: presenting) controller.menuWidth = manager.menuWidth controller.dismissTransition = dismiss return controller } - func animationController(forPresented presented: UIViewController, - presenting: UIViewController, - source: UIViewController) -> UIViewControllerAnimatedTransitioning? { - return present + func animationController(forPresented _: UIViewController, + presenting _: UIViewController, + source _: UIViewController) -> UIViewControllerAnimatedTransitioning? + { + present } - func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { - return dismiss + func animationController(forDismissed _: UIViewController) -> UIViewControllerAnimatedTransitioning? { + dismiss } - func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) - -> UIViewControllerInteractiveTransitioning? { - return manager.isInteractive ? present : nil + func interactionControllerForPresentation(using _: UIViewControllerAnimatedTransitioning) + -> UIViewControllerInteractiveTransitioning? + { + manager.isInteractive ? present : nil } - func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) - -> UIViewControllerInteractiveTransitioning? { - return manager.isInteractive ? dismiss : nil + func interactionControllerForDismissal(using _: UIViewControllerAnimatedTransitioning) + -> UIViewControllerInteractiveTransitioning? + { + manager.isInteractive ? dismiss : nil } - } diff --git a/station/Classes/Presentation/Modules/Menu/View/MenuViewInput.swift b/station/Classes/Presentation/Modules/Menu/View/MenuViewInput.swift index b518cad83..df6247600 100644 --- a/station/Classes/Presentation/Modules/Menu/View/MenuViewInput.swift +++ b/station/Classes/Presentation/Modules/Menu/View/MenuViewInput.swift @@ -1,5 +1,3 @@ import Foundation -protocol MenuViewInput: ViewInput { - -} +protocol MenuViewInput: ViewInput {} diff --git a/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift b/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift index 48241f44e..30c7d8c82 100644 --- a/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift +++ b/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift @@ -4,23 +4,24 @@ import UIKit class MenuTableEmbededViewController: UITableViewController, MenuViewInput { var output: MenuViewOutput! - @IBOutlet weak var feedbackCell: UITableViewCell! - @IBOutlet weak var addRuuviTagCell: UITableViewCell! - @IBOutlet weak var aboutCell: UITableViewCell! - @IBOutlet weak var whatToMeasureCell: UITableViewCell! - @IBOutlet weak var getMoreSensorsCell: UITableViewCell! - @IBOutlet weak var settingsCell: UITableViewCell! - @IBOutlet weak var accountCell: UITableViewCell! - @IBOutlet weak var feedbackLabel: UILabel! - @IBOutlet weak var addANewSensorLabel: UILabel! - @IBOutlet weak var appSettingsLabel: UILabel! - @IBOutlet weak var aboutHelpLabel: UILabel! - @IBOutlet weak var whatToMeasureLabel: UILabel! - @IBOutlet weak var getMoreSensorsLabel: UILabel! - @IBOutlet weak var accountAuthLabel: UILabel! + @IBOutlet var feedbackCell: UITableViewCell! + @IBOutlet var addRuuviTagCell: UITableViewCell! + @IBOutlet var aboutCell: UITableViewCell! + @IBOutlet var whatToMeasureCell: UITableViewCell! + @IBOutlet var getMoreSensorsCell: UITableViewCell! + @IBOutlet var settingsCell: UITableViewCell! + @IBOutlet var accountCell: UITableViewCell! + @IBOutlet var feedbackLabel: UILabel! + @IBOutlet var addANewSensorLabel: UILabel! + @IBOutlet var appSettingsLabel: UILabel! + @IBOutlet var aboutHelpLabel: UILabel! + @IBOutlet var whatToMeasureLabel: UILabel! + @IBOutlet var getMoreSensorsLabel: UILabel! + @IBOutlet var accountAuthLabel: UILabel! } // MARK: - MenuViewInput + extension MenuTableEmbededViewController { func localize() { addANewSensorLabel.text = RuuviLocalization.Menu.Label.AddAnNewSensor.text @@ -33,6 +34,7 @@ extension MenuTableEmbededViewController { } // MARK: - View lifecycle + extension MenuTableEmbededViewController { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) @@ -41,20 +43,23 @@ extension MenuTableEmbededViewController { } // MARK: - UITableViewDelegate + extension MenuTableEmbededViewController { override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return super.tableView(tableView, numberOfRowsInSection: section) + super.tableView(tableView, numberOfRowsInSection: section) } - override func tableView(_ tableView: UITableView, + override func tableView(_: UITableView, willDisplay cell: UITableViewCell, - forRowAt indexPath: IndexPath) { + forRowAt _: IndexPath) + { if cell == accountCell { accountAuthLabel.text = output.userIsAuthorized - ? RuuviLocalization.Menu.Label.MyRuuviAccount.text - : RuuviLocalization.SignIn.Title.text + ? RuuviLocalization.Menu.Label.MyRuuviAccount.text + : RuuviLocalization.SignIn.Title.text } } + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: false) if let cell = tableView.cellForRow(at: indexPath) { diff --git a/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift b/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift index 4631fa8ae..2aee201d7 100644 --- a/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift +++ b/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift @@ -7,8 +7,7 @@ class MenuTableViewController: UIViewController { } extension MenuTableViewController: MenuViewInput { - func localize() { - } + func localize() {} } extension MenuTableViewController { diff --git a/station/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountConfigurator.swift b/station/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountConfigurator.swift index e6b9873fa..d99b9e87d 100644 --- a/station/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountConfigurator.swift +++ b/station/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountConfigurator.swift @@ -1,10 +1,10 @@ import Foundation -import RuuviUser -import RuuviService -import RuuviPresenters import RuuviCloud import RuuviCore import RuuviLocal +import RuuviPresenters +import RuuviService +import RuuviUser class MyRuuviAccountConfigurator { func configure(view: MyRuuviAccountViewController) { diff --git a/station/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountInitializer.swift b/station/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountInitializer.swift index 267338acb..bf0e2c83a 100644 --- a/station/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountInitializer.swift +++ b/station/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountInitializer.swift @@ -1,7 +1,7 @@ import UIKit class MyRuuviAccountInitializer: NSObject { - @IBOutlet weak var viewController: MyRuuviAccountViewController! + @IBOutlet var viewController: MyRuuviAccountViewController! override func awakeFromNib() { super.awakeFromNib() diff --git a/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift b/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift index a22c4957f..d7107dad3 100644 --- a/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift +++ b/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift @@ -1,16 +1,16 @@ import Foundation -import RuuviUser -import RuuviService -import RuuviPresenters +import Future import RuuviCloud import RuuviCore -import Future import RuuviLocal import RuuviLocalization +import RuuviPresenters +import RuuviService +import RuuviUser import UIKit #if canImport(WidgetKit) -import WidgetKit + import WidgetKit #endif final class MyRuuviAccountPresenter: MyRuuviAccountModuleInput { @@ -28,6 +28,7 @@ final class MyRuuviAccountPresenter: MyRuuviAccountModuleInput { } // MARK: - MyRuuviAccountViewOutput + extension MyRuuviAccountPresenter: MyRuuviAccountViewOutput { func viewDidLoad() { syncViewModel() @@ -58,6 +59,7 @@ extension MyRuuviAccountPresenter: MyRuuviAccountViewOutput { } // MARK: - Private + extension MyRuuviAccountPresenter { private func syncViewModel() { let viewModel = MyRuuviAccountViewModel() @@ -69,14 +71,14 @@ extension MyRuuviAccountPresenter { } extension MyRuuviAccountPresenter { - private func createSignOutAlert() { let title = RuuviLocalization.Menu.SignOut.text let message = RuuviLocalization.TagsManagerPresenter.SignOutConfirmAlert.message let confirmActionTitle = RuuviLocalization.ok let cancelActionTitle = RuuviLocalization.cancel let confirmAction = UIAlertAction(title: confirmActionTitle, - style: .default) { [weak self] (_) in + style: .default) + { [weak self] _ in guard let sSelf = self else { return } sSelf.activityPresenter.show(with: .loading(message: nil)) sSelf.cloudNotificationService.unregister( @@ -101,7 +103,7 @@ extension MyRuuviAccountPresenter { let cancleAction = UIAlertAction(title: cancelActionTitle, style: .cancel, handler: nil) - let actions = [ confirmAction, cancleAction ] + let actions = [confirmAction, cancleAction] let alertViewModel = AlertViewModel(title: title, message: message, style: .alert, diff --git a/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift b/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift index de118c87f..fa5bc235b 100644 --- a/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift +++ b/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift @@ -1,15 +1,15 @@ import Foundation -import UIKit import RuuviLocalization +import UIKit class MyRuuviAccountViewController: UIViewController { var output: MyRuuviAccountViewOutput! - @IBOutlet weak var headerTitleLabel: UILabel! - @IBOutlet weak var loggedInLabel: UILabel! - @IBOutlet weak var usernameLabel: UILabel! - @IBOutlet weak var signoutButton: UIButton! - @IBOutlet weak var deleteAccountButton: UIButton! + @IBOutlet var headerTitleLabel: UILabel! + @IBOutlet var loggedInLabel: UILabel! + @IBOutlet var usernameLabel: UILabel! + @IBOutlet var signoutButton: UIButton! + @IBOutlet var deleteAccountButton: UIButton! var viewModel: MyRuuviAccountViewModel? { didSet { @@ -24,15 +24,16 @@ class MyRuuviAccountViewController: UIViewController { } // MARK: - Button actions - @IBAction func backButtonTouchUpInside(_ sender: Any) { + + @IBAction func backButtonTouchUpInside(_: Any) { output.viewDidTriggerClose() } - @IBAction func deleteButtonTouchUpInside(_ sender: Any) { + @IBAction func deleteButtonTouchUpInside(_: Any) { output.viewDidTapDeleteButton() } - @IBAction func signoutButtonTouchUpInside(_ sender: Any) { + @IBAction func signoutButtonTouchUpInside(_: Any) { output.viewDidTapSignoutButton() } } @@ -50,7 +51,7 @@ extension MyRuuviAccountViewController: MyRuuviAccountViewInput { extension MyRuuviAccountViewController { private func bindViewModel() { - guard let viewModel = viewModel, isViewLoaded else { + guard let viewModel, isViewLoaded else { return } usernameLabel.bind(viewModel.username) { label, username in diff --git a/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewInput.swift b/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewInput.swift index 8a5705d72..a55e4f7a9 100644 --- a/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewInput.swift +++ b/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewInput.swift @@ -1,4 +1,4 @@ protocol MyRuuviAccountViewInput: ViewInput { - var viewModel: MyRuuviAccountViewModel? { get set } + var viewModel: MyRuuviAccountViewModel? { get set } func viewDidShowAccountDeletionConfirmation() } diff --git a/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewModel.swift b/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewModel.swift index 7f67a1d11..f05105d11 100644 --- a/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewModel.swift +++ b/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewModel.swift @@ -1,5 +1,5 @@ import Foundation struct MyRuuviAccountViewModel { - let username: Observable = Observable() + let username: Observable = .init() } diff --git a/station/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableConfigurator.swift b/station/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableConfigurator.swift index a7aaf04af..3ea9c49f2 100644 --- a/station/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableConfigurator.swift +++ b/station/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableConfigurator.swift @@ -1,11 +1,11 @@ import Foundation import RuuviContext -import RuuviReactor import RuuviLocal -import RuuviService import RuuviPresenters -import RuuviUser +import RuuviReactor +import RuuviService import RuuviStorage +import RuuviUser class SettingsTableConfigurator { func configure(view: SettingsTableViewController) { diff --git a/station/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableInitializer.swift b/station/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableInitializer.swift index 03f816a8b..7aab8aadd 100644 --- a/station/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableInitializer.swift +++ b/station/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableInitializer.swift @@ -1,7 +1,7 @@ import UIKit class SettingsTableInitializer: NSObject { - @IBOutlet weak var viewController: SettingsTableViewController! + @IBOutlet var viewController: SettingsTableViewController! override func awakeFromNib() { super.awakeFromNib() diff --git a/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsModuleInput.swift b/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsModuleInput.swift index a3d9073bd..d7640a1d8 100644 --- a/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsModuleInput.swift +++ b/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsModuleInput.swift @@ -1,5 +1,3 @@ import Foundation -protocol SettingsModuleInput: AnyObject { - -} +protocol SettingsModuleInput: AnyObject {} diff --git a/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift index 7c4e1b7d0..8f8394214 100644 --- a/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift @@ -1,13 +1,13 @@ -import RuuviLocalization import Foundation -import RuuviOntology import RuuviContext -import RuuviReactor import RuuviLocal -import RuuviService +import RuuviLocalization +import RuuviOntology import RuuviPresenters -import RuuviUser +import RuuviReactor +import RuuviService import RuuviStorage +import RuuviUser import UIKit class SettingsPresenter: SettingsModuleInput { @@ -40,14 +40,14 @@ extension SettingsPresenter: SettingsViewOutput { .addObserver(forName: .LanguageDidChange, object: nil, queue: .main, - using: { [weak self] (_) in - self?.view.language = self?.settings.language ?? .english - }) + using: { [weak self] _ in + self?.view.language = self?.settings.language ?? .english + }) view.experimentalFunctionsEnabled = settings.experimentalFeaturesEnabled ruuviStorage.readAll().on(success: { [weak self] tags in guard let sSelf = self else { return } - let cloudTagsCount = tags.filter({ $0.isOwner || $0.isCloud }).count + let cloudTagsCount = tags.filter { $0.isOwner || $0.isCloud }.count let cloudModeVisible = sSelf.ruuviUser.isAuthorized && cloudTagsCount > 0 sSelf.view.cloudModeVisible = cloudModeVisible }) @@ -57,7 +57,7 @@ extension SettingsPresenter: SettingsViewOutput { let selectionItems: [TemperatureUnit] = [ .celsius, .fahrenheit, - .kelvin + .kelvin, ] let viewModel = UnitSettingsViewModel(title: RuuviLocalization.TagSettings.OffsetCorrection.temperature, items: selectionItems, @@ -69,7 +69,7 @@ extension SettingsPresenter: SettingsViewOutput { let selectionItems: [HumidityUnit] = [ .percent, .gm3, - .dew + .dew, ] let viewModel = UnitSettingsViewModel(title: RuuviLocalization.TagSettings.OffsetCorrection.humidity, items: selectionItems, @@ -81,7 +81,7 @@ extension SettingsPresenter: SettingsViewOutput { let selectionItems: [UnitPressure] = [ .hectopascals, .inchesOfMercury, - .millimetersOfMercury + .millimetersOfMercury, ] let viewModel = UnitSettingsViewModel(title: RuuviLocalization.TagSettings.OffsetCorrection.pressure, items: selectionItems, diff --git a/station/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouter.swift b/station/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouter.swift index 0d2f9f941..60e636630 100644 --- a/station/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouter.swift +++ b/station/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouter.swift @@ -15,15 +15,15 @@ class SettingsRouter: SettingsRouterInput { try! transitionHandler .forStoryboard(factory: factory, to: DefaultsModuleInput.self) .to(preferred: .navigation(style: .push)) - .then({ module in + .then { module in module.configure(output: output) - }) + } } func openDevices() { let factory: DevicesModuleFactory = DevicesModuleFactoryImpl() let module = factory.create() - self.devicesModule = module + devicesModule = module transitionHandler .navigationController? .pushViewController( @@ -37,9 +37,9 @@ class SettingsRouter: SettingsRouterInput { try! transitionHandler .forStoryboard(factory: factory, to: HeartbeatModuleInput.self) .to(preferred: .navigation(style: .push)) - .then({ module in + .then { module in module.configure() - }) + } } func openChart() { @@ -47,9 +47,9 @@ class SettingsRouter: SettingsRouterInput { try! transitionHandler .forStoryboard(factory: factory, to: ChartSettingsModuleInput.self) .to(preferred: .navigation(style: .push)) - .then({ module in + .then { module in module.configure() - }) + } } func openFeatureToggles() { @@ -69,15 +69,15 @@ class SettingsRouter: SettingsRouterInput { try! transitionHandler .forStoryboard(factory: factory, to: UnitSettingsModuleInput.self) .to(preferred: .navigation(style: .push)) - .then({ module in + .then { module in module.configure(viewModel: viewModel, output: output) - }) + } } func openRuuviCloud() { let factory: RuuviCloudModuleFactory = RuuviCloudModuleFactoryImpl() let module = factory.create() - self.ruuviCloudModule = module + ruuviCloudModule = module transitionHandler .navigationController? .pushViewController( diff --git a/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift index 998efab4e..bc177e3de 100644 --- a/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift @@ -1,55 +1,55 @@ import RuuviLocalization -import UIKit import RuuviOntology +import UIKit class SettingsTableViewController: UITableViewController { var output: SettingsViewOutput! - @IBOutlet weak var alertNotificationsCell: UITableViewCell! - @IBOutlet weak var alertNotificationsTitleLabel: UILabel! + @IBOutlet var alertNotificationsCell: UITableViewCell! + @IBOutlet var alertNotificationsTitleLabel: UILabel! - @IBOutlet weak var appearanceCell: UITableViewCell! - @IBOutlet weak var appearanceTitleLabel: UILabel! + @IBOutlet var appearanceCell: UITableViewCell! + @IBOutlet var appearanceTitleLabel: UILabel! - @IBOutlet weak var temperatureTitleLabel: UILabel! - @IBOutlet weak var temperatureCell: UITableViewCell! + @IBOutlet var temperatureTitleLabel: UILabel! + @IBOutlet var temperatureCell: UITableViewCell! - @IBOutlet weak var humidityTitleLabel: UILabel! - @IBOutlet weak var humidityCell: UITableViewCell! + @IBOutlet var humidityTitleLabel: UILabel! + @IBOutlet var humidityCell: UITableViewCell! - @IBOutlet weak var pressureTitleLabel: UILabel! - @IBOutlet weak var pressureCell: UITableViewCell! + @IBOutlet var pressureTitleLabel: UILabel! + @IBOutlet var pressureCell: UITableViewCell! - @IBOutlet weak var heartbeatTitleLabel: UILabel! - @IBOutlet weak var heartbeatCell: UITableViewCell! + @IBOutlet var heartbeatTitleLabel: UILabel! + @IBOutlet var heartbeatCell: UITableViewCell! - @IBOutlet weak var defaultsTitleLabel: UILabel! - @IBOutlet weak var defaultsCell: UITableViewCell! + @IBOutlet var defaultsTitleLabel: UILabel! + @IBOutlet var defaultsCell: UITableViewCell! - @IBOutlet weak var devicesTitleLabel: UILabel! - @IBOutlet weak var devicesCell: UITableViewCell! + @IBOutlet var devicesTitleLabel: UILabel! + @IBOutlet var devicesCell: UITableViewCell! - @IBOutlet weak var closeBarButtonItem: UIBarButtonItem! + @IBOutlet var closeBarButtonItem: UIBarButtonItem! - @IBOutlet weak var languageValueLabel: UILabel! - @IBOutlet weak var languageTitleLabel: UILabel! - @IBOutlet weak var languageCell: UITableViewCell! + @IBOutlet var languageValueLabel: UILabel! + @IBOutlet var languageTitleLabel: UILabel! + @IBOutlet var languageCell: UITableViewCell! - @IBOutlet weak var chartCell: UITableViewCell! - @IBOutlet weak var chartTitleLabel: UILabel! + @IBOutlet var chartCell: UITableViewCell! + @IBOutlet var chartTitleLabel: UILabel! - @IBOutlet weak var experimentalFunctionsCell: UITableViewCell! - @IBOutlet weak var experimentalFunctionsLabel: UILabel! + @IBOutlet var experimentalFunctionsCell: UITableViewCell! + @IBOutlet var experimentalFunctionsLabel: UILabel! - @IBOutlet weak var ruuviCloudTitleLabel: UILabel! - @IBOutlet weak var ruuviCloudCell: UITableViewCell! + @IBOutlet var ruuviCloudTitleLabel: UILabel! + @IBOutlet var ruuviCloudCell: UITableViewCell! #if DEVELOPMENT - private let showDefaults = true - private let showDevices = true + private let showDefaults = true + private let showDevices = true #else - private let showDefaults = false - private let showDevices = false + private let showDefaults = false + private let showDevices = false #endif var language: Language = .english { @@ -63,6 +63,7 @@ class SettingsTableViewController: UITableViewController { updateTableIfLoaded() } } + var cloudModeVisible: Bool = false { didSet { updateTableIfLoaded() @@ -71,6 +72,7 @@ class SettingsTableViewController: UITableViewController { } // MARK: - SettingsViewInput + extension SettingsTableViewController: SettingsViewInput { func localize() { navigationItem.title = RuuviLocalization.Settings.NavigationItem.title @@ -104,17 +106,18 @@ extension SettingsTableViewController: SettingsViewInput { } // MARK: - IBActions -extension SettingsTableViewController { - @IBAction func closeBarButtonItemAction(_ sender: Any) { +extension SettingsTableViewController { + @IBAction func closeBarButtonItemAction(_: Any) { output.viewDidTriggerClose() } } // MARK: - View lifecycle + extension SettingsTableViewController { override var canBecomeFirstResponder: Bool { - return true + true } override func viewDidLoad() { @@ -125,14 +128,15 @@ extension SettingsTableViewController { becomeFirstResponder() } - override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) { - if motion == .motionShake && !experimentalFunctionsEnabled { + override func motionEnded(_ motion: UIEvent.EventSubtype, with _: UIEvent?) { + if motion == .motionShake, !experimentalFunctionsEnabled { output.viewDidTriggerShake() } } } // MARK: - UITableViewDelegate + extension SettingsTableViewController { override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { let cell = super.tableView(tableView, cellForRowAt: indexPath) @@ -143,8 +147,9 @@ extension SettingsTableViewController { } // Add the logic for the cloud mode cell here if !showDefaults && cell == defaultsCell || - (!showDevices || !cloudModeVisible) && cell == devicesCell || - !cloudModeVisible && cell == ruuviCloudCell { + (!showDevices || !cloudModeVisible) && cell == devicesCell || + !cloudModeVisible && cell == ruuviCloudCell + { return 0 } else { return super.tableView(tableView, heightForRowAt: indexPath) @@ -153,7 +158,8 @@ extension SettingsTableViewController { // swiftlint:disable:next cyclomatic_complexity override func tableView(_ tableView: UITableView, - didSelectRowAt indexPath: IndexPath) { + didSelectRowAt indexPath: IndexPath) + { guard let cell = tableView.cellForRow(at: indexPath) else { return } switch cell { case temperatureCell: @@ -187,6 +193,7 @@ extension SettingsTableViewController { } // MARK: - Update UI + extension SettingsTableViewController { private func updateUI() { updateUILanguage() diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Assembly/AppearanceSettingsModuleFactory.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Assembly/AppearanceSettingsModuleFactory.swift index 32a24b6c8..8d84cadcb 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Assembly/AppearanceSettingsModuleFactory.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Assembly/AppearanceSettingsModuleFactory.swift @@ -1,6 +1,6 @@ -import UIKit import RuuviLocal import RuuviLocalization +import UIKit protocol AppearanceSettingsModuleFactory { func create() -> AppearanceSettingsTableViewController diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsModuleInput.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsModuleInput.swift index 95dc39503..e06fb88ff 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsModuleInput.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsModuleInput.swift @@ -1,6 +1,4 @@ import Foundation import UIKit -protocol AppearanceSettingsModuleInput: AnyObject { - -} +protocol AppearanceSettingsModuleInput: AnyObject {} diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift index f41b48607..032ec5895 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift @@ -1,8 +1,8 @@ import Foundation -import UIKit -import RuuviOntology import RuuviLocal import RuuviLocalization +import RuuviOntology +import UIKit class AppearanceSettingsPresenter: NSObject, AppearanceSettingsModuleInput { weak var view: AppearanceSettingsViewInput? @@ -29,18 +29,18 @@ extension AppearanceSettingsPresenter: AppearanceSettingsViewOutput { } extension AppearanceSettingsPresenter { - fileprivate func configure() { - if let view = view { + private func configure() { + if let view { view.viewModels = [appThemeSetting()] } } - fileprivate func appThemeSetting() -> AppearanceSettingsViewModel { + private func appThemeSetting() -> AppearanceSettingsViewModel { let title = RuuviLocalization.appTheme let selectionItems: [RuuviTheme] = [ .system, .dark, - .light + .light, ] let selectedTheme: RuuviTheme = settings.theme @@ -59,10 +59,10 @@ extension AppearanceSettingsPresenter { .addObserver(forName: .AppearanceSettingsDidChange, object: nil, queue: .main, - using: { [weak self] (_) in - self?.configure() - self?.updateTheme() - }) + using: { [weak self] _ in + self?.configure() + self?.updateTheme() + }) } private func updateTheme() { @@ -70,9 +70,9 @@ extension AppearanceSettingsPresenter { delay: 0.0, options: .curveLinear, animations: { [weak self] in - guard let sSelf = self else { return } - UIWindow.key?.overrideUserInterfaceStyle = - sSelf.settings.theme.uiInterfaceStyle - }) + guard let sSelf = self else { return } + UIWindow.key?.overrideUserInterfaceStyle = + sSelf.settings.theme.uiInterfaceStyle + }) } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Assembly/ASSelectionModuleFactory.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Assembly/ASSelectionModuleFactory.swift index 195257495..8227591be 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Assembly/ASSelectionModuleFactory.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Assembly/ASSelectionModuleFactory.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviLocal +import UIKit protocol ASSelectionModuleFactory { func create(with title: String) -> ASSelectionTableViewController diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionPresenter.swift index 10f42f764..b3eaca54e 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionPresenter.swift @@ -1,7 +1,7 @@ import Foundation -import UIKit -import RuuviOntology import RuuviLocal +import RuuviOntology +import UIKit class ASSelectionPresenter: NSObject { weak var view: ASSelectionViewInput? @@ -21,7 +21,8 @@ extension ASSelectionPresenter: ASSelectionViewOutput { } func viewDidSelectItem(item: SelectionItemProtocol, - type: AppearanceSettingType) { + type: AppearanceSettingType) + { update(with: item, type: type) } } @@ -34,11 +35,13 @@ extension ASSelectionPresenter: ASSelectionModuleInput { extension ASSelectionPresenter { private func update(with selection: SelectionItemProtocol, - type: AppearanceSettingType) { + type: AppearanceSettingType) + { switch type { case .theme: if let theme = selection as? RuuviTheme, - let viewModel = viewModel { + let viewModel + { settings.theme = theme let updatedViewModel = AppearanceSettingsViewModel( title: viewModel.title, diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift index 0ede1e542..16d687e91 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift @@ -1,7 +1,6 @@ import UIKit class ASSelectionTableViewCell: UITableViewCell { - private lazy var titleLabel: UILabel = { let label = UILabel() label.textColor = RuuviColor.ruuviTextColor @@ -12,13 +11,15 @@ class ASSelectionTableViewCell: UITableViewCell { }() override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) { + reuseIdentifier: String?) + { super.init(style: style, reuseIdentifier: reuseIdentifier) setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift index 2930741cf..d35a67b3a 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift @@ -1,5 +1,5 @@ -import UIKit import Foundation +import UIKit class ASSelectionTableViewController: UITableViewController { var output: ASSelectionViewOutput! @@ -14,7 +14,8 @@ class ASSelectionTableViewController: UITableViewController { self.title = title } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -22,6 +23,7 @@ class ASSelectionTableViewController: UITableViewController { } // MARK: - LIFECYCLE + extension ASSelectionTableViewController { override func viewDidLoad() { super.viewDidLoad() @@ -36,43 +38,44 @@ extension ASSelectionTableViewController: ASSelectionViewInput { } } -extension ASSelectionTableViewController { - fileprivate func setUpUI() { +private extension ASSelectionTableViewController { + func setUpUI() { view.backgroundColor = RuuviColor.ruuviPrimary setUpTableView() } - fileprivate func setUpTableView() { + func setUpTableView() { tableView.sectionFooterHeight = UITableView.automaticDimension tableView.register(ASSelectionTableViewCell.self, forCellReuseIdentifier: reuseIdentifier) } - fileprivate func updateUI() { + func updateUI() { if isViewLoaded { - DispatchQueue.main.async(execute: { [weak self] in + DispatchQueue.main.async { [weak self] in self?.tableView.reloadData() - }) + } } } } // MARK: - UITableViewDataSource -extension ASSelectionTableViewController { - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return viewModel?.items.count ?? 0 +extension ASSelectionTableViewController { + override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { + viewModel?.items.count ?? 0 } override func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { + cellForRowAt indexPath: IndexPath) -> UITableViewCell + { guard let cell = tableView.dequeueReusableCell( withIdentifier: reuseIdentifier, for: indexPath ) as? ASSelectionTableViewCell else { fatalError() } - if let viewModel = viewModel { + if let viewModel { let item = viewModel.items[indexPath.row] cell.configure( title: item.title(""), @@ -84,11 +87,13 @@ extension ASSelectionTableViewController { } // MARK: - UITableViewDelegate + extension ASSelectionTableViewController { override func tableView(_ tableView: UITableView, - didSelectRowAt indexPath: IndexPath) { + didSelectRowAt indexPath: IndexPath) + { tableView.deselectRow(at: indexPath, animated: true) - if let viewModel = viewModel { + if let viewModel { output.viewDidSelectItem(item: viewModel.items[indexPath.row], type: viewModel.type) } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift index 67bac6133..bf8e9d995 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift @@ -1,7 +1,6 @@ import UIKit class AppearanceSettingsTableViewBasicCell: UITableViewCell { - private lazy var titleLabel: UILabel = { let label = UILabel() label.textColor = RuuviColor.ruuviMenuTextColor @@ -21,13 +20,15 @@ class AppearanceSettingsTableViewBasicCell: UITableViewCell { }() override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) { + reuseIdentifier: String?) + { super.init(style: style, reuseIdentifier: reuseIdentifier) setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -36,7 +37,7 @@ class AppearanceSettingsTableViewBasicCell: UITableViewCell { accessoryType = .disclosureIndicator let stack = UIStackView(arrangedSubviews: [ - titleLabel, valueLabel + titleLabel, valueLabel, ]) stack.spacing = 4 stack.distribution = .fillProportionally diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift index 504083e94..c6ebf1253 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift @@ -1,5 +1,5 @@ -import UIKit import Foundation +import UIKit class AppearanceSettingsTableViewController: UITableViewController { var output: AppearanceSettingsViewOutput! @@ -14,7 +14,8 @@ class AppearanceSettingsTableViewController: UITableViewController { self.title = title } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -22,6 +23,7 @@ class AppearanceSettingsTableViewController: UITableViewController { } // MARK: - LIFECYCLE + extension AppearanceSettingsTableViewController { override func viewDidLoad() { super.viewDidLoad() @@ -36,36 +38,37 @@ extension AppearanceSettingsTableViewController: AppearanceSettingsViewInput { } } -extension AppearanceSettingsTableViewController { - fileprivate func setUpUI() { +private extension AppearanceSettingsTableViewController { + func setUpUI() { view.backgroundColor = RuuviColor.ruuviPrimary setUpTableView() } - fileprivate func setUpTableView() { + func setUpTableView() { tableView.sectionFooterHeight = UITableView.automaticDimension tableView.register(AppearanceSettingsTableViewBasicCell.self, forCellReuseIdentifier: reuseIdentifier) } - fileprivate func updateUI() { + func updateUI() { if isViewLoaded { - DispatchQueue.main.async(execute: { [weak self] in + DispatchQueue.main.async { [weak self] in self?.tableView.reloadData() - }) + } } } } // MARK: - UITableViewDataSource -extension AppearanceSettingsTableViewController { - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return viewModels.count +extension AppearanceSettingsTableViewController { + override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { + viewModels.count } override func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { + cellForRowAt indexPath: IndexPath) -> UITableViewCell + { guard let cell = tableView.dequeueReusableCell( withIdentifier: reuseIdentifier, for: indexPath @@ -79,9 +82,11 @@ extension AppearanceSettingsTableViewController { } // MARK: - UITableViewDelegate + extension AppearanceSettingsTableViewController { override func tableView(_ tableView: UITableView, - didSelectRowAt indexPath: IndexPath) { + didSelectRowAt indexPath: IndexPath) + { tableView.deselectRow(at: indexPath, animated: true) let viewModel = viewModels[indexPath.row] output.viewDidTriggerViewModel(viewModel: viewModel) diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Assembly/ChartSettingsInitializer.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Assembly/ChartSettingsInitializer.swift index 59c6c52bc..77ac0013c 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Assembly/ChartSettingsInitializer.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Assembly/ChartSettingsInitializer.swift @@ -1,7 +1,7 @@ import UIKit class ChartSettingsInitializer: NSObject { - @IBOutlet weak var viewController: ChartSettingsTableViewController! + @IBOutlet var viewController: ChartSettingsTableViewController! override func awakeFromNib() { super.awakeFromNib() diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift index becb92f5f..698958d54 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift @@ -1,7 +1,7 @@ import Foundation import RuuviLocal -import RuuviService import RuuviLocalization +import RuuviService class ChartSettingsPresenter: NSObject, ChartSettingsModuleInput { weak var view: ChartSettingsViewInput! @@ -10,7 +10,7 @@ class ChartSettingsPresenter: NSObject, ChartSettingsModuleInput { var featureToggleService: FeatureToggleService! var ruuviAppSettingsService: RuuviServiceAppSettings! - private var viewModel: ChartSettingsViewModel = ChartSettingsViewModel(sections: []) { + private var viewModel: ChartSettingsViewModel = .init(sections: []) { didSet { view.viewModel = viewModel } @@ -18,16 +18,16 @@ class ChartSettingsPresenter: NSObject, ChartSettingsModuleInput { func configure() { let sections: [ChartSettingsSection] = [ - buildDisplayAllDataSection() + buildDisplayAllDataSection(), ] viewModel = ChartSettingsViewModel(sections: sections) } private func buildDisplayAllDataSection() -> ChartSettingsSection { - return ChartSettingsSection( + ChartSettingsSection( note: RuuviLocalization.ChartSettings.AllPoints.description, cells: [ - buildChartDownsampling() + buildChartDownsampling(), ] ) } @@ -35,16 +35,17 @@ class ChartSettingsPresenter: NSObject, ChartSettingsModuleInput { // Draw dots feature is disabled from v1.3.0 onwards to // maintain better performance until we find a better approach to do it. private func buildDrawDotsSection() -> ChartSettingsSection { - return ChartSettingsSection( + ChartSettingsSection( note: RuuviLocalization.ChartSettings.DrawDots.description, cells: [ - buildChartDotsDrawing() + buildChartDotsDrawing(), ] ) } } // MARK: - ChartSettingsViewOutput + extension ChartSettingsPresenter: ChartSettingsViewOutput { func viewWillDisappear() { // No op. @@ -52,17 +53,17 @@ extension ChartSettingsPresenter: ChartSettingsViewOutput { } // MARK: Private -extension ChartSettingsPresenter { +extension ChartSettingsPresenter { private func buildChartDownsampling() -> ChartSettingsCell { let title = RuuviLocalization.ChartSettings.AllPoints.title let value = !settings.chartDownsamplingOn let type: ChartSettingsCellType = .switcher(title: title, - value: value) + value: value) let cell = ChartSettingsCell(type: type) cell.boolean.value = value bind(cell.boolean, fire: false) { [weak self] observer, value in - guard let value = value else { return } + guard let value else { return } observer.settings.chartDownsamplingOn = !value self?.ruuviAppSettingsService.set(showAllData: value) } @@ -73,15 +74,14 @@ extension ChartSettingsPresenter { let title = RuuviLocalization.ChartSettings.DrawDots.title let value = settings.chartDrawDotsOn let type: ChartSettingsCellType = .switcher(title: title, - value: value) + value: value) let cell = ChartSettingsCell(type: type) cell.boolean.value = value bind(cell.boolean, fire: false) { [weak self] observer, value in - guard let value = value else { return } + guard let value else { return } observer.settings.chartDrawDotsOn = value self?.ruuviAppSettingsService.set(drawDots: value) } return cell } - } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Router/ChartSettingsRouterInput.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Router/ChartSettingsRouterInput.swift index a45235c17..3cc147cd1 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Router/ChartSettingsRouterInput.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Router/ChartSettingsRouterInput.swift @@ -1,4 +1,3 @@ import Foundation -protocol ChartSettingsRouterInput { -} +protocol ChartSettingsRouterInput {} diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift index c1c89de64..b8419fc06 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift @@ -12,8 +12,8 @@ struct ChartSettingsSection { struct ChartSettingsCell { var type: ChartSettingsCellType - var boolean: Observable = Observable() - var integer: Observable = Observable() + var boolean: Observable = .init() + var integer: Observable = .init() } enum ChartSettingsIntegerUnit { @@ -23,9 +23,9 @@ enum ChartSettingsIntegerUnit { var unitString: String { switch self { case .day: - return RuuviLocalization.Interval.Day.string + RuuviLocalization.Interval.Day.string case .days: - return RuuviLocalization.Interval.Days.string + RuuviLocalization.Interval.Days.string } } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsDisclosureTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsDisclosureTableViewCell.swift index 94d1c435f..aacab3a2e 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsDisclosureTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsDisclosureTableViewCell.swift @@ -1,4 +1,3 @@ import UIKit -class ChartSettingsDisclosureTableViewCell: UITableViewCell { -} +class ChartSettingsDisclosureTableViewCell: UITableViewCell {} diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift index af4b17253..e3ba42572 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviLocalization +import UIKit // swiftlint:disable:next type_name protocol ChartSettingsStepperTableViewCellDelegate: AnyObject { @@ -9,8 +9,8 @@ protocol ChartSettingsStepperTableViewCellDelegate: AnyObject { class ChartSettingsStepperTableViewCell: UITableViewCell { weak var delegate: ChartSettingsStepperTableViewCellDelegate? - @IBOutlet weak var titleLabel: UILabel! - @IBOutlet weak var stepper: UIStepper! + @IBOutlet var titleLabel: UILabel! + @IBOutlet var stepper: UIStepper! var prefix: String = "" @@ -19,7 +19,7 @@ class ChartSettingsStepperTableViewCell: UITableViewCell { stepper.layer.cornerRadius = 8 } - @IBAction func stepperValueChanged(_ sender: Any) { + @IBAction func stepperValueChanged(_: Any) { let result = Int(stepper.value) let unitString: String = result > 1 ? RuuviLocalization.Interval.Days.string : RuuviLocalization.Interval.Day.string titleLabel.text = prefix + " " + "(" + "\(result)" + " " + unitString + ")" diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsSwitchTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsSwitchTableViewCell.swift index bb79da867..150441c47 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsSwitchTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsSwitchTableViewCell.swift @@ -5,14 +5,12 @@ protocol ChartSettingsSwitchTableViewCellDelegate: AnyObject { } class ChartSettingsSwitchTableViewCell: UITableViewCell { - weak var delegate: ChartSettingsSwitchTableViewCellDelegate? - @IBOutlet weak var titleLabel: UILabel! - @IBOutlet weak var isOnSwitch: UISwitch! + @IBOutlet var titleLabel: UILabel! + @IBOutlet var isOnSwitch: UISwitch! - @IBAction func isOnSwitchValueChanged(_ sender: Any) { + @IBAction func isOnSwitchValueChanged(_: Any) { delegate?.chartSettingsSwitch(cell: self, didChange: isOnSwitch.isOn) } - } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift index 187e49230..0b28ee4b0 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviLocalization +import UIKit class ChartSettingsTableViewController: UITableViewController { var output: ChartSettingsViewOutput! @@ -31,33 +31,32 @@ extension ChartSettingsTableViewController: ChartSettingsViewInput { } // MARK: - View lifecycle -extension ChartSettingsTableViewController { -} +extension ChartSettingsTableViewController {} // MARK: - UITableViewDataSource -extension ChartSettingsTableViewController { - override func numberOfSections(in tableView: UITableView) -> Int { - return viewModel.sections.count +extension ChartSettingsTableViewController { + override func numberOfSections(in _: UITableView) -> Int { + viewModel.sections.count } - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return viewModel.sections[section].cells.count + override func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { + viewModel.sections[section].cells.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cellViewModel = viewModel.sections[indexPath.section].cells[indexPath.row] switch cellViewModel.type { - case .switcher(let title, let value): + case let .switcher(title, value): let cell = tableView .dequeueReusableCell(with: ChartSettingsSwitchTableViewCell.self, for: indexPath) cell.titleLabel.text = title cell.isOnSwitch.isOn = value cell.delegate = self return cell - case .stepper(let title, let value, let unitSingular, let unitPlural): + case let .stepper(title, value, unitSingular, unitPlural): let cell = tableView .dequeueReusableCell(with: ChartSettingsStepperTableViewCell.self, for: indexPath) @@ -65,23 +64,23 @@ extension ChartSettingsTableViewController { let unit = value > 1 ? unitPlural : unitSingular cell.titleLabel.text = title + " " + "(" + "\(value)" + " " - + unit.unitString + ")" + + unit.unitString + ")" cell.prefix = title cell.stepper.value = Double(value) cell.delegate = self return cell - case .disclosure(let title): + case let .disclosure(title): let cell = tableView.dequeueReusableCell(with: ChartSettingsDisclosureTableViewCell.self, for: indexPath) cell.textLabel?.text = title return cell } } - override func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat { - return 100 + override func tableView(_: UITableView, estimatedHeightForFooterInSection _: Int) -> CGFloat { + 100 } - override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { + override func tableView(_: UITableView, viewForFooterInSection section: Int) -> UIView? { let footerView = UIView() let footerLabel = UILabel() footerLabel.textColor = RuuviColor.ruuviTextColor @@ -99,6 +98,7 @@ extension ChartSettingsTableViewController { } // MARK: - AdvancedSwitchTableViewCellDelegate + extension ChartSettingsTableViewController: ChartSettingsSwitchTableViewCellDelegate { func chartSettingsSwitch(cell: ChartSettingsSwitchTableViewCell, didChange value: Bool) { if let indexPath = tableView.indexPath(for: cell) { @@ -109,6 +109,7 @@ extension ChartSettingsTableViewController: ChartSettingsSwitchTableViewCellDele } // MARK: - AdvancedStepperTableViewCellDelegate + extension ChartSettingsTableViewController: ChartSettingsStepperTableViewCellDelegate { func chartSettingsStepper(cell: ChartSettingsStepperTableViewCell, didChange value: Int) { if let indexPath = tableView.indexPath(for: cell) { diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Assembly/DefaultsInitializer.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Assembly/DefaultsInitializer.swift index fa36f7021..a902519a8 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Assembly/DefaultsInitializer.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Assembly/DefaultsInitializer.swift @@ -1,7 +1,7 @@ import UIKit class DefaultsInitializer: NSObject { - @IBOutlet weak var viewController: DefaultsViewController! + @IBOutlet var viewController: DefaultsViewController! override func awakeFromNib() { super.awakeFromNib() diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift index deb48a5be..abfd2d73b 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift @@ -47,6 +47,7 @@ class DefaultsPresenter: NSObject, DefaultsModuleInput { } // MARK: - DefaultsViewOutput + extension DefaultsPresenter: DefaultsViewOutput { func viewDidTriggerUseDevServer(useDevServer: Bool?) { changeRuuviCloudEndpoint(useDevServer: useDevServer) @@ -54,6 +55,7 @@ extension DefaultsPresenter: DefaultsViewOutput { } // MARK: Private + extension DefaultsPresenter { private func buildWelcomeShown() -> DefaultsViewModel { let welcomeShown = DefaultsViewModel() @@ -246,7 +248,7 @@ extension DefaultsPresenter { viewModel.type.value = .switcher bind(viewModel.boolean, fire: false) { observer, showChart in - if let showChart = showChart { + if let showChart { observer.settings.dashboardTapActionType = showChart ? .chart : .card } } @@ -270,11 +272,12 @@ extension DefaultsPresenter { // local settings module for this since we load the whole Local settings in // the AppAssembly. bind(viewModel.boolean, - fire: false) { [weak self] _, useDevServer in + fire: false) + { [weak self] _, useDevServer in self?.view .showEndpointChangeConfirmationDialog( - useDevServer: useDevServer - ) + useDevServer: useDevServer + ) } return viewModel } @@ -286,14 +289,14 @@ extension DefaultsPresenter { viewModel.type.value = .switcher bind(viewModel.boolean, - fire: false) { observer, hideNFC in + fire: false) + { observer, hideNFC in observer.settings.hideNFCForSensorContest = hideNFC.bound } return viewModel } private func buildShowEmailAlertSettings() -> DefaultsViewModel { - let viewModel = DefaultsViewModel() viewModel.title = RuuviLocalization.Defaults.ShowEmailAlertsSettings.title viewModel.boolean.value = settings.showEmailAlertSettings @@ -307,7 +310,6 @@ extension DefaultsPresenter { } private func buildShowPushAlertSettings() -> DefaultsViewModel { - let viewModel = DefaultsViewModel() viewModel.title = RuuviLocalization.Defaults.ShowPushAlertsSettings.title viewModel.boolean.value = settings.showPushAlertSettings @@ -319,7 +321,6 @@ extension DefaultsPresenter { return viewModel } - } extension DefaultsPresenter { diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift index 37060f877..c87c73e10 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift @@ -1,7 +1,7 @@ -import UIKit import RuuviLocalization +import UIKit #if canImport(SwiftUI) && canImport(Combine) -import SwiftUI + import SwiftUI #endif class DefaultsViewController: UIViewController { @@ -9,22 +9,22 @@ class DefaultsViewController: UIViewController { var viewModels = [DefaultsViewModel]() { didSet { -#if canImport(SwiftUI) && canImport(Combine) - if #available(iOS 13, *) { - env.viewModels = viewModels - } -#endif + #if canImport(SwiftUI) && canImport(Combine) + if #available(iOS 13, *) { + env.viewModels = viewModels + } + #endif table?.viewModels = viewModels } } - @IBOutlet weak var tableContainer: UIView! - @IBOutlet weak var listContainer: UIView! + @IBOutlet var tableContainer: UIView! + @IBOutlet var listContainer: UIView! -#if canImport(SwiftUI) && canImport(Combine) - @available(iOS 13, *) - private lazy var env = DefaultsEnvironmentObject() -#endif + #if canImport(SwiftUI) && canImport(Combine) + @available(iOS 13, *) + private lazy var env = DefaultsEnvironmentObject() + #endif private var table: DefaultsTableViewController? } @@ -48,40 +48,41 @@ extension DefaultsViewController: DefaultsViewInput { } // MARK: - View lifecycle + extension DefaultsViewController { override func viewDidLoad() { super.viewDidLoad() configureViews() } - override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { + override func shouldPerformSegue(withIdentifier identifier: String, sender _: Any?) -> Bool { #if SWIFTUI - if #available(iOS 13, *) { - return identifier == DefaultsEmbedSegue.list.rawValue - } else { - return identifier == DefaultsEmbedSegue.table.rawValue - } + if #available(iOS 13, *) { + return identifier == DefaultsEmbedSegue.list.rawValue + } else { + return identifier == DefaultsEmbedSegue.table.rawValue + } #else - return identifier == DefaultsEmbedSegue.table.rawValue + return identifier == DefaultsEmbedSegue.table.rawValue #endif } #if SWIFTUI && canImport(SwiftUI) && canImport(Combine) - @IBSegueAction func addSwiftUIView(_ coder: NSCoder) -> UIViewController? { - if #available(iOS 13, *) { - env.viewModels = viewModels - return UIHostingController(coder: coder, rootView: DefaultsList().environmentObject(env)) - } else { - return nil + @IBSegueAction func addSwiftUIView(_ coder: NSCoder) -> UIViewController? { + if #available(iOS 13, *) { + env.viewModels = viewModels + return UIHostingController(coder: coder, rootView: DefaultsList().environmentObject(env)) + } else { + return nil + } } - } #else - @IBSegueAction func addSwiftUIView(_ coder: NSCoder) -> UIViewController? { - return nil - } + @IBSegueAction func addSwiftUIView(_: NSCoder) -> UIViewController? { + nil + } #endif - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + override func prepare(for segue: UIStoryboardSegue, sender _: Any?) { switch segue.identifier { case DefaultsEmbedSegue.table.rawValue: table = segue.destination as? DefaultsTableViewController @@ -94,6 +95,7 @@ extension DefaultsViewController { } // MARK: - Configure Views + extension DefaultsViewController { func configureViews() { tableContainer.isHidden = !shouldPerformSegue(withIdentifier: DefaultsEmbedSegue.table.rawValue, sender: nil) diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewModel.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewModel.swift index 2b5bf69d6..de00cc1fd 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewModel.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewModel.swift @@ -5,17 +5,18 @@ enum DefaultsType { case stepper case plain } + class DefaultsViewModel: Identifiable { var id = UUID().uuidString var title: String? - var type: Observable = Observable() + var type: Observable = .init() // Value for switcher type - var boolean: Observable = Observable() + var boolean: Observable = .init() // Value for stepper type - var integer: Observable = Observable() + var integer: Observable = .init() // Value for plain type - var value: Observable = Observable() + var value: Observable = .init() var unit: DefaultsIntegerUnit = .seconds } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsEnvironmentObject.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsEnvironmentObject.swift index 9af63b798..98b5ce5cc 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsEnvironmentObject.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsEnvironmentObject.swift @@ -1,9 +1,9 @@ #if canImport(SwiftUI) && canImport(Combine) -import Combine -import SwiftUI + import Combine + import SwiftUI -@available(iOS 13, *) -final class DefaultsEnvironmentObject: ObservableObject { - @Published var viewModels = [DefaultsViewModel]() -} + @available(iOS 13, *) + final class DefaultsEnvironmentObject: ObservableObject { + @Published var viewModels = [DefaultsViewModel]() + } #endif diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsList.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsList.swift index ba2895df6..11c412201 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsList.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsList.swift @@ -1,27 +1,26 @@ #if canImport(SwiftUI) && canImport(Combine) -import SwiftUI + import SwiftUI -@available(iOS 13.0, *) -struct DefaultsList: View { + @available(iOS 13.0, *) + struct DefaultsList: View { + @EnvironmentObject var env: DefaultsEnvironmentObject - @EnvironmentObject var env: DefaultsEnvironmentObject - - var body: some View { - List { - ForEach(env.viewModels) { _ in - Section(header: Text("Hello")) { - Text("World") + var body: some View { + List { + ForEach(env.viewModels) { _ in + Section(header: Text("Hello")) { + Text("World") + } } - } - }.listStyle(GroupedListStyle()) + }.listStyle(GroupedListStyle()) + } } -} -@available(iOS 13.0, *) -struct DefaultsList_Previews: PreviewProvider { - static var previews: some View { - return DefaultsList().environmentObject(DefaultsEnvironmentObject()) + @available(iOS 13.0, *) + struct DefaultsList_Previews: PreviewProvider { + static var previews: some View { + DefaultsList().environmentObject(DefaultsEnvironmentObject()) + } } -} #endif diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsPlainTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsPlainTableViewCell.swift index 3b189717c..e9f56d01a 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsPlainTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsPlainTableViewCell.swift @@ -1,8 +1,6 @@ import UIKit class DefaultsPlainTableViewCell: UITableViewCell { - - @IBOutlet weak var titleLabel: UILabel! - @IBOutlet weak var valueLabel: UILabel! - + @IBOutlet var titleLabel: UILabel! + @IBOutlet var valueLabel: UILabel! } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsStepperTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsStepperTableViewCell.swift index e9067d56e..a922cdfdd 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsStepperTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsStepperTableViewCell.swift @@ -9,8 +9,8 @@ class DefaultsStepperTableViewCell: UITableViewCell { weak var delegate: DefaultsStepperTableViewCellDelegate? var unit: DefaultsIntegerUnit = .seconds - @IBOutlet weak var titleLabel: UILabel! - @IBOutlet weak var stepper: UIStepper! + @IBOutlet var titleLabel: UILabel! + @IBOutlet var stepper: UIStepper! var prefix: String = "" @@ -19,18 +19,17 @@ class DefaultsStepperTableViewCell: UITableViewCell { stepper.layer.cornerRadius = 8 } - @IBAction func stepperValueChanged(_ sender: Any) { + @IBAction func stepperValueChanged(_: Any) { let result = Int(stepper.value) - let unitString: String - switch unit { + let unitString: String = switch unit { case .hours: - unitString = RuuviLocalization.Defaults.Interval.Hour.string + RuuviLocalization.Defaults.Interval.Hour.string case .minutes: - unitString = RuuviLocalization.Defaults.Interval.Min.string + RuuviLocalization.Defaults.Interval.Min.string case .seconds: - unitString = RuuviLocalization.Defaults.Interval.Sec.string + RuuviLocalization.Defaults.Interval.Sec.string case .decimal: - unitString = "" + "" } switch unit { case .hours, .minutes, .seconds: diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsSwitchTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsSwitchTableViewCell.swift index 0df03c1d8..e3450753e 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsSwitchTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsSwitchTableViewCell.swift @@ -5,14 +5,12 @@ protocol DefaultsSwitchTableViewCellDelegate: AnyObject { } class DefaultsSwitchTableViewCell: UITableViewCell { - weak var delegate: DefaultsSwitchTableViewCellDelegate? - @IBOutlet weak var titleLabel: UILabel! - @IBOutlet weak var isOnSwitch: UISwitch! + @IBOutlet var titleLabel: UILabel! + @IBOutlet var isOnSwitch: UISwitch! - @IBAction func isOnSwitchValueChanged(_ sender: Any) { + @IBAction func isOnSwitchValueChanged(_: Any) { delegate?.defaultsSwitch(cell: self, didChange: isOnSwitch.isOn) } - } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift index 72bb8f95e..4a1304cf3 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift @@ -22,21 +22,20 @@ extension DefaultsTableViewController: DefaultsViewInput { // do nothing } - func showEndpointChangeConfirmationDialog(useDevServer: Bool?) { + func showEndpointChangeConfirmationDialog(useDevServer _: Bool?) { // No op. } } // MARK: - View lifecycle -extension DefaultsTableViewController { -} +extension DefaultsTableViewController {} // MARK: - UITableViewDataSource -extension DefaultsTableViewController { - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return viewModels.count +extension DefaultsTableViewController { + override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { + viewModels.count } // swiftlint:disable:next function_body_length @@ -90,8 +89,8 @@ extension DefaultsTableViewController { switch viewModel.unit { case .hours, .minutes, .seconds: cell.titleLabel.text = title + " " - + "(" + "\(result)" + " " - + unitString + ")" + + "(" + "\(result)" + " " + + unitString + ")" case .decimal: cell.titleLabel.text = title + " " + "(" + "\(result)" + ")" } @@ -103,11 +102,11 @@ extension DefaultsTableViewController { // Should never be here return UITableViewCell() } - } } // MARK: - DefaultsSwitchTableViewCellDelegate + extension DefaultsTableViewController: DefaultsSwitchTableViewCellDelegate { func defaultsSwitch(cell: DefaultsSwitchTableViewCell, didChange value: Bool) { if let indexPath = tableView.indexPath(for: cell) { @@ -117,6 +116,7 @@ extension DefaultsTableViewController: DefaultsSwitchTableViewCellDelegate { } // MARK: - DefaultsStepperTableViewCellDelegate + extension DefaultsTableViewController: DefaultsStepperTableViewCellDelegate { func defaultsStepper(cell: DefaultsStepperTableViewCell, didChange value: Int) { if let indexPath = tableView.indexPath(for: cell) { diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/Assembly/DevicesModuleFactory.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/Assembly/DevicesModuleFactory.swift index 57886d498..713fe9927 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/Assembly/DevicesModuleFactory.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/Assembly/DevicesModuleFactory.swift @@ -1,8 +1,8 @@ -import UIKit +import RuuviLocal import RuuviOntology -import RuuviService import RuuviPresenters -import RuuviLocal +import RuuviService +import UIKit protocol DevicesModuleFactory { func create() -> DevicesModuleInput diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/Presenter/DevicesPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/Presenter/DevicesPresenter.swift index c6e22f56a..e7cd02a5e 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/Presenter/DevicesPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/Presenter/DevicesPresenter.swift @@ -1,24 +1,24 @@ import Foundation +import RuuviLocal import RuuviOntology -import RuuviService import RuuviPresenters -import RuuviLocal +import RuuviService import UIKit final class DevicesPresenter: DevicesModuleInput { var interactor: DevicesInteractorInput! var viewController: UIViewController { - if let view = self.weakView { + if let view = weakView { return view } else { let view = DevicesTableViewController() view.output = self - self.weakView = view + weakView = view return view } - } + private weak var weakView: UIViewController? private var viewModels: [DevicesViewModel] = [] { @@ -48,13 +48,13 @@ extension DevicesPresenter: DevicesViewOutput { extension DevicesPresenter: DevicesInteractorOutput { func interactorDidUpdate(tokens: [RuuviCloudPNToken]) { - let viewModels = tokens.compactMap({ (token) -> DevicesViewModel in + let viewModels = tokens.compactMap { token -> DevicesViewModel in let viewModel = DevicesViewModel() viewModel.id.value = token.id viewModel.lastAccessed.value = token.lastAccessed viewModel.name.value = token.name return viewModel - }) + } self.viewModels = viewModels } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewModel.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewModel.swift index 477a951bc..3e994705f 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewModel.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewModel.swift @@ -1,8 +1,8 @@ -import UIKit import RuuviOntology +import UIKit struct DevicesViewModel { - let id: Observable = Observable() - let lastAccessed: Observable = Observable() - let name: Observable = Observable() + let id: Observable = .init() + let lastAccessed: Observable = .init() + let name: Observable = .init() } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewOutput.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewOutput.swift index 729d6b51a..fa007013d 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewOutput.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewOutput.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviOntology +import UIKit protocol DevicesViewOutput { func viewDidLoad() diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift index d41aeffe6..52e1242d0 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift @@ -7,7 +7,8 @@ class DevicesTableViewCell: UITableViewCell { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -49,8 +50,8 @@ extension DevicesTableViewCell { } } -extension DevicesTableViewCell { - fileprivate func setUpUI() { +private extension DevicesTableViewCell { + func setUpUI() { backgroundColor = .clear selectionStyle = .none @@ -60,7 +61,7 @@ extension DevicesTableViewCell { container.fillSuperview(padding: .init(top: 4, left: 8, bottom: 4, right: 8)) let textStack = UIStackView(arrangedSubviews: [ - deviceNameLabel, tokenIdLabel, lastAccessedLabel + deviceNameLabel, tokenIdLabel, lastAccessedLabel, ]) textStack.spacing = 4 textStack.distribution = .fill diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift index 483407470..f0a53fdf0 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviLocalization +import UIKit class DevicesTableViewController: UITableViewController { var output: DevicesViewOutput! @@ -15,12 +15,14 @@ class DevicesTableViewController: UITableViewController { super.init(style: .grouped) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } } // MARK: LIFE CYCLE + extension DevicesTableViewController { override func viewDidLoad() { super.viewDidLoad() @@ -36,7 +38,7 @@ extension DevicesTableViewController { extension DevicesTableViewController: DevicesViewInput { func localize() { - self.title = RuuviLocalization.DfuDevicesScanner.Title.text + title = RuuviLocalization.DfuDevicesScanner.Title.text } func showTokenIdDialog(for viewModel: DevicesViewModel) { @@ -51,8 +53,8 @@ extension DevicesTableViewController: DevicesViewInput { controller.addAction(UIAlertAction(title: RuuviLocalization.copy, style: .default, handler: { _ in - UIPasteboard.general.string = tokenId.stringValue - })) + UIPasteboard.general.string = tokenId.stringValue + })) controller.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) present(controller, animated: true) } @@ -64,20 +66,20 @@ extension DevicesTableViewController: DevicesViewInput { controller.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .default, handler: { [weak self] _ in - self?.navigationController?.popViewController(animated: true) - })) + self?.navigationController?.popViewController(animated: true) + })) present(controller, animated: true) } } -extension DevicesTableViewController { - fileprivate func updateUI() { +private extension DevicesTableViewController { + func updateUI() { DispatchQueue.main.async { [weak self] in self?.tableView.reloadData() } } - fileprivate func setUpTableView() { + func setUpTableView() { view.backgroundColor = RuuviColor.ruuviPrimary tableView.showsVerticalScrollIndicator = false tableView.tableFooterView = UIView() @@ -91,15 +93,18 @@ extension DevicesTableViewController { } // MARK: - TABLEVIEW DATA SOURCE + extension DevicesTableViewController { - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return viewModels.count + override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { + viewModels.count } override func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { + cellForRowAt indexPath: IndexPath) -> UITableViewCell + { guard let cell = tableView.dequeueReusableCell(withIdentifier: reuseIndentifier, - for: indexPath) as? DevicesTableViewCell else { + for: indexPath) as? DevicesTableViewCell + else { fatalError() } cell.configure(with: viewModels[indexPath.row]) @@ -108,9 +113,11 @@ extension DevicesTableViewController { } // MARK: - TABLEVIEW DELEGATE + extension DevicesTableViewController { - override func tableView(_ tableView: UITableView, - didSelectRowAt indexPath: IndexPath) { + override func tableView(_: UITableView, + didSelectRowAt indexPath: IndexPath) + { output.viewDidTapDevice(viewModel: viewModels[indexPath.row]) } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Assembly/HeartbeatInitializer.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Assembly/HeartbeatInitializer.swift index 0e15f4866..2f89ebe14 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Assembly/HeartbeatInitializer.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Assembly/HeartbeatInitializer.swift @@ -1,7 +1,7 @@ import UIKit class HeartbeatInitializer: NSObject { - @IBOutlet weak var viewController: HeartbeatViewController! + @IBOutlet var viewController: HeartbeatViewController! override func awakeFromNib() { super.awakeFromNib() diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Presenter/HeartbeatPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Presenter/HeartbeatPresenter.swift index d4af0f1d8..c29993ac6 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Presenter/HeartbeatPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Presenter/HeartbeatPresenter.swift @@ -27,6 +27,4 @@ class HeartbeatPresenter: NSObject, HeartbeatModuleInput { } } -extension HeartbeatPresenter: HeartbeatViewOutput { - -} +extension HeartbeatPresenter: HeartbeatViewOutput {} diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Router/HeartbeatRouterInput.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Router/HeartbeatRouterInput.swift index b0a818493..c5786f387 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Router/HeartbeatRouterInput.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Router/HeartbeatRouterInput.swift @@ -1,5 +1,3 @@ import Foundation -protocol HeartbeatRouterInput { - -} +protocol HeartbeatRouterInput {} diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift index 7bcd5ad64..b13649bb9 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift @@ -1,7 +1,7 @@ -import UIKit import RuuviLocalization +import UIKit #if canImport(SwiftUI) && canImport(Combine) -import SwiftUI + import SwiftUI #endif class HeartbeatViewController: UIViewController { @@ -9,22 +9,22 @@ class HeartbeatViewController: UIViewController { var viewModel = HeartbeatViewModel() { didSet { -#if canImport(SwiftUI) && canImport(Combine) - if #available(iOS 13, *) { - env.viewModel = viewModel - } -#endif + #if canImport(SwiftUI) && canImport(Combine) + if #available(iOS 13, *) { + env.viewModel = viewModel + } + #endif table?.viewModel = viewModel } } - @IBOutlet weak var tableContainer: UIView! - @IBOutlet weak var listContainer: UIView! + @IBOutlet var tableContainer: UIView! + @IBOutlet var listContainer: UIView! -#if canImport(SwiftUI) && canImport(Combine) - @available(iOS 13, *) - private lazy var env = HeartbeatEnvironmentObject() -#endif + #if canImport(SwiftUI) && canImport(Combine) + @available(iOS 13, *) + private lazy var env = HeartbeatEnvironmentObject() + #endif private var table: HeartbeatTableViewController? } @@ -36,40 +36,41 @@ extension HeartbeatViewController: HeartbeatViewInput { } // MARK: - View lifecycle + extension HeartbeatViewController { override func viewDidLoad() { super.viewDidLoad() configureViews() } - override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { + override func shouldPerformSegue(withIdentifier identifier: String, sender _: Any?) -> Bool { #if SWIFTUI - if #available(iOS 13, *) { - return identifier == HeartbeatEmbedSegue.list.rawValue - } else { - return identifier == HeartbeatEmbedSegue.table.rawValue - } + if #available(iOS 13, *) { + return identifier == HeartbeatEmbedSegue.list.rawValue + } else { + return identifier == HeartbeatEmbedSegue.table.rawValue + } #else - return identifier == HeartbeatEmbedSegue.table.rawValue + return identifier == HeartbeatEmbedSegue.table.rawValue #endif } #if SWIFTUI && canImport(SwiftUI) && canImport(Combine) - @IBSegueAction func addSwiftUIView(_ coder: NSCoder) -> UIViewController? { - if #available(iOS 13, *) { - env.viewModel = viewModel - return UIHostingController(coder: coder, rootView: HeartbeatList().environmentObject(env)) - } else { - return nil + @IBSegueAction func addSwiftUIView(_ coder: NSCoder) -> UIViewController? { + if #available(iOS 13, *) { + env.viewModel = viewModel + return UIHostingController(coder: coder, rootView: HeartbeatList().environmentObject(env)) + } else { + return nil + } } - } #else - @IBSegueAction func addSwiftUIView(_ coder: NSCoder) -> UIViewController? { - return nil - } + @IBSegueAction func addSwiftUIView(_: NSCoder) -> UIViewController? { + nil + } #endif - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + override func prepare(for segue: UIStoryboardSegue, sender _: Any?) { switch segue.identifier { case HeartbeatEmbedSegue.table.rawValue: table = segue.destination as? HeartbeatTableViewController @@ -82,6 +83,7 @@ extension HeartbeatViewController { } // MARK: - Configure Views + extension HeartbeatViewController { func configureViews() { tableContainer.isHidden = !shouldPerformSegue(withIdentifier: HeartbeatEmbedSegue.table.rawValue, sender: nil) diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewModel.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewModel.swift index 45af19a3e..e7b4785ba 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewModel.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewModel.swift @@ -6,10 +6,10 @@ class HeartbeatViewModel { var bgScanningInterval = Observable(1) var bgScanningTitle: String { - return RuuviLocalization.Settings.BackgroundScanning.title + RuuviLocalization.Settings.BackgroundScanning.title } var bgScanningIntervalTitle: String { - return RuuviLocalization.Settings.BackgroundScanning.interval + RuuviLocalization.Settings.BackgroundScanning.interval } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewOutput.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewOutput.swift index 815a71bfb..01de28f75 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewOutput.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewOutput.swift @@ -1,5 +1,3 @@ import Foundation -protocol HeartbeatViewOutput { - -} +protocol HeartbeatViewOutput {} diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatEnvironmentObject.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatEnvironmentObject.swift index 101a35983..64bb7f491 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatEnvironmentObject.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatEnvironmentObject.swift @@ -1,9 +1,9 @@ #if canImport(SwiftUI) && canImport(Combine) -import Combine -import SwiftUI + import Combine + import SwiftUI -@available(iOS 13, *) -final class HeartbeatEnvironmentObject: ObservableObject { - @Published var viewModel = HeartbeatViewModel() -} + @available(iOS 13, *) + final class HeartbeatEnvironmentObject: ObservableObject { + @Published var viewModel = HeartbeatViewModel() + } #endif diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift index 69e32f4db..02b12bda9 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift @@ -1,33 +1,32 @@ import RuuviLocalization #if canImport(SwiftUI) && canImport(Combine) -import SwiftUI + import SwiftUI -@available(iOS 13.0, *) -struct HeartbeatList: View { + @available(iOS 13.0, *) + struct HeartbeatList: View { + @EnvironmentObject var env: HeartbeatEnvironmentObject - @EnvironmentObject var env: HeartbeatEnvironmentObject + var body: some View { + VStack { + Toggle(isOn: $env.viewModel.bgScanningState.value.bound) { + Text(env.viewModel.bgScanningTitle) + } - var body: some View { - VStack { - Toggle(isOn: self.$env.viewModel.bgScanningState.value.bound) { - Text(self.env.viewModel.bgScanningTitle) - } - - if self.env.viewModel.bgScanningState.value.bound { - Stepper(RuuviLocalization.Heartbeat.Interval.Every.string - + " " + "\(self.env.viewModel.bgScanningInterval.value.bound)" + if env.viewModel.bgScanningState.value.bound { + Stepper(RuuviLocalization.Heartbeat.Interval.Every.string + + " " + "\(env.viewModel.bgScanningInterval.value.bound)" + " " + RuuviLocalization.Heartbeat.Interval.Min.string, - value: self.$env.viewModel.bgScanningInterval.value.bound, - in: 0...3600) + value: $env.viewModel.bgScanningInterval.value.bound, + in: 0 ... 3600) + } } } } -} -@available(iOS 13.0, *) -struct HeartbeatList_Previews: PreviewProvider { - static var previews: some View { - return HeartbeatList().environmentObject(HeartbeatEnvironmentObject()) + @available(iOS 13.0, *) + struct HeartbeatList_Previews: PreviewProvider { + static var previews: some View { + HeartbeatList().environmentObject(HeartbeatEnvironmentObject()) + } } -} #endif diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift index 30938368e..842b78e95 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift @@ -2,7 +2,6 @@ import RuuviLocalization import UIKit class HeartbeatTableViewController: UITableViewController { - var output: HeartbeatViewOutput! var viewModel = HeartbeatViewModel() { @@ -11,14 +10,15 @@ class HeartbeatTableViewController: UITableViewController { } } - @IBOutlet weak var bgScanningTitleLabel: UILabel! - @IBOutlet weak var bgScanningSwitch: RuuviUISwitch! - @IBOutlet weak var bgScanningIntervalTitleLabel: UILabel! - @IBOutlet weak var bgScanningIntervalValueLabel: UILabel! - @IBOutlet weak var bgScanningIntervalStepper: UIStepper! + @IBOutlet var bgScanningTitleLabel: UILabel! + @IBOutlet var bgScanningSwitch: RuuviUISwitch! + @IBOutlet var bgScanningIntervalTitleLabel: UILabel! + @IBOutlet var bgScanningIntervalValueLabel: UILabel! + @IBOutlet var bgScanningIntervalStepper: UIStepper! } // MARK: - HeartbeatViewInput + extension HeartbeatTableViewController: HeartbeatViewInput { func localize() { bgScanningTitleLabel.text = viewModel.bgScanningTitle @@ -26,7 +26,7 @@ extension HeartbeatTableViewController: HeartbeatViewInput { if viewModel.bgScanningInterval.value.bound > 0 { bgScanningIntervalValueLabel.text = RuuviLocalization.Heartbeat.Interval.Every.string + " " + "\(viewModel.bgScanningInterval.value.bound)" - + " " + RuuviLocalization.Heartbeat.Interval.Min.string + + " " + RuuviLocalization.Heartbeat.Interval.Min.string } else { bgScanningIntervalValueLabel.text = RuuviLocalization.Heartbeat.Interval.All.string } @@ -34,17 +34,19 @@ extension HeartbeatTableViewController: HeartbeatViewInput { } // MARK: - IBActions + extension HeartbeatTableViewController { - @IBAction func bgScanningIntervalStepperValueChanged(_ sender: Any) { + @IBAction func bgScanningIntervalStepperValueChanged(_: Any) { viewModel.bgScanningInterval.value = Int(bgScanningIntervalStepper.value) } - @IBAction func bgScanningSwitchValueChanged(_ sender: Any) { + @IBAction func bgScanningSwitchValueChanged(_: Any) { viewModel.bgScanningState.value = bgScanningSwitch.isOn } } // MARK: - View lifecycle + extension HeartbeatTableViewController { override func viewDidLoad() { super.viewDidLoad() @@ -54,12 +56,13 @@ extension HeartbeatTableViewController { } // MARK: - UI TABLE VIEW + extension HeartbeatTableViewController { - override func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat { - return 100 + override func tableView(_: UITableView, estimatedHeightForFooterInSection _: Int) -> CGFloat { + 100 } - override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { + override func tableView(_: UITableView, viewForFooterInSection _: Int) -> UIView? { let footerView = UIView() let footerLabel = UILabel() footerLabel.textColor = RuuviColor.ruuviTextColor @@ -73,30 +76,30 @@ extension HeartbeatTableViewController { } // MARK: - Private + extension HeartbeatTableViewController { private func updateUIComponent() { tableView.sectionFooterHeight = UITableView.automaticDimension bgScanningIntervalStepper.layer.cornerRadius = 8 } + private func bindViewModel() { if isViewLoaded { - - bgScanningSwitch.bind(viewModel.bgScanningState) { (view, isOn) in + bgScanningSwitch.bind(viewModel.bgScanningState) { view, isOn in view.isOn = isOn.bound } - bgScanningIntervalValueLabel.bind(viewModel.bgScanningInterval) { (label, interval) in + bgScanningIntervalValueLabel.bind(viewModel.bgScanningInterval) { label, interval in if interval.bound > 0 { - label.text = RuuviLocalization.Heartbeat.Interval.Every.string - + " " + "\(interval.bound)" - + " " + RuuviLocalization.Heartbeat.Interval.Min.string + label.text = RuuviLocalization.Heartbeat.Interval.Every.string + + " " + "\(interval.bound)" + + " " + RuuviLocalization.Heartbeat.Interval.Min.string } else { label.text = RuuviLocalization.Heartbeat.Interval.All.string } } - bgScanningIntervalStepper.bind(viewModel.bgScanningInterval) { (stepper, interval) in + bgScanningIntervalStepper.bind(viewModel.bgScanningInterval) { stepper, interval in stepper.value = Double(interval.bound) } } } - } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Assembly/NotificationsSettingsModuleFactory.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Assembly/NotificationsSettingsModuleFactory.swift index 24b57b157..2f192d819 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Assembly/NotificationsSettingsModuleFactory.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Assembly/NotificationsSettingsModuleFactory.swift @@ -1,7 +1,7 @@ -import UIKit import RuuviLocal -import RuuviService import RuuviLocalization +import RuuviService +import UIKit protocol NotificationsSettingsModuleFactory { func create() -> NotificationsSettingsTableViewController diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift index 612934414..874f00a3d 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift @@ -1,9 +1,9 @@ import Foundation -import UIKit -import RuuviOntology import RuuviLocal -import RuuviService import RuuviLocalization +import RuuviOntology +import RuuviService +import UIKit class NotificationsSettingsPresenter: NSObject, NotificationsSettingsModuleInput { weak var view: NotificationsSettingsViewInput? @@ -43,7 +43,7 @@ extension NotificationsSettingsPresenter: NotificationsSettingsViewOutput { title: RuuviLocalization.settingsAlertSound, items: [ RuuviAlertSound.systemDefault, - RuuviAlertSound.ruuviSpeak + RuuviAlertSound.ruuviSpeak, ], selection: settings.alertSound ) @@ -52,7 +52,7 @@ extension NotificationsSettingsPresenter: NotificationsSettingsViewOutput { } extension NotificationsSettingsPresenter { - fileprivate func configure() { + private func configure() { var viewModels: [NotificationsSettingsViewModel] = [] if settings.showEmailAlertSettings { @@ -135,17 +135,17 @@ extension NotificationsSettingsPresenter { .addObserver(forName: .AlertSoundSettingsDidChange, object: nil, queue: .main, - using: { [weak self] (_) in - self?.configure() - guard let sSelf = self else { return } - DispatchQueue.main.async { - sSelf.cloudNotificationService.set( - sound: sSelf.settings.alertSound, - language: sSelf.settings.language, - deviceName: UIDevice.modelName - ) - } - }) + using: { [weak self] _ in + self?.configure() + guard let sSelf = self else { return } + DispatchQueue.main.async { + sSelf.cloudNotificationService.set( + sound: sSelf.settings.alertSound, + language: sSelf.settings.language, + deviceName: UIDevice.modelName + ) + } + }) } private func startObservingEmailAlertSetting() { @@ -154,9 +154,9 @@ extension NotificationsSettingsPresenter { .addObserver(forName: .EmailAlertSettingsDidChange, object: nil, queue: .main, - using: { [weak self] (_) in - self?.updateEmailViewModel() - }) + using: { [weak self] _ in + self?.updateEmailViewModel() + }) } private func startObservingPushAlertSetting() { @@ -165,9 +165,9 @@ extension NotificationsSettingsPresenter { .addObserver(forName: .PushAlertSettingsDidChange, object: nil, queue: .main, - using: { [weak self] (_) in - self?.updatePushViewModel() - }) + using: { [weak self] _ in + self?.updatePushViewModel() + }) } private func updateEmailViewModel() { diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouter.swift index 93a69341a..be11c6e8f 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouter.swift @@ -1,7 +1,7 @@ import LightRoute import UIKit -class NotificationsSettingsRouter: NotificationsSettingsRouterInput { +class NotificationsSettingsRouter: NotificationsSettingsRouterInput { weak var transitionHandler: UIViewController? func dismiss() { diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Assembly/PushAlertSoundSelectionModuleFactory.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Assembly/PushAlertSoundSelectionModuleFactory.swift index ec9360721..aa739714a 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Assembly/PushAlertSoundSelectionModuleFactory.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Assembly/PushAlertSoundSelectionModuleFactory.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviLocal +import UIKit protocol PushAlertSoundSelectionModuleFactory { func create(with title: String) -> PushAlertSoundSelectionTableViewController diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionPresenter.swift index 7c11258f9..8e0edf8a1 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionPresenter.swift @@ -1,7 +1,7 @@ import Foundation -import UIKit -import RuuviOntology import RuuviLocal +import RuuviOntology +import UIKit class PushAlertSoundSelectionPresenter: NSObject { weak var view: PushAlertSoundSelectionViewInput? @@ -22,7 +22,8 @@ extension PushAlertSoundSelectionPresenter: PushAlertSoundSelectionViewOutput { func viewDidSelectItem(item: SelectionItemProtocol) { if let selectedSound = item as? RuuviAlertSound, - let viewModel = viewModel { + let viewModel + { settings.alertSound = selectedSound let updatedViewModel = PushAlertSoundSelectionViewModel( title: viewModel.title, diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift index 0a81233ab..46b2dc270 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift @@ -1,7 +1,6 @@ import UIKit class PushAlertSelectionTableViewCell: UITableViewCell { - private lazy var titleLabel: UILabel = { let label = UILabel() label.textColor = RuuviColor.ruuviTextColor @@ -12,13 +11,15 @@ class PushAlertSelectionTableViewCell: UITableViewCell { }() override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) { + reuseIdentifier: String?) + { super.init(style: style, reuseIdentifier: reuseIdentifier) setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift index 68430ac7f..c2130f36f 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift @@ -1,7 +1,7 @@ -import UIKit -import Foundation import AVFoundation +import Foundation import RuuviOntology +import UIKit // swiftlint:disable:next type_name class PushAlertSoundSelectionTableViewController: UITableViewController { @@ -19,7 +19,8 @@ class PushAlertSoundSelectionTableViewController: UITableViewController { self.title = title } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -32,6 +33,7 @@ class PushAlertSoundSelectionTableViewController: UITableViewController { } // MARK: - LIFECYCLE + extension PushAlertSoundSelectionTableViewController { override func viewDidLoad() { super.viewDidLoad() @@ -55,43 +57,44 @@ extension PushAlertSoundSelectionTableViewController: PushAlertSoundSelectionVie } } -extension PushAlertSoundSelectionTableViewController { - fileprivate func setUpUI() { +private extension PushAlertSoundSelectionTableViewController { + func setUpUI() { view.backgroundColor = RuuviColor.ruuviPrimary setUpTableView() } - fileprivate func setUpTableView() { + func setUpTableView() { tableView.sectionFooterHeight = UITableView.automaticDimension tableView.register(PushAlertSelectionTableViewCell.self, forCellReuseIdentifier: reuseIdentifier) } - fileprivate func updateUI() { + func updateUI() { if isViewLoaded { - DispatchQueue.main.async(execute: { [weak self] in + DispatchQueue.main.async { [weak self] in self?.tableView.reloadData() - }) + } } } } // MARK: - UITableViewDataSource -extension PushAlertSoundSelectionTableViewController { - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return viewModel?.items.count ?? 0 +extension PushAlertSoundSelectionTableViewController { + override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { + viewModel?.items.count ?? 0 } override func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { + cellForRowAt indexPath: IndexPath) -> UITableViewCell + { guard let cell = tableView.dequeueReusableCell( withIdentifier: reuseIdentifier, for: indexPath ) as? PushAlertSelectionTableViewCell else { fatalError() } - if let viewModel = viewModel { + if let viewModel { let item = viewModel.items[indexPath.row] cell.configure( title: item.title(""), @@ -103,17 +106,20 @@ extension PushAlertSoundSelectionTableViewController { } // MARK: - UITableViewDelegate + extension PushAlertSoundSelectionTableViewController { override func tableView(_ tableView: UITableView, - didSelectRowAt indexPath: IndexPath) { + didSelectRowAt indexPath: IndexPath) + { tableView.deselectRow(at: indexPath, animated: true) - if let viewModel = viewModel { + if let viewModel { output.viewDidSelectItem(item: viewModel.items[indexPath.row]) } } } // MARK: - Audio Player + extension PushAlertSoundSelectionTableViewController { func playSound(from sound: RuuviAlertSound) { audioPlayer?.invalidate() @@ -132,5 +138,4 @@ extension PushAlertSoundSelectionTableViewController { audioPlayer?.play() } } - } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewModel.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewModel.swift index fc2f1a314..b85e59cf4 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewModel.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewModel.swift @@ -19,11 +19,11 @@ class NotificationsSettingsViewModel: Identifiable { var title: String? var subtitle: String? var configType: Observable = - Observable() + .init() var settingsType: Observable = - Observable() + .init() // Value for switcher type - var boolean: Observable = Observable() + var boolean: Observable = .init() // Value for plain type - var value: Observable = Observable() + var value: Observable = .init() } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift index 0537ef2d8..fabf1a9d6 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift @@ -5,7 +5,6 @@ protocol NotificationsSettingsSwitchCellDelegate: NSObjectProtocol { } class NotificationsSettingsSwitchCell: UITableViewCell { - weak var delegate: NotificationsSettingsSwitchCellDelegate? private lazy var titleLabel: UILabel = { @@ -38,13 +37,15 @@ class NotificationsSettingsSwitchCell: UITableViewCell { }() override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) { + reuseIdentifier: String?) + { super.init(style: style, reuseIdentifier: reuseIdentifier) setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -55,7 +56,7 @@ class NotificationsSettingsSwitchCell: UITableViewCell { backgroundColor = .clear let textStack = UIStackView(arrangedSubviews: [ - titleLabel, subtitleLabel + titleLabel, subtitleLabel, ]) textStack.spacing = 4 textStack.distribution = .fillProportionally @@ -88,13 +89,13 @@ class NotificationsSettingsSwitchCell: UITableViewCell { } } - // MARK: - SETTERS -extension NotificationsSettingsSwitchCell { +// MARK: - SETTERS +extension NotificationsSettingsSwitchCell { func configure(title: String?, subtitle: String?, value: Bool?) { titleLabel.text = title subtitleLabel.text = subtitle - if let value = value { + if let value { statusSwitch.setOn(value, animated: false) } else { statusSwitch.setOn(false, animated: false) diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift index b31f30378..872314e0b 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift @@ -1,6 +1,6 @@ -import UIKit import Foundation import RuuviLocalization +import UIKit class NotificationsSettingsTableViewController: UITableViewController { var output: NotificationsSettingsViewOutput? @@ -15,7 +15,8 @@ class NotificationsSettingsTableViewController: UITableViewController { self.title = title } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -24,6 +25,7 @@ class NotificationsSettingsTableViewController: UITableViewController { } // MARK: - LIFECYCLE + extension NotificationsSettingsTableViewController { override func viewDidLoad() { super.viewDidLoad() @@ -34,17 +36,17 @@ extension NotificationsSettingsTableViewController { extension NotificationsSettingsTableViewController: NotificationsSettingsViewInput { func localize() { - // no op. + // no op. } } -extension NotificationsSettingsTableViewController { - fileprivate func setUpUI() { +private extension NotificationsSettingsTableViewController { + func setUpUI() { view.backgroundColor = RuuviColor.ruuviPrimary setUpTableView() } - fileprivate func setUpTableView() { + func setUpTableView() { tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 120 tableView.sectionFooterHeight = UITableView.automaticDimension @@ -58,25 +60,27 @@ extension NotificationsSettingsTableViewController { ) } - fileprivate func updateUI() { + func updateUI() { if isViewLoaded { - DispatchQueue.main.async(execute: { [weak self] in + DispatchQueue.main.async { [weak self] in self?.tableView.reloadData() - }) + } } } } - // MARK: - UITableViewDataSource -extension NotificationsSettingsTableViewController { +// MARK: - UITableViewDataSource - override func tableView(_ tableView: UITableView, - numberOfRowsInSection section: Int) -> Int { - return viewModels.count +extension NotificationsSettingsTableViewController { + override func tableView(_: UITableView, + numberOfRowsInSection _: Int) -> Int + { + viewModels.count } override func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { + cellForRowAt indexPath: IndexPath) -> UITableViewCell + { let viewModel = viewModels[indexPath.row] switch viewModel.configType.value { case .plain: @@ -109,16 +113,17 @@ extension NotificationsSettingsTableViewController { default: return UITableViewCell() } - } - override func tableView(_ tableView: UITableView, - estimatedHeightForFooterInSection section: Int) -> CGFloat { - return 100 + override func tableView(_: UITableView, + estimatedHeightForFooterInSection _: Int) -> CGFloat + { + 100 } - override func tableView(_ tableView: UITableView, - viewForFooterInSection section: Int) -> UIView? { + override func tableView(_: UITableView, + viewForFooterInSection _: Int) -> UIView? + { let footerView = UIView() let footerTextView = RuuviLinkTextView( fullTextString: RuuviLocalization.settingsAlertsFooterDescription, @@ -133,9 +138,11 @@ extension NotificationsSettingsTableViewController { } // MARK: - UITableViewDelegate + extension NotificationsSettingsTableViewController { override func tableView(_ tableView: UITableView, - didSelectRowAt indexPath: IndexPath) { + didSelectRowAt indexPath: IndexPath) + { tableView.deselectRow(at: indexPath, animated: true) let viewModel = viewModels[indexPath.row] switch viewModel.settingsType.value { @@ -148,6 +155,7 @@ extension NotificationsSettingsTableViewController { } // MARK: - NotificationsSettingsSwitchCellDelegate + extension NotificationsSettingsTableViewController: NotificationsSettingsSwitchCellDelegate { func didToggleSwitch(isOn: Bool, sender: NotificationsSettingsSwitchCell) { if let indexPath = tableView.indexPath(for: sender) { diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift index fba531810..295fe464d 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift @@ -1,7 +1,6 @@ import UIKit class NotificationsSettingsTextCell: UITableViewCell { - private lazy var titleLabel: UILabel = { let label = UILabel() label.textColor = RuuviColor.ruuviMenuTextColor @@ -32,13 +31,15 @@ class NotificationsSettingsTextCell: UITableViewCell { }() override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) { + reuseIdentifier: String?) + { super.init(style: style, reuseIdentifier: reuseIdentifier) setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -47,14 +48,14 @@ class NotificationsSettingsTextCell: UITableViewCell { accessoryType = .disclosureIndicator let leftStack = UIStackView(arrangedSubviews: [ - titleLabel, subtitleLabel + titleLabel, subtitleLabel, ]) leftStack.spacing = 4 leftStack.distribution = .fillProportionally leftStack.axis = .vertical let fullStack = UIStackView(arrangedSubviews: [ - leftStack, valueLabel + leftStack, valueLabel, ]) fullStack.spacing = 4 fullStack.distribution = .fillProportionally @@ -67,7 +68,8 @@ class NotificationsSettingsTextCell: UITableViewCell { } } - // MARK: - SETTERS +// MARK: - SETTERS + extension NotificationsSettingsTextCell { func configure(title: String?, subtitle: String?, value: String?) { titleLabel.text = title diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Assembly/RuuviCloudModuleFactory.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Assembly/RuuviCloudModuleFactory.swift index 65c8980f5..f3ba4771c 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Assembly/RuuviCloudModuleFactory.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Assembly/RuuviCloudModuleFactory.swift @@ -1,6 +1,6 @@ -import UIKit -import RuuviService import RuuviLocal +import RuuviService +import UIKit protocol RuuviCloudModuleFactory { func create() -> RuuviCloudModuleInput diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudPresenter.swift index d23ef666d..1cb44deaf 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudPresenter.swift @@ -1,21 +1,21 @@ -import RuuviLocalization import Foundation -import UIKit -import RuuviService import RuuviLocal +import RuuviLocalization +import RuuviService +import UIKit class RuuviCloudPresenter: NSObject, RuuviCloudModuleInput { var viewController: UIViewController { - if let view = self.weakView { + if let view = weakView { return view } else { let view = RuuviCloudTableViewController() view.output = self - self.weakView = view + weakView = view return view } - } + private weak var weakView: UIViewController? var settings: RuuviLocalSettings! @@ -32,14 +32,14 @@ extension RuuviCloudPresenter: RuuviCloudViewOutput { } } -extension RuuviCloudPresenter { - fileprivate func configure() { +private extension RuuviCloudPresenter { + func configure() { if let view = weakView as? RuuviCloudTableViewController { view.viewModels = [ruuviCloudIsOn()] } } - fileprivate func ruuviCloudIsOn() -> RuuviCloudViewModel { + func ruuviCloudIsOn() -> RuuviCloudViewModel { let cloudMode = RuuviCloudViewModel() cloudMode.title = RuuviLocalization.Settings.Label.cloudMode cloudMode.boolean.value = settings.cloudModeEnabled diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewModel.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewModel.swift index b4be9bcbb..22e469ca9 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewModel.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewModel.swift @@ -4,5 +4,5 @@ class RuuviCloudViewModel: Identifiable { var id = UUID().uuidString var title: String? - var boolean: Observable = Observable() + var boolean: Observable = .init() } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift index bdff46585..93cfc8ad5 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift @@ -5,7 +5,6 @@ protocol RuuviCloudTableViewCellDelegate: NSObjectProtocol { } class RuuviCloudTableViewCell: UITableViewCell { - weak var delegate: RuuviCloudTableViewCellDelegate? private lazy var titleLabel: UILabel = { @@ -27,13 +26,15 @@ class RuuviCloudTableViewCell: UITableViewCell { }() override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) { + reuseIdentifier: String?) + { super.init(style: style, reuseIdentifier: reuseIdentifier) setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -70,10 +71,9 @@ class RuuviCloudTableViewCell: UITableViewCell { // MARK: - SETTERS extension RuuviCloudTableViewCell { - func configure(title: String?, value: Bool?) { titleLabel.text = title - if let value = value { + if let value { statusSwitch.setOn(value, animated: false) } else { statusSwitch.setOn(false, animated: false) diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift index ba2316210..2b1131af3 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift @@ -1,6 +1,6 @@ +import Foundation import RuuviLocalization import UIKit -import Foundation class RuuviCloudTableViewController: UITableViewController { var output: RuuviCloudViewOutput! @@ -14,7 +14,8 @@ class RuuviCloudTableViewController: UITableViewController { super.init(style: .grouped) } - required init?(coder aDecoder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -22,6 +23,7 @@ class RuuviCloudTableViewController: UITableViewController { } // MARK: - LIFECYCLE + extension RuuviCloudTableViewController { override func viewDidLoad() { super.viewDidLoad() @@ -37,40 +39,41 @@ extension RuuviCloudTableViewController { extension RuuviCloudTableViewController: RuuviCloudViewInput { func localize() { - self.title = RuuviLocalization.ruuviCloud + title = RuuviLocalization.ruuviCloud } } -extension RuuviCloudTableViewController { - fileprivate func setUpUI() { +private extension RuuviCloudTableViewController { + func setUpUI() { view.backgroundColor = RuuviColor.ruuviPrimary setUpTableView() } - fileprivate func setUpTableView() { + func setUpTableView() { tableView.sectionFooterHeight = UITableView.automaticDimension tableView.register(RuuviCloudTableViewCell.self, forCellReuseIdentifier: reuseIdentifier) } - fileprivate func updateUI() { + func updateUI() { if isViewLoaded { - DispatchQueue.main.async(execute: { [weak self] in + DispatchQueue.main.async { [weak self] in self?.tableView.reloadData() - }) + } } } } // MARK: - UITableViewDataSource -extension RuuviCloudTableViewController { - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return viewModels.count +extension RuuviCloudTableViewController { + override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { + viewModels.count } override func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { + cellForRowAt indexPath: IndexPath) -> UITableViewCell + { guard let cell = tableView.dequeueReusableCell( withIdentifier: reuseIdentifier, for: indexPath @@ -83,11 +86,11 @@ extension RuuviCloudTableViewController { return cell } - override func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat { - return 100 + override func tableView(_: UITableView, estimatedHeightForFooterInSection _: Int) -> CGFloat { + 100 } - override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { + override func tableView(_: UITableView, viewForFooterInSection _: Int) -> UIView? { let footerView = UIView() let footerLabel = UILabel() footerLabel.textColor = RuuviColor.ruuviTextColor @@ -101,6 +104,7 @@ extension RuuviCloudTableViewController { } // MARK: - RuuviCloudTableViewCellDelegate + extension RuuviCloudTableViewController: RuuviCloudTableViewCellDelegate { func didToggleSwitch(isOn: Bool, sender: RuuviCloudTableViewCell) { if let indexPath = tableView.indexPath(for: sender) { diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Assembly/Table/SelectionTableInitializer.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Assembly/Table/SelectionTableInitializer.swift index fce644557..0f1ce5f08 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Assembly/Table/SelectionTableInitializer.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Assembly/Table/SelectionTableInitializer.swift @@ -1,7 +1,7 @@ import UIKit class SelectionTableInitializer: NSObject { - @IBOutlet weak var viewController: SelectionTableViewController! + @IBOutlet var viewController: SelectionTableViewController! override func awakeFromNib() { super.awakeFromNib() diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionPresenter.swift index caf981f96..85b1ec4d1 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionPresenter.swift @@ -10,8 +10,10 @@ class SelectionPresenter { view.viewModel = viewModel } } + var output: SelectionModuleOutput? } + extension SelectionPresenter { func viewDidLoad() { view.temperatureUnit = settings.temperatureUnit @@ -19,6 +21,7 @@ extension SelectionPresenter { view.pressureUnit = settings.pressureUnit } } + extension SelectionPresenter: SelectionModuleInput { func configure(viewModel: SelectionViewModel, output: SelectionModuleOutput?) { self.viewModel = viewModel @@ -32,8 +35,9 @@ extension SelectionPresenter: SelectionModuleInput { extension SelectionPresenter: SelectionViewOutput { func viewDidSelect(itemAtIndex index: Int) { - guard let viewModel = viewModel, - viewModel.items.count > 0 else { + guard let viewModel, + viewModel.items.count > 0 + else { dismiss() return } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewCell.swift index 8b0a5ac2d..436b9bb21 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewCell.swift @@ -1,6 +1,5 @@ import UIKit class SelectionTableViewCell: UITableViewCell { - - @IBOutlet weak var nameLabel: UILabel! + @IBOutlet var nameLabel: UILabel! } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift index 8d71a8fe2..0f3a6462c 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift @@ -1,12 +1,12 @@ -import UIKit -import RuuviOntology import RuuviLocal import RuuviLocalization +import RuuviOntology +import UIKit class SelectionTableViewController: UITableViewController { var output: SelectionViewOutput! var settings: RuuviLocalSettings! - @IBOutlet weak var descriptionTextView: UITextView! + @IBOutlet var descriptionTextView: UITextView! var viewModel: SelectionViewModel? { didSet { @@ -36,6 +36,7 @@ class SelectionTableViewController: UITableViewController { } // MARK: - SelectionViewInput + extension SelectionTableViewController: SelectionViewInput { func localize() { tableView.reloadData() @@ -43,6 +44,7 @@ extension SelectionTableViewController: SelectionViewInput { } // MARK: - View lifecycle + extension SelectionTableViewController { override func viewDidLoad() { super.viewDidLoad() @@ -52,21 +54,24 @@ extension SelectionTableViewController { } // MARK: - UITableViewDataSource + extension SelectionTableViewController { - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return viewModel?.items.count ?? 0 + override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { + viewModel?.items.count ?? 0 } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let item = viewModel?.items[indexPath.row], let cell = tableView - .dequeueReusableCell(withIdentifier: cellReuseIdentifier, - for: indexPath) as? SelectionTableViewCell else { + .dequeueReusableCell(withIdentifier: cellReuseIdentifier, + for: indexPath) as? SelectionTableViewCell + else { return .init() } if viewModel?.unitSettingsType == .accuracy, - let item = item as? MeasurementAccuracyType { + let item = item as? MeasurementAccuracyType + { let titleProvider = MeasurementAccuracyTitles() let title = titleProvider.formattedTitle(type: item, settings: settings) switch viewModel?.measurementType { @@ -99,6 +104,7 @@ extension SelectionTableViewController { } // MARK: - UITableViewDelegate + extension SelectionTableViewController { override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) @@ -107,6 +113,7 @@ extension SelectionTableViewController { } // MARK: - Update UI + extension SelectionTableViewController { private func updateUI() { title = viewModel?.title @@ -123,7 +130,8 @@ extension SelectionTableViewController { } private func updateCellStyle(with title: String?, - cell: SelectionTableViewCell) { + cell: SelectionTableViewCell) + { if title == viewModel?.selection { cell.accessoryType = .checkmark cell.nameLabel.textColor = RuuviColor.ruuviMenuTextColor diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Assembly/Table/UnitSettingsTableInitializer.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Assembly/Table/UnitSettingsTableInitializer.swift index 4c88f382b..bca131f79 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Assembly/Table/UnitSettingsTableInitializer.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Assembly/Table/UnitSettingsTableInitializer.swift @@ -1,7 +1,7 @@ import UIKit class UnitSettingsTableInitializer: NSObject { - @IBOutlet weak var viewController: UnitSettingsTableViewController! + @IBOutlet var viewController: UnitSettingsTableViewController! override func awakeFromNib() { super.awakeFromNib() diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift index a3a2a8a5d..45ff547ce 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift @@ -1,8 +1,8 @@ import Foundation -import RuuviOntology import RuuviLocal -import RuuviService import RuuviLocalization +import RuuviOntology +import RuuviService class UnitSettingsPresenter { weak var view: UnitSettingsViewInput! @@ -22,6 +22,7 @@ class UnitSettingsPresenter { view.viewModel = viewModel } } + var output: UnitSettingsModuleOutput? deinit { @@ -33,6 +34,7 @@ class UnitSettingsPresenter { pressureAccuracyToken?.invalidate() } } + extension UnitSettingsPresenter: UnitSettingsModuleInput { func configure(viewModel: UnitSettingsViewModel, output: UnitSettingsModuleOutput?) { self.viewModel = viewModel @@ -86,8 +88,9 @@ extension UnitSettingsPresenter: SelectionModuleOutput { break } case .accuracy: - guard let viewModel = viewModel, - let item = item as? MeasurementAccuracyType else { + guard let viewModel, + let item = item as? MeasurementAccuracyType + else { return } switch viewModel.measurementType { @@ -110,7 +113,7 @@ extension UnitSettingsPresenter: SelectionModuleOutput { extension UnitSettingsPresenter { private func unitViewModel() -> SelectionViewModel? { - guard let viewModel = viewModel else { + guard let viewModel else { return nil } @@ -168,7 +171,7 @@ extension UnitSettingsPresenter { let selectionItems: [MeasurementAccuracyType] = [ .zero, .one, - .two + .two, ] return SelectionViewModel(title: accuracyTitle, @@ -185,17 +188,19 @@ extension UnitSettingsPresenter { .default .addObserver(forName: .TemperatureUnitDidChange, object: nil, - queue: .main) { [weak self] _ in - guard let sSelf = self else { return } - sSelf.view.temperatureUnit = sSelf.settings.temperatureUnit + queue: .main) + { [weak self] _ in + guard let sSelf = self else { return } + sSelf.view.temperatureUnit = sSelf.settings.temperatureUnit } temperatureAccuracyToken = NotificationCenter .default .addObserver(forName: .TemperatureAccuracyDidChange, object: nil, - queue: .main) { [weak self] _ in - guard let sSelf = self else { return } - sSelf.view.temperatureAccuracy = sSelf.settings.temperatureAccuracy + queue: .main) + { [weak self] _ in + guard let sSelf = self else { return } + sSelf.view.temperatureAccuracy = sSelf.settings.temperatureAccuracy } humidityUnitToken = NotificationCenter .default @@ -203,36 +208,36 @@ extension UnitSettingsPresenter { object: nil, queue: .main, using: { [weak self] _ in - guard let sSelf = self else { return } - sSelf.view.humidityUnit = sSelf.settings.humidityUnit - }) + guard let sSelf = self else { return } + sSelf.view.humidityUnit = sSelf.settings.humidityUnit + }) humidityAccuracyToken = NotificationCenter .default .addObserver(forName: .HumidityAccuracyDidChange, object: nil, queue: .main, using: { [weak self] _ in - guard let sSelf = self else { return } - sSelf.view.humidityAccuracy = sSelf.settings.humidityAccuracy - }) + guard let sSelf = self else { return } + sSelf.view.humidityAccuracy = sSelf.settings.humidityAccuracy + }) pressureUnitToken = NotificationCenter .default .addObserver(forName: .PressureUnitDidChange, object: nil, queue: .main, using: { [weak self] _ in - guard let sSelf = self else { return } - sSelf.view.pressureUnit = sSelf.settings.pressureUnit - }) + guard let sSelf = self else { return } + sSelf.view.pressureUnit = sSelf.settings.pressureUnit + }) pressureAccuracyToken = NotificationCenter .default .addObserver(forName: .PressureUnitAccuracyChange, object: nil, queue: .main, using: { [weak self] _ in - guard let sSelf = self else { return } - sSelf.view.pressureAccuracy = sSelf.settings.pressureAccuracy - }) + guard let sSelf = self else { return } + sSelf.view.pressureAccuracy = sSelf.settings.pressureAccuracy + }) } private func updateUnits() { diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Router/UnitSettingsRouter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Router/UnitSettingsRouter.swift index 9c993f53b..6d6eb9487 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Router/UnitSettingsRouter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Router/UnitSettingsRouter.swift @@ -12,8 +12,8 @@ class UnitSettingsRouter: UnitSettingsRouterInput { try! transitionHandler .forStoryboard(factory: factory, to: SelectionModuleInput.self) .to(preferred: .navigation(style: .push)) - .then({ module in + .then { module in module.configure(viewModel: viewModel, output: output) - }) + } } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewCell.swift index 2e7fcdaad..7e46b7feb 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewCell.swift @@ -1,6 +1,6 @@ import UIKit class UnitSettingsTableViewCell: UITableViewCell { - @IBOutlet weak var titleLbl: UILabel! - @IBOutlet weak var valueLbl: UILabel! + @IBOutlet var titleLbl: UILabel! + @IBOutlet var valueLbl: UILabel! } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift index 734f4de5f..6b23c4ac4 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift @@ -1,13 +1,13 @@ -import UIKit -import RuuviOntology import RuuviLocal import RuuviLocalization +import RuuviOntology +import UIKit class UnitSettingsTableViewController: UITableViewController { var output: UnitSettingsViewOutput! var settings: RuuviLocalSettings! - @IBOutlet weak var descriptionTextView: UITextView! + @IBOutlet var descriptionTextView: UITextView! var viewModel: UnitSettingsViewModel? { didSet { @@ -55,6 +55,7 @@ class UnitSettingsTableViewController: UITableViewController { } // MARK: - SelectionViewInput + extension UnitSettingsTableViewController: UnitSettingsViewInput { func localize() { tableView.reloadData() @@ -62,6 +63,7 @@ extension UnitSettingsTableViewController: UnitSettingsViewInput { } // MARK: - View lifecycle + extension UnitSettingsTableViewController { override func viewDidLoad() { super.viewDidLoad() @@ -71,9 +73,10 @@ extension UnitSettingsTableViewController { } // MARK: - UITableViewDataSource + extension UnitSettingsTableViewController { - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return 2 + override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { + 2 } // swiftlint:disable:next cyclomatic_complexity @@ -129,14 +132,16 @@ extension UnitSettingsTableViewController { } // MARK: - UITableViewDelegate + extension UnitSettingsTableViewController { override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) - output.viewDidSelect(type: indexPath.row == 0 ? .unit :.accuracy) + output.viewDidSelect(type: indexPath.row == 0 ? .unit : .accuracy) } } // MARK: - Update UI + extension UnitSettingsTableViewController { private func updateUI() { title = viewModel?.title diff --git a/station/Classes/Presentation/Modules/Share/Assembly/ShareConfigurator.swift b/station/Classes/Presentation/Modules/Share/Assembly/ShareConfigurator.swift index bab51a1dc..3b6d0a0fd 100644 --- a/station/Classes/Presentation/Modules/Share/Assembly/ShareConfigurator.swift +++ b/station/Classes/Presentation/Modules/Share/Assembly/ShareConfigurator.swift @@ -1,7 +1,7 @@ import Foundation -import RuuviService import RuuviPresenters import RuuviReactor +import RuuviService class ShareConfigurator { func configure(view: ShareViewController) { diff --git a/station/Classes/Presentation/Modules/Share/Assembly/ShareInitializer.swift b/station/Classes/Presentation/Modules/Share/Assembly/ShareInitializer.swift index 01dfe9e38..a0bad98a0 100644 --- a/station/Classes/Presentation/Modules/Share/Assembly/ShareInitializer.swift +++ b/station/Classes/Presentation/Modules/Share/Assembly/ShareInitializer.swift @@ -1,7 +1,7 @@ import UIKit class ShareInitializer: NSObject { - @IBOutlet weak var viewController: ShareViewController! + @IBOutlet var viewController: ShareViewController! override func awakeFromNib() { super.awakeFromNib() diff --git a/station/Classes/Presentation/Modules/Share/Presenter/ShareModuleOutput.swift b/station/Classes/Presentation/Modules/Share/Presenter/ShareModuleOutput.swift index 666fe48f9..2a36d6ca4 100644 --- a/station/Classes/Presentation/Modules/Share/Presenter/ShareModuleOutput.swift +++ b/station/Classes/Presentation/Modules/Share/Presenter/ShareModuleOutput.swift @@ -1,2 +1 @@ -protocol ShareModuleOutput: AnyObject { -} +protocol ShareModuleOutput: AnyObject {} diff --git a/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift b/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift index 2474db52c..8db83dc48 100644 --- a/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift +++ b/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift @@ -1,11 +1,11 @@ -import RuuviLocalization import Foundation import Future -import UIKit -import RuuviService +import RuuviLocalization import RuuviOntology import RuuviPresenters import RuuviReactor +import RuuviService +import UIKit class SharePresenter { weak var view: ShareViewInput! @@ -22,6 +22,7 @@ class SharePresenter { fetchShared() } } + private let maxShareCount: Int = 10 private var viewModel: ShareViewModel! { didSet { @@ -35,16 +36,19 @@ class SharePresenter { ruuviTagToken?.invalidate() } } + // MARK: - ShareViewOutput + extension SharePresenter: ShareViewOutput { func viewDidLoad() { startObservingRuuviTag() } func viewDidTapSendButton(email: String?) { - guard let email = email, + guard let email, !email.isEmpty, - isValidEmail(email) else { + isValidEmail(email) + else { view.showInvalidEmail() return } @@ -82,8 +86,9 @@ extension SharePresenter: ShareViewOutput { } func viewDidTapUnshareEmail(_ email: String?) { - guard let email = email, - !email.isEmpty else { + guard let email, + !email.isEmpty + else { return } let title: String? = nil @@ -91,14 +96,15 @@ extension SharePresenter: ShareViewOutput { let confirmActionTitle = RuuviLocalization.yes let cancelActionTitle = RuuviLocalization.no let confirmAction = UIAlertAction(title: confirmActionTitle, - style: .default) { [weak self] (_) in + style: .default) + { [weak self] _ in self?.unshareTag(email) } let cancleAction = UIAlertAction(title: cancelActionTitle, style: .cancel, handler: nil) - let actions = [ confirmAction, cancleAction ] + let actions = [confirmAction, cancleAction] let alertViewModel = AlertViewModel(title: title, message: message, style: .alert, @@ -106,7 +112,9 @@ extension SharePresenter: ShareViewOutput { alertPresenter.showAlert(alertViewModel) } } + // MARK: - ShareModuleInput + extension SharePresenter: ShareModuleInput { func configure(sensor: RuuviTagSensor) { viewModel = ShareViewModel(maxCount: maxShareCount) @@ -117,23 +125,25 @@ extension SharePresenter: ShareModuleInput { router.dismiss(completion: nil) } } + // MARK: - Private -extension SharePresenter { +extension SharePresenter { // swiftlint:disable switch_case_alignment private func startObservingRuuviTag() { ruuviTagToken?.invalidate() - ruuviTagToken = ruuviReactor.observe { [weak self] (change) in + ruuviTagToken = ruuviReactor.observe { [weak self] change in switch change { - case .update(let sensor): - if (sensor.luid?.any != nil && - sensor.luid?.any == self?.sensor.luid?.any) - || - (sensor.macId?.any != nil && - sensor.macId?.any == self?.sensor.macId?.any) { - self?.sensor = sensor - } - default: return + case let .update(sensor): + if (sensor.luid?.any != nil && + sensor.luid?.any == self?.sensor.luid?.any) + || + (sensor.macId?.any != nil && + sensor.macId?.any == self?.sensor.macId?.any) + { + self?.sensor = sensor + } + default: return } } } @@ -151,7 +161,8 @@ extension SharePresenter { if let shareable = shareableSensors .first(where: { $0.id == sSelf.sensor.id - }) { + }) + { guard shareable.canShare else { return } @@ -194,4 +205,5 @@ extension SharePresenter { return emailPred.evaluate(with: email) } } + // swiftlint:enable switch_case_alignment diff --git a/station/Classes/Presentation/Modules/Share/Router/ShareRouterInput.swift b/station/Classes/Presentation/Modules/Share/Router/ShareRouterInput.swift index 3b245aedd..032ac6478 100644 --- a/station/Classes/Presentation/Modules/Share/Router/ShareRouterInput.swift +++ b/station/Classes/Presentation/Modules/Share/Router/ShareRouterInput.swift @@ -3,6 +3,7 @@ import Foundation protocol ShareRouterInput { func dismiss(completion: (() -> Void)?) } + extension ShareRouterInput { func dismiss() { dismiss(completion: nil) diff --git a/station/Classes/Presentation/Modules/Share/View/Cells/ShareDescriptionTableViewCell.swift b/station/Classes/Presentation/Modules/Share/View/Cells/ShareDescriptionTableViewCell.swift index 07a7ac39e..00cbb0d52 100644 --- a/station/Classes/Presentation/Modules/Share/View/Cells/ShareDescriptionTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Share/View/Cells/ShareDescriptionTableViewCell.swift @@ -1,6 +1,6 @@ import UIKit class ShareDescriptionTableViewCell: UITableViewCell { - @IBOutlet weak var sharingDisabledLabel: UILabel! - @IBOutlet weak var descriptionLabel: UILabel! + @IBOutlet var sharingDisabledLabel: UILabel! + @IBOutlet var descriptionLabel: UILabel! } diff --git a/station/Classes/Presentation/Modules/Share/View/Cells/ShareEmailInputTableViewCell.swift b/station/Classes/Presentation/Modules/Share/View/Cells/ShareEmailInputTableViewCell.swift index abc487960..a502bc89c 100644 --- a/station/Classes/Presentation/Modules/Share/View/Cells/ShareEmailInputTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Share/View/Cells/ShareEmailInputTableViewCell.swift @@ -1,5 +1,5 @@ import UIKit class ShareEmailInputTableViewCell: UITableViewCell { - @IBOutlet weak var emailTextField: UITextField! + @IBOutlet var emailTextField: UITextField! } diff --git a/station/Classes/Presentation/Modules/Share/View/Cells/ShareEmailTableViewCell.swift b/station/Classes/Presentation/Modules/Share/View/Cells/ShareEmailTableViewCell.swift index 2d09ddafe..f4ae7987b 100644 --- a/station/Classes/Presentation/Modules/Share/View/Cells/ShareEmailTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Share/View/Cells/ShareEmailTableViewCell.swift @@ -2,13 +2,14 @@ import UIKit protocol ShareEmailTableViewCellDelegate: AnyObject { func didTapUnshare(for email: String) } + class ShareEmailTableViewCell: UITableViewCell { - @IBOutlet weak var emailLabel: UILabel! - @IBOutlet weak var unshareButton: UIButton! + @IBOutlet var emailLabel: UILabel! + @IBOutlet var unshareButton: UIButton! weak var delegate: ShareEmailTableViewCellDelegate? - @IBAction func didTapUnshareButton(_ sender: UIButton) { + @IBAction func didTapUnshareButton(_: UIButton) { guard let email = emailLabel.text else { return } diff --git a/station/Classes/Presentation/Modules/Share/View/Cells/ShareSendButtonTableViewCell.swift b/station/Classes/Presentation/Modules/Share/View/Cells/ShareSendButtonTableViewCell.swift index 3f26be417..7ffdef482 100644 --- a/station/Classes/Presentation/Modules/Share/View/Cells/ShareSendButtonTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Share/View/Cells/ShareSendButtonTableViewCell.swift @@ -1,5 +1,5 @@ import UIKit class ShareSendButtonTableViewCell: UITableViewCell { - @IBOutlet weak var sendButton: UIButton! + @IBOutlet var sendButton: UIButton! } diff --git a/station/Classes/Presentation/Modules/Share/View/ShareViewModel.swift b/station/Classes/Presentation/Modules/Share/View/ShareViewModel.swift index aefb5ff3f..b8b563ae6 100644 --- a/station/Classes/Presentation/Modules/Share/View/ShareViewModel.swift +++ b/station/Classes/Presentation/Modules/Share/View/ShareViewModel.swift @@ -2,6 +2,6 @@ import Foundation struct ShareViewModel { let sharedEmails: Observable<[String]?> = .init() - let canShare: Observable = Observable(false) + let canShare: Observable = .init(false) let maxCount: Int } diff --git a/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift b/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift index bcd178f8e..b5503d5e7 100644 --- a/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift +++ b/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift @@ -22,11 +22,11 @@ extension ShareViewController { var title: ((Int, Int) -> String)? { switch self { case .description: - return nil + nil case .addFriend: - return { _, _ in RuuviLocalization.ShareViewController.AddFriend.title } + { _, _ in RuuviLocalization.ShareViewController.AddFriend.title } case .sharedEmails: - return { a, b in RuuviLocalization.ShareViewController.SharedEmails.title(a, b) } + { a, b in RuuviLocalization.ShareViewController.SharedEmails.title(a, b) } } } } @@ -37,7 +37,7 @@ class ShareViewController: UITableViewController { var viewModel: ShareViewModel! private lazy var backButton: UIButton = { - let button = UIButton() + let button = UIButton() button.tintColor = .label let buttonImage = RuuviAssets.backButtonImage button.setImage(buttonImage, for: .normal) @@ -49,6 +49,7 @@ class ShareViewController: UITableViewController { }() // MARK: - Lifecycle + override func viewDidLoad() { super.viewDidLoad() configureTableView() @@ -58,31 +59,32 @@ class ShareViewController: UITableViewController { // MARK: - TableView - override func numberOfSections(in tableView: UITableView) -> Int { + override func numberOfSections(in _: UITableView) -> Int { if let canShare = viewModel.canShare.value, canShare { if viewModel.sharedEmails.value?.isEmpty == true { - return 2 + 2 } else { - return 3 + 3 } } else { - return 1 + 1 } } - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + override func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { switch Section(value: section) { case .description: - return 1 + 1 case .addFriend: - return 2 + 2 case .sharedEmails: - return viewModel.sharedEmails.value?.count ?? 0 + viewModel.sharedEmails.value?.count ?? 0 } } - override func tableView(_ tableView: UITableView, - viewForHeaderInSection section: Int) -> UIView? { + override func tableView(_: UITableView, + viewForHeaderInSection section: Int) -> UIView? + { let section = Section(value: section) let headerView = UIView(color: .clear) let titleLabel = UILabel() @@ -92,7 +94,8 @@ class ShareViewController: UITableViewController { switch section { case .sharedEmails: if let count = viewModel.sharedEmails.value?.count, - let title = section.title { + let title = section.title + { titleLabel.text = title(count, viewModel.maxCount) } default: @@ -107,24 +110,24 @@ class ShareViewController: UITableViewController { } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell: UITableViewCell - switch Section(value: indexPath.section) { + let cell: UITableViewCell = switch Section(value: indexPath.section) { case .description: - cell = getDescriptionCell(tableView, indexPath: indexPath) + getDescriptionCell(tableView, indexPath: indexPath) case .addFriend: if indexPath.row == 0 { - cell = getAddFriendCell(tableView, indexPath: indexPath) + getAddFriendCell(tableView, indexPath: indexPath) } else { - cell = getButtonCell(tableView, indexPath: indexPath) + getButtonCell(tableView, indexPath: indexPath) } case .sharedEmails: - cell = getSharedEmailCell(tableView, indexPath: indexPath) + getSharedEmailCell(tableView, indexPath: indexPath) } return cell } } // MARK: - ShareViewInput + extension ShareViewController: ShareViewInput { func localize() { title = RuuviLocalization.ShareViewController.title @@ -135,7 +138,7 @@ extension ShareViewController: ShareViewInput { } func clearInput() { - let indexPath: IndexPath = IndexPath(row: 0, section: Section.addFriend.rawValue) + let indexPath = IndexPath(row: 0, section: Section.addFriend.rawValue) guard let cell = tableView.cellForRow(at: indexPath) as? ShareEmailInputTableViewCell else { return } @@ -163,22 +166,26 @@ extension ShareViewController: ShareViewInput { ) } } + extension ShareViewController: ShareEmailTableViewCellDelegate { func didTapUnshare(for email: String) { output.viewDidTapUnshareEmail(email) } } + extension ShareViewController: UITextFieldDelegate { - func textFieldDidBeginEditing(_ textField: UITextField) { + func textFieldDidBeginEditing(_: UITextField) { tableView.scrollToBottom() } - func textFieldShouldReturn(_ textField: UITextField) -> Bool { + + func textFieldShouldReturn(_: UITextField) -> Bool { view.endEditing(true) return true } } // MARK: - Private + extension ShareViewController { func configureTableView() { tableView.sectionHeaderHeight = UITableView.automaticDimension @@ -225,10 +232,11 @@ extension ShareViewController { return cell } - @objc private func didTapSendButton(_ sender: UIButton) { + @objc private func didTapSendButton(_: UIButton) { guard let cell = tableView.cellForRow(at: IndexPath(row: 0, section: Section.addFriend.rawValue)) - as? ShareEmailInputTableViewCell else { + as? ShareEmailInputTableViewCell + else { return } cell.emailTextField.endEditing(true) @@ -249,19 +257,19 @@ extension ShareViewController { navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backBarButtonItemView) } - @objc fileprivate func backButtonDidTap() { + @objc private func backButtonDidTap() { _ = navigationController?.popViewController(animated: true) } } extension UITableView { func scrollToBottom() { - let numberOfSections = self.numberOfSections + let numberOfSections = numberOfSections if numberOfSections > 0 { - let numberOfRows = self.numberOfRows(inSection: numberOfSections - 1) + let numberOfRows = numberOfRows(inSection: numberOfSections - 1) if numberOfRows > 0 { - let indexPath = IndexPath(row: numberOfRows - 1, section: (numberOfSections - 1)) - self.scrollToRow(at: indexPath, at: .bottom, animated: true) + let indexPath = IndexPath(row: numberOfRows - 1, section: numberOfSections - 1) + scrollToRow(at: indexPath, at: .bottom, animated: true) } } } diff --git a/station/Classes/Presentation/Modules/SignIn/Assembly/SignInModuleFactory.swift b/station/Classes/Presentation/Modules/SignIn/Assembly/SignInModuleFactory.swift index defc76b3f..cec60c0eb 100644 --- a/station/Classes/Presentation/Modules/SignIn/Assembly/SignInModuleFactory.swift +++ b/station/Classes/Presentation/Modules/SignIn/Assembly/SignInModuleFactory.swift @@ -1,10 +1,10 @@ import Foundation import RuuviCloud -import RuuviService -import RuuviUser -import RuuviPresenters import RuuviDaemon import RuuviLocal +import RuuviPresenters +import RuuviService +import RuuviUser protocol SignInModuleFactory: AnyObject { func create() -> SignInViewController diff --git a/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift b/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift index a4d568535..770658e19 100644 --- a/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift +++ b/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift @@ -1,15 +1,15 @@ -import RuuviLocalization +import FirebaseMessaging import Foundation import Future import RuuviCloud -import RuuviService -import RuuviUser -import RuuviPresenters import RuuviDaemon -import FirebaseMessaging import RuuviLocal -import WidgetKit +import RuuviLocalization +import RuuviPresenters +import RuuviService +import RuuviUser import UIKit +import WidgetKit class SignInPresenter: NSObject { enum State { @@ -44,7 +44,9 @@ class SignInPresenter: NSObject { NotificationCenter.default.removeObserver(self) } } + // MARK: - SignInViewOutput + extension SignInPresenter: SignInViewOutput { func viewDidLoad() { syncViewModel() @@ -65,7 +67,7 @@ extension SignInPresenter: SignInViewOutput { } func viewDidTapRequestCodeButton(for email: String?) { - guard let email = email, isValidEmail(email) else { + guard let email, isValidEmail(email) else { view.showInvalidEmailEntered() return } @@ -88,6 +90,7 @@ extension SignInPresenter: SignInViewOutput { } // MARK: - SignInModuleInput + extension SignInPresenter: SignInModuleInput { func configure(with state: SignInPresenter.State, output: SignInModuleOutput?) { self.output = output @@ -100,15 +103,16 @@ extension SignInPresenter: SignInModuleInput { } // MARK: - Private + extension SignInPresenter { @objc private func syncViewModel() { viewModel = SignInViewModel() switch state { case .enterEmail: viewModel.showVerficationScreen.value = false - case .enterVerificationCode(let code): + case let .enterVerificationCode(code): viewModel.showVerficationScreen.value = true - if let code = code { + if let code { processCode(code) } case .isSyncing: @@ -117,7 +121,7 @@ extension SignInPresenter { } private func isValidEmail(_ email: String?) -> Bool { - guard let email = email else { + guard let email else { return false } let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}" @@ -134,7 +138,7 @@ extension SignInPresenter { sSelf.ruuviUser.email = email sSelf.viewModel.showVerficationScreen.value = true sSelf.state = .enterVerificationCode(nil) - }, failure: { [weak self] (error) in + }, failure: { [weak self] error in self?.errorPresenter.present(error: error) }, completion: { [weak self] in self?.activityPresenter.dismiss() @@ -175,7 +179,7 @@ extension SignInPresenter { sSelf.view.showFailedToGetRequestedEmail() sSelf.activityPresenter.dismiss() } - }, failure: { [weak self] (error) in + }, failure: { [weak self] error in self?.activityPresenter.dismiss() self?.view.showInvalidTokenEntered() self?.errorPresenter.present(error: error) @@ -188,13 +192,14 @@ extension SignInPresenter { .addObserver(forName: .DidOpenWithUniversalLink, object: nil, queue: .main, - using: { [weak self] (notification) in - guard let self = self, - let userInfo = notification.userInfo else { - return - } - self.processLink(userInfo) - }) + using: { [weak self] notification in + guard let self, + let userInfo = notification.userInfo + else { + return + } + processLink(userInfo) + }) } private func startObservingAppState() { @@ -236,10 +241,11 @@ extension SignInPresenter { guard let path = userInfo["path"] as? UniversalLinkType, path == .verify, let code = userInfo["token"] as? String, - !code.isEmpty else { + !code.isEmpty + else { return } - self.processCode(code) + processCode(code) default: break } @@ -248,9 +254,9 @@ extension SignInPresenter { private func processCode(_ code: String) { view.fromDeepLink = true viewModel.inputText.value = code - DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(750), execute: { [weak self] in + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(750)) { [weak self] in self?.verify(code) - }) + } } private func reloadWidgets() { diff --git a/station/Classes/Presentation/Modules/SignIn/Router/SignInRouter.swift b/station/Classes/Presentation/Modules/SignIn/Router/SignInRouter.swift index 3608d17bc..04025894d 100644 --- a/station/Classes/Presentation/Modules/SignIn/Router/SignInRouter.swift +++ b/station/Classes/Presentation/Modules/SignIn/Router/SignInRouter.swift @@ -11,7 +11,8 @@ class SignInRouter: SignInRouterInput { func popViewController(animated: Bool, completion: (() -> Void)?) { if let navigationController = transitionHandler.navigationController, - navigationController.viewControllers.count > 1 { + navigationController.viewControllers.count > 1 + { // There is at least one view controller that can be popped navigationController.popViewController(animated: animated) } else { diff --git a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Assembly/SignInBenefitsModuleFactory.swift b/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Assembly/SignInBenefitsModuleFactory.swift index b0de9dcc6..a1a1523ba 100644 --- a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Assembly/SignInBenefitsModuleFactory.swift +++ b/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Assembly/SignInBenefitsModuleFactory.swift @@ -6,7 +6,6 @@ protocol SignInBenefitsModuleFactory: AnyObject { class SignInPromoModuleFactoryImpl: SignInBenefitsModuleFactory { func create() -> SignInBenefitsViewController { - let view = SignInBenefitsViewController() let router = SignInBenefitsRouter() let presenter = SignInBenefitsPresenter() diff --git a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsPresenter.swift b/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsPresenter.swift index ff7183dba..c1fcc1f53 100644 --- a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsPresenter.swift +++ b/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsPresenter.swift @@ -5,7 +5,9 @@ class SignInBenefitsPresenter: NSObject { var output: SignInBenefitsModuleOutput? var router: SignInBenefitsRouterInput! } + // MARK: - SignInViewOutput + extension SignInBenefitsPresenter: SignInBenefitsViewOutput { func viewDidLoad() { // No op. @@ -21,6 +23,7 @@ extension SignInBenefitsPresenter: SignInBenefitsViewOutput { } // MARK: - SignInPromoModuleInput + extension SignInBenefitsPresenter: SignInBenefitsModuleInput { func configure(output: SignInBenefitsModuleOutput?) { self.output = output @@ -34,22 +37,22 @@ extension SignInBenefitsPresenter: SignInBenefitsModuleInput { extension SignInBenefitsPresenter: SignInModuleOutput { func signIn(module: SignInModuleInput, didSuccessfulyLogin sender: Any?) { module.dismiss(completion: { [weak self] in - guard let self = self else { return } - self.output?.signIn(module: self, didSuccessfulyLogin: sender) + guard let self else { return } + output?.signIn(module: self, didSuccessfulyLogin: sender) }) } func signIn(module: SignInModuleInput, didCloseSignInWithoutAttempt sender: Any?) { module.dismiss(completion: { [weak self] in - guard let self = self else { return } - self.output?.signIn(module: self, didCloseSignInWithoutAttempt: sender) + guard let self else { return } + output?.signIn(module: self, didCloseSignInWithoutAttempt: sender) }) } func signIn(module: SignInModuleInput, didSelectUseWithoutAccount sender: Any?) { module.dismiss(completion: { [weak self] in - guard let self = self else { return } - self.output?.signIn(module: self, didSelectUseWithoutAccount: sender) + guard let self else { return } + output?.signIn(module: self, didSelectUseWithoutAccount: sender) }) } } diff --git a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift b/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift index c00ba1137..b231109b5 100644 --- a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift +++ b/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift @@ -1,9 +1,8 @@ -import RuuviLocalization import Foundation +import RuuviLocalization import UIKit class SignInBenefitsViewController: UIViewController, SignInBenefitsViewInput { - // Configuration var output: SignInBenefitsViewOutput? @@ -94,10 +93,10 @@ class SignInBenefitsViewController: UIViewController, SignInBenefitsViewInput { label.font = UIFont.Muli(.regular, size: UIDevice.isiPhoneSE() ? 16 : 18) return label }() - } // MARK: - VIEW LIFE CYCLE + extension SignInBenefitsViewController { override func viewDidLoad() { super.viewDidLoad() @@ -111,7 +110,7 @@ extension SignInBenefitsViewController { } extension SignInBenefitsViewController { - @objc fileprivate func handleCloseButtonTap() { + @objc private func handleCloseButtonTap() { output?.viewDidTapClose() } @@ -127,6 +126,7 @@ extension SignInBenefitsViewController { } // MARK: - PRIVATE UI SETUP + extension SignInBenefitsViewController { private func setUpUI() { setUpNavBarView() @@ -134,7 +134,7 @@ extension SignInBenefitsViewController { setUpSignInPromoView() } - fileprivate func setUpNavBarView() { + private func setUpNavBarView() { navigationItem.leftBarButtonItem = closeButton } @@ -156,7 +156,7 @@ extension SignInBenefitsViewController { container.centerInSuperview() titleStack = UIStackView(arrangedSubviews: [ - titleLabel, subtitleLabel + titleLabel, subtitleLabel, ]) titleStack.axis = .vertical titleStack.distribution = .fillProportionally @@ -164,11 +164,11 @@ extension SignInBenefitsViewController { container.addSubview(titleStack) titleStack.anchor(top: container.safeTopAnchor, - leading: container.safeLeftAnchor, - bottom: nil, - trailing: container.safeRightAnchor, - padding: .init(top: 0, left: !UIDevice.isTablet() ? 20 : 80, - bottom: 0, right: !UIDevice.isTablet() ? 20 : 80)) + leading: container.safeLeftAnchor, + bottom: nil, + trailing: container.safeRightAnchor, + padding: .init(top: 0, left: !UIDevice.isTablet() ? 20 : 80, + bottom: 0, right: !UIDevice.isTablet() ? 20 : 80)) container.addSubview(featuresLabel) featuresLabel.anchor( @@ -207,13 +207,13 @@ extension SignInBenefitsViewController { container.addSubview(signInOptionalLabel) signInOptionalLabel.anchor(top: continueButton.bottomAnchor, - leading: container.safeLeftAnchor, - bottom: nil, - trailing: container.safeRightAnchor, - padding: .init(top: UIDevice.isiPhoneSE() ? 6 : 10, - left: 30, - bottom: 0, - right: 30)) + leading: container.safeLeftAnchor, + bottom: nil, + trailing: container.safeRightAnchor, + padding: .init(top: UIDevice.isiPhoneSE() ? 6 : 10, + left: 30, + bottom: 0, + right: 30)) signInOptionalLabel.bottomAnchor.constraint( lessThanOrEqualTo: container.bottomAnchor, constant: -30 @@ -223,13 +223,13 @@ extension SignInBenefitsViewController { extension SignInBenefitsViewController { private func prepareFeatures() -> String { - return [ + [ RuuviLocalization.cloudStoredOwnerships, RuuviLocalization.cloudStoredNames, RuuviLocalization.cloudStoredAlerts, RuuviLocalization.cloudStoredBackgrounds, RuuviLocalization.cloudStoredCalibration, - RuuviLocalization.cloudStoredSharing + RuuviLocalization.cloudStoredSharing, ].joined(separator: "\n") } diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeTextField.swift b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeTextField.swift index dccde6148..15440df25 100644 --- a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeTextField.swift +++ b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeTextField.swift @@ -9,5 +9,4 @@ class RuuviCodeTextField: UITextField { text = "" previousEntry?.becomeFirstResponder() } - } diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeView.swift b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeView.swift index ca8223dff..9861d7735 100644 --- a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeView.swift +++ b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeView.swift @@ -34,10 +34,11 @@ class RuuviCodeView: UIStackView { } // MARK: - Public methods + extension RuuviCodeView { // Fill the view with pasted code func autofill(with code: String?) { - guard let code = code else { + guard let code else { return } populateRuuviCodeFields(with: code) @@ -45,7 +46,7 @@ extension RuuviCodeView { // Returns entered code func ruuviCode() -> String { - return codeEntries.map({ $0.text ?? "" }).joined(separator: "") + codeEntries.map { $0.text ?? "" }.joined(separator: "") } // Activate last field if invalid code is entered @@ -57,6 +58,7 @@ extension RuuviCodeView { } // MARK: - Private methods + extension RuuviCodeView { private func setupSuper() { setupStackView() @@ -73,15 +75,15 @@ extension RuuviCodeView { } private func setupRuuviCodeFields() { - for index in 0.. 0 { codeEntries[0].layer.borderColor = activeBorderColor.cgColor @@ -109,7 +111,7 @@ extension RuuviCodeView { } private func populateRuuviCodeFields(with string: String) { - remainingStrStack = string.reversed().filter({ $0 != " " }).compactMap { String($0) } + remainingStrStack = string.reversed().filter { $0 != " " }.compactMap { String($0) } for textField in codeEntries { if let charToAdd = remainingStrStack.popLast() { textField.text = String(charToAdd).uppercased() @@ -128,6 +130,7 @@ extension RuuviCodeView { } // MARK: - Textfield Delegate + extension RuuviCodeView: UITextFieldDelegate { func textFieldDidBeginEditing(_ textField: UITextField) { textField.layer.borderColor = activeBorderColor.cgColor @@ -167,7 +170,7 @@ extension RuuviCodeView: UITextFieldDelegate { guard textField.previousEntry == nil || textField.previousEntry?.text != "" else { return false } - if range.length == 0 && code.isEmpty { + if range.length == 0, code.isEmpty { return false } else if range.length == 0 { textField.text = code.uppercased() diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift index 87c09cca8..63dbf3d60 100644 --- a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift +++ b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift @@ -6,7 +6,6 @@ protocol SignInVerifyViewDelegate: NSObjectProtocol { } class SignInVerifyView: UIView { - weak var delegate: SignInVerifyViewDelegate? override init(frame: CGRect) { @@ -14,7 +13,8 @@ class SignInVerifyView: UIView { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -51,6 +51,7 @@ class SignInVerifyView: UIView { iv.backgroundColor = .clear return iv }() + private var beaverImageViewTopAnchor: NSLayoutConstraint! } @@ -66,7 +67,7 @@ extension SignInVerifyView { container.fillSuperview() titleStack = UIStackView(arrangedSubviews: [ - titleLabel, subtitleLabel + titleLabel, subtitleLabel, ]) titleStack.axis = .vertical titleStack.distribution = .fillProportionally @@ -74,11 +75,11 @@ extension SignInVerifyView { container.addSubview(titleStack) titleStack.anchor(top: nil, - leading: container.safeLeftAnchor, - bottom: nil, - trailing: container.safeRightAnchor, - padding: .init(top: 0, left: !UIDevice.isTablet() ? 20 : 80, - bottom: 0, right: !UIDevice.isTablet() ? 20 : 80)) + leading: container.safeLeftAnchor, + bottom: nil, + trailing: container.safeRightAnchor, + padding: .init(top: 0, left: !UIDevice.isTablet() ? 20 : 80, + bottom: 0, right: !UIDevice.isTablet() ? 20 : 80)) titleStack.topAnchor.constraint( equalTo: container.safeTopAnchor ).isActive = true @@ -96,7 +97,6 @@ extension SignInVerifyView { } private func setUpBeaverView() { - let beaverContainerView = UIView(color: .clear) container.addSubview(beaverContainerView) @@ -117,7 +117,7 @@ extension SignInVerifyView { } extension SignInVerifyView { - override func touchesBegan(_ touches: Set, with event: UIEvent?) { + override func touchesBegan(_: Set, with _: UIEvent?) { endEditing(true) } } @@ -134,7 +134,7 @@ extension SignInVerifyView: RuuviCodeViewDelegate { extension SignInVerifyView { func updateMessage(with email: String?) { - guard let email = email else { return } + guard let email else { return } subtitleLabel.text = RuuviLocalization.SignIn.checkMailbox(email) } diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift index 362852cc2..a5a8f5af5 100644 --- a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift +++ b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift @@ -6,13 +6,13 @@ protocol SignInViewDelegate: NSObjectProtocol { } class SignInView: UIView { - override init(frame: CGRect) { super.init(frame: frame) setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -102,7 +102,7 @@ extension SignInView { container.fillSuperview() titleStack = UIStackView(arrangedSubviews: [ - titleLabel, subtitleLabel + titleLabel, subtitleLabel, ]) titleStack.axis = .vertical titleStack.distribution = .fillProportionally @@ -122,7 +122,7 @@ extension SignInView { private func setUpTextFieldView() { let textFieldStack = UIStackView(arrangedSubviews: [ - emailTextField, requestCodeButton + emailTextField, requestCodeButton, ]) textFieldStack.axis = .vertical textFieldStack.distribution = .fillEqually @@ -131,11 +131,11 @@ extension SignInView { container.addSubview(textFieldStack) textFieldStack.anchor(top: titleStack.bottomAnchor, - leading: container.safeLeftAnchor, - bottom: nil, - trailing: container.safeRightAnchor, - padding: .init(top: 30, left: !UIDevice.isTablet() ? 30 : 100, - bottom: 0, right: !UIDevice.isTablet() ? 30 : 100)) + leading: container.safeLeftAnchor, + bottom: nil, + trailing: container.safeRightAnchor, + padding: .init(top: 30, left: !UIDevice.isTablet() ? 30 : 100, + bottom: 0, right: !UIDevice.isTablet() ? 30 : 100)) textFieldStack.centerYInSuperview() container.addSubview(noPasswordLabel) @@ -152,7 +152,7 @@ extension SignInView { } extension SignInView { - override func touchesBegan(_ touches: Set, with event: UIEvent?) { + override func touchesBegan(_: Set, with _: UIEvent?) { emailTextField.resignFirstResponder() } } diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift b/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift index 84112bf27..7244d9405 100644 --- a/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift +++ b/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift @@ -1,9 +1,8 @@ -import RuuviLocalization import Foundation +import RuuviLocalization import UIKit class SignInViewController: UIViewController { - // Configuration var output: SignInViewOutput! @@ -61,10 +60,10 @@ class SignInViewController: UIViewController { // --------------------- private var shouldAvoidVerifying: Bool = false - } // MARK: - VIEW LIFE CYCLE + extension SignInViewController { override func viewDidLoad() { super.viewDidLoad() @@ -83,12 +82,12 @@ extension SignInViewController { } } -extension SignInViewController { - @objc fileprivate func handleBackButtonTap() { +private extension SignInViewController { + @objc func handleBackButtonTap() { output.viewDidTapBack() } - @objc fileprivate func handleUseWithoutAccountTap() { + @objc func handleUseWithoutAccountTap() { output.viewDidTapUseWithoutAccount() } @@ -97,20 +96,20 @@ extension SignInViewController { return } - view.bind(viewModel.showVerficationScreen) { [weak self] (_, verificationPage) in + view.bind(viewModel.showVerficationScreen) { [weak self] _, verificationPage in let showVerificationPage = GlobalHelpers.getBool(from: verificationPage) self?.signInVerifyView.alpha = showVerificationPage ? 1 : 0 self?.signInView.alpha = showVerificationPage ? 0 : 1 self?.useWithoutAccountButton.alpha = showVerificationPage ? 0 : 1 } - signInView.bind(viewModel.inputText) { (view, text) in + signInView.bind(viewModel.inputText) { view, text in if view.enteredEmail() != text { view.populateEmail(from: text) } } - signInVerifyView.bind(viewModel.inputText) { (view, text) in + signInVerifyView.bind(viewModel.inputText) { view, text in view.populate(from: text) } } @@ -144,7 +143,6 @@ extension SignInViewController: SignInViewInput { let alertVC = UIAlertController(title: nil, message: message, preferredStyle: .alert) alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) - } } @@ -157,7 +155,7 @@ extension SignInViewController: SignInViewDelegate { } extension SignInViewController: SignInVerifyViewDelegate { - func didFinishTypingCode(code: String, sender: SignInVerifyView) { + func didFinishTypingCode(code: String, sender _: SignInVerifyView) { if !shouldAvoidVerifying { output.viewDidTapEnterCodeManually(code: code) } @@ -165,6 +163,7 @@ extension SignInViewController: SignInVerifyViewDelegate { } // MARK: - PRIVATE UI SETUP + extension SignInViewController { private func setUpUI() { setUpNavBarView() @@ -189,16 +188,16 @@ extension SignInViewController { scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true } - fileprivate func setUpNavBarView() { + private func setUpNavBarView() { navigationItem.leftBarButtonItem = backButton } private func setUpSignInView() { scrollView.addSubview(signInView) signInView.anchor(top: scrollView.topAnchor, - leading: nil, - bottom: nil, - trailing: nil) + leading: nil, + bottom: nil, + trailing: nil) signInView.centerXInSuperview() signInView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true signInView.alpha = 1 @@ -213,7 +212,8 @@ extension SignInViewController { trailing: scrollView.trailingAnchor, size: .init( width: 0, - height: view.bounds.height)) + height: view.bounds.height + )) signInVerifyView.centerXInSuperview() signInVerifyView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true signInVerifyView.alpha = 0 diff --git a/station/Classes/Presentation/Modules/TagSettings/Assembly/TagSettingsModuleFactory.swift b/station/Classes/Presentation/Modules/TagSettings/Assembly/TagSettingsModuleFactory.swift index 3d9461e96..3c07c96d6 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Assembly/TagSettingsModuleFactory.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Assembly/TagSettingsModuleFactory.swift @@ -1,16 +1,16 @@ -import Foundation import BTKit -import RuuviStorage -import RuuviReactor -import RuuviLocal -import RuuviService -import RuuviUser +import Foundation import RuuviCore -import RuuviPresenters -import RuuviPool -import RuuviNotifier import RuuviDaemon +import RuuviLocal +import RuuviNotifier import RuuviOntology +import RuuviPool +import RuuviPresenters +import RuuviReactor +import RuuviService +import RuuviStorage +import RuuviUser import UIKit protocol TagSettingsModuleFactory { diff --git a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift index e77aacd01..8b9cead0b 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift @@ -1,26 +1,25 @@ -// swiftlint:disable file_length -import RuuviLocalization -import Foundation import BTKit -import UIKit +import Foundation import Future +import RuuviLocal +// swiftlint:disable file_length +import RuuviLocalization import RuuviOntology -import RuuviStorage import RuuviReactor -import RuuviLocal import RuuviService +import RuuviStorage +import UIKit #if canImport(RuuviServiceOwnership) -import RuuviServiceOwnership + import RuuviServiceOwnership #endif -import RuuviUser import RuuviCore -import RuuviPresenters -import RuuviPool -import RuuviNotifier import RuuviDaemon +import RuuviNotifier +import RuuviPool +import RuuviPresenters +import RuuviUser class TagSettingsPresenter: NSObject, TagSettingsModuleInput { - weak var view: TagSettingsViewInput! weak var output: TagSettingsModuleOutput? var router: TagSettingsRouterInput! @@ -52,6 +51,7 @@ class TagSettingsPresenter: NSObject, TagSettingsModuleInput { bindViewModel() } } + private var sensorSettings: SensorSettings? { didSet { syncOffsetCorrection() @@ -115,17 +115,17 @@ class TagSettingsPresenter: NSObject, TagSettingsModuleInput { func configure(ruuviTag: RuuviTagSensor, latestMeasurement: RuuviTagSensorRecord?, - sensorSettings: SensorSettings?) { - + sensorSettings: SensorSettings?) + { // TODO: - Check if this can be improved. - // Note:(Temporary solution) ViewModel should not depend on this. + // Note:(Temporary solution) ViewModel should not depend on this. let tagViewModel = TagSettingsViewModel() tagViewModel.isAuthorized.value = ruuviUser.isAuthorized - self.viewModel = tagViewModel + viewModel = tagViewModel self.ruuviTag = ruuviTag - self.lastMeasurement = latestMeasurement - if let sensorSettings = sensorSettings { + lastMeasurement = latestMeasurement + if let sensorSettings { self.sensorSettings = sensorSettings } else { self.sensorSettings = emptySensorSettings() @@ -157,6 +157,7 @@ class TagSettingsPresenter: NSObject, TagSettingsModuleInput { } // MARK: - TagSettingsViewOutput + extension TagSettingsPresenter: TagSettingsViewOutput { func viewDidLoad() { startSubscribeToBackgroundUploadProgressChanges() @@ -188,8 +189,9 @@ extension TagSettingsPresenter: TagSettingsViewOutput { @objc private func handleAppEnterForgroundState() { syncAllAlerts() if let keep = viewModel.keepConnection.value, - let connected = viewModel.isConnected.value { - if keep && !connected { + let connected = viewModel.isConnected.value + { + if keep, !connected { view.startKeepConnectionAnimatingDots() } } @@ -197,8 +199,9 @@ extension TagSettingsPresenter: TagSettingsViewOutput { @objc private func handleAppEnterBackgroundState() { if let keep = viewModel.keepConnection.value, - let connected = viewModel.isConnected.value { - if keep && !connected { + let connected = viewModel.isConnected.value + { + if keep, !connected { view.stopKeepConnectionAnimatingDots() } } @@ -217,7 +220,7 @@ extension TagSettingsPresenter: TagSettingsViewOutput { } func viewDidTriggerKeepConnection(isOn: Bool) { - if settings.cloudModeEnabled && ruuviTag.isCloud { + if settings.cloudModeEnabled, ruuviTag.isCloud { if isOn { view.showKeepConnectionCloudModeDialog() } else { @@ -407,6 +410,7 @@ extension TagSettingsPresenter: TagSettingsViewOutput { } // MARK: - SensorRemovalModuleOutput + extension TagSettingsPresenter: SensorRemovalModuleOutput { func sensorRemovalDidRemoveTag( module: SensorRemovalModuleInput, @@ -440,9 +444,10 @@ extension TagSettingsPresenter: SensorRemovalModuleOutput { } // MARK: - Private + extension TagSettingsPresenter { private func startMutedTillTimer() { - self.mutedTillTimer = Timer + mutedTillTimer = Timer .scheduledTimer( withTimeInterval: 5, repeats: true @@ -549,9 +554,10 @@ extension TagSettingsPresenter { ruuviTag.ownersPlan?.lowercased() != "basic" && ruuviTag.ownersPlan?.lowercased() != "free" - if (ruuviTag.name == ruuviTag.luid?.value - || ruuviTag.name == ruuviTag.macId?.value) - && !ruuviTag.isCloud { + if ruuviTag.name == ruuviTag.luid?.value + || ruuviTag.name == ruuviTag.macId?.value, + !ruuviTag.isCloud + { viewModel.name.value = nil } else { viewModel.name.value = ruuviTag.name @@ -628,14 +634,14 @@ extension TagSettingsPresenter { /// Sets the view model properties related to all alert type. private func syncAllAlerts() { - AlertType.allCases.forEach { (type) in + AlertType.allCases.forEach { type in syncAlerts(of: type) } } private func sync(temperature: AlertType, ruuviTag: RuuviTagSensor) { viewModel.temperatureAlertDescription.value = alertService.temperatureDescription(for: ruuviTag) - if case .temperature(let lower, let upper) = alertService.alert(for: ruuviTag, of: temperature) { + if case let .temperature(lower, upper) = alertService.alert(for: ruuviTag, of: temperature) { viewModel.isTemperatureAlertOn.value = true viewModel.temperatureLowerBound.value = Temperature(Double(lower), unit: .celsius) viewModel.temperatureUpperBound.value = Temperature(Double(upper), unit: .celsius) @@ -655,7 +661,7 @@ extension TagSettingsPresenter { viewModel.relativeHumidityAlertDescription.value = alertService.relativeHumidityDescription( for: ruuviTag ) - if case .relativeHumidity(let lower, let upper) = alertService.alert(for: ruuviTag, of: relativeHumidity) { + if case let .relativeHumidity(lower, upper) = alertService.alert(for: ruuviTag, of: relativeHumidity) { viewModel.isRelativeHumidityAlertOn.value = true // must multiply by 100 because it is fraction of one viewModel.relativeHumidityLowerBound.value = lower * 100.0 @@ -676,10 +682,10 @@ extension TagSettingsPresenter { private func sync(pressure: AlertType, ruuviTag: RuuviTagSensor) { viewModel.pressureAlertDescription.value = alertService.pressureDescription(for: ruuviTag) - if case .pressure(let lower, let upper) = alertService.alert(for: ruuviTag, of: pressure) { + if case let .pressure(lower, upper) = alertService.alert(for: ruuviTag, of: pressure) { viewModel.isPressureAlertOn.value = true viewModel.pressureLowerBound.value = Pressure(Double(lower), unit: .hectopascals) - viewModel.pressureUpperBound.value = Pressure(Double(upper), unit: .hectopascals) + viewModel.pressureUpperBound.value = Pressure(Double(upper), unit: .hectopascals) } else { viewModel.isPressureAlertOn.value = false if let pressureLowerBound = alertService.lowerPressure(for: ruuviTag) { @@ -694,10 +700,10 @@ extension TagSettingsPresenter { private func sync(signal: AlertType, ruuviTag: RuuviTagSensor) { viewModel.signalAlertDescription.value = alertService.signalDescription(for: ruuviTag) - if case .signal(let lower, let upper) = alertService.alert(for: ruuviTag, of: signal) { + if case let .signal(lower, upper) = alertService.alert(for: ruuviTag, of: signal) { viewModel.isSignalAlertOn.value = true viewModel.signalLowerBound.value = Double(lower) - viewModel.signalUpperBound.value = Double(upper) + viewModel.signalUpperBound.value = Double(upper) } else { viewModel.isSignalAlertOn.value = false if let signalLowerBound = alertService.lowerSignal(for: ruuviTag) { @@ -724,7 +730,7 @@ extension TagSettingsPresenter { private func sync(cloudConnection: AlertType, ruuviTag: RuuviTagSensor) { viewModel.cloudConnectionAlertDescription.value = alertService.cloudConnectionDescription(for: ruuviTag) - if case .cloudConnection(let unseenDuration) = alertService.alert( + if case let .cloudConnection(unseenDuration) = alertService.alert( for: ruuviTag, of: cloudConnection ) { viewModel.isCloudConnectionAlertOn.value = true @@ -756,40 +762,44 @@ extension TagSettingsPresenter { .default .addObserver(forName: .BackgroundPersistenceDidChangeBackground, object: nil, - queue: .main) { [weak self] notification in - - guard let sSelf = self else { return } - if let userInfo = notification.userInfo { - let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier - let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier - if (sSelf.ruuviTag.luid?.value != nil && sSelf.ruuviTag.luid?.value == luid?.value) - || (sSelf.ruuviTag.macId?.value != nil && sSelf.ruuviTag.macId?.value == macId?.value) { - sSelf.ruuviSensorPropertiesService.getImage(for: sSelf.ruuviTag) - .on(success: { [weak sSelf] image in - sSelf?.viewModel.background.value = image - }, failure: { [weak sSelf] error in - sSelf?.errorPresenter.present(error: error) - }) - } + queue: .main) + { [weak self] notification in + + guard let sSelf = self else { return } + if let userInfo = notification.userInfo { + let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier + let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier + if (sSelf.ruuviTag.luid?.value != nil && sSelf.ruuviTag.luid?.value == luid?.value) + || (sSelf.ruuviTag.macId?.value != nil && sSelf.ruuviTag.macId?.value == macId?.value) + { + sSelf.ruuviSensorPropertiesService.getImage(for: sSelf.ruuviTag) + .on(success: { [weak sSelf] image in + sSelf?.viewModel.background.value = image + }, failure: { [weak sSelf] error in + sSelf?.errorPresenter.present(error: error) + }) } } + } } private func startObservingRuuviTag() { ruuviTagToken?.invalidate() - ruuviTagToken = ruuviReactor.observe { [weak self] (change) in + ruuviTagToken = ruuviReactor.observe { [weak self] change in switch change { - case .insert(let sensor): + case let .insert(sensor): if (sensor.luid?.any != nil && sensor.luid?.any == self?.ruuviTag.luid?.any) - || (sensor.macId?.any != nil && sensor.macId?.any == self?.ruuviTag.macId?.any) { + || (sensor.macId?.any != nil && sensor.macId?.any == self?.ruuviTag.macId?.any) + { self?.ruuviTag = sensor } - case .update(let sensor): + case let .update(sensor): if (sensor.luid?.any != nil && sensor.luid?.any == self?.ruuviTag.luid?.any) - || (sensor.macId?.any != nil && sensor.macId?.any == self?.ruuviTag.macId?.any) { + || (sensor.macId?.any != nil && sensor.macId?.any == self?.ruuviTag.macId?.any) + { self?.ruuviTag = sensor } - case .error(let error): + case let .error(error): self?.errorPresenter.present(error: error) default: return @@ -799,21 +809,21 @@ extension TagSettingsPresenter { private func startObservingRuuviTagSensor(ruuviTag: RuuviTagSensor) { ruuviTagSensorRecordToken?.invalidate() - ruuviTagSensorRecordToken = ruuviReactor.observeLatest(ruuviTag, { - [weak self] (changes) in + ruuviTagSensorRecordToken = ruuviReactor.observeLatest(ruuviTag) { + [weak self] changes in switch changes { - case .update(let record): + case let .update(record): if let lastRecord = record { self?.lastMeasurement = lastRecord self?.viewModel.updateRecord(lastRecord) self?.processAlerts() } - case .error(let error): + case let .error(error): self?.errorPresenter.present(error: error) default: break } - }) + } } private func startObservingRuuviTagOwnerCheckResponse() { @@ -825,15 +835,16 @@ extension TagSettingsPresenter { .addObserver(forName: .RuuviTagOwnershipCheckDidEnd, object: nil, queue: .main, - using: { [weak self] (notification) in - guard let sSelf = self, - let userInfo = notification.userInfo, - let hasOwner = userInfo[RuuviTagOwnershipCheckResultKey.hasOwner] as? Bool, - !hasOwner else { - return - } - sSelf.view.showTagClaimDialog() - }) + using: { [weak self] notification in + guard let sSelf = self, + let userInfo = notification.userInfo, + let hasOwner = userInfo[RuuviTagOwnershipCheckResultKey.hasOwner] as? Bool, + !hasOwner + else { + return + } + sSelf.view.showTagClaimDialog() + }) } private func startScanningRuuviTag() { @@ -846,13 +857,13 @@ extension TagSettingsPresenter { guard !skip else { return } - advertisementToken = foreground.observe(self, uuid: luid.value, closure: { [weak self] (_, device) in + advertisementToken = foreground.observe(self, uuid: luid.value, closure: { [weak self] _, device in if let tag = device.ruuvi?.tag { self?.handleMeasurementPoint(tag: tag, luid: luid, source: .advertisement) } }) - heartbeatToken = background.observe(self, uuid: luid.value, closure: { [weak self] (_, device) in + heartbeatToken = background.observe(self, uuid: luid.value, closure: { [weak self] _, device in if let tag = device.ruuvi?.tag { self?.handleMeasurementPoint(tag: tag, luid: luid, source: .heartbeat) } @@ -861,10 +872,10 @@ extension TagSettingsPresenter { private func handleMeasurementPoint(tag: RuuviTag, luid: LocalIdentifier, - source: RuuviTagSensorRecordSource) { - + source: RuuviTagSensorRecordSource) + { // Trigger firmware aler dialog for DF3 tags. - if !firmwareUpdateDialogShown && tag.version < 5 { + if !firmwareUpdateDialogShown, tag.version < 5 { view.showFirmwareUpdateDialog() firmwareUpdateDialogShown = true } @@ -885,8 +896,9 @@ extension TagSettingsPresenter { } private func sync(device: RuuviTag, - luid: LocalIdentifier, - source: RuuviTagSensorRecordSource) { + luid _: LocalIdentifier, + source: RuuviTagSensorRecordSource) + { let record = RuuviTagSensorRecordStruct( luid: device.luid, date: device.date, @@ -978,17 +990,17 @@ extension TagSettingsPresenter { sensorSettingsToken?.invalidate() sensorSettingsToken = nil - sensorSettingsToken = ruuviReactor.observe(ruuviTag, { [weak self] change in + sensorSettingsToken = ruuviReactor.observe(ruuviTag) { [weak self] change in switch change { - case .insert(let sensorSettings): + case let .insert(sensorSettings): self?.sensorSettings = sensorSettings - case .update(let updateSensorSettings): + case let .update(updateSensorSettings): self?.sensorSettings = updateSensorSettings case .delete: self?.sensorSettings = self?.emptySensorSettings() default: break } - }) + } } private func startObservingSettingsChanges() { @@ -996,16 +1008,17 @@ extension TagSettingsPresenter { .default .addObserver(forName: .TemperatureUnitDidChange, object: nil, - queue: .main) { [weak self] _ in - self?.viewModel.temperatureUnit.value = self?.settings.temperatureUnit - } + queue: .main) + { [weak self] _ in + self?.viewModel.temperatureUnit.value = self?.settings.temperatureUnit + } humidityUnitToken = NotificationCenter .default .addObserver(forName: .HumidityUnitDidChange, object: nil, queue: .main, using: { [weak self] _ in - self?.viewModel.humidityUnit.value = self?.settings.humidityUnit + self?.viewModel.humidityUnit.value = self?.settings.humidityUnit }) pressureUnitToken = NotificationCenter .default @@ -1013,7 +1026,7 @@ extension TagSettingsPresenter { object: nil, queue: .main, using: { [weak self] _ in - self?.viewModel.pressureUnit.value = self?.settings.pressureUnit + self?.viewModel.pressureUnit.value = self?.settings.pressureUnit }) } @@ -1023,12 +1036,13 @@ extension TagSettingsPresenter { .addObserver(forName: .BTBackgroundDidConnect, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let uuid = userInfo[BTBackgroundDidConnectKey.uuid] as? String, - uuid == self?.ruuviTag.luid?.value { - self?.viewModel.isConnected.value = true - } + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let uuid = userInfo[BTBackgroundDidConnectKey.uuid] as? String, + uuid == self?.ruuviTag.luid?.value + { + self?.viewModel.isConnected.value = true + } }) disconnectToken = NotificationCenter @@ -1036,13 +1050,14 @@ extension TagSettingsPresenter { .addObserver(forName: .BTBackgroundDidDisconnect, object: nil, queue: .main, - using: { [weak self] (notification) in - if let userInfo = notification.userInfo, - let uuid = userInfo[BTBackgroundDidDisconnectKey.uuid] as? String, - uuid == self?.ruuviTag.luid?.value { - self?.viewModel.isConnected.value = false - } - }) + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let uuid = userInfo[BTBackgroundDidDisconnectKey.uuid] as? String, + uuid == self?.ruuviTag.luid?.value + { + self?.viewModel.isConnected.value = false + } + }) } private func startObservingApplicationState() { @@ -1051,13 +1066,13 @@ extension TagSettingsPresenter { .addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: .main, - using: { [weak self] (_) in - self?.checkPushNotificationsStatus() + using: { [weak self] _ in + self?.checkPushNotificationsStatus() }) } private func checkPushNotificationsStatus() { - pushNotificationsManager.getRemoteNotificationsAuthorizationStatus { [weak self] (status) in + pushNotificationsManager.getRemoteNotificationsAuthorizationStatus { [weak self] status in switch status { case .notDetermined: self?.pushNotificationsManager.registerForRemoteNotifications() @@ -1070,7 +1085,7 @@ extension TagSettingsPresenter { } private func checkLastSensorSettings() { - ruuviStorage.readSensorSettings(self.ruuviTag).on { settings in + ruuviStorage.readSensorSettings(ruuviTag).on { settings in self.sensorSettings = settings } } @@ -1081,46 +1096,52 @@ extension TagSettingsPresenter { .addObserver(forName: .RuuviServiceAlertDidChange, object: nil, queue: .main, - using: { [weak self] (notification) in - guard let isSyncing = self?.settings.isSyncing, isSyncing else { - return - } - if let userInfo = notification.userInfo { - if let physicalSensor - = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor, - physicalSensor.id == self?.viewModel.uuid.value, - let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType { - self?.updateIsOnState(of: type, for: physicalSensor.id) - self?.updateMutedTill(of: type, for: physicalSensor.id) - self?.syncAlerts(of: type) - } - } - }) + using: { [weak self] notification in + guard let isSyncing = self?.settings.isSyncing, isSyncing else { + return + } + if let userInfo = notification.userInfo { + if let physicalSensor + = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor, + physicalSensor.id == self?.viewModel.uuid.value, + let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType + { + self?.updateIsOnState(of: type, for: physicalSensor.id) + self?.updateMutedTill(of: type, for: physicalSensor.id) + self?.syncAlerts(of: type) + } + } + }) } private func reloadMutedTill() { if let mutedTill = viewModel.temperatureAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.temperatureAlertMutedTill.value = nil } if let mutedTill = viewModel.pressureAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.pressureAlertMutedTill.value = nil } if let mutedTill = viewModel.signalAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.signalAlertMutedTill.value = nil } if let mutedTill = viewModel.connectionAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.connectionAlertMutedTill.value = nil } if let mutedTill = viewModel.movementAlertMutedTill.value, - mutedTill < Date() { + mutedTill < Date() + { viewModel.movementAlertMutedTill.value = nil } } @@ -1181,12 +1202,13 @@ extension TagSettingsPresenter { } private func processAlerts() { - guard let lastMeasurement = lastMeasurement else { + guard let lastMeasurement else { return } if ruuviTag.isCloud, - let macId = ruuviTag.macId { + let macId = ruuviTag.macId + { alertHandler.processNetwork(record: lastMeasurement, trigger: false, for: macId) @@ -1207,14 +1229,15 @@ extension TagSettingsPresenter { /// Sets up a 10 seconds timer to attempt pairing to a Ruuvi Sensor via Bluetooth. private func setupTimeoutTimerForKeepConnection() { - timer = Timer.scheduledTimer(withTimeInterval: 10, repeats: true, block: { [weak self] (_) in - guard let self = self else { return } - self.invalidateTimer() - if let isConnected = self.viewModel.isConnected.value, - !isConnected { - self.viewModel.keepConnection.value = false - self.view.resetKeepConnectionSwitch() - self.view.showKeepConnectionTimeoutDialog() + timer = Timer.scheduledTimer(withTimeInterval: 10, repeats: true, block: { [weak self] _ in + guard let self else { return } + invalidateTimer() + if let isConnected = viewModel.isConnected.value, + !isConnected + { + viewModel.keepConnection.value = false + view.resetKeepConnectionSwitch() + view.showKeepConnectionTimeoutDialog() } }) } @@ -1224,20 +1247,20 @@ extension TagSettingsPresenter { timer?.invalidate() timer = nil } - } // MARK: - RuuviNotifierObserver + extension TagSettingsPresenter: RuuviNotifierObserver { - func ruuvi(notifier: RuuviNotifier, isTriggered: Bool, for uuid: String) { + func ruuvi(notifier _: RuuviNotifier, isTriggered _: Bool, for _: String) { // No op here. } - func ruuvi(notifier: RuuviNotifier, + func ruuvi(notifier _: RuuviNotifier, alertType: AlertType, isTriggered: Bool, - for uuid: String) { - + for uuid: String) + { if ruuviTag.luid?.value == uuid || ruuviTag.macId?.value == uuid { let isFireable = ruuviTag.isCloud || viewModel.isConnected.value ?? false switch alertType { @@ -1284,7 +1307,9 @@ extension TagSettingsPresenter: RuuviNotifierObserver { } // MARK: - ALERT SETTERS + // MARK: - TEMPERATURE + extension TagSettingsPresenter { private func setTemperatureAlertState(isOn: Bool) { viewModel.isTemperatureAlertOn.value = isOn @@ -1292,7 +1317,8 @@ extension TagSettingsPresenter { let temperatureUpper = viewModel.temperatureUpperBound.value if let l = temperatureLower?.converted(to: .celsius).value, - let u = temperatureUpper?.converted(to: .celsius).value { + let u = temperatureUpper?.converted(to: .celsius).value + { let type: AlertType = .temperature(lower: l, upper: u) let currentState = alertService.isOn( type: type, for: ruuviTag @@ -1353,6 +1379,7 @@ extension TagSettingsPresenter { } // MARK: - RELATIVE HUMIDITY + extension TagSettingsPresenter { private func setRHAlertState(isOn: Bool) { viewModel.isRelativeHumidityAlertOn.value = isOn @@ -1360,7 +1387,7 @@ extension TagSettingsPresenter { let rhUpper = viewModel.relativeHumidityUpperBound.value if let l = rhLower, let u = rhUpper { - // must divide by 100 because it's fraction of one + // must divide by 100 because it's fraction of one let type: AlertType = .relativeHumidity( lower: l / 100.0, upper: u / 100.0 @@ -1416,6 +1443,7 @@ extension TagSettingsPresenter { } // MARK: - PRESSURE + extension TagSettingsPresenter { private func setPressureAlertState(isOn: Bool) { viewModel.isPressureAlertOn.value = isOn @@ -1423,7 +1451,8 @@ extension TagSettingsPresenter { let pressureUpper = viewModel.pressureUpperBound.value if let l = pressureLower?.converted(to: .hectopascals).value, - let u = pressureUpper?.converted(to: .hectopascals).value { + let u = pressureUpper?.converted(to: .hectopascals).value + { let type: AlertType = .pressure(lower: l, upper: u) let currentState = alertService.isOn(type: type, for: ruuviTag) if currentState != isOn { @@ -1483,6 +1512,7 @@ extension TagSettingsPresenter { } // MARK: - SIGNAL + extension TagSettingsPresenter { private func setSignalAlertState(isOn: Bool) { viewModel.isSignalAlertOn.value = isOn @@ -1545,6 +1575,7 @@ extension TagSettingsPresenter { } // MARK: - MOVEMENT + extension TagSettingsPresenter { private func setMovementAlertState(isOn: Bool) { viewModel.isMovementAlertOn.value = isOn @@ -1573,6 +1604,7 @@ extension TagSettingsPresenter { } // MARK: - CONNECTION + extension TagSettingsPresenter { private func setConnectionAlertState(isOn: Bool) { viewModel.isConnectionAlertOn.value = isOn @@ -1600,6 +1632,7 @@ extension TagSettingsPresenter { } // MARK: - CLOUD CONNECTION + extension TagSettingsPresenter { private func setCloudConnectionAlertState(isOn: Bool) { viewModel.isCloudConnectionAlertOn.value = isOn @@ -1642,7 +1675,7 @@ extension TagSettingsPresenter { extension TagSettingsPresenter { private func notifyRestartAdvertisementDaemon() { - // Notify daemon to restart + // Notify daemon to restart NotificationCenter .default .post(name: .RuuviTagAdvertisementDaemonShouldRestart, @@ -1651,7 +1684,7 @@ extension TagSettingsPresenter { } private func notifyRestartHeartBeatDaemon() { - // Notify daemon to restart + // Notify daemon to restart NotificationCenter .default .post(name: .RuuviTagHeartBeatDaemonShouldRestart, @@ -1662,7 +1695,8 @@ extension TagSettingsPresenter { func checkAndUpdateFirmwareVersion() { guard let luid = ruuviTag.luid, ruuviTag.firmwareVersion == nil || - !ruuviTag.firmwareVersion.hasText() else { + !ruuviTag.firmwareVersion.hasText() + else { return } @@ -1673,7 +1707,7 @@ extension TagSettingsPresenter { ) { [weak self] _, result in guard let sSelf = self else { return } switch result { - case .success(let version): + case let .success(version): let tagWithVersion = sSelf.ruuviTag.with(firmwareVersion: version) self?.ruuviPool.update(tagWithVersion) default: @@ -1687,7 +1721,8 @@ extension TagSettingsPresenter { // Otherwise proceed to removal directly. if let luid = ruuviTag.luid, let isConnected = viewModel.isConnected.value, - isConnected { + isConnected + { connectionPersistence.setKeepConnection(false, for: luid) notifyRestartHeartBeatDaemon() } @@ -1695,7 +1730,8 @@ extension TagSettingsPresenter { if ruuviTag.isOwner { notifyRestartAdvertisementDaemon() if let isConnected = viewModel.isConnected.value, - isConnected { + isConnected + { notifyRestartHeartBeatDaemon() } } @@ -1709,7 +1745,7 @@ extension TagSettingsPresenter { extension TagSettingsPresenter { private func emptySensorSettings() -> SensorSettings { - return SensorSettingsStruct( + SensorSettingsStruct( luid: ruuviTag.luid, macId: ruuviTag.macId, temperatureOffset: nil, @@ -1723,10 +1759,11 @@ extension TagSettingsPresenter { } extension TagSettingsPresenter: UIDocumentPickerDelegate { - func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { + func documentPicker(_: UIDocumentPickerViewController, didPickDocumentsAt _: [URL]) { if let url = exportFileUrl { try? FileManager.default.removeItem(at: url) } } } + // swiftlint:enable file_length diff --git a/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift b/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift index 38952a1c6..7fe6d6b3a 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift @@ -1,8 +1,8 @@ -import UIKit import LightRoute -import SwiftUI import RuuviOntology import RuuviUser +import SwiftUI +import UIKit class TagSettingsRouter: NSObject, TagSettingsRouterInput { weak var transitionHandler: UIViewController! @@ -22,14 +22,13 @@ class TagSettingsRouter: NSObject, TagSettingsRouterInput { func openBackgroundSelectionView(ruuviTag: RuuviTagSensor) { let factory: BackgroundSelectionModuleFactory = BackgroundSelectionModuleFactoryImpl() let module = factory.create(for: ruuviTag) - self.backgroundSelectionModule = module + backgroundSelectionModule = module transitionHandler .navigationController? .pushViewController( module.viewController, animated: true ) - } func openShare(for sensor: RuuviTagSensor) { @@ -39,27 +38,28 @@ class TagSettingsRouter: NSObject, TagSettingsRouterInput { .forStoryboard(factory: factory, to: ShareModuleInput.self) .to(preferred: .navigation(style: .push)) - .then({ (module) -> Any? in + .then { module -> Any? in module.configure(sensor: sensor) - }) + } } func openOffsetCorrection(type: OffsetCorrectionType, ruuviTag: RuuviTagSensor, - sensorSettings: SensorSettings?) { + sensorSettings: SensorSettings?) + { let factory = StoryboardFactory(storyboardName: "OffsetCorrection") try? transitionHandler .forStoryboard(factory: factory, to: OffsetCorrectionModuleInput.self) .to(preferred: .navigation(style: .push)) - .then({ (module) -> Any? in + .then { module -> Any? in module.configure(type: type, ruuviTag: ruuviTag, sensorSettings: sensorSettings) - }) + } } func openUpdateFirmware(ruuviTag: RuuviTagSensor) { let factory: DFUModuleFactory = DFUModuleFactoryImpl() let module = factory.create(for: ruuviTag) - self.dfuModule = module + dfuModule = module transitionHandler .navigationController? .pushViewController( @@ -77,9 +77,9 @@ class TagSettingsRouter: NSObject, TagSettingsRouterInput { try? transitionHandler .forStoryboard(factory: factory, to: OwnerModuleInput.self) .to(preferred: .navigation(style: .push)) - .then({ module in + .then { module in module.configure(ruuviTag: ruuviTag, mode: mode) - }) + } } func openContest(ruuviTag: RuuviTagSensor) { @@ -115,7 +115,7 @@ class TagSettingsRouter: NSObject, TagSettingsRouterInput { } extension TagSettingsRouter: UIAdaptivePresentationControllerDelegate { - func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool { - return dfuModule?.isSafeToDismiss() ?? false + func presentationControllerShouldDismiss(_: UIPresentationController) -> Bool { + dfuModule?.isSafeToDismiss() ?? false } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouterInput.swift b/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouterInput.swift index e2f4321bd..78a3b6411 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouterInput.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouterInput.swift @@ -1,6 +1,6 @@ import Foundation -import UIKit import RuuviOntology +import UIKit protocol TagSettingsRouterInput { func dismiss(completion: (() -> Void)?) diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/DFUModuleFactory.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/DFUModuleFactory.swift index 60d9a5556..76880f197 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/DFUModuleFactory.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/DFUModuleFactory.swift @@ -1,13 +1,13 @@ -import UIKit -import RuuviOntology -import RuuviDFU import BTKit -import RuuviPool -import RuuviStorage -import RuuviLocal import RuuviDaemon -import RuuviPresenters +import RuuviDFU +import RuuviLocal +import RuuviOntology import RuuviPersistence +import RuuviPool +import RuuviPresenters +import RuuviStorage +import UIKit protocol DFUModuleFactory { func create(for ruuviTag: RuuviTagSensor) -> DFUModuleInput diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift index 124271411..c9a7aec26 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift @@ -1,9 +1,9 @@ -import Foundation -import Combine import BTKit -import RuuviOntology +import Combine +import Foundation import RuuviDFU import RuuviFirmware +import RuuviOntology final class DFUInteractor { var ruuviDFU: RuuviDFU! @@ -21,9 +21,8 @@ extension DFUInteractor: DFUInteractorInput { appUrl: URL, fullUrl: URL ) -> AnyPublisher { - let firmwareUrl: URL - if let currentRelease = currentRelease { + if let currentRelease { let currentMajor = currentRelease.version.drop(while: { !$0.isNumber }).prefix(while: { $0 != "." }) let latestMajor = latestRelease.version.drop(while: { !$0.isNumber }).prefix(while: { $0 != "." }) if currentMajor == latestMajor { @@ -32,7 +31,7 @@ extension DFUInteractor: DFUInteractorInput { firmwareUrl = fullUrl } } else { - firmwareUrl = fullUrl + firmwareUrl = fullUrl } guard let firmware = ruuviDFU.firmwareFromUrl(url: firmwareUrl) else { @@ -57,17 +56,19 @@ extension DFUInteractor: DFUInteractorInput { return app .combineLatest(full) .map { app, full in - return (appUrl: app, fullUrl: full) + (appUrl: app, fullUrl: full) }.eraseToAnyPublisher() } func download(release: LatestRelease) -> AnyPublisher { guard let fullName = release.defaultFullZipName, - let fullUrl = release.defaultFullZipUrl else { + let fullUrl = release.defaultFullZipUrl + else { return Fail(error: URLError(.badURL)).eraseToAnyPublisher() } guard let appName = release.defaultAppZipName, - let appUrl = release.defaultAppZipUrl else { + let appUrl = release.defaultAppZipUrl + else { return Fail(error: URLError(.badURL)).eraseToAnyPublisher() } let progress = Progress(totalUnitCount: 2) @@ -75,28 +76,28 @@ extension DFUInteractor: DFUInteractorInput { let app = download(url: appUrl, name: appName, progress: progress) return app .combineLatest(full) - .map({ app, full in + .map { app, full in switch (app, full) { case let (.progress(appProgress), .progress): - return .progress(appProgress) + .progress(appProgress) case let (.progress(appProgress), .response): - return .progress(appProgress) + .progress(appProgress) case let (.response, .progress(fullProgress)): - return .progress(fullProgress) + .progress(fullProgress) case let (.response(appUrl), .response(fullUrl)): - return .response(appUrl: appUrl, fullUrl: fullUrl) + .response(appUrl: appUrl, fullUrl: fullUrl) } - }).eraseToAnyPublisher() + }.eraseToAnyPublisher() } func download(url: URL, name: String, progress: Progress) -> AnyPublisher { - return URLSession.shared + URLSession.shared .downloadTaskPublisher(for: url, progress: progress) .catch { error in Fail(error: error) } - .map({ [weak self] response in + .map { [weak self] response in guard let sSelf = self else { return response } switch response { - case .response(let fileUrl): + case let .response(fileUrl): if let movedUrl = try? sSelf.firmwareRepository.save( name: name, fileUrl: fileUrl @@ -108,8 +109,7 @@ extension DFUInteractor: DFUInteractorInput { case .progress: return response } - - }) + } .receive(on: RunLoop.main) .eraseToAnyPublisher() } @@ -121,15 +121,15 @@ extension DFUInteractor: DFUInteractorInput { } return URLSession.shared.dataTaskPublisher(for: url) - .map { $0.data } + .map(\.data) .decode(type: LatestRelease.self, decoder: JSONDecoder()) - .catch { error in Fail(error: error)} + .catch { error in Fail(error: error) } .receive(on: RunLoop.main) .eraseToAnyPublisher() } func serveCurrentRelease(for ruuviTag: RuuviTagSensor) -> Future { - return Future { [weak self] promise in + Future { [weak self] promise in guard let sSelf = self else { return } guard let uuid = ruuviTag.luid?.value else { promise(.failure(DFUError.failedToGetLuid)) @@ -150,10 +150,10 @@ extension DFUInteractor: DFUInteractorInput { options: [.connectionTimeout(15)] ) { _, result in switch result { - case .success(let version): + case let .success(version): let currentRelease = CurrentRelease(version: version) promise(.success(currentRelease)) - case .failure(let error): + case let .failure(error): promise(.failure(error)) } } @@ -161,7 +161,7 @@ extension DFUInteractor: DFUInteractorInput { } func listen() -> Future { - return Future { [weak self] promise in + Future { [weak self] promise in guard let sSelf = self else { return } sSelf.ruuviDFU.scan(sSelf) { _, device in promise(.success(device.uuid)) @@ -170,7 +170,7 @@ extension DFUInteractor: DFUInteractorInput { } func observeLost(uuid: String) -> Future { - return Future { [weak self] promise in + Future { [weak self] promise in guard let sSelf = self else { return } sSelf.ruuviDFU.lost(sSelf, closure: { _, device in if device.uuid == uuid { diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractorInput.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractorInput.swift index 1146b8958..2ff75860f 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractorInput.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractorInput.swift @@ -1,8 +1,8 @@ -import Foundation -import Combine import BTKit -import RuuviOntology +import Combine +import Foundation import RuuviDFU +import RuuviOntology protocol DFUInteractorInput { func listen() -> Future diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/LatestRelease.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/LatestRelease.swift index 386944c6b..b92b76669 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/LatestRelease.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/LatestRelease.swift @@ -6,11 +6,11 @@ struct LatestRelease: Codable { enum CodingKeys: String, CodingKey { case version = "tag_name" - case assets = "assets" + case assets } private var defaultFullZipAsset: LatestReleaseAsset? { - return assets.first(where: { + assets.first(where: { $0.name.hasSuffix("zip") && $0.name.contains("default") && !$0.name.contains("app") @@ -18,7 +18,7 @@ struct LatestRelease: Codable { } private var defaultAppZipAsset: LatestReleaseAsset? { - return assets.first(where: { + assets.first(where: { $0.name.hasSuffix("zip") && $0.name.contains("default") && $0.name.contains("app") @@ -26,26 +26,26 @@ struct LatestRelease: Codable { } var defaultFullZipName: String? { - return defaultFullZipAsset?.name + defaultFullZipAsset?.name } var defaultFullZipUrl: URL? { if let downloadUrlString = defaultFullZipAsset?.downloadUrlString { - return URL(string: downloadUrlString) + URL(string: downloadUrlString) } else { - return nil + nil } } var defaultAppZipName: String? { - return defaultAppZipAsset?.name + defaultAppZipAsset?.name } var defaultAppZipUrl: URL? { if let downloadUrlString = defaultAppZipAsset?.downloadUrlString { - return URL(string: downloadUrlString) + URL(string: downloadUrlString) } else { - return nil + nil } } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUModuleInput.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUModuleInput.swift index ea2131df6..ae5064321 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUModuleInput.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUModuleInput.swift @@ -1,6 +1,6 @@ import Foundation -import UIKit import RuuviOntology +import UIKit protocol DFUModuleInput: AnyObject { var viewController: UIViewController { get } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift index 3c775b5a6..7957f59fc 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift @@ -1,26 +1,26 @@ -import Foundation -import SwiftUI +import BTKit import Combine +import Foundation +import RuuviDaemon +import RuuviLocal import RuuviOntology +import RuuviPersistence import RuuviPool -import RuuviStorage -import RuuviLocal -import RuuviDaemon import RuuviPresenters -import BTKit -import RuuviPersistence +import RuuviStorage +import SwiftUI final class DFUPresenter: DFUModuleInput { var viewController: UIViewController { - if let view = self.weakView { + if let view = weakView { return view } else { let view = UIHostingController(rootView: DFUUIView(viewModel: viewModel)) - self.weakView = view + weakView = view return view } - } + private weak var weakView: UIViewController? private let viewModel: DFUViewModel private let interactor: DFUInteractorInput @@ -59,7 +59,7 @@ final class DFUPresenter: DFUModuleInput { self.settings = settings self.propertiesDaemon = propertiesDaemon self.activityPresenter = activityPresenter - self.viewModel = DFUViewModel( + viewModel = DFUViewModel( interactor: interactor, foreground: foreground, idPersistence: idPersistence, @@ -77,9 +77,9 @@ final class DFUPresenter: DFUModuleInput { func isSafeToDismiss() -> Bool { switch viewModel.state { case .flashing: - return false + false default: - return true + true } } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift index 70bce601f..a3a36cf2c 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift @@ -1,15 +1,15 @@ +import BTKit +import Combine // swiftlint:disable file_length import Foundation -import Combine +import RuuviDaemon +import RuuviFirmware +import RuuviLocal import RuuviOntology +import RuuviPersistence import RuuviPool -import RuuviStorage -import RuuviLocal -import RuuviDaemon import RuuviPresenters -import BTKit -import RuuviPersistence -import RuuviFirmware +import RuuviStorage final class DFUViewModel: ObservableObject { @Published private(set) var state: State = .idle @@ -79,16 +79,16 @@ final class DFUViewModel: ObservableObject { reduce: Self.reduce, scheduler: RunLoop.main, feedbacks: [ - self.whenLoading(), - self.whenServing(), - self.whenReading(), - self.whenDownloading(), - self.whenListening(), - self.whenReadyToUpdate(), - self.whenFlashing(), - self.whenFlashed(), - self.whenServingAfterUpdate(), - self.userInput(input: input.eraseToAnyPublisher()) + whenLoading(), + whenServing(), + whenReading(), + whenDownloading(), + whenListening(), + whenReadyToUpdate(), + whenFlashing(), + whenFlashed(), + whenServingAfterUpdate(), + userInput(input: input.eraseToAnyPublisher()), ] ) .assign(to: \.state, on: self) @@ -114,18 +114,18 @@ final class DFUViewModel: ObservableObject { // Usually tags without macId are stored in the realm database // For tags with macId don't need migration if ruuviTag.macId != nil { - guard let currentRelease = currentRelease else { + guard let currentRelease else { return } isLoading = true ruuviPool.update(ruuviTag .with(isConnectable: true) .with(firmwareVersion: currentRelease.version)) - .on(success: { [weak self] _ in - self?.isLoading = false - }, failure: { [weak self] _ in - self?.isLoading = false - }) + .on(success: { [weak self] _ in + self?.isLoading = false + }, failure: { [weak self] _ in + self?.isLoading = false + }) } else { isLoading = true propertiesDaemon.stop() @@ -135,8 +135,9 @@ final class DFUViewModel: ObservableObject { func storeCurrentFirmwareVersion(from currentRelease: CurrentRelease?) { guard ruuviTag.firmwareVersion == nil || - !ruuviTag.firmwareVersion.hasText(), - let currentRelease = currentRelease else { + !ruuviTag.firmwareVersion.hasText(), + let currentRelease + else { return } ruuviPool.update(ruuviTag @@ -151,9 +152,10 @@ final class DFUViewModel: ObservableObject { } ruuviTagObserveToken?.invalidate() ruuviTagObserveToken = foreground.observe(self, - uuid: luid.value, - options: [.callbackQueue(.untouch)]) { - [weak self] (_, device) in + uuid: luid.value, + options: [.callbackQueue(.untouch)]) + { + [weak self] _, device in guard let sSelf = self else { return } if let tag = device.ruuvi?.tag { guard !sSelf.isMigrating else { @@ -168,6 +170,7 @@ final class DFUViewModel: ObservableObject { } // MARK: - Migration starts + @objc private func tryToMigrate(pair: RuuviTagPropertiesDaemonPair) { if let mac = pair.device.mac { moveTagToSqlite(mac: mac.mac, pair: pair) @@ -176,7 +179,8 @@ final class DFUViewModel: ObservableObject { /// This method creates the updated instance of the Ruuvi Tag after firmware update. private func moveTagToSqlite(mac: MACIdentifier, - pair: RuuviTagPropertiesDaemonPair) { + pair: RuuviTagPropertiesDaemonPair) + { sqiltePersistence.create( pair.ruuviTag .with(macId: mac) @@ -193,10 +197,11 @@ final class DFUViewModel: ObservableObject { /// This method fetches the latest record from the Realm and creates the same record to SQLite. /// If there's no record move to the next step. private func moveLatestRecordToSqlite(mac: MACIdentifier, - pair: RuuviTagPropertiesDaemonPair) { + pair: RuuviTagPropertiesDaemonPair) + { realmPersistence.readLatest(pair.ruuviTag).on(success: { [weak self] record in // If there's no record move to next action - guard let record = record else { + guard let record else { self?.moveRecordsHistoryToSqlite(mac: mac, pair: pair) return } @@ -213,14 +218,14 @@ final class DFUViewModel: ObservableObject { /// This method fetches the all the records from the Realm and creates the same records to SQLite. /// If there are no records move to the next step. private func moveRecordsHistoryToSqlite(mac: MACIdentifier, - pair: RuuviTagPropertiesDaemonPair) { - + pair: RuuviTagPropertiesDaemonPair) + { realmPersistence.readAll(pair.device.uuid).on(success: { [weak self] realmRecords in guard realmRecords.count > 0 else { self?.moveSettingsToSqlite(mac: mac, pair: pair) return } - let records = realmRecords.map({ $0.with(macId: mac) }) + let records = realmRecords.map { $0.with(macId: mac) } self?.sqiltePersistence.create(records).on(success: { _ in self?.idPersistence.set(mac: mac, for: pair.device.uuid.luid) self?.moveSettingsToSqlite(mac: mac, pair: pair) @@ -235,7 +240,8 @@ final class DFUViewModel: ObservableObject { /// This method fetches the sensor settings from the Realm and creates the same sensor settings record to SQLite. /// If there's no record move to the next step. private func moveSettingsToSqlite(mac: MACIdentifier, - pair: RuuviTagPropertiesDaemonPair) { + pair: RuuviTagPropertiesDaemonPair) + { realmPersistence.readSensorSettings(pair.ruuviTag.withoutMac()) .on(success: { [weak self] sensorSettings in if let withMacSettings = sensorSettings?.with(macId: mac) { @@ -261,7 +267,7 @@ final class DFUViewModel: ObservableObject { self?.realmPersistence.deleteLatest(pair.device.uuid).on(success: { _ in self?.realmPersistence.delete(pair.ruuviTag.withoutMac()).on(success: { _ in self?.realmPersistence.deleteOffsetCorrection(ruuviTag: - pair.ruuviTag.withoutMac()).on(completion: { + pair.ruuviTag.withoutMac()).on(completion: { self?.isMigrating = false self?.isLoading = false }) @@ -284,7 +290,7 @@ final class DFUViewModel: ObservableObject { // Migration ends - func checkBatteryState(completion: @escaping(Bool) -> Void ) { + func checkBatteryState(completion: @escaping (Bool) -> Void) { let batteryStatusProvider = RuuviTagBatteryStatusProvider() ruuviStorage .readLatest(ruuviTag) @@ -311,25 +317,25 @@ extension DFUViewModel { case reading(LatestRelease, CurrentRelease?) case downloading(LatestRelease, CurrentRelease?) case listening( - LatestRelease, - CurrentRelease?, - appUrl: URL, - fullUrl: URL - ) + LatestRelease, + CurrentRelease?, + appUrl: URL, + fullUrl: URL + ) case readyToUpdate( - LatestRelease, - CurrentRelease?, - uuid: String, - appUrl: URL, - fullUrl: URL - ) + LatestRelease, + CurrentRelease?, + uuid: String, + appUrl: URL, + fullUrl: URL + ) case flashing( - LatestRelease, - CurrentRelease?, - uuid: String, - appUrl: URL, - fullUrl: URL - ) + LatestRelease, + CurrentRelease?, + uuid: String, + appUrl: URL, + fullUrl: URL + ) case successfulyFlashed(LatestRelease) case servingAfterUpdate(LatestRelease) case firmwareAfterUpdate(CurrentRelease?) @@ -344,41 +350,41 @@ extension DFUViewModel { case onLoadedAndServed(LatestRelease, CurrentRelease?) case onStartUpgrade(LatestRelease, CurrentRelease?) case onRead( - LatestRelease, - CurrentRelease?, - appUrl: URL, - fullUrl: URL - ) + LatestRelease, + CurrentRelease?, + appUrl: URL, + fullUrl: URL + ) case onDidFailReading(LatestRelease, CurrentRelease?, Error) case onDownloading(LatestRelease, CurrentRelease?, Double) case onDownloaded( - LatestRelease, - CurrentRelease?, - appUrl: URL, - fullUrl: URL - ) + LatestRelease, + CurrentRelease?, + appUrl: URL, + fullUrl: URL + ) case onDidFailDownloading(Error) case onHeardRuuviBootDevice( - LatestRelease, - CurrentRelease?, - uuid: String, - appUrl: URL, - fullUrl: URL - ) + LatestRelease, + CurrentRelease?, + uuid: String, + appUrl: URL, + fullUrl: URL + ) case onLostRuuviBootDevice( - LatestRelease, - CurrentRelease?, - uuid: String, - appUrl: URL, - fullUrl: URL - ) + LatestRelease, + CurrentRelease?, + uuid: String, + appUrl: URL, + fullUrl: URL + ) case onUserDidConfirmToFlash( - LatestRelease, - CurrentRelease?, - uuid: String, - appUrl: URL, - fullUrl: URL - ) + LatestRelease, + CurrentRelease?, + uuid: String, + appUrl: URL, + fullUrl: URL + ) case onSuccessfullyFlashedFirmware(LatestRelease) case onServingAfterUpdate(CurrentRelease?) case onServedAfterUpdate(CurrentRelease?) @@ -393,110 +399,110 @@ extension DFUViewModel { case .idle: switch event { case .onAppear: - return .loading + .loading default: - return state + state } case .loading: switch event { case let .onDidFailLoading(error): - return .error(error) + .error(error) case let .onLoaded(latestRelease): - return .loaded(latestRelease) + .loaded(latestRelease) default: - return state + state } case let .loaded(latestRelease): - return .serving(latestRelease) + .serving(latestRelease) case let .serving(latestRelease): switch event { case let .onServed(currentRelease): - return .checking(latestRelease, currentRelease) + .checking(latestRelease, currentRelease) default: - return state + state } case let .checking(latestRelease, currentRelease): if isRecommendedToUpdate( latestRelease: latestRelease, currentRelease: currentRelease ) { - return .isAbleToUpgrade(latestRelease, currentRelease) + .isAbleToUpgrade(latestRelease, currentRelease) } else { - return .noNeedToUpgrade(latestRelease, currentRelease) + .noNeedToUpgrade(latestRelease, currentRelease) } case .noNeedToUpgrade: - return state + state case let .isAbleToUpgrade(latestRelease, currentRelease): - return .reading(latestRelease, currentRelease) + .reading(latestRelease, currentRelease) case .reading: switch event { case let .onRead(latestRelease, currentRelease, appUrl, fullUrl): - return .listening( + .listening( latestRelease, currentRelease, appUrl: appUrl, fullUrl: fullUrl ) case let .onDidFailReading(latestRelease, currentRelease, _): - return .downloading(latestRelease, currentRelease) + .downloading(latestRelease, currentRelease) default: - return state + state } case .downloading: switch event { case let .onDownloaded( - latestRelease, - currentRelease, - appUrl, - fullUrl + latestRelease, + currentRelease, + appUrl, + fullUrl ): - return .listening( + .listening( latestRelease, currentRelease, appUrl: appUrl, fullUrl: fullUrl ) default: - return state + state } case .listening: switch event { case let .onHeardRuuviBootDevice(latestRelease, currentRelease, uuid, appUrl, fullUrl): - return .readyToUpdate(latestRelease, currentRelease, uuid: uuid, appUrl: appUrl, fullUrl: fullUrl) + .readyToUpdate(latestRelease, currentRelease, uuid: uuid, appUrl: appUrl, fullUrl: fullUrl) default: - return state + state } case .readyToUpdate: switch event { case let .onLostRuuviBootDevice(latestRelease, currentRelease, _, appUrl, fullUrl): - return .listening(latestRelease, currentRelease, appUrl: appUrl, fullUrl: fullUrl) + .listening(latestRelease, currentRelease, appUrl: appUrl, fullUrl: fullUrl) case let .onUserDidConfirmToFlash(latestRelease, currentRelease, uuid, appUrl, fullUrl): - return .flashing(latestRelease, currentRelease, uuid: uuid, appUrl: appUrl, fullUrl: fullUrl) + .flashing(latestRelease, currentRelease, uuid: uuid, appUrl: appUrl, fullUrl: fullUrl) default: - return state + state } case .flashing: switch event { - case .onSuccessfullyFlashedFirmware(let latestRelease): - return .successfulyFlashed(latestRelease) - case .onDidFailFlashingFirmware(let error): - return .error(error) + case let .onSuccessfullyFlashedFirmware(latestRelease): + .successfulyFlashed(latestRelease) + case let .onDidFailFlashingFirmware(error): + .error(error) default: - return state + state } - case .successfulyFlashed(let latestRelease): - return .servingAfterUpdate(latestRelease) + case let .successfulyFlashed(latestRelease): + .servingAfterUpdate(latestRelease) case .servingAfterUpdate: switch event { case let .onServedAfterUpdate(currentRelease): - return .firmwareAfterUpdate(currentRelease) + .firmwareAfterUpdate(currentRelease) default: - return state + state } case .error: - return state + state case .firmwareAfterUpdate: - return state + state } } @@ -504,18 +510,18 @@ extension DFUViewModel { latestRelease: LatestRelease, currentRelease: CurrentRelease? ) -> Bool { - guard let currentRelease = currentRelease else { return true } + guard let currentRelease else { return true } return !currentRelease.version.contains(latestRelease.version) } func whenFlashing() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in guard case let .flashing( - latestRelease, - currentRelease, - uuid, - appUrl, - fullUrl + latestRelease, + currentRelease, + uuid, + appUrl, + fullUrl ) = state, let sSelf = self else { return Empty().eraseToAnyPublisher() } @@ -527,17 +533,17 @@ extension DFUViewModel { fullUrl: fullUrl ) .receive(on: RunLoop.main) - .compactMap({ [weak sSelf] response in + .compactMap { [weak sSelf] response in switch response { case .done: return Event.onSuccessfullyFlashedFirmware(latestRelease) - case .progress(let percentage): + case let .progress(percentage): sSelf?.flashProgress = percentage return nil case .log: return nil } - }) + } .catch { Just(Event.onDidFailFlashingFirmware($0)) } .eraseToAnyPublisher() } @@ -546,13 +552,14 @@ extension DFUViewModel { func whenReadyToUpdate() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in guard case let .readyToUpdate(latestRelease, currentRelease, uuid, appUrl, fullUrl) = state, - let sSelf = self else { + let sSelf = self + else { return Empty().eraseToAnyPublisher() } return sSelf.interactor.observeLost(uuid: uuid) .receive(on: RunLoop.main) .map { uuid in - return Event.onLostRuuviBootDevice( + Event.onLostRuuviBootDevice( latestRelease, currentRelease, uuid: uuid, @@ -567,13 +574,14 @@ extension DFUViewModel { func whenListening() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in guard case let .listening(latestRelease, currentRelease, appUrl, fullUrl) = state, - let sSelf = self else { + let sSelf = self + else { return Empty().eraseToAnyPublisher() } return sSelf.interactor.listen() .receive(on: RunLoop.main) .map { uuid in - return Event.onHeardRuuviBootDevice( + Event.onHeardRuuviBootDevice( latestRelease, currentRelease, uuid: uuid, @@ -588,13 +596,14 @@ extension DFUViewModel { func whenReading() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in guard case let .reading(latestRelease, currentRelease) = state, - let sSelf = self else { + let sSelf = self + else { return Empty().eraseToAnyPublisher() } return sSelf.interactor.read(release: latestRelease) .receive(on: RunLoop.main) .map { tuple in - return Event.onRead( + Event.onRead( latestRelease, currentRelease, appUrl: tuple.appUrl, @@ -639,15 +648,15 @@ extension DFUViewModel { } return sSelf.interactor.download(release: latestRelease) .receive(on: RunLoop.main) - .compactMap({ [weak sSelf] response in + .compactMap { [weak sSelf] response in switch response { case let .response(appUrl, fullUrl): return Event.onDownloaded(latestRelease, currentRelease, appUrl: appUrl, fullUrl: fullUrl) - case .progress(let progress): + case let .progress(progress): sSelf?.downloadProgress = progress.fractionCompleted return nil } - }) + } .catch { Just(Event.onDidFailDownloading($0)) } .eraseToAnyPublisher() } @@ -681,7 +690,7 @@ extension DFUViewModel { func userInput(input: AnyPublisher) -> Feedback { Feedback(run: { _ in - return input + input }) } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift index c927fe4b6..0280f84c5 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift @@ -1,6 +1,6 @@ import RuuviFirmware -import SwiftUI import RuuviLocalization +import SwiftUI // swiftlint:disable file_length // swiftlint:disable:next type_body_length @@ -61,10 +61,10 @@ struct DFUUIView: View { } }) .onAppear { - self.viewModel.send(event: .onAppear) + viewModel.send(event: .onAppear) } .onDisappear { - self.viewModel.restartPropertiesDaemon() + viewModel.restartPropertiesDaemon() } } @@ -86,7 +86,7 @@ struct DFUUIView: View { ) .padding() .eraseToAnyView() - case .error(let error): + case let .error(error): return Text(error.localizedDescription) .font(muliRegular16) .eraseToAnyView() @@ -109,7 +109,7 @@ struct DFUUIView: View { alignment: .topLeading ) .padding() - .onAppear { self.viewModel.send(event: .onLoaded(latestRelease)) } + .onAppear { viewModel.send(event: .onLoaded(latestRelease)) } .eraseToAnyView() case let .serving(latestRelease): return VStack(alignment: .leading, spacing: 16) { @@ -158,9 +158,9 @@ struct DFUUIView: View { alignment: .topLeading ) .padding() - .onAppear { self.viewModel.send(event: .onLoadedAndServed(latestRelease, currentRelease)) } + .onAppear { viewModel.send(event: .onLoadedAndServed(latestRelease, currentRelease)) } .eraseToAnyView() - case .noNeedToUpgrade(_, let currentRelease): + case let .noNeedToUpgrade(_, currentRelease): return Text(texts.alreadyOnLatest) .font(muliRegular16) .foregroundColor(RuuviColor.ruuviTextColorSUI) @@ -170,7 +170,7 @@ struct DFUUIView: View { alignment: .topLeading ) .padding() - .onAppear { self.viewModel.storeCurrentFirmwareVersion(from: currentRelease) } + .onAppear { viewModel.storeCurrentFirmwareVersion(from: currentRelease) } .eraseToAnyView() case let .isAbleToUpgrade(latestRelease, currentRelease): return VStack { @@ -195,7 +195,7 @@ struct DFUUIView: View { } Button( action: { - self.viewModel.send( + viewModel.send( event: .onStartUpgrade(latestRelease, currentRelease) ) }, @@ -346,7 +346,7 @@ struct DFUUIView: View { } Button( action: { - self.viewModel.send( + viewModel.send( event: .onUserDidConfirmToFlash( latestRelease, currentRelease, @@ -396,7 +396,6 @@ struct DFUUIView: View { .bold() .multilineTextAlignment(.center) .foregroundColor(RuuviColor.ruuviTextColorSUI) - } .frame( maxWidth: .infinity, @@ -427,7 +426,7 @@ struct DFUUIView: View { ) .padding() .eraseToAnyView() - case .firmwareAfterUpdate(let currentRelease): + case let .firmwareAfterUpdate(currentRelease): viewModel.storeUpdatedFirmware(currentRelease: currentRelease) return Text(texts.successfulTitle) .font(muliRegular16) @@ -443,6 +442,6 @@ struct DFUUIView: View { } func goBack() { - self.presentationMode.wrappedValue.dismiss() + presentationMode.wrappedValue.dismiss() } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Assembly/SensorForceClaimModuleFactory.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Assembly/SensorForceClaimModuleFactory.swift index 15566ba23..d1844ad2b 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Assembly/SensorForceClaimModuleFactory.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Assembly/SensorForceClaimModuleFactory.swift @@ -1,11 +1,11 @@ +import BTKit import Foundation -import RuuviService -import RuuviUser -import RuuviPool -import RuuviPresenters import RuuviDFU -import BTKit import RuuviLocal +import RuuviPool +import RuuviPresenters +import RuuviService +import RuuviUser protocol SensorForceClaimModuleFactory { func create() -> SensorForceClaimViewController diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift index dad1a507e..5cd7b6e44 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift @@ -1,12 +1,12 @@ +import BTKit +import CoreNFC import Foundation +import RuuviLocal import RuuviOntology -import RuuviService -import RuuviUser import RuuviPool import RuuviPresenters -import BTKit -import CoreNFC -import RuuviLocal +import RuuviService +import RuuviUser final class SensorForceClaimPresenter: SensorForceClaimModuleInput { weak var view: SensorForceClaimViewInput? @@ -81,11 +81,12 @@ extension SensorForceClaimPresenter { timer = Timer.scheduledTimer( withTimeInterval: gattTimeoutSeconds, repeats: true, - block: { [weak self] (_) in + block: { [weak self] _ in self?.activityPresenter.dismiss() self?.invalidateTimer() self?.view?.showGATTConnectionTimeoutDialog() - }) + } + ) } /// Invalidates the running timer @@ -105,9 +106,9 @@ extension SensorForceClaimPresenter { options: [.connectionTimeout(gattTimeoutSeconds)] // Doesn't work now. ) { [weak self] _, result in switch result { - case .success(let secret): + case let .success(secret): self?.contestSensor(with: secret) - case .failure(let error): + case let .failure(error): self?.activityPresenter.dismiss() self?.errorPresenter.present(error: error) } @@ -116,8 +117,8 @@ extension SensorForceClaimPresenter { /// Contest sensor with tag secret. private func contestSensor(with secret: String?) { - guard let ruuviTag = ruuviTag, - let secret = secret else { return } + guard let ruuviTag, + let secret else { return } activityPresenter.show(with: .loading(message: nil)) ruuviOwnershipService diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/SensorForceClaimViewOutput.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/SensorForceClaimViewOutput.swift index b9657430a..ddc3f2793 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/SensorForceClaimViewOutput.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/SensorForceClaimViewOutput.swift @@ -1,5 +1,5 @@ -import Foundation import CoreNFC +import Foundation protocol SensorForceClaimViewOutput { func viewDidLoad() diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift index 9817204a9..f262c72b3 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift @@ -1,12 +1,11 @@ -import RuuviLocalization -import UIKit import CoreNFC +import RuuviLocalization import RuuviOntology +import UIKit class SensorForceClaimViewController: UIViewController { - private lazy var backButton: UIButton = { - let button = UIButton() + let button = UIButton() button.tintColor = .label let buttonImage = RuuviAssets.backButtonImage button.setImage(buttonImage, for: .normal) @@ -39,7 +38,7 @@ class SensorForceClaimViewController: UIViewController { return button }() - private lazy var sensorClaimNotesViewContainer: UIView = UIView( + private lazy var sensorClaimNotesViewContainer: UIView = .init( color: RuuviColor.ruuviPrimary ) private lazy var sensorClaimNotesView: UITextView = { @@ -60,7 +59,7 @@ class SensorForceClaimViewController: UIViewController { cornerRadius: 25) button.setTitle( RuuviLocalization.useNfc, - for: .normal + for: .normal ) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, size: 16) @@ -87,8 +86,9 @@ class SensorForceClaimViewController: UIViewController { // Implementation private var isNFCAvailable: Bool { - return NFCNDEFReaderSession.readingAvailable + NFCNDEFReaderSession.readingAvailable } + private var session: NFCNDEFReaderSession? // Constraints @@ -100,10 +100,10 @@ class SensorForceClaimViewController: UIViewController { // Output var output: SensorForceClaimViewOutput? - } // MARK: - VIEW LIFECYCLE + extension SensorForceClaimViewController { override func viewDidLoad() { super.viewDidLoad() @@ -113,6 +113,7 @@ extension SensorForceClaimViewController { } // MARK: - SensorForceClaimViewInput + extension SensorForceClaimViewController: SensorForceClaimViewInput { func localize() { // No op. @@ -148,6 +149,7 @@ extension SensorForceClaimViewController: SensorForceClaimViewInput { } // MARK: - PRIVATE SET UI + extension SensorForceClaimViewController { private func setUpUI() { setUpBase() @@ -156,7 +158,7 @@ extension SensorForceClaimViewController { } private func setUpBase() { - self.title = RuuviLocalization.forceClaimSensor + title = RuuviLocalization.forceClaimSensor view.backgroundColor = RuuviColor.ruuviPrimary @@ -265,8 +267,9 @@ extension SensorForceClaimViewController { } // MARK: - IBACTIONS + extension SensorForceClaimViewController { - @objc fileprivate func backButtonDidTap() { + @objc private func backButtonDidTap() { _ = navigationController?.popViewController(animated: true) } @@ -284,8 +287,9 @@ extension SensorForceClaimViewController { } // MARK: - PRIVATE -extension SensorForceClaimViewController { - fileprivate func hideNFCButton(hide: Bool) { + +private extension SensorForceClaimViewController { + func hideNFCButton(hide: Bool) { useNFCButton.alpha = hide ? 0 : 1 bluetoothButtonRegularLeadingConstraint.isActive = !hide bluetoothButtonRegularTrailingConstraint.isActive = !hide @@ -296,14 +300,15 @@ extension SensorForceClaimViewController { } // MARK: - NFCNDEFReaderSessionDelegate + extension SensorForceClaimViewController: NFCNDEFReaderSessionDelegate { - func readerSession(_ session: NFCNDEFReaderSession, didInvalidateWithError error: Error) { + func readerSession(_: NFCNDEFReaderSession, didInvalidateWithError _: Error) { DispatchQueue.main.async { [weak self] in self?.stopNFCSession() } } - func readerSession(_ session: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) { + func readerSession(_: NFCNDEFReaderSession, didDetectNDEFs messages: [NFCNDEFMessage]) { DispatchQueue.main.async { [weak self] in self?.output?.viewDidReceiveNFCMessages(messages: messages) } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionAppleInitializer.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionAppleInitializer.swift index 8efae7a8f..2f334e612 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionAppleInitializer.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionAppleInitializer.swift @@ -1,7 +1,7 @@ import UIKit class OffsetCorrectionAppleInitializer: NSObject { - @IBOutlet weak var viewController: OffsetCorrectionAppleViewController! + @IBOutlet var viewController: OffsetCorrectionAppleViewController! override func awakeFromNib() { super.awakeFromNib() diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionConfigurator.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionConfigurator.swift index c837fedb0..6e085b6b8 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionConfigurator.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionConfigurator.swift @@ -1,10 +1,10 @@ -import UIKit import BTKit -import RuuviService -import RuuviReactor import RuuviLocal -import RuuviStorage import RuuviPresenters +import RuuviReactor +import RuuviService +import RuuviStorage +import UIKit class OffsetCorrectionConfigurator { func configure(view: OffsetCorrectionAppleViewController) { diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionPresenter.swift index e16ad6993..3a3342390 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionPresenter.swift @@ -1,11 +1,11 @@ -import Foundation import BTKit -import RuuviOntology -import RuuviService +import Foundation import RuuviLocal -import RuuviStorage +import RuuviOntology import RuuviPresenters import RuuviReactor +import RuuviService +import RuuviStorage final class OffsetCorrectionPresenter: OffsetCorrectionModuleInput { weak var view: OffsetCorrectionViewInput! @@ -42,13 +42,13 @@ final class OffsetCorrectionPresenter: OffsetCorrectionModuleInput { pressureOffset: nil, pressureOffsetDate: nil ) - self.view.viewModel = { + view.viewModel = { let vm = OffsetCorrectionViewModel( type: type, sensorSettings: self.sensorSettings ) - ruuviStorage.readLatest(ruuviTag).on {[weak self] record in - if let record = record { + ruuviStorage.readLatest(ruuviTag).on { [weak self] record in + if let record { self?.lastSensorRecord = record vm.update( ruuviTagRecord: record @@ -110,19 +110,20 @@ extension OffsetCorrectionPresenter: OffsetCorrectionViewOutput { offset: offset, of: view.viewModel.type, for: ruuviTag, - lastOriginalRecord: lastSensorRecord) - .on(success: { [weak self] settings in - self?.sensorSettings = settings - self?.view.viewModel.update(sensorSettings: settings) - if let lastRecord = self?.lastSensorRecord { - self?.view.viewModel.update( - ruuviTagRecord: lastRecord.with(sensorSettings: settings) - ) - } - self?.notifyCalibrationSettingsUpdate() - }, failure: { [weak self] (error) in - self?.errorPresenter.present(error: error) - }) + lastOriginalRecord: lastSensorRecord + ) + .on(success: { [weak self] settings in + self?.sensorSettings = settings + self?.view.viewModel.update(sensorSettings: settings) + if let lastRecord = self?.lastSensorRecord { + self?.view.viewModel.update( + ruuviTagRecord: lastRecord.with(sensorSettings: settings) + ) + } + self?.notifyCalibrationSettingsUpdate() + }, failure: { [weak self] error in + self?.errorPresenter.present(error: error) + }) } func viewDidClearOffsetValue() { @@ -130,48 +131,50 @@ extension OffsetCorrectionPresenter: OffsetCorrectionViewOutput { offset: nil, of: view.viewModel.type, for: ruuviTag, - lastOriginalRecord: lastSensorRecord) - .on(success: { [weak self] sensorSettings in - self?.sensorSettings = sensorSettings - self?.view.viewModel.update(sensorSettings: sensorSettings) - if let lastRecord = self?.lastSensorRecord { - self?.view.viewModel.update( - ruuviTagRecord: lastRecord - .with(sensorSettings: sensorSettings) - ) - } - self?.notifyCalibrationSettingsUpdate() - }, failure: { [weak self] (error) in - self?.errorPresenter.present(error: error) - }) + lastOriginalRecord: lastSensorRecord + ) + .on(success: { [weak self] sensorSettings in + self?.sensorSettings = sensorSettings + self?.view.viewModel.update(sensorSettings: sensorSettings) + if let lastRecord = self?.lastSensorRecord { + self?.view.viewModel.update( + ruuviTagRecord: lastRecord + .with(sensorSettings: sensorSettings) + ) + } + self?.notifyCalibrationSettingsUpdate() + }, failure: { [weak self] error in + self?.errorPresenter.present(error: error) + }) } private func notifyCalibrationSettingsUpdate() { NotificationCenter.default.post(name: .SensorCalibrationDidChange, - object: self, - userInfo: nil) + object: self, + userInfo: nil) } private func observeRuuviTagUpdate() { - guard let luid = self.ruuviTag.luid?.value else { + guard let luid = ruuviTag.luid?.value else { return } if !(settings.cloudModeEnabled && ruuviTag.isCloud) { ruuviTagObserveToken?.invalidate() - ruuviTagObserveToken = foreground.observe(self, uuid: luid) { [weak self] (_, device) in + ruuviTagObserveToken = foreground.observe(self, uuid: luid) { [weak self] _, device in if let ruuviTag = device.ruuvi?.tag { self?.lastSensorRecord = ruuviTag self?.view.viewModel.update( ruuviTagRecord: ruuviTag.with(sensorSettings: - self?.sensorSettings).with(source: .advertisement) + self?.sensorSettings).with(source: .advertisement) ) } } } else { ruuviTagObserveLastRecordToken?.invalidate() - ruuviTagObserveLastRecordToken = ruuviReactor.observeLatest(ruuviTag) { [weak self] (changes) in - if case .update(let anyRecord) = changes, - let record = anyRecord { + ruuviTagObserveLastRecordToken = ruuviReactor.observeLatest(ruuviTag) { [weak self] changes in + if case let .update(anyRecord) = changes, + let record = anyRecord + { self?.lastSensorRecord = record self?.view.viewModel.update( ruuviTagRecord: record.with(sensorSettings: self?.sensorSettings) @@ -185,22 +188,23 @@ extension OffsetCorrectionPresenter: OffsetCorrectionViewOutput { temperatureUnitSettingToken = NotificationCenter.default .addObserver(forName: .TemperatureUnitDidChange, object: nil, - queue: .main) { [weak self] _ in - self?.view.viewModel.temperatureUnit.value = self?.settings.temperatureUnit - } + queue: .main) + { [weak self] _ in + self?.view.viewModel.temperatureUnit.value = self?.settings.temperatureUnit + } humidityUnitSettingToken = NotificationCenter.default .addObserver(forName: .HumidityUnitDidChange, object: nil, queue: .main, using: { [weak self] _ in - self?.view.viewModel.humidityUnit.value = self?.settings.humidityUnit + self?.view.viewModel.humidityUnit.value = self?.settings.humidityUnit }) pressureUnitSettingToken = NotificationCenter.default .addObserver(forName: .PressureUnitDidChange, object: nil, queue: .main, using: { [weak self] _ in - self?.view.viewModel.pressureUnit.value = self?.settings.pressureUnit + self?.view.viewModel.pressureUnit.value = self?.settings.pressureUnit }) } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift index efb698e25..b8a8ebeb3 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift @@ -1,9 +1,9 @@ -import UIKit -import RuuviOntology import RuuviLocalization +import RuuviOntology import RuuviService +import UIKit #if canImport(RuuviServiceMeasurement) -import RuuviServiceMeasurement + import RuuviServiceMeasurement #endif class OffsetCorrectionAppleViewController: UIViewController { @@ -18,7 +18,7 @@ class OffsetCorrectionAppleViewController: UIViewController { } private lazy var backButton: UIButton = { - let button = UIButton() + let button = UIButton() button.tintColor = .label let buttonImage = RuuviAssets.backButtonImage button.setImage(buttonImage, for: .normal) @@ -29,16 +29,16 @@ class OffsetCorrectionAppleViewController: UIViewController { return button }() - @IBOutlet weak var correctedValueTitle: UILabel! - @IBOutlet weak var originalValueTitle: UILabel! - @IBOutlet weak var descriptionTextView: UITextView! - @IBOutlet weak var originalValueLabel: UILabel! - @IBOutlet weak var originalValueUpdateTimeLabel: UILabel! - @IBOutlet weak var correctedValueLabel: UILabel! - @IBOutlet weak var offsetValueLabel: UILabel! - @IBOutlet weak var correctedValueView: UIView! - @IBOutlet weak var calibrateButton: UIButton! - @IBOutlet weak var clearButton: UIButton! + @IBOutlet var correctedValueTitle: UILabel! + @IBOutlet var originalValueTitle: UILabel! + @IBOutlet var descriptionTextView: UITextView! + @IBOutlet var originalValueLabel: UILabel! + @IBOutlet var originalValueUpdateTimeLabel: UILabel! + @IBOutlet var correctedValueLabel: UILabel! + @IBOutlet var offsetValueLabel: UILabel! + @IBOutlet var correctedValueView: UIView! + @IBOutlet var calibrateButton: UIButton! + @IBOutlet var clearButton: UIButton! private var timer: Timer? private var updatedAt: Date? @@ -50,7 +50,7 @@ class OffsetCorrectionAppleViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { [weak self] (_) in + timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { [weak self] _ in if let updateAt = self?.updatedAt { self?.originalValueUpdateTimeLabel.text = "(\(updateAt.ruuviAgo()))" } @@ -76,9 +76,10 @@ class OffsetCorrectionAppleViewController: UIViewController { bindViews() } } + private func bindViews() { - correctedValueView.bind(viewModel.hasOffsetValue) {[weak self] _, hasValue in - if let hasValue = hasValue, hasValue == true { + correctedValueView.bind(viewModel.hasOffsetValue) { [weak self] _, hasValue in + if let hasValue, hasValue == true { self?.correctedValueView.isHidden = false self?.clearButton.isEnabled = true self?.clearButton.alpha = 1 @@ -89,6 +90,7 @@ class OffsetCorrectionAppleViewController: UIViewController { } } } + private func bindLabels() { originalValueLabel.bind(viewModel.originalValue) { [weak self] label, value in switch self?.viewModel.type { @@ -102,21 +104,20 @@ class OffsetCorrectionAppleViewController: UIViewController { allowSettings: false) } } - originalValueUpdateTimeLabel.bind(viewModel.updateAt) {[weak self] label, date in - if let date = date { + originalValueUpdateTimeLabel.bind(viewModel.updateAt) { [weak self] label, date in + if let date { self?.updatedAt = date label.text = "(\(date.ruuviAgo()))" } } offsetValueLabel.bind(viewModel.offsetCorrectionValue) { [weak self] label, value in - let text: String? - switch self?.viewModel.type { + let text: String? = switch self?.viewModel.type { case .humidity: - text = self?.measurementService.humidityOffsetCorrectionString(for: value ?? 0) + self?.measurementService.humidityOffsetCorrectionString(for: value ?? 0) case .pressure: - text = self?.measurementService.pressureOffsetCorrectionString(for: value ?? 0) + self?.measurementService.pressureOffsetCorrectionString(for: value ?? 0) default: - text = self?.measurementService.temperatureOffsetCorrectionString(for: value ?? 0) + self?.measurementService.temperatureOffsetCorrectionString(for: value ?? 0) } label.text = "(\(text!))" @@ -143,11 +144,11 @@ extension OffsetCorrectionAppleViewController: OffsetCorrectionViewInput { originalValueTitle.text = RuuviLocalization.OffsetCorrection.OriginalValue.title calibrateButton.setTitle(RuuviLocalization.HumidityCalibration.Button.Calibrate.title, for: .normal) clearButton.setTitle(RuuviLocalization.HumidityCalibration.Button.Clear.title, for: .normal) - self.title = self.viewModel.title + title = viewModel.title } private func configDescriptionContent() { - let text = RuuviLocalization.OffsetCorrection.CalibrationDescription.text + let text = RuuviLocalization.OffsetCorrection.CalibrationDescription.text let attrString = NSMutableAttributedString(string: text) let muliRegular = UIFont.Muli(.regular, size: 16) @@ -155,8 +156,8 @@ extension OffsetCorrectionAppleViewController: OffsetCorrectionViewInput { attrString.addAttribute(NSAttributedString.Key.font, value: muliRegular, range: range) // make text color gray attrString.addAttribute(.foregroundColor, - value: RuuviColor.ruuviTextColor ?? UIColor.secondaryLabel, - range: NSRange(location: 0, length: attrString.length)) + value: RuuviColor.ruuviTextColor ?? UIColor.secondaryLabel, + range: NSRange(location: 0, length: attrString.length)) descriptionTextView.attributedText = attrString descriptionTextView.textColor = RuuviColor.ruuviTextColor @@ -165,16 +166,16 @@ extension OffsetCorrectionAppleViewController: OffsetCorrectionViewInput { func showCalibrateDialog() { let title = RuuviLocalization.OffsetCorrection.Dialog.Calibration.title var message = "" - switch self.viewModel.type { + switch viewModel.type { case .humidity: message = RuuviLocalization.OffsetCorrection.Dialog.Calibration.enterHumidity("%") case .pressure: let format = RuuviLocalization.OffsetCorrection.Dialog.Calibration.enterPressure - let unit = self.viewModel.pressureUnit.value ?? .hectopascals + let unit = viewModel.pressureUnit.value ?? .hectopascals message = format(unit.symbol) default: let format = RuuviLocalization.OffsetCorrection.Dialog.Calibration.enterTemperature - let unit = self.viewModel.temperatureUnit.value ?? .celsius + let unit = viewModel.temperatureUnit.value ?? .celsius message = format(unit.symbol) } @@ -182,12 +183,12 @@ extension OffsetCorrectionAppleViewController: OffsetCorrectionViewInput { controller.addTextField { textfield in textfield.keyboardType = .numbersAndPunctuation } - controller.addAction(UIAlertAction(title: RuuviLocalization.confirm, - style: .destructive, - handler: { [weak self] _ in - let text = controller.textFields?.first?.text ?? "0.0" - self?.output.viewDidSetCorrectValue(correctValue: text.doubleValue) - })) + controller.addAction(UIAlertAction(title: RuuviLocalization.confirm, + style: .destructive, + handler: { [weak self] _ in + let text = controller.textFields?.first?.text ?? "0.0" + self?.output.viewDidSetCorrectValue(correctValue: text.doubleValue) + })) controller.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) present(controller, animated: true) } @@ -197,26 +198,27 @@ extension OffsetCorrectionAppleViewController: OffsetCorrectionViewInput { let message = RuuviLocalization.OffsetCorrection.Dialog.Calibration.clearConfirm let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) controller.addAction(UIAlertAction(title: RuuviLocalization.confirm, - style: .destructive, - handler: { [weak self] _ in - self?.output.viewDidClearOffsetValue() - })) + style: .destructive, + handler: { [weak self] _ in + self?.output.viewDidClearOffsetValue() + })) controller.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) present(controller, animated: true) } } // MARK: - IBOutlet + extension OffsetCorrectionAppleViewController { - @IBAction func calibrateButtonAction(_ sender: Any) { + @IBAction func calibrateButtonAction(_: Any) { output.viewDidOpenCalibrateDialog() } - @IBAction func clearButtonAction(_ sender: Any) { + @IBAction func clearButtonAction(_: Any) { output.viewDidOpenClearDialog() } - @objc fileprivate func backButtonDidTap() { + @objc private func backButtonDidTap() { _ = navigationController?.popViewController(animated: true) } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift index d9da13165..5bfeaa087 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift @@ -1,35 +1,35 @@ -import UIKit import BTKit import Humidity -import RuuviOntology import RuuviLocal import RuuviLocalization +import RuuviOntology +import UIKit class OffsetCorrectionViewModel { var type: OffsetCorrectionType = .temperature - var originalValue: Observable = Observable() - var updateAt: Observable = Observable() - var offsetCorrectionValue: Observable = Observable() - var offsetCorrectionDate: Observable = Observable() - var correctedValue: Observable = Observable() + var originalValue: Observable = .init() + var updateAt: Observable = .init() + var offsetCorrectionValue: Observable = .init() + var offsetCorrectionDate: Observable = .init() + var correctedValue: Observable = .init() - let temperatureUnit: Observable = Observable() - let humidityUnit: Observable = Observable() - let pressureUnit: Observable = Observable() + let temperatureUnit: Observable = .init() + let humidityUnit: Observable = .init() + let pressureUnit: Observable = .init() var title: String { switch type { case .humidity: - return RuuviLocalization.OffsetCorrection.Humidity.title + RuuviLocalization.OffsetCorrection.Humidity.title case .pressure: - return RuuviLocalization.OffsetCorrection.Pressure.title + RuuviLocalization.OffsetCorrection.Pressure.title default: - return RuuviLocalization.OffsetCorrection.Temperature.title + RuuviLocalization.OffsetCorrection.Temperature.title } } - var hasOffsetValue: Observable = Observable(false) + var hasOffsetValue: Observable = .init(false) init() { type = .pressure @@ -37,50 +37,51 @@ class OffsetCorrectionViewModel { } convenience init(type: OffsetCorrectionType, - sensorSettings: SensorSettings) { + sensorSettings: SensorSettings) + { self.init() self.type = type - self.update(sensorSettings: sensorSettings) + update(sensorSettings: sensorSettings) } func update(ruuviTagRecord: RuuviTagSensorRecord) { switch type { case .temperature: if let value = ruuviTagRecord.temperature?.value { - self.originalValue.value = value - ruuviTagRecord.temperatureOffset - self.correctedValue.value = value + originalValue.value = value - ruuviTagRecord.temperatureOffset + correctedValue.value = value } case .humidity: if let value = ruuviTagRecord.humidity?.value { - self.originalValue.value = value - ruuviTagRecord.humidityOffset - self.correctedValue.value = value + originalValue.value = value - ruuviTagRecord.humidityOffset + correctedValue.value = value } case .pressure: if let value = ruuviTagRecord.pressure?.value { - self.originalValue.value = value - ruuviTagRecord.pressureOffset - self.correctedValue.value = value + originalValue.value = value - ruuviTagRecord.pressureOffset + correctedValue.value = value } } - self.updateAt.value = ruuviTagRecord.date + updateAt.value = ruuviTagRecord.date } func update(sensorSettings: SensorSettings) { switch type { case .temperature: - self.offsetCorrectionValue.value = sensorSettings.temperatureOffset - self.offsetCorrectionDate.value = sensorSettings.temperatureOffsetDate + offsetCorrectionValue.value = sensorSettings.temperatureOffset + offsetCorrectionDate.value = sensorSettings.temperatureOffsetDate case .humidity: - self.offsetCorrectionValue.value = sensorSettings.humidityOffset - self.offsetCorrectionDate.value = sensorSettings.humidityOffsetDate + offsetCorrectionValue.value = sensorSettings.humidityOffset + offsetCorrectionDate.value = sensorSettings.humidityOffsetDate case .pressure: - self.offsetCorrectionValue.value = sensorSettings.pressureOffset - self.offsetCorrectionDate.value = sensorSettings.pressureOffsetDate + offsetCorrectionValue.value = sensorSettings.pressureOffset + offsetCorrectionDate.value = sensorSettings.pressureOffsetDate } - if let value = self.offsetCorrectionValue.value, value != 0 { - self.hasOffsetValue.value = true + if let value = offsetCorrectionValue.value, value != 0 { + hasOffsetValue.value = true } else { - self.hasOffsetValue.value = false + hasOffsetValue.value = false } } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerConfigurator.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerConfigurator.swift index ea9bf3650..facead928 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerConfigurator.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerConfigurator.swift @@ -1,9 +1,9 @@ import Foundation -import RuuviService +import RuuviLocal import RuuviPool -import RuuviStorage import RuuviPresenters -import RuuviLocal +import RuuviService +import RuuviStorage final class OwnerConfigurator { func configure(view: OwnerViewController) { diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerInitializer.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerInitializer.swift index 762f3003b..ddd28fdad 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerInitializer.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerInitializer.swift @@ -1,7 +1,7 @@ import UIKit final class OwnerInitializer: NSObject { - @IBOutlet weak var viewController: OwnerViewController! + @IBOutlet var viewController: OwnerViewController! override func awakeFromNib() { super.awakeFromNib() diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift index 5d3f66d7e..105ea4dac 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift @@ -1,10 +1,10 @@ import Foundation +import RuuviLocal import RuuviOntology -import RuuviService import RuuviPool -import RuuviStorage import RuuviPresenters -import RuuviLocal +import RuuviService +import RuuviStorage enum OwnershipMode { case claim @@ -32,7 +32,7 @@ final class OwnerPresenter: OwnerModuleInput { func configure(ruuviTag: RuuviTagSensor, mode: OwnershipMode) { self.ruuviTag = ruuviTag - self.ownershipMode = mode + ownershipMode = mode } } @@ -55,13 +55,14 @@ extension OwnerPresenter: OwnerViewOutput { func updateOwnerInfo(with email: String) { ruuviStorage.readAll().on(success: { [weak self] localSensors in guard let sSelf = self else { return } - if let sensor = localSensors.first(where: {$0.id == sSelf.ruuviTag.id }) { + if let sensor = localSensors.first(where: { $0.id == sSelf.ruuviTag.id }) { sSelf.ruuviPool.update(sensor - .with(owner: email) - .with(isOwner: false)) + .with(owner: email) + .with(isOwner: false)) } }) } + func viewDidTriggerFirmwareUpdateDialog() { guard ruuviTag.luid?.value != nil, ruuviTag.version < 5, diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift index b32b129fc..14ac4b772 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift @@ -13,7 +13,7 @@ final class OwnerRouter: OwnerRouterInput { func openUpdateFirmware(ruuviTag: RuuviTagSensor) { let factory: DFUModuleFactory = DFUModuleFactoryImpl() let module = factory.create(for: ruuviTag) - self.dfuModule = module + dfuModule = module transitionHandler .navigationController? .pushViewController( diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift index ba8aece2a..9c5a76afc 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift @@ -6,9 +6,9 @@ final class OwnerViewController: UIViewController { var mode: OwnershipMode = .claim - @IBOutlet weak var claimOwnershipDescriptionLabel: UILabel! - @IBOutlet weak var removeCloudHistoryActionContainer: UIView! - @IBOutlet weak var claimOwnershipButton: UIButton! + @IBOutlet var claimOwnershipDescriptionLabel: UILabel! + @IBOutlet var removeCloudHistoryActionContainer: UIView! + @IBOutlet var claimOwnershipButton: UIButton! private lazy var removeCloudHistoryTitleLabel: UILabel = { let label = UILabel() @@ -37,7 +37,7 @@ final class OwnerViewController: UIViewController { }() private lazy var backButton: UIButton = { - let button = UIButton() + let button = UIButton() button.tintColor = .label let buttonImage = RuuviAssets.backButtonImage button.setImage(buttonImage, for: .normal) @@ -51,7 +51,7 @@ final class OwnerViewController: UIViewController { var removeCloudHistoryContainerVisibleConstraint: NSLayoutConstraint! var removeCloudHistoryContainerHiddenConstraint: NSLayoutConstraint! - @IBAction func claimOwnershipButtonTouchUpInside(_ sender: Any) { + @IBAction func claimOwnershipButtonTouchUpInside(_: Any) { output.viewDidTapOnClaim(mode: mode) } @@ -91,7 +91,7 @@ extension OwnerViewController: OwnerViewInput { claimOwnershipButton.setTitle(RuuviLocalization.unclaim.capitalized, for: .normal) } removeCloudHistoryContainerVisibleConstraint.isActive = mode == .unclaim - removeCloudHistoryContainerHiddenConstraint.isActive = mode == .claim + removeCloudHistoryContainerHiddenConstraint.isActive = mode == .claim removeCloudHistoryActionContainer.isHidden = mode == .claim } @@ -129,9 +129,9 @@ extension OwnerViewController: OwnerViewInput { controller.addAction(UIAlertAction(title: RuuviLocalization.confirm, style: .destructive, handler: { [weak self] _ in - guard let self = self else { return } - self.output?.viewDidConfirmUnclaim(removeCloudHistory: self.removeCloudHistorySwitch.isOn) - })) + guard let self else { return } + output?.viewDidConfirmUnclaim(removeCloudHistory: removeCloudHistorySwitch.isOn) + })) controller.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) present(controller, animated: true) } @@ -151,9 +151,8 @@ extension OwnerViewController { } private func setUpCloudHistoryContentView() { - let horizontalStackView = UIStackView(arrangedSubviews: [ - removeCloudHistoryTitleLabel, removeCloudHistorySwitch + removeCloudHistoryTitleLabel, removeCloudHistorySwitch, ]) horizontalStackView.spacing = 8 horizontalStackView.distribution = .fill @@ -161,7 +160,7 @@ extension OwnerViewController { removeCloudHistorySwitch.constrainWidth(constant: 51) let verticalStackView = UIStackView(arrangedSubviews: [ - horizontalStackView, removeCloudHistoryDescriptionLabel + horizontalStackView, removeCloudHistoryDescriptionLabel, ]) verticalStackView.spacing = 10 verticalStackView.distribution = .fill @@ -181,22 +180,22 @@ extension OwnerViewController { removeCloudHistoryActionContainer.isHidden = true removeCloudHistoryContainerVisibleConstraint = - claimOwnershipButton - .topAnchor - .constraint( - equalTo: removeCloudHistoryActionContainer.bottomAnchor, - constant: 40 - ) + claimOwnershipButton + .topAnchor + .constraint( + equalTo: removeCloudHistoryActionContainer.bottomAnchor, + constant: 40 + ) removeCloudHistoryContainerHiddenConstraint = - claimOwnershipButton - .topAnchor - .constraint( - equalTo: claimOwnershipDescriptionLabel.bottomAnchor, - constant: 40 - ) + claimOwnershipButton + .topAnchor + .constraint( + equalTo: claimOwnershipDescriptionLabel.bottomAnchor, + constant: 40 + ) } - @objc fileprivate func backButtonDidTap() { + @objc private func backButtonDidTap() { output.viewDidDismiss() } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Assembly/SensorRemovalModuleFactory.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Assembly/SensorRemovalModuleFactory.swift index a318d2258..98b9acdb9 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Assembly/SensorRemovalModuleFactory.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Assembly/SensorRemovalModuleFactory.swift @@ -1,7 +1,7 @@ import Foundation -import RuuviService -import RuuviPresenters import RuuviLocal +import RuuviPresenters +import RuuviService protocol SensorRemovalModuleFactory { func create() -> SensorRemovalViewController diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalPresenter.swift index fcb2721f6..2e8b065cd 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalPresenter.swift @@ -1,8 +1,8 @@ import Foundation +import RuuviLocal import RuuviOntology -import RuuviService import RuuviPresenters -import RuuviLocal +import RuuviService final class SensorRemovalPresenter: SensorRemovalModuleInput { weak var view: SensorRemovalViewInput? @@ -29,11 +29,12 @@ final class SensorRemovalPresenter: SensorRemovalModuleInput { extension SensorRemovalPresenter: SensorRemovalViewOutput { func viewDidLoad() { - guard let ruuviTag = ruuviTag else { return } + guard let ruuviTag else { return } view?.updateView( claimedAndOwned: ruuviTag.isClaimed && ruuviTag.isOwner, locallyOwned: !ruuviTag.isClaimed && ruuviTag.isOwner, - shared: !ruuviTag.isOwner) + shared: !ruuviTag.isOwner + ) } func viewDidTriggerRemoveTag() { @@ -41,7 +42,7 @@ extension SensorRemovalPresenter: SensorRemovalViewOutput { } func viewDidConfirmTagRemoval(with removeCloudData: Bool) { - guard let ruuviTag = ruuviTag else { return } + guard let ruuviTag else { return } ruuviOwnershipService.remove( sensor: ruuviTag, removeCloudHistory: removeCloudData diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/SensorRemovalViewOutput.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/SensorRemovalViewOutput.swift index 5456ae59d..0f10b7737 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/SensorRemovalViewOutput.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/SensorRemovalViewOutput.swift @@ -1,5 +1,5 @@ -import Foundation import CoreNFC +import Foundation protocol SensorRemovalViewOutput { func viewDidLoad() diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift index 10409a932..42e2a7c4b 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift @@ -1,12 +1,11 @@ -import RuuviLocalization -import UIKit import CoreNFC +import RuuviLocalization import RuuviOntology +import UIKit class SensorRemovalViewController: UIViewController { - private lazy var backButton: UIButton = { - let button = UIButton() + let button = UIButton() button.tintColor = .label let buttonImage = RuuviAssets.backButtonImage button.setImage(buttonImage, for: .normal) @@ -26,7 +25,7 @@ class SensorRemovalViewController: UIViewController { return label }() - private var removeCloudHistoryActionContainer = UIView.init(color: .clear) + private var removeCloudHistoryActionContainer = UIView(color: .clear) private lazy var removeCloudHistoryTitleLabel: UILabel = { let label = UILabel() label.text = RuuviLocalization.removeCloudHistoryTitle @@ -69,10 +68,10 @@ class SensorRemovalViewController: UIViewController { var output: SensorRemovalViewOutput? var removeButtonConstraintClaimedSensor: NSLayoutConstraint! var removeButtonConstraintOtherSensor: NSLayoutConstraint! - } // MARK: - VIEW LIFECYCLE + extension SensorRemovalViewController { override func viewDidLoad() { super.viewDidLoad() @@ -82,14 +81,14 @@ extension SensorRemovalViewController { } // MARK: - SensorForceClaimViewInput -extension SensorRemovalViewController: SensorRemovalViewInput { +extension SensorRemovalViewController: SensorRemovalViewInput { func localize() { // No op. } func updateView(claimedAndOwned: Bool, locallyOwned: Bool, shared: Bool) { - var message: String = "" + var message = "" if claimedAndOwned { message = RuuviLocalization.removeClaimedSensorDescription } @@ -117,15 +116,16 @@ extension SensorRemovalViewController: SensorRemovalViewInput { controller.addAction(UIAlertAction(title: RuuviLocalization.confirm, style: .destructive, handler: { [weak self] _ in - guard let self = self else { return } - self.output?.viewDidConfirmTagRemoval(with: self.removeCloudHistorySwitch.isOn) - })) + guard let self else { return } + output?.viewDidConfirmTagRemoval(with: removeCloudHistorySwitch.isOn) + })) controller.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) present(controller, animated: true) } } // MARK: - PRIVATE SET UI + extension SensorRemovalViewController { private func setUpUI() { setUpBase() @@ -133,7 +133,7 @@ extension SensorRemovalViewController { } private func setUpBase() { - self.title = RuuviLocalization.TagSettings.ConfirmTagRemovalDialog.title + title = RuuviLocalization.TagSettings.ConfirmTagRemovalDialog.title view.backgroundColor = RuuviColor.ruuviPrimary @@ -160,7 +160,7 @@ extension SensorRemovalViewController { ) let horizontalStackView = UIStackView(arrangedSubviews: [ - removeCloudHistoryTitleLabel, removeCloudHistorySwitch + removeCloudHistoryTitleLabel, removeCloudHistorySwitch, ]) horizontalStackView.spacing = 8 horizontalStackView.distribution = .fill @@ -168,7 +168,7 @@ extension SensorRemovalViewController { removeCloudHistorySwitch.constrainWidth(constant: 51) let verticalStackView = UIStackView(arrangedSubviews: [ - horizontalStackView, removeCloudHistoryDescriptionLabel + horizontalStackView, removeCloudHistoryDescriptionLabel, ]) verticalStackView.spacing = 10 verticalStackView.distribution = .fill @@ -201,22 +201,23 @@ extension SensorRemovalViewController { removeButton .topAnchor .constraint( - equalTo: removeCloudHistoryActionContainer.bottomAnchor, - constant: 40 - ) + equalTo: removeCloudHistoryActionContainer.bottomAnchor, + constant: 40 + ) removeButtonConstraintOtherSensor = removeButton .topAnchor .constraint( - equalTo: messageLabel.bottomAnchor, - constant: 40 - ) + equalTo: messageLabel.bottomAnchor, + constant: 40 + ) } } // MARK: - IBACTIONS + extension SensorRemovalViewController { - @objc fileprivate func backButtonDidTap() { + @objc private func backButtonDidTap() { _ = navigationController?.popViewController(animated: true) } diff --git a/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift b/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift index 7ee9dc516..63381e91f 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift @@ -1,103 +1,103 @@ -import UIKit import RuuviOntology +import UIKit struct TagSettingsViewModel { - let background: Observable = Observable() - let name: Observable = Observable() - let uuid: Observable = Observable() - let mac: Observable = Observable() - let rssi: Observable = Observable() - let humidity: Observable = Observable() - let temperature: Observable = Observable() - let humidityOffset: Observable = Observable() - let voltage: Observable = Observable() - let batteryNeedsReplacement: Observable = Observable() - let accelerationX: Observable = Observable() - let accelerationY: Observable = Observable() - let accelerationZ: Observable = Observable() - let version: Observable = Observable() - let firmwareVersion: Observable = Observable() - let movementCounter: Observable = Observable() - let measurementSequenceNumber: Observable = Observable() - let txPower: Observable = Observable() - let isConnectable: Observable = Observable() - let isConnected: Observable = Observable() - let isNetworkConnected: Observable = Observable() - let keepConnection: Observable = Observable() - let isPushNotificationsEnabled: Observable = Observable() - - let temperatureUnit: Observable = Observable() - let humidityUnit: Observable = Observable() - let pressureUnit: Observable = Observable() - - let isTemperatureAlertOn: Observable = Observable(false) - let temperatureAlertMutedTill: Observable = Observable(nil) - let temperatureLowerBound: Observable = Observable(Temperature(-40, unit: .celsius)) - let temperatureUpperBound: Observable = Observable(Temperature(85, unit: .celsius)) - let temperatureAlertDescription: Observable = Observable() - let temperatureAlertState: Observable = Observable() - - let isRelativeHumidityAlertOn: Observable = Observable(false) - let relativeHumidityAlertMutedTill: Observable = Observable(nil) - let relativeHumidityLowerBound: Observable = Observable(0) - let relativeHumidityUpperBound: Observable = Observable(100.0) - let relativeHumidityAlertDescription: Observable = Observable() - let relativeHumidityAlertState: Observable = Observable() - - let isPressureAlertOn: Observable = Observable(false) - let pressureAlertMutedTill: Observable = Observable(nil) - let pressureLowerBound: Observable = Observable(Pressure(500, unit: .hectopascals)) - let pressureUpperBound: Observable = Observable(Pressure(1155, unit: .hectopascals)) - let pressureAlertDescription: Observable = Observable() - let pressureAlertState: Observable = Observable() - - let isSignalAlertOn: Observable = Observable(false) - let signalAlertMutedTill: Observable = Observable(nil) - let signalLowerBound: Observable = Observable(-105) - let signalUpperBound: Observable = Observable(0) - let signalAlertDescription: Observable = Observable() - let signalAlertState: Observable = Observable() - - let isConnectionAlertOn: Observable = Observable(false) - let connectionAlertMutedTill: Observable = Observable(nil) - let connectionAlertDescription: Observable = Observable() - let connectionAlertState: Observable = Observable() - - let isCloudConnectionAlertOn: Observable = Observable(false) - let cloudConnectionAlertMutedTill: Observable = Observable(nil) - let cloudConnectionAlertUnseenDuration: Observable = Observable() - let cloudConnectionAlertDescription: Observable = Observable() - let cloudConnectionAlertState: Observable = Observable() - - let isMovementAlertOn: Observable = Observable(false) - let movementAlertMutedTill: Observable = Observable(nil) - let movementAlertDescription: Observable = Observable() - let movementAlertState: Observable = Observable() - - let isAuthorized: Observable = Observable(true) - let canClaimTag: Observable = Observable(false) - let canShareTag: Observable = Observable(false) - var sharedTo: Observable<[String]?> = Observable<[String]?>() - let isClaimedTag: Observable = Observable(false) - let owner: Observable = Observable() - let isOwner: Observable = Observable(false) - let ownersPlan: Observable = Observable() - let isOwnersPlanProPlus: Observable = Observable(false) - - let temperatureOffsetCorrection: Observable = Observable() - let humidityOffsetCorrection: Observable = Observable() - let pressureOffsetCorrection: Observable = Observable() - - let humidityOffsetCorrectionVisible: Observable = Observable() - let pressureOffsetCorrectionVisible: Observable = Observable() - - let isAlertsEnabled: Observable = Observable(false) - let isPNAlertsAvailiable: Observable = Observable(false) - let isCloudAlertsAvailable: Observable = Observable(false) - - var source: Observable = Observable() - - var latestMeasurement: Observable = Observable() + let background: Observable = .init() + let name: Observable = .init() + let uuid: Observable = .init() + let mac: Observable = .init() + let rssi: Observable = .init() + let humidity: Observable = .init() + let temperature: Observable = .init() + let humidityOffset: Observable = .init() + let voltage: Observable = .init() + let batteryNeedsReplacement: Observable = .init() + let accelerationX: Observable = .init() + let accelerationY: Observable = .init() + let accelerationZ: Observable = .init() + let version: Observable = .init() + let firmwareVersion: Observable = .init() + let movementCounter: Observable = .init() + let measurementSequenceNumber: Observable = .init() + let txPower: Observable = .init() + let isConnectable: Observable = .init() + let isConnected: Observable = .init() + let isNetworkConnected: Observable = .init() + let keepConnection: Observable = .init() + let isPushNotificationsEnabled: Observable = .init() + + let temperatureUnit: Observable = .init() + let humidityUnit: Observable = .init() + let pressureUnit: Observable = .init() + + let isTemperatureAlertOn: Observable = .init(false) + let temperatureAlertMutedTill: Observable = .init(nil) + let temperatureLowerBound: Observable = .init(Temperature(-40, unit: .celsius)) + let temperatureUpperBound: Observable = .init(Temperature(85, unit: .celsius)) + let temperatureAlertDescription: Observable = .init() + let temperatureAlertState: Observable = .init() + + let isRelativeHumidityAlertOn: Observable = .init(false) + let relativeHumidityAlertMutedTill: Observable = .init(nil) + let relativeHumidityLowerBound: Observable = .init(0) + let relativeHumidityUpperBound: Observable = .init(100.0) + let relativeHumidityAlertDescription: Observable = .init() + let relativeHumidityAlertState: Observable = .init() + + let isPressureAlertOn: Observable = .init(false) + let pressureAlertMutedTill: Observable = .init(nil) + let pressureLowerBound: Observable = .init(Pressure(500, unit: .hectopascals)) + let pressureUpperBound: Observable = .init(Pressure(1155, unit: .hectopascals)) + let pressureAlertDescription: Observable = .init() + let pressureAlertState: Observable = .init() + + let isSignalAlertOn: Observable = .init(false) + let signalAlertMutedTill: Observable = .init(nil) + let signalLowerBound: Observable = .init(-105) + let signalUpperBound: Observable = .init(0) + let signalAlertDescription: Observable = .init() + let signalAlertState: Observable = .init() + + let isConnectionAlertOn: Observable = .init(false) + let connectionAlertMutedTill: Observable = .init(nil) + let connectionAlertDescription: Observable = .init() + let connectionAlertState: Observable = .init() + + let isCloudConnectionAlertOn: Observable = .init(false) + let cloudConnectionAlertMutedTill: Observable = .init(nil) + let cloudConnectionAlertUnseenDuration: Observable = .init() + let cloudConnectionAlertDescription: Observable = .init() + let cloudConnectionAlertState: Observable = .init() + + let isMovementAlertOn: Observable = .init(false) + let movementAlertMutedTill: Observable = .init(nil) + let movementAlertDescription: Observable = .init() + let movementAlertState: Observable = .init() + + let isAuthorized: Observable = .init(true) + let canClaimTag: Observable = .init(false) + let canShareTag: Observable = .init(false) + var sharedTo: Observable<[String]?> = .init() + let isClaimedTag: Observable = .init(false) + let owner: Observable = .init() + let isOwner: Observable = .init(false) + let ownersPlan: Observable = .init() + let isOwnersPlanProPlus: Observable = .init(false) + + let temperatureOffsetCorrection: Observable = .init() + let humidityOffsetCorrection: Observable = .init() + let pressureOffsetCorrection: Observable = .init() + + let humidityOffsetCorrectionVisible: Observable = .init() + let pressureOffsetCorrectionVisible: Observable = .init() + + let isAlertsEnabled: Observable = .init(false) + let isPNAlertsAvailiable: Observable = .init(false) + let isCloudAlertsAvailable: Observable = .init(false) + + var source: Observable = .init() + + var latestMeasurement: Observable = .init() func updateRecord(_ record: RuuviTagSensorRecord) { humidity.value = record.humidity @@ -112,12 +112,12 @@ struct TagSettingsViewModel { source.value = record.source let batteryStatusProvider = RuuviTagBatteryStatusProvider() batteryNeedsReplacement.value = batteryStatusProvider.batteryNeedsReplacement(temperature: record.temperature, - voltage: record.voltage) + voltage: record.voltage) latestMeasurement.value = record } func reset() { - // TODO:- @Priyonto: This whole block needs to be refactored in good level later + // TODO: - @Priyonto: This whole block needs to be refactored in good level later isTemperatureAlertOn.value = false temperatureLowerBound.value = Temperature(-40, unit: .celsius) temperatureUpperBound.value = Temperature(85, unit: .celsius) diff --git a/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewOutput.swift b/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewOutput.swift index d7f868377..1c6b1b351 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewOutput.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewOutput.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviOntology +import UIKit protocol TagSettingsViewOutput { func viewDidLoad() diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift index 287d0e519..ab87e0c71 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift @@ -5,7 +5,6 @@ protocol RUAlertDetailsCellChildViewDelegate: NSObjectProtocol { } class RUAlertDetailsCellChildView: UIView { - // Public weak var delegate: RUAlertDetailsCellChildViewDelegate? @@ -30,18 +29,18 @@ class RUAlertDetailsCellChildView: UIView { override init(frame: CGRect) { super.init(frame: frame) - self.setUpUI() + setUpUI() } required init?(coder: NSCoder) { super.init(coder: coder) - self.setUpUI() + setUpUI() } } extension RUAlertDetailsCellChildView { private func setUpUI() { - self.backgroundColor = .clear + backgroundColor = .clear addSubview(titleLabel) titleLabel.anchor(top: topAnchor, @@ -74,7 +73,9 @@ extension RUAlertDetailsCellChildView { delegate?.didTapView(sender: self) } } + // MARK: - Public Setter + extension RUAlertDetailsCellChildView { func configure(with message: String?) { titleLabel.text = message diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift index 6e572c736..fa6b50c4e 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift @@ -5,7 +5,6 @@ protocol RUAlertExpandButtonDelegate: NSObjectProtocol { } class RUAlertExpandButton: UIView { - // Public weak var delegate: RUAlertExpandButtonDelegate? @@ -23,12 +22,12 @@ class RUAlertExpandButton: UIView { override init(frame: CGRect) { super.init(frame: frame) - self.setUpUI() + setUpUI() } required init?(coder: NSCoder) { super.init(coder: coder) - self.setUpUI() + setUpUI() } } @@ -61,7 +60,9 @@ extension RUAlertExpandButton { delegate?.didTapButton(sender: self, expanded: isExpanded) } } + // MARK: - Public Setter + extension RUAlertExpandButton { func toggle() { handleButtonTap() diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/RangeSeekSlider/RURangeSeekSlider.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/RangeSeekSlider/RURangeSeekSlider.swift index 2b78cf665..160cdc4f1 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/RangeSeekSlider/RURangeSeekSlider.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/RangeSeekSlider/RURangeSeekSlider.swift @@ -2,12 +2,11 @@ import RangeSeekSlider import UIKit class RURangeSeekSlider: RangeSeekSlider { - - open override var intrinsicContentSize: CGSize { - return CGSize(width: UIView.noIntrinsicMetric, height: 40) + override open var intrinsicContentSize: CGSize { + CGSize(width: UIView.noIntrinsicMetric, height: 40) } override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { - return !(gestureRecognizer is UIPanGestureRecognizer) + !(gestureRecognizer is UIPanGestureRecognizer) } } diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift index 72d3dd88a..91bcddbb0 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift @@ -1,6 +1,6 @@ -import UIKit import RangeSeekSlider import RuuviLocalization +import UIKit protocol TagSettingsAlertConfigCellDelegate: AnyObject { func didSelectSetCustomDescription(sender: TagSettingsAlertConfigCell) @@ -99,7 +99,8 @@ class TagSettingsAlertConfigCell: UITableViewCell { // Init override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) { + reuseIdentifier: String?) + { super.init(style: style, reuseIdentifier: reuseIdentifier) setUpUI() } @@ -129,9 +130,9 @@ extension TagSettingsAlertConfigCell { addSubview(noticeView) noticeView.anchor(top: topAnchor, - leading: self.safeLeftAnchor, + leading: safeLeftAnchor, bottom: nil, - trailing: self.safeRightAnchor) + trailing: safeRightAnchor) noticeViewHiddenHeight = noticeView.heightAnchor.constraint(equalToConstant: 0) noticeViewHiddenHeight.isActive = true @@ -145,9 +146,9 @@ extension TagSettingsAlertConfigCell { addSubview(statusContainerView) statusContainerView.anchor(top: noticeView.bottomAnchor, - leading: self.safeLeftAnchor, + leading: safeLeftAnchor, bottom: nil, - trailing: self.safeRightAnchor, + trailing: safeRightAnchor, padding: .init(top: 0, left: 18, bottom: 0, @@ -173,43 +174,43 @@ extension TagSettingsAlertConfigCell { statusSeparator.backgroundColor = RuuviColor.ruuviLineColor addSubview(statusSeparator) statusSeparator.anchor(top: statusContainerView.bottomAnchor, - leading: self.safeLeftAnchor, + leading: safeLeftAnchor, bottom: nil, - trailing: self.safeRightAnchor, + trailing: safeRightAnchor, padding: .init(top: 0, left: 16, bottom: 0, right: 16), size: .init(width: 0, height: 1)) addSubview(setCustomDescriptionView) setCustomDescriptionView.anchor(top: statusSeparator.bottomAnchor, - leading: self.safeLeftAnchor, + leading: safeLeftAnchor, bottom: nil, - trailing: self.safeRightAnchor, + trailing: safeRightAnchor, size: .init(width: 0, height: 44)) let customDescriptionSeparator = UIView() customDescriptionSeparator.backgroundColor = RuuviColor.ruuviLineColor addSubview(customDescriptionSeparator) customDescriptionSeparator.anchor(top: setCustomDescriptionView.bottomAnchor, - leading: self.safeLeftAnchor, + leading: safeLeftAnchor, bottom: nil, - trailing: self.safeRightAnchor, + trailing: safeRightAnchor, padding: .init(top: 0, left: 16, bottom: 0, right: 16), size: .init(width: 0, height: 1)) addSubview(alertLimitDescriptionView) alertLimitDescriptionView.anchor(top: customDescriptionSeparator.bottomAnchor, - leading: self.safeLeftAnchor, + leading: safeLeftAnchor, bottom: nil, - trailing: self.safeRightAnchor) + trailing: safeRightAnchor) alertLimitDescriptionViewHiddenHeight = alertLimitDescriptionView .heightAnchor .constraint(equalToConstant: 0) addSubview(alertLimitSliderView) alertLimitSliderView.anchor(top: alertLimitDescriptionView.bottomAnchor, - leading: self.safeLeftAnchor, + leading: safeLeftAnchor, bottom: nil, - trailing: self.safeRightAnchor, + trailing: safeRightAnchor, padding: .init(top: 0, left: 0, bottom: 0, right: 4), size: .init(width: 0, height: 40)) alertLimitSliderViewHiddenHeight = alertLimitSliderView @@ -218,9 +219,9 @@ extension TagSettingsAlertConfigCell { addSubview(additionalTextView) additionalTextView.anchor(top: alertLimitSliderView.bottomAnchor, - leading: self.safeLeftAnchor, - bottom: self.safeBottomAnchor, - trailing: self.safeRightAnchor, + leading: safeLeftAnchor, + bottom: safeBottomAnchor, + trailing: safeRightAnchor, size: .init(width: 0, height: 44)) additionalTextViewHiddenHeight = additionalTextView .heightAnchor @@ -237,6 +238,7 @@ extension TagSettingsAlertConfigCell { } // MARK: - Private action + extension TagSettingsAlertConfigCell { @objc private func handleStatusToggle(_ sender: RuuviUISwitch) { delegate?.didChangeAlertState(sender: self, didToggle: sender.isOn) @@ -244,9 +246,10 @@ extension TagSettingsAlertConfigCell { } // MARK: - Pubic Setters + extension TagSettingsAlertConfigCell { func setStatus(with value: Bool?) { - if let value = value { + if let value { statusLabel.text = value ? RuuviLocalization.on : RuuviLocalization.off statusSwitch.setOn(value, animated: false) } @@ -267,20 +270,21 @@ extension TagSettingsAlertConfigCell { func setAlertRange(minValue: CGFloat? = nil, selectedMinValue: CGFloat? = nil, maxValue: CGFloat? = nil, - selectedMaxValue: CGFloat? = nil) { - if let minValue = minValue { + selectedMaxValue: CGFloat? = nil) + { + if let minValue { alertLimitSliderView.minValue = minValue } - if let maxValue = maxValue { + if let maxValue { alertLimitSliderView.maxValue = maxValue } - if let selectedMinValue = selectedMinValue { + if let selectedMinValue { alertLimitSliderView.selectedMinValue = selectedMinValue } - if let selectedMaxValue = selectedMaxValue { + if let selectedMaxValue { alertLimitSliderView.selectedMaxValue = selectedMaxValue } alertLimitSliderView.refresh() @@ -345,7 +349,8 @@ extension TagSettingsAlertConfigCell { } func disableEditing(disable: Bool, - identifier: TagSettingsSectionIdentifier) { + identifier: TagSettingsSectionIdentifier) + { statusSwitch.disable(disable) statusLabel.disable(disable) setCustomDescriptionView.disable(disable) @@ -364,6 +369,7 @@ extension TagSettingsAlertConfigCell { } // MARK: - RUAlertDetailsCellChildViewDelegate + extension TagSettingsAlertConfigCell: RUAlertDetailsCellChildViewDelegate { func didTapView(sender: RUAlertDetailsCellChildView) { if sender == setCustomDescriptionView { @@ -375,14 +381,15 @@ extension TagSettingsAlertConfigCell: RUAlertDetailsCellChildViewDelegate { } // MARK: - RangeSeekSliderDelegate + extension TagSettingsAlertConfigCell: RangeSeekSliderDelegate { - func rangeSeekSlider(_ slider: RangeSeekSlider, didChange minValue: CGFloat, maxValue: CGFloat) { + func rangeSeekSlider(_: RangeSeekSlider, didChange minValue: CGFloat, maxValue: CGFloat) { delegate?.didChangeAlertRange(sender: self, didSlideTo: minValue, maxValue: maxValue) } - func didEndTouches(in slider: RangeSeekSlider) { + func didEndTouches(in _: RangeSeekSlider) { delegate?.didSetAlertRange(sender: self, minValue: alertLimitSliderView.selectedMinValue, maxValue: alertLimitSliderView.selectedMaxValue) diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift index 883bfe40f..51f98a0b7 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift @@ -1,5 +1,5 @@ -import UIKit import RuuviLocalization +import UIKit // swiftlint:disable:next type_name protocol TagSettingsBackgroundSelectionViewDelegate: NSObjectProtocol { @@ -7,7 +7,6 @@ protocol TagSettingsBackgroundSelectionViewDelegate: NSObjectProtocol { } class TagSettingsBackgroundSelectionView: UIView { - weak var delegate: TagSettingsBackgroundSelectionViewDelegate? private lazy var backgroundView = CardsBackgroundView() @@ -39,12 +38,12 @@ class TagSettingsBackgroundSelectionView: UIView { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setUpUI() { - addSubview(backgroundView) backgroundView.fillSuperview() @@ -66,16 +65,16 @@ class TagSettingsBackgroundSelectionView: UIView { addSubview(iconAndLabelContainer) iconAndLabelContainer.anchor(top: nil, - leading: safeLeftAnchor, - bottom: nil, - trailing: safeRightAnchor, - padding: .init(top: 0, left: 8, bottom: 0, right: 8)) + leading: safeLeftAnchor, + bottom: nil, + trailing: safeRightAnchor, + padding: .init(top: 0, left: 8, bottom: 0, right: 8)) iconAndLabelContainer.centerYInSuperview() addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleViewTap(_:)))) } - @objc private func handleViewTap(_ gestureRecognizer: UITapGestureRecognizer) { + @objc private func handleViewTap(_: UITapGestureRecognizer) { delegate?.didTapChangeBackground() } } diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift index 9b192b063..43d32fc32 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift @@ -9,7 +9,6 @@ enum TagSettingsBasicAccessory { /// Leading title label and trailing aligned value label /// with an optional disclosure icon. class TagSettingsBasicCell: UITableViewCell { - lazy var titleLabel: UILabel = { let label = UILabel() label.textColor = RuuviColor.ruuviTextColor @@ -39,13 +38,15 @@ class TagSettingsBasicCell: UITableViewCell { private lazy var separator = UIView(color: RuuviColor.ruuviLineColor) override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) { + reuseIdentifier: String?) + { super.init(style: style, reuseIdentifier: reuseIdentifier) setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -53,7 +54,7 @@ class TagSettingsBasicCell: UITableViewCell { backgroundColor = .clear let stack = UIStackView(arrangedSubviews: [ - titleLabel, valueLabel + titleLabel, valueLabel, ]) stack.spacing = 4 stack.distribution = .fill @@ -75,15 +76,15 @@ class TagSettingsBasicCell: UITableViewCell { iconView.centerYInSuperview() iconHiddenWidthConstraints = [ iconView.widthAnchor.constraint(equalToConstant: 0), - stack.trailingAnchor.constraint(equalTo: safeRightAnchor, constant: -12) + stack.trailingAnchor.constraint(equalTo: safeRightAnchor, constant: -12), ] addSubview(separator) separator.anchor(top: nil, - leading: safeLeftAnchor, - bottom: bottomAnchor, - trailing: safeRightAnchor, - size: .init(width: 0, height: 1)) + leading: safeLeftAnchor, + bottom: bottomAnchor, + trailing: safeRightAnchor, + size: .init(width: 0, height: 1)) } func configure(title: String?, value: String?) { @@ -104,20 +105,20 @@ class TagSettingsBasicCell: UITableViewCell { case .pencil: iconView.image = RuuviAssets.editPenImage iconView.tintColor = RuuviColor.ruuviTintColor - iconHiddenWidthConstraints.forEach({ anchor in + iconHiddenWidthConstraints.forEach { anchor in anchor.isActive = false - }) + } case .chevron: iconView.image = UIImage(systemName: "chevron.right") iconView.tintColor = .secondaryLabel - iconHiddenWidthConstraints.forEach({ anchor in + iconHiddenWidthConstraints.forEach { anchor in anchor.isActive = false - }) + } case .none: iconView.image = nil - iconHiddenWidthConstraints.forEach({ anchor in + iconHiddenWidthConstraints.forEach { anchor in anchor.isActive = true - }) + } } } diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift index b5dec9ba9..b87458739 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift @@ -1,6 +1,6 @@ -import UIKit -import RuuviOntology import RuuviLocalization +import RuuviOntology +import UIKit // swiftlint:disable:next type_name protocol TagSettingsExpandableSectionHeaderDelegate: NSObjectProtocol { @@ -10,7 +10,6 @@ protocol TagSettingsExpandableSectionHeaderDelegate: NSObjectProtocol { } class TagSettingsExpandableSectionHeader: UIView { - weak var delegate: TagSettingsExpandableSectionHeaderDelegate? private var section: Int = 0 @@ -73,7 +72,8 @@ class TagSettingsExpandableSectionHeader: UIView { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -104,14 +104,14 @@ class TagSettingsExpandableSectionHeader: UIView { addSubview(arrowView) arrowView.anchor(top: nil, - leading: mutedTillLabel.trailingAnchor, - bottom: nil, - trailing: safeRightAnchor, - padding: .init(top: 0, - left: 8, - bottom: 0, - right: 12), - size: .init(width: 14, height: 14)) + leading: mutedTillLabel.trailingAnchor, + bottom: nil, + trailing: safeRightAnchor, + padding: .init(top: 0, + left: 8, + bottom: 0, + right: 12), + size: .init(width: 14, height: 14)) arrowView.centerYInSuperview() addSubview(seprator) @@ -122,7 +122,7 @@ class TagSettingsExpandableSectionHeader: UIView { size: .init(width: 0, height: 1)) let noValueStack = UIStackView(arrangedSubviews: [ - noValueLabel, iconView + noValueLabel, iconView, ]) iconView.size(width: 16, height: 16) noValueStack.axis = .horizontal @@ -156,7 +156,7 @@ class TagSettingsExpandableSectionHeader: UIView { delegate?.toggleSection(self, section: cell.section) } - @objc private func tapNoValuesView(_ gestureRecognizer: UITapGestureRecognizer) { + @objc private func tapNoValuesView(_: UITapGestureRecognizer) { delegate?.didTapSectionMoreInfo(headerView: self) } } @@ -170,7 +170,8 @@ extension TagSettingsExpandableSectionHeader { section: Int, collapsed: Bool, backgroundColor: UIColor? = nil, - font: UIFont?) { + font: UIFont?) + { titleLabel.text = string self.section = section setCollapsed(collapsed) @@ -179,7 +180,7 @@ extension TagSettingsExpandableSectionHeader { } else { self.backgroundColor = RuuviColor.tagSettingsItemHeaderColor } - if let font = font { + if let font { titleLabel.font = font } else { titleLabel.font = UIFont.Muli(.bold, size: 16) @@ -213,13 +214,14 @@ extension TagSettingsExpandableSectionHeader { func setAlertState(with date: Date?, isOn: Bool, - alertState: AlertState?) { + alertState: AlertState?) + { // Show alert icon only when alert is on alertIcon.alpha = isOn ? 1 : 0 // Show muted label if muted till is not nil // If muted till is not nil, we don't have to execute the rest of the code - if let date = date, date > Date() { + if let date, date > Date() { mutedTillLabel.isHidden = !isOn mutedTillLabel.text = AppDateFormatter .shared @@ -247,15 +249,15 @@ extension TagSettingsExpandableSectionHeader { alertIcon.alpha = 1.0 alertIcon.tintColor = RuuviColor.ruuviOrangeColor alertIcon.image = RuuviAssets.alertActiveImage - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { UIView.animate(withDuration: 0.5, delay: 0, options: [.repeat, .autoreverse], animations: { [weak self] in - self?.alertIcon.alpha = 0.0 - }) - }) + self?.alertIcon.alpha = 0.0 + }) + } default: alertIcon.image = nil removeAlertAnimations() @@ -263,10 +265,9 @@ extension TagSettingsExpandableSectionHeader { } func removeAlertAnimations() { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, - execute: { [weak self] in + DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in self?.alertIcon.layer.removeAllAnimations() self?.alertIcon.alpha = 1 - }) + } } } diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsFooterCell.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsFooterCell.swift index 22eff44fb..ed57db689 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsFooterCell.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsFooterCell.swift @@ -1,7 +1,6 @@ import UIKit class TagSettingsFooterCell: UITableViewCell { - private lazy var noteLabel: UILabel = { let label = UILabel() label.textAlignment = .left @@ -12,13 +11,15 @@ class TagSettingsFooterCell: UITableViewCell { }() override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) { + reuseIdentifier: String?) + { super.init(style: style, reuseIdentifier: reuseIdentifier) setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift index 94381c9c7..2518fe9b1 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift @@ -4,7 +4,6 @@ import UIKit /// with an optional label in middle for any additional value. /// This cell is used for more info section. class TagSettingsPlainCell: UITableViewCell { - private lazy var titleLabel: UILabel = { let label = UILabel() label.textColor = RuuviColor.ruuviTextColor @@ -32,13 +31,15 @@ class TagSettingsPlainCell: UITableViewCell { }() override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) { + reuseIdentifier: String?) + { super.init(style: style, reuseIdentifier: reuseIdentifier) setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -46,7 +47,7 @@ class TagSettingsPlainCell: UITableViewCell { backgroundColor = .clear let stack = UIStackView(arrangedSubviews: [ - titleLabel, noteLabel, valueLabel + titleLabel, noteLabel, valueLabel, ]) stack.spacing = 8 stack.distribution = .fill @@ -62,7 +63,8 @@ class TagSettingsPlainCell: UITableViewCell { func configure(title: String?, value: String?, note: String? = nil, - noteColor: UIColor? = nil) { + noteColor: UIColor? = nil) + { titleLabel.text = title valueLabel.text = value noteLabel.text = note @@ -71,14 +73,16 @@ class TagSettingsPlainCell: UITableViewCell { func configure(value: String?, note: String? = nil, - noteColor: UIColor? = nil) { + noteColor: UIColor? = nil) + { valueLabel.text = value noteLabel.text = note noteLabel.textColor = noteColor } func configure(note: String? = nil, - noteColor: UIColor? = nil) { + noteColor: UIColor? = nil) + { noteLabel.text = note noteLabel.textColor = noteColor } diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift index 3ecb39a0c..ee5cf0a4f 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift @@ -1,11 +1,8 @@ import UIKit -protocol TagSettingsSimpleSectionHeaderDelegate: NSObjectProtocol { - -} +protocol TagSettingsSimpleSectionHeaderDelegate: NSObjectProtocol {} class TagSettingsSimpleSectionHeader: UIView { - weak var delegate: TagSettingsSimpleSectionHeaderDelegate? private var section: Int = 0 @@ -23,7 +20,8 @@ class TagSettingsSimpleSectionHeader: UIView { setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -36,7 +34,8 @@ class TagSettingsSimpleSectionHeader: UIView { func setTitle(with string: String?, section: Int, - backgroundColor: UIColor? = nil) { + backgroundColor: UIColor? = nil) + { titleLabel.text = string self.section = section if let color = backgroundColor { diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift index e6efa63d6..4cd2896dd 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift @@ -5,7 +5,6 @@ protocol TagSettingsSwitchCellDelegate: NSObjectProtocol { } class TagSettingsSwitchCell: UITableViewCell { - weak var delegate: TagSettingsSwitchCellDelegate? private lazy var titleLabel: UILabel = { @@ -33,13 +32,15 @@ class TagSettingsSwitchCell: UITableViewCell { lazy var seprator = UIView(color: RuuviColor.ruuviLineColor) override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) { + reuseIdentifier: String?) + { super.init(style: style, reuseIdentifier: reuseIdentifier) setUpUI() } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -92,13 +93,12 @@ class TagSettingsSwitchCell: UITableViewCell { // MARK: - SETTERS extension TagSettingsSwitchCell { - func configure(title: String?) { titleLabel.text = title } func configureSwitch(value: Bool?) { - if let value = value { + if let value { statusSwitch.setOn(value, animated: false) } else { statusSwitch.setOn(false, animated: false) diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift index 284f4bb2a..b15df35e7 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift @@ -1,8 +1,8 @@ -// swiftlint:disable file_length -import UIKit import RuuviLocalization import RuuviOntology import RuuviService +// swiftlint:disable file_length +import UIKit enum TagSettingsSectionHeaderType { case simple @@ -37,13 +37,14 @@ enum TagSettingsItemCellIdentifier: Int { } class TagSettingsSection { - internal init(identifier: TagSettingsSectionIdentifier, - title: String, - cells: [TagSettingsItem], - collapsed: Bool, - headerType: TagSettingsSectionHeaderType, - backgroundColor: UIColor? = nil, - font: UIFont? = nil) { + init(identifier: TagSettingsSectionIdentifier, + title: String, + cells: [TagSettingsItem], + collapsed: Bool, + headerType: TagSettingsSectionHeaderType, + backgroundColor: UIColor? = nil, + font: UIFont? = nil) + { self.identifier = identifier self.title = title self.cells = cells @@ -64,14 +65,13 @@ class TagSettingsSection { struct TagSettingsItem { // swiftlint:disable:next redundant_optional_initialization - var identifier: TagSettingsItemCellIdentifier? = nil + var identifier: TagSettingsItemCellIdentifier? var createdCell: () -> UITableViewCell var action: ((TagSettingsItem) -> Swift.Void)? } // swiftlint:disable:next type_body_length class TagSettingsViewController: UIViewController { - var output: TagSettingsViewOutput! var measurementService: RuuviServiceMeasurement! var viewModel: TagSettingsViewModel? { @@ -83,7 +83,7 @@ class TagSettingsViewController: UIViewController { } private lazy var backButton: UIButton = { - let button = UIButton() + let button = UIButton() button.tintColor = .label let buttonImage = RuuviAssets.backButtonImage button.setImage(buttonImage, for: .normal) @@ -95,7 +95,7 @@ class TagSettingsViewController: UIViewController { }() private lazy var exportButton: UIButton = { - let button = UIButton() + let button = UIButton() button.tintColor = .label let buttonImage = UIImage(systemName: "square.and.arrow.up") button.setImage(buttonImage, for: .normal) @@ -131,7 +131,7 @@ class TagSettingsViewController: UIViewController { private let pairedString = RuuviLocalization.TagSettings.PairAndBackgroundScan.Paired.title private let pairingString = RuuviLocalization.TagSettings.PairAndBackgroundScan.Pairing.title - private let unpairedString = RuuviLocalization.TagSettings.PairAndBackgroundScan.Unpaired.title + private let unpairedString = RuuviLocalization.TagSettings.PairAndBackgroundScan.Unpaired.title private let temperatureAlertFormat = RuuviLocalization.TagSettings.TemperatureAlertTitleLabel.text private let airHumidityAlertFormat = RuuviLocalization.TagSettings.AirHumidityAlert.title @@ -143,34 +143,26 @@ class TagSettingsViewController: UIViewController { // Weak reference to the cells // General section - private lazy var tagNameCell: TagSettingsBasicCell? = { - return TagSettingsBasicCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() - private lazy var tagOwnerCell: TagSettingsBasicCell? = { - return TagSettingsBasicCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() - private lazy var tagOwnersPlanCell: TagSettingsBasicCell? = { - return TagSettingsBasicCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() - private lazy var tagShareCell: TagSettingsBasicCell? = { - return TagSettingsBasicCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() + private lazy var tagNameCell: TagSettingsBasicCell? = TagSettingsBasicCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) + + private lazy var tagOwnerCell: TagSettingsBasicCell? = TagSettingsBasicCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) + + private lazy var tagOwnersPlanCell: TagSettingsBasicCell? = TagSettingsBasicCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) + + private lazy var tagShareCell: TagSettingsBasicCell? = TagSettingsBasicCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) + // Bluetooth section - private lazy var btPairCell: TagSettingsSwitchCell? = { - return TagSettingsSwitchCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() + private lazy var btPairCell: TagSettingsSwitchCell? = TagSettingsSwitchCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) // Alerts // Temperature private lazy var temperatureAlertSectionHeaderView: - TagSettingsExpandableSectionHeader? = { - return TagSettingsExpandableSectionHeader() - }() + TagSettingsExpandableSectionHeader? = TagSettingsExpandableSectionHeader() private lazy var temperatureAlertSection: TagSettingsSection? = { let sectionTitle = temperatureAlertFormat( @@ -180,23 +172,21 @@ class TagSettingsViewController: UIViewController { identifier: .alertTemperature, title: sectionTitle, cells: [ - termperatureAlertItem() + termperatureAlertItem(), ], collapsed: true, headerType: .expandable ) return section }() - private lazy var temperatureAlertCell: TagSettingsAlertConfigCell? = { - return TagSettingsAlertConfigCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() + + private lazy var temperatureAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) // Humidity private lazy var humidityAlertSectionHeaderView: - TagSettingsExpandableSectionHeader? = { - return TagSettingsExpandableSectionHeader() - }() + TagSettingsExpandableSectionHeader? = TagSettingsExpandableSectionHeader() + private lazy var humidityAlertSection: TagSettingsSection? = { let symbol = HumidityUnit.percent.symbol let sectionTitle = airHumidityAlertFormat(symbol) @@ -204,22 +194,20 @@ class TagSettingsViewController: UIViewController { identifier: .alertHumidity, title: sectionTitle, cells: [ - humidityAlertItem() + humidityAlertItem(), ], collapsed: true, headerType: .expandable ) return section }() - private lazy var humidityAlertCell: TagSettingsAlertConfigCell? = { - return TagSettingsAlertConfigCell(style: .value1, reuseIdentifier: Self.ReuseIdentifier) - }() + + private lazy var humidityAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell(style: .value1, reuseIdentifier: Self.ReuseIdentifier) // Pressure private lazy var pressureAlertSectionHeaderView: - TagSettingsExpandableSectionHeader? = { - return TagSettingsExpandableSectionHeader() - }() + TagSettingsExpandableSectionHeader? = TagSettingsExpandableSectionHeader() + private lazy var pressureAlertSection: TagSettingsSection? = { let sectionTitle = pressureAlertFormat( viewModel?.pressureUnit.value?.symbol ?? RuuviLocalization.na @@ -228,123 +216,92 @@ class TagSettingsViewController: UIViewController { identifier: .alertPressure, title: sectionTitle, cells: [ - pressureAlertItem() + pressureAlertItem(), ], collapsed: true, headerType: .expandable ) return section }() - private lazy var pressureAlertCell: TagSettingsAlertConfigCell? = { - return TagSettingsAlertConfigCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() + + private lazy var pressureAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) // RSSI private lazy var rssiAlertSectionHeaderView: - TagSettingsExpandableSectionHeader? = { - return TagSettingsExpandableSectionHeader() - }() - private lazy var rssiAlertCell: TagSettingsAlertConfigCell? = { - return TagSettingsAlertConfigCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() + TagSettingsExpandableSectionHeader? = TagSettingsExpandableSectionHeader() + + private lazy var rssiAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) // Movement private lazy var movementAlertSectionHeaderView: - TagSettingsExpandableSectionHeader? = { - return TagSettingsExpandableSectionHeader() - }() - private lazy var movementAlertCell: TagSettingsAlertConfigCell? = { - return TagSettingsAlertConfigCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() + TagSettingsExpandableSectionHeader? = TagSettingsExpandableSectionHeader() + + private lazy var movementAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) // Connection private lazy var connectionAlertSectionHeaderView: - TagSettingsExpandableSectionHeader? = { - return TagSettingsExpandableSectionHeader() - }() - private lazy var connectionAlertCell: TagSettingsAlertConfigCell? = { - return TagSettingsAlertConfigCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() + TagSettingsExpandableSectionHeader? = TagSettingsExpandableSectionHeader() + + private lazy var connectionAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) // Cloud Connection private lazy var cloudConnectionAlertSectionHeaderView: - TagSettingsExpandableSectionHeader? = { - return TagSettingsExpandableSectionHeader() - }() - private lazy var cloudConnectionAlertCell: TagSettingsAlertConfigCell? = { - return TagSettingsAlertConfigCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() + TagSettingsExpandableSectionHeader? = TagSettingsExpandableSectionHeader() + + private lazy var cloudConnectionAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) // Offset correction - private lazy var tempOffsetCorrectionCell: TagSettingsBasicCell? = { - return TagSettingsBasicCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() - private lazy var humidityOffsetCorrectionCell: TagSettingsBasicCell? = { - return TagSettingsBasicCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() - private lazy var pressureOffsetCorrectionCell: TagSettingsBasicCell? = { - return TagSettingsBasicCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() + private lazy var tempOffsetCorrectionCell: TagSettingsBasicCell? = TagSettingsBasicCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) + + private lazy var humidityOffsetCorrectionCell: TagSettingsBasicCell? = TagSettingsBasicCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) + + private lazy var pressureOffsetCorrectionCell: TagSettingsBasicCell? = TagSettingsBasicCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) // More Info section private lazy var moreInfoSectionHeaderView: - TagSettingsExpandableSectionHeader? = { - return TagSettingsExpandableSectionHeader() - }() - private lazy var moreInfoMacAddressCell: TagSettingsPlainCell? = { - return TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() - private lazy var moreInfoDataFormatCell: TagSettingsPlainCell? = { - return TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() - private lazy var moreInfoDataSourceCell: TagSettingsPlainCell? = { - return TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() - private lazy var moreInfoBatteryVoltageCell: TagSettingsPlainCell? = { - return TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() - private lazy var moreInfoAccXCell: TagSettingsPlainCell? = { - return TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() - private lazy var moreInfoAccYCell: TagSettingsPlainCell? = { - return TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() - private lazy var moreInfoAccZCell: TagSettingsPlainCell? = { - return TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() - private lazy var moreInfoTxPowerCell: TagSettingsPlainCell? = { - return TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() - private lazy var moreInfoRSSICell: TagSettingsPlainCell? = { - return TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() - private lazy var moreInfoMSNCell: TagSettingsPlainCell? = { - return TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() + TagSettingsExpandableSectionHeader? = TagSettingsExpandableSectionHeader() + + private lazy var moreInfoMacAddressCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) + + private lazy var moreInfoDataFormatCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) + + private lazy var moreInfoDataSourceCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) + + private lazy var moreInfoBatteryVoltageCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) + + private lazy var moreInfoAccXCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) + + private lazy var moreInfoAccYCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) + + private lazy var moreInfoAccZCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) + + private lazy var moreInfoTxPowerCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) + + private lazy var moreInfoRSSICell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) + + private lazy var moreInfoMSNCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) // Firmware section - private lazy var firmwareVersionCell: TagSettingsBasicCell? = { - return TagSettingsBasicCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - }() + private lazy var firmwareVersionCell: TagSettingsBasicCell? = TagSettingsBasicCell(style: .value1, + reuseIdentifier: Self.ReuseIdentifier) deinit { tagNameCell = nil @@ -398,6 +355,7 @@ class TagSettingsViewController: UIViewController { } // MARK: - BINDINGS + extension TagSettingsViewController { private func bindViewModel() { bindBackgroundView() @@ -411,6 +369,7 @@ extension TagSettingsViewController { } // MARK: - CONFIGURATION + extension TagSettingsViewController { private func configureSections() { tableViewSections = [] @@ -418,7 +377,7 @@ extension TagSettingsViewController { // Fixed item on top - general and bluetooth. tableViewSections += [ configureGeneralSection(), - configureBluetoothSection() + configureBluetoothSection(), ] // Variable items @@ -435,7 +394,7 @@ extension TagSettingsViewController { tableViewSections += [ configureMoreInfoSection(), configureFirmwareSection(), - configureRemoveSection() + configureRemoveSection(), ] } @@ -562,14 +521,14 @@ extension TagSettingsViewController { let sectionIndex = indexOfSection(section: section) var oldIndexPaths: [IndexPath] = [] - for rowIndex in 0.. Int { - return tableViewSections.firstIndex(where: { + tableViewSections.firstIndex(where: { $0.identifier == section }) ?? tableViewSections.count } } // MARK: - HEADER VIEW + extension TagSettingsViewController { private func bindBackgroundView() { - guard let viewModel = viewModel else { + guard let viewModel else { return } @@ -608,32 +568,33 @@ extension TagSettingsViewController { } // MARK: - GENERAL SECTION + extension TagSettingsViewController { private func bindGeneralSection() { - guard let viewModel = viewModel else { + guard let viewModel else { return } - if let tagNameCell = tagNameCell { + if let tagNameCell { tagNameCell.bind(viewModel.name) { cell, name in cell.configure(value: name) } } - if let tagOwnerCell = tagOwnerCell { + if let tagOwnerCell { tagOwnerCell.bind(viewModel.owner) { cell, owner in cell.configure(value: owner) cell.setAccessory(type: .chevron) } } - if let tagOwnersPlanCell = tagOwnersPlanCell { + if let tagOwnersPlanCell { tagOwnersPlanCell.bind(viewModel.ownersPlan) { cell, ownersPlan in cell.configure(value: ownersPlan) } } - if let tagShareCell = tagShareCell { + if let tagShareCell { tagShareCell.bind(viewModel.sharedTo) { [weak self] cell, sharedTo in cell.configure(value: self?.sensorSharedTo(from: sharedTo)) } @@ -654,13 +615,14 @@ extension TagSettingsViewController { private func itemsForGeneralSection(showPlan: Bool = false) -> [TagSettingsItem] { var availableItems: [TagSettingsItem] = [ - tagNameSettingItem() + tagNameSettingItem(), ] if showOwner() { availableItems.append(tagOwnerSettingItem()) if let isOwner = viewModel?.isOwner.value, !isOwner, let isCloudTag = viewModel?.isNetworkConnected.value, - isCloudTag, showPlan { + isCloudTag, showPlan + { availableItems.append(tagOwnersPlanSettingItem()) } } @@ -687,7 +649,7 @@ extension TagSettingsViewController { identifier: .generalName, createdCell: { [weak self] in self?.tagNameCell?.configure(title: RuuviLocalization.TagSettings.TagNameTitleLabel.text, - value: self?.viewModel?.name.value) + value: self?.viewModel?.name.value) self?.tagNameCell?.setAccessory(type: .pencil) return self?.tagNameCell ?? UITableViewCell() }, @@ -703,7 +665,7 @@ extension TagSettingsViewController { identifier: .generalOwner, createdCell: { [weak self] in self?.tagOwnerCell?.configure(title: RuuviLocalization.TagSettings.NetworkInfo.owner, - value: self?.viewModel?.owner.value) + value: self?.viewModel?.owner.value) self?.tagOwnerCell?.setAccessory(type: .chevron) self?.tagOwnerCell?.hideSeparator(hide: false) return self?.tagOwnerCell ?? UITableViewCell() @@ -742,7 +704,7 @@ extension TagSettingsViewController { from: self?.viewModel?.sharedTo.value ) ) - self?.tagShareCell?.setAccessory(type: .chevron ) + self?.tagShareCell?.setAccessory(type: .chevron) self?.tagShareCell?.hideSeparator(hide: true) return self?.tagShareCell ?? UITableViewCell() }, @@ -754,15 +716,15 @@ extension TagSettingsViewController { } private func showOwner() -> Bool { - return viewModel?.isAuthorized.value == true + viewModel?.isAuthorized.value == true } private func isOwner() -> Bool { - return viewModel?.isOwner.value == true + viewModel?.isOwner.value == true } private func showShare() -> Bool { - return viewModel?.canShareTag.value == true + viewModel?.canShareTag.value == true } private func sensorSharedTo(from: [String]?) -> String { @@ -776,13 +738,14 @@ extension TagSettingsViewController { } // MARK: - BLUETOOTH SECTION + extension TagSettingsViewController: TagSettingsSwitchCellDelegate { private func bindBluetoothSection() { - guard let viewModel = viewModel else { + guard let viewModel else { return } - if let btPairCell = btPairCell { + if let btPairCell { btPairCell.bind(viewModel.isConnected) { [weak self] cell, isConnected in cell.configureSwitch(value: isConnected.bound) cell.disableSwitch(disable: false) @@ -796,7 +759,7 @@ extension TagSettingsViewController: TagSettingsSwitchCellDelegate { let keepConnection = viewModel.keepConnection btPairCell.bind(viewModel.isConnected) { [weak self, - weak keepConnection] (cell, isConnected) in + weak keepConnection] cell, isConnected in let keep = keepConnection?.value ?? false if isConnected.bound { // Connected state @@ -817,7 +780,7 @@ extension TagSettingsViewController: TagSettingsSwitchCellDelegate { let isConnected = viewModel.isConnected btPairCell.bind(viewModel.keepConnection) { [weak self, - weak isConnected] (cell, keepConnection) in + weak isConnected] cell, keepConnection in let isConnected = isConnected?.value ?? false if isConnected { // Connected state @@ -838,13 +801,12 @@ extension TagSettingsViewController: TagSettingsSwitchCellDelegate { } private func configureBluetoothSection() -> TagSettingsSection { - let section = TagSettingsSection( identifier: .btPair, title: RuuviLocalization.TagSettings.SectionHeader.BTConnection.title.capitalized, cells: [ tagPairSettingItem(), - tagPairFooterItem() + tagPairFooterItem(), ], collapsed: false, headerType: .simple @@ -891,19 +853,20 @@ extension TagSettingsViewController: TagSettingsSwitchCellDelegate { } // MARK: - TAG_SETTINGS_SWITCH_CELL_DELEGATE + func didToggleSwitch(isOn: Bool, sender: TagSettingsSwitchCell) { - if let btPairCell = btPairCell, sender == btPairCell { + if let btPairCell, sender == btPairCell { output.viewDidTriggerKeepConnection(isOn: isOn) } } } // MARK: - ALERTS SECTION -extension TagSettingsViewController { +extension TagSettingsViewController { // swiftlint:disable:next function_body_length cyclomatic_complexity private func bindAlertsSection() { - guard let viewModel = viewModel else { + guard let viewModel else { return } @@ -915,7 +878,7 @@ extension TagSettingsViewController { ) } - if let temperatureAlertCell = temperatureAlertCell { + if let temperatureAlertCell { temperatureAlertCell.bind(viewModel.isTemperatureAlertOn) { cell, value in cell.setStatus(with: value) } @@ -950,53 +913,54 @@ extension TagSettingsViewController { selectedMaxValue: sSelf.temperatureUpperBound()) } - temperatureAlertCell.bind(viewModel.latestMeasurement) { (cell, measurement) in + temperatureAlertCell.bind(viewModel.latestMeasurement) { cell, measurement in cell.disableEditing(disable: measurement == nil, identifier: .alertTemperature) } } - if let temperatureAlertSectionHeaderView = temperatureAlertSectionHeaderView { + if let temperatureAlertSectionHeaderView { temperatureAlertSectionHeaderView.bind(viewModel.temperatureUnit) { [weak self] header, unit in - guard let sSelf = self else { return } - let sectionTitle = sSelf.temperatureAlertFormat( - unit?.symbol ?? RuuviLocalization.na - ) - header.setTitle(with: sectionTitle) + guard let sSelf = self else { return } + let sectionTitle = sSelf.temperatureAlertFormat( + unit?.symbol ?? RuuviLocalization.na + ) + header.setTitle(with: sectionTitle) } temperatureAlertSectionHeaderView.bind( - viewModel.temperatureAlertMutedTill) { header, mutedTill in - let isOn = self.alertsAvailable() && + viewModel.temperatureAlertMutedTill) + { header, mutedTill in + let isOn = self.alertsAvailable() && GlobalHelpers.getBool(from: viewModel.isTemperatureAlertOn.value) - let alertState = viewModel.temperatureAlertState.value - header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) + let alertState = viewModel.temperatureAlertState.value + header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) } temperatureAlertSectionHeaderView .bind(viewModel.isTemperatureAlertOn) { [weak self] header, isOn in - guard let self = self else { return } - let isOn = self.alertsAvailable() && - GlobalHelpers.getBool(from: isOn) + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: isOn) let mutedTill = viewModel.temperatureAlertMutedTill.value let alertState = viewModel.temperatureAlertState.value header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) - } + } temperatureAlertSectionHeaderView .bind(viewModel.temperatureAlertState) { [weak self] header, state in - guard let self = self else { return } - let isOn = self.alertsAvailable() && - GlobalHelpers.getBool(from: viewModel.isTemperatureAlertOn.value) + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: viewModel.isTemperatureAlertOn.value) let mutedTill = viewModel.temperatureAlertMutedTill.value header.setAlertState(with: mutedTill, isOn: isOn, alertState: state) - } + } } // Humidity - if let humidityAlertCell = humidityAlertCell { + if let humidityAlertCell { humidityAlertCell.bind(viewModel.isRelativeHumidityAlertOn) { cell, value in cell.setStatus(with: value) } @@ -1032,7 +996,7 @@ extension TagSettingsViewController { } humidityAlertCell.bind(viewModel.latestMeasurement) { - [weak self] (cell, measurement) in + [weak self] cell, measurement in guard let sSelf = self else { return } cell.disableEditing( disable: measurement == nil || !sSelf.showHumidityOffsetCorrection(), @@ -1041,34 +1005,35 @@ extension TagSettingsViewController { } } - if let humidityAlertSectionHeaderView = humidityAlertSectionHeaderView { + if let humidityAlertSectionHeaderView { humidityAlertSectionHeaderView.bind( - viewModel.relativeHumidityAlertMutedTill) { [weak self] header, mutedTill in - guard let self = self else { return } - let isOn = self.alertsAvailable() && + viewModel.relativeHumidityAlertMutedTill) + { [weak self] header, mutedTill in + guard let self else { return } + let isOn = alertsAvailable() && GlobalHelpers.getBool(from: viewModel.isRelativeHumidityAlertOn.value) - let alertState = viewModel.relativeHumidityAlertState.value - header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) + let alertState = viewModel.relativeHumidityAlertState.value + header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) } humidityAlertSectionHeaderView .bind(viewModel.isRelativeHumidityAlertOn) { [weak self] header, isOn in - guard let self = self else { return } - let isOn = self.alertsAvailable() && - GlobalHelpers.getBool(from: isOn) + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: isOn) let alertState = viewModel.relativeHumidityAlertState.value let mutedTill = viewModel.relativeHumidityAlertMutedTill.value header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) - } + } humidityAlertSectionHeaderView .bind(viewModel.relativeHumidityAlertState) { [weak self] header, state in - guard let self = self else { return } - let isOn = self.alertsAvailable() && - GlobalHelpers.getBool(from: viewModel.isRelativeHumidityAlertOn.value) + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: viewModel.isRelativeHumidityAlertOn.value) let mutedTill = viewModel.relativeHumidityAlertMutedTill.value header.setAlertState(with: mutedTill, isOn: isOn, alertState: state) - } + } } // Pressure @@ -1079,7 +1044,7 @@ extension TagSettingsViewController { ) } - if let pressureAlertCell = pressureAlertCell { + if let pressureAlertCell { pressureAlertCell.bind(viewModel.isPressureAlertOn) { cell, value in cell.setStatus(with: value) } @@ -1115,7 +1080,7 @@ extension TagSettingsViewController { } pressureAlertCell.bind(viewModel.latestMeasurement) { - [weak self] (cell, measurement) in + [weak self] cell, measurement in guard let sSelf = self else { return } cell.disableEditing( disable: measurement == nil || !sSelf.showPressureOffsetCorrection(), @@ -1124,9 +1089,9 @@ extension TagSettingsViewController { } } - if let pressureAlertSectionHeaderView = pressureAlertSectionHeaderView { + if let pressureAlertSectionHeaderView { pressureAlertSectionHeaderView.bind(viewModel.pressureUnit) { - [weak self ] header, unit in + [weak self] header, unit in guard let sSelf = self else { return } let sectionTitle = sSelf.pressureAlertFormat( unit?.symbol ?? RuuviLocalization.na @@ -1135,35 +1100,36 @@ extension TagSettingsViewController { } pressureAlertSectionHeaderView.bind( - viewModel.pressureAlertMutedTill) { header, mutedTill in - let isOn = self.alertsAvailable() && + viewModel.pressureAlertMutedTill) + { header, mutedTill in + let isOn = self.alertsAvailable() && GlobalHelpers.getBool(from: viewModel.isPressureAlertOn.value) - let alertState = viewModel.pressureAlertState.value - header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) + let alertState = viewModel.pressureAlertState.value + header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) } pressureAlertSectionHeaderView .bind(viewModel.isPressureAlertOn) { [weak self] header, isOn in - guard let self = self else { return } - let isOn = self.alertsAvailable() && - GlobalHelpers.getBool(from: isOn) + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: isOn) let alertState = viewModel.pressureAlertState.value let mutedTill = viewModel.pressureAlertMutedTill.value header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) - } + } pressureAlertSectionHeaderView .bind(viewModel.pressureAlertState) { [weak self] header, state in - guard let self = self else { return } - let isOn = self.alertsAvailable() && - GlobalHelpers.getBool(from: viewModel.isPressureAlertOn.value) + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: viewModel.isPressureAlertOn.value) let mutedTill = viewModel.pressureAlertMutedTill.value header.setAlertState(with: mutedTill, isOn: isOn, alertState: state) - } + } } // RSSI - if let rssiAlertCell = rssiAlertCell { + if let rssiAlertCell { rssiAlertCell.bind(viewModel.isSignalAlertOn) { cell, value in cell.setStatus(with: value) } @@ -1188,7 +1154,7 @@ extension TagSettingsViewController { selectedMaxValue: self?.rssiUpperBound()) } - rssiAlertCell.bind(viewModel.latestMeasurement) { (cell, measurement) in + rssiAlertCell.bind(viewModel.latestMeasurement) { cell, measurement in cell.disableEditing( disable: measurement == nil, identifier: .alertRSSI @@ -1196,38 +1162,39 @@ extension TagSettingsViewController { } } - if let rssiAlertSectionHeaderView = rssiAlertSectionHeaderView { + if let rssiAlertSectionHeaderView { rssiAlertSectionHeaderView.bind( - viewModel.signalAlertMutedTill) { [weak self] header, mutedTill in - guard let self = self else { return } - let isOn = self.alertsAvailable() && + viewModel.signalAlertMutedTill) + { [weak self] header, mutedTill in + guard let self else { return } + let isOn = alertsAvailable() && GlobalHelpers.getBool(from: viewModel.isSignalAlertOn.value) - let alertState = viewModel.signalAlertState.value - header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) + let alertState = viewModel.signalAlertState.value + header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) } rssiAlertSectionHeaderView .bind(viewModel.isSignalAlertOn) { [weak self] header, isOn in - guard let self = self else { return } - let isOn = self.alertsAvailable() && - GlobalHelpers.getBool(from: isOn) + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: isOn) let alertState = viewModel.signalAlertState.value let mutedTill = viewModel.signalAlertMutedTill.value header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) - } + } rssiAlertSectionHeaderView .bind(viewModel.signalAlertState) { [weak self] header, state in - guard let self = self else { return } - let isOn = self.alertsAvailable() && - GlobalHelpers.getBool(from: viewModel.isSignalAlertOn.value) + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: viewModel.isSignalAlertOn.value) let mutedTill = viewModel.signalAlertMutedTill.value header.setAlertState(with: mutedTill, isOn: isOn, alertState: state) - } + } } // Movement - if let movementAlertCell = movementAlertCell { + if let movementAlertCell { movementAlertCell.bind(viewModel.isMovementAlertOn) { cell, value in cell.setStatus(with: value) } @@ -1238,7 +1205,7 @@ extension TagSettingsViewController { } movementAlertCell.bind(viewModel.latestMeasurement) { - [weak self] (cell, measurement) in + [weak self] cell, measurement in guard let sSelf = self else { return } cell.disableEditing( disable: measurement == nil || sSelf.viewModel?.movementCounter.value == nil, @@ -1247,38 +1214,39 @@ extension TagSettingsViewController { } } - if let movementAlertSectionHeaderView = movementAlertSectionHeaderView { + if let movementAlertSectionHeaderView { movementAlertSectionHeaderView.bind( - viewModel.movementAlertMutedTill) { [weak self] header, mutedTill in - guard let self = self else { return } - let isOn = self.alertsAvailable() && + viewModel.movementAlertMutedTill) + { [weak self] header, mutedTill in + guard let self else { return } + let isOn = alertsAvailable() && GlobalHelpers.getBool(from: viewModel.isMovementAlertOn.value) - let alertState = viewModel.movementAlertState.value - header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) + let alertState = viewModel.movementAlertState.value + header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) } movementAlertSectionHeaderView .bind(viewModel.isMovementAlertOn) { [weak self] header, isOn in - guard let self = self else { return } - let isOn = self.alertsAvailable() && - GlobalHelpers.getBool(from: isOn) + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: isOn) let alertState = viewModel.movementAlertState.value let mutedTill = viewModel.movementAlertMutedTill.value header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) - } + } movementAlertSectionHeaderView .bind(viewModel.movementAlertState) { [weak self] header, state in - guard let self = self else { return } - let isOn = self.alertsAvailable() && - GlobalHelpers.getBool(from: viewModel.isMovementAlertOn.value) + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: viewModel.isMovementAlertOn.value) let mutedTill = viewModel.movementAlertMutedTill.value header.setAlertState(with: mutedTill, isOn: isOn, alertState: state) - } + } } // Connection - if let connectionAlertCell = connectionAlertCell { + if let connectionAlertCell { connectionAlertCell.bind(viewModel.isConnectionAlertOn) { cell, value in cell.setStatus(with: value) } @@ -1288,7 +1256,7 @@ extension TagSettingsViewController { cell.setCustomDescription(with: self?.alertCustomDescription(from: value)) } - connectionAlertCell.bind(viewModel.latestMeasurement) { (cell, measurement) in + connectionAlertCell.bind(viewModel.latestMeasurement) { cell, measurement in cell.disableEditing( disable: measurement == nil, identifier: .alertConnection @@ -1296,34 +1264,35 @@ extension TagSettingsViewController { } } - if let connectionAlertSectionHeaderView = connectionAlertSectionHeaderView { + if let connectionAlertSectionHeaderView { connectionAlertSectionHeaderView.bind( - viewModel.connectionAlertMutedTill) { [weak self] header, mutedTill in - guard let self = self else { return } - let isOn = self.alertsAvailable() && + viewModel.connectionAlertMutedTill) + { [weak self] header, mutedTill in + guard let self else { return } + let isOn = alertsAvailable() && GlobalHelpers.getBool(from: viewModel.isConnectionAlertOn.value) - let alertState = viewModel.connectionAlertState.value - header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) + let alertState = viewModel.connectionAlertState.value + header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) } connectionAlertSectionHeaderView .bind(viewModel.isConnectionAlertOn) { [weak self] header, isOn in - guard let self = self else { return } - let isOn = self.alertsAvailable() && - GlobalHelpers.getBool(from: isOn) + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: isOn) let alertState = viewModel.connectionAlertState.value let mutedTill = viewModel.connectionAlertMutedTill.value header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) - } + } connectionAlertSectionHeaderView .bind(viewModel.connectionAlertState) { [weak self] header, state in - guard let self = self else { return } - let isOn = self.alertsAvailable() && - GlobalHelpers.getBool(from: viewModel.isConnectionAlertOn.value) + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: viewModel.isConnectionAlertOn.value) let mutedTill = viewModel.connectionAlertMutedTill.value header.setAlertState(with: mutedTill, isOn: isOn, alertState: state) - } + } } // Cloud Connection @@ -1332,7 +1301,7 @@ extension TagSettingsViewController { self?.reloadSection(identifier: .alertCloudConnection) } - if let cloudConnectionAlertCell = cloudConnectionAlertCell { + if let cloudConnectionAlertCell { cloudConnectionAlertCell.bind(viewModel.isCloudConnectionAlertOn) { cell, value in cell.setStatus(with: value) } @@ -1344,7 +1313,7 @@ extension TagSettingsViewController { } cell.setAlertLimitDescription( - description: self?.cloudConnectionAlertRangeDescription(from: durationInt/60) + description: self?.cloudConnectionAlertRangeDescription(from: durationInt / 60) ) } @@ -1354,34 +1323,35 @@ extension TagSettingsViewController { } } - if let cloudConnectionAlertSectionHeaderView = cloudConnectionAlertSectionHeaderView { + if let cloudConnectionAlertSectionHeaderView { cloudConnectionAlertSectionHeaderView.bind( - viewModel.cloudConnectionAlertMutedTill) { [weak self] header, mutedTill in - guard let self = self else { return } - let isOn = self.alertsAvailable() && + viewModel.cloudConnectionAlertMutedTill) + { [weak self] header, mutedTill in + guard let self else { return } + let isOn = alertsAvailable() && GlobalHelpers.getBool(from: viewModel.isCloudConnectionAlertOn.value) - let alertState = viewModel.cloudConnectionAlertState.value - header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) + let alertState = viewModel.cloudConnectionAlertState.value + header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) } cloudConnectionAlertSectionHeaderView .bind(viewModel.isCloudConnectionAlertOn) { [weak self] header, isOn in - guard let self = self else { return } - let isOn = self.alertsAvailable() && - GlobalHelpers.getBool(from: isOn) + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: isOn) let alertState = viewModel.cloudConnectionAlertState.value let mutedTill = viewModel.cloudConnectionAlertMutedTill.value header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) - } + } cloudConnectionAlertSectionHeaderView .bind(viewModel.cloudConnectionAlertState) { [weak self] header, state in - guard let self = self else { return } - let isOn = self.alertsAvailable() && - GlobalHelpers.getBool(from: viewModel.isCloudConnectionAlertOn.value) + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: viewModel.isCloudConnectionAlertOn.value) let mutedTill = viewModel.cloudConnectionAlertMutedTill.value header.setAlertState(with: mutedTill, isOn: isOn, alertState: state) - } + } } } @@ -1396,19 +1366,19 @@ extension TagSettingsViewController { configurePressureAlertSection(), configureRSSIAlertSection(), configureMovementAlertSection(), - configureConnectionAlertSection() + configureConnectionAlertSection(), ] if cloudConnectionAlertVisible() { sections += [ - configureCloudConnectionAlertSection() + configureCloudConnectionAlertSection(), ] } return sections } - private func configureAlertHeaderSection() -> TagSettingsSection { + private func configureAlertHeaderSection() -> TagSettingsSection { let section = TagSettingsSection( identifier: .alertHeader, title: RuuviLocalization.TagSettings.Label.Alerts.text.capitalized, @@ -1420,8 +1390,9 @@ extension TagSettingsViewController { } // MARK: - TEMPERATURE ALERTS + private func configureTemperatureAlertSection() -> TagSettingsSection { - return temperatureAlertSection! + temperatureAlertSection! } private func termperatureAlertItem() -> TagSettingsItem { @@ -1437,9 +1408,9 @@ extension TagSettingsViewController { self?.temperatureAlertCell? .setAlertLimitDescription(description: self?.temperatureAlertRangeDescription()) self?.temperatureAlertCell?.setAlertRange(minValue: minRange, - selectedMinValue: self?.temperatureLowerBound(), - maxValue: maxRange, - selectedMaxValue: self?.temperatureUpperBound()) + selectedMinValue: self?.temperatureLowerBound(), + maxValue: maxRange, + selectedMaxValue: self?.temperatureUpperBound()) self?.temperatureAlertCell?.disableEditing( disable: disableTemperature, identifier: .alertTemperature @@ -1453,8 +1424,9 @@ extension TagSettingsViewController { } // MARK: - HUMIDITY ALERTS + private func configureHumidityAlertSection() -> TagSettingsSection { - return humidityAlertSection! + humidityAlertSection! } private func humidityAlertItem() -> TagSettingsItem { @@ -1489,8 +1461,9 @@ extension TagSettingsViewController { } // MARK: - PRESSURE ALERTS + private func configurePressureAlertSection() -> TagSettingsSection { - return pressureAlertSection! + pressureAlertSection! } private func pressureAlertItem() -> TagSettingsItem { @@ -1523,12 +1496,13 @@ extension TagSettingsViewController { } // MARK: - RSSI ALERTS + private func configureRSSIAlertSection() -> TagSettingsSection { let section = TagSettingsSection( identifier: .alertRSSI, title: RuuviLocalization.signalStrengthDbm, cells: [ - rssiAlertItem() + rssiAlertItem(), ], collapsed: true, headerType: .expandable @@ -1554,9 +1528,9 @@ extension TagSettingsViewController { self?.rssiAlertCell? .setAlertLimitDescription(description: self?.rssiAlertRangeDescription()) self?.rssiAlertCell?.setAlertRange(minValue: minRange, - selectedMinValue: self?.rssiLowerBound(), - maxValue: maxRange, - selectedMaxValue: self?.rssiUpperBound()) + selectedMinValue: self?.rssiLowerBound(), + maxValue: maxRange, + selectedMaxValue: self?.rssiUpperBound()) self?.rssiAlertCell?.disableEditing( disable: disableRssi, identifier: .alertRSSI @@ -1570,12 +1544,13 @@ extension TagSettingsViewController { } // MARK: - MOVEMENT ALERTS + private func configureMovementAlertSection() -> TagSettingsSection { let section = TagSettingsSection( identifier: .alertMovement, title: RuuviLocalization.TagSettings.MovementAlert.title, cells: [ - movementAlertItem() + movementAlertItem(), ], collapsed: true, headerType: .expandable @@ -1585,7 +1560,7 @@ extension TagSettingsViewController { private func movementAlertItem() -> TagSettingsItem { let disableMovement = viewModel?.movementCounter.value == nil || - !hasMeasurement() + !hasMeasurement() let settingItem = TagSettingsItem( createdCell: { [weak self] in self?.movementAlertCell? @@ -1606,12 +1581,13 @@ extension TagSettingsViewController { } // MARK: - CONNECTION ALERTS + private func configureConnectionAlertSection() -> TagSettingsSection { let section = TagSettingsSection( identifier: .alertConnection, title: RuuviLocalization.TagSettings.ConnectionAlert.title, cells: [ - connectionAlertItem() + connectionAlertItem(), ], collapsed: true, headerType: .expandable @@ -1641,12 +1617,13 @@ extension TagSettingsViewController { } // MARK: - CLOUD CONNECTION ALERTS + private func configureCloudConnectionAlertSection() -> TagSettingsSection { let section = TagSettingsSection( identifier: .alertCloudConnection, title: RuuviLocalization.alertCloudConnectionTitle, cells: [ - cloudConnectionAlertItem() + cloudConnectionAlertItem(), ], collapsed: true, headerType: .expandable @@ -1669,7 +1646,7 @@ extension TagSettingsViewController { self?.cloudConnectionAlertCell? .setAlertLimitDescription( description: self?.cloudConnectionAlertRangeDescription( - from: duration/60 + from: duration / 60 ) ) self?.cloudConnectionAlertCell?.delegate = self @@ -1681,9 +1658,10 @@ extension TagSettingsViewController { } // MARK: - Alerts helpers + private func alertsAvailable() -> Bool { - return (viewModel?.isCloudAlertsAvailable.value ?? false || - viewModel?.isConnected.value ?? false) + (viewModel?.isCloudAlertsAvailable.value ?? false || + viewModel?.isConnected.value ?? false) } private func reloadAlertSectionHeaders() { @@ -1785,10 +1763,11 @@ extension TagSettingsViewController { } private func temperatureAlertRangeDescription(from min: CGFloat? = nil, - max: CGFloat? = nil) -> NSMutableAttributedString? { + max: CGFloat? = nil) -> NSMutableAttributedString? + { guard isViewLoaded else { return nil } - var format = RuuviLocalization.TagSettings.Alerts.Temperature.description - if let min = min, let max = max { + var format = RuuviLocalization.TagSettings.Alerts.Temperature.description + if let min, let max { return attributedString(from: String(format: format, locale: Locale.autoupdatingCurrent, min, max)) @@ -1796,7 +1775,8 @@ extension TagSettingsViewController { if let tu = viewModel?.temperatureUnit.value?.unitTemperature, let l = viewModel?.temperatureLowerBound.value?.converted(to: tu), - let u = viewModel?.temperatureUpperBound.value?.converted(to: tu) { + let u = viewModel?.temperatureUpperBound.value?.converted(to: tu) + { if l.value.decimalPoint > 0 { let decimalPointToConsider = l.value.decimalPoint > 2 ? 2 : l.value.decimalPoint format = format.replacingFirstOccurrence(of: "%0.f", @@ -1810,10 +1790,9 @@ extension TagSettingsViewController { } let message = String(format: format, - locale: Locale.autoupdatingCurrent, - l.value.round(to: 2), - u.value.round(to: 2) - ) + locale: Locale.autoupdatingCurrent, + l.value.round(to: 2), + u.value.round(to: 2)) return attributedString(from: message) } else { @@ -1855,16 +1834,18 @@ extension TagSettingsViewController { // Humidity private func humidityAlertRangeDescription(from min: CGFloat? = nil, - max: CGFloat? = nil) -> NSMutableAttributedString? { + max: CGFloat? = nil) -> NSMutableAttributedString? + { guard isViewLoaded else { return nil } - var format = RuuviLocalization.TagSettings.Alerts.Temperature.description - if let min = min, let max = max { + var format = RuuviLocalization.TagSettings.Alerts.Temperature.description + if let min, let max { return attributedString(from: String(format: format, locale: Locale.autoupdatingCurrent, min, max)) } if let l = viewModel?.relativeHumidityLowerBound.value, - let u = viewModel?.relativeHumidityUpperBound.value { + let u = viewModel?.relativeHumidityUpperBound.value + { if l.decimalPoint > 0 { let decimalPointToConsider = l.decimalPoint > 2 ? 2 : l.decimalPoint format = format.replacingFirstOccurrence(of: "%0.f", with: "%0.\(decimalPointToConsider)f") @@ -1911,11 +1892,12 @@ extension TagSettingsViewController { // Pressure private func pressureAlertRangeDescription(from minValue: CGFloat? = nil, - maxValue: CGFloat? = nil) -> NSMutableAttributedString? { + maxValue: CGFloat? = nil) -> NSMutableAttributedString? + { guard isViewLoaded else { return nil } - var format = RuuviLocalization.TagSettings.Alerts.Temperature.description + var format = RuuviLocalization.TagSettings.Alerts.Temperature.description - if let minValue = minValue, let maxValue = maxValue { + if let minValue, let maxValue { return attributedString(from: String(format: format, locale: Locale.autoupdatingCurrent, minValue, maxValue)) @@ -1923,7 +1905,8 @@ extension TagSettingsViewController { if let pu = viewModel?.pressureUnit.value, let lower = viewModel?.pressureLowerBound.value?.converted(to: pu).value, - let upper = viewModel?.pressureUpperBound.value?.converted(to: pu).value { + let upper = viewModel?.pressureUpperBound.value?.converted(to: pu).value + { let l = min( max(lower, pu.alertRange.lowerBound), pu.alertRange.upperBound @@ -1992,18 +1975,20 @@ extension TagSettingsViewController { // RSSI private func rssiAlertRangeDescription(from min: CGFloat? = nil, - max: CGFloat? = nil) -> NSMutableAttributedString? { + max: CGFloat? = nil) -> NSMutableAttributedString? + { guard isViewLoaded else { return nil } - let format = RuuviLocalization.TagSettings.Alerts.Temperature.description + let format = RuuviLocalization.TagSettings.Alerts.Temperature.description - if let min = min, let max = max { + if let min, let max { return attributedString(from: String(format: format, locale: Locale.autoupdatingCurrent, min, max)) } if let lower = viewModel?.signalLowerBound.value, - let upper = viewModel?.signalUpperBound.value { + let upper = viewModel?.signalUpperBound.value + { let message = String(format: format, locale: Locale.autoupdatingCurrent, lower, upper) @@ -2034,13 +2019,14 @@ extension TagSettingsViewController { } private func rssiMinMaxForSliders() -> (minimum: CGFloat, - maximum: CGFloat) { - return (minimum: CGFloat(-105), - maximum: CGFloat(0)) + maximum: CGFloat) + { + (minimum: CGFloat(-105), + maximum: CGFloat(0)) } private func attributedString(from message: String?) -> NSMutableAttributedString? { - if let message = message { + if let message { let attributedString = NSMutableAttributedString(string: message) let boldFont = UIFont.Muli(.bold, size: 14) let numberRegex = try? NSRegularExpression(pattern: "\\d+([.,]\\d+)?") @@ -2058,14 +2044,14 @@ extension TagSettingsViewController { // Cloud Connection private func cloudConnectionAlertVisible() -> Bool { - return viewModel?.isOwnersPlanProPlus.value ?? false + viewModel?.isOwnersPlanProPlus.value ?? false } private func cloudConnectionAlertRangeDescription( from delay: Int? = nil ) -> NSMutableAttributedString? { guard isViewLoaded else { return nil } - if let delay = delay { + if let delay { return attributedString(from: RuuviLocalization.alertCloudConnectionDescription(delay)) } else { return nil @@ -2073,18 +2059,16 @@ extension TagSettingsViewController { } private func cloudConnectionMinUnseenDuration() -> Int { - return 2 // mins + 2 // mins } private func cloudConnectionDefaultUnseenDuration() -> Int { - return 15 // mins + 15 // mins } } extension TagSettingsViewController: TagSettingsAlertConfigCellDelegate { - func didSelectSetCustomDescription(sender: TagSettingsAlertConfigCell) { - var description: String? switch sender { case temperatureAlertCell: @@ -2107,7 +2091,8 @@ extension TagSettingsViewController: TagSettingsAlertConfigCellDelegate { showSensorCustomAlertDescriptionDialog( description: description, - sender: sender) + sender: sender + ) } func didSelectAlertLimitDescription(sender: TagSettingsAlertConfigCell) { @@ -2179,7 +2164,8 @@ extension TagSettingsViewController: TagSettingsAlertConfigCellDelegate { // swiftlint:disable:next cyclomatic_complexity function_body_length func didSetAlertRange(sender: TagSettingsAlertConfigCell, minValue: CGFloat, - maxValue: CGFloat) { + maxValue: CGFloat) + { guard minValue < maxValue else { return } switch sender { case temperatureAlertCell: @@ -2249,7 +2235,8 @@ extension TagSettingsViewController: TagSettingsAlertConfigCellDelegate { func didChangeAlertRange(sender: TagSettingsAlertConfigCell, didSlideTo minValue: CGFloat, - maxValue: CGFloat) { + maxValue: CGFloat) + { switch sender { case temperatureAlertCell: temperatureAlertCell?.setAlertLimitDescription( @@ -2262,7 +2249,7 @@ extension TagSettingsViewController: TagSettingsAlertConfigCellDelegate { case pressureAlertCell: pressureAlertCell?.setAlertLimitDescription( description: pressureAlertRangeDescription(from: minValue, - maxValue: maxValue)) + maxValue: maxValue)) case rssiAlertCell: rssiAlertCell?.setAlertLimitDescription( description: rssiAlertRangeDescription(from: minValue, @@ -2274,6 +2261,7 @@ extension TagSettingsViewController: TagSettingsAlertConfigCellDelegate { } // MARK: - SET CUSTOM ALERT RANGE POPUP + extension TagSettingsViewController { private func showTemperatureAlertSetPopup(sender: TagSettingsAlertConfigCell) { let temperatureUnit = viewModel?.temperatureUnit.value ?? .celsius @@ -2348,7 +2336,7 @@ extension TagSettingsViewController { message: message, minimum: minimumDuration, default: defaultDuration, - current: currentDuration/60, + current: currentDuration / 60, sender: sender ) } @@ -2362,12 +2350,13 @@ extension TagSettingsViewController { private func temperatureValue() -> (minimum: Double?, maximum: Double?) { if let unit = viewModel?.temperatureUnit.value?.unitTemperature, let l = viewModel?.temperatureLowerBound.value?.converted(to: unit), - let u = viewModel?.temperatureUpperBound.value?.converted(to: unit) { - return (minimum: l.value, - maximum: u.value) + let u = viewModel?.temperatureUpperBound.value?.converted(to: unit) + { + (minimum: l.value, + maximum: u.value) } else { - return (minimum: nil, - maximum: nil) + (minimum: nil, + maximum: nil) } } @@ -2378,10 +2367,11 @@ extension TagSettingsViewController { private func humidityValue() -> (minimum: Double?, maximum: Double?) { if let l = viewModel?.relativeHumidityLowerBound.value, - let u = viewModel?.relativeHumidityUpperBound.value { - return (minimum: l, maximum: u) + let u = viewModel?.relativeHumidityUpperBound.value + { + (minimum: l, maximum: u) } else { - return (minimum: nil, maximum: nil) + (minimum: nil, maximum: nil) } } @@ -2395,7 +2385,8 @@ extension TagSettingsViewController { let (minimumRange, maximumRange) = pressureAlertRange() if let pressureUnit = viewModel?.pressureUnit.value, let lower = viewModel?.pressureLowerBound.value?.converted(to: pressureUnit).value, - let upper = viewModel?.pressureUpperBound.value?.converted(to: pressureUnit).value { + let upper = viewModel?.pressureUpperBound.value?.converted(to: pressureUnit).value + { let l = min( max(lower, minimumRange), maximumRange @@ -2412,100 +2403,103 @@ extension TagSettingsViewController { // TODO: - Move the values to a separate constant file private func rssiAlertRange() -> (minimum: Double, maximum: Double) { - return (minimum: -105, - maximum: 0) + (minimum: -105, + maximum: 0) } private func rssiValue() -> (minimum: Double?, maximum: Double?) { if let lower = viewModel?.signalLowerBound.value, - let upper = viewModel?.signalUpperBound.value { - return (minimum: lower, maximum: upper) + let upper = viewModel?.signalUpperBound.value + { + (minimum: lower, maximum: upper) } else { - return (minimum: nil, maximum: nil) + (minimum: nil, maximum: nil) } } } // MARK: - OFFSET CORRECTION SECTION -extension TagSettingsViewController { +extension TagSettingsViewController { // swiftlint:disable:next function_body_length private func bindOffsetCorrectionSection() { - guard let viewModel = viewModel else { + guard let viewModel else { return } - tableView.bind(viewModel.isNetworkConnected) { [weak self] (_, _) in + tableView.bind(viewModel.isNetworkConnected) { [weak self] _, _ in self?.reloadSection(identifier: .offsetCorrection) } - tableView.bind(viewModel.isOwner) { [weak self] (_, _) in + tableView.bind(viewModel.isOwner) { [weak self] _, _ in self?.reloadSection(identifier: .offsetCorrection) } - if let tempOffsetCorrectionCell = tempOffsetCorrectionCell { + if let tempOffsetCorrectionCell { tempOffsetCorrectionCell.bind(viewModel - .temperatureOffsetCorrection) { [weak self] cell, value in + .temperatureOffsetCorrection) + { [weak self] cell, value in cell.configure(value: self? .measurementService .temperatureOffsetCorrectionString(for: value ?? 0)) } - tempOffsetCorrectionCell.bind(viewModel.latestMeasurement) { (cell, measurement) in + tempOffsetCorrectionCell.bind(viewModel.latestMeasurement) { cell, measurement in cell.disableEditing(measurement == nil) } } - if let humidityOffsetCorrectionCell = humidityOffsetCorrectionCell { + if let humidityOffsetCorrectionCell { humidityOffsetCorrectionCell .bind(viewModel.humidityOffsetCorrection) { [weak self] cell, value in - cell.configure(value: self? - .measurementService - .humidityOffsetCorrectionString(for: value ?? 0)) - } + cell.configure(value: self? + .measurementService + .humidityOffsetCorrectionString(for: value ?? 0)) + } humidityOffsetCorrectionCell.bind(viewModel.latestMeasurement) { - [weak self] (cell, measurement) in + [weak self] cell, measurement in guard let sSelf = self else { return } cell.disableEditing(measurement == nil || - !sSelf.showHumidityOffsetCorrection()) + !sSelf.showHumidityOffsetCorrection()) } humidityOffsetCorrectionCell.bind(viewModel - .humidityOffsetCorrectionVisible) { cell, visible in - cell.disableEditing(!GlobalHelpers.getBool(from: visible)) + .humidityOffsetCorrectionVisible) + { cell, visible in + cell.disableEditing(!GlobalHelpers.getBool(from: visible)) } - } - if let pressureOffsetCorrectionCell = pressureOffsetCorrectionCell { + if let pressureOffsetCorrectionCell { pressureOffsetCorrectionCell.bind(viewModel - .pressureOffsetCorrection) { [weak self] cell, value in + .pressureOffsetCorrection) + { [weak self] cell, value in cell.configure(value: self? .measurementService .pressureOffsetCorrectionString(for: value ?? 0)) } pressureOffsetCorrectionCell.bind(viewModel - .pressureOffsetCorrectionVisible) { cell, visible in - cell.disableEditing(!GlobalHelpers.getBool(from: visible)) + .pressureOffsetCorrectionVisible) + { cell, visible in + cell.disableEditing(!GlobalHelpers.getBool(from: visible)) } pressureOffsetCorrectionCell.bind(viewModel.latestMeasurement) { - [weak self] (cell, measurement) in + [weak self] cell, measurement in guard let sSelf = self else { return } cell.disableEditing(measurement == nil || - !sSelf.showPressureOffsetCorrection()) + !sSelf.showPressureOffsetCorrection()) } } } private func configureOffsetCorrectionSection() -> TagSettingsSection { - let offsetCorrectionItems: [TagSettingsItem] = [ offsetCorrectionTemperatureItem(), offsetCorrectionHumidityItem(), - offsetCorrectionPressureItem() + offsetCorrectionPressureItem(), ] let section = TagSettingsSection( @@ -2527,8 +2521,8 @@ extension TagSettingsViewController { identifier: .offsetTemperature, createdCell: { [weak self] in self?.tempOffsetCorrectionCell?.configure(title: RuuviLocalization.TagSettings.OffsetCorrection.temperature, - value: self?.measurementService - .temperatureOffsetCorrectionString(for: tempOffset)) + value: self?.measurementService + .temperatureOffsetCorrectionString(for: tempOffset)) self?.tempOffsetCorrectionCell?.setAccessory(type: .chevron) self?.tempOffsetCorrectionCell?.disableEditing(!hasMeasurement) return self?.tempOffsetCorrectionCell ?? UITableViewCell() @@ -2551,7 +2545,7 @@ extension TagSettingsViewController { .humidityOffsetCorrectionCell? .configure(title: RuuviLocalization.TagSettings.OffsetCorrection.humidity, value: self?.measurementService - .humidityOffsetCorrectionString(for: humOffset)) + .humidityOffsetCorrectionString(for: humOffset)) self?.humidityOffsetCorrectionCell?.setAccessory(type: .chevron) self?.humidityOffsetCorrectionCell?.disableEditing(disableHumidity) return self?.humidityOffsetCorrectionCell ?? UITableViewCell() @@ -2604,71 +2598,71 @@ extension TagSettingsViewController { } private func showHumidityOffsetCorrection() -> Bool { - return viewModel?.humidityOffsetCorrectionVisible.value == true + viewModel?.humidityOffsetCorrectionVisible.value == true } private func showPressureOffsetCorrection() -> Bool { - return viewModel?.pressureOffsetCorrectionVisible.value == true + viewModel?.pressureOffsetCorrectionVisible.value == true } private func showOnlyTemperatureOffsetCorrection() -> Bool { - return !showHumidityOffsetCorrection() && !showPressureOffsetCorrection() + !showHumidityOffsetCorrection() && !showPressureOffsetCorrection() } /// Returns True if viewModel has measurement private func hasMeasurement() -> Bool { - return GlobalHelpers.getBool(from: viewModel?.latestMeasurement.value != nil) + GlobalHelpers.getBool(from: viewModel?.latestMeasurement.value != nil) } } // MARK: - MORE INFO SECTION -extension TagSettingsViewController { +extension TagSettingsViewController { // swiftlint:disable:next cyclomatic_complexity function_body_length private func bindMoreInfoSection() { - guard let viewModel = viewModel else { + guard let viewModel else { return } let emptyString = RuuviLocalization.na // Mac address - if let moreInfoMacAddressCell = moreInfoMacAddressCell { + if let moreInfoMacAddressCell { moreInfoMacAddressCell.bind(viewModel.mac) { cell, mac in cell.configure(value: mac ?? emptyString) } } // Data format - if let moreInfoDataFormatCell = moreInfoDataFormatCell { - moreInfoDataFormatCell.bind(viewModel.version) { (cell, version) in + if let moreInfoDataFormatCell { + moreInfoDataFormatCell.bind(viewModel.version) { cell, version in cell.configure(value: version.stringValue) } } // Data source - if let moreInfoDataSourceCell = moreInfoDataSourceCell { + if let moreInfoDataSourceCell { moreInfoDataSourceCell.bind(viewModel.source) { [weak self] cell, source in cell.configure(value: self?.formattedDataSource(from: source)) } } // Voltage cell - if let moreInfoBatteryVoltageCell = moreInfoBatteryVoltageCell { + if let moreInfoBatteryVoltageCell { moreInfoBatteryVoltageCell.bind(viewModel.voltage) { [weak self] cell, voltage in cell.configure(value: self?.formattedBatteryVoltage(from: voltage)) } moreInfoBatteryVoltageCell.bind(viewModel.batteryNeedsReplacement) { [weak self] cell, needsReplacement in - guard let sSelf = self else { return } - let (status, color) = sSelf.formattedBatteryStatus(from: needsReplacement) - cell.configure(note: status, noteColor: color) + guard let sSelf = self else { return } + let (status, color) = sSelf.formattedBatteryStatus(from: needsReplacement) + cell.configure(note: status, noteColor: color) } } // Acceleration X - if let moreInfoAccXCell = moreInfoAccXCell { + if let moreInfoAccXCell { moreInfoAccXCell.bind(viewModel.accelerationX) { [weak self] cell, accelerationX in cell.configure(value: self? @@ -2677,7 +2671,7 @@ extension TagSettingsViewController { } // Acceleration Y - if let moreInfoAccYCell = moreInfoAccYCell { + if let moreInfoAccYCell { moreInfoAccYCell.bind(viewModel.accelerationY) { [weak self] cell, accelerationY in cell.configure(value: self? @@ -2686,7 +2680,7 @@ extension TagSettingsViewController { } // Acceleration Z - if let moreInfoAccZCell = moreInfoAccZCell { + if let moreInfoAccZCell { moreInfoAccZCell.bind(viewModel.accelerationZ) { [weak self] cell, accelerationZ in cell.configure(value: self? @@ -2695,32 +2689,32 @@ extension TagSettingsViewController { } // TX power - if let moreInfoTxPowerCell = moreInfoTxPowerCell { + if let moreInfoTxPowerCell { moreInfoTxPowerCell.bind(viewModel.txPower) { - [weak self] (cell, txPower) in + [weak self] cell, txPower in cell.configure(value: self?.formattedTXPower(from: txPower)) } } // RSSI - if let moreInfoRSSICell = moreInfoRSSICell { + if let moreInfoRSSICell { moreInfoRSSICell.bind(viewModel.rssi) { cell, rssi in cell.configure(value: rssi?.stringValue) } } // MSN - if let moreInfoMSNCell = moreInfoMSNCell { - moreInfoMSNCell.bind(viewModel.measurementSequenceNumber) { (cell, msn) in + if let moreInfoMSNCell { + moreInfoMSNCell.bind(viewModel.measurementSequenceNumber) { cell, msn in cell.configure(value: msn.stringValue) } } // Header - if let moreInfoSectionHeaderView = moreInfoSectionHeaderView { + if let moreInfoSectionHeaderView { moreInfoSectionHeaderView.bind(viewModel.version) { header, value in - guard let value = value else { return } + guard let value else { return } header.showNoValueView( show: GlobalHelpers.getBool(from: value < 5)) } @@ -2728,7 +2722,6 @@ extension TagSettingsViewController { } private func configureMoreInfoSection() -> TagSettingsSection { - let section = TagSettingsSection( identifier: .moreInfo, title: RuuviLocalization.TagSettings.Label.MoreInfo.text.capitalized, @@ -2742,7 +2735,7 @@ extension TagSettingsViewController { moreInfoAccZItem(), moreInfoTxPowerItem(), moreInfoRSSIItem(), - moreInfoMeasurementSequenceItem() + moreInfoMeasurementSequenceItem(), ], collapsed: true, headerType: .expandable, @@ -2756,7 +2749,7 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( createdCell: { [weak self] in self?.moreInfoMacAddressCell?.configure(title: RuuviLocalization.TagSettings.MacAddressTitleLabel.text, - value: self?.viewModel?.mac.value ?? RuuviLocalization.na) + value: self?.viewModel?.mac.value ?? RuuviLocalization.na) return self?.moreInfoMacAddressCell ?? UITableViewCell() }, action: { [weak self] _ in @@ -2770,7 +2763,7 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( createdCell: { [weak self] in self?.moreInfoDataFormatCell?.configure(title: RuuviLocalization.TagSettings.DataFormatTitleLabel.text, - value: self?.viewModel?.version.value?.stringValue) + value: self?.viewModel?.version.value?.stringValue) self?.moreInfoDataFormatCell?.selectionStyle = .none return self?.moreInfoDataFormatCell ?? UITableViewCell() }, @@ -2783,7 +2776,7 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( createdCell: { [weak self] in self?.moreInfoDataSourceCell?.configure(title: RuuviLocalization.TagSettings.DataSourceTitleLabel.text, - value: self?.formattedDataSource(from: self?.viewModel?.source.value)) + value: self?.formattedDataSource(from: self?.viewModel?.source.value)) self?.moreInfoDataSourceCell?.selectionStyle = .none return self?.moreInfoDataSourceCell ?? UITableViewCell() }, @@ -2814,7 +2807,7 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( createdCell: { [weak self] in self?.moreInfoAccXCell?.configure(title: RuuviLocalization.TagSettings.AccelerationXTitleLabel.text, - value: self?.formattedAccelerationValue(from: self?.viewModel?.accelerationX.value)) + value: self?.formattedAccelerationValue(from: self?.viewModel?.accelerationX.value)) self?.moreInfoAccXCell?.selectionStyle = .none return self?.moreInfoAccXCell ?? UITableViewCell() }, @@ -2827,7 +2820,7 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( createdCell: { [weak self] in self?.moreInfoAccYCell?.configure(title: RuuviLocalization.TagSettings.AccelerationYTitleLabel.text, - value: self?.formattedAccelerationValue(from: self?.viewModel?.accelerationY.value)) + value: self?.formattedAccelerationValue(from: self?.viewModel?.accelerationY.value)) self?.moreInfoAccYCell?.selectionStyle = .none return self?.moreInfoAccYCell ?? UITableViewCell() }, @@ -2840,7 +2833,7 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( createdCell: { [weak self] in self?.moreInfoAccZCell?.configure(title: RuuviLocalization.TagSettings.AccelerationZTitleLabel.text, - value: self?.formattedAccelerationValue(from: self?.viewModel?.accelerationZ.value)) + value: self?.formattedAccelerationValue(from: self?.viewModel?.accelerationZ.value)) self?.moreInfoAccZCell?.selectionStyle = .none return self?.moreInfoAccZCell ?? UITableViewCell() }, @@ -2853,7 +2846,7 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( createdCell: { [weak self] in self?.moreInfoTxPowerCell?.configure(title: RuuviLocalization.TagSettings.TxPowerTitleLabel.text, - value: self?.formattedTXPower(from: self?.viewModel?.txPower.value)) + value: self?.formattedTXPower(from: self?.viewModel?.txPower.value)) self?.moreInfoTxPowerCell?.selectionStyle = .none return self?.moreInfoTxPowerCell ?? UITableViewCell() }, @@ -2866,7 +2859,7 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( createdCell: { [weak self] in self?.moreInfoRSSICell?.configure(title: RuuviLocalization.TagSettings.RssiTitleLabel.text, - value: self?.viewModel?.rssi.value.stringValue) + value: self?.viewModel?.rssi.value.stringValue) return self?.moreInfoRSSICell ?? UITableViewCell() }, action: { [weak self] _ in @@ -2880,7 +2873,7 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( createdCell: { [weak self] in self?.moreInfoMSNCell?.configure(title: RuuviLocalization.TagSettings.MsnTitleLabel.text, - value: self?.viewModel?.measurementSequenceNumber.value.stringValue) + value: self?.viewModel?.measurementSequenceNumber.value.stringValue) return self?.moreInfoMSNCell ?? UITableViewCell() }, action: { [weak self] _ in @@ -2894,7 +2887,7 @@ extension TagSettingsViewController { private func formattedDataSource(from source: RuuviTagSensorRecordSource?) -> String { let emptyString = RuuviLocalization.na - if let source = source { + if let source { var sourceString = emptyString switch source { case .advertisement: @@ -2913,16 +2906,17 @@ extension TagSettingsViewController { return emptyString } } + private func formattedBatteryVoltage(from value: Double?) -> String { - if let value = value { - return String.localizedStringWithFormat("%.3f", value) + " " + RuuviLocalization.v + if let value { + String.localizedStringWithFormat("%.3f", value) + " " + RuuviLocalization.v } else { - return RuuviLocalization.na + RuuviLocalization.na } } private func formattedBatteryStatus(from batteryLow: Bool?) -> (status: String?, color: UIColor?) { - if let batteryLow = batteryLow { + if let batteryLow { // swiftlint:disable:next line_length let batteryStatus = batteryLow ? "(\(RuuviLocalization.TagSettings.BatteryStatusLabel.Replace.message))" : "(\(RuuviLocalization.TagSettings.BatteryStatusLabel.Ok.message))" let indicatorColor = batteryLow ? .red : RuuviColor.ruuviTintColor @@ -2933,30 +2927,31 @@ extension TagSettingsViewController { } private func formattedAccelerationValue(from value: Double?) -> String { - if let value = value { - return String.localizedStringWithFormat("%.3f", value) + " " + RuuviLocalization.g + if let value { + String.localizedStringWithFormat("%.3f", value) + " " + RuuviLocalization.g } else { - return RuuviLocalization.na + RuuviLocalization.na } } private func formattedTXPower(from value: Int?) -> String { - if let value = value { - return value.stringValue + " " + RuuviLocalization.dBm + if let value { + value.stringValue + " " + RuuviLocalization.dBm } else { - return RuuviLocalization.na + RuuviLocalization.na } } } // MARK: - FIRMWARE SECTION + extension TagSettingsViewController { private func bindFirmwareSection() { - guard let viewModel = viewModel else { + guard let viewModel else { return } - if let firmwareVersionCell = firmwareVersionCell { + if let firmwareVersionCell { firmwareVersionCell.bind(viewModel.firmwareVersion) { cell, value in cell.configure(value: value ?? RuuviLocalization.na) } @@ -2964,13 +2959,12 @@ extension TagSettingsViewController { } private func configureFirmwareSection() -> TagSettingsSection { - let section = TagSettingsSection( identifier: .firmware, title: RuuviLocalization.TagSettings.SectionHeader.Firmware.title.capitalized, cells: [ tagFirmwareVersionItem(), - tagFirmwareUpdateItem() + tagFirmwareUpdateItem(), ], collapsed: true, headerType: .expandable, @@ -2984,7 +2978,7 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( createdCell: { [weak self] in self?.firmwareVersionCell?.configure(title: RuuviLocalization.TagSettings.Firmware.currentVersion, - value: self?.viewModel?.firmwareVersion.value ?? RuuviLocalization.na) + value: self?.viewModel?.firmwareVersion.value ?? RuuviLocalization.na) self?.firmwareVersionCell?.setAccessory(type: .none) self?.firmwareVersionCell?.selectionStyle = .none return self?.firmwareVersionCell ?? UITableViewCell() @@ -3013,15 +3007,14 @@ extension TagSettingsViewController { } // MARK: - REMOVE SECTION -extension TagSettingsViewController { +extension TagSettingsViewController { private func configureRemoveSection() -> TagSettingsSection { - let section = TagSettingsSection( identifier: .remove, title: RuuviLocalization.remove.capitalized, cells: [ - tagRemoveItem() + tagRemoveItem(), ], collapsed: true, headerType: .expandable, @@ -3049,39 +3042,39 @@ extension TagSettingsViewController { } // MARK: - TableView delegate and datasource -extension TagSettingsViewController: UITableViewDelegate, UITableViewDataSource { - func tableView(_ tableView: UITableView, - numberOfRowsInSection section: Int) -> Int { - return tableViewSections[section].collapsed ? 0 : tableViewSections[section].cells.count +extension TagSettingsViewController: UITableViewDelegate, UITableViewDataSource { + func tableView(_: UITableView, + numberOfRowsInSection section: Int) -> Int + { + tableViewSections[section].collapsed ? 0 : tableViewSections[section].cells.count } - func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell { + func tableView(_: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell + { let cell = tableViewSections[indexPath.section].cells[indexPath.row] return cell.createdCell() } - func numberOfSections(in tableView: UITableView) -> Int { - return tableViewSections.count + func numberOfSections(in _: UITableView) -> Int { + tableViewSections.count } - func tableView(_ tableView: UITableView, didSelectRowAt - indexPath: IndexPath) { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let cell = tableViewSections[indexPath.section].cells[indexPath.row] cell.action?(cell) } - func tableView(_ tableView: UITableView, heightForHeaderInSection - section: Int) -> CGFloat { - return 48 + func tableView(_: UITableView, heightForHeaderInSection _: Int) -> CGFloat { + 48 } // swiftlint:disable:next function_body_length cyclomatic_complexity - func tableView(_ tableView: UITableView, - viewForHeaderInSection - section: Int) -> UIView? { + func tableView(_: UITableView, + viewForHeaderInSection section: Int) -> UIView? + { let sectionItem = tableViewSections[section] switch sectionItem.headerType { case .simple: @@ -3172,10 +3165,10 @@ extension TagSettingsViewController: UITableViewDelegate, UITableViewDataSource case .moreInfo: moreInfoSectionHeaderView?.delegate = self moreInfoSectionHeaderView?.setTitle(with: sectionItem.title, - section: section, - collapsed: sectionItem.collapsed, - backgroundColor: sectionItem.backgroundColor, - font: sectionItem.font) + section: section, + collapsed: sectionItem.collapsed, + backgroundColor: sectionItem.backgroundColor, + font: sectionItem.font) moreInfoSectionHeaderView? .hideSeparator(hide: tableViewSections.count == section) moreInfoSectionHeaderView?.hideAlertComponents() @@ -3214,13 +3207,13 @@ extension TagSettingsViewController: UITableViewDelegate, UITableViewDataSource alertState: AlertState?, section: Int ) -> TagSettingsExpandableSectionHeader { - if let header = header { + if let header { header.delegate = self header.setTitle(with: sectionItem.title, - section: section, - collapsed: sectionItem.collapsed, - backgroundColor: sectionItem.backgroundColor, - font: sectionItem.font) + section: section, + collapsed: sectionItem.collapsed, + backgroundColor: sectionItem.backgroundColor, + font: sectionItem.font) header.setAlertState(with: mutedTill, isOn: isAlertOn, alertState: alertState) @@ -3235,10 +3228,11 @@ extension TagSettingsViewController: UITableViewDelegate, UITableViewDataSource } // + // MARK: - Section Header Delegate + // extension TagSettingsViewController: TagSettingsExpandableSectionHeaderDelegate { - // swiftlint:disable:next cyclomatic_complexity function_body_length func toggleSection(_ header: TagSettingsExpandableSectionHeader, section: Int) { let currentSection = tableViewSections[section] @@ -3269,7 +3263,7 @@ extension TagSettingsViewController: TagSettingsExpandableSectionHeaderDelegate if !collapsed { switch currentSection.identifier { case .alertTemperature: - if let temperatureAlertCell = temperatureAlertCell { + if let temperatureAlertCell { let (minRange, maxRange) = temperatureMinMaxForSliders() temperatureAlertCell.setAlertLimitDescription(description: temperatureAlertRangeDescription()) temperatureAlertCell.setAlertRange(minValue: minRange, @@ -3282,13 +3276,13 @@ extension TagSettingsViewController: TagSettingsExpandableSectionHeaderDelegate ) } case .alertHumidity: - if let humidityAlertCell = humidityAlertCell { + if let humidityAlertCell { let (minRange, maxRange) = humidityMinMaxForSliders() humidityAlertCell.setAlertLimitDescription(description: humidityAlertRangeDescription()) humidityAlertCell.setAlertRange(minValue: minRange, - selectedMinValue: humidityLowerBound(), - maxValue: maxRange, - selectedMaxValue: humidityUpperBound()) + selectedMinValue: humidityLowerBound(), + maxValue: maxRange, + selectedMaxValue: humidityUpperBound()) humidityAlertCell.disableEditing( disable: GlobalHelpers.getBool( from: !showHumidityOffsetCorrection() || !hasMeasurement() @@ -3297,13 +3291,13 @@ extension TagSettingsViewController: TagSettingsExpandableSectionHeaderDelegate ) } case .alertPressure: - if let pressureAlertCell = pressureAlertCell { + if let pressureAlertCell { let (minRange, maxRange) = pressureMinMaxForSliders() pressureAlertCell.setAlertLimitDescription(description: pressureAlertRangeDescription()) pressureAlertCell.setAlertRange(minValue: minRange, - selectedMinValue: pressureLowerBound(), - maxValue: maxRange, - selectedMaxValue: pressureUpperBound()) + selectedMinValue: pressureLowerBound(), + maxValue: maxRange, + selectedMaxValue: pressureUpperBound()) pressureAlertCell.disableEditing( disable: GlobalHelpers.getBool( from: !showPressureOffsetCorrection() || !hasMeasurement() @@ -3312,20 +3306,20 @@ extension TagSettingsViewController: TagSettingsExpandableSectionHeaderDelegate ) } case .alertRSSI: - if let rssiAlertCell = rssiAlertCell { + if let rssiAlertCell { let (minRange, maxRange) = rssiMinMaxForSliders() rssiAlertCell.setAlertLimitDescription(description: rssiAlertRangeDescription()) rssiAlertCell.setAlertRange(minValue: minRange, - selectedMinValue: rssiLowerBound(), - maxValue: maxRange, - selectedMaxValue: rssiUpperBound()) + selectedMinValue: rssiLowerBound(), + maxValue: maxRange, + selectedMaxValue: rssiUpperBound()) rssiAlertCell.disableEditing( disable: GlobalHelpers.getBool(from: !hasMeasurement()), identifier: currentSection.identifier ) } case .alertMovement: - if let movementAlertCell = movementAlertCell { + if let movementAlertCell { movementAlertCell.disableEditing( disable: GlobalHelpers.getBool( from: viewModel?.movementCounter.value == nil || !hasMeasurement() @@ -3334,7 +3328,7 @@ extension TagSettingsViewController: TagSettingsExpandableSectionHeaderDelegate ) } case .alertConnection: - if let connectionAlertCell = connectionAlertCell { + if let connectionAlertCell { connectionAlertCell.disableEditing( disable: GlobalHelpers.getBool( from: !hasMeasurement() @@ -3345,21 +3339,21 @@ extension TagSettingsViewController: TagSettingsExpandableSectionHeaderDelegate case .alertCloudConnection: break case .offsetCorrection: - if let tempOffsetCorrectionCell = tempOffsetCorrectionCell { + if let tempOffsetCorrectionCell { tempOffsetCorrectionCell.disableEditing(!hasMeasurement()) } - if let humidityOffsetCorrectionCell = humidityOffsetCorrectionCell { + if let humidityOffsetCorrectionCell { humidityOffsetCorrectionCell.disableEditing( !hasMeasurement() || - !showHumidityOffsetCorrection() + !showHumidityOffsetCorrection() ) } - if let pressureOffsetCorrectionCell = pressureOffsetCorrectionCell { + if let pressureOffsetCorrectionCell { pressureOffsetCorrectionCell.disableEditing( !hasMeasurement() || - !showPressureOffsetCorrection() + !showPressureOffsetCorrection() ) } default: @@ -3368,16 +3362,14 @@ extension TagSettingsViewController: TagSettingsExpandableSectionHeaderDelegate } } - func didTapSectionMoreInfo(headerView: TagSettingsExpandableSectionHeader) { + func didTapSectionMoreInfo(headerView _: TagSettingsExpandableSectionHeader) { output.viewDidTapOnNoValuesView() } } -extension TagSettingsViewController { - - fileprivate func setUpUI() { - - self.title = RuuviLocalization.TagSettings.NavigationItem.title +private extension TagSettingsViewController { + func setUpUI() { + title = RuuviLocalization.TagSettings.NavigationItem.title view.backgroundColor = RuuviColor.ruuviPrimary @@ -3424,19 +3416,19 @@ extension TagSettingsViewController { tableView.tableFooterView = UIView(frame: CGRect.zero) tableView.cellLayoutMarginsFollowReadableWidth = true if #available(iOS 15.0, *) { - tableView.sectionHeaderTopPadding = 0 + tableView.sectionHeaderTopPadding = 0 } tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 50 } } -extension TagSettingsViewController { - @objc fileprivate func backButtonDidTap() { +private extension TagSettingsViewController { + @objc func backButtonDidTap() { output.viewDidAskToDismiss() } - @objc fileprivate func exportButtonDidTap() { + @objc func exportButtonDidTap() { output.viewDidTapOnExport() } } @@ -3446,29 +3438,31 @@ extension TagSettingsViewController: TagSettingsBackgroundSelectionViewDelegate output.viewDidTriggerChangeBackground() } } + // MARK: - Sensor name rename dialog + extension TagSettingsViewController { private func showSensorNameRenameDialog(name: String?) { let defaultName = GlobalHelpers.ruuviTagDefaultName( - from: self.viewModel?.mac.value, - luid: self.viewModel?.uuid.value + from: viewModel?.mac.value, + luid: viewModel?.uuid.value ) let alert = UIAlertController(title: RuuviLocalization.TagSettings.TagNameTitleLabel.text, message: RuuviLocalization.TagSettings.TagNameTitleLabel.Rename.text, preferredStyle: .alert) alert.addTextField { [weak self] alertTextField in - guard let self = self else { return } + guard let self else { return } alertTextField.delegate = self alertTextField.text = (defaultName == name) ? nil : name alertTextField.placeholder = defaultName - self.tagNameTextField = alertTextField + tagNameTextField = alertTextField } let action = UIAlertAction(title: RuuviLocalization.ok, style: .default) { [weak self] _ in - guard let self = self else { return } - if let name = self.tagNameTextField.text, !name.isEmpty { - self.output.viewDidChangeTag(name: name) + guard let self else { return } + if let name = tagNameTextField.text, !name.isEmpty { + output.viewDidChangeTag(name: name) } else { - self.output.viewDidChangeTag(name: defaultName) + output.viewDidChangeTag(name: defaultName) } } let cancelAction = UIAlertAction(title: RuuviLocalization.cancel, style: .cancel) @@ -3479,72 +3473,78 @@ extension TagSettingsViewController { } // MARK: - Sensor alert custom description dialog + extension TagSettingsViewController { // swiftlint:disable:next function_body_length private func showSensorCustomAlertDescriptionDialog(description: String?, - sender: TagSettingsAlertConfigCell) { + sender: TagSettingsAlertConfigCell) + { let alert = UIAlertController(title: RuuviLocalization.TagSettings.Alert.CustomDescription.title, message: nil, preferredStyle: .alert) alert.addTextField { [weak self] alertTextField in - guard let self = self else { return } + guard let self else { return } alertTextField.delegate = self alertTextField.text = description - self.customAlertDescriptionTextField = alertTextField + customAlertDescriptionTextField = alertTextField } let action = UIAlertAction(title: RuuviLocalization.ok, style: .default) { [weak self] _ in - guard let self = self else { return } - let inputText = self.customAlertDescriptionTextField.text - - switch sender { - case self.temperatureAlertCell: - self.output.viewDidChangeAlertDescription( - for: .temperature(lower: 0, upper: 0), - description: inputText - ) - case self.humidityAlertCell: - self.output.viewDidChangeAlertDescription( - for: .relativeHumidity(lower: 0, upper: 0), - description: inputText - ) - case self.pressureAlertCell: - self.output.viewDidChangeAlertDescription( - for: .pressure(lower: 0, upper: 0), - description: inputText - ) - case self.rssiAlertCell: - self.output.viewDidChangeAlertDescription( - for: .signal(lower: 0, upper: 0), - description: inputText - ) - case self.movementAlertCell: - self.output.viewDidChangeAlertDescription( - for: .movement(last: 0), - description: inputText - ) - case self.connectionAlertCell: - self.output.viewDidChangeAlertDescription( - for: .connection, - description: inputText - ) - case self.cloudConnectionAlertCell: - self.output.viewDidChangeAlertDescription( - for: .cloudConnection(unseenDuration: 0), - description: inputText - ) - default: - break - } + guard let self else { return } + let inputText = customAlertDescriptionTextField.text + notify(sender: sender, inputText: inputText) } let cancelAction = UIAlertAction(title: RuuviLocalization.cancel, style: .cancel) alert.addAction(action) alert.addAction(cancelAction) present(alert, animated: true, completion: nil) } + + private func notify(sender: TagSettingsAlertConfigCell, inputText: String?) { + switch sender { + case temperatureAlertCell: + output.viewDidChangeAlertDescription( + for: .temperature(lower: 0, upper: 0), + description: inputText + ) + case humidityAlertCell: + output.viewDidChangeAlertDescription( + for: .relativeHumidity(lower: 0, upper: 0), + description: inputText + ) + case pressureAlertCell: + output.viewDidChangeAlertDescription( + for: .pressure(lower: 0, upper: 0), + description: inputText + ) + case rssiAlertCell: + output.viewDidChangeAlertDescription( + for: .signal(lower: 0, upper: 0), + description: inputText + ) + case movementAlertCell: + output.viewDidChangeAlertDescription( + for: .movement(last: 0), + description: inputText + ) + case connectionAlertCell: + output.viewDidChangeAlertDescription( + for: .connection, + description: inputText + ) + case cloudConnectionAlertCell: + output.viewDidChangeAlertDescription( + for: .cloudConnection(unseenDuration: 0), + description: inputText + ) + default: + break + } + } } // MARK: - Sensor alert range settings + extension TagSettingsViewController { // swiftlint:disable:next function_parameter_count function_body_length cyclomatic_complexity private func showSensorCustomAlertRangeDialog(title: String?, @@ -3552,73 +3552,62 @@ extension TagSettingsViewController { maximumBound: Double, currentLowerBound: Double?, currentUpperBound: Double?, - sender: TagSettingsAlertConfigCell) { + sender: TagSettingsAlertConfigCell) + { let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert) alert.addTextField { [weak self] alertTextField in - guard let self = self else { return } + guard let self else { return } alertTextField.delegate = self let format = RuuviLocalization.TagSettings.AlertSettings.Dialog.min alertTextField.placeholder = String(format: format, locale: Locale.autoupdatingCurrent, minimumBound) alertTextField.keyboardType = .decimalPad - self.alertMinRangeTextField = alertTextField + alertMinRangeTextField = alertTextField if minimumBound < 0 { - self.alertMinRangeTextField.addNumericAccessory() - } - switch sender { - case self.temperatureAlertCell: - alertTextField.text = self.measurementService.string(for: currentLowerBound) - case self.humidityAlertCell: - alertTextField.text = self.measurementService.string(for: currentLowerBound) - case self.pressureAlertCell: - alertTextField.text = self.measurementService.string(for: currentLowerBound) - default: - break + alertMinRangeTextField.addNumericAccessory() + } + if sender == temperatureAlertCell || sender == humidityAlertCell || sender == pressureAlertCell { + alertTextField.text = measurementService.string(for: currentLowerBound) } } alert.addTextField { [weak self] alertTextField in - guard let self = self else { return } + guard let self else { return } alertTextField.delegate = self let format = RuuviLocalization.TagSettings.AlertSettings.Dialog.max alertTextField.placeholder = String(format: format, locale: Locale.autoupdatingCurrent, maximumBound) alertTextField.keyboardType = .decimalPad - self.alertMaxRangeTextField = alertTextField + alertMaxRangeTextField = alertTextField if maximumBound < 0 { - self.alertMaxRangeTextField.addNumericAccessory() - } - switch sender { - case self.temperatureAlertCell: - alertTextField.text = self.measurementService.string(for: currentUpperBound) - case self.humidityAlertCell: - alertTextField.text = self.measurementService.string(for: currentUpperBound) - case self.pressureAlertCell: - alertTextField.text = self.measurementService.string(for: currentUpperBound) - default: - break + alertMaxRangeTextField.addNumericAccessory() + } + if sender == temperatureAlertCell || sender == humidityAlertCell || sender == pressureAlertCell { + alertTextField.text = measurementService.string(for: currentUpperBound) } } let action = UIAlertAction(title: RuuviLocalization.ok, style: .default) { [weak self] _ in - guard let self = self else { return } - guard let minimumInputText = self.alertMinRangeTextField.text, - minimumInputText.doubleValue >= minimumBound else { + guard let self else { return } + guard let minimumInputText = alertMinRangeTextField.text, + minimumInputText.doubleValue >= minimumBound + else { return } - guard let maximumInputText = self.alertMaxRangeTextField.text, - maximumInputText.doubleValue <= maximumBound else { + guard let maximumInputText = alertMaxRangeTextField.text, + maximumInputText.doubleValue <= maximumBound + else { return } - self.didSetAlertRange(sender: sender, - minValue: minimumInputText.doubleValue, - maxValue: maximumInputText.doubleValue ) + didSetAlertRange(sender: sender, + minValue: minimumInputText.doubleValue, + maxValue: maximumInputText.doubleValue) } let cancelAction = UIAlertAction(title: RuuviLocalization.cancel, style: .cancel) alert.addAction(action) @@ -3628,38 +3617,41 @@ extension TagSettingsViewController { } // MARK: - Cloud connection alert delay settings + extension TagSettingsViewController { // swiftlint:disable:next function_parameter_count private func showSensorCustomAlertRangeDialog(title: String?, message: String?, minimum: Int, - default: Int, + default _: Int, current: Int?, - sender: TagSettingsAlertConfigCell) { + sender _: TagSettingsAlertConfigCell) + { let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) alert.addTextField { [weak self] alertTextField in - guard let self = self else { return } + guard let self else { return } alertTextField.delegate = self alertTextField.keyboardType = .numberPad - self.cloudConnectionAlertDelayTextField = alertTextField + cloudConnectionAlertDelayTextField = alertTextField alertTextField.text = current?.stringValue } let action = UIAlertAction(title: RuuviLocalization.ok, style: .default) { [weak self] _ in - guard let self = self else { return } - guard let durationInput = self.cloudConnectionAlertDelayTextField.text?.intValue, - durationInput >= minimum else { + guard let self else { return } + guard let durationInput = cloudConnectionAlertDelayTextField.text?.intValue, + durationInput >= minimum + else { return } - let currentDuration = self.viewModel?.cloudConnectionAlertUnseenDuration.value?.intValue ?? 900 - if durationInput == (currentDuration/60) { + let currentDuration = viewModel?.cloudConnectionAlertUnseenDuration.value?.intValue ?? 900 + if durationInput == (currentDuration / 60) { return } - self.output.viewDidChangeCloudConnectionAlertUnseenDuration(duration: durationInput*60) + output.viewDidChangeCloudConnectionAlertUnseenDuration(duration: durationInput * 60) } let cancelAction = UIAlertAction(title: RuuviLocalization.cancel, style: .cancel) alert.addAction(action) @@ -3680,8 +3672,8 @@ extension TagSettingsViewController: TagSettingsViewInput { controller.addAction(UIAlertAction(title: RuuviLocalization.yes, style: .default, handler: { [weak self] _ in - self?.output.viewDidConfirmClaimTag() - })) + self?.output.viewDidConfirmClaimTag() + })) controller.addAction(UIAlertAction(title: RuuviLocalization.no, style: .cancel, handler: nil)) present(controller, animated: true) } @@ -3732,7 +3724,7 @@ extension TagSettingsViewController: TagSettingsViewInput { } func resetKeepConnectionSwitch() { - if let btPairCell = btPairCell { + if let btPairCell { btPairCell.configureSwitch(value: false) btPairCell.disableSwitch(disable: false) } @@ -3744,19 +3736,19 @@ extension TagSettingsViewController: TagSettingsViewInput { controller.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: { [weak self] _ in - self?.resetKeepConnectionSwitch() - })) + self?.resetKeepConnectionSwitch() + })) present(controller, animated: true) } func stopKeepConnectionAnimatingDots() { - if let btPairCell = btPairCell { + if let btPairCell { btPairCell.configurePairingAnimation(start: false) } } func startKeepConnectionAnimatingDots() { - if let btPairCell = btPairCell { + if let btPairCell { btPairCell.configurePairingAnimation(start: true) } } @@ -3775,12 +3767,13 @@ extension TagSettingsViewController: TagSettingsViewInput { } // MARK: - UITextFieldDelegate -extension TagSettingsViewController: UITextFieldDelegate { +extension TagSettingsViewController: UITextFieldDelegate { // swiftlint:disable:next cyclomatic_complexity - func textField(_ textField: UITextField, shouldChangeCharactersIn - range: NSRange, - replacementString string: String) -> Bool { + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, + + replacementString string: String) -> Bool + { guard let text = textField.text else { return true } @@ -3798,7 +3791,6 @@ extension TagSettingsViewController: UITextFieldDelegate { return false } } else if textField == alertMinRangeTextField || textField == alertMaxRangeTextField { - guard let text = textField.text, let decimalSeparator = NSLocale.current.decimalSeparator else { return true } @@ -3811,14 +3803,14 @@ extension TagSettingsViewController: UITextFieldDelegate { // Check if we will exceed 2 dp if - splitText.last?.count ?? 0 > 1 && string.count != 0 && - isEditingEnd + splitText.last?.count ?? 0 > 1, string.count != 0, + isEditingEnd { return false } // If there is already a dot we don't want to allow further dots - if totalDecimalSeparators > 0 && string == decimalSeparator { + if totalDecimalSeparators > 0, string == decimalSeparator { return false } diff --git a/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift b/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift index cf5934113..43e406b69 100644 --- a/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift +++ b/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift @@ -1,12 +1,12 @@ -import UIKit import RuuviPresenters +import UIKit class AlertPresenterImpl: AlertPresenter { func showAlert(_ viewModel: AlertViewModel) { let alert = UIAlertController(title: viewModel.title, message: viewModel.message, preferredStyle: viewModel.style) - viewModel.actions.forEach({ alert.addAction($0) }) + viewModel.actions.forEach { alert.addAction($0) } let group = DispatchGroup() DispatchQueue.main.async { group.enter() diff --git a/station/Classes/Presentation/Presenters/MailComposer/MailComposerPresenter.swift b/station/Classes/Presentation/Presenters/MailComposer/MailComposerPresenter.swift index a4fbbc249..e42d1eb33 100644 --- a/station/Classes/Presentation/Presenters/MailComposer/MailComposerPresenter.swift +++ b/station/Classes/Presentation/Presenters/MailComposer/MailComposerPresenter.swift @@ -6,6 +6,6 @@ protocol MailComposerPresenter { extension MailComposerPresenter { func present(email: String, subject: String) { - return present(email: email, subject: subject, body: nil) + present(email: email, subject: subject, body: nil) } } diff --git a/station/Classes/Presentation/Presenters/MailComposer/MessageUI/MailComposerPresenterMessageUI.swift b/station/Classes/Presentation/Presenters/MailComposer/MessageUI/MailComposerPresenterMessageUI.swift index ffc1217b7..b2bb27e61 100644 --- a/station/Classes/Presentation/Presenters/MailComposer/MessageUI/MailComposerPresenterMessageUI.swift +++ b/station/Classes/Presentation/Presenters/MailComposer/MessageUI/MailComposerPresenterMessageUI.swift @@ -19,29 +19,33 @@ class MailComposerPresenterMessageUI: NSObject, MailComposerPresenter { } // MARK: - MFMailComposeViewControllerDelegate + extension MailComposerPresenterMessageUI: MFMailComposeViewControllerDelegate { func mailComposeController(_ controller: MFMailComposeViewController, - didFinishWith result: MFMailComposeResult, - error: Error?) { + didFinishWith _: MFMailComposeResult, + error _: Error?) + { controller.dismiss(animated: true) } } // MARK: - Private method + extension MailComposerPresenterMessageUI { /// This method takes three arguments recipient email, subject and body. /// Returns a computer email URL that opens the default email client set by the user. private func generateEmailURL(email: String, subject: String, body: String?) -> URL? { guard let toEncoded = email - .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), - let subjectEncoded = subject - .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), + let subjectEncoded = subject + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) + else { return nil } let bodyEncoded = body?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "" let defaultURL = URL(string: "mailto:\(toEncoded)?subject=\(subjectEncoded)&body=\(bodyEncoded)") - if let defaultURL = defaultURL, UIApplication.shared.canOpenURL(defaultURL) { + if let defaultURL, UIApplication.shared.canOpenURL(defaultURL) { return defaultURL } else { return nil diff --git a/station/Classes/Presentation/Presenters/PhotoPicker/Sheet/PhotoPickerPresenterSheet.swift b/station/Classes/Presentation/Presenters/PhotoPicker/Sheet/PhotoPickerPresenterSheet.swift index 311515aa4..3e2a0fae1 100644 --- a/station/Classes/Presentation/Presenters/PhotoPicker/Sheet/PhotoPickerPresenterSheet.swift +++ b/station/Classes/Presentation/Presenters/PhotoPicker/Sheet/PhotoPickerPresenterSheet.swift @@ -1,7 +1,7 @@ -import UIKit import MobileCoreServices import RuuviCore import RuuviPresenters +import UIKit class PhotoPickerPresenterSheet: NSObject, PhotoPickerPresenter { weak var delegate: PhotoPickerPresenterDelegate? @@ -18,9 +18,11 @@ class PhotoPickerPresenterSheet: NSObject, PhotoPickerPresenter { } // MARK: - UIImagePickerControllerDelegate + extension PhotoPickerPresenterSheet: UIImagePickerControllerDelegate, UINavigationControllerDelegate { func imagePickerController(_ picker: UIImagePickerController, - didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) { + didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) + { picker.dismiss(animated: true, completion: { [weak self] in guard let sSelf = self else { return } if let photo = info[.originalImage] as? UIImage { @@ -31,13 +33,13 @@ extension PhotoPickerPresenterSheet: UIImagePickerControllerDelegate, UINavigati } // MARK: - Private -extension PhotoPickerPresenterSheet { +extension PhotoPickerPresenterSheet { private func checkPhotoLibraryPermission() { if permissionsManager.isPhotoLibraryPermissionGranted { showPhotoLibrary() } else { - permissionsManager.requestPhotoLibraryPermission { [weak self] (granted) in + permissionsManager.requestPhotoLibraryPermission { [weak self] granted in if granted { self?.showPhotoLibrary() } else { @@ -51,7 +53,7 @@ extension PhotoPickerPresenterSheet { if permissionsManager.isCameraPermissionGranted { showCamera() } else { - permissionsManager.requestCameraPermission { [weak self] (granted) in + permissionsManager.requestCameraPermission { [weak self] granted in if granted { self?.showCamera() } else { @@ -76,5 +78,4 @@ extension PhotoPickerPresenterSheet { vc.delegate = self viewController.present(vc, animated: true) } - } diff --git a/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissNavigationController.swift b/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissNavigationController.swift index fdd2b8b71..1fe140c1b 100644 --- a/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissNavigationController.swift +++ b/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissNavigationController.swift @@ -4,7 +4,7 @@ class SwipeDownToDismissNavigationController: UINavigationController, UIGestureR lazy var panGR: UIPanGestureRecognizer = { let panGR = UIPanGestureRecognizer(target: self, action: #selector - (SwipeDownToDismissNavigationController.handlePanGesture(_:))) + (SwipeDownToDismissNavigationController.handlePanGesture(_:))) panGR.delegate = self panGR.isEnabled = true return panGR @@ -12,12 +12,13 @@ class SwipeDownToDismissNavigationController: UINavigationController, UIGestureR override func viewDidLoad() { super.viewDidLoad() - self.view.addGestureRecognizer(panGR) + view.addGestureRecognizer(panGR) } - func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, - shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { - return true + func gestureRecognizer(_: UIGestureRecognizer, + shouldRecognizeSimultaneouslyWith _: UIGestureRecognizer) -> Bool + { + true } @objc func handlePanGesture(_ sender: UIPanGestureRecognizer) { @@ -35,7 +36,8 @@ class SwipeDownToDismissNavigationController: UINavigationController, UIGestureR switch sender.state { case .began: if let tagSettings = topViewController as? UITableViewController, - tagSettings.tableView.contentOffset.y <= 0 { + tagSettings.tableView.contentOffset.y <= 0 + { interactor.hasStarted = true dismiss(animated: true) } diff --git a/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitionAnimation.swift b/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitionAnimation.swift index be30f03de..87fbf553e 100644 --- a/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitionAnimation.swift +++ b/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitionAnimation.swift @@ -1,7 +1,6 @@ import UIKit class SwipeDownToDismissTransitionAnimation: NSObject, UIViewControllerAnimatedTransitioning { - private lazy var dimmingView: UIView = { let view = UIView() view.backgroundColor = UIColor(white: 0.0, alpha: 1.0) @@ -9,16 +8,16 @@ class SwipeDownToDismissTransitionAnimation: NSObject, UIViewControllerAnimatedT return view }() - func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { - return 0.3 + func transitionDuration(using _: UIViewControllerContextTransitioning?) -> TimeInterval { + 0.3 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let fromVC = transitionContext.viewController(forKey: .from), let toVC = transitionContext.viewController(forKey: .to) - else { - return + else { + return } let containerView = transitionContext.containerView @@ -38,8 +37,9 @@ class SwipeDownToDismissTransitionAnimation: NSObject, UIViewControllerAnimatedT animations: { self.dimmingView.alpha = 0.0 fromVC.view.frame = finalFrame - }, completion: { _ in - transitionContext.completeTransition(!transitionContext.transitionWasCancelled) - }) + }, completion: { _ in + transitionContext.completeTransition(!transitionContext.transitionWasCancelled) + } + ) } } diff --git a/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitioningDelegate.swift b/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitioningDelegate.swift index 215b8a899..b3bb27c80 100644 --- a/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitioningDelegate.swift +++ b/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitioningDelegate.swift @@ -1,15 +1,15 @@ import UIKit class SwipeDownToDismissTransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate { - let interactionControllerForDismissal = SwipeDownToDismissInteractiveTransition() - func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { - return SwipeDownToDismissTransitionAnimation() + func animationController(forDismissed _: UIViewController) -> UIViewControllerAnimatedTransitioning? { + SwipeDownToDismissTransitionAnimation() } - func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) - -> UIViewControllerInteractiveTransitioning? { - return interactionControllerForDismissal.hasStarted ? interactionControllerForDismissal : nil + func interactionControllerForDismissal(using _: UIViewControllerAnimatedTransitioning) + -> UIViewControllerInteractiveTransitioning? + { + interactionControllerForDismissal.hasStarted ? interactionControllerForDismissal : nil } } diff --git a/station/Classes/Routers/AppRouter.swift b/station/Classes/Routers/AppRouter.swift index 4c52abc4a..0aba657d9 100644 --- a/station/Classes/Routers/AppRouter.swift +++ b/station/Classes/Routers/AppRouter.swift @@ -1,19 +1,19 @@ -import UIKit -import RuuviLocal import LightRoute -import RuuviUser +import RuuviLocal import RuuviOntology +import RuuviUser +import UIKit final class AppRouter { var viewController: UIViewController { - return self.navigationController + navigationController } var settings: RuuviLocalSettings! // navigation controller private var navigationController: UINavigationController { - if let navigationController = self.weakNavigationController { + if let navigationController = weakNavigationController { return navigationController } else { let rootViewController: UIViewController @@ -22,11 +22,11 @@ final class AppRouter { rootViewController = controller } else { AppUtility.lockOrientation(.portrait) - rootViewController = self.onboardRouter().viewController + rootViewController = onboardRouter().viewController } let navigationController = UINavigationController(rootViewController: rootViewController) navigationController.navigationBar.tintColor = .clear - self.weakNavigationController = navigationController + weakNavigationController = navigationController return navigationController } } @@ -36,15 +36,16 @@ final class AppRouter { // routers private func onboardRouter() -> OnboardRouter { - if let onboardRouter = self.weakOnboardRouter { + if let onboardRouter = weakOnboardRouter { return onboardRouter } else { let onboardRouter = OnboardRouter() onboardRouter.delegate = self - self.weakOnboardRouter = onboardRouter + weakOnboardRouter = onboardRouter return onboardRouter } } + private weak var weakOnboardRouter: OnboardRouter? private func discoverRouter() -> DiscoverRouter { @@ -53,10 +54,11 @@ final class AppRouter { } else { let discoverRouter = DiscoverRouter() discoverRouter.delegate = self - self.weakDiscoverRouter = discoverRouter + weakDiscoverRouter = discoverRouter return discoverRouter } } + private weak var weakDiscoverRouter: DiscoverRouter? /// Return dashboard view controller @@ -71,24 +73,25 @@ final class AppRouter { func prepareRootViewControllerWidgets() { let rootViewController: UIViewController if settings.welcomeShown { - if let weakDashboardController = weakDashboardController { + if let weakDashboardController { rootViewController = weakDashboardController } else { let controller = dashboardViewController() rootViewController = controller } } else { - rootViewController = self.onboardRouter().viewController + rootViewController = onboardRouter().viewController } let navigationController = UINavigationController(rootViewController: rootViewController) navigationController.navigationBar.tintColor = .clear - self.weakNavigationController = navigationController + weakNavigationController = navigationController } } extension AppRouter: OnboardRouterDelegate { - func onboardRouterDidShowSignIn(_ router: OnboardRouter, - output: SignInBenefitsModuleOutput) { + func onboardRouterDidShowSignIn(_: OnboardRouter, + output: SignInBenefitsModuleOutput) + { let factory: SignInBenefitsModuleFactory = SignInPromoModuleFactoryImpl() let module = factory.create() @@ -101,13 +104,14 @@ extension AppRouter: OnboardRouterDelegate { } } - func onboardRouterDidFinish(_ router: OnboardRouter) { + func onboardRouterDidFinish(_: OnboardRouter) { presentDashboard() } - func onboardRouterDidFinish(_ router: OnboardRouter, + func onboardRouterDidFinish(_: OnboardRouter, module: SignInBenefitsModuleInput, - showDashboard: Bool) { + showDashboard: Bool) + { module.dismiss(completion: { [weak self] in if showDashboard { self?.presentDashboard() @@ -125,8 +129,8 @@ extension AppRouter: OnboardRouterDelegate { } extension AppRouter: DiscoverRouterDelegate { - func discoverRouterWantsClose(_ router: DiscoverRouter) { - if let weakDashboardController = weakDashboardController { + func discoverRouterWantsClose(_: DiscoverRouter) { + if let weakDashboardController { navigationController.pushViewController(weakDashboardController, animated: true) } else { @@ -136,8 +140,8 @@ extension AppRouter: DiscoverRouterDelegate { } func discoverRouterWantsCloseWithRuuviTagNavigation( - _ router: DiscoverRouter, - ruuviTag: RuuviTagSensor + _: DiscoverRouter, + ruuviTag _: RuuviTagSensor ) { // No op. } diff --git a/station/Classes/Routers/DiscoverRouter.swift b/station/Classes/Routers/DiscoverRouter.swift index f017b590f..971440c94 100644 --- a/station/Classes/Routers/DiscoverRouter.swift +++ b/station/Classes/Routers/DiscoverRouter.swift @@ -1,7 +1,7 @@ +import BTKit import Foundation import RuuviDiscover import RuuviOntology -import BTKit import UIKit protocol DiscoverRouterDelegate: AnyObject { @@ -14,36 +14,38 @@ protocol DiscoverRouterDelegate: AnyObject { final class DiscoverRouter { var viewController: UIViewController { - return self.discover.viewController + self.discover.viewController } + weak var delegate: DiscoverRouterDelegate? // modules private var discover: RuuviDiscover { - if let discover = self.weakDiscover { + if let discover = weakDiscover { return discover } else { let r = AppAssembly.shared.assembler.resolver let discover = r.resolve(RuuviDiscover.self)! discover.router = self discover.output = self - self.weakDiscover = discover + weakDiscover = discover return discover } } + private weak var weakDiscover: RuuviDiscover? } extension DiscoverRouter: RuuviDiscoverOutput { - func ruuviDiscoverWantsClose(_ ruuviDiscover: RuuviDiscover) { + func ruuviDiscoverWantsClose(_: RuuviDiscover) { delegate?.discoverRouterWantsClose(self) } - func ruuvi(discover: RuuviDiscover, didAdd ruuviTag: AnyRuuviTagSensor) { + func ruuvi(discover _: RuuviDiscover, didAdd _: AnyRuuviTagSensor) { delegate?.discoverRouterWantsClose(self) } - func ruuvi(discover: RuuviDiscover, didSelectFromNFC ruuviTag: RuuviTagSensor) { + func ruuvi(discover _: RuuviDiscover, didSelectFromNFC ruuviTag: RuuviTagSensor) { delegate?.discoverRouterWantsCloseWithRuuviTagNavigation(self, ruuviTag: ruuviTag) } } diff --git a/station/Classes/Routers/OnboardRouter.swift b/station/Classes/Routers/OnboardRouter.swift index dcaae73ca..7fe282c01 100644 --- a/station/Classes/Routers/OnboardRouter.swift +++ b/station/Classes/Routers/OnboardRouter.swift @@ -1,6 +1,6 @@ -import UIKit import RuuviOnboard import RuuviUser +import UIKit protocol OnboardRouterDelegate: AnyObject { func onboardRouterDidFinish(_ router: OnboardRouter) @@ -15,45 +15,46 @@ final class OnboardRouter { let r = AppAssembly.shared.assembler.resolver weak var delegate: OnboardRouterDelegate? var viewController: UIViewController { - return self.onboard.viewController + onboard.viewController } // modules private var onboard: RuuviOnboard { - if let onboard = self.weakOnboard { + if let onboard = weakOnboard { return onboard } else { let ruuviUser = r.resolve(RuuviUser.self)! let onboard = RuuviOnboardPages(ruuviUser: ruuviUser) onboard.router = self onboard.output = self - self.weakOnboard = onboard + weakOnboard = onboard return onboard } } + private weak var weakOnboard: RuuviOnboard? } extension OnboardRouter: RuuviOnboardOutput { - func ruuviOnboardDidFinish(_ ruuviOnboard: RuuviOnboard) { + func ruuviOnboardDidFinish(_: RuuviOnboard) { delegate?.onboardRouterDidFinish(self) } - func ruuviOnboardDidShowSignIn(_ ruuviOnboard: RuuviOnboard) { + func ruuviOnboardDidShowSignIn(_: RuuviOnboard) { delegate?.onboardRouterDidShowSignIn(self, output: self) } } extension OnboardRouter: SignInBenefitsModuleOutput { - func signIn(module: SignInBenefitsModuleInput, didCloseSignInWithoutAttempt sender: Any?) { + func signIn(module: SignInBenefitsModuleInput, didCloseSignInWithoutAttempt _: Any?) { delegate?.onboardRouterDidFinish(self, module: module, showDashboard: false) } - func signIn(module: SignInBenefitsModuleInput, didSelectUseWithoutAccount sender: Any?) { + func signIn(module: SignInBenefitsModuleInput, didSelectUseWithoutAccount _: Any?) { delegate?.onboardRouterDidFinish(self, module: module, showDashboard: true) } - func signIn(module: SignInBenefitsModuleInput, didSuccessfulyLogin sender: Any?) { + func signIn(module: SignInBenefitsModuleInput, didSuccessfulyLogin _: Any?) { delegate?.onboardRouterDidFinish(self, module: module, showDashboard: true) } } diff --git a/station/Extensions/Array+AnyRuuviTagSensor.swift b/station/Extensions/Array+AnyRuuviTagSensor.swift index f2e1b9467..fe15ce65a 100644 --- a/station/Extensions/Array+AnyRuuviTagSensor.swift +++ b/station/Extensions/Array+AnyRuuviTagSensor.swift @@ -1,10 +1,10 @@ import Foundation -import RuuviOntology import RuuviLocal +import RuuviOntology -extension Array where Element == AnyRuuviTagSensor { +extension [AnyRuuviTagSensor] { func reordered() -> Self { - return self.sorted(by: { + sorted(by: { // Sort sensors by name alphabetically let first = $0.name.lowercased() let second = $1.name.lowercased() diff --git a/station/Extensions/CALayer+IB.swift b/station/Extensions/CALayer+IB.swift index d9c141d49..8b1c681a8 100644 --- a/station/Extensions/CALayer+IB.swift +++ b/station/Extensions/CALayer+IB.swift @@ -1,13 +1,12 @@ import UIKit extension CALayer { - @IBInspectable var borderColorIB: UIColor? { get { if let borderColorCG = borderColor { - return UIColor(cgColor: borderColorCG) + UIColor(cgColor: borderColorCG) } else { - return nil + nil } } set { @@ -18,9 +17,9 @@ extension CALayer { @IBInspectable var shadowColorIB: UIColor? { get { if let shadowColorCG = shadowColor { - return UIColor(cgColor: shadowColorCG) + UIColor(cgColor: shadowColorCG) } else { - return nil + nil } } set { diff --git a/station/Extensions/Classess/AppDateFormatter.swift b/station/Extensions/Classess/AppDateFormatter.swift index 0f7b3465f..a6f33a0e4 100644 --- a/station/Extensions/Classess/AppDateFormatter.swift +++ b/station/Extensions/Classess/AppDateFormatter.swift @@ -29,15 +29,15 @@ class AppDateFormatter { extension AppDateFormatter { func ruuviAgoString(from date: Date) -> String { - return ruuviAgoFormatter.string(from: date) + ruuviAgoFormatter.string(from: date) } func shortTimeString(from date: Date) -> String { - return shortTimeFormatter.string(from: date) + shortTimeFormatter.string(from: date) } func graphXAxisTimeString(from date: Date) -> String { - return shortTimeFormatter.string(from: date) + shortTimeFormatter.string(from: date) } func graphXAxisDateString(from date: Date) -> String { diff --git a/station/Extensions/Classess/RuuviCustomButton.swift b/station/Extensions/Classess/RuuviCustomButton.swift index a8a273158..c5f9480d4 100644 --- a/station/Extensions/Classess/RuuviCustomButton.swift +++ b/station/Extensions/Classess/RuuviCustomButton.swift @@ -1,7 +1,6 @@ import UIKit class RuuviCustomButton: UIView { - var image: UIImage? { didSet { iconView.image = image @@ -24,17 +23,18 @@ class RuuviCustomButton: UIView { iconSize: CGSize = .init(width: 20, height: 20) ) { self.init() - self.iconView.image = icon - self.iconView.tintColor = tintColor + iconView.image = icon + iconView.tintColor = tintColor self.iconSize = iconSize - self.setUpUI() + setUpUI() } override init(frame: CGRect) { super.init(frame: frame) } - required init?(coder: NSCoder) { + @available(*, unavailable) + required init?(coder _: NSCoder) { fatalError("init(coder:) has not been implemented") } } diff --git a/station/Extensions/Classess/RuuviLinkTextView.swift b/station/Extensions/Classess/RuuviLinkTextView.swift index 5dc1b6958..4b02184d5 100644 --- a/station/Extensions/Classess/RuuviLinkTextView.swift +++ b/station/Extensions/Classess/RuuviLinkTextView.swift @@ -5,7 +5,6 @@ protocol RuuviLinkTextViewDelegate: NSObjectProtocol { } class RuuviLinkTextView: UITextView { - private var textRegularColor: UIColor? = RuuviColor .dashboardIndicatorTextColor? .withAlphaComponent(0.6) @@ -24,8 +23,8 @@ class RuuviLinkTextView: UITextView { link: String? ) { self.init() - self.textRegularColor = textColor - self.textLinkColor = linkColor + textRegularColor = textColor + textLinkColor = linkColor self.fullTextString = fullTextString self.linkString = linkString self.link = link @@ -51,16 +50,16 @@ class RuuviLinkTextView: UITextView { let regularAttributes: [NSAttributedString.Key: Any] = [ .font: UIFont.Muli(.regular, size: 13), - .foregroundColor: textRegularColor ?? .secondaryLabel + .foregroundColor: textRegularColor ?? .secondaryLabel, ] let tappableAttributes: [NSAttributedString.Key: Any] = [ .font: UIFont.Muli(.bold, size: 13), - .foregroundColor: textLinkColor ?? .secondaryLabel + .foregroundColor: textLinkColor ?? .secondaryLabel, ] - guard let fullTextString = fullTextString, - let linkString = linkString else { return } + guard let fullTextString, + let linkString else { return } let attributedText = NSMutableAttributedString( string: fullTextString, attributes: regularAttributes @@ -86,9 +85,9 @@ class RuuviLinkTextView: UITextView { fractionOfDistanceBetweenInsertionPoints: nil ) - guard let fullTextString = fullTextString, - let linkString = linkString, - let link = link else { return } + guard let fullTextString, + let linkString, + let link else { return } if let tappableTextRange = fullTextString.range(of: linkString) { let nsRange = NSRange(tappableTextRange, in: fullTextString) diff --git a/station/Extensions/Classess/RuuviUISwitch.swift b/station/Extensions/Classess/RuuviUISwitch.swift index 99b97f3f4..b4864ee02 100644 --- a/station/Extensions/Classess/RuuviUISwitch.swift +++ b/station/Extensions/Classess/RuuviUISwitch.swift @@ -1,7 +1,6 @@ import UIKit class RuuviUISwitch: UISwitch { - private let activeThumbColor: UIColor? = RuuviColor.ruuviTintColor private let inactiveThumbColor: UIColor? = RuuviColor.ruuviSwitchDisabledThumbTint diff --git a/station/Extensions/Color+Ruuvi.swift b/station/Extensions/Color+Ruuvi.swift index 8ae0121ae..e5f9b30c0 100644 --- a/station/Extensions/Color+Ruuvi.swift +++ b/station/Extensions/Color+Ruuvi.swift @@ -2,13 +2,13 @@ import UIKit extension UIColor { static var normalButtonBackground: UIColor { - return UIColor(red: 21.0 / 255, - green: 141.0 / 255, - blue: 165.0 / 255, - alpha: 1) + UIColor(red: 21.0 / 255, + green: 141.0 / 255, + blue: 165.0 / 255, + alpha: 1) } static var disableButtonBackground: UIColor { - return UIColor.darkGray + UIColor.darkGray } } diff --git a/station/Extensions/Date+Ruuvi.swift b/station/Extensions/Date+Ruuvi.swift index b1b735d66..8070761bd 100644 --- a/station/Extensions/Date+Ruuvi.swift +++ b/station/Extensions/Date+Ruuvi.swift @@ -11,7 +11,7 @@ extension Date { } else { let seconds = elapsed % 60 let minutes = (elapsed / 60) % 60 - let hours = (elapsed / (60*60)) % 24 + let hours = (elapsed / (60 * 60)) % 24 if hours > 0 { output += String(hours) + " " + RuuviLocalization.h + " " } diff --git a/station/Extensions/DfuFirmware+Log.swift b/station/Extensions/DfuFirmware+Log.swift index d8638a716..773b60029 100644 --- a/station/Extensions/DfuFirmware+Log.swift +++ b/station/Extensions/DfuFirmware+Log.swift @@ -1,11 +1,11 @@ import Foundation -import RuuviLocalization import RuuviDFU +import RuuviLocalization #if canImport(NordicDFU) -import NordicDFU + import NordicDFU #endif #if canImport(iOSDFULibrary) -import iOSDFULibrary + import iOSDFULibrary #endif extension DFUFirmware { diff --git a/station/Extensions/Double+Extension.swift b/station/Extensions/Double+Extension.swift index 4993bdd41..8da2911a3 100644 --- a/station/Extensions/Double+Extension.swift +++ b/station/Extensions/Double+Extension.swift @@ -13,9 +13,9 @@ extension Double { } } -extension Optional where Wrapped == Double { +extension Double? { var intValue: Int { - guard let self = self else { + guard let self else { return 0 } return Int(self) @@ -24,6 +24,6 @@ extension Optional where Wrapped == Double { extension Double { var intValue: Int { - return Int(self) + Int(self) } } diff --git a/station/Extensions/Double+Temperature.swift b/station/Extensions/Double+Temperature.swift index 57b944209..692578976 100644 --- a/station/Extensions/Double+Temperature.swift +++ b/station/Extensions/Double+Temperature.swift @@ -2,36 +2,36 @@ import Foundation extension Double { var fahrenheit: Double { - return self * 9.0/5.0 + 32.0 + self * 9.0 / 5.0 + 32.0 } var kelvin: Double { - return self + 273.15 + self + 273.15 } var celsiusFromFahrenheit: Double { - return (self - 32.0) * 5.0/9.0 + (self - 32.0) * 5.0 / 9.0 } var celsiusFromKelvin: Double { - return self - 273.15 + self - 273.15 } } extension Double { var inHg: Double { - return self * 0.02953 + self * 0.02953 } var mmHg: Double { - return self * 0.75006 + self * 0.75006 } var hPaFrominHg: Double { - return self * 33.86389 + self * 33.86389 } var hPaFrommmHg: Double { - return self * 1.33322 + self * 1.33322 } } diff --git a/station/Extensions/Errors/RUError.swift b/station/Extensions/Errors/RUError.swift index e0856a7ac..19f152ed1 100644 --- a/station/Extensions/Errors/RUError.swift +++ b/station/Extensions/Errors/RUError.swift @@ -1,12 +1,12 @@ -import Foundation import BTKit -import RuuviStorage +import Foundation +import RuuviDFU +import RuuviLocal +import RuuviLocalization import RuuviPersistence import RuuviPool -import RuuviLocal import RuuviService -import RuuviDFU -import RuuviLocalization +import RuuviStorage enum RUError: Error { case ruuviLocal(RuuviLocalError) @@ -30,38 +30,38 @@ enum RUError: Error { extension RUError: LocalizedError { public var errorDescription: String? { switch self { - case .ruuviLocal(let error): - return error.localizedDescription - case .ruuviPool(let error): - return error.localizedDescription - case .ruuviPersistence(let error): - return error.localizedDescription - case .ruuviStorage(let error): - return error.localizedDescription - case .ruuviService(let error): - return error.localizedDescription - case .core(let error): - return error.localizedDescription - case .persistence(let error): - return error.localizedDescription - case .networking(let error): - return error.localizedDescription - case .parse(let error): - return error.localizedDescription - case .map(let error): - return error.localizedDescription - case .expected(let error): - return error.localizedDescription - case .unexpected(let error): - return error.localizedDescription - case .btkit(let error): - return error.localizedDescription - case .bluetooth(let error): - return error.localizedDescription - case .writeToDisk(let error): - return error.localizedDescription - case .dfuError(let error): - return error.localizedDescription + case let .ruuviLocal(error): + error.localizedDescription + case let .ruuviPool(error): + error.localizedDescription + case let .ruuviPersistence(error): + error.localizedDescription + case let .ruuviStorage(error): + error.localizedDescription + case let .ruuviService(error): + error.localizedDescription + case let .core(error): + error.localizedDescription + case let .persistence(error): + error.localizedDescription + case let .networking(error): + error.localizedDescription + case let .parse(error): + error.localizedDescription + case let .map(error): + error.localizedDescription + case let .expected(error): + error.localizedDescription + case let .unexpected(error): + error.localizedDescription + case let .btkit(error): + error.localizedDescription + case let .bluetooth(error): + error.localizedDescription + case let .writeToDisk(error): + error.localizedDescription + case let .dfuError(error): + error.localizedDescription } } } @@ -74,7 +74,7 @@ extension BluetoothError: LocalizedError { public var errorDescription: String? { switch self { case .disconnected: - return RuuviLocalization.BluetoothError.disconnected + RuuviLocalization.BluetoothError.disconnected } } } @@ -95,23 +95,23 @@ extension CoreError: LocalizedError { public var errorDescription: String? { switch self { case .failedToGetDataFromResponse: - return RuuviLocalization.CoreError.failedToGetDataFromResponse + RuuviLocalization.CoreError.failedToGetDataFromResponse case .failedToGetCurrentLocation: - return RuuviLocalization.CoreError.failedToGetCurrentLocation + RuuviLocalization.CoreError.failedToGetCurrentLocation case .failedToGetPngRepresentation: - return RuuviLocalization.CoreError.failedToGetPngRepresentation + RuuviLocalization.CoreError.failedToGetPngRepresentation case .failedToGetDocumentsDirectory: - return RuuviLocalization.CoreError.failedToGetDocumentsDirectory + RuuviLocalization.CoreError.failedToGetDocumentsDirectory case .locationPermissionDenied: - return RuuviLocalization.CoreError.locationPermissionDenied + RuuviLocalization.CoreError.locationPermissionDenied case .locationPermissionNotDetermined: - return RuuviLocalization.CoreError.locationPermissionNotDetermined + RuuviLocalization.CoreError.locationPermissionNotDetermined case .objectNotFound: - return RuuviLocalization.CoreError.objectNotFound + RuuviLocalization.CoreError.objectNotFound case .objectInvalidated: - return RuuviLocalization.CoreError.objectInvalidated + RuuviLocalization.CoreError.objectInvalidated case .unableToSendEmail: - return RuuviLocalization.CoreError.unableToSendEmail + RuuviLocalization.CoreError.unableToSendEmail } } } @@ -126,11 +126,11 @@ extension ExpectedError: LocalizedError { public var errorDescription: String? { switch self { case .missingOpenWeatherMapAPIKey: - return RuuviLocalization.ExpectedError.missingOpenWeatherMapAPIKey + RuuviLocalization.ExpectedError.missingOpenWeatherMapAPIKey case .isAlreadySyncingLogsWithThisTag: - return RuuviLocalization.ExpectedError.isAlreadySyncingLogsWithThisTag + RuuviLocalization.ExpectedError.isAlreadySyncingLogsWithThisTag case .failedToDeleteTag: - return RuuviLocalization.ExpectedError.failedToDeleteTag + RuuviLocalization.ExpectedError.failedToDeleteTag } } } @@ -151,23 +151,23 @@ extension UnexpectedError: LocalizedError { public var errorDescription: String? { switch self { case .callbackErrorAndResultAreNil: - return RuuviLocalization.UnexpectedError.callbackErrorAndResultAreNil + RuuviLocalization.UnexpectedError.callbackErrorAndResultAreNil case .callerDeinitedDuringOperation: - return RuuviLocalization.UnexpectedError.callerDeinitedDuringOperation + RuuviLocalization.UnexpectedError.callerDeinitedDuringOperation case .failedToReverseGeocodeCoordinate: - return RuuviLocalization.UnexpectedError.failedToReverseGeocodeCoordinate + RuuviLocalization.UnexpectedError.failedToReverseGeocodeCoordinate case .failedToFindRuuviTag: - return RuuviLocalization.UnexpectedError.failedToFindRuuviTag + RuuviLocalization.UnexpectedError.failedToFindRuuviTag case .failedToFindLogsForTheTag: - return RuuviLocalization.UnexpectedError.failedToFindLogsForTheTag + RuuviLocalization.UnexpectedError.failedToFindLogsForTheTag case .viewModelUUIDIsNil: - return RuuviLocalization.UnexpectedError.viewModelUUIDIsNil + RuuviLocalization.UnexpectedError.viewModelUUIDIsNil case .attemptToReadDataFromRealmWithoutLUID: - return RuuviLocalization.UnexpectedError.attemptToReadDataFromRealmWithoutLUID + RuuviLocalization.UnexpectedError.attemptToReadDataFromRealmWithoutLUID case .failedToFindOrGenerateBackgroundImage: - return RuuviLocalization.UnexpectedError.failedToFindOrGenerateBackgroundImage + RuuviLocalization.UnexpectedError.failedToFindOrGenerateBackgroundImage case .bothLuidAndMacAreNil: - return RuuviLocalization.UnexpectedError.bothLuidAndMacAreNil + RuuviLocalization.UnexpectedError.bothLuidAndMacAreNil } } } diff --git a/station/Extensions/Errors/RuuviCloudApiError+LocalizedError.swift b/station/Extensions/Errors/RuuviCloudApiError+LocalizedError.swift index 272b57389..4a08aa700 100644 --- a/station/Extensions/Errors/RuuviCloudApiError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviCloudApiError+LocalizedError.swift @@ -6,21 +6,21 @@ extension RuuviCloudApiError: LocalizedError { public var errorDescription: String? { switch self { case .connection: - return RuuviLocalization.internetConnectionProblem + RuuviLocalization.internetConnectionProblem case .emptyResponse: - return RuuviLocalization.RuuviCloudApiError.emptyResponse + RuuviLocalization.RuuviCloudApiError.emptyResponse case .failedToGetDataFromResponse: - return RuuviLocalization.RuuviCloudApiError.failedToGetDataFromResponse + RuuviLocalization.RuuviCloudApiError.failedToGetDataFromResponse case .unexpectedHTTPStatusCode: - return RuuviLocalization.RuuviCloudApiError.unexpectedHTTPStatusCode - case .api(let code): - return code.localizedDescription - case .networking(let error): - return error.localizedDescription - case .parsing(let error): - return error.localizedDescription + RuuviLocalization.RuuviCloudApiError.unexpectedHTTPStatusCode + case let .api(code): + code.localizedDescription + case let .networking(error): + error.localizedDescription + case let .parsing(error): + error.localizedDescription case .unauthorized: - return nil + nil } } } @@ -29,73 +29,73 @@ private extension RuuviCloudApiErrorCode { var localizedDescription: String { switch self { case .erForbidden: - return RuuviLocalization.UserApiError.erForbidden + RuuviLocalization.UserApiError.erForbidden case .erUnauthorized: - return RuuviLocalization.UserApiError.erUnauthorized + RuuviLocalization.UserApiError.erUnauthorized case .erInternal: - return RuuviLocalization.UserApiError.erInternal + RuuviLocalization.UserApiError.erInternal case .erInvalidFormat: - return RuuviLocalization.UserApiError.erInvalidFormat + RuuviLocalization.UserApiError.erInvalidFormat case .erUserNotFound: - return RuuviLocalization.UserApiError.erUserNotFound + RuuviLocalization.UserApiError.erUserNotFound case .erSensorNotFound: - return RuuviLocalization.UserApiError.erSensorNotFound + RuuviLocalization.UserApiError.erSensorNotFound case .erTokenExpired: - return RuuviLocalization.UserApiError.erTokenExpired + RuuviLocalization.UserApiError.erTokenExpired case .erThrottled: - return RuuviLocalization.UserApiError.erThrottled + RuuviLocalization.UserApiError.erThrottled case .erGatewayNotFound: - return RuuviLocalization.UserApiError.erGatewayNotFound + RuuviLocalization.UserApiError.erGatewayNotFound case .erGatewayAlreadyWhitelisted: - return RuuviLocalization.UserApiError.erGatewayAlreadyWhitelisted + RuuviLocalization.UserApiError.erGatewayAlreadyWhitelisted case .erGatewayStatusReportFailed: - return RuuviLocalization.UserApiError.erGatewayStatusReportFailed + RuuviLocalization.UserApiError.erGatewayStatusReportFailed case .erConflict: - return RuuviLocalization.UserApiError.erConflict + RuuviLocalization.UserApiError.erConflict case .erSubscriptionNotFound: - return RuuviLocalization.UserApiError.erSubscriptionNotFound + RuuviLocalization.UserApiError.erSubscriptionNotFound case .erShareCountReached: - return RuuviLocalization.UserApiError.erShareCountReached + RuuviLocalization.UserApiError.erShareCountReached case .erClaimCountReached: - return RuuviLocalization.UserApiError.erClaimCountReached + RuuviLocalization.UserApiError.erClaimCountReached case .erSensorShareCountReached: - return RuuviLocalization.UserApiError.erSensorShareCountReached + RuuviLocalization.UserApiError.erSensorShareCountReached case .erNoDataToShare: - return RuuviLocalization.UserApiError.erNoDataToShare + RuuviLocalization.UserApiError.erNoDataToShare case .erSensorAlreadyShared: - return RuuviLocalization.UserApiError.erSensorAlreadyShared + RuuviLocalization.UserApiError.erSensorAlreadyShared case .erSensorAlreadyClaimed: - return RuuviLocalization.UserApiError.erSensorAlreadyClaimed("") + RuuviLocalization.UserApiError.erSensorAlreadyClaimed("") case .erSensorAlreadyRegistered: - return RuuviLocalization.UserApiError.erSensorAlreadyRegistered + RuuviLocalization.UserApiError.erSensorAlreadyRegistered case .erUnableToSendEmail: - return RuuviLocalization.UserApiError.erUnableToSendEmail + RuuviLocalization.UserApiError.erUnableToSendEmail case .erSubscriptionCodeExists: - return RuuviLocalization.UserApiError.erSubscriptionCodeExists + RuuviLocalization.UserApiError.erSubscriptionCodeExists case .erSubscriptionCodeUsed: - return RuuviLocalization.UserApiError.erSubscriptionCodeUsed + RuuviLocalization.UserApiError.erSubscriptionCodeUsed case .erMissingArgument: - return RuuviLocalization.UserApiError.erMissingArgument + RuuviLocalization.UserApiError.erMissingArgument case .erInvalidDensityMode: - return RuuviLocalization.UserApiError.erInvalidDensityMode + RuuviLocalization.UserApiError.erInvalidDensityMode case .erInvalidSortMode: - return RuuviLocalization.UserApiError.erInvalidSortMode + RuuviLocalization.UserApiError.erInvalidSortMode case .erInvalidTimeRange: - return RuuviLocalization.UserApiError.erInvalidTimeRange + RuuviLocalization.UserApiError.erInvalidTimeRange case .erOldEntry: - return RuuviLocalization.UserApiError.erOldEntry + RuuviLocalization.UserApiError.erOldEntry case .erInvalidEmailAddress: - return RuuviLocalization.UserApiError.erInvalidEmailAddress + RuuviLocalization.UserApiError.erInvalidEmailAddress case .erInvalidMacAddress: - return RuuviLocalization.UserApiError.erInvalidMacAddress + RuuviLocalization.UserApiError.erInvalidMacAddress case .erInvalidEnumValue: - return RuuviLocalization.UserApiError.erInvalidEnumValue + RuuviLocalization.UserApiError.erInvalidEnumValue case .erSubDataStorageError: - return RuuviLocalization.UserApiError.erSubDataStorageError + RuuviLocalization.UserApiError.erSubDataStorageError case .erSubNoUser: - return RuuviLocalization.UserApiError.erSubNoUser + RuuviLocalization.UserApiError.erSubNoUser case .ok: - return RuuviLocalization.UserApiError.ok + RuuviLocalization.UserApiError.ok } } } diff --git a/station/Extensions/Errors/RuuviCloudError+LocalizedError.swift b/station/Extensions/Errors/RuuviCloudError+LocalizedError.swift index 3a56ba119..41461e590 100644 --- a/station/Extensions/Errors/RuuviCloudError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviCloudError+LocalizedError.swift @@ -1,14 +1,14 @@ -import RuuviCloud import Foundation +import RuuviCloud import RuuviLocalization extension RuuviCloudError: LocalizedError { public var errorDescription: String? { switch self { - case .api(let error): - return error.errorDescription + case let .api(error): + error.errorDescription case .notAuthorized: - return RuuviLocalization.RuuviCloudError.notAuthorized + RuuviLocalization.RuuviCloudError.notAuthorized } } } diff --git a/station/Extensions/Errors/RuuviCoreError+LocalizedError.swift b/station/Extensions/Errors/RuuviCoreError+LocalizedError.swift index badd8412d..321031ee9 100644 --- a/station/Extensions/Errors/RuuviCoreError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviCoreError+LocalizedError.swift @@ -1,16 +1,16 @@ -import RuuviLocalization import Foundation import RuuviCore +import RuuviLocalization extension RuuviCoreError: LocalizedError { public var errorDescription: String? { switch self { case .locationPermissionDenied: - return RuuviLocalization.CoreError.locationPermissionDenied + RuuviLocalization.CoreError.locationPermissionDenied case .locationPermissionNotDetermined: - return RuuviLocalization.CoreError.locationPermissionNotDetermined + RuuviLocalization.CoreError.locationPermissionNotDetermined case .failedToGetCurrentLocation: - return RuuviLocalization.CoreError.failedToGetCurrentLocation + RuuviLocalization.CoreError.failedToGetCurrentLocation } } } diff --git a/station/Extensions/Errors/RuuviDFUError+LocalizedError.swift b/station/Extensions/Errors/RuuviDFUError+LocalizedError.swift index 2284a39e9..71dab2190 100644 --- a/station/Extensions/Errors/RuuviDFUError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviDFUError+LocalizedError.swift @@ -1,9 +1,9 @@ -import RuuviLocalization import Foundation import RuuviDFU +import RuuviLocalization extension RuuviDfuError: LocalizedError { public var errorDescription: String? { - return description + description } } diff --git a/station/Extensions/Errors/RuuviDaemonError+LocalizedError.swift b/station/Extensions/Errors/RuuviDaemonError+LocalizedError.swift index 1c986e28e..5b5731b6f 100644 --- a/station/Extensions/Errors/RuuviDaemonError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviDaemonError+LocalizedError.swift @@ -1,24 +1,24 @@ +import BTKit import Foundation -import RuuviStorage -import RuuviReactor -import RuuviPool -import RuuviPersistence import RuuviDaemon -import BTKit +import RuuviPersistence +import RuuviPool +import RuuviReactor +import RuuviStorage extension RuuviDaemonError: LocalizedError { public var errorDescription: String? { switch self { - case .btkit(let error): - return error.errorDescription - case .ruuviPersistence(let error): - return error.errorDescription - case .ruuviPool(let error): - return error.errorDescription - case .ruuviReactor(let error): - return error.errorDescription - case .ruuviStorage(let error): - return error.errorDescription + case let .btkit(error): + error.errorDescription + case let .ruuviPersistence(error): + error.errorDescription + case let .ruuviPool(error): + error.errorDescription + case let .ruuviReactor(error): + error.errorDescription + case let .ruuviStorage(error): + error.errorDescription } } } diff --git a/station/Extensions/Errors/RuuviLocalError+LocalizedError.swift b/station/Extensions/Errors/RuuviLocalError+LocalizedError.swift index e974c89ba..1ac30628f 100644 --- a/station/Extensions/Errors/RuuviLocalError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviLocalError+LocalizedError.swift @@ -1,16 +1,16 @@ -import RuuviLocalization import Foundation import RuuviLocal +import RuuviLocalization extension RuuviLocalError: LocalizedError { public var errorDescription: String? { switch self { - case .disk(let error): - return error.localizedDescription + case let .disk(error): + error.localizedDescription case .failedToGetJpegRepresentation: - return RuuviLocalization.RuuviLocalError.failedToGetJpegRepresentation + RuuviLocalization.RuuviLocalError.failedToGetJpegRepresentation case .failedToGetDocumentsDirectory: - return RuuviLocalization.RuuviLocalError.failedToGetDocumentsDirectory + RuuviLocalization.RuuviLocalError.failedToGetDocumentsDirectory } } } diff --git a/station/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift b/station/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift index d6d0002f2..52fcfc5ae 100644 --- a/station/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift @@ -1,16 +1,16 @@ -import RuuviLocalization import Foundation +import RuuviLocalization import RuuviPersistence extension RuuviPersistenceError: LocalizedError { public var errorDescription: String? { switch self { - case .grdb(let error): - return error.localizedDescription - case .realm(let error): - return error.localizedDescription + case let .grdb(error): + error.localizedDescription + case let .realm(error): + error.localizedDescription case .failedToFindRuuviTag: - return RuuviLocalization.RuuviPersistenceError.failedToFindRuuviTag + RuuviLocalization.RuuviPersistenceError.failedToFindRuuviTag } } } diff --git a/station/Extensions/Errors/RuuviPoolError+LocalizedError.swift b/station/Extensions/Errors/RuuviPoolError+LocalizedError.swift index 2e83f821d..22ed541ba 100644 --- a/station/Extensions/Errors/RuuviPoolError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviPoolError+LocalizedError.swift @@ -4,8 +4,8 @@ import RuuviPool extension RuuviPoolError: LocalizedError { public var errorDescription: String? { switch self { - case .ruuviPersistence(let error): - return error.errorDescription + case let .ruuviPersistence(error): + error.errorDescription } } } diff --git a/station/Extensions/Errors/RuuviReactorError+LocalizedError.swift b/station/Extensions/Errors/RuuviReactorError+LocalizedError.swift index 1cd76a675..a35a549d3 100644 --- a/station/Extensions/Errors/RuuviReactorError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviReactorError+LocalizedError.swift @@ -4,8 +4,8 @@ import RuuviReactor extension RuuviReactorError: LocalizedError { public var errorDescription: String? { switch self { - case .ruuviPersistence(let error): - return error.errorDescription + case let .ruuviPersistence(error): + error.errorDescription } } } diff --git a/station/Extensions/Errors/RuuviRepositoryError+LocalizedError.swift b/station/Extensions/Errors/RuuviRepositoryError+LocalizedError.swift index d95a33282..57c6f7077 100644 --- a/station/Extensions/Errors/RuuviRepositoryError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviRepositoryError+LocalizedError.swift @@ -1,13 +1,13 @@ -import RuuviRepository import Foundation +import RuuviRepository extension RuuviRepositoryError: LocalizedError { public var errorDescription: String? { switch self { - case .ruuviStorage(let error): - return error.errorDescription - case .ruuviPool(let error): - return error.errorDescription + case let .ruuviStorage(error): + error.errorDescription + case let .ruuviPool(error): + error.errorDescription } } } diff --git a/station/Extensions/Errors/RuuviServiceError+LocalizedError.swift b/station/Extensions/Errors/RuuviServiceError+LocalizedError.swift index 0077f87f9..28785046e 100644 --- a/station/Extensions/Errors/RuuviServiceError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviServiceError+LocalizedError.swift @@ -1,40 +1,40 @@ -import RuuviLocalization import Foundation +import RuuviLocalization import RuuviService extension RuuviServiceError: LocalizedError { public var errorDescription: String? { switch self { - case .btkit(let error): - return error.localizedDescription - case .writeToDisk(let error): - return error.localizedDescription - case .ruuviRepository(let error): - return error.errorDescription - case .ruuviStorage(let error): - return error.errorDescription - case .ruuviPool(let error): - return error.errorDescription - case .ruuviLocal(let error): - return error.errorDescription - case .ruuviCloud(let error): - return error.errorDescription - case .networking(let error): - return error.localizedDescription + case let .btkit(error): + error.localizedDescription + case let .writeToDisk(error): + error.localizedDescription + case let .ruuviRepository(error): + error.errorDescription + case let .ruuviStorage(error): + error.errorDescription + case let .ruuviPool(error): + error.errorDescription + case let .ruuviLocal(error): + error.errorDescription + case let .ruuviCloud(error): + error.errorDescription + case let .networking(error): + error.localizedDescription case .pictureUrlIsNil: - return RuuviLocalization.RuuviServiceError.pictureUrlIsNil + RuuviLocalization.RuuviServiceError.pictureUrlIsNil case .macIdIsNil: - return RuuviLocalization.RuuviServiceError.macIdIsNil + RuuviLocalization.RuuviServiceError.macIdIsNil case .bothLuidAndMacAreNil: - return RuuviLocalization.RuuviServiceError.bothLuidAndMacAreNil + RuuviLocalization.RuuviServiceError.bothLuidAndMacAreNil case .failedToParseNetworkResponse: - return RuuviLocalization.RuuviServiceError.failedToParseNetworkResponse + RuuviLocalization.RuuviServiceError.failedToParseNetworkResponse case .failedToFindOrGenerateBackgroundImage: - return RuuviLocalization.RuuviServiceError.failedToFindOrGenerateBackgroundImage + RuuviLocalization.RuuviServiceError.failedToFindOrGenerateBackgroundImage case .failedToGetJpegRepresentation: - return RuuviLocalization.RuuviServiceError.failedToGetJpegRepresentation + RuuviLocalization.RuuviServiceError.failedToGetJpegRepresentation case .isAlreadySyncingLogsWithThisTag: - return RuuviLocalization.ExpectedError.isAlreadySyncingLogsWithThisTag + RuuviLocalization.ExpectedError.isAlreadySyncingLogsWithThisTag } } } diff --git a/station/Extensions/Errors/RuuviStorageError+LocalizedError.swift b/station/Extensions/Errors/RuuviStorageError+LocalizedError.swift index 45d602954..359120dc6 100644 --- a/station/Extensions/Errors/RuuviStorageError+LocalizedError.swift +++ b/station/Extensions/Errors/RuuviStorageError+LocalizedError.swift @@ -4,8 +4,8 @@ import RuuviStorage extension RuuviStorageError: LocalizedError { public var errorDescription: String? { switch self { - case .ruuviPersistence(let error): - return error.errorDescription + case let .ruuviPersistence(error): + error.errorDescription } } } diff --git a/station/Extensions/FileManager+Date.swift b/station/Extensions/FileManager+Date.swift index faf4fd7e4..e52fbdbda 100644 --- a/station/Extensions/FileManager+Date.swift +++ b/station/Extensions/FileManager+Date.swift @@ -6,12 +6,12 @@ extension FileManager { let urlToDocumentsFolder = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last, let installDateAny = try? FileManager.default.attributesOfItem(atPath: - urlToDocumentsFolder.path)[.creationDate], + urlToDocumentsFolder.path)[.creationDate], let installDate = installDateAny as? Date { - return installDate + installDate } else { - return Date() + Date() } } } diff --git a/station/Extensions/Humidity+Offset.swift b/station/Extensions/Humidity+Offset.swift index 20412fab4..d1056a45e 100644 --- a/station/Extensions/Humidity+Offset.swift +++ b/station/Extensions/Humidity+Offset.swift @@ -3,11 +3,12 @@ import RuuviOntology extension Humidity { func offseted(by offset: Double?, temperature: Temperature?) -> Humidity? { - guard let offset = offset, - let temperature = temperature else { + guard let offset, + let temperature + else { return nil } - let relativeHumidity = self.converted(to: .relative(temperature: temperature)).value - return Humidity.init(relative: relativeHumidity + offset, temperature: temperature) + let relativeHumidity = converted(to: .relative(temperature: temperature)).value + return Humidity(relative: relativeHumidity + offset, temperature: temperature) } } diff --git a/station/Extensions/HumidityUnit+Localization.swift b/station/Extensions/HumidityUnit+Localization.swift index 0119e50da..46bb3c816 100644 --- a/station/Extensions/HumidityUnit+Localization.swift +++ b/station/Extensions/HumidityUnit+Localization.swift @@ -1,38 +1,38 @@ import Foundation -import RuuviOntology import RuuviLocalization +import RuuviOntology extension HumidityUnit: SelectionItemProtocol { var title: (String) -> String { switch self { case .percent: - return { _ in RuuviLocalization.HumidityUnit.Percent.title } + { _ in RuuviLocalization.HumidityUnit.Percent.title } case .gm3: - return { _ in RuuviLocalization.HumidityUnit.Gm3.title } + { _ in RuuviLocalization.HumidityUnit.Gm3.title } case .dew: - return RuuviLocalization.HumidityUnit.Dew.title + RuuviLocalization.HumidityUnit.Dew.title } } var symbol: String { switch self { case .percent: - return "%" + "%" case .gm3: - return RuuviLocalization.gm³ + RuuviLocalization.gm³ case .dew: - return "°" + "°" } } var alertRange: Range { switch self { case .gm3: - return .init(uncheckedBounds: (lower: 0, upper: 40)) + .init(uncheckedBounds: (lower: 0, upper: 40)) case .percent: - return .init(uncheckedBounds: (lower: 0, upper: 100)) + .init(uncheckedBounds: (lower: 0, upper: 100)) case .dew: - return .init(uncheckedBounds: (lower: 0, upper: 100)) + .init(uncheckedBounds: (lower: 0, upper: 100)) } } } diff --git a/station/Extensions/Int+Extension.swift b/station/Extensions/Int+Extension.swift index 93edbf702..4269f8616 100644 --- a/station/Extensions/Int+Extension.swift +++ b/station/Extensions/Int+Extension.swift @@ -3,16 +3,16 @@ import RuuviLocalization extension Int { var stringValue: String { - return "\(self)" + "\(self)" } } -extension Optional where Wrapped == Int { +extension Int? { var stringValue: String { - if let self = self { - return "\(self)" + if let self { + "\(self)" } else { - return RuuviLocalization.na + RuuviLocalization.na } } } diff --git a/station/Extensions/Language+Localization.swift b/station/Extensions/Language+Localization.swift index cfe7e70d7..6ad539751 100644 --- a/station/Extensions/Language+Localization.swift +++ b/station/Extensions/Language+Localization.swift @@ -1,23 +1,23 @@ import Foundation import Humidity -import RuuviOntology import RuuviLocalization +import RuuviOntology extension Language { var name: String { switch self { case .english: - return RuuviLocalization.Language.english + RuuviLocalization.Language.english case .russian: - return RuuviLocalization.Language.russian + RuuviLocalization.Language.russian case .finnish: - return RuuviLocalization.Language.finnish + RuuviLocalization.Language.finnish case .french: - return RuuviLocalization.Language.french + RuuviLocalization.Language.french case .swedish: - return RuuviLocalization.Language.swedish + RuuviLocalization.Language.swedish case .german: - return RuuviLocalization.Language.german + RuuviLocalization.Language.german } } } diff --git a/station/Extensions/MeasurementAccuracyType+Extension.swift b/station/Extensions/MeasurementAccuracyType+Extension.swift index 4191714a0..ff9b4aa37 100644 --- a/station/Extensions/MeasurementAccuracyType+Extension.swift +++ b/station/Extensions/MeasurementAccuracyType+Extension.swift @@ -5,11 +5,11 @@ extension MeasurementAccuracyType: SelectionItemProtocol { public var title: (String) -> String { switch self { case .zero: - return { _ in "1" } + { _ in "1" } case .one: - return { _ in "0.1" } + { _ in "0.1" } case .two: - return { _ in "0.01" } + { _ in "0.01" } } } } diff --git a/station/Extensions/MeasurementType.swift b/station/Extensions/MeasurementType.swift index f2221152c..87e0f0559 100644 --- a/station/Extensions/MeasurementType.swift +++ b/station/Extensions/MeasurementType.swift @@ -13,10 +13,10 @@ enum MeasurementType: String { extension MeasurementType { static var chartsCases: [MeasurementType] { - return [ + [ .temperature, .humidity, - .pressure + .pressure, ] } } diff --git a/station/Extensions/NSObjectProtocol+Invalidation.swift b/station/Extensions/NSObjectProtocol+Invalidation.swift index 9bf8ea6ff..837243df7 100644 --- a/station/Extensions/NSObjectProtocol+Invalidation.swift +++ b/station/Extensions/NSObjectProtocol+Invalidation.swift @@ -1,7 +1,6 @@ import Foundation extension NSObjectProtocol { - func invalidate() { // swiftlint:disable:next notification_center_detachment NotificationCenter diff --git a/station/Extensions/RuuviAlertSound+Extension.swift b/station/Extensions/RuuviAlertSound+Extension.swift index a7640981b..db7b958b0 100644 --- a/station/Extensions/RuuviAlertSound+Extension.swift +++ b/station/Extensions/RuuviAlertSound+Extension.swift @@ -1,14 +1,14 @@ import Foundation -import RuuviOntology import RuuviLocalization +import RuuviOntology extension RuuviAlertSound: SelectionItemProtocol { var title: (String) -> String { switch self { case .systemDefault: - return { _ in RuuviLocalization.settingsAlertSoundDefault } + { _ in RuuviLocalization.settingsAlertSoundDefault } case .ruuviSpeak: - return { _ in RuuviLocalization.settingsAlertSoundRuuviSpeak } + { _ in RuuviLocalization.settingsAlertSoundRuuviSpeak } } } } diff --git a/station/Extensions/RuuviTheme+Extension.swift b/station/Extensions/RuuviTheme+Extension.swift index 761bf319c..6d6aafd63 100644 --- a/station/Extensions/RuuviTheme+Extension.swift +++ b/station/Extensions/RuuviTheme+Extension.swift @@ -1,16 +1,16 @@ -import RuuviLocalization import Foundation +import RuuviLocalization import RuuviOntology extension RuuviTheme: SelectionItemProtocol { var title: (String) -> String { switch self { case .light: - return { _ in RuuviLocalization.lightTheme } + { _ in RuuviLocalization.lightTheme } case .dark: - return { _ in RuuviLocalization.darkTheme } + { _ in RuuviLocalization.darkTheme } case .system: - return { _ in RuuviLocalization.followSystemTheme } + { _ in RuuviLocalization.followSystemTheme } } } } diff --git a/station/Extensions/String+Characters.swift b/station/Extensions/String+Characters.swift index c63267abb..5bfe7f7eb 100644 --- a/station/Extensions/String+Characters.swift +++ b/station/Extensions/String+Characters.swift @@ -4,12 +4,12 @@ extension String { static let nbsp = "\u{00a0}" } -extension Optional where Wrapped == String { +extension String? { func hasText() -> Bool { - if let self = self, !self.isEmpty { - return true + if let self, !self.isEmpty { + true } else { - return false + false } } } diff --git a/station/Extensions/String+Replace.swift b/station/Extensions/String+Replace.swift index dcab1c618..ebfea7a40 100644 --- a/station/Extensions/String+Replace.swift +++ b/station/Extensions/String+Replace.swift @@ -2,12 +2,12 @@ import Foundation extension String { func replace(with text: String, in range: NSRange) -> String? { - guard range.location + range.length <= self.count else { return nil } + guard range.location + range.length <= count else { return nil } return (self as NSString).replacingCharacters(in: range, with: text) } func replace(_ text: String, with replacementText: String) -> String { - return replacingOccurrences(of: text, with: replacementText) + replacingOccurrences(of: text, with: replacementText) } } @@ -15,7 +15,7 @@ extension String { static let numberFormatter = NumberFormatter() var doubleValue: Double { String.numberFormatter.decimalSeparator = "." - if let result = String.numberFormatter.number(from: self) { + if let result = String.numberFormatter.number(from: self) { return result.doubleValue } else { String.numberFormatter.decimalSeparator = "," @@ -29,23 +29,24 @@ extension String { extension String { var intValue: Int? { - return Int(self) + Int(self) } } extension String { func replacingFirstOccurrence(of target: String, with replacement: String) -> String { - guard let range = self.range(of: target) else { return self } - return self.replacingCharacters(in: range, with: replacement) + guard let range = range(of: target) else { return self } + return replacingCharacters(in: range, with: replacement) } func replacingLastOccurrence(of target: String, with replacement: String) -> String { let options: String.CompareOptions = [.backwards] - if let range = self.range(of: target, - options: options, - range: nil, - locale: nil) { - return self.replacingCharacters(in: range, with: replacement) + if let range = range(of: target, + options: options, + range: nil, + locale: nil) + { + return replacingCharacters(in: range, with: replacement) } return self } diff --git a/station/Extensions/Structs/AppStoreReviewHelper.swift b/station/Extensions/Structs/AppStoreReviewHelper.swift index 87495ae2b..d960266b1 100644 --- a/station/Extensions/Structs/AppStoreReviewHelper.swift +++ b/station/Extensions/Structs/AppStoreReviewHelper.swift @@ -1,13 +1,13 @@ import Foundation -import StoreKit import RuuviLocal +import StoreKit -struct AppStoreReviewHelper { +enum AppStoreReviewHelper { static func askForReview(settings: RuuviLocalSettings) { switch settings.appOpenedCount { case settings.appOpenedInitialCountToAskReview: requestReview() - case _ where settings.appOpenedCount%settings.appOpenedCountDivisibleToAskReview == 0: + case _ where settings.appOpenedCount % settings.appOpenedCountDivisibleToAskReview == 0: requestReview() default: break diff --git a/station/Extensions/Structs/AppUtility.swift b/station/Extensions/Structs/AppUtility.swift index afa08c4c6..8e3ee226b 100644 --- a/station/Extensions/Structs/AppUtility.swift +++ b/station/Extensions/Structs/AppUtility.swift @@ -1,7 +1,6 @@ import UIKit -struct AppUtility { - +enum AppUtility { static func lockOrientation(_ orientation: UIInterfaceOrientationMask) { if let delegate = UIApplication.shared.delegate as? AppDelegate { delegate.orientationLock = orientation @@ -10,8 +9,9 @@ struct AppUtility { /// OPTIONAL Added method to adjust lock and rotate to the desired orientation static func lockOrientation(_ orientation: UIInterfaceOrientationMask, - andRotateTo rotateOrientation: UIInterfaceOrientation) { - self.lockOrientation(orientation) + andRotateTo rotateOrientation: UIInterfaceOrientation) + { + lockOrientation(orientation) UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation") UINavigationController.attemptRotationToDeviceOrientation() } diff --git a/station/Extensions/Structs/ExportHeadersProvider.swift b/station/Extensions/Structs/ExportHeadersProvider.swift index 8ac996f05..0af7acf2b 100644 --- a/station/Extensions/Structs/ExportHeadersProvider.swift +++ b/station/Extensions/Structs/ExportHeadersProvider.swift @@ -1,5 +1,5 @@ -import RuuviLocalization import Foundation +import RuuviLocalization import RuuviService struct ExportHeadersProvider: RuuviServiceExportHeaders { @@ -13,15 +13,15 @@ struct ExportHeadersProvider: RuuviServiceExportHeaders { units.humidityUnit == .dew ? humidityFormat(units.temperatureUnit.symbol) : humidityFormat(units.humidityUnit.symbol), - pressureFormat(units.pressureUnit.symbol), + pressureFormat(units.pressureUnit.symbol), "RSSI" + " (\(RuuviLocalization.dBm))", - RuuviLocalization.ExportService.accelerationX + " (\(RuuviLocalization.g))", - RuuviLocalization.ExportService.accelerationY + " (\(RuuviLocalization.g))", - RuuviLocalization.ExportService.accelerationZ + " (\(RuuviLocalization.g))", - RuuviLocalization.ExportService.voltage, - RuuviLocalization.ExportService.movementCounter + " (\(RuuviLocalization.Cards.Movements.title))", - RuuviLocalization.ExportService.measurementSequenceNumber, - RuuviLocalization.ExportService.txPower + " (\(RuuviLocalization.dBm))" + RuuviLocalization.ExportService.accelerationX + " (\(RuuviLocalization.g))", + RuuviLocalization.ExportService.accelerationY + " (\(RuuviLocalization.g))", + RuuviLocalization.ExportService.accelerationZ + " (\(RuuviLocalization.g))", + RuuviLocalization.ExportService.voltage, + RuuviLocalization.ExportService.movementCounter + " (\(RuuviLocalization.Cards.Movements.title))", + RuuviLocalization.ExportService.measurementSequenceNumber, + RuuviLocalization.ExportService.txPower + " (\(RuuviLocalization.dBm))", ] } } diff --git a/station/Extensions/Structs/GlobalHelpers.swift b/station/Extensions/Structs/GlobalHelpers.swift index 5de55b8b5..2bed572a4 100644 --- a/station/Extensions/Structs/GlobalHelpers.swift +++ b/station/Extensions/Structs/GlobalHelpers.swift @@ -3,7 +3,7 @@ import UIKit struct GlobalHelpers { static func isDeviceTablet() -> Bool { - return UIDevice.current.userInterfaceIdiom == .pad + UIDevice.current.userInterfaceIdiom == .pad } static func isDeviceLandscape() -> Bool { @@ -12,20 +12,20 @@ struct GlobalHelpers { } static func getBool(from value: Bool?) -> Bool { - if let value = value { - return value + if let value { + value } else { - return false + false } } static func ruuviTagDefaultName(from macId: String?, luid: String?) -> String { // identifier if let mac = macId { - return RuuviLocalization.DiscoverTable.RuuviDevice.prefix + RuuviLocalization.DiscoverTable.RuuviDevice.prefix + " " + mac.replacingOccurrences(of: ":", with: "").suffix(4) } else { - return RuuviLocalization.DiscoverTable.RuuviDevice.prefix + RuuviLocalization.DiscoverTable.RuuviDevice.prefix + " " + (luid?.prefix(4) ?? "") } } @@ -36,5 +36,4 @@ struct GlobalHelpers { formatter.numberStyle = .decimal return formatter.string(from: NSNumber(value: double)) ?? "0" } - } diff --git a/station/Extensions/Structs/MeasurementAccuracyTitles.swift b/station/Extensions/Structs/MeasurementAccuracyTitles.swift index 922849938..f3919d2cf 100644 --- a/station/Extensions/Structs/MeasurementAccuracyTitles.swift +++ b/station/Extensions/Structs/MeasurementAccuracyTitles.swift @@ -1,10 +1,11 @@ import Foundation -import RuuviOntology import RuuviLocal +import RuuviOntology struct MeasurementAccuracyTitles { func formattedTitle(type: MeasurementAccuracyType, - settings: RuuviLocalSettings) -> String { + settings _: RuuviLocalSettings) -> String + { let formatter = NumberFormatter() formatter.locale = Locale.autoupdatingCurrent formatter.numberStyle = .decimal diff --git a/station/Extensions/Structs/RuuviNotifierTitlesImpl.swift b/station/Extensions/Structs/RuuviNotifierTitlesImpl.swift index de02947bc..817b0d7f4 100644 --- a/station/Extensions/Structs/RuuviNotifierTitlesImpl.swift +++ b/station/Extensions/Structs/RuuviNotifierTitlesImpl.swift @@ -1,5 +1,5 @@ -import RuuviLocalization import Foundation +import RuuviLocalization import RuuviNotifier struct RuuviNotifierTitlesImpl: RuuviNotifierTitles { diff --git a/station/Extensions/Structs/RuuviTagBatteryStatusProvider.swift b/station/Extensions/Structs/RuuviTagBatteryStatusProvider.swift index 5a76dd8df..5817cc256 100644 --- a/station/Extensions/Structs/RuuviTagBatteryStatusProvider.swift +++ b/station/Extensions/Structs/RuuviTagBatteryStatusProvider.swift @@ -3,18 +3,20 @@ import RuuviOntology struct RuuviTagBatteryStatusProvider { func batteryNeedsReplacement(temperature: Temperature?, - voltage: Voltage?) -> Bool { + voltage: Voltage?) -> Bool + { if let temperature = temperature?.value, - let voltage = voltage?.value { - if temperature < 0 && temperature >= -20 { - return voltage < 2.3 + let voltage = voltage?.value + { + if temperature < 0, temperature >= -20 { + voltage < 2.3 } else if temperature < -20 { - return voltage < 2 + voltage < 2 } else { - return voltage < 2.5 + voltage < 2.5 } } else { - return false + false } } } diff --git a/station/Extensions/TemperatureUnit+Localization.swift b/station/Extensions/TemperatureUnit+Localization.swift index 79a18d252..c476db890 100644 --- a/station/Extensions/TemperatureUnit+Localization.swift +++ b/station/Extensions/TemperatureUnit+Localization.swift @@ -1,16 +1,16 @@ import Foundation -import RuuviOntology import RuuviLocalization +import RuuviOntology extension TemperatureUnit: SelectionItemProtocol { var title: (String) -> String { switch self { case .celsius: - return { _ in RuuviLocalization.TemperatureUnit.Celsius.title } + { _ in RuuviLocalization.TemperatureUnit.Celsius.title } case .fahrenheit: - return { _ in RuuviLocalization.TemperatureUnit.Fahrenheit.title } + { _ in RuuviLocalization.TemperatureUnit.Fahrenheit.title } case .kelvin: - return { _ in RuuviLocalization.TemperatureUnit.Kelvin.title } + { _ in RuuviLocalization.TemperatureUnit.Kelvin.title } } } } @@ -19,13 +19,13 @@ extension UnitTemperature: SelectionItemProtocol { var title: (String) -> String { switch self { case .celsius: - return { _ in RuuviLocalization.TemperatureUnit.Celsius.title } + { _ in RuuviLocalization.TemperatureUnit.Celsius.title } case .fahrenheit: - return { _ in RuuviLocalization.TemperatureUnit.Fahrenheit.title } + { _ in RuuviLocalization.TemperatureUnit.Fahrenheit.title } case .kelvin: - return { _ in RuuviLocalization.TemperatureUnit.Kelvin.title } + { _ in RuuviLocalization.TemperatureUnit.Kelvin.title } default: - return { _ in RuuviLocalization.na } + { _ in RuuviLocalization.na } } } } @@ -33,8 +33,8 @@ extension UnitTemperature: SelectionItemProtocol { // defaults range of temperature extension TemperatureUnit { var alertRange: Range { - let lowerTemp = Temperature(value: -40, unit: .celsius).converted(to: self.unitTemperature).value - let upperTemp = Temperature(value: 85, unit: .celsius).converted(to: self.unitTemperature).value + let lowerTemp = Temperature(value: -40, unit: .celsius).converted(to: unitTemperature).value + let upperTemp = Temperature(value: 85, unit: .celsius).converted(to: unitTemperature).value return .init(uncheckedBounds: (lowerTemp, upperTemp)) } } diff --git a/station/Extensions/UIButton+Extension.swift b/station/Extensions/UIButton+Extension.swift index 0156370db..fde26ce82 100644 --- a/station/Extensions/UIButton+Extension.swift +++ b/station/Extensions/UIButton+Extension.swift @@ -2,8 +2,8 @@ import UIKit extension UIButton { func underline() { - guard let text = self.titleLabel?.text, - let titleColor = self.titleColor(for: .normal) else { return } + guard let text = titleLabel?.text, + let titleColor = titleColor(for: .normal) else { return } let attributedString = NSMutableAttributedString(string: text) attributedString.addAttribute(NSAttributedString.Key.underlineColor, value: titleColor, @@ -15,6 +15,6 @@ extension UIButton { attributedString.addAttribute(NSAttributedString.Key.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: NSRange(location: 0, length: text.count)) - self.setAttributedTitle(attributedString, for: .normal) + setAttributedTitle(attributedString, for: .normal) } } diff --git a/station/Extensions/UICollectionView+Extension.swift b/station/Extensions/UICollectionView+Extension.swift index 958af87a4..e5cb24dba 100644 --- a/station/Extensions/UICollectionView+Extension.swift +++ b/station/Extensions/UICollectionView+Extension.swift @@ -11,12 +11,12 @@ extension UICollectionView { } func scrollTo(index: Int, section: Int = 0, animated: Bool = false) { - guard self.numberOfSections > 0, - self.numberOfItems(inSection: section) > 0 else { return } + guard numberOfSections > 0, + numberOfItems(inSection: section) > 0 else { return } let indexPath = IndexPath(item: index, section: section) - self.scrollToItem(at: indexPath, - at: .centeredHorizontally, - animated: animated) + scrollToItem(at: indexPath, + at: .centeredHorizontally, + animated: animated) } } diff --git a/station/Extensions/UIColor+Extension.swift b/station/Extensions/UIColor+Extension.swift index 722cfdfef..16f3c54d0 100644 --- a/station/Extensions/UIColor+Extension.swift +++ b/station/Extensions/UIColor+Extension.swift @@ -1,11 +1,10 @@ import UIKit extension UIColor { - convenience init(hex: Int, alpha: CGFloat = 1.0) { - self.init(red: CGFloat((hex>>16)&0xFF)/255.0, - green: CGFloat((hex>>8)&0xFF)/255.0, - blue: CGFloat((hex)&0xFF)/255.0, + self.init(red: CGFloat((hex >> 16) & 0xFF) / 255.0, + green: CGFloat((hex >> 8) & 0xFF) / 255.0, + blue: CGFloat(hex & 0xFF) / 255.0, alpha: CGFloat(255 * alpha) / 255) } @@ -26,11 +25,10 @@ extension UIColor { blue: CGFloat(rgbValue & 0x0000FF) / 255.0, alpha: alpha) } - } extension UIColor { static func rgb(r: CGFloat, g: CGFloat, b: CGFloat) -> UIColor { - return UIColor(red: r/255, green: g/255, blue: b/255, alpha: 1) + UIColor(red: r / 255, green: g / 255, blue: b / 255, alpha: 1) } } diff --git a/station/Extensions/UIDevice+ReadableModel.swift b/station/Extensions/UIDevice+ReadableModel.swift index 33b78f1ce..e336e873e 100644 --- a/station/Extensions/UIDevice+ReadableModel.swift +++ b/station/Extensions/UIDevice+ReadableModel.swift @@ -25,9 +25,9 @@ extension UIDevice { extension UIDevice { static var isSimulator: Bool = { #if targetEnvironment(simulator) - return true + return true #else - return false + return false #endif }() } @@ -45,92 +45,92 @@ extension UIDevice { // swiftlint:disable line_length cyclomatic_complexity function_body_length func mapToDevice(identifier: String) -> String { #if os(iOS) - switch identifier { - case "iPod5,1": return "iPod touch (5th generation)" - case "iPod7,1": return "iPod touch (6th generation)" - case "iPod9,1": return "iPod touch (7th generation)" - case "iPhone3,1", "iPhone3,2", "iPhone3,3": return "iPhone 4" - case "iPhone4,1": return "iPhone 4s" - case "iPhone5,1", "iPhone5,2": return "iPhone 5" - case "iPhone5,3", "iPhone5,4": return "iPhone 5c" - case "iPhone6,1", "iPhone6,2": return "iPhone 5s" - case "iPhone7,2": return "iPhone 6" - case "iPhone7,1": return "iPhone 6 Plus" - case "iPhone8,1": return "iPhone 6s" - case "iPhone8,2": return "iPhone 6s Plus" - case "iPhone9,1", "iPhone9,3": return "iPhone 7" - case "iPhone9,2", "iPhone9,4": return "iPhone 7 Plus" - case "iPhone10,1", "iPhone10,4": return "iPhone 8" - case "iPhone10,2", "iPhone10,5": return "iPhone 8 Plus" - case "iPhone10,3", "iPhone10,6": return "iPhone X" - case "iPhone11,2": return "iPhone XS" - case "iPhone11,4", "iPhone11,6": return "iPhone XS Max" - case "iPhone11,8": return "iPhone XR" - case "iPhone12,1": return "iPhone 11" - case "iPhone12,3": return "iPhone 11 Pro" - case "iPhone12,5": return "iPhone 11 Pro Max" - case "iPhone13,1": return "iPhone 12 mini" - case "iPhone13,2": return "iPhone 12" - case "iPhone13,3": return "iPhone 12 Pro" - case "iPhone13,4": return "iPhone 12 Pro Max" - case "iPhone14,4": return "iPhone 13 mini" - case "iPhone14,5": return "iPhone 13" - case "iPhone14,2": return "iPhone 13 Pro" - case "iPhone14,3": return "iPhone 13 Pro Max" - case "iPhone14,7": return "iPhone 14" - case "iPhone14,8": return "iPhone 14 Plus" - case "iPhone15,2": return "iPhone 14 Pro" - case "iPhone15,3": return "iPhone 14 Pro Max" - case "iPhone8,4": return "iPhone SE" - case "iPhone12,8": return "iPhone SE (2nd generation)" - case "iPhone14,6": return "iPhone SE (3rd generation)" - case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4": return "iPad 2" - case "iPad3,1", "iPad3,2", "iPad3,3": return "iPad (3rd generation)" - case "iPad3,4", "iPad3,5", "iPad3,6": return "iPad (4th generation)" - case "iPad6,11", "iPad6,12": return "iPad (5th generation)" - case "iPad7,5", "iPad7,6": return "iPad (6th generation)" - case "iPad7,11", "iPad7,12": return "iPad (7th generation)" - case "iPad11,6", "iPad11,7": return "iPad (8th generation)" - case "iPad12,1", "iPad12,2": return "iPad (9th generation)" - case "iPad13,18", "iPad13,19": return "iPad (10th generation)" - case "iPad4,1", "iPad4,2", "iPad4,3": return "iPad Air" - case "iPad5,3", "iPad5,4": return "iPad Air 2" - case "iPad11,3", "iPad11,4": return "iPad Air (3rd generation)" - case "iPad13,1", "iPad13,2": return "iPad Air (4th generation)" - case "iPad13,16", "iPad13,17": return "iPad Air (5th generation)" - case "iPad2,5", "iPad2,6", "iPad2,7": return "iPad mini" - case "iPad4,4", "iPad4,5", "iPad4,6": return "iPad mini 2" - case "iPad4,7", "iPad4,8", "iPad4,9": return "iPad mini 3" - case "iPad5,1", "iPad5,2": return "iPad mini 4" - case "iPad11,1", "iPad11,2": return "iPad mini (5th generation)" - case "iPad14,1", "iPad14,2": return "iPad mini (6th generation)" - case "iPad6,3", "iPad6,4": return "iPad Pro (9.7-inch)" - case "iPad7,3", "iPad7,4": return "iPad Pro (10.5-inch)" - case "iPad8,1", "iPad8,2", "iPad8,3", "iPad8,4": return "iPad Pro (11-inch) (1st generation)" - case "iPad8,9", "iPad8,10": return "iPad Pro (11-inch) (2nd generation)" - case "iPad13,4", "iPad13,5", "iPad13,6", "iPad13,7": return "iPad Pro (11-inch) (3rd generation)" - case "iPad14,3", "iPad14,4": return "iPad Pro (11-inch) (4th generation)" - case "iPad6,7", "iPad6,8": return "iPad Pro (12.9-inch) (1st generation)" - case "iPad7,1", "iPad7,2": return "iPad Pro (12.9-inch) (2nd generation)" - case "iPad8,5", "iPad8,6", "iPad8,7", "iPad8,8": return "iPad Pro (12.9-inch) (3rd generation)" - case "iPad8,11", "iPad8,12": return "iPad Pro (12.9-inch) (4th generation)" - case "iPad13,8", "iPad13,9", "iPad13,10", "iPad13,11": return "iPad Pro (12.9-inch) (5th generation)" - case "iPad14,5", "iPad14,6": return "iPad Pro (12.9-inch) (6th generation)" - case "AppleTV5,3": return "Apple TV" - case "AppleTV6,2": return "Apple TV 4K" - case "AudioAccessory1,1": return "HomePod" - case "AudioAccessory5,1": return "HomePod mini" - case "i386", "x86_64", "arm64": return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "iOS"))" - default: return identifier - } + switch identifier { + case "iPod5,1": return "iPod touch (5th generation)" + case "iPod7,1": return "iPod touch (6th generation)" + case "iPod9,1": return "iPod touch (7th generation)" + case "iPhone3,1", "iPhone3,2", "iPhone3,3": return "iPhone 4" + case "iPhone4,1": return "iPhone 4s" + case "iPhone5,1", "iPhone5,2": return "iPhone 5" + case "iPhone5,3", "iPhone5,4": return "iPhone 5c" + case "iPhone6,1", "iPhone6,2": return "iPhone 5s" + case "iPhone7,2": return "iPhone 6" + case "iPhone7,1": return "iPhone 6 Plus" + case "iPhone8,1": return "iPhone 6s" + case "iPhone8,2": return "iPhone 6s Plus" + case "iPhone9,1", "iPhone9,3": return "iPhone 7" + case "iPhone9,2", "iPhone9,4": return "iPhone 7 Plus" + case "iPhone10,1", "iPhone10,4": return "iPhone 8" + case "iPhone10,2", "iPhone10,5": return "iPhone 8 Plus" + case "iPhone10,3", "iPhone10,6": return "iPhone X" + case "iPhone11,2": return "iPhone XS" + case "iPhone11,4", "iPhone11,6": return "iPhone XS Max" + case "iPhone11,8": return "iPhone XR" + case "iPhone12,1": return "iPhone 11" + case "iPhone12,3": return "iPhone 11 Pro" + case "iPhone12,5": return "iPhone 11 Pro Max" + case "iPhone13,1": return "iPhone 12 mini" + case "iPhone13,2": return "iPhone 12" + case "iPhone13,3": return "iPhone 12 Pro" + case "iPhone13,4": return "iPhone 12 Pro Max" + case "iPhone14,4": return "iPhone 13 mini" + case "iPhone14,5": return "iPhone 13" + case "iPhone14,2": return "iPhone 13 Pro" + case "iPhone14,3": return "iPhone 13 Pro Max" + case "iPhone14,7": return "iPhone 14" + case "iPhone14,8": return "iPhone 14 Plus" + case "iPhone15,2": return "iPhone 14 Pro" + case "iPhone15,3": return "iPhone 14 Pro Max" + case "iPhone8,4": return "iPhone SE" + case "iPhone12,8": return "iPhone SE (2nd generation)" + case "iPhone14,6": return "iPhone SE (3rd generation)" + case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4": return "iPad 2" + case "iPad3,1", "iPad3,2", "iPad3,3": return "iPad (3rd generation)" + case "iPad3,4", "iPad3,5", "iPad3,6": return "iPad (4th generation)" + case "iPad6,11", "iPad6,12": return "iPad (5th generation)" + case "iPad7,5", "iPad7,6": return "iPad (6th generation)" + case "iPad7,11", "iPad7,12": return "iPad (7th generation)" + case "iPad11,6", "iPad11,7": return "iPad (8th generation)" + case "iPad12,1", "iPad12,2": return "iPad (9th generation)" + case "iPad13,18", "iPad13,19": return "iPad (10th generation)" + case "iPad4,1", "iPad4,2", "iPad4,3": return "iPad Air" + case "iPad5,3", "iPad5,4": return "iPad Air 2" + case "iPad11,3", "iPad11,4": return "iPad Air (3rd generation)" + case "iPad13,1", "iPad13,2": return "iPad Air (4th generation)" + case "iPad13,16", "iPad13,17": return "iPad Air (5th generation)" + case "iPad2,5", "iPad2,6", "iPad2,7": return "iPad mini" + case "iPad4,4", "iPad4,5", "iPad4,6": return "iPad mini 2" + case "iPad4,7", "iPad4,8", "iPad4,9": return "iPad mini 3" + case "iPad5,1", "iPad5,2": return "iPad mini 4" + case "iPad11,1", "iPad11,2": return "iPad mini (5th generation)" + case "iPad14,1", "iPad14,2": return "iPad mini (6th generation)" + case "iPad6,3", "iPad6,4": return "iPad Pro (9.7-inch)" + case "iPad7,3", "iPad7,4": return "iPad Pro (10.5-inch)" + case "iPad8,1", "iPad8,2", "iPad8,3", "iPad8,4": return "iPad Pro (11-inch) (1st generation)" + case "iPad8,9", "iPad8,10": return "iPad Pro (11-inch) (2nd generation)" + case "iPad13,4", "iPad13,5", "iPad13,6", "iPad13,7": return "iPad Pro (11-inch) (3rd generation)" + case "iPad14,3", "iPad14,4": return "iPad Pro (11-inch) (4th generation)" + case "iPad6,7", "iPad6,8": return "iPad Pro (12.9-inch) (1st generation)" + case "iPad7,1", "iPad7,2": return "iPad Pro (12.9-inch) (2nd generation)" + case "iPad8,5", "iPad8,6", "iPad8,7", "iPad8,8": return "iPad Pro (12.9-inch) (3rd generation)" + case "iPad8,11", "iPad8,12": return "iPad Pro (12.9-inch) (4th generation)" + case "iPad13,8", "iPad13,9", "iPad13,10", "iPad13,11": return "iPad Pro (12.9-inch) (5th generation)" + case "iPad14,5", "iPad14,6": return "iPad Pro (12.9-inch) (6th generation)" + case "AppleTV5,3": return "Apple TV" + case "AppleTV6,2": return "Apple TV 4K" + case "AudioAccessory1,1": return "HomePod" + case "AudioAccessory5,1": return "HomePod mini" + case "i386", "x86_64", "arm64": return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "iOS"))" + default: return identifier + } #elseif os(tvOS) - switch identifier { - case "AppleTV5,3": return "Apple TV 4" - case "AppleTV6,2": return "Apple TV 4K" - case "i386", "x86_64": - return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "tvOS"))" - default: return identifier - } + switch identifier { + case "AppleTV5,3": return "Apple TV 4" + case "AppleTV6,2": return "Apple TV 4K" + case "i386", "x86_64": + return "Simulator \(mapToDevice(identifier: ProcessInfo().environment["SIMULATOR_MODEL_IDENTIFIER"] ?? "tvOS"))" + default: return identifier + } #endif } @@ -140,15 +140,17 @@ extension UIDevice { } // MARK: - Model Identifier + extension UIDevice { static func isiPhoneSE() -> Bool { - return modelIdentifier() == "iPhone8,4" + modelIdentifier() == "iPhone8,4" || modelIdentifier() == "iPhone12,8" } fileprivate static func modelIdentifier() -> String { if let simulatorModelIdentifier = ProcessInfo() - .environment["SIMULATOR_MODEL_IDENTIFIER"] { + .environment["SIMULATOR_MODEL_IDENTIFIER"] + { return simulatorModelIdentifier } var sysinfo = utsname() @@ -161,6 +163,6 @@ extension UIDevice { extension UIDevice { static func isTablet() -> Bool { - return UIDevice.current.userInterfaceIdiom == .pad + UIDevice.current.userInterfaceIdiom == .pad } } diff --git a/station/Extensions/UIFont+Extension.swift b/station/Extensions/UIFont+Extension.swift index 66acd5a1e..1b906c966 100644 --- a/station/Extensions/UIFont+Extension.swift +++ b/station/Extensions/UIFont+Extension.swift @@ -20,32 +20,36 @@ public extension UIFont { } // MARK: - FUNCTIONS + static func Montserrat(_ type: MontserratStyles = .regular, - size: CGFloat = UIFont.systemFontSize) -> UIFont { - return UIFont(name: "Montserrat-\(type.rawValue)", - size: size.adjustedSize()) ?? - UIFont.systemFont(ofSize: size.adjustedSize()) + size: CGFloat = UIFont.systemFontSize) -> UIFont + { + UIFont(name: "Montserrat-\(type.rawValue)", + size: size.adjustedSize()) ?? + UIFont.systemFont(ofSize: size.adjustedSize()) } static func Muli(_ type: MuliStyles = .regular, - size: CGFloat = UIFont.systemFontSize) -> UIFont { + size: CGFloat = UIFont.systemFontSize) -> UIFont + { let prefix = (type == .semiBoldItalic || type == .extraBold) ? "Mulish" : "Muli" return UIFont(name: "\(prefix)-\(type.rawValue)", size: size.adjustedSize()) ?? - UIFont.systemFont(ofSize: size.adjustedSize()) + UIFont.systemFont(ofSize: size.adjustedSize()) } static func Oswald(_ type: OswaldStyles = .extraLight, - size: CGFloat = UIFont.systemFontSize) -> UIFont { - return UIFont(name: "Oswald-\(type.rawValue)", - size: size.adjustedSize()) ?? - UIFont.systemFont(ofSize: size.adjustedSize(), - weight: .ultraLight) + size: CGFloat = UIFont.systemFontSize) -> UIFont + { + UIFont(name: "Oswald-\(type.rawValue)", + size: size.adjustedSize()) ?? + UIFont.systemFont(ofSize: size.adjustedSize(), + weight: .ultraLight) } } extension CGFloat { func adjustedSize() -> CGFloat { - return GlobalHelpers.isDeviceTablet() ? self + 4 : self + GlobalHelpers.isDeviceTablet() ? self + 4 : self } } diff --git a/station/Extensions/UIImage+Extension.swift b/station/Extensions/UIImage+Extension.swift index e54858364..bccd26b05 100644 --- a/station/Extensions/UIImage+Extension.swift +++ b/station/Extensions/UIImage+Extension.swift @@ -1,8 +1,8 @@ import UIKit -extension Optional where Wrapped == UIImage { +extension UIImage? { func resize(targetWidth: CGFloat = 100) -> UIImage? { - guard let self = self else { + guard let self else { return nil } @@ -18,7 +18,7 @@ extension Optional where Wrapped == UIImage { } func resize(targetHeight: CGFloat) -> UIImage? { - guard let self = self else { + guard let self else { return nil } diff --git a/station/Extensions/UIImageView+Init.swift b/station/Extensions/UIImageView+Init.swift index 33f2444bd..d13e35b68 100644 --- a/station/Extensions/UIImageView+Init.swift +++ b/station/Extensions/UIImageView+Init.swift @@ -4,13 +4,14 @@ extension UIImageView { convenience init(image: UIImage? = nil, backgroundColor: UIColor = .clear, contentMode: ContentMode = .scaleAspectFill, - cornerRadius: CGFloat = 0) { + cornerRadius: CGFloat = 0) + { self.init() self.image = image self.backgroundColor = backgroundColor self.contentMode = contentMode - self.layer.cornerRadius = cornerRadius - self.clipsToBounds = true - self.isUserInteractionEnabled = true + layer.cornerRadius = cornerRadius + clipsToBounds = true + isUserInteractionEnabled = true } } diff --git a/station/Extensions/UINavigationController.swift b/station/Extensions/UINavigationController.swift index 320ee901c..848651dd6 100644 --- a/station/Extensions/UINavigationController.swift +++ b/station/Extensions/UINavigationController.swift @@ -1,7 +1,7 @@ import UIKit extension UINavigationController { - open override func viewWillLayoutSubviews() { + override open func viewWillLayoutSubviews() { navigationBar.topItem?.backButtonDisplayMode = .minimal } @@ -20,13 +20,13 @@ extension UINavigationController { /// removes any matching instances from self's /// viewControllers array. func removeAnyViewControllers(ofKind kind: AnyClass) { - self.viewControllers = self.viewControllers.filter { !$0.isKind(of: kind)} + viewControllers = viewControllers.filter { !$0.isKind(of: kind) } } /// Given the kind of a (UIViewController subclass), /// returns true if self's viewControllers array contains at /// least one matching instance. func containsViewController(ofKind kind: AnyClass) -> Bool { - return self.viewControllers.contains(where: { $0.isKind(of: kind) }) + viewControllers.contains(where: { $0.isKind(of: kind) }) } } diff --git a/station/Extensions/UITableViewCell+ReusableView.swift b/station/Extensions/UITableViewCell+ReusableView.swift index f09fcc784..11a546dff 100644 --- a/station/Extensions/UITableViewCell+ReusableView.swift +++ b/station/Extensions/UITableViewCell+ReusableView.swift @@ -6,26 +6,27 @@ protocol ReusableView: AnyObject { extension ReusableView where Self: UIView { static var reuseIdentifier: String { - return String(describing: self) + String(describing: self) } } -extension UICollectionViewCell: ReusableView { -} +extension UICollectionViewCell: ReusableView {} + +extension UITableViewCell: ReusableView {} + +extension UITableViewHeaderFooterView: ReusableView {} -extension UITableViewCell: ReusableView { -} -extension UITableViewHeaderFooterView: ReusableView { -} extension UITableView { - func dequeueReusableCell(with type: T.Type, - for indexPath: IndexPath) -> T { + func dequeueReusableCell(with _: T.Type, + for indexPath: IndexPath) -> T + { guard let cell = dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as? T else { preconditionFailure("Unable to dequeue \(T.description()) for indexPath: \(indexPath)") } return cell } - func dequeueReusableHeaderFooterView(with type: T.Type) -> T { + + func dequeueReusableHeaderFooterView(with _: T.Type) -> T { guard let cell = dequeueReusableHeaderFooterView(withIdentifier: T.reuseIdentifier) as? T else { preconditionFailure("Unable to dequeue \(T.description())") } diff --git a/station/Extensions/UITextField+Extension.swift b/station/Extensions/UITextField+Extension.swift index 779d12be7..c7388b064 100644 --- a/station/Extensions/UITextField+Extension.swift +++ b/station/Extensions/UITextField+Extension.swift @@ -1,7 +1,6 @@ import UIKit extension UITextField { - func addNumericAccessory() { let numberToolbar = UIToolbar() numberToolbar.barStyle = UIBarStyle.default @@ -20,22 +19,20 @@ extension UITextField { } @objc func handleMinusTap() { - guard let currentText = self.text else { + guard let currentText = text else { return } if currentText.hasPrefix("-") { let offsetIndex = currentText.index(currentText.startIndex, offsetBy: 1) let substring = currentText[offsetIndex...] - self.text = String(substring) + text = String(substring) } else { - self.text = "-" + currentText + text = "-" + currentText } } - } extension UITextField { - enum PaddingSpace { case left(CGFloat) case right(CGFloat) @@ -43,39 +40,39 @@ extension UITextField { } func addPadding(padding: PaddingSpace) { - - self.leftViewMode = .always - self.layer.masksToBounds = true + leftViewMode = .always + layer.masksToBounds = true switch padding { - case .left(let spacing): - let leftPaddingView = UIView(frame: CGRect(x: 0, y: 0, width: spacing, height: self.frame.height)) - self.leftView = leftPaddingView - self.leftViewMode = .always + case let .left(spacing): + let leftPaddingView = UIView(frame: CGRect(x: 0, y: 0, width: spacing, height: frame.height)) + leftView = leftPaddingView + leftViewMode = .always - case .right(let spacing): - let rightPaddingView = UIView(frame: CGRect(x: 0, y: 0, width: spacing, height: self.frame.height)) - self.rightView = rightPaddingView - self.rightViewMode = .always + case let .right(spacing): + let rightPaddingView = UIView(frame: CGRect(x: 0, y: 0, width: spacing, height: frame.height)) + rightView = rightPaddingView + rightViewMode = .always - case .equalSpacing(let spacing): - let equalPaddingView = UIView(frame: CGRect(x: 0, y: 0, width: spacing, height: self.frame.height)) + case let .equalSpacing(spacing): + let equalPaddingView = UIView(frame: CGRect(x: 0, y: 0, width: spacing, height: frame.height)) // left - self.leftView = equalPaddingView - self.leftViewMode = .always + leftView = equalPaddingView + leftViewMode = .always // right - self.rightView = equalPaddingView - self.rightViewMode = .always + rightView = equalPaddingView + rightViewMode = .always } } func setPlaceHolderColor(color: UIColor?) { - guard let placeholder = placeholder, - let color = color else { + guard let placeholder, + let color + else { return } - self.attributedPlaceholder = NSAttributedString( + attributedPlaceholder = NSAttributedString( string: placeholder, attributes: [NSAttributedString.Key.foregroundColor: color] ) diff --git a/station/Extensions/UIView+Extension.swift b/station/Extensions/UIView+Extension.swift index 5176f845c..fb15685fd 100644 --- a/station/Extensions/UIView+Extension.swift +++ b/station/Extensions/UIView+Extension.swift @@ -2,39 +2,39 @@ import UIKit extension UIView { func disable(_ disable: Bool) { - self.alpha = disable ? 0.4 : 1 - self.isUserInteractionEnabled = !disable + alpha = disable ? 0.4 : 1 + isUserInteractionEnabled = !disable } } extension UIView { func fadeIn(animated: Bool = true) { - guard self.alpha == 0 else { return } + guard alpha == 0 else { return } if animated { UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveLinear, animations: { [weak self] in - self?.alpha = 1 - self?.layoutIfNeeded() - }) + self?.alpha = 1 + self?.layoutIfNeeded() + }) } else { - self.alpha = 1 + alpha = 1 } } func fadeOut(animated: Bool = true) { - guard self.alpha == 1 else { return } + guard alpha == 1 else { return } if animated { UIView.animate(withDuration: 0.3, delay: 0.0, options: .curveLinear, animations: { [weak self] in - self?.alpha = 0 - self?.layoutIfNeeded() - }) + self?.alpha = 0 + self?.layoutIfNeeded() + }) } else { - self.alpha = 0 + alpha = 0 } } } diff --git a/station/Extensions/UIView+Init.swift b/station/Extensions/UIView+Init.swift index 16e947142..046e18f21 100644 --- a/station/Extensions/UIView+Init.swift +++ b/station/Extensions/UIView+Init.swift @@ -4,12 +4,13 @@ extension UIView { convenience init(color: UIColor? = .clear, cornerRadius: CGFloat = 0, borderWidth: CGFloat = 0, - borderColor: UIColor = .clear) { + borderColor: UIColor = .clear) + { self.init() - self.layer.cornerRadius = cornerRadius - self.layer.borderWidth = borderWidth - self.layer.borderColor = borderColor.cgColor - self.backgroundColor = color + layer.cornerRadius = cornerRadius + layer.borderWidth = borderWidth + layer.borderColor = borderColor.cgColor + backgroundColor = color clipsToBounds = true } } diff --git a/station/Extensions/UIView+Layout.swift b/station/Extensions/UIView+Layout.swift index ef2cc47ce..888fc7f5c 100644 --- a/station/Extensions/UIView+Layout.swift +++ b/station/Extensions/UIView+Layout.swift @@ -4,33 +4,32 @@ import UIKit /// It helps to reduce a lot of redundant code to set constraint for all views extension UIView { - @discardableResult func anchor(top: NSLayoutYAxisAnchor?, leading: NSLayoutXAxisAnchor?, bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, - padding: UIEdgeInsets = .zero, size: CGSize = .zero) -> AnchoredConstraints { - + padding: UIEdgeInsets = .zero, size: CGSize = .zero) -> AnchoredConstraints + { translatesAutoresizingMaskIntoConstraints = false var anchoredConstraints = AnchoredConstraints() - if let top = top { + if let top { anchoredConstraints.top = topAnchor.constraint(equalTo: top, constant: padding.top) } - if let leading = leading { + if let leading { anchoredConstraints.leading = leadingAnchor.constraint(equalTo: leading, constant: padding.left) } - if let bottom = bottom { + if let bottom { anchoredConstraints.bottom = bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom) } - if let trailing = trailing { + if let trailing { anchoredConstraints.trailing = trailingAnchor.constraint(equalTo: trailing, constant: -padding.right) } @@ -59,28 +58,28 @@ extension UIView { bottom: NSLayoutYAxisAnchor?, trailing: NSLayoutXAxisAnchor?, padding: UIEdgeInsets = .zero, - size: CGSize = .zero) -> AnchoredConstraints { - + size: CGSize = .zero) -> AnchoredConstraints + { translatesAutoresizingMaskIntoConstraints = false var anchoredConstraints = AnchoredConstraints() - if let top = top { + if let top { anchoredConstraints.top = topAnchor.constraint(equalTo: top, constant: padding.top) } - if let leading = leading { + if let leading { anchoredConstraints.leading = leadingAnchor.constraint(greaterThanOrEqualTo: leading, constant: padding.left) } - if let bottom = bottom { + if let bottom { anchoredConstraints.bottom = bottomAnchor.constraint(equalTo: bottom, constant: -padding.bottom) } - if let trailing = trailing { + if let trailing { anchoredConstraints.trailing = trailingAnchor.constraint(lessThanOrEqualTo: trailing, constant: -padding.right) @@ -208,10 +207,10 @@ extension UIView { func match(view: UIView) { translatesAutoresizingMaskIntoConstraints = false - self.topAnchor.constraint(equalTo: view.topAnchor).isActive = true - self.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true - self.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true - self.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true + topAnchor.constraint(equalTo: view.topAnchor).isActive = true + bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true + leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true + trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true } } @@ -220,33 +219,32 @@ struct AnchoredConstraints { } extension UIView { - var safeTopAnchor: NSLayoutYAxisAnchor { if #available(iOS 11.0, *) { return self.safeAreaLayoutGuide.topAnchor } - return self.topAnchor + return topAnchor } var safeLeftAnchor: NSLayoutXAxisAnchor { if #available(iOS 11.0, *) { return self.safeAreaLayoutGuide.leadingAnchor } - return self.leftAnchor + return leftAnchor } var safeRightAnchor: NSLayoutXAxisAnchor { if #available(iOS 11.0, *) { return self.safeAreaLayoutGuide.trailingAnchor } - return self.rightAnchor + return rightAnchor } var safeBottomAnchor: NSLayoutYAxisAnchor { if #available(iOS 11.0, *) { return self.safeAreaLayoutGuide.bottomAnchor } - return self.bottomAnchor + return bottomAnchor } var topSafeAreaHeight: CGFloat { diff --git a/station/Extensions/UIViewController+Alert.swift b/station/Extensions/UIViewController+Alert.swift index 801715ef6..45af1a46f 100644 --- a/station/Extensions/UIViewController+Alert.swift +++ b/station/Extensions/UIViewController+Alert.swift @@ -1,9 +1,10 @@ -import UIKit import RuuviLocalization +import UIKit extension UIViewController { func showAlert(title: String? = nil, - message: String? = nil) { + message: String? = nil) + { let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) diff --git a/station/Extensions/UIWindow+Orientation.swift b/station/Extensions/UIWindow+Orientation.swift index 12ef5f2a3..59136b908 100644 --- a/station/Extensions/UIWindow+Orientation.swift +++ b/station/Extensions/UIWindow+Orientation.swift @@ -3,25 +3,25 @@ import UIKit extension UIWindow { static var isLandscape: Bool { if #available(iOS 13.0, *) { - return UIApplication.shared.windows + UIApplication.shared.windows .first? .windowScene? .interfaceOrientation .isLandscape ?? false } else { - return UIApplication.shared.statusBarOrientation.isLandscape + UIApplication.shared.statusBarOrientation.isLandscape } } static var isPortrait: Bool { - return !self.isLandscape + !isLandscape } static var key: UIWindow? { if #available(iOS 13, *) { - return UIApplication.shared.windows.first { $0.isKeyWindow } + UIApplication.shared.windows.first { $0.isKeyWindow } } else { - return UIApplication.shared.keyWindow + UIApplication.shared.keyWindow } } } diff --git a/station/Extensions/UIWindow+Shake.swift b/station/Extensions/UIWindow+Shake.swift index bb7368d39..5fbf47f91 100644 --- a/station/Extensions/UIWindow+Shake.swift +++ b/station/Extensions/UIWindow+Shake.swift @@ -1,13 +1,13 @@ import UIKit #if DEBUG && canImport(FLEX) -import FLEX + import FLEX -extension UIWindow { - open override func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) { - super.motionEnded(motion, with: event) - if motion == .motionShake { - FLEXManager.shared.showExplorer() + extension UIWindow { + override open func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) { + super.motionEnded(motion, with: event) + if motion == .motionShake { + FLEXManager.shared.showExplorer() + } } } -} #endif diff --git a/station/Extensions/UnitPressure+Extension.swift b/station/Extensions/UnitPressure+Extension.swift index baf35f0da..c3e9e3211 100644 --- a/station/Extensions/UnitPressure+Extension.swift +++ b/station/Extensions/UnitPressure+Extension.swift @@ -1,6 +1,6 @@ import Foundation -import RuuviOntology import RuuviLocalization +import RuuviOntology extension UnitPressure: SelectionItemProtocol { var title: (String) -> String { @@ -12,10 +12,11 @@ extension UnitPressure: SelectionItemProtocol { case .millimetersOfMercury: return { _ in RuuviLocalization.UnitPressure.MillimetreOfMercury.title } default: - assert(false, "Not allowed") + assertionFailure("Not allowed") return { _ in .init() } } } + var alertRange: Range { let min = Pressure(500, unit: .hectopascals)?.converted(to: self).value ?? 500 let max = Pressure(1155, unit: .hectopascals)?.converted(to: self).value ?? 1155 diff --git a/station/Extensions/UnitSettingsType.swift b/station/Extensions/UnitSettingsType.swift index 3e0554d1d..e5eb15889 100644 --- a/station/Extensions/UnitSettingsType.swift +++ b/station/Extensions/UnitSettingsType.swift @@ -10,9 +10,9 @@ extension UnitSettingsType: SelectionItemProtocol { var title: (String) -> String { switch self { case .unit: - return { _ in RuuviLocalization.Settings.Measurement.Unit.title } + { _ in RuuviLocalization.Settings.Measurement.Unit.title } case .accuracy: - return { _ in RuuviLocalization.Settings.Measurement.Resolution.title } + { _ in RuuviLocalization.Settings.Measurement.Resolution.title } } } } diff --git a/station/Extensions/UserDefaults+Optional.swift b/station/Extensions/UserDefaults+Optional.swift index f5bd173f8..75db3d45c 100644 --- a/station/Extensions/UserDefaults+Optional.swift +++ b/station/Extensions/UserDefaults+Optional.swift @@ -1,7 +1,6 @@ import Foundation extension UserDefaults { - func optionalDouble(forKey defaultName: String) -> Double? { let defaults = self if let value = defaults.value(forKey: defaultName) { diff --git a/station/Resources/Assets/RuuviAssets.swift b/station/Resources/Assets/RuuviAssets.swift index 18ce0d504..f6c43c5dc 100644 --- a/station/Resources/Assets/RuuviAssets.swift +++ b/station/Resources/Assets/RuuviAssets.swift @@ -1,6 +1,6 @@ import UIKit -struct RuuviAssets { +enum RuuviAssets { static let alertActiveImage = UIImage(named: "icon-alert-active") static let alertOffImage = UIImage(named: "icon-alert-off") static let alertOnImage = UIImage(named: "icon-alert-on") diff --git a/stationTests/MockAlertPersistence.swift b/stationTests/MockAlertPersistence.swift index b4d1dade0..17c8af55a 100644 --- a/stationTests/MockAlertPersistence.swift +++ b/stationTests/MockAlertPersistence.swift @@ -1,99 +1,118 @@ import Foundation @testable import station class MockAlertPersistense: AlertPersistence { - func lowerHumidity(for uuid: String) -> Humidity? { - return nil + func lowerHumidity(for _: String) -> Humidity? { + nil } - func setLower(humidity: Humidity?, for uuid: String) {} + func setLower(humidity _: Humidity?, for _: String) {} - func upperHumidity(for uuid: String) -> Humidity? { - return nil + func upperHumidity(for _: String) -> Humidity? { + nil } - func setUpper(humidity: Humidity?, for uuid: String) {} + func setUpper(humidity _: Humidity?, for _: String) {} - func humidityDescription(for uuid: String) -> String? { - return nil + func humidityDescription(for _: String) -> String? { + nil } - func setHumidity(description: String?, for uuid: String) {} + func setHumidity(description _: String?, for _: String) {} - func alert(for uuid: String, of type: AlertType) -> AlertType? { - return .none + func alert(for _: String, of _: AlertType) -> AlertType? { + .none } - func register(type: AlertType, for uuid: String) {} - func unregister(type: AlertType, for uuid: String) {} - func lowerCelsius(for uuid: String) -> Double? { - return nil + + func register(type _: AlertType, for _: String) {} + func unregister(type _: AlertType, for _: String) {} + func lowerCelsius(for _: String) -> Double? { + nil } - func setLower(celsius: Double?, for uuid: String) {} - func upperCelsius(for uuid: String) -> Double? { - return nil + + func setLower(celsius _: Double?, for _: String) {} + func upperCelsius(for _: String) -> Double? { + nil } - func setUpper(celsius: Double?, for uuid: String) {} - func temperatureDescription(for uuid: String) -> String? { - return nil + + func setUpper(celsius _: Double?, for _: String) {} + func temperatureDescription(for _: String) -> String? { + nil } - func setTemperature(description: String?, for uuid: String) {} - func lowerRelativeHumidity(for uuid: String) -> Double? { - return nil + + func setTemperature(description _: String?, for _: String) {} + func lowerRelativeHumidity(for _: String) -> Double? { + nil } - func setLower(relativeHumidity: Double?, for uuid: String) {} - func upperRelativeHumidity(for uuid: String) -> Double? { - return nil + + func setLower(relativeHumidity _: Double?, for _: String) {} + func upperRelativeHumidity(for _: String) -> Double? { + nil } - func setUpper(relativeHumidity: Double?, for uuid: String) {} - func relativeHumidityDescription(for uuid: String) -> String? { - return nil + + func setUpper(relativeHumidity _: Double?, for _: String) {} + func relativeHumidityDescription(for _: String) -> String? { + nil } - func setRelativeHumidity(description: String?, for uuid: String) {} - func lowerAbsoluteHumidity(for uuid: String) -> Double? { - return nil + + func setRelativeHumidity(description _: String?, for _: String) {} + func lowerAbsoluteHumidity(for _: String) -> Double? { + nil } - func setLower(absoluteHumidity: Double?, for uuid: String) {} - func upperAbsoluteHumidity(for uuid: String) -> Double? { - return nil + + func setLower(absoluteHumidity _: Double?, for _: String) {} + func upperAbsoluteHumidity(for _: String) -> Double? { + nil } - func setUpper(absoluteHumidity: Double?, for uuid: String) {} - func absoluteHumidityDescription(for uuid: String) -> String? { - return nil + + func setUpper(absoluteHumidity _: Double?, for _: String) {} + func absoluteHumidityDescription(for _: String) -> String? { + nil } - func setAbsoluteHumidity(description: String?, for uuid: String) {} - func lowerDewPointCelsius(for uuid: String) -> Double? { - return nil + + func setAbsoluteHumidity(description _: String?, for _: String) {} + func lowerDewPointCelsius(for _: String) -> Double? { + nil } - func setLowerDewPoint(celsius: Double?, for uuid: String) {} - func upperDewPointCelsius(for uuid: String) -> Double? { - return nil + + func setLowerDewPoint(celsius _: Double?, for _: String) {} + func upperDewPointCelsius(for _: String) -> Double? { + nil } - func setUpperDewPoint(celsius: Double?, for uuid: String) {} - func dewPointDescription(for uuid: String) -> String? { - return nil + + func setUpperDewPoint(celsius _: Double?, for _: String) {} + func dewPointDescription(for _: String) -> String? { + nil } - func setDewPoint(description: String?, for uuid: String) {} - func lowerPressure(for uuid: String) -> Double? { - return nil + + func setDewPoint(description _: String?, for _: String) {} + func lowerPressure(for _: String) -> Double? { + nil } - func setLower(pressure: Double?, for uuid: String) {} - func upperPressure(for uuid: String) -> Double? { - return nil + + func setLower(pressure _: Double?, for _: String) {} + func upperPressure(for _: String) -> Double? { + nil } - func setUpper(pressure: Double?, for uuid: String) {} - func pressureDescription(for uuid: String) -> String? { - return nil + + func setUpper(pressure _: Double?, for _: String) {} + func pressureDescription(for _: String) -> String? { + nil } - func setPressure(description: String?, for uuid: String) {} - func connectionDescription(for uuid: String) -> String? { - return nil + + func setPressure(description _: String?, for _: String) {} + func connectionDescription(for _: String) -> String? { + nil } - func setConnection(description: String?, for uuid: String) {} - func movementCounter(for uuid: String) -> Int? { - return nil + + func setConnection(description _: String?, for _: String) {} + func movementCounter(for _: String) -> Int? { + nil } - func setMovement(counter: Int?, for uuid: String) {} - func movementDescription(for uuid: String) -> String? { - return nil + + func setMovement(counter _: Int?, for _: String) {} + func movementDescription(for _: String) -> String? { + nil } - func setMovement(description: String?, for uuid: String) {} + + func setMovement(description _: String?, for _: String) {} } diff --git a/stationTests/MockCalibrationService.swift b/stationTests/MockCalibrationService.swift index cf8f3ded7..e6158a08f 100644 --- a/stationTests/MockCalibrationService.swift +++ b/stationTests/MockCalibrationService.swift @@ -3,26 +3,27 @@ import Future @testable import station class MockCalibrationService: CalibrationService { - func calibrateHumiditySaltTest(currentValue: Double, for ruuviTag: RuuviTagSensor) {} + func calibrateHumiditySaltTest(currentValue _: Double, for _: RuuviTagSensor) {} - func cleanHumidityCalibration(for ruuviTag: RuuviTagSensor) {} + func cleanHumidityCalibration(for _: RuuviTagSensor) {} - func humidityOffset(for luid: LocalIdentifier) -> (Double, Date?) { - return (.nan, nil) + func humidityOffset(for _: LocalIdentifier) -> (Double, Date?) { + (.nan, nil) } - func calibrateHumidityTo100Percent(currentValue: Double, for ruuviTag: RuuviTagSensor) {} + func calibrateHumidityTo100Percent(currentValue _: Double, for _: RuuviTagSensor) {} - func calibrateHumiditySaltTest(currentValue: Double, for ruuviTag: RuuviTagRealmProtocol) -> Future { - return .init(value: true) + func calibrateHumiditySaltTest(currentValue _: Double, for _: RuuviTagRealmProtocol) -> Future { + .init(value: true) } - func cleanHumidityCalibration(for ruuviTag: RuuviTagRealmProtocol) -> Future { - return .init(value: true) - } - func humidityOffset(for uuid: String) -> (Double, Date?) { - return (0, Date()) + + func cleanHumidityCalibration(for _: RuuviTagRealmProtocol) -> Future { + .init(value: true) } - func calibrateHumidityTo100Percent(currentValue: Double, for ruuviTag: RuuviTagSensor) { + func humidityOffset(for _: String) -> (Double, Date?) { + (0, Date()) } + + func calibrateHumidityTo100Percent(currentValue _: Double, for _: RuuviTagSensor) {} } diff --git a/stationTests/MockLocalNotificationsManager.swift b/stationTests/MockLocalNotificationsManager.swift index 9fd759890..021e2492b 100644 --- a/stationTests/MockLocalNotificationsManager.swift +++ b/stationTests/MockLocalNotificationsManager.swift @@ -1,19 +1,19 @@ -import UIKit @testable import station +import UIKit class MockLocalNotificationsManager: LocalNotificationsManager { var reason: LowHighNotificationReason? var type: LowHighNotificationType? var uuid: String? - func application(_ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) { - } - func showDidConnect(uuid: String) { - } - func showDidDisconnect(uuid: String) { - } - func notifyDidMove(for uuid: String, counter: Int) { - } + func application(_: UIApplication, + didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) {} + + func showDidConnect(uuid _: String) {} + + func showDidDisconnect(uuid _: String) {} + + func notifyDidMove(for _: String, counter _: Int) {} + func notify(_ reason: LowHighNotificationReason, _ type: LowHighNotificationType, for uuid: String) { self.reason = reason self.type = type diff --git a/stationTests/Services/Alert/AlertServiceSpec.swift b/stationTests/Services/Alert/AlertServiceSpec.swift index e6f68bc6a..2c8176736 100644 --- a/stationTests/Services/Alert/AlertServiceSpec.swift +++ b/stationTests/Services/Alert/AlertServiceSpec.swift @@ -1,7 +1,7 @@ -import XCTest -import Quick -import Nimble import Humidity +import Nimble +import Quick +import XCTest @testable import station class AlertServiceSpec: QuickSpec { @@ -15,15 +15,17 @@ class AlertServiceSpec: QuickSpec { alertService.calibrationService = MockCalibrationService() var uuid: String = UUID().uuidString - var randomDouble: Double = Double.random(in: -100...100) - var randomPercentDouble: Double = Double.random(in: 10...90) + var randomDouble = Double.random(in: -100 ... 100) + var randomPercentDouble = Double.random(in: 10 ... 90) let type: AlertType = .connection beforeEach { - randomPercentDouble = Double.random(in: 10...90) - randomDouble = Double.random(in: -100...100) + randomPercentDouble = Double.random(in: 10 ... 90) + randomDouble = Double.random(in: -100 ... 100) uuid = UUID().uuidString } + // MARK: - Registration + describe("Registration") { context("when register") { it("must has registration") { @@ -43,7 +45,8 @@ class AlertServiceSpec: QuickSpec { alertService.register(type: type, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } context("when unregister") { @@ -64,11 +67,14 @@ class AlertServiceSpec: QuickSpec { alertService.unregister(type: type, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } } + // MARK: - Temperature + describe("Temperature") { context("when set lower") { it("must return lower") { @@ -81,7 +87,8 @@ class AlertServiceSpec: QuickSpec { alertService.setLower(celsius: randomDouble, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } context("when set upper") { @@ -95,7 +102,8 @@ class AlertServiceSpec: QuickSpec { alertService.setUpper(celsius: randomDouble, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } context("when set description") { @@ -110,11 +118,14 @@ class AlertServiceSpec: QuickSpec { alertService.setTemperature(description: uuid, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } } + // MARK: - Relative Humidity + describe("Relative Humidity") { context("when set lower") { it("must return lower") { @@ -127,7 +138,8 @@ class AlertServiceSpec: QuickSpec { alertService.setLower(relativeHumidity: randomDouble, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } context("when set upper") { @@ -141,7 +153,8 @@ class AlertServiceSpec: QuickSpec { alertService.setUpper(relativeHumidity: randomDouble, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } context("when set description") { @@ -156,11 +169,14 @@ class AlertServiceSpec: QuickSpec { alertService.setRelativeHumidity(description: uuid, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } } + // MARK: - Absolute Humidity + describe("Absolute Humidity") { context("when set lower") { it("must return lower") { @@ -173,7 +189,8 @@ class AlertServiceSpec: QuickSpec { alertService.setLower(absoluteHumidity: randomDouble, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } context("when set upper") { @@ -187,7 +204,8 @@ class AlertServiceSpec: QuickSpec { alertService.setUpper(absoluteHumidity: randomDouble, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } context("when set description") { @@ -202,11 +220,14 @@ class AlertServiceSpec: QuickSpec { alertService.setAbsoluteHumidity(description: uuid, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } } + // MARK: - Dew Point + describe("Dew Point") { context("when set lower") { it("must return lower") { @@ -219,7 +240,8 @@ class AlertServiceSpec: QuickSpec { alertService.setLowerDewPoint(celsius: randomDouble, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } context("when set upper") { @@ -233,7 +255,8 @@ class AlertServiceSpec: QuickSpec { alertService.setUpperDewPoint(celsius: randomDouble, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } context("when set description") { @@ -248,11 +271,14 @@ class AlertServiceSpec: QuickSpec { alertService.setDewPoint(description: uuid, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } } + // MARK: - Pressure + describe("Pressure") { context("when set lower") { it("must return lower") { @@ -265,7 +291,8 @@ class AlertServiceSpec: QuickSpec { alertService.setLower(pressure: randomDouble, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } context("when set upper") { @@ -279,7 +306,8 @@ class AlertServiceSpec: QuickSpec { alertService.setUpper(pressure: randomDouble, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } context("when set description") { @@ -294,11 +322,14 @@ class AlertServiceSpec: QuickSpec { alertService.setPressure(description: uuid, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } } + // MARK: - Connection + describe("Connection") { context("when set description") { it("must return description") { @@ -310,11 +341,13 @@ class AlertServiceSpec: QuickSpec { } } } + // MARK: - Movement + describe("Movement") { context("when set counter") { it("must retur counter") { - let randomInt: Int = Int(randomDouble) + let randomInt: Int = .init(randomDouble) alertService.setMovement(counter: randomInt, for: uuid) expect(alertService.movementCounter(for: uuid)).to(equal(randomInt)) } @@ -325,17 +358,20 @@ class AlertServiceSpec: QuickSpec { expect(alertService.movementDescription(for: uuid)).to(equal(uuid)) } it("must send notification AlertServiceAlertDidChange with type .movement(last: c)") { - let randomInt: Int = Int(randomDouble) + let randomInt: Int = .init(randomDouble) alertService.alertPersistence.setMovement(counter: randomInt, for: uuid) expect { alertService.setMovement(description: uuid, for: uuid) }.toEventually( postNotifications(self.equalName(.AlertServiceAlertDidChange, for: uuid) - ), timeout: self.notificationWaitTimeout) + ), timeout: self.notificationWaitTimeout + ) } } } + // MARK: - HeartBeat + describe("HeartBeat process") { context("temperature trigger") { it("if less") { @@ -491,7 +527,9 @@ class AlertServiceSpec: QuickSpec { } } } + // MARK: - WPSData + describe("WPSData process") { context("temperature trigger") { it("if less") { @@ -499,7 +537,7 @@ class AlertServiceSpec: QuickSpec { let fakeDelegate = MockAlertServiceObserver() alertService.subscribe(fakeDelegate, to: uuid) - let vTag: WPSData = WPSData(celsius: randomDouble - 10, humidity: nil, pressure: nil) + let vTag: WPSData = .init(celsius: randomDouble - 10, humidity: nil, pressure: nil) alertService.process(data: vTag, for: uuid) expect(fakeDelegate.uuid).toEventually(equal(uuid)) expect(fakeDelegate.service).toEventuallyNot(beNil()) @@ -512,7 +550,7 @@ class AlertServiceSpec: QuickSpec { let fakeDelegate = MockAlertServiceObserver() alertService.subscribe(fakeDelegate, to: uuid) - let vTag: WPSData = WPSData(celsius: randomDouble + 10, humidity: nil, pressure: nil) + let vTag: WPSData = .init(celsius: randomDouble + 10, humidity: nil, pressure: nil) alertService.process(data: vTag, for: uuid) expect(fakeDelegate.uuid).toEventually(equal(uuid)) expect(fakeDelegate.service).toEventuallyNot(beNil()) @@ -528,7 +566,7 @@ class AlertServiceSpec: QuickSpec { let fakeDelegate = MockAlertServiceObserver() alertService.subscribe(fakeDelegate, to: uuid) - let vTag: WPSData = WPSData(celsius: nil, humidity: randomPercentDouble - 10, pressure: nil) + let vTag: WPSData = .init(celsius: nil, humidity: randomPercentDouble - 10, pressure: nil) alertService.process(data: vTag, for: uuid) expect(fakeDelegate.uuid).toEventually(equal(uuid)) expect(fakeDelegate.service).toEventuallyNot(beNil()) @@ -541,7 +579,7 @@ class AlertServiceSpec: QuickSpec { let fakeDelegate = MockAlertServiceObserver() alertService.subscribe(fakeDelegate, to: uuid) - let vTag: WPSData = WPSData(celsius: nil, humidity: randomPercentDouble + 10, pressure: nil) + let vTag: WPSData = .init(celsius: nil, humidity: randomPercentDouble + 10, pressure: nil) alertService.process(data: vTag, for: uuid) expect(fakeDelegate.uuid).toEventually(equal(uuid)) expect(fakeDelegate.service).toEventuallyNot(beNil()) @@ -560,7 +598,7 @@ class AlertServiceSpec: QuickSpec { let fakeDelegate = MockAlertServiceObserver() alertService.subscribe(fakeDelegate, to: uuid) - let vTag: WPSData = WPSData(celsius: randomDouble, humidity: h.ah, pressure: nil) + let vTag: WPSData = .init(celsius: randomDouble, humidity: h.ah, pressure: nil) alertService.process(data: vTag, for: uuid) expect(fakeDelegate.uuid).toEventually(equal(uuid)) expect(fakeDelegate.service).toEventuallyNot(beNil()) @@ -576,7 +614,7 @@ class AlertServiceSpec: QuickSpec { let fakeDelegate = MockAlertServiceObserver() alertService.subscribe(fakeDelegate, to: uuid) - let vTag: WPSData = WPSData(celsius: randomDouble, humidity: h.rh, pressure: nil) + let vTag: WPSData = .init(celsius: randomDouble, humidity: h.rh, pressure: nil) alertService.process(data: vTag, for: uuid) expect(fakeDelegate.uuid).toEventually(equal(uuid)) expect(fakeDelegate.service).toEventuallyNot(beNil()) @@ -593,7 +631,7 @@ class AlertServiceSpec: QuickSpec { let fakeDelegate = MockAlertServiceObserver() alertService.subscribe(fakeDelegate, to: uuid) - let vTag: WPSData = WPSData(celsius: 30, humidity: h.rh, pressure: nil) + let vTag: WPSData = .init(celsius: 30, humidity: h.rh, pressure: nil) alertService.process(data: vTag, for: uuid) expect(fakeDelegate.uuid).toEventually(equal(uuid)) expect(fakeDelegate.service).toEventuallyNot(beNil()) @@ -607,7 +645,7 @@ class AlertServiceSpec: QuickSpec { let fakeDelegate = MockAlertServiceObserver() alertService.subscribe(fakeDelegate, to: uuid) - let vTag: WPSData = WPSData(celsius: 30, humidity: h.rh, pressure: nil) + let vTag: WPSData = .init(celsius: 30, humidity: h.rh, pressure: nil) alertService.process(data: vTag, for: uuid) expect(fakeDelegate.uuid).toEventually(equal(uuid)) expect(fakeDelegate.service).toEventuallyNot(beNil()) @@ -623,7 +661,7 @@ class AlertServiceSpec: QuickSpec { let fakeDelegate = MockAlertServiceObserver() alertService.subscribe(fakeDelegate, to: uuid) - let vTag: WPSData = WPSData(celsius: nil, humidity: nil, pressure: randomDouble - 10) + let vTag: WPSData = .init(celsius: nil, humidity: nil, pressure: randomDouble - 10) alertService.process(data: vTag, for: uuid) expect(fakeDelegate.uuid).toEventually(equal(uuid)) expect(fakeDelegate.service).toEventuallyNot(beNil()) @@ -636,7 +674,7 @@ class AlertServiceSpec: QuickSpec { let fakeDelegate = MockAlertServiceObserver() alertService.subscribe(fakeDelegate, to: uuid) - let vTag: WPSData = WPSData(celsius: nil, humidity: nil, pressure: randomDouble + 10) + let vTag: WPSData = .init(celsius: nil, humidity: nil, pressure: randomDouble + 10) alertService.process(data: vTag, for: uuid) expect(fakeDelegate.uuid).toEventually(equal(uuid)) expect(fakeDelegate.service).toEventuallyNot(beNil()) @@ -648,8 +686,9 @@ class AlertServiceSpec: QuickSpec { } } } + func equalName(_ expectedName: Notification.Name, for uuid: String) -> Predicate<[Notification]> { - return Predicate.define("equal <\(stringify(expectedName))>") { actualExpression, msg in + Predicate.define("equal <\(stringify(expectedName))>") { actualExpression, msg in guard let actualValue = try actualExpression.evaluate() else { return PredicateResult(status: .fail, message: msg) } @@ -662,7 +701,7 @@ class AlertServiceSpec: QuickSpec { } return userInfo[RuuviServiceAlertDidChangeKey.uuid] as? String == uuid } - .compactMap { $0.name } + .compactMap(\.name) let matches = actualNames.contains(expectedName) return PredicateResult(bool: matches, message: msg) } diff --git a/stationTests/Services/MeasurementsService/MeasurementsServiceEnSpec.swift b/stationTests/Services/MeasurementsService/MeasurementsServiceEnSpec.swift index fe752fde4..dbcf3ffaf 100644 --- a/stationTests/Services/MeasurementsService/MeasurementsServiceEnSpec.swift +++ b/stationTests/Services/MeasurementsService/MeasurementsServiceEnSpec.swift @@ -1,12 +1,11 @@ -import XCTest import Humidity -import Quick import Nimble +import Quick +import XCTest @testable import station class MeasurementsServiceEnSpec: QuickSpec { - override func spec() { let r = AppAssembly.shared.assembler.resolver var service: MeasurementsService! = r.resolve(MeasurementsService.self) diff --git a/stationTests/Services/MeasurementsService/MeasurementsServiceFiSpec.swift b/stationTests/Services/MeasurementsService/MeasurementsServiceFiSpec.swift index d127e4e43..b6fe94ca6 100644 --- a/stationTests/Services/MeasurementsService/MeasurementsServiceFiSpec.swift +++ b/stationTests/Services/MeasurementsService/MeasurementsServiceFiSpec.swift @@ -1,12 +1,11 @@ -import XCTest import Humidity -import Quick import Nimble +import Quick +import XCTest @testable import station class MeasurementsServiceFiSpec: QuickSpec { - override func spec() { let r = AppAssembly.shared.assembler.resolver var service: MeasurementsService! = r.resolve(MeasurementsService.self) diff --git a/stationTests/Services/MeasurementsService/MeasurementsServiceRuSpec.swift b/stationTests/Services/MeasurementsService/MeasurementsServiceRuSpec.swift index 346df77ba..a1495d9bc 100644 --- a/stationTests/Services/MeasurementsService/MeasurementsServiceRuSpec.swift +++ b/stationTests/Services/MeasurementsService/MeasurementsServiceRuSpec.swift @@ -1,12 +1,11 @@ -import XCTest import Humidity -import Quick import Nimble +import Quick +import XCTest @testable import station class MeasurementsServiceRuSpec: QuickSpec { - override func spec() { let r = AppAssembly.shared.assembler.resolver var service: MeasurementsService! = r.resolve(MeasurementsService.self) diff --git a/stationTests/Services/MeasurementsService/MeasurementsServiceSvSpec.swift b/stationTests/Services/MeasurementsService/MeasurementsServiceSvSpec.swift index 66c84601b..13ff35b38 100644 --- a/stationTests/Services/MeasurementsService/MeasurementsServiceSvSpec.swift +++ b/stationTests/Services/MeasurementsService/MeasurementsServiceSvSpec.swift @@ -1,12 +1,11 @@ -import XCTest import Humidity -import Quick import Nimble +import Quick +import XCTest @testable import station class MeasurementsServiceSvSpec: QuickSpec { - override func spec() { let r = AppAssembly.shared.assembler.resolver var service: MeasurementsService! = r.resolve(MeasurementsService.self) diff --git a/stationTests/StationTests.swift b/stationTests/StationTests.swift index 03d628f79..8ca8bd1fe 100644 --- a/stationTests/StationTests.swift +++ b/stationTests/StationTests.swift @@ -1,19 +1,17 @@ -import XCTest @testable import station +import XCTest class StationTests: XCTestCase { - func testWebTagDaemonCrash() { NotificationCenter - .default - .post(name: .isWebTagDaemonOnDidChange, - object: self, - userInfo: nil) + .default + .post(name: .isWebTagDaemonOnDidChange, + object: self, + userInfo: nil) NotificationCenter - .default - .post(name: .WebTagDaemonIntervalDidChange, - object: self, - userInfo: nil) + .default + .post(name: .WebTagDaemonIntervalDidChange, + object: self, + userInfo: nil) } - } diff --git a/stationUITests/StationUITests.swift b/stationUITests/StationUITests.swift index 1a47e2c68..d5025188c 100644 --- a/stationUITests/StationUITests.swift +++ b/stationUITests/StationUITests.swift @@ -1,16 +1,13 @@ import XCTest class StationUITests: XCTestCase { - override func setUp() { super.setUp() continueAfterFailure = false XCUIApplication().launch() - } override func tearDown() { super.tearDown() } - } From 86ce4ed09390faf4663d5ec806c95ddb5de8aa45 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 9 Dec 2023 22:01:29 +0200 Subject: [PATCH 32/84] Run SwiftLint --fix and --format (#1761) Cleans the codebase with auto fixes from SwiftLint --- .swiftformat | 5 +- .swiftlint.yml | 14 +- .../View/ActivityPresenterView.swift | 12 +- .../Util/RuuviBundleUtils.swift | 6 +- .../RuuviDiscover/Util/RuuviBundleUtils.swift | 6 +- .../Util/UITableViewCell+ReusableView.swift | 13 +- .../Util/UIViewController+Alert.swift | 7 +- .../VMP/Presenter/DiscoverPresenter.swift | 12 +- .../View/Table/DiscoverTableHeaderView.swift | 18 +- .../Table/DiscoverTableViewController.swift | 80 +- .../URLSession+downloadTaskPublisher.swift | 18 +- .../RuuviFirmware/FirmwareInteractor.swift | 22 +- .../Repository/FirmwareRepository.swift | 6 +- .../SwiftUI/FirmwareViewModel.swift | 12 +- .../RuuviFirmware/Util/RuuviBundleUtils.swift | 6 +- Modules/RuuviOnboard/Package.swift | 2 +- .../Pages/Extensions/UIButton+Extension.swift | 28 +- .../Pages/Extensions/UIFont+Extension.swift | 45 +- .../Pages/Extensions/UIImageView+Init.swift | 11 +- .../Pages/Extensions/UILabel+Init.swift | 13 +- .../Pages/Extensions/UIView+Init.swift | 11 +- .../Pages/Extensions/UIView+Layout.swift | 99 +- .../Pages/RuuviOnboardCoreFeaturesCell.swift | 41 +- .../RuuviOnboardGatewayFeaturesCell.swift | 81 +- .../Pages/RuuviOnboardPages.swift | 14 +- .../Pages/RuuviOnboardSignInCell.swift | 70 +- .../Pages/RuuviOnboardStartCell.swift | 42 +- .../Pages/RuuviOnboardViewController.swift | 170 ++- .../Pages/Util/RuuviBundleUtils.swift | 6 +- .../RuuviAnalyticsImpl.swift | 39 +- .../Sources/RuuviCloud/RuuviCloud.swift | 30 +- .../RuuviCloudApiGetSensorsDenseRequest.swift | 13 +- .../RuuviCloudPNTokenRegisterRequest.swift | 13 +- .../Response/RuuviCloudApiBaseResponse.swift | 9 +- .../RuuviCloudApiGetAlertsResponse.swift | 3 +- .../RuuviCloudApiGetSensorResponse.swift | 3 +- .../RuuviCloudPNTokenListResponse.swift | 3 +- .../URLSession/RuuviCloudApiURLSession.swift | 226 +-- .../RuuviCloudFactoryPure.swift | 9 +- .../RuuviCloudPure/RuuviCloudPure.swift | 238 +-- .../SQLiteContextGRDB.swift | 7 +- Packages/RuuviCore/Package.swift | 2 +- .../Impl/DiffCalculatorImpl.swift | 15 +- .../RuuviCoreDiff/Util/Array+Extension.swift | 3 +- Packages/RuuviDFU/Package.swift | 2 +- .../Sources/RuuviDFUImpl/DfuFlasher.swift | 32 +- .../Sources/RuuviDFUImpl/DfuScanner.swift | 41 +- .../RuuviDaemon/RuuviDaemonWorker.swift | 24 +- .../RuuviDaemonCloudSyncWorker.swift | 15 +- .../Data/RuuviTagDataPruningOperation.swift | 8 +- .../RuuviTagAdvertisementDaemonBTKit.swift | 108 +- .../RuuviTagHeartbeatDaemonBTKit.swift | 229 +-- .../RuuviTagPropertiesDaemonBTKit.swift | 59 +- Packages/RuuviLocal/Package.swift | 2 +- .../Documents/ImagePersistenceDocuments.swift | 3 +- .../RuuviLocalImagesUserDefaults.swift | 33 +- .../RuuviLocalConnectionsUserDefaults.swift | 118 +- .../RuuviLocalSettingsUserDefaults.swift | 160 +- .../RuuviLocalSyncStateUserDefaults.swift | 12 +- .../MigrationManagerAlertService.swift | 30 +- .../RuuviMigrationFactoryImpl.swift | 20 +- .../RuuviMigrationFixRHAlerts.swift | 3 +- .../toRH/MigrationManagerToRH.swift | 3 +- .../toSQLite/MigrationManagerToSQLite.swift | 8 +- .../toVIPER/MigrationManagerToVIPER.swift | 53 +- .../RuuviNotificationLocal.swift | 8 +- .../RuuviNotificationLocalImpl.swift | 128 +- Packages/RuuviNotifier/Package.swift | 2 +- .../Sources/RuuviNotifier/RuuviNotifier.swift | 20 +- .../RuuviNotifierImpl+Process.swift | 124 +- .../RuuviOntology/Alert/AlertType.swift | 22 +- .../RuuviOntology/Common/Reorderable.swift | 6 +- .../RuuviOntology/Identifier/Identifier.swift | 6 +- .../RuuviTag+RuuviTagSensorRecord.swift | 28 +- .../Measurement/Measurement.swift | 3 +- .../Measurement/RuuviMeasurement.swift | 3 +- .../Notification/RuuviCloudPNToken.swift | 9 +- .../Sensor/CloudSensorDense.swift | 20 +- .../RuuviOntology/Sensor/PhysicalSensor.swift | 3 +- .../Sensor/RuuviTag/RuuviTagSensor.swift | 3 +- .../RuuviTag/RuuviTagSensorRecord.swift | 6 +- .../RuuviTagDataRealm+Extension.swift | 46 +- .../RuuviTagLatestDataRealm+Extension.swift | 46 +- .../RuuviCloudQueuedRequestSQLite.swift | 6 +- .../RuuviTagDataSQLite.swift | 20 +- .../RuuviTagLatestDataSQLite.swift | 20 +- .../RuuviPersistenceRealm.swift | 106 +- .../RuuviPersistenceSQLite.swift | 23 +- .../RuuviPoolCoordinator.swift | 15 +- .../RuuviTagLastRecordSubjectCombine.swift | 8 +- .../RuuviTagLatestRecordSubjectCombine.swift | 8 +- .../RuuviTagRecordSubjectCombine.swift | 8 +- .../SensorSettingsCombine.swift | 8 +- .../RuuviReactorImpl/RuuviReactorImpl.swift | 28 +- Packages/RuuviService/Package.swift | 18 +- .../RuuviServiceCloudNotification.swift | 38 +- .../RuuviServiceMeasurement.swift | 48 +- .../AlertPersistenceUserDefaults.swift | 27 +- .../RuuviServiceAlertImpl.swift | 27 +- .../RuuviServiceAppSettingsImpl.swift | 3 +- .../RuuviServiceAuthImpl.swift | 25 +- .../RuuviServiceCloudNotificationImpl.swift | 92 +- .../RuuviServiceCloudSyncImpl.swift | 113 +- ...uuviServiceCloudSyncRecordsOperation.swift | 26 +- .../RuuviServiceExportImpl.swift | 11 +- .../RuuviTagReadLogsOperation.swift | 75 +- .../RuuviServiceMeasurementImpl.swift | 103 +- .../RuuviServiceOwnershipImpl.swift | 56 +- .../RuuviServiceSensorPropertiesImpl.swift | 7 +- .../RuuviStorageCoordinator.swift | 12 +- Packages/RuuviUser/Package.swift | 4 +- .../RuuviUserCoordinator.swift | 8 +- intents/IntentHandler.swift | 11 +- pnservice/NotificationService.swift | 42 +- ruuvi-widgets/Assembly/WidgetAssembly.swift | 2 +- ruuvi-widgets/Helper/Extensions.swift | 6 +- ruuvi-widgets/Helper/MeasurementService.swift | 31 +- ruuvi-widgets/Model/Model+Extension.swift | 58 +- ruuvi-widgets/Model/WidgetEntry.swift | 63 +- ruuvi-widgets/Provider/WidgetProvider.swift | 96 +- ruuvi-widgets/RuuviWidgets.swift | 2 +- .../View Model/WidgetViewModel.swift | 62 +- ruuvi-widgets/View/EmptyWidgetView.swift | 26 +- ruuvi-widgets/View/SimpleWidgetView.swift | 30 +- .../View/SimpleWidgetViewCircular.swift | 40 +- .../View/SimpleWidgetViewRectangle.swift | 46 +- ruuvi-widgets/View/UnauthorizedView.swift | 16 +- station/Classes/Application/AppDelegate.swift | 57 +- .../AppState/AppStateService.swift | 6 +- .../AppState/Impl/AppStateServiceImpl.swift | 7 +- .../Features/FeatureToggleService.swift | 3 +- .../FallbackFeatureToggleProvider.swift | 3 +- .../Impl/UniversalLinkCoordinatormpl.swift | 35 +- .../Binding/NSObject+Observable.swift | 9 +- .../About/Presenter/AboutPresenter.swift | 35 +- .../Modules/About/Router/AboutRouter.swift | 3 +- .../About/View/AboutViewController.swift | 58 +- .../BackgroundSelectionPresenter.swift | 108 +- .../UI/BackgroundSelectionButtonView.swift | 63 +- ...ackgroundSelectionUploadProgressView.swift | 42 +- .../BackgroundSelectionViewController.swift | 185 ++- .../UI/BackgroundSelectionViewHeader.swift | 70 +- .../Cards/Interactor/CardsInteractor.swift | 7 +- .../Interactor/CardsInteractorInput.swift | 6 +- .../Cards/Presenter/CardsModuleInput.swift | 14 +- .../Cards/Presenter/CardsPresenter.swift | 658 +++++---- .../Dashboard/Cards/Router/CardsRouter.swift | 19 +- .../Dashboard/Cards/View/CardsViewModel.swift | 9 +- .../Cards/View/UI/CardsBackgroundView.swift | 22 +- .../Cards/View/UI/CardsIndicatorView.swift | 10 +- .../Cards/View/UI/CardsLargeImageCell.swift | 262 ++-- .../Cards/View/UI/CardsViewController.swift | 254 ++-- .../Assembly/TagChartsViewConfigurator.swift | 7 +- .../Charts/Helpers/CustomXAxisRenderer.swift | 7 +- .../Charts/Helpers/CustomYAxisRenderer.swift | 3 +- .../Charts/Helpers/YAxisValueFormatter.swift | 3 +- .../Interactor/TagChartsViewInteractor.swift | 59 +- .../TagChartsViewInteractorInput.swift | 6 +- .../Presenter/TagChartsViewModuleOutput.swift | 6 +- .../Presenter/TagChartsViewPresenter.swift | 392 ++--- .../Charts/View/TagChartsViewInput.swift | 28 +- .../Charts/View/UI/TagChartsMarkerView.swift | 59 +- .../Charts/View/UI/TagChartsView.swift | 82 +- .../View/UI/TagChartsViewController.swift | 641 +++++---- .../Assembly/DashboardModuleFactory.swift | 8 +- .../Home/Interactor/DashboardInteractor.swift | 9 +- .../Home/Presenter/DashboardPresenter.swift | 859 ++++++----- .../Home/Router/DashboardRouter.swift | 112 +- .../Home/View/DashboardImageCell.swift | 282 ++-- .../Home/View/DashboardIndicatorView.swift | 30 +- .../Home/View/DashboardPlainCell.swift | 245 ++-- .../Home/View/DashboardViewController.swift | 375 ++--- .../Dashboard/Home/View/LowBatteryView.swift | 2 +- .../Dashboard/Home/View/NoSensorView.swift | 120 +- .../Home/View/RuuviContextMenuButton.swift | 23 +- .../RuuviSimpleViewCompositionalLayout.swift | 6 +- .../MenuTableDismissTransitionAnimation.swift | 39 +- .../MenuTablePresentTransitionAnimation.swift | 36 +- .../MenuTablePresentationController.swift | 28 +- .../MenuTableTransitioningDelegate.swift | 24 +- .../MenuTableEmbededViewController.swift | 13 +- .../View/Table/MenuTableViewController.swift | 6 +- .../Presenter/MyRuuviAccountPresenter.swift | 25 +- .../View/MyRuuviAccountViewController.swift | 3 +- .../Module/Presenter/SettingsPresenter.swift | 44 +- .../Table/SettingsTableViewController.swift | 10 +- .../AppearanceSettingsPresenter.swift | 34 +- .../Presenter/ASSelectionPresenter.swift | 17 +- .../View/ASSelectionViewOutput.swift | 6 +- .../View/UI/ASSelectionTableViewCell.swift | 25 +- .../UI/ASSelectionTableViewController.swift | 29 +- ...AppearanceSettingsTableViewBasicCell.swift | 15 +- ...ppearanceSettingsTableViewController.swift | 23 +- .../Presenter/ChartSettingsPresenter.swift | 18 +- .../Chart/View/ChartSettingsViewModel.swift | 10 +- .../ChartSettingsTableViewController.swift | 6 +- .../Presenter/DefaultsPresenter.swift | 66 +- .../Table/DefaultsTableViewController.swift | 18 +- .../View/UI/DevicesTableViewCell.swift | 8 +- .../View/UI/DevicesTableViewController.swift | 69 +- .../View/SwiftUI/HeartbeatList.swift | 10 +- .../NotificationsSettingsPresenter.swift | 58 +- .../PushAlertSoundSelectionPresenter.swift | 3 +- ...PushAlertSoundSelectionTableViewCell.swift | 25 +- ...ertSoundSelectionTableViewController.swift | 26 +- .../UI/NotificationsSettingsSwitchCell.swift | 33 +- ...ficationsSettingsTableViewController.swift | 44 +- .../UI/NotificationsSettingsTextCell.swift | 17 +- .../View/UI/RuuviCloudTableViewCell.swift | 53 +- .../UI/RuuviCloudTableViewController.swift | 16 +- .../Table/SelectionTableViewController.swift | 17 +- .../Presenter/UnitSettingsPresenter.swift | 162 ++- .../UnitSettingsTableViewController.swift | 31 +- .../Share/Presenter/SharePresenter.swift | 37 +- .../View/Cells/ShareEmailTableViewCell.swift | 3 +- .../ViewController/ShareViewController.swift | 53 +- .../SignIn/Presenter/SignInModuleInput.swift | 6 +- .../SignIn/Presenter/SignInPresenter.swift | 68 +- .../Modules/SignIn/Router/SignInRouter.swift | 3 +- .../SignInBenefitsModuleOutput.swift | 18 +- .../View/SignInBenefitsViewController.swift | 142 +- .../Modules/SignIn/View/SignInViewInput.swift | 6 +- .../SignIn/View/UI/Helper/RuuviCodeView.swift | 9 +- .../View/UI/Helper/SignInVerifyView.swift | 56 +- .../SignIn/View/UI/Helper/SignInView.swift | 84 +- .../SignIn/View/UI/SignInViewController.swift | 83 +- .../Presenter/TagSettingsModuleInput.swift | 8 +- .../Presenter/TagSettingsModuleOutput.swift | 6 +- .../Presenter/TagSettingsPresenter.swift | 372 ++--- .../Router/TagSettingsRouter.swift | 15 +- .../Router/TagSettingsRouterInput.swift | 8 +- .../DFU/Interactor/DFUInteractor.swift | 25 +- .../Submodules/DFU/View/DFUViewModel.swift | 76 +- .../DFU/View/SwiftUI/DFUUIView.swift | 16 +- .../Presenter/SensorForceClaimPresenter.swift | 3 +- .../UI/SensorForceClaimViewController.swift | 56 +- .../Presenter/OffsetCorrectionPresenter.swift | 55 +- .../OffsetCorrectionAppleViewController.swift | 72 +- .../View/OffsetCorrectionViewModel.swift | 7 +- .../Owner/Presenter/OwnerPresenter.swift | 3 +- .../Owner/View/OwnerViewController.swift | 32 +- .../View/UI/SensorRemovalViewController.swift | 46 +- .../View/TagSettingsViewModel.swift | 6 +- .../RUAlertDetailsCellChildView.swift | 40 +- .../View/UI/TagSettingsAlertConfigCell.swift | 203 +-- .../TagSettingsBackgroundSelectionView.swift | 48 +- .../View/UI/TagSettingsBasicCell.swift | 53 +- .../TagSettingsExpandableSectionHeader.swift | 144 +- .../View/UI/TagSettingsFooterCell.swift | 13 +- .../View/UI/TagSettingsPlainCell.swift | 54 +- .../UI/TagSettingsSimpleSectionHeader.swift | 9 +- .../View/UI/TagSettingsSwitchCell.swift | 77 +- .../View/UI/TagSettingsViewController.swift | 1282 ++++++++++------- .../Alert/Impl/AlertPresenterImpl.swift | 8 +- .../MailComposerPresenterMessageUI.swift | 11 +- .../Sheet/PhotoPickerPresenterSheet.swift | 7 +- ...ipeDownToDismissNavigationController.swift | 18 +- ...peDownToDismissTransitioningDelegate.swift | 3 +- station/Classes/Routers/AppRouter.swift | 22 +- station/Classes/Routers/OnboardRouter.swift | 14 +- station/Extensions/Color+Ruuvi.swift | 10 +- station/Extensions/Double+Extension.swift | 3 +- station/Extensions/FileManager+Date.swift | 9 +- .../HumidityUnit+Localization.swift | 6 +- .../MeasurementAccuracyType+Extension.swift | 9 +- .../RuuviAlertSound+Extension.swift | 6 +- station/Extensions/RuuviTheme+Extension.swift | 9 +- station/Extensions/String+Replace.swift | 11 +- station/Extensions/Structs/AppUtility.swift | 7 +- .../Structs/MeasurementAccuracyTitles.swift | 7 +- .../RuuviTagBatteryStatusProvider.swift | 10 +- .../TemperatureUnit+Localization.swift | 21 +- station/Extensions/UIButton+Extension.swift | 28 +- .../UICollectionView+Extension.swift | 14 +- station/Extensions/UIColor+Extension.swift | 20 +- .../Extensions/UIDevice+ReadableModel.swift | 23 +- station/Extensions/UIFont+Extension.swift | 45 +- station/Extensions/UIImage+Extension.swift | 6 +- station/Extensions/UIImageView+Init.swift | 11 +- .../UITableViewCell+ReusableView.swift | 13 +- .../Extensions/UITextField+Extension.swift | 13 +- station/Extensions/UIView+Extension.swift | 32 +- station/Extensions/UIView+Init.swift | 11 +- station/Extensions/UIView+Layout.swift | 99 +- .../Extensions/UIViewController+Alert.swift | 7 +- station/Extensions/UnitSettingsType.swift | 6 +- .../MockLocalNotificationsManager.swift | 6 +- .../Services/Alert/AlertServiceSpec.swift | 6 +- .../MeasurementsServiceEnSpec.swift | 16 +- .../MeasurementsServiceFiSpec.swift | 16 +- .../MeasurementsServiceRuSpec.swift | 16 +- .../MeasurementsServiceSvSpec.swift | 16 +- stationTests/StationTests.swift | 16 +- stationUITests/StationUITests.swift | 4 - 294 files changed, 8530 insertions(+), 6161 deletions(-) diff --git a/.swiftformat b/.swiftformat index 61f6ea500..0b95d9516 100644 --- a/.swiftformat +++ b/.swiftformat @@ -1,2 +1,5 @@ --swiftversion 5.9 ---exclude ./Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift \ No newline at end of file +--exclude ./Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift +--disable wrapMultilineStatementBraces,trailingCommas +--xcodeindentation enabled +--wraparguments before-first \ No newline at end of file diff --git a/.swiftlint.yml b/.swiftlint.yml index a0d799147..af0e8101b 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -1,13 +1,11 @@ +trailing_comma: + mandatory_comma: true +opening_brace: + allow_multiline_func: true nesting: type_level: 3 -excluded: # paths to ignore during linting. Takes precedence over `included`. +excluded: - Carthage - Pods - - stationTests - - Package - - station/ThirdParty -disabled_rules: # rule identifiers to exclude from running - - identifier_name - - force_try +disabled_rules: - closure_parameter_position - - todo diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift index 8d51f6bc2..a5430f308 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift @@ -19,10 +19,14 @@ public struct ActivityPresenterView: View { } ActivityPresenterContentView(state: stateHolder.state) - .padding([.leading, .trailing], - stateHolder.state == .dismiss ? 0 : 12) - .padding([.top, .bottom], - stateHolder.state == .dismiss ? 0 : 12) + .padding( + [.leading, .trailing], + stateHolder.state == .dismiss ? 0 : 12 + ) + .padding( + [.top, .bottom], + stateHolder.state == .dismiss ? 0 : 12 + ) .background(Color.black.opacity(0.8)) .cornerRadius(8) .foregroundColor(.white) diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift index ccd444085..6d2204801 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift @@ -39,12 +39,10 @@ extension String { #endif if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), - let bundle = Bundle(path: path) - { + let bundle = Bundle(path: path) { return bundle.localizedString(forKey: self, value: nil, table: module) } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), - let bundle = Bundle(path: path) - { + let bundle = Bundle(path: path) { return bundle.localizedString(forKey: self, value: nil, table: module) } else { assertionFailure() diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift index ccd444085..6d2204801 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift @@ -39,12 +39,10 @@ extension String { #endif if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), - let bundle = Bundle(path: path) - { + let bundle = Bundle(path: path) { return bundle.localizedString(forKey: self, value: nil, table: module) } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), - let bundle = Bundle(path: path) - { + let bundle = Bundle(path: path) { return bundle.localizedString(forKey: self, value: nil, table: module) } else { assertionFailure() diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UITableViewCell+ReusableView.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UITableViewCell+ReusableView.swift index 11a546dff..571174aae 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UITableViewCell+ReusableView.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UITableViewCell+ReusableView.swift @@ -17,17 +17,20 @@ extension UITableViewCell: ReusableView {} extension UITableViewHeaderFooterView: ReusableView {} extension UITableView { - func dequeueReusableCell(with _: T.Type, - for indexPath: IndexPath) -> T - { - guard let cell = dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as? T else { + func dequeueReusableCell( + with _: T.Type, + for indexPath: IndexPath + ) -> T { + guard let cell = dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as? T + else { preconditionFailure("Unable to dequeue \(T.description()) for indexPath: \(indexPath)") } return cell } func dequeueReusableHeaderFooterView(with _: T.Type) -> T { - guard let cell = dequeueReusableHeaderFooterView(withIdentifier: T.reuseIdentifier) as? T else { + guard let cell = dequeueReusableHeaderFooterView(withIdentifier: T.reuseIdentifier) as? T + else { preconditionFailure("Unable to dequeue \(T.description())") } return cell diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UIViewController+Alert.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UIViewController+Alert.swift index 8c53be715..ef5362fea 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UIViewController+Alert.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UIViewController+Alert.swift @@ -1,9 +1,10 @@ import UIKit extension UIViewController { - func showAlert(title: String? = nil, - message: String? = nil) - { + func showAlert( + title: String? = nil, + message: String? = nil + ) { let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) alertVC.addAction(UIAlertAction(title: "OK".localized(for: Self.self), style: .cancel, handler: nil)) present(alertVC, animated: true) diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift index f6e59a52e..d91669c98 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift @@ -239,7 +239,8 @@ extension DiscoverPresenter: DiscoverViewOutput { } func viewDidAddDeviceWithNFC(with tag: NFCSensor?) { - guard let displayName = displayName(for: tag) else { + guard let displayName = displayName(for: tag) + else { return } if let ruuviTag = ruuviTags.first(where: { $0.mac != nil && $0.mac == tag?.macId }) { @@ -381,12 +382,10 @@ extension DiscoverPresenter { let filtered = ruuviTags.filter { tag in !persistedSensors.contains(where: { persistedTag in if let tagLuid = tag.luid?.value, - let persistedTagLuid = persistedTag.luid?.value - { + let persistedTagLuid = persistedTag.luid?.value { tagLuid == persistedTagLuid } else if let tagMacId = tag.mac, - let persistedTagMacId = persistedTag.macId?.value - { + let persistedTagMacId = persistedTag.macId?.value { tagMacId == persistedTagMacId } else { false @@ -428,7 +427,8 @@ extension DiscoverPresenter { } private func displayName(for tag: NFCSensor?) -> String? { - guard let tag else { + guard let tag + else { return nil } return "DiscoverTable.RuuviDevice.prefix".localized(for: Self.self) diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift index a3e6d1d77..48f757007 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift @@ -56,9 +56,11 @@ class DiscoverTableHeaderView: UIView { headerView.addSubview(nfcButton) } - setupLayout(headerView: headerView, - descriptionLabel: descriptionLabel, - button: nfcButton) + setupLayout( + headerView: headerView, + descriptionLabel: descriptionLabel, + button: nfcButton + ) } private func createHeaderView() -> UIView { @@ -98,9 +100,11 @@ class DiscoverTableHeaderView: UIView { button.titleLabel?.font = font } button.tintColor = UIColor(named: "RuuviTintColor") - button.addTarget(self, - action: #selector(handleButtonTap), - for: .touchUpInside) + button.addTarget( + self, + action: #selector(handleButtonTap), + for: .touchUpInside + ) return button } @@ -140,7 +144,7 @@ class DiscoverTableHeaderView: UIView { ]) } else { NSLayoutConstraint.activate([ - descriptionLabelBottomConstraint, + descriptionLabelBottomConstraint ]) } } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift index 1ee5ddd3a..fea137aae 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift @@ -58,10 +58,13 @@ extension DiscoverTableViewController: DiscoverViewInput { let title = "DiscoverTable.BluetoothDisabledAlert.title".localized(for: Self.self) let message = "DiscoverTable.BluetoothDisabledAlert.message".localized(for: Self.self) let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "PermissionPresenter.settings".localized(for: Self.self), - style: .default, handler: { [weak self] _ in - self?.takeUserToBTSettings(userDeclined: userDeclined) - })) + alertVC.addAction(UIAlertAction( + title: "PermissionPresenter.settings".localized(for: Self.self), + style: .default, + handler: { [weak self] _ in + self?.takeUserToBTSettings(userDeclined: userDeclined) + } + )) alertVC.addAction(UIAlertAction(title: "OK".localized(for: Self.self), style: .cancel, handler: nil)) present(alertVC, animated: true) } @@ -118,34 +121,49 @@ extension DiscoverTableViewController: DiscoverViewInput { alertVC.setValue(messageText, forKey: "attributedMessage") if showAddSensor { - alertVC.addAction(UIAlertAction(title: "add_sensor".localized(for: Self.self), - style: .default, handler: { [weak self] _ in - self?.output.viewDidAddDeviceWithNFC(with: tag) - })) + alertVC.addAction(UIAlertAction( + title: "add_sensor".localized(for: Self.self), + style: .default, + handler: { [weak self] _ in + self?.output.viewDidAddDeviceWithNFC(with: tag) + } + )) } - alertVC.addAction(UIAlertAction(title: "copy_mac_address".localized(for: Self.self), - style: .default, handler: { [weak self] _ in - self?.output.viewDidACopyMacAddress(of: tag) - })) + alertVC.addAction(UIAlertAction( + title: "copy_mac_address".localized(for: Self.self), + style: .default, + handler: { [weak self] _ in + self?.output.viewDidACopyMacAddress(of: tag) + } + )) - alertVC.addAction(UIAlertAction(title: "copy_unique_id".localized(for: Self.self), - style: .default, handler: { [weak self] _ in - self?.output.viewDidACopySecret(of: tag) - })) + alertVC.addAction(UIAlertAction( + title: "copy_unique_id".localized(for: Self.self), + style: .default, + handler: { [weak self] _ in + self?.output.viewDidACopySecret(of: tag) + } + )) if showGoToSensor { - alertVC.addAction(UIAlertAction(title: "go_to_sensor".localized(for: Self.self), - style: .default, handler: { [weak self] _ in - self?.output.viewDidGoToSensor(with: tag) - })) + alertVC.addAction(UIAlertAction( + title: "go_to_sensor".localized(for: Self.self), + style: .default, + handler: { [weak self] _ in + self?.output.viewDidGoToSensor(with: tag) + } + )) } if showUpgradeFirmware { - alertVC.addAction(UIAlertAction(title: "upgrade_firmware".localized(for: Self.self), - style: .default, handler: { [weak self] _ in - self?.output.viewDidAskToUpgradeFirmware(of: tag) - })) + alertVC.addAction(UIAlertAction( + title: "upgrade_firmware".localized(for: Self.self), + style: .default, + handler: { [weak self] _ in + self?.output.viewDidAskToUpgradeFirmware(of: tag) + } + )) } alertVC.addAction(UIAlertAction(title: "close".localized(for: Self.self), style: .cancel, handler: nil)) @@ -365,17 +383,19 @@ extension DiscoverTableViewController { // MARK: - NFCNDEFReaderSessionDelegate extension DiscoverTableViewController: NFCNDEFReaderSessionDelegate { - func readerSession(_: NFCNDEFReaderSession, - didInvalidateWithError _: Error) - { + func readerSession( + _: NFCNDEFReaderSession, + didInvalidateWithError _: Error + ) { DispatchQueue.main.async { [weak self] in self?.stopNFCSession() } } - func readerSession(_: NFCNDEFReaderSession, - didDetectNDEFs messages: [NFCNDEFMessage]) - { + func readerSession( + _: NFCNDEFReaderSession, + didDetectNDEFs messages: [NFCNDEFMessage] + ) { DispatchQueue.main.async { [weak self] in self?.output?.viewDidReceiveNFCMessages(messages: messages) } diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/URLSession+downloadTaskPublisher.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/URLSession+downloadTaskPublisher.swift index 7bda19c6c..2c1b9efb9 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/URLSession+downloadTaskPublisher.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Extensions/URLSession+downloadTaskPublisher.swift @@ -31,8 +31,7 @@ public extension URLSession { public func receive(subscriber: S) where S: Subscriber, DownloadTaskPublisher.Failure == S.Failure, - DownloadTaskPublisher.Output == S.Input - { + DownloadTaskPublisher.Output == S.Input { let subscription = DownloadTaskSubscription( subscriber: subscriber, session: session, @@ -47,8 +46,7 @@ public extension URLSession { extension URLSession { final class DownloadTaskSubscription: Subscription where SubscriberType.Input == DownloadResponse, - SubscriberType.Failure == URLError - { + SubscriberType.Failure == URLError { private var subscriber: SubscriberType? private weak var session: URLSession? private var request: URLRequest @@ -73,10 +71,12 @@ extension URLSession { } func request(_ demand: Subscribers.Demand) { - guard demand > 0 else { + guard demand > 0 + else { return } - guard task == nil else { + guard task == nil + else { return } self.task = session?.downloadTask(with: request) { [weak self] url, response, error in @@ -84,11 +84,13 @@ extension URLSession { self?.subscriber?.receive(completion: .failure(error)) return } - guard response != nil else { + guard response != nil + else { self?.subscriber?.receive(completion: .failure(URLError(.badServerResponse))) return } - guard let url else { + guard let url + else { self?.subscriber?.receive(completion: .failure(URLError(.badURL))) return } diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift index 478377534..00bd99755 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift @@ -34,16 +34,17 @@ final class FirmwareInteractor { func loadLatestGitHubRelease() -> AnyPublisher { let urlString = "https://api.github.com/repos/ruuvi/ruuvi.firmware.c/releases/latest" - guard let url = URL(string: urlString) else { + guard let url = URL(string: urlString) + else { return Fail(error: URLError(.badURL)).eraseToAnyPublisher() } return URLSession.shared.dataTaskPublisher(for: url) - .map(\.data) - .decode(type: GitHubRelease.self, decoder: JSONDecoder()) - .catch { error in Fail(error: error) } - .receive(on: RunLoop.main) - .eraseToAnyPublisher() + .map(\.data) + .decode(type: GitHubRelease.self, decoder: JSONDecoder()) + .catch { error in Fail(error: error) } + .receive(on: RunLoop.main) + .eraseToAnyPublisher() } func serveCurrentRelease(uuid: String) -> Future { @@ -66,12 +67,14 @@ final class FirmwareInteractor { } func read(release: GitHubRelease) -> AnyPublisher<(appUrl: URL, fullUrl: URL), Error> { - guard let fullName = release.defaultFullZipName else { + guard let fullName = release.defaultFullZipName + else { return Fail<(appUrl: URL, fullUrl: URL), Error>( error: FirmwareError.failedToGetFirmwareName ).eraseToAnyPublisher() } - guard let appName = release.defaultAppZipName else { + guard let appName = release.defaultAppZipName + else { return Fail<(appUrl: URL, fullUrl: URL), Error>( error: FirmwareError.failedToGetFirmwareName ).eraseToAnyPublisher() @@ -179,7 +182,8 @@ final class FirmwareInteractor { firmwareUrl = fullUrl } - guard let firmware = ruuviDFU.firmwareFromUrl(url: firmwareUrl) else { + guard let firmware = ruuviDFU.firmwareFromUrl(url: firmwareUrl) + else { return Fail(error: FirmwareError.failedToConstructFirmwareFromFile).eraseToAnyPublisher() } return ruuviDFU.flashFirmware(uuid: uuid, with: firmware).eraseToAnyPublisher() diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Repository/FirmwareRepository.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Repository/FirmwareRepository.swift index 90c5f51d5..153a1a097 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Repository/FirmwareRepository.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Repository/FirmwareRepository.swift @@ -22,8 +22,7 @@ public final class FirmwareRepositoryImpl: FirmwareRepository { DispatchQueue.global(qos: .userInitiated).async { [weak self] in do { if let dstUrl = try self?.getFirmwareDirectory().appendingPathComponent(name), - FileManager.default.fileExists(atPath: dstUrl.path) - { + FileManager.default.fileExists(atPath: dstUrl.path) { promise(.success(dstUrl)) } else { promise(.failure(FirmwareRepositoryError.fileNotFound)) @@ -46,7 +45,8 @@ public final class FirmwareRepositoryImpl: FirmwareRepository { } private func getFirmwareDirectory() throws -> URL { - guard let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { + guard let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first + else { throw FirmwareRepositoryError.failedToGetDocumentsDirectory } let dir = docDir.appendingPathComponent(fwDir, isDirectory: true) diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift index 8ff16d74a..6293a7b95 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift @@ -63,7 +63,8 @@ extension FirmwareViewModel { func whenLoading() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in - guard case .loading = state, let self else { + guard case .loading = state, let self + else { return Empty().eraseToAnyPublisher() } return interactor.loadLatestGitHubRelease() @@ -76,7 +77,8 @@ extension FirmwareViewModel { func whenServing() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in - guard case .serving = state, let self else { + guard case .serving = state, let self + else { return Empty().eraseToAnyPublisher() } if let currentFirmware { @@ -117,7 +119,8 @@ extension FirmwareViewModel { func whenDownloading() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in - guard case let .downloading(latestRelease, currentRelease) = state, let self else { + guard case let .downloading(latestRelease, currentRelease) = state, let self + else { return Empty().eraseToAnyPublisher() } return interactor.download(release: latestRelease) @@ -188,7 +191,8 @@ extension FirmwareViewModel { uuid, appUrl, fullUrl - ) = state, let sSelf = self else { + ) = state, let sSelf = self + else { return Empty().eraseToAnyPublisher() } return sSelf.interactor.flash( diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift index ccd444085..6d2204801 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift @@ -39,12 +39,10 @@ extension String { #endif if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), - let bundle = Bundle(path: path) - { + let bundle = Bundle(path: path) { return bundle.localizedString(forKey: self, value: nil, table: module) } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), - let bundle = Bundle(path: path) - { + let bundle = Bundle(path: path) { return bundle.localizedString(forKey: self, value: nil, table: module) } else { assertionFailure() diff --git a/Modules/RuuviOnboard/Package.swift b/Modules/RuuviOnboard/Package.swift index 41e8c7576..5f7e621a9 100644 --- a/Modules/RuuviOnboard/Package.swift +++ b/Modules/RuuviOnboard/Package.swift @@ -14,7 +14,7 @@ let package = Package( ), ], dependencies: [ - .package(path: "../../Packages/RuuviUser"), + .package(path: "../../Packages/RuuviUser") ], targets: [ .target( diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIButton+Extension.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIButton+Extension.swift index fde26ce82..49a4e0b40 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIButton+Extension.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIButton+Extension.swift @@ -5,16 +5,24 @@ extension UIButton { guard let text = titleLabel?.text, let titleColor = titleColor(for: .normal) else { return } let attributedString = NSMutableAttributedString(string: text) - attributedString.addAttribute(NSAttributedString.Key.underlineColor, - value: titleColor, - range: NSRange(location: 0, - length: text.count)) - attributedString.addAttribute(NSAttributedString.Key.foregroundColor, - value: titleColor, - range: NSRange(location: 0, length: text.count)) - attributedString.addAttribute(NSAttributedString.Key.underlineStyle, - value: NSUnderlineStyle.single.rawValue, - range: NSRange(location: 0, length: text.count)) + attributedString.addAttribute( + NSAttributedString.Key.underlineColor, + value: titleColor, + range: NSRange( + location: 0, + length: text.count + ) + ) + attributedString.addAttribute( + NSAttributedString.Key.foregroundColor, + value: titleColor, + range: NSRange(location: 0, length: text.count) + ) + attributedString.addAttribute( + NSAttributedString.Key.underlineStyle, + value: NSUnderlineStyle.single.rawValue, + range: NSRange(location: 0, length: text.count) + ) setAttributedTitle(attributedString, for: .normal) } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIFont+Extension.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIFont+Extension.swift index 4f965e4c1..6f0b4c83a 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIFont+Extension.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIFont+Extension.swift @@ -20,30 +20,41 @@ extension UIFont { // MARK: - FUNCTIONS - static func Montserrat(_ type: MontserratStyles = .regular, - size: CGFloat = UIFont.systemFontSize) -> UIFont - { - UIFont(name: "Montserrat-\(type.rawValue)", - size: size.adjustedSize()) ?? + static func Montserrat( + _ type: MontserratStyles = .regular, + size: CGFloat = UIFont.systemFontSize + ) -> UIFont { + UIFont( + name: "Montserrat-\(type.rawValue)", + size: size.adjustedSize() + ) ?? UIFont.systemFont(ofSize: size.adjustedSize()) } - static func Muli(_ type: MuliStyles = .regular, - size: CGFloat = UIFont.systemFontSize) -> UIFont - { + static func Muli( + _ type: MuliStyles = .regular, + size: CGFloat = UIFont.systemFontSize + ) -> UIFont { let prefix = type == .semiBoldItalic ? "Mulish" : "Muli" - return UIFont(name: "\(prefix)-\(type.rawValue)", - size: size.adjustedSize()) ?? + return UIFont( + name: "\(prefix)-\(type.rawValue)", + size: size.adjustedSize() + ) ?? UIFont.systemFont(ofSize: size.adjustedSize()) } - static func Oswald(_ type: OswaldStyles = .extraLight, - size: CGFloat = UIFont.systemFontSize) -> UIFont - { - UIFont(name: "Oswald-\(type.rawValue)", - size: size.adjustedSize()) ?? - UIFont.systemFont(ofSize: size.adjustedSize(), - weight: .ultraLight) + static func Oswald( + _ type: OswaldStyles = .extraLight, + size: CGFloat = UIFont.systemFontSize + ) -> UIFont { + UIFont( + name: "Oswald-\(type.rawValue)", + size: size.adjustedSize() + ) ?? + UIFont.systemFont( + ofSize: size.adjustedSize(), + weight: .ultraLight + ) } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIImageView+Init.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIImageView+Init.swift index d13e35b68..2cfc6f435 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIImageView+Init.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIImageView+Init.swift @@ -1,11 +1,12 @@ import UIKit extension UIImageView { - convenience init(image: UIImage? = nil, - backgroundColor: UIColor = .clear, - contentMode: ContentMode = .scaleAspectFill, - cornerRadius: CGFloat = 0) - { + convenience init( + image: UIImage? = nil, + backgroundColor: UIColor = .clear, + contentMode: ContentMode = .scaleAspectFill, + cornerRadius: CGFloat = 0 + ) { self.init() self.image = image self.backgroundColor = backgroundColor diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UILabel+Init.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UILabel+Init.swift index f003dae89..8c84ffd2e 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UILabel+Init.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UILabel+Init.swift @@ -1,12 +1,13 @@ import UIKit extension UILabel { - convenience init(text: String, - textColor: UIColor = .label, - font: UIFont = .Muli(.regular, size: 16), - numberOfLines: Int = 0, - alignment: NSTextAlignment = .left) - { + convenience init( + text: String, + textColor: UIColor = .label, + font: UIFont = .Muli(.regular, size: 16), + numberOfLines: Int = 0, + alignment: NSTextAlignment = .left + ) { self.init() self.text = text self.textColor = textColor diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIView+Init.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIView+Init.swift index 046e18f21..608bde0cf 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIView+Init.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIView+Init.swift @@ -1,11 +1,12 @@ import UIKit extension UIView { - convenience init(color: UIColor? = .clear, - cornerRadius: CGFloat = 0, - borderWidth: CGFloat = 0, - borderColor: UIColor = .clear) - { + convenience init( + color: UIColor? = .clear, + cornerRadius: CGFloat = 0, + borderWidth: CGFloat = 0, + borderColor: UIColor = .clear + ) { self.init() layer.cornerRadius = cornerRadius layer.borderWidth = borderWidth diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIView+Layout.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIView+Layout.swift index 3369cba98..f00573bdd 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIView+Layout.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Extensions/UIView+Layout.swift @@ -5,33 +5,43 @@ import UIKit extension UIView { @discardableResult - func anchor(top: NSLayoutYAxisAnchor?, - leading: NSLayoutXAxisAnchor?, - bottom: NSLayoutYAxisAnchor?, - trailing: NSLayoutXAxisAnchor?, - padding: UIEdgeInsets = .zero, size: CGSize = .zero) -> AnchoredConstraints - { + func anchor( + top: NSLayoutYAxisAnchor?, + leading: NSLayoutXAxisAnchor?, + bottom: NSLayoutYAxisAnchor?, + trailing: NSLayoutXAxisAnchor?, + padding: UIEdgeInsets = .zero, + size: CGSize = .zero + ) -> AnchoredConstraints { translatesAutoresizingMaskIntoConstraints = false var anchoredConstraints = AnchoredConstraints() if let top { - anchoredConstraints.top = topAnchor.constraint(equalTo: top, - constant: padding.top) + anchoredConstraints.top = topAnchor.constraint( + equalTo: top, + constant: padding.top + ) } if let leading { - anchoredConstraints.leading = leadingAnchor.constraint(equalTo: leading, - constant: padding.left) + anchoredConstraints.leading = leadingAnchor.constraint( + equalTo: leading, + constant: padding.left + ) } if let bottom { - anchoredConstraints.bottom = bottomAnchor.constraint(equalTo: bottom, - constant: -padding.bottom) + anchoredConstraints.bottom = bottomAnchor.constraint( + equalTo: bottom, + constant: -padding.bottom + ) } if let trailing { - anchoredConstraints.trailing = trailingAnchor.constraint(equalTo: trailing, - constant: -padding.right) + anchoredConstraints.trailing = trailingAnchor.constraint( + equalTo: trailing, + constant: -padding.right + ) } if size.width != 0 { @@ -42,24 +52,27 @@ extension UIView { anchoredConstraints.height = heightAnchor.constraint(equalToConstant: size.height) } - [anchoredConstraints.top, - anchoredConstraints.leading, - anchoredConstraints.bottom, - anchoredConstraints.trailing, - anchoredConstraints.width, - anchoredConstraints.height].forEach { $0?.isActive = true } + [ + anchoredConstraints.top, + anchoredConstraints.leading, + anchoredConstraints.bottom, + anchoredConstraints.trailing, + anchoredConstraints.width, + anchoredConstraints.height, + ].forEach { $0?.isActive = true } return anchoredConstraints } @discardableResult - func anchorLeading(top: NSLayoutYAxisAnchor?, - leading: NSLayoutXAxisAnchor?, - bottom: NSLayoutYAxisAnchor?, - trailing: NSLayoutXAxisAnchor?, - padding: UIEdgeInsets = .zero, - size: CGSize = .zero) -> AnchoredConstraints - { + func anchorLeading( + top: NSLayoutYAxisAnchor?, + leading: NSLayoutXAxisAnchor?, + bottom: NSLayoutYAxisAnchor?, + trailing: NSLayoutXAxisAnchor?, + padding: UIEdgeInsets = .zero, + size: CGSize = .zero + ) -> AnchoredConstraints { translatesAutoresizingMaskIntoConstraints = false var anchoredConstraints = AnchoredConstraints() @@ -69,20 +82,26 @@ extension UIView { if let leading { anchoredConstraints.leading = - leadingAnchor.constraint(greaterThanOrEqualTo: leading, - constant: padding.left) + leadingAnchor.constraint( + greaterThanOrEqualTo: leading, + constant: padding.left + ) } if let bottom { anchoredConstraints.bottom = - bottomAnchor.constraint(equalTo: bottom, - constant: -padding.bottom) + bottomAnchor.constraint( + equalTo: bottom, + constant: -padding.bottom + ) } if let trailing { anchoredConstraints.trailing = - trailingAnchor.constraint(lessThanOrEqualTo: trailing, - constant: -padding.right) + trailingAnchor.constraint( + lessThanOrEqualTo: trailing, + constant: -padding.right + ) } if size.width != 0 { @@ -93,12 +112,14 @@ extension UIView { anchoredConstraints.height = heightAnchor.constraint(equalToConstant: size.height) } - [anchoredConstraints.top, - anchoredConstraints.leading, - anchoredConstraints.bottom, - anchoredConstraints.trailing, - anchoredConstraints.width, - anchoredConstraints.height].forEach { $0?.isActive = true } + [ + anchoredConstraints.top, + anchoredConstraints.leading, + anchoredConstraints.bottom, + anchoredConstraints.trailing, + anchoredConstraints.width, + anchoredConstraints.height, + ].forEach { $0?.isActive = true } return anchoredConstraints } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardCoreFeaturesCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardCoreFeaturesCell.swift index d058199fc..fac8a36cf 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardCoreFeaturesCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardCoreFeaturesCell.swift @@ -2,8 +2,10 @@ import UIKit class RuuviOnboardCoreFeaturesCell: UICollectionViewCell { private lazy var appImageView: UIImageView = { - let iv = UIImageView(image: nil, - contentMode: .scaleAspectFit) + let iv = UIImageView( + image: nil, + contentMode: .scaleAspectFit + ) iv.backgroundColor = .clear return iv }() @@ -44,26 +46,34 @@ private extension RuuviOnboardCoreFeaturesCell { container.fillSuperview() let textStack = UIStackView(arrangedSubviews: [ - subtitleLabel, titleLabel, + subtitleLabel, titleLabel ]) textStack.axis = .vertical textStack.distribution = .fillProportionally textStack.spacing = 12 container.addSubview(textStack) - textStack.anchor(top: container.safeTopAnchor, - leading: container.safeLeadingAnchor, - bottom: nil, - trailing: container.safeTrailingAnchor, - padding: .init(top: 44 + 12, left: 16, - bottom: 0, right: 16)) + textStack.anchor( + top: container.safeTopAnchor, + leading: container.safeLeadingAnchor, + bottom: nil, + trailing: container.safeTrailingAnchor, + padding: .init( + top: 44 + 12, + left: 16, + bottom: 0, + right: 16 + ) + ) container.addSubview(appImageView) - appImageView.anchor(top: textStack.bottomAnchor, - leading: container.safeLeadingAnchor, - bottom: nil, - trailing: container.safeTrailingAnchor, - padding: .init(top: 30, left: 0, bottom: 0, right: 0)) + appImageView.anchor( + top: textStack.bottomAnchor, + leading: container.safeLeadingAnchor, + bottom: nil, + trailing: container.safeTrailingAnchor, + padding: .init(top: 30, left: 0, bottom: 0, right: 0) + ) appImageView.bottomAnchor.constraint(lessThanOrEqualTo: container.bottomAnchor).isActive = true } } @@ -81,7 +91,8 @@ extension RuuviOnboardCoreFeaturesCell { titleLabel.text = viewModel.title subtitleLabel.text = viewModel.subtitle - guard let image = viewModel.image else { + guard let image = viewModel.image + else { return } appImageView.image = UIImage.named(image, for: Self.self) diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift index 31a73c2f3..891407685 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift @@ -2,8 +2,10 @@ import UIKit class RuuviOnboardGatewayFeaturesCell: UICollectionViewCell { private lazy var appImageView: UIImageView = { - let iv = UIImageView(image: nil, - contentMode: .scaleAspectFit) + let iv = UIImageView( + image: nil, + contentMode: .scaleAspectFit + ) iv.backgroundColor = .clear return iv }() @@ -27,9 +29,13 @@ class RuuviOnboardGatewayFeaturesCell: UICollectionViewCell { }() private lazy var gateWayImageView: UIImageView = { - let iv = UIImageView(image: UIImage.named(RuuviAssets.gateway, - for: Self.self), - contentMode: .scaleAspectFit) + let iv = UIImageView( + image: UIImage.named( + RuuviAssets.gateway, + for: Self.self + ), + contentMode: .scaleAspectFit + ) iv.backgroundColor = .clear return iv }() @@ -63,26 +69,34 @@ private extension RuuviOnboardGatewayFeaturesCell { container.fillSuperview() let textStack = UIStackView(arrangedSubviews: [ - subtitleLabel, titleLabel, + subtitleLabel, titleLabel ]) textStack.axis = .vertical textStack.distribution = .fillProportionally textStack.spacing = 12 container.addSubview(textStack) - textStack.anchor(top: container.safeTopAnchor, - leading: container.safeLeadingAnchor, - bottom: nil, - trailing: container.safeTrailingAnchor, - padding: .init(top: 44 + 12, left: 16, - bottom: 0, right: 16)) + textStack.anchor( + top: container.safeTopAnchor, + leading: container.safeLeadingAnchor, + bottom: nil, + trailing: container.safeTrailingAnchor, + padding: .init( + top: 44 + 12, + left: 16, + bottom: 0, + right: 16 + ) + ) let appImageViewContainer = UIView(color: .clear) container.addSubview(appImageViewContainer) - appImageViewContainer.anchor(top: textStack.bottomAnchor, - leading: container.safeLeadingAnchor, - bottom: nil, - trailing: container.safeTrailingAnchor) + appImageViewContainer.anchor( + top: textStack.bottomAnchor, + leading: container.safeLeadingAnchor, + bottom: nil, + trailing: container.safeTrailingAnchor + ) appImageViewContainer.addSubview(appImageView) if UIDevice.isTablet() { @@ -93,13 +107,15 @@ private extension RuuviOnboardGatewayFeaturesCell { let footerView = UIView(color: RuuviAssets.ruuviTintColor) container.addSubview(footerView) - footerView.anchor(top: appImageViewContainer.bottomAnchor, - leading: container.leadingAnchor, - bottom: container.bottomAnchor, - trailing: container.trailingAnchor) + footerView.anchor( + top: appImageViewContainer.bottomAnchor, + leading: container.leadingAnchor, + bottom: container.bottomAnchor, + trailing: container.trailingAnchor + ) let stackView = UIStackView(arrangedSubviews: [ - gateWayImageView, gatewayRequireLabel, + gateWayImageView, gatewayRequireLabel ]) stackView.distribution = .fillProportionally stackView.spacing = 8 @@ -107,14 +123,18 @@ private extension RuuviOnboardGatewayFeaturesCell { gateWayImageView.size(width: 70, height: 60) footerView.addSubview(stackView) - stackView.anchor(top: footerView.topAnchor, - leading: nil, - bottom: footerView.safeBottomAnchor, - trailing: nil, - padding: .init(top: 12, - left: 0, - bottom: bottomSafeAreaHeight > 0 ? 0 : 12, - right: 0)) + stackView.anchor( + top: footerView.topAnchor, + leading: nil, + bottom: footerView.safeBottomAnchor, + trailing: nil, + padding: .init( + top: 12, + left: 0, + bottom: bottomSafeAreaHeight > 0 ? 0 : 12, + right: 0 + ) + ) stackView.leadingAnchor.constraint( lessThanOrEqualTo: footerView.leadingAnchor, constant: 20 @@ -140,7 +160,8 @@ extension RuuviOnboardGatewayFeaturesCell { titleLabel.text = viewModel.title subtitleLabel.text = viewModel.subtitle - guard let image = viewModel.image else { + guard let image = viewModel.image + else { return } appImageView.image = UIImage.named(image, for: Self.self) diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardPages.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardPages.swift index 7df1292a7..1df5cb0bc 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardPages.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardPages.swift @@ -27,15 +27,17 @@ public final class RuuviOnboardPages: RuuviOnboard { } extension RuuviOnboardPages: RuuviOnboardViewControllerOutput { - func ruuviOnboardPages(_: RuuviOnboardViewController, - didFinish _: Any?) - { + func ruuviOnboardPages( + _: RuuviOnboardViewController, + didFinish _: Any? + ) { output?.ruuviOnboardDidFinish(self) } - func ruuviOnboardCloudSignIn(_: RuuviOnboardViewController, - didPresentSignIn _: Any?) - { + func ruuviOnboardCloudSignIn( + _: RuuviOnboardViewController, + didPresentSignIn _: Any? + ) { output?.ruuviOnboardDidShowSignIn(self) } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift index 340b315bd..cbded7754 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift @@ -39,13 +39,17 @@ class RuuviOnboardSignInCell: UICollectionViewCell { private lazy var continueButton: UIButton = { let button = UIButton(color: RuuviAssets.ruuviTintColor, cornerRadius: 22) - button.setTitle("onboarding_continue".localized(for: Self.self), - for: .normal) + button.setTitle( + "onboarding_continue".localized(for: Self.self), + for: .normal + ) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, size: 16) - button.addTarget(self, - action: #selector(handleContinueTap), - for: .touchUpInside) + button.addTarget( + self, + action: #selector(handleContinueTap), + for: .touchUpInside + ) return button }() @@ -67,43 +71,55 @@ private extension RuuviOnboardSignInCell { container.fillSuperview() let textStack = UIStackView(arrangedSubviews: [ - titleLabel, subtitleLabel, + titleLabel, subtitleLabel ]) textStack.axis = .vertical textStack.distribution = .fillProportionally textStack.spacing = 12 container.addSubview(textStack) - textStack.anchor(top: container.safeTopAnchor, - leading: container.safeLeadingAnchor, - bottom: nil, - trailing: container.safeTrailingAnchor, - padding: .init(top: 44 + 12, left: 16, - bottom: 0, right: 16)) + textStack.anchor( + top: container.safeTopAnchor, + leading: container.safeLeadingAnchor, + bottom: nil, + trailing: container.safeTrailingAnchor, + padding: .init( + top: 44 + 12, + left: 16, + bottom: 0, + right: 16 + ) + ) container.addSubview(continueButton) - continueButton.anchor(top: textStack.bottomAnchor, - leading: nil, - bottom: nil, - trailing: nil, - padding: .init(top: 20, left: 0, bottom: 0, right: 0), - size: .init(width: 0, height: 44)) + continueButton.anchor( + top: textStack.bottomAnchor, + leading: nil, + bottom: nil, + trailing: nil, + padding: .init(top: 20, left: 0, bottom: 0, right: 0), + size: .init(width: 0, height: 44) + ) continueButton.widthAnchor.constraint(greaterThanOrEqualToConstant: 140).isActive = true continueButton.centerXInSuperview() let beaverContainerView = UIView(color: .clear) container.addSubview(beaverContainerView) - beaverContainerView.anchor(top: continueButton.bottomAnchor, - leading: container.leadingAnchor, - bottom: container.bottomAnchor, - trailing: container.trailingAnchor) + beaverContainerView.anchor( + top: continueButton.bottomAnchor, + leading: container.leadingAnchor, + bottom: container.bottomAnchor, + trailing: container.trailingAnchor + ) beaverContainerView.addSubview(beaverImageView) - beaverImageView.anchor(top: nil, - leading: beaverContainerView.safeLeadingAnchor, - bottom: nil, - trailing: beaverContainerView.safeTrailingAnchor, - size: .init(width: 0, height: bounds.height / 2)) + beaverImageView.anchor( + top: nil, + leading: beaverContainerView.safeLeadingAnchor, + bottom: nil, + trailing: beaverContainerView.safeTrailingAnchor, + size: .init(width: 0, height: bounds.height / 2) + ) beaverImageView.centerYInSuperview() } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardStartCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardStartCell.swift index 2b68288fe..3e55256fd 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardStartCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardStartCell.swift @@ -58,33 +58,43 @@ private extension RuuviOnboardStartCell { container.fillSuperview() let textStack = UIStackView(arrangedSubviews: [ - titleLabel, subtitleLabel, sub_subtitleLabel, + titleLabel, subtitleLabel, sub_subtitleLabel ]) textStack.axis = .vertical textStack.distribution = .fill textStack.spacing = 12 container.addSubview(textStack) - textStack.anchor(top: container.safeTopAnchor, - leading: container.safeLeadingAnchor, - bottom: nil, - trailing: container.safeTrailingAnchor, - padding: .init(top: 44 + 12, left: 16, - bottom: 0, right: 16)) + textStack.anchor( + top: container.safeTopAnchor, + leading: container.safeLeadingAnchor, + bottom: nil, + trailing: container.safeTrailingAnchor, + padding: .init( + top: 44 + 12, + left: 16, + bottom: 0, + right: 16 + ) + ) let beaverContainerView = UIView(color: .clear) container.addSubview(beaverContainerView) - beaverContainerView.anchor(top: textStack.bottomAnchor, - leading: container.leadingAnchor, - bottom: container.bottomAnchor, - trailing: container.trailingAnchor) + beaverContainerView.anchor( + top: textStack.bottomAnchor, + leading: container.leadingAnchor, + bottom: container.bottomAnchor, + trailing: container.trailingAnchor + ) beaverContainerView.addSubview(beaverImageView) - beaverImageView.anchor(top: nil, - leading: beaverContainerView.safeLeadingAnchor, - bottom: nil, - trailing: beaverContainerView.safeTrailingAnchor, - size: .init(width: 0, height: bounds.height / 2)) + beaverImageView.anchor( + top: nil, + leading: beaverContainerView.safeLeadingAnchor, + bottom: nil, + trailing: beaverContainerView.safeTrailingAnchor, + size: .init(width: 0, height: bounds.height / 2) + ) beaverImageView.centerYInSuperview() } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift index 0ba34bd93..d9b5e9dea 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift @@ -4,10 +4,14 @@ import UIKit // swiftlint:disable file_length protocol RuuviOnboardViewControllerOutput: AnyObject { - func ruuviOnboardPages(_ viewController: RuuviOnboardViewController, - didFinish sender: Any?) - func ruuviOnboardCloudSignIn(_ viewController: RuuviOnboardViewController, - didPresentSignIn sender: Any?) + func ruuviOnboardPages( + _ viewController: RuuviOnboardViewController, + didFinish sender: Any? + ) + func ruuviOnboardCloudSignIn( + _ viewController: RuuviOnboardViewController, + didPresentSignIn sender: Any? + ) } enum OnboardPageType: Int { @@ -46,8 +50,10 @@ class RuuviOnboardViewController: UIViewController { } private lazy var bgLayer: UIImageView = { - let iv = UIImageView(image: UIImage.named(RuuviAssets.bg_layer, - for: Self.self)) + let iv = UIImageView(image: UIImage.named( + RuuviAssets.bg_layer, + for: Self.self + )) iv.backgroundColor = .clear return iv }() @@ -66,9 +72,11 @@ class RuuviOnboardViewController: UIViewController { button.setTitleColor(.white, for: .normal) button.setTitle("onboarding_skip".localized(for: Self.self), for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, size: 14) - button.addTarget(self, - action: #selector(handleSkipButtonTap), - for: .touchUpInside) + button.addTarget( + self, + action: #selector(handleSkipButtonTap), + for: .touchUpInside + ) button.underline() return button }() @@ -76,8 +84,10 @@ class RuuviOnboardViewController: UIViewController { private lazy var collectionView: UICollectionView = { let layout = UICollectionViewFlowLayout() layout.scrollDirection = .horizontal - let cv = UICollectionView(frame: .zero, - collectionViewLayout: layout) + let cv = UICollectionView( + frame: .zero, + collectionViewLayout: layout + ) cv.backgroundColor = .clear cv.delegate = self cv.dataSource = self @@ -121,7 +131,8 @@ extension RuuviOnboardViewController { extension RuuviOnboardViewController { private func isUserAuthorized() -> Bool { - guard let isAuthorized = ruuviUser?.isAuthorized else { + guard let isAuthorized = ruuviUser?.isAuthorized + else { return false } return isAuthorized @@ -138,9 +149,11 @@ extension RuuviOnboardViewController { currentPage = lastPageIndex pageControl.currentPage = lastPageIndex let indexPath = IndexPath(item: lastPageIndex, section: 0) - collectionView.scrollToItem(at: indexPath, - at: .centeredHorizontally, - animated: false) + collectionView.scrollToItem( + at: indexPath, + at: .centeredHorizontally, + animated: false + ) } private func updateSkipButtonState() { @@ -149,7 +162,8 @@ extension RuuviOnboardViewController { private func showDiscoverPage() { viewModels = constructOnboardingPages() - guard isUserAuthorized() else { + guard isUserAuthorized() + else { return } navigationController?.setNavigationBarHidden(false, animated: false) @@ -158,19 +172,23 @@ extension RuuviOnboardViewController { } extension RuuviOnboardViewController: UICollectionViewDataSource { - func collectionView(_: UICollectionView, - numberOfItemsInSection _: Int) -> Int - { + func collectionView( + _: UICollectionView, + numberOfItemsInSection _: Int + ) -> Int { viewModels.count } - func collectionView(_ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath) -> UICollectionViewCell - { + func collectionView( + _ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath + ) -> UICollectionViewCell { let viewModel = viewModels[indexPath.item] - guard let cell = cell(collectionView: collectionView, - indexPath: indexPath, - viewModel: viewModel) + guard let cell = cell( + collectionView: collectionView, + indexPath: indexPath, + viewModel: viewModel + ) else { fatalError() } @@ -200,19 +218,21 @@ extension RuuviOnboardViewController: UICollectionViewDelegateFlowLayout { CGSize(width: view.bounds.width, height: view.bounds.height) } - func collectionView(_: UICollectionView, - layout _: UICollectionViewLayout, - minimumLineSpacingForSectionAt _: Int) -> CGFloat - { + func collectionView( + _: UICollectionView, + layout _: UICollectionViewLayout, + minimumLineSpacingForSectionAt _: Int + ) -> CGFloat { 0 } } extension RuuviOnboardViewController { - private func cell(collectionView: UICollectionView, - indexPath: IndexPath, - viewModel: OnboardViewModel) -> UICollectionViewCell? - { + private func cell( + collectionView: UICollectionView, + indexPath: IndexPath, + viewModel: OnboardViewModel + ) -> UICollectionViewCell? { switch viewModel.pageType { case .measure: let cell = collectionView.dequeueReusableCell( @@ -275,57 +295,71 @@ extension RuuviOnboardViewController { view.addSubview(collectionView) collectionView.fillSuperview() - collectionView.register(RuuviOnboardStartCell.self, - forCellWithReuseIdentifier: Self.reuseIdentifierMeasure) - collectionView.register(RuuviOnboardCoreFeaturesCell.self, - forCellWithReuseIdentifier: Self.reuseIdentifierCoreFeatures) - collectionView.register(RuuviOnboardGatewayFeaturesCell.self, - forCellWithReuseIdentifier: Self.reuseIdentifierGatewayFeatures) - collectionView.register(RuuviOnboardSignInCell.self, - forCellWithReuseIdentifier: Self.reuseIdentifierSignIn) + collectionView.register( + RuuviOnboardStartCell.self, + forCellWithReuseIdentifier: Self.reuseIdentifierMeasure + ) + collectionView.register( + RuuviOnboardCoreFeaturesCell.self, + forCellWithReuseIdentifier: Self.reuseIdentifierCoreFeatures + ) + collectionView.register( + RuuviOnboardGatewayFeaturesCell.self, + forCellWithReuseIdentifier: Self.reuseIdentifierGatewayFeatures + ) + collectionView.register( + RuuviOnboardSignInCell.self, + forCellWithReuseIdentifier: Self.reuseIdentifierSignIn + ) } private func setUpHeaderView() { let headerView = UIView(color: .clear) view.addSubview(headerView) - headerView.anchor(top: view.safeTopAnchor, - leading: view.safeLeadingAnchor, - bottom: nil, - trailing: view.safeTrailingAnchor, - padding: .init(top: 0, left: 12, bottom: 0, right: 12), - size: .init(width: 0, height: 44)) + headerView.anchor( + top: view.safeTopAnchor, + leading: view.safeLeadingAnchor, + bottom: nil, + trailing: view.safeTrailingAnchor, + padding: .init(top: 0, left: 12, bottom: 0, right: 12), + size: .init(width: 0, height: 44) + ) headerView.addSubview(pageControl) pageControl.centerInSuperview() headerView.addSubview(skipButton) - skipButton.anchor(top: nil, - leading: nil, - bottom: nil, - trailing: headerView.trailingAnchor) + skipButton.anchor( + top: nil, + leading: nil, + bottom: nil, + trailing: headerView.trailingAnchor + ) skipButton.centerYInSuperview() } } private extension RuuviOnboardViewController { static func createLayout() -> UICollectionViewLayout { - let sectionProvider = { (_: Int, - _: NSCollectionLayoutEnvironment) - -> NSCollectionLayoutSection? in - let itemSize = NSCollectionLayoutSize( - widthDimension: .fractionalWidth(1), - heightDimension: .fractionalHeight(1) - ) - let item = NSCollectionLayoutItem(layoutSize: itemSize) - - let groupSize = NSCollectionLayoutSize( - widthDimension: .fractionalWidth(1.0), - heightDimension: .fractionalHeight(1.0) - ) - let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) - - let section = NSCollectionLayoutSection(group: group) - return section + let sectionProvider = { ( + _: Int, + _: NSCollectionLayoutEnvironment + ) + -> NSCollectionLayoutSection? in + let itemSize = NSCollectionLayoutSize( + widthDimension: .fractionalWidth(1), + heightDimension: .fractionalHeight(1) + ) + let item = NSCollectionLayoutItem(layoutSize: itemSize) + + let groupSize = NSCollectionLayoutSize( + widthDimension: .fractionalWidth(1.0), + heightDimension: .fractionalHeight(1.0) + ) + let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) + + let section = NSCollectionLayoutSection(group: group) + return section } let config = UICollectionViewCompositionalLayoutConfiguration() diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift index ccd444085..6d2204801 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift @@ -39,12 +39,10 @@ extension String { #endif if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), - let bundle = Bundle(path: path) - { + let bundle = Bundle(path: path) { return bundle.localizedString(forKey: self, value: nil, table: module) } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), - let bundle = Bundle(path: path) - { + let bundle = Bundle(path: path) { return bundle.localizedString(forKey: self, value: nil, table: module) } else { assertionFailure() diff --git a/Packages/RuuviAnalytics/Sources/RuuviAnalyticsImpl/RuuviAnalyticsImpl.swift b/Packages/RuuviAnalytics/Sources/RuuviAnalyticsImpl/RuuviAnalyticsImpl.swift index 721dadff7..13c765245 100644 --- a/Packages/RuuviAnalytics/Sources/RuuviAnalyticsImpl/RuuviAnalyticsImpl.swift +++ b/Packages/RuuviAnalytics/Sources/RuuviAnalyticsImpl/RuuviAnalyticsImpl.swift @@ -232,38 +232,43 @@ public final class RuuviAnalyticsImpl: RuuviAnalytics { } // swiftlint:disable:next large_tuple - private func calculateAlerts(from tags: [RuuviTagSensor]) -> (temperature: Int, - humidity: Int, - pressure: Int, - movementCounter: Int) - { + private func calculateAlerts(from tags: [RuuviTagSensor]) -> ( + temperature: Int, + humidity: Int, + pressure: Int, + movementCounter: Int + ) { var temperatureAlertCount = 0 var humidityAlertCount = 0 var pressureAlertCount = 0 var movementAlertCount = 0 for tag in tags { - if alertService.isOn(type: .temperature(lower: 0, upper: 0), - for: tag) - { + if alertService.isOn( + type: .temperature(lower: 0, upper: 0), + for: tag + ) { temperatureAlertCount += 1 } - if alertService.isOn(type: .relativeHumidity(lower: 0, upper: 0), - for: tag) - { + if alertService.isOn( + type: .relativeHumidity(lower: 0, upper: 0), + for: tag + ) { humidityAlertCount += 1 } - if alertService.isOn(type: .pressure(lower: 0, upper: 0), - for: tag) - { + if alertService.isOn( + type: .pressure(lower: 0, upper: 0), + for: tag + ) { pressureAlertCount += 1 } - if alertService.isOn(type: .movement(last: 0), - for: tag) - { + if alertService.isOn( + type: .movement(last: 0), + for: tag + ) { movementAlertCount += 1 } } diff --git a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift index 7f57e3f52..f08705581 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift @@ -35,15 +35,19 @@ public protocol RuuviCloud { func deleteAccount(email: String) -> Future @discardableResult - func registerPNToken(token: String, - type: String, - name: String?, - data: String?, - params: [String: String]?) -> Future + func registerPNToken( + token: String, + type: String, + name: String?, + data: String?, + params: [String: String]? + ) -> Future @discardableResult - func unregisterPNToken(token: String?, - tokenId: Int?) -> Future + func unregisterPNToken( + token: String?, + tokenId: Int? + ) -> Future @discardableResult func listPNTokens() -> Future<[RuuviCloudPNToken], RuuviCloudError> @@ -52,11 +56,13 @@ public protocol RuuviCloud { func loadSensors() -> Future<[AnyCloudSensor], RuuviCloudError> @discardableResult - func loadSensorsDense(for sensor: RuuviTagSensor?, - measurements: Bool?, - sharedToOthers: Bool?, - sharedToMe: Bool?, - alerts: Bool?) -> Future<[RuuviCloudSensorDense], RuuviCloudError> + func loadSensorsDense( + for sensor: RuuviTagSensor?, + measurements: Bool?, + sharedToOthers: Bool?, + sharedToMe: Bool?, + alerts: Bool? + ) -> Future<[RuuviCloudSensorDense], RuuviCloudError> @discardableResult func loadRecords( diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudApiGetSensorsDenseRequest.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudApiGetSensorsDenseRequest.swift index 0cf0113da..811602396 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudApiGetSensorsDenseRequest.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudApiGetSensorsDenseRequest.swift @@ -7,12 +7,13 @@ public struct RuuviCloudApiGetSensorsDenseRequest: Encodable { let sharedToOthers: Bool? let alerts: Bool? - public init(sensor: String?, - measurements: Bool?, - sharedToMe: Bool?, - sharedToOthers: Bool?, - alerts: Bool?) - { + public init( + sensor: String?, + measurements: Bool?, + sharedToMe: Bool?, + sharedToOthers: Bool?, + alerts: Bool? + ) { self.sensor = sensor self.measurements = measurements self.sharedToMe = sharedToMe diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenRegisterRequest.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenRegisterRequest.swift index 69e9ccfe7..9161a0ed3 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenRegisterRequest.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudPNTokenRegisterRequest.swift @@ -13,12 +13,13 @@ public struct RuuviCloudPNTokenRegisterRequest: Encodable { let data: String? let params: [String: String]? - public init(token: String, - type: String, - name: String? = nil, - data: String? = nil, - params: [String: String]? = nil) - { + public init( + token: String, + type: String, + name: String? = nil, + data: String? = nil, + params: [String: String]? = nil + ) { self.token = token self.type = type self.name = name diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiBaseResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiBaseResponse.swift index 3e34b5003..3f2529581 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiBaseResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiBaseResponse.swift @@ -26,7 +26,8 @@ public extension RuuviCloudApiBaseResponse { var result: Swift.Result { switch status { case .success: - guard let data else { + guard let data + else { if let emptyModel = T.emptyModel { return .success(emptyModel) } else { @@ -35,7 +36,8 @@ public extension RuuviCloudApiBaseResponse { } return .success(data) case .error: - guard let code else { + guard let code + else { if errorDescription != nil { return .failure(.api(.erInternal)) } else { @@ -56,8 +58,7 @@ public extension Decodable { static var emptyModel: Self? { let emptyString = "{}" if let emptyData = emptyString.data(using: .utf8), - let emptyModel = try? JSONDecoder().decode(self, from: emptyData) - { + let emptyModel = try? JSONDecoder().decode(self, from: emptyData) { return emptyModel } else { return nil diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetAlertsResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetAlertsResponse.swift index 99edc542b..5aa15d0a3 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetAlertsResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetAlertsResponse.swift @@ -38,8 +38,7 @@ public struct RuuviCloudApiGetAlert: Decodable, RuuviCloudAlert { let container = try decoder.container(keyedBy: CodingKeys.self) if let typeString = try? container.decode(String.self, forKey: .type), - let type = RuuviCloudAlertType(rawValue: typeString) - { + let type = RuuviCloudAlertType(rawValue: typeString) { self.type = type } else { type = nil diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSensorResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSensorResponse.swift index da3feb9ee..1a7e1d5f6 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSensorResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSensorResponse.swift @@ -17,7 +17,8 @@ public struct UserApiSensorRecord: Decodable { public extension UserApiSensorRecord { var date: Date { - guard let timestamp else { + guard let timestamp + else { return Date() } return Date(timeIntervalSince1970: timestamp) diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudPNTokenListResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudPNTokenListResponse.swift index f09546ba1..87792cc0d 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudPNTokenListResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudPNTokenListResponse.swift @@ -11,7 +11,8 @@ public struct RuuviCloudPNTokenListResponse: Decodable { } public var anyTokens: [RuuviCloudPNToken] { - guard let tokens else { + guard let tokens + else { return [] } return tokens.map { diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiURLSession.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiURLSession.swift index dcf4744be..b730de909 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiURLSession.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiURLSession.swift @@ -53,153 +53,186 @@ public final class RuuviCloudApiURLSession: NSObject, RuuviCloudApi { public func register( _ requestModel: RuuviCloudApiRegisterRequest ) -> Future { - request(endpoint: Routes.register, - with: requestModel, - method: .post) + request( + endpoint: Routes.register, + with: requestModel, + method: .post + ) } public func verify( _ requestModel: RuuviCloudApiVerifyRequest ) -> Future { - request(endpoint: Routes.verify, - with: requestModel) + request( + endpoint: Routes.verify, + with: requestModel + ) } - public func deleteAccount(_ requestModel: RuuviCloudApiAccountDeleteRequest, - authorization: String) -> - Future - { - request(endpoint: Routes.deleteAccount, - with: requestModel, - method: .post, - authorization: authorization) + public func deleteAccount( + _ requestModel: RuuviCloudApiAccountDeleteRequest, + authorization: String + ) -> + Future { + request( + endpoint: Routes.deleteAccount, + with: requestModel, + method: .post, + authorization: authorization + ) } public func registerPNToken( _ requestModel: RuuviCloudPNTokenRegisterRequest, authorization: String ) -> Future { - request(endpoint: Routes.registerPNToken, - with: requestModel, - method: .post, - authorization: authorization) + request( + endpoint: Routes.registerPNToken, + with: requestModel, + method: .post, + authorization: authorization + ) } public func unregisterPNToken( _ requestModel: RuuviCloudPNTokenUnregisterRequest, authorization: String? ) -> Future { - request(endpoint: Routes.unregisterPNToken, - with: requestModel, - method: .post, - authorization: authorization) + request( + endpoint: Routes.unregisterPNToken, + with: requestModel, + method: .post, + authorization: authorization + ) } public func listPNTokens( _ requestModel: RuuviCloudPNTokenListRequest, authorization: String ) -> Future { - request(endpoint: Routes.PNTokens, - with: requestModel, - method: .get, - authorization: authorization) + request( + endpoint: Routes.PNTokens, + with: requestModel, + method: .get, + authorization: authorization + ) } public func claim( _ requestModel: RuuviCloudApiClaimRequest, authorization: String ) -> Future { - request(endpoint: Routes.claim, - with: requestModel, - method: .post, - authorization: authorization) + request( + endpoint: Routes.claim, + with: requestModel, + method: .post, + authorization: authorization + ) } public func contest( _ requestModel: RuuviCloudApiContestRequest, authorization: String ) -> Future { - request(endpoint: Routes.contest, - with: requestModel, - method: .post, - authorization: authorization) + request( + endpoint: Routes.contest, + with: requestModel, + method: .post, + authorization: authorization + ) } public func unclaim( _ requestModel: RuuviCloudApiUnclaimRequest, authorization: String ) -> Future { - request(endpoint: Routes.unclaim, - with: requestModel, - method: .post, - authorization: authorization) + request( + endpoint: Routes.unclaim, + with: requestModel, + method: .post, + authorization: authorization + ) } public func share( _ requestModel: RuuviCloudApiShareRequest, authorization: String ) -> Future { - request(endpoint: Routes.share, - with: requestModel, - method: .post, - authorization: authorization) + request( + endpoint: Routes.share, + with: requestModel, + method: .post, + authorization: authorization + ) } public func unshare( _ requestModel: RuuviCloudApiShareRequest, authorization: String ) -> Future { - request(endpoint: Routes.unshare, - with: requestModel, - method: .post, - authorization: authorization) + request( + endpoint: Routes.unshare, + with: requestModel, + method: .post, + authorization: authorization + ) } public func sensors( _ requestModel: RuuviCloudApiGetSensorsRequest, authorization: String ) -> Future { - request(endpoint: Routes.sensors, - with: requestModel, - method: .get, - authorization: authorization) + request( + endpoint: Routes.sensors, + with: requestModel, + method: .get, + authorization: authorization + ) } public func owner( _ requestModel: RuuviCloudApiGetSensorsRequest, authorization: String ) -> Future { - request(endpoint: Routes.check, - with: requestModel, - method: .get, - authorization: authorization) + request( + endpoint: Routes.check, + with: requestModel, + method: .get, + authorization: authorization + ) } public func sensorsDense( _ requestModel: RuuviCloudApiGetSensorsDenseRequest, authorization: String ) -> Future { - request(endpoint: Routes.sensorsDense, - with: requestModel, - method: .get, - authorization: authorization) + request( + endpoint: Routes.sensorsDense, + with: requestModel, + method: .get, + authorization: authorization + ) } public func user(authorization: String) -> Future { let requestModel = RuuviCloudApiUserRequest() - return request(endpoint: Routes.user, - with: requestModel, - authorization: authorization) + return request( + endpoint: Routes.user, + with: requestModel, + authorization: authorization + ) } public func getSensorData( _ requestModel: RuuviCloudApiGetSensorRequest, authorization: String ) -> Future { - request(endpoint: Routes.getSensorData, - with: requestModel, - method: .get, - authorization: authorization) + request( + endpoint: Routes.getSensorData, + with: requestModel, + method: .get, + authorization: authorization + ) } public func update( @@ -281,28 +314,30 @@ public final class RuuviCloudApiURLSession: NSObject, RuuviCloudApi { uploadProgress: ((Double) -> Void)? ) -> Future { let promise = Promise() - request(endpoint: Routes.uploadImage, - with: requestModel, - method: .post, - authorization: authorization) - .on(success: { [weak self] (response: RuuviCloudApiSensorImageUploadResponse) in - let url = response.uploadURL - self?.upload(url: url, with: imageData, mimeType: .jpg, progress: { percentage in - #if DEBUG - debugPrint(percentage) - #endif - uploadProgress?(percentage) - }, completion: { result in - switch result { - case .success: - promise.succeed(value: response) - case let .failure(error): - promise.fail(error: error) - } - }) - }, failure: { error in - promise.fail(error: error) + request( + endpoint: Routes.uploadImage, + with: requestModel, + method: .post, + authorization: authorization + ) + .on(success: { [weak self] (response: RuuviCloudApiSensorImageUploadResponse) in + let url = response.uploadURL + self?.upload(url: url, with: imageData, mimeType: .jpg, progress: { percentage in + #if DEBUG + debugPrint(percentage) + #endif + uploadProgress?(percentage) + }, completion: { result in + switch result { + case .success: + promise.succeed(value: response) + case let .failure(error): + promise.fail(error: error) + } }) + }, failure: { error in + promise.fail(error: error) + }) return promise.future } } @@ -318,7 +353,8 @@ extension RuuviCloudApiURLSession { authorization: String? = nil ) -> Future { let promise = Promise() - guard Reachability.active else { + guard Reachability.active + else { promise.fail(error: .connection) return promise.future } @@ -326,7 +362,8 @@ extension RuuviCloudApiURLSession { if method == .get { var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: true) urlComponents?.queryItems = try? URLQueryItemEncoder().encode(model) - guard let urlFromComponents = urlComponents?.url else { + guard let urlFromComponents = urlComponents?.url + else { fatalError() } url = urlFromComponents @@ -343,11 +380,15 @@ extension RuuviCloudApiURLSession { if let buildNumber = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion") as? String { #if DEBUG - request.setValue("Station_iOS_Debug/Build_\(buildNumber)/\(endpoint.rawValue)", - forHTTPHeaderField: "User-Agent") + request.setValue( + "Station_iOS_Debug/Build_\(buildNumber)/\(endpoint.rawValue)", + forHTTPHeaderField: "User-Agent" + ) #else - request.setValue("Station_iOS/Build_\(buildNumber)/\(endpoint.rawValue)", - forHTTPHeaderField: "User-Agent") + request.setValue( + "Station_iOS/Build_\(buildNumber)/\(endpoint.rawValue)", + forHTTPHeaderField: "User-Agent" + ) #endif } @@ -364,8 +405,7 @@ extension RuuviCloudApiURLSession { #if DEBUG if let object = try? JSONSerialization.jsonObject(with: data, options: []), let jsonData = try? JSONSerialization.data(withJSONObject: object, options: [.prettyPrinted]), - let prettyPrintedString = NSString(data: jsonData, encoding: String.Encoding.utf8.rawValue) - { + let prettyPrintedString = NSString(data: jsonData, encoding: String.Encoding.utf8.rawValue) { debugPrint("📬 Response of request", dump(request), prettyPrintedString) } #endif diff --git a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift index 1e3dc0be8..51b63009d 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift @@ -8,10 +8,11 @@ import RuuviUser public final class RuuviCloudFactoryPure: RuuviCloudFactory { public init() {} - public func create(baseUrl: URL, - user: RuuviUser, - pool: RuuviPool?) -> RuuviCloud - { + public func create( + baseUrl: URL, + user: RuuviUser, + pool: RuuviPool? + ) -> RuuviCloud { let api = RuuviCloudApiURLSession(baseUrl: baseUrl) let cloud = RuuviCloudPure(api: api, user: user, pool: pool) return cloud diff --git a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift index b64a2b37d..11c94485f 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift @@ -16,10 +16,11 @@ public final class RuuviCloudPure: RuuviCloud { private let api: RuuviCloudApi private let pool: RuuviPool? - public init(api: RuuviCloudApi, - user: RuuviUser, - pool: RuuviPool?) - { + public init( + api: RuuviCloudApi, + user: RuuviUser, + pool: RuuviPool? + ) { self.api = api self.user = user self.pool = pool @@ -28,7 +29,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func loadAlerts() -> Future<[RuuviCloudSensorAlerts], RuuviCloudError> { let promise = Promise<[RuuviCloudSensorAlerts], RuuviCloudError>() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -56,7 +58,8 @@ public final class RuuviCloudPure: RuuviCloud { for macId: MACIdentifier ) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -90,7 +93,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(temperatureUnit: TemperatureUnit) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -116,7 +120,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(temperatureAccuracy: MeasurementAccuracyType) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -142,7 +147,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(humidityUnit: HumidityUnit) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -168,7 +174,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(humidityAccuracy: MeasurementAccuracyType) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -194,7 +201,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(pressureUnit: UnitPressure) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -220,7 +228,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(pressureAccuracy: MeasurementAccuracyType) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -246,7 +255,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(showAllData: Bool) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -272,7 +282,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(drawDots: Bool) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -298,7 +309,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(chartDuration: Int) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -324,7 +336,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(showMinMaxAvg: Bool) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -350,7 +363,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(cloudMode: Bool) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -376,7 +390,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(dashboard: Bool) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -402,7 +417,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(dashboardType: DashboardType) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -427,10 +443,10 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(dashboardTapActionType: DashboardTapActionType) -> - Future - { + Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -456,7 +472,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(emailAlert: Bool) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -482,7 +499,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(pushAlert: Bool) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -508,7 +526,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func set(profileLanguageCode: String) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -534,7 +553,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func getCloudSettings() -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -553,7 +573,8 @@ public final class RuuviCloudPure: RuuviCloud { for macId: MACIdentifier ) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -577,7 +598,8 @@ public final class RuuviCloudPure: RuuviCloud { for macId: MACIdentifier ) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -615,7 +637,8 @@ public final class RuuviCloudPure: RuuviCloud { for sensor: RuuviTagSensor ) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -658,7 +681,8 @@ public final class RuuviCloudPure: RuuviCloud { for sensor: RuuviTagSensor ) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -687,7 +711,8 @@ public final class RuuviCloudPure: RuuviCloud { public func loadShared(for sensor: RuuviTagSensor) -> Future, RuuviCloudError> { let promise = Promise, RuuviCloudError>() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -706,7 +731,8 @@ public final class RuuviCloudPure: RuuviCloud { @discardableResult public func checkOwner(macId: MACIdentifier) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -728,7 +754,8 @@ public final class RuuviCloudPure: RuuviCloud { alerts: Bool? ) -> Future<[RuuviCloudSensorDense], RuuviCloudError> { let promise = Promise<[RuuviCloudSensorDense], RuuviCloudError>() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -775,7 +802,8 @@ public final class RuuviCloudPure: RuuviCloud { public func share(macId: MACIdentifier, with email: String) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -795,7 +823,8 @@ public final class RuuviCloudPure: RuuviCloud { public func unshare(macId: MACIdentifier, with email: String?) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -804,7 +833,8 @@ public final class RuuviCloudPure: RuuviCloud { .on(success: { _ in promise.succeed(value: macId) }, failure: { [weak self] error in - guard let email else { + guard let email + else { promise.fail(error: .api(error)) return } @@ -824,7 +854,8 @@ public final class RuuviCloudPure: RuuviCloud { macId: MACIdentifier ) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -844,7 +875,8 @@ public final class RuuviCloudPure: RuuviCloud { secret: String ) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -863,7 +895,8 @@ public final class RuuviCloudPure: RuuviCloud { removeCloudHistory: Bool ) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -921,29 +954,34 @@ public final class RuuviCloudPure: RuuviCloud { public func deleteAccount(email: String) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } let request = RuuviCloudApiAccountDeleteRequest(email: email) - api.deleteAccount(request, - authorization: apiKey) - .on(success: { response in - promise.succeed(value: response.email == email) - }, failure: { error in - promise.fail(error: .api(error)) - }) + api.deleteAccount( + request, + authorization: apiKey + ) + .on(success: { response in + promise.succeed(value: response.email == email) + }, failure: { error in + promise.fail(error: .api(error)) + }) return promise.future } - public func registerPNToken(token: String, - type: String, - name: String?, - data: String?, - params: [String: String]?) -> Future - { + public func registerPNToken( + token: String, + type: String, + name: String?, + data: String?, + params: [String: String]? + ) -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -954,41 +992,51 @@ public final class RuuviCloudPure: RuuviCloud { data: data, params: params ) - api.registerPNToken(request, - authorization: apiKey) - .on(success: { response in - promise.succeed(value: response.id) - }, failure: { error in - promise.fail(error: .api(error)) - }) + api.registerPNToken( + request, + authorization: apiKey + ) + .on(success: { response in + promise.succeed(value: response.id) + }, failure: { error in + promise.fail(error: .api(error)) + }) return promise.future } - public func unregisterPNToken(token: String?, - tokenId: Int?) -> Future - { + public func unregisterPNToken( + token: String?, + tokenId: Int? + ) -> Future { let promise = Promise() - let request = RuuviCloudPNTokenUnregisterRequest(token: token, - id: tokenId) - api.unregisterPNToken(request, - authorization: user.apiKey) - .on(success: { _ in - promise.succeed(value: true) - }, failure: { error in - promise.fail(error: .api(error)) - }) + let request = RuuviCloudPNTokenUnregisterRequest( + token: token, + id: tokenId + ) + api.unregisterPNToken( + request, + authorization: user.apiKey + ) + .on(success: { _ in + promise.succeed(value: true) + }, failure: { error in + promise.fail(error: .api(error)) + }) return promise.future } public func listPNTokens() -> Future<[RuuviCloudPNToken], RuuviCloudError> { let promise = Promise<[RuuviCloudPNToken], RuuviCloudError>() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } let request = RuuviCloudPNTokenListRequest() - api.listPNTokens(request, - authorization: apiKey).on(success: { response in + api.listPNTokens( + request, + authorization: apiKey + ).on(success: { response in let tokens = response.anyTokens promise.succeed(value: tokens) }, failure: { error in @@ -999,7 +1047,8 @@ public final class RuuviCloudPure: RuuviCloud { public func loadSensors() -> Future<[AnyCloudSensor], RuuviCloudError> { let promise = Promise<[AnyCloudSensor], RuuviCloudError>() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } @@ -1040,7 +1089,8 @@ public final class RuuviCloudPure: RuuviCloud { chunkSize: Int, promise: Promise<[AnyRuuviTagSensorRecord], RuuviCloudError> ) { - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return } @@ -1058,8 +1108,7 @@ public final class RuuviCloudPure: RuuviCloud { // Offset is to check whether we have recent minute data. (Current time + 1 min) let offset = Date().addingTimeInterval(1 * 60) if let lastRecord = fetchedRecords.last, - !records.contains(lastRecord) - { + !records.contains(lastRecord) { let loadable = (until != nil && lastRecord.date < until!) || lastRecord.date > offset if loadable { @@ -1084,15 +1133,16 @@ public final class RuuviCloudPure: RuuviCloud { // swiftlint:disable:next function_body_length cyclomatic_complexity public func executeQueuedRequest(from request: RuuviCloudQueuedRequest) - -> Future - { + -> Future { let promise = Promise() - guard let apiKey = user.apiKey else { + guard let apiKey = user.apiKey + else { promise.fail(error: .notAuthorized) return promise.future } - guard let type = request.type, let requestBody = request.requestBodyData else { + guard let type = request.type, let requestBody = request.requestBodyData + else { promise.fail(error: .api(.unexpectedHTTPStatusCode)) return promise.future } @@ -1181,7 +1231,8 @@ public final class RuuviCloudPure: RuuviCloud { } case .uploadImage: do { - guard let imageData = request.additionalData else { + guard let imageData = request.additionalData + else { return promise.future } @@ -1215,7 +1266,8 @@ public final class RuuviCloudPure: RuuviCloud { response: RuuviCloudApiGetSensorResponse ) -> [AnyRuuviTagSensorRecord] { let decoder = Ruuvi.decoder - guard let measurements = response.measurements else { + guard let measurements = response.measurements + else { return [] } return measurements.compactMap { measurement in @@ -1290,13 +1342,15 @@ public final class RuuviCloudPure: RuuviCloud { ).any } - private func createQueuedRequest(from request: Codable, - additionalData: Data? = nil, - type: RuuviCloudQueuedRequestType, - uniqueKey: String) - { + private func createQueuedRequest( + from request: Codable, + additionalData: Data? = nil, + type: RuuviCloudQueuedRequestType, + uniqueKey: String + ) { let encoder = JSONEncoder() - guard let data = try? encoder.encode(request) else { + guard let data = try? encoder.encode(request) + else { return } let request = RuuviCloudQueuedRequestStruct( diff --git a/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextGRDB.swift b/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextGRDB.swift index f1984c4e2..864faed91 100644 --- a/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextGRDB.swift +++ b/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextGRDB.swift @@ -23,8 +23,11 @@ class SQLiteGRDBDatabase: GRDBDatabase { }() static var databasePath: String { - let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, - .userDomainMask, true).first! as NSString + let documentsPath = NSSearchPathForDirectoriesInDomains( + .documentDirectory, + .userDomainMask, + true + ).first! as NSString let databasePath = documentsPath.appendingPathComponent("grdb.sqlite") return databasePath } diff --git a/Packages/RuuviCore/Package.swift b/Packages/RuuviCore/Package.swift index 4e7c1ecae..7f48b5bfd 100644 --- a/Packages/RuuviCore/Package.swift +++ b/Packages/RuuviCore/Package.swift @@ -33,7 +33,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/kean/Future", .exact("1.3.0")), + .package(url: "https://github.com/kean/Future", .exact("1.3.0")) ], targets: [ .target( diff --git a/Packages/RuuviCore/Sources/RuuviCoreDiff/Impl/DiffCalculatorImpl.swift b/Packages/RuuviCore/Sources/RuuviCoreDiff/Impl/DiffCalculatorImpl.swift index 6d6f676ab..03ea66ed6 100644 --- a/Packages/RuuviCore/Sources/RuuviCoreDiff/Impl/DiffCalculatorImpl.swift +++ b/Packages/RuuviCore/Sources/RuuviCoreDiff/Impl/DiffCalculatorImpl.swift @@ -27,8 +27,10 @@ class DiffCalculatorImpl: DiffCalculator { let newCellItem = newCellData[cellKey] if let oldCellItem, let newCelItem = newCellItem { if oldCellItem != newCelItem { - let indexPath: IndexPath = .init(row: oldCellItem.index, - section: oldSectionItem.index) + let indexPath: IndexPath = .init( + row: oldCellItem.index, + section: oldSectionItem.index + ) cellChanges.reloads .append(indexPath) } @@ -51,10 +53,11 @@ class DiffCalculatorImpl: DiffCalculator { return sectionChanges } - func calculate(oldItems: [ReloadableCell], - newItems: [ReloadableCell], - in sectionIndex: Int) -> CellChanges - { + func calculate( + oldItems: [ReloadableCell], + newItems: [ReloadableCell], + in sectionIndex: Int + ) -> CellChanges { let cellChanges = CellChanges() let oldCellIData = ReloadableCellData(items: oldItems) diff --git a/Packages/RuuviCore/Sources/RuuviCoreDiff/Util/Array+Extension.swift b/Packages/RuuviCore/Sources/RuuviCoreDiff/Util/Array+Extension.swift index e5892cdcd..98102d064 100644 --- a/Packages/RuuviCore/Sources/RuuviCoreDiff/Util/Array+Extension.swift +++ b/Packages/RuuviCore/Sources/RuuviCoreDiff/Util/Array+Extension.swift @@ -13,7 +13,8 @@ extension Array where Element: Hashable { extension String { subscript(safe range: NSRange) -> String? { - guard count > range.location else { + guard count > range.location + else { return nil } let length = count > range.location + range.length ? range.location + range.length : count diff --git a/Packages/RuuviDFU/Package.swift b/Packages/RuuviDFU/Package.swift index 5897c0669..7c27eb255 100644 --- a/Packages/RuuviDFU/Package.swift +++ b/Packages/RuuviDFU/Package.swift @@ -27,7 +27,7 @@ let package = Package( .target( name: "RuuviDFU", dependencies: [ - "NordicDFU", + "NordicDFU" ] ), .target( diff --git a/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift b/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift index c8702aede..d2c5c9c11 100644 --- a/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift +++ b/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift @@ -18,10 +18,12 @@ class DfuFlasher: NSObject { private var subject: PassthroughSubject? override init() { - dfuServiceInitiator = DFUServiceInitiator(queue: queue, - delegateQueue: queue, - progressQueue: queue, - loggerQueue: queue) + dfuServiceInitiator = DFUServiceInitiator( + queue: queue, + delegateQueue: queue, + progressQueue: queue, + loggerQueue: queue + ) super.init() } @@ -29,7 +31,8 @@ class DfuFlasher: NSObject { uuid: String, with firmware: DFUFirmware ) -> AnyPublisher { - guard let uuid = UUID(uuidString: uuid) else { + guard let uuid = UUID(uuidString: uuid) + else { return Fail(error: RuuviDfuError.failedToConstructUUID).eraseToAnyPublisher() } let subject = PassthroughSubject() @@ -45,7 +48,8 @@ class DfuFlasher: NSObject { } func stopFlashFirmware(device _: DFUDevice) -> Bool { - guard let serviceController = dfuServiceController else { + guard let serviceController = dfuServiceController + else { return false } return serviceController.abort() @@ -71,13 +75,15 @@ extension DfuFlasher: DFUServiceDelegate { } extension DfuFlasher: DFUProgressDelegate { - func dfuProgressDidChange(for part: Int, - outOf totalParts: Int, - to progress: Int, - currentSpeedBytesPerSecond _: Double, - avgSpeedBytesPerSecond _: Double) - { - guard let parts = firmware?.parts else { + func dfuProgressDidChange( + for part: Int, + outOf totalParts: Int, + to progress: Int, + currentSpeedBytesPerSecond _: Double, + avgSpeedBytesPerSecond _: Double + ) { + guard let parts = firmware?.parts + else { return } // Update the total progress view diff --git a/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuScanner.swift b/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuScanner.swift index 803f1720d..c8a722e7e 100644 --- a/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuScanner.swift +++ b/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuScanner.swift @@ -37,12 +37,18 @@ class DfuScanner: NSObject { override required init() { super.init() - NotificationCenter.default.addObserver(self, - selector: #selector(willResignActiveNotification(_:)), - name: UIApplication.willResignActiveNotification, object: nil) - NotificationCenter.default.addObserver(self, - selector: #selector(didBecomeActiveNotification(_:)), - name: UIApplication.didBecomeActiveNotification, object: nil) + NotificationCenter.default.addObserver( + self, + selector: #selector(willResignActiveNotification(_:)), + name: UIApplication.willResignActiveNotification, + object: nil + ) + NotificationCenter.default.addObserver( + self, + selector: #selector(didBecomeActiveNotification(_:)), + name: UIApplication.didBecomeActiveNotification, + object: nil + ) queue.async { [weak self] in self?.startIfNeeded() } @@ -92,8 +98,10 @@ class DfuScanner: NSObject { private func startIfNeeded() { if manager.state == .poweredOn, !manager.isScanning { - manager.scanForPeripherals(withServices: scanServices, - options: [CBCentralManagerScanOptionAllowDuplicatesKey: NSNumber(value: true)]) + manager.scanForPeripherals( + withServices: scanServices, + options: [CBCentralManagerScanOptionAllowDuplicatesKey: NSNumber(value: true)] + ) } let shouldObserveLostDevices = observations.lost.count > 0 if shouldObserveLostDevices, lostTimer == nil { @@ -116,7 +124,8 @@ class DfuScanner: NSObject { let id = UUID() queue.async { [weak self] in self?.observations.device[id] = { [weak self, weak observer] device in - guard let observer else { + guard let observer + else { self?.observations.device.removeValue(forKey: id) self?.stopIfNeeded() return @@ -141,7 +150,8 @@ class DfuScanner: NSObject { let id = UUID() queue.async { [weak self] in self?.observations.lost[id] = LostObservation(block: { [weak self, weak observer] device in - guard let observer else { + guard let observer + else { self?.observations.lost.removeValue(forKey: id) self?.stopIfNeeded() return @@ -169,11 +179,12 @@ extension DfuScanner: CBCentralManagerDelegate { } } - func centralManager(_: CBCentralManager, - didDiscover peripheral: CBPeripheral, - advertisementData: [String: Any], - rssi RSSI: NSNumber) - { + func centralManager( + _: CBCentralManager, + didDiscover peripheral: CBPeripheral, + advertisementData: [String: Any], + rssi RSSI: NSNumber + ) { guard RSSI.intValue != 127 else { return } let uuid = peripheral.identifier.uuidString let isConnectable = (advertisementData[CBAdvertisementDataIsConnectable] as? NSNumber)?.boolValue ?? false diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviDaemonWorker.swift b/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviDaemonWorker.swift index 109cd9e77..9093e967b 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviDaemonWorker.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemon/RuuviDaemonWorker.swift @@ -30,20 +30,24 @@ open class RuuviDaemonWorker: NSObject { thread.name = "\(threadName)-\(UUID().uuidString)" thread.start() - perform(#selector(runBlock), - on: thread, - with: nil, - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) + perform( + #selector(runBlock), + on: thread, + with: nil, + waitUntilDone: false, + modes: [RunLoop.Mode.default.rawValue] + ) } public func stopWork() { block = nil - perform(#selector(stopThread), - on: thread, - with: nil, - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) + perform( + #selector(stopThread), + on: thread, + with: nil, + waitUntilDone: false, + modes: [RunLoop.Mode.default.rawValue] + ) } @objc func stopThread() { diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift index 890750e4e..72df85cfa 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift @@ -39,14 +39,17 @@ class RuuviDaemonCloudSyncWorker: RuuviDaemonWorker, RuuviDaemonCloudSync { } func stop() { - guard let thread else { + guard let thread + else { return } - perform(#selector(RuuviDaemonCloudSyncWorker.stopDaemon), - on: thread, - with: nil, - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) + perform( + #selector(RuuviDaemonCloudSyncWorker.stopDaemon), + on: thread, + with: nil, + waitUntilDone: false, + modes: [RunLoop.Mode.default.rawValue] + ) } @objc private func stopDaemon() { diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/RuuviTagDataPruningOperation.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/RuuviTagDataPruningOperation.swift index 12c6e7a6f..aa38e7c08 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/RuuviTagDataPruningOperation.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/RuuviTagDataPruningOperation.swift @@ -15,9 +15,11 @@ class RuuviTagDataPruningOperation: AsyncOperation { override func main() { let offset = settings.dataPruningOffsetHours - let date = Calendar.current.date(byAdding: .hour, - value: -offset, - to: Date()) ?? Date() + let date = Calendar.current.date( + byAdding: .hour, + value: -offset, + to: Date() + ) ?? Date() ruuviPool.deleteAllRecords(id, before: date).on(failure: { error in print(error.localizedDescription) }, completion: { diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Advertisement/RuuviTagAdvertisementDaemonBTKit.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Advertisement/RuuviTagAdvertisementDaemonBTKit.swift index eae63238a..5dc3f022d 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Advertisement/RuuviTagAdvertisementDaemonBTKit.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Advertisement/RuuviTagAdvertisementDaemonBTKit.swift @@ -70,37 +70,40 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag super.init() isOnToken = NotificationCenter .default - .addObserver(forName: .isAdvertisementDaemonOnDidChange, - object: nil, - queue: .main) - { [weak self] _ in - guard let sSelf = self else { return } - if sSelf.settings.isAdvertisementDaemonOn { - sSelf.start() - } else { - sSelf.stop() + .addObserver( + forName: .isAdvertisementDaemonOnDidChange, + object: nil, + queue: .main + ) { [weak self] _ in + guard let sSelf = self else { return } + if sSelf.settings.isAdvertisementDaemonOn { + sSelf.start() + } else { + sSelf.stop() + } } - } cloudModeOnToken = NotificationCenter .default - .addObserver(forName: .CloudModeDidChange, - object: nil, - queue: .main) - { [weak self] _ in - guard let sSelf = self else { return } - sSelf.restartObserving() - } + .addObserver( + forName: .CloudModeDidChange, + object: nil, + queue: .main + ) { [weak self] _ in + guard let sSelf = self else { return } + sSelf.restartObserving() + } daemonRestartToken = NotificationCenter .default - .addObserver(forName: .RuuviTagAdvertisementDaemonShouldRestart, - object: nil, - queue: .main) - { [weak self] _ in - guard let sSelf = self else { return } - sSelf.restart() - } + .addObserver( + forName: .RuuviTagAdvertisementDaemonShouldRestart, + object: nil, + queue: .main + ) { [weak self] _ in + guard let sSelf = self else { return } + sSelf.restart() + } } public func start() { @@ -131,11 +134,13 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag } public func stop() { - perform(#selector(RuuviTagAdvertisementDaemonBTKit.stopDaemon), - on: thread, - with: nil, - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) + perform( + #selector(RuuviTagAdvertisementDaemonBTKit.stopDaemon), + on: thread, + with: nil, + waitUntilDone: false, + modes: [RunLoop.Mode.default.rawValue] + ) } public func restart() { @@ -179,20 +184,23 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag continue } guard let luid = ruuviTag.luid else { continue } - observeTokens.append(foreground.observe(self, - uuid: luid.value, - options: [.callbackQueue(.untouch)]) - { - [weak self] _, device in - guard let sSelf = self else { return } - if let tag = device.ruuvi?.tag, !tag.isConnected { - sSelf.perform(#selector(RuuviTagAdvertisementDaemonBTKit.persist(wrapper:)), - on: sSelf.thread, - with: RuuviTagWrapper(device: tag), - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) - } - }) + observeTokens.append(foreground.observe( + self, + uuid: luid.value, + options: [.callbackQueue(.untouch)] + ) { + [weak self] _, device in + guard let sSelf = self else { return } + if let tag = device.ruuvi?.tag, !tag.isConnected { + sSelf.perform( + #selector(RuuviTagAdvertisementDaemonBTKit.persist(wrapper:)), + on: sSelf.thread, + with: RuuviTagWrapper(device: tag), + waitUntilDone: false, + modes: [RunLoop.Mode.default.rawValue] + ) + } + }) sensorSettingsTokens.append(ruuviReactor.observe(ruuviTag) { [weak self] change in switch change { case let .delete(sensorSettings): @@ -252,9 +260,11 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag DispatchQueue.main.async { NotificationCenter .default - .post(name: .RuuviTagAdvertisementDaemonDidFail, - object: nil, - userInfo: [RuuviTagAdvertisementDaemonDidFailKey.error: error]) + .post( + name: .RuuviTagAdvertisementDaemonDidFail, + object: nil, + userInfo: [RuuviTagAdvertisementDaemonDidFailKey.error: error] + ) } } @@ -287,8 +297,7 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag private func createLatestRecord(with record: RuuviTag) { if let ruuviTag = ruuviTags.first(where: { if let luid = $0.luid?.value, let recordLuid = record.luid?.value, - luid == recordLuid - { + luid == recordLuid { true } else { false @@ -296,7 +305,8 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag }) { ruuviStorage.readLatest(ruuviTag).on(success: { [weak self] localRecord in let advertisement = record.with(source: .advertisement) - guard localRecord != nil else { + guard localRecord != nil + else { self?.ruuviPool.createLast(record) return } diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Heartbeat/RuuviTagHeartbeatDaemonBTKit.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Heartbeat/RuuviTagHeartbeatDaemonBTKit.swift index 4b56fa948..8286fcfd9 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Heartbeat/RuuviTagHeartbeatDaemonBTKit.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Heartbeat/RuuviTagHeartbeatDaemonBTKit.swift @@ -61,58 +61,66 @@ public final class RuuviTagHeartbeatDaemonBTKit: RuuviDaemonWorker, RuuviTagHear super.init() connectionAddedToken = NotificationCenter .default - .addObserver(forName: .ConnectionPersistenceDidStartToKeepConnection, - object: nil, - queue: .main, - using: { [weak self] notification in - guard let sSelf = self else { return } - if let userInfo = notification.userInfo, - let uuid = userInfo[CPDidStartToKeepConnectionKey.uuid] as? String - { - sSelf.perform(#selector(RuuviTagHeartbeatDaemonBTKit.connect(uuid:)), - on: sSelf.thread, - with: uuid, - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) - } - }) + .addObserver( + forName: .ConnectionPersistenceDidStartToKeepConnection, + object: nil, + queue: .main, + using: { [weak self] notification in + guard let sSelf = self else { return } + if let userInfo = notification.userInfo, + let uuid = userInfo[CPDidStartToKeepConnectionKey.uuid] as? String { + sSelf.perform( + #selector(RuuviTagHeartbeatDaemonBTKit.connect(uuid:)), + on: sSelf.thread, + with: uuid, + waitUntilDone: false, + modes: [RunLoop.Mode.default.rawValue] + ) + } + } + ) connectionRemovedToken = NotificationCenter .default - .addObserver(forName: .ConnectionPersistenceDidStopToKeepConnection, - object: nil, - queue: .main, - using: { [weak self] notification in - guard let sSelf = self else { return } - if let userInfo = notification.userInfo, - let uuid = userInfo[CPDidStopToKeepConnectionKey.uuid] as? String - { - sSelf.perform(#selector(RuuviTagHeartbeatDaemonBTKit.disconnect(uuid:)), - on: sSelf.thread, - with: uuid, - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) - } - }) + .addObserver( + forName: .ConnectionPersistenceDidStopToKeepConnection, + object: nil, + queue: .main, + using: { [weak self] notification in + guard let sSelf = self else { return } + if let userInfo = notification.userInfo, + let uuid = userInfo[CPDidStopToKeepConnectionKey.uuid] as? String { + sSelf.perform( + #selector(RuuviTagHeartbeatDaemonBTKit.disconnect(uuid:)), + on: sSelf.thread, + with: uuid, + waitUntilDone: false, + modes: [RunLoop.Mode.default.rawValue] + ) + } + } + ) cloudModeOnToken = NotificationCenter .default - .addObserver(forName: .CloudModeDidChange, - object: nil, - queue: .main) - { [weak self] _ in - guard let sSelf = self else { return } - sSelf.handleRuuviTagsChange() - } + .addObserver( + forName: .CloudModeDidChange, + object: nil, + queue: .main + ) { [weak self] _ in + guard let sSelf = self else { return } + sSelf.handleRuuviTagsChange() + } daemonRestartToken = NotificationCenter .default - .addObserver(forName: .RuuviTagHeartBeatDaemonShouldRestart, - object: nil, - queue: .main) - { [weak self] _ in - guard let sSelf = self else { return } - sSelf.handleRuuviTagsChange() - } + .addObserver( + forName: .RuuviTagHeartBeatDaemonShouldRestart, + object: nil, + queue: .main + ) { [weak self] _ in + guard let sSelf = self else { return } + sSelf.handleRuuviTagsChange() + } } deinit { @@ -159,11 +167,13 @@ public final class RuuviTagHeartbeatDaemonBTKit: RuuviDaemonWorker, RuuviTagHear } public func stop() { - perform(#selector(RuuviTagHeartbeatDaemonBTKit.stopDaemon), - on: thread, - with: nil, - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) + perform( + #selector(RuuviTagHeartbeatDaemonBTKit.stopDaemon), + on: thread, + with: nil, + waitUntilDone: false, + modes: [RunLoop.Mode.default.rawValue] + ) } public func restart() { @@ -212,11 +222,10 @@ extension RuuviTagHeartbeatDaemonBTKit { || ($0.luid?.any != nil && $0.luid?.any == ruuviTag.luid?.any) }), let settings = observer.sensorSettingsList - .first(where: { - ($0.luid?.any != nil && $0.luid?.any == ruuviTagSensor.luid?.any) - || ($0.macId?.any != nil && $0.macId?.any == ruuviTagSensor.macId?.any) - }) - { + .first(where: { + ($0.luid?.any != nil && $0.luid?.any == ruuviTagSensor.luid?.any) + || ($0.macId?.any != nil && $0.macId?.any == ruuviTagSensor.macId?.any) + }) { sensorSettings = settings } observer.alertHandler.process( @@ -234,14 +243,18 @@ extension RuuviTagHeartbeatDaemonBTKit { let interval = observer.settings.appIsOnForeground ? 2 : (observer.settings.saveHeartbeatsIntervalMinutes * 60) if let date = observer.savedDate[uuid] { if Date().timeIntervalSince(date) > TimeInterval(interval) { - self.createRecords(observer: observer, - ruuviTag: ruuviTag, - uuid: uuid) + self.createRecords( + observer: observer, + ruuviTag: ruuviTag, + uuid: uuid + ) } } else { - self.createRecords(observer: observer, - ruuviTag: ruuviTag, - uuid: uuid) + self.createRecords( + observer: observer, + ruuviTag: ruuviTag, + uuid: uuid + ) } } } @@ -249,40 +262,40 @@ extension RuuviTagHeartbeatDaemonBTKit { } private func disconnectedHandler(for uuid: String) -> - ((RuuviTagHeartbeatDaemonBTKit, BTDisconnectResult) -> Void)? - { - { observer, result in - switch result { - case .stillConnected: - break // do nothing - case .already: - break // do nothing - case .bluetoothWasPoweredOff: - if observer.alertService.isOn(type: .connection, for: uuid) { - observer.notifyDidDisconnect(uuid: uuid) - } - case .just: - if observer.alertService.isOn(type: .connection, for: uuid) { - observer.notifyDidDisconnect(uuid: uuid) - } - case let .failure(error): - observer.post(error: .btkit(error)) + ((RuuviTagHeartbeatDaemonBTKit, BTDisconnectResult) -> Void)? { { observer, result in + switch result { + case .stillConnected: + break // do nothing + case .already: + break // do nothing + case .bluetoothWasPoweredOff: + if observer.alertService.isOn(type: .connection, for: uuid) { + observer.notifyDidDisconnect(uuid: uuid) + } + case .just: + if observer.alertService.isOn(type: .connection, for: uuid) { + observer.notifyDidDisconnect(uuid: uuid) } + case let .failure(error): + observer.post(error: .btkit(error)) } } + } - private func createRecords(observer: RuuviTagHeartbeatDaemonBTKit, - ruuviTag: RuuviTag, - uuid: String) - { + private func createRecords( + observer: RuuviTagHeartbeatDaemonBTKit, + ruuviTag: RuuviTag, + uuid: String + ) { createRecord(observer: observer, ruuviTag: ruuviTag, uuid: uuid) observer.savedDate[uuid] = Date() } - private func createRecord(observer: RuuviTagHeartbeatDaemonBTKit, - ruuviTag: RuuviTag, - uuid: String) - { + private func createRecord( + observer: RuuviTagHeartbeatDaemonBTKit, + ruuviTag: RuuviTag, + uuid: String + ) { observer.ruuviPool.create( ruuviTag .with(source: .heartbeat) @@ -291,16 +304,16 @@ extension RuuviTagHeartbeatDaemonBTKit { }) } - private func createLastRecord(observer: RuuviTagHeartbeatDaemonBTKit, - ruuviTag: RuuviTag, - uuid: String) - { + private func createLastRecord( + observer: RuuviTagHeartbeatDaemonBTKit, + ruuviTag: RuuviTag, + uuid: String + ) { if let tag = ruuviTags.first(where: { $0.luid?.value == uuid }) { ruuviStorage.readLatest(tag).on(success: { localRecord in let record = ruuviTag.with(source: .heartbeat) if let localRecord, - record.macId?.value == localRecord.macId?.value - { + record.macId?.value == localRecord.macId?.value { observer.ruuviPool.updateLast(record) } else { observer.ruuviPool.createLast(record) @@ -344,12 +357,14 @@ extension RuuviTagHeartbeatDaemonBTKit { disconnectTokens[uuid]?.invalidate() disconnectTokens.removeValue(forKey: uuid) connectTokens[uuid] = background - .connect(for: self, - uuid: uuid, - options: [.callbackQueue(.untouch)], - connected: connectedHandler(for: uuid), - heartbeat: heartbeatHandler(), - disconnected: disconnectedHandler(for: uuid)) + .connect( + for: self, + uuid: uuid, + options: [.callbackQueue(.untouch)], + connected: connectedHandler(for: uuid), + heartbeat: heartbeatHandler(), + disconnected: disconnectedHandler(for: uuid) + ) } @objc private func disconnect(uuid: String) { @@ -358,10 +373,12 @@ extension RuuviTagHeartbeatDaemonBTKit { sensorSettingsTokens[uuid]?.invalidate() sensorSettingsTokens.removeValue(forKey: uuid) disconnectTokens[uuid] = background - .disconnect(for: self, - uuid: uuid, - options: [.callbackQueue(.untouch)], - result: disconnectedHandler(for: uuid)) + .disconnect( + for: self, + uuid: uuid, + options: [.callbackQueue(.untouch)], + result: disconnectedHandler(for: uuid) + ) } private func invalidateTokens() { @@ -380,9 +397,11 @@ extension RuuviTagHeartbeatDaemonBTKit { DispatchQueue.main.async { NotificationCenter .default - .post(name: .RuuviTagHeartbeatDaemonDidFail, - object: nil, - userInfo: [RuuviTagHeartbeatDaemonDidFailKey.error: error]) + .post( + name: .RuuviTagHeartbeatDaemonDidFail, + object: nil, + userInfo: [RuuviTagHeartbeatDaemonDidFailKey.error: error] + ) } } diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift index fa2252cf7..f9cc9e9cc 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift @@ -71,8 +71,7 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro where: { ($0.macId != nil && $0.macId?.any == ruuviTag.macId?.any) || ($0.luid != nil && $0.luid?.any == ruuviTag.luid?.any) - }) - { + }) { sSelf.ruuviTags[index] = ruuviTag } sSelf.restartObserving() @@ -93,11 +92,13 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro } public func stop() { - perform(#selector(RuuviTagPropertiesDaemonBTKit.stopDaemon), - on: thread, - with: nil, - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) + perform( + #selector(RuuviTagPropertiesDaemonBTKit.stopDaemon), + on: thread, + with: nil, + waitUntilDone: false, + modes: [RunLoop.Mode.default.rawValue] + ) } @objc private func stopDaemon() { @@ -117,21 +118,24 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro removeTokens() for ruuviTag in ruuviTags { if let luid = ruuviTag.luid { - observeTokens.append(foreground.observe(self, - uuid: luid.value, - options: [.callbackQueue(.untouch)]) - { - [weak self] _, device in - guard let sSelf = self else { return } - if let tag = device.ruuvi?.tag { - let pair = RuuviTagPropertiesDaemonPair(ruuviTag: ruuviTag, device: tag) - sSelf.perform(#selector(RuuviTagPropertiesDaemonBTKit.tryToUpdate(pair:)), - on: sSelf.thread, - with: pair, - waitUntilDone: false, - modes: [RunLoop.Mode.default.rawValue]) - } - }) + observeTokens.append(foreground.observe( + self, + uuid: luid.value, + options: [.callbackQueue(.untouch)] + ) { + [weak self] _, device in + guard let sSelf = self else { return } + if let tag = device.ruuvi?.tag { + let pair = RuuviTagPropertiesDaemonPair(ruuviTag: ruuviTag, device: tag) + sSelf.perform( + #selector(RuuviTagPropertiesDaemonBTKit.tryToUpdate(pair:)), + on: sSelf.thread, + with: pair, + waitUntilDone: false, + modes: [RunLoop.Mode.default.rawValue] + ) + } + }) } else if ruuviTag.isCloud { scanRemoteSensor(ruuviTag: ruuviTag) } @@ -204,8 +208,7 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro // this is the case when 2.5.9 tag is returning to data format 3 mode // but we have it in sqlite database already if let mac = idPersistence.mac(for: pair.device.uuid.luid), - pair.device.version != pair.ruuviTag.version - { + pair.device.version != pair.ruuviTag.version { ruuviPool.update(pair.ruuviTag .with(macId: mac) .with(version: pair.device.version)) @@ -271,9 +274,11 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro DispatchQueue.main.async { NotificationCenter .default - .post(name: .RuuviTagPropertiesDaemonDidFail, - object: nil, - userInfo: [RuuviTagPropertiesDaemonDidFailKey.error: error]) + .post( + name: .RuuviTagPropertiesDaemonDidFail, + object: nil, + userInfo: [RuuviTagPropertiesDaemonDidFailKey.error: error] + ) } } } diff --git a/Packages/RuuviLocal/Package.swift b/Packages/RuuviLocal/Package.swift index 67bca1c34..2b6c487e0 100644 --- a/Packages/RuuviLocal/Package.swift +++ b/Packages/RuuviLocal/Package.swift @@ -31,7 +31,7 @@ let package = Package( .target( name: "RuuviLocalUserDefaults", dependencies: [ - "RuuviLocal", + "RuuviLocal" ] ), .testTarget( diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/Documents/ImagePersistenceDocuments.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/Documents/ImagePersistenceDocuments.swift index f6a8d5ef5..c663ac74b 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/Documents/ImagePersistenceDocuments.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/Documents/ImagePersistenceDocuments.swift @@ -40,7 +40,8 @@ class ImagePersistenceDocuments: ImagePersistence { } private func getBgDirectory() throws -> URL { - guard let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { + guard let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first + else { throw RuuviLocalError.failedToGetDocumentsDirectory } let dir = docDir.appendingPathComponent(bgDir, isDirectory: true) diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/RuuviLocalImagesUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/RuuviLocalImagesUserDefaults.swift index b2a85b517..eee3aa941 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/RuuviLocalImagesUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/RuuviLocalImagesUserDefaults.swift @@ -22,8 +22,7 @@ final class RuuviLocalImagesUserDefaults: RuuviLocalImages { private var usedBackgrounds: [Int] { if let ub = UserDefaults.standard.array(forKey: usedBackgroundsUDKey) as? [Int], - ub.count == bgMaxIndex - { + ub.count == bgMaxIndex { return ub } else { let ub = Array(repeating: 0, count: bgMaxIndex - bgMinIndex + 1) @@ -95,9 +94,11 @@ final class RuuviLocalImagesUserDefaults: RuuviLocalImages { } NotificationCenter .default - .post(name: .BackgroundPersistenceDidChangeBackground, - object: nil, - userInfo: [userInfoKey: identifier]) + .post( + name: .BackgroundPersistenceDidChangeBackground, + object: nil, + userInfo: [userInfoKey: identifier] + ) promise.succeed(value: url) }, failure: { error in promise.fail(error: error) @@ -121,9 +122,11 @@ final class RuuviLocalImagesUserDefaults: RuuviLocalImages { } NotificationCenter .default - .post(name: .BackgroundPersistenceDidChangeBackground, - object: nil, - userInfo: [userInfoKey: identifier]) + .post( + name: .BackgroundPersistenceDidChangeBackground, + object: nil, + userInfo: [userInfoKey: identifier] + ) if id >= bgMinIndex, id <= bgMaxIndex { var array = usedBackgrounds array[id - bgMinIndex] += 1 @@ -182,12 +185,14 @@ final class RuuviLocalImagesUserDefaults: RuuviLocalImages { } NotificationCenter .default - .post(name: .BackgroundPersistenceDidUpdateBackgroundUploadProgress, - object: nil, - userInfo: [ - userInfoKey: identifier, - BPDidUpdateBackgroundUploadProgressKey.progress: percentage, - ]) + .post( + name: .BackgroundPersistenceDidUpdateBackgroundUploadProgress, + object: nil, + userInfo: [ + userInfoKey: identifier, + BPDidUpdateBackgroundUploadProgressKey.progress: percentage, + ] + ) UserDefaults.standard.setValue(percentage, forKey: key) } diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalConnectionsUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalConnectionsUserDefaults.swift index 773ba96c7..4d065bb44 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalConnectionsUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalConnectionsUserDefaults.swift @@ -7,64 +7,110 @@ final class RuuviLocalConnectionsUserDefaults: RuuviLocalConnections { private let keepConnectionArrayUDKey = "ConnectionPersistenceUserDefaults.keepConnection.array" var keepConnectionUUIDs: [AnyLocalIdentifier] { - let strings = prefs.array(forKey: keepConnectionArrayUDKey) as? [String] - return strings?.map(\.luid.any) ?? [] + let strings = prefs.array( + forKey: keepConnectionArrayUDKey + ) as? [String] + return strings?.map( + \.luid.any + ) ?? [] } - func keepConnection(to luid: LocalIdentifier) -> Bool { + func keepConnection( + to luid: LocalIdentifier + ) -> Bool { let uuid = luid.value - assert(uuid.count == 36) - if let array = prefs.array(forKey: keepConnectionArrayUDKey) as? [String] { - return array.contains(uuid) + assert( + uuid.count == 36 + ) + if let array = prefs.array( + forKey: keepConnectionArrayUDKey + ) as? [String] { + return array.contains( + uuid + ) } else { return false } } - func setKeepConnection(_ value: Bool, for luid: LocalIdentifier) { + func setKeepConnection( + _ value: Bool, + for luid: LocalIdentifier + ) { let uuid = luid.value - assert(uuid.count == 36) + assert( + uuid.count == 36 + ) if value { - if var array = prefs.array(forKey: keepConnectionArrayUDKey) as? [String], - !array.contains(uuid) - { - array.append(uuid) - prefs.set(array, forKey: keepConnectionArrayUDKey) - NotificationCenter.default.post(name: .ConnectionPersistenceDidStartToKeepConnection, - object: nil, - userInfo: - [CPDidStartToKeepConnectionKey.uuid: uuid]) + if var array = prefs.array( + forKey: keepConnectionArrayUDKey + ) as? [String], + !array.contains( + uuid + ) { + array.append( + uuid + ) + prefs.set( + array, + forKey: keepConnectionArrayUDKey + ) + NotificationCenter.default.post( + name: .ConnectionPersistenceDidStartToKeepConnection, + object: nil, + userInfo: [CPDidStartToKeepConnectionKey.uuid: uuid] + ) } else { var array = [String]() - array.append(uuid) - prefs.set(array, forKey: keepConnectionArrayUDKey) - NotificationCenter.default.post(name: .ConnectionPersistenceDidStartToKeepConnection, - object: nil, - userInfo: - [CPDidStartToKeepConnectionKey.uuid: uuid]) + array.append( + uuid + ) + prefs.set( + array, + forKey: keepConnectionArrayUDKey + ) + NotificationCenter.default.post( + name: .ConnectionPersistenceDidStartToKeepConnection, + object: nil, + userInfo: [CPDidStartToKeepConnectionKey.uuid: uuid] + ) } } else { - if var array = prefs.array(forKey: keepConnectionArrayUDKey) as? [String] { - array.removeAll(where: { $0 == uuid }) - prefs.set(array, forKey: keepConnectionArrayUDKey) - NotificationCenter.default.post(name: .ConnectionPersistenceDidStopToKeepConnection, - object: nil, - userInfo: - [CPDidStopToKeepConnectionKey.uuid: uuid]) + if var array = prefs.array( + forKey: keepConnectionArrayUDKey + ) as? [String] { + array.removeAll(where: { + $0 == uuid + }) + prefs.set( + array, + forKey: keepConnectionArrayUDKey + ) + NotificationCenter.default.post( + name: .ConnectionPersistenceDidStopToKeepConnection, + object: nil, + userInfo: [CPDidStopToKeepConnectionKey.uuid: uuid] + ) } } } func unpairAllConnection() { - if var array = prefs.array(forKey: keepConnectionArrayUDKey) as? [String] { + if var array = prefs.array( + forKey: keepConnectionArrayUDKey + ) as? [String] { for uuid in array { - NotificationCenter.default.post(name: .ConnectionPersistenceDidStopToKeepConnection, - object: nil, - userInfo: - [CPDidStopToKeepConnectionKey.uuid: uuid]) + NotificationCenter.default.post( + name: .ConnectionPersistenceDidStopToKeepConnection, + object: nil, + userInfo: [CPDidStopToKeepConnectionKey.uuid: uuid] + ) } array.removeAll() - prefs.set(array, forKey: keepConnectionArrayUDKey) + prefs.set( + array, + forKey: keepConnectionArrayUDKey + ) } } } diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift index 3430e04a4..7b5e05aa3 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift @@ -57,9 +57,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { UserDefaults.standard.set(newValue.rawValue, forKey: languageUDKey) NotificationCenter .default - .post(name: .LanguageDidChange, - object: self, - userInfo: nil) + .post( + name: .LanguageDidChange, + object: self, + userInfo: nil + ) } } @@ -90,9 +92,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { } NotificationCenter .default - .post(name: .HumidityUnitDidChange, - object: self, - userInfo: nil) + .post( + name: .HumidityUnitDidChange, + object: self, + userInfo: nil + ) } } @@ -116,9 +120,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { humidityAccuracyInt = newValue.value NotificationCenter .default - .post(name: .HumidityAccuracyDidChange, - object: self, - userInfo: nil) + .post( + name: .HumidityAccuracyDidChange, + object: self, + userInfo: nil + ) } } @@ -149,9 +155,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { } NotificationCenter .default - .post(name: .TemperatureUnitDidChange, - object: self, - userInfo: nil) + .post( + name: .TemperatureUnitDidChange, + object: self, + userInfo: nil + ) } } @@ -175,9 +183,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { temperatureAccuracyInt = newValue.value NotificationCenter .default - .post(name: .TemperatureAccuracyDidChange, - object: self, - userInfo: nil) + .post( + name: .TemperatureAccuracyDidChange, + object: self, + userInfo: nil + ) } } @@ -196,9 +206,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { pressureUnitInt = newValue.hashValue NotificationCenter .default - .post(name: .PressureUnitDidChange, - object: self, - userInfo: nil) + .post( + name: .PressureUnitDidChange, + object: self, + userInfo: nil + ) } } @@ -222,9 +234,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { pressureAccuracyInt = newValue.value NotificationCenter .default - .post(name: .PressureUnitAccuracyChange, - object: self, - userInfo: nil) + .post( + name: .PressureUnitAccuracyChange, + object: self, + userInfo: nil + ) } } @@ -245,9 +259,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { didSet { NotificationCenter .default - .post(name: .isAdvertisementDaemonOnDidChange, - object: self, - userInfo: nil) + .post( + name: .isAdvertisementDaemonOnDidChange, + object: self, + userInfo: nil + ) } } @@ -283,9 +299,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { didSet { NotificationCenter .default - .post(name: .ChartDurationHourDidChange, - object: self, - userInfo: nil) + .post( + name: .ChartDurationHourDidChange, + object: self, + userInfo: nil + ) } } @@ -338,9 +356,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { didSet { NotificationCenter .default - .post(name: .DownsampleOnDidChange, - object: self, - userInfo: nil) + .post( + name: .DownsampleOnDidChange, + object: self, + userInfo: nil + ) } } @@ -349,9 +369,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { didSet { NotificationCenter .default - .post(name: .ChartDrawDotsOnDidChange, - object: self, - userInfo: nil) + .post( + name: .ChartDrawDotsOnDidChange, + object: self, + userInfo: nil + ) } } @@ -360,9 +382,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { didSet { NotificationCenter .default - .post(name: .ChartStatsOnDidChange, - object: self, - userInfo: nil) + .post( + name: .ChartStatsOnDidChange, + object: self, + userInfo: nil + ) } } @@ -377,9 +401,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { didSet { NotificationCenter .default - .post(name: .CloudModeDidChange, - object: self, - userInfo: nil) + .post( + name: .CloudModeDidChange, + object: self, + userInfo: nil + ) } } @@ -466,9 +492,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { } NotificationCenter .default - .post(name: .DashboardTypeDidChange, - object: self, - userInfo: [DashboardTypeKey.type: newValue]) + .post( + name: .DashboardTypeDidChange, + object: self, + userInfo: [DashboardTypeKey.type: newValue] + ) } } @@ -504,9 +532,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { } NotificationCenter .default - .post(name: .DashboardTapActionTypeDidChange, - object: self, - userInfo: [DashboardTapActionTypeKey.type: newValue]) + .post( + name: .DashboardTapActionTypeDidChange, + object: self, + userInfo: [DashboardTapActionTypeKey.type: newValue] + ) } } @@ -546,9 +576,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { } NotificationCenter .default - .post(name: .AppearanceSettingsDidChange, - object: self, - userInfo: [AppearanceTypeKey.style: newValue]) + .post( + name: .AppearanceSettingsDidChange, + object: self, + userInfo: [AppearanceTypeKey.style: newValue] + ) } } @@ -575,9 +607,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { UserDefaults.standard.set(newValue.rawValue, forKey: ruuviAlertSoundKey) NotificationCenter .default - .post(name: .AlertSoundSettingsDidChange, - object: self, - userInfo: [AppearanceTypeKey.style: newValue]) + .post( + name: .AlertSoundSettingsDidChange, + object: self, + userInfo: [AppearanceTypeKey.style: newValue] + ) } } @@ -590,9 +624,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { DispatchQueue.global(qos: .userInitiated).async { NotificationCenter .default - .post(name: .EmailAlertSettingsDidChange, - object: self, - userInfo: nil) + .post( + name: .EmailAlertSettingsDidChange, + object: self, + userInfo: nil + ) } } } @@ -606,9 +642,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { DispatchQueue.global(qos: .userInitiated).async { NotificationCenter .default - .post(name: .PushAlertSettingsDidChange, - object: self, - userInfo: nil) + .post( + name: .PushAlertSettingsDidChange, + object: self, + userInfo: nil + ) } } } @@ -619,9 +657,11 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { DispatchQueue.global(qos: .userInitiated).async { NotificationCenter .default - .post(name: .LimitAlertNotificationsSettingsDidChange, - object: self, - userInfo: nil) + .post( + name: .LimitAlertNotificationsSettingsDidChange, + object: self, + userInfo: nil + ) } } } diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSyncStateUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSyncStateUserDefaults.swift index 8ca53bbfc..66eafaf15 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSyncStateUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSyncStateUserDefaults.swift @@ -47,11 +47,11 @@ final class RuuviLocalSyncStateUserDefaults: RuuviLocalSyncState { DispatchQueue.main.async { NotificationCenter .default - .post(name: .NetworkHistorySyncDidCompleteForSensor, - object: nil, - userInfo: [ - NetworkSyncStatusKey.mac: macId, - ]) + .post( + name: .NetworkHistorySyncDidCompleteForSensor, + object: nil, + userInfo: [NetworkSyncStatusKey.mac: macId] + ) } } @@ -108,7 +108,7 @@ final class RuuviLocalSyncStateUserDefaults: RuuviLocalSyncState { NotificationCenter .default .post(name: .NetworkSyncDidChangeCommonStatus, object: self, userInfo: [ - NetworkSyncStatusKey.status: newValue, + NetworkSyncStatusKey.status: newValue ]) } } diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/AlertService/MigrationManagerAlertService.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/AlertService/MigrationManagerAlertService.swift index ab6742a00..2f673895c 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/AlertService/MigrationManagerAlertService.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/AlertService/MigrationManagerAlertService.swift @@ -99,26 +99,32 @@ extension MigrationManagerAlertService { if prefs.bool(forKey: Keys.Ver1.relativeHumidityAlertIsOnUDKeyPrefix + id), let lower = prefs.optionalDouble(forKey: Keys.Ver1.relativeHumidityLowerBoundUDKeyPrefix + id), let upper = prefs.optionalDouble(forKey: Keys.Ver1.relativeHumidityUpperBoundUDKeyPrefix + id), - let temperature = element.1 - { + let temperature = element.1 { prefs.set(false, forKey: Keys.Ver1.relativeHumidityAlertIsOnUDKeyPrefix + id) - let lowerHumidity = Humidity(value: lower / 100, - unit: .relative(temperature: temperature)) - let upperHumidity = Humidity(value: upper / 100, - unit: .relative(temperature: temperature)) + let lowerHumidity = Humidity( + value: lower / 100, + unit: .relative(temperature: temperature) + ) + let upperHumidity = Humidity( + value: upper / 100, + unit: .relative(temperature: temperature) + ) ruuviAlertService.register( type: .humidity(lower: lowerHumidity, upper: upperHumidity), ruuviTag: element.0 ) } else if prefs.bool(forKey: Keys.Ver1.absoluteHumidityAlertIsOnUDKeyPrefix + id), let lower = prefs.optionalDouble(forKey: Keys.Ver1.absoluteHumidityLowerBoundUDKeyPrefix + id), - let upper = prefs.optionalDouble(forKey: Keys.Ver1.absoluteHumidityUpperBoundUDKeyPrefix + id) - { + let upper = prefs.optionalDouble(forKey: Keys.Ver1.absoluteHumidityUpperBoundUDKeyPrefix + id) { prefs.set(false, forKey: Keys.Ver1.absoluteHumidityAlertIsOnUDKeyPrefix + id) - let lowerHumidity = Humidity(value: lower, - unit: .absolute) - let upperHumidity = Humidity(value: upper, - unit: .absolute) + let lowerHumidity = Humidity( + value: lower, + unit: .absolute + ) + let upperHumidity = Humidity( + value: upper, + unit: .absolute + ) ruuviAlertService.register( type: .humidity(lower: lowerHumidity, upper: upperHumidity), ruuviTag: element.0 diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift index f0139aa3f..613175356 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift @@ -59,14 +59,16 @@ public final class RuuviMigrationFactoryImpl: RuuviMigrationFactory { ruuviAlertService: ruuviAlertService ) let toNetworkPull60 = MigrationManagerToNetworkPull60(settings: settings) - return [toSQLite, - toAlertService, - toPrune240, - toChartDuration240, - toSensorSettings, - toRH, - toTimeouts, - fixRHAlerts, - toNetworkPull60] + return [ + toSQLite, + toAlertService, + toPrune240, + toChartDuration240, + toSensorSettings, + toRH, + toTimeouts, + fixRHAlerts, + toNetworkPull60, + ] } } diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/fixRHAlerts/RuuviMigrationFixRHAlerts.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/fixRHAlerts/RuuviMigrationFixRHAlerts.swift index 5d4bf5a4e..bd551d126 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/fixRHAlerts/RuuviMigrationFixRHAlerts.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/fixRHAlerts/RuuviMigrationFixRHAlerts.swift @@ -28,8 +28,7 @@ final class RuuviMigrationFixRHAlerts: RuuviMigration { .on(success: { sensors in sensors.forEach { sensor in if let lower = self.ruuviAlertService.lowerRelativeHumidity(for: sensor), - lower > 1.0 - { + lower > 1.0 { self.ruuviAlertService.setLower( relativeHumidity: lower / 100.0, ruuviTag: sensor diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toRH/MigrationManagerToRH.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toRH/MigrationManagerToRH.swift index e1321efe8..98e12af1a 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toRH/MigrationManagerToRH.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toRH/MigrationManagerToRH.swift @@ -29,8 +29,7 @@ final class MigrationManagerToRH: RuuviMigration { let temperature = tuple.1 if let lower = self.ruuviAlertService.lowerHumidity(for: sensor), let upper = self.ruuviAlertService.upperHumidity(for: sensor), - let temperature - { + let temperature { let humidityType: AlertType = .humidity(lower: lower, upper: upper) if self.ruuviAlertService.isOn(type: humidityType, for: sensor) { self.ruuviAlertService.register( diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift index 08e4b0f88..d1b544ed3 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift @@ -42,9 +42,11 @@ class MigrationManagerToSQLite: RuuviMigration { dispatchGroup.notify(queue: .main) { NotificationCenter .default - .post(name: .MigrationManagerToSQLiteDidFinish, - object: self, - userInfo: nil) + .post( + name: .MigrationManagerToSQLiteDidFinish, + object: self, + userInfo: nil + ) } didMigrateRuuviTagRealmWithMAC = true } diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift index 5767a574a..ce94e097a 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift @@ -73,18 +73,20 @@ public final class MigrationManagerToVIPER: RuuviMigration { private func from1to2(_ migration: Migration) { migration.enumerateObjects(ofType: "RuuviTag") { oldObject, _ in - if let uuid = oldObject?["uuid"] as? String, let name = oldObject?["name"] as? String, let version = oldObject?["dataFormat"] as? Int, - let mac = oldObject?["mac"] as? String - { + let mac = oldObject?["mac"] as? String { let realName = real(name, mac, uuid) - let ruuviTag = migration.create(RuuviTagRealm.className(), - value: ["uuid": uuid, - "name": realName, - "version": version, - "mac": mac]) + let ruuviTag = migration.create( + RuuviTagRealm.className(), + value: [ + "uuid": uuid, + "name": realName, + "version": version, + "mac": mac, + ] + ) if let temperature = oldObject?["temperature"] as? Double, let humidity = oldObject?["humidity"] as? Double, @@ -97,22 +99,25 @@ public final class MigrationManagerToVIPER: RuuviMigration { let movementCounter = oldObject?["movementCounter"] as? Int, let measurementSequenceNumber = oldObject?["measurementSequenceNumber"] as? Int, let txPower = oldObject?["txPower"] as? Int, - let updatedAt = oldObject?["updatedAt"] as? NSDate - { - migration.create(RuuviTagDataRealm.className(), - value: ["ruuviTag": ruuviTag, - "date": updatedAt, - "rssi": rssi, - "celsius": temperature, - "humidity": humidity, - "pressure": pressure, - "accelerationX": accelerationX, - "accelerationY": accelerationY, - "accelerationZ": accelerationZ, - "voltage": voltage, - "movementCounter": movementCounter, - "measurementSequenceNumber": measurementSequenceNumber, - "txPower": txPower]) + let updatedAt = oldObject?["updatedAt"] as? NSDate { + migration.create( + RuuviTagDataRealm.className(), + value: [ + "ruuviTag": ruuviTag, + "date": updatedAt, + "rssi": rssi, + "celsius": temperature, + "humidity": humidity, + "pressure": pressure, + "accelerationX": accelerationX, + "accelerationY": accelerationY, + "accelerationZ": accelerationZ, + "voltage": voltage, + "movementCounter": movementCounter, + "measurementSequenceNumber": measurementSequenceNumber, + "txPower": txPower, + ] + ) } } diff --git a/Packages/RuuviNotification/Sources/RuuviNotification/RuuviNotificationLocal.swift b/Packages/RuuviNotification/Sources/RuuviNotification/RuuviNotificationLocal.swift index 9b8c11973..7a9687e74 100644 --- a/Packages/RuuviNotification/Sources/RuuviNotification/RuuviNotificationLocal.swift +++ b/Packages/RuuviNotification/Sources/RuuviNotification/RuuviNotificationLocal.swift @@ -14,9 +14,11 @@ public protocol RuuviNotificationLocalOutput: AnyObject { } public protocol RuuviNotificationLocal: AnyObject { - func setup(disableTitle: String, - muteTitle: String, - output: RuuviNotificationLocalOutput?) + func setup( + disableTitle: String, + muteTitle: String, + output: RuuviNotificationLocalOutput? + ) func showDidConnect(uuid: String, title: String) func showDidDisconnect(uuid: String, title: String) diff --git a/Packages/RuuviNotification/Sources/RuuviNotificationLocal/RuuviNotificationLocalImpl.swift b/Packages/RuuviNotification/Sources/RuuviNotificationLocal/RuuviNotificationLocalImpl.swift index 59e8c94ec..6ba15a039 100644 --- a/Packages/RuuviNotification/Sources/RuuviNotificationLocal/RuuviNotificationLocalImpl.swift +++ b/Packages/RuuviNotification/Sources/RuuviNotificationLocal/RuuviNotificationLocalImpl.swift @@ -72,10 +72,11 @@ public final class RuuviNotificationLocalImpl: NSObject, RuuviNotificationLocal private var alertDidChangeToken: NSObjectProtocol? - public func setup(disableTitle: String, - muteTitle: String, - output: RuuviNotificationLocalOutput?) - { + public func setup( + disableTitle: String, + muteTitle: String, + output: RuuviNotificationLocalOutput? + ) { setupButtons(disableTitle: disableTitle, muteTitle: muteTitle) startObserving() self.output = output @@ -331,8 +332,11 @@ public extension RuuviNotificationLocalImpl { ruuviStorage.readOne(id(for: uuid)).on(success: { ruuviTag in content.subtitle = ruuviTag.name let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.1, repeats: false) - let request = UNNotificationRequest(identifier: uuid + type.rawValue, - content: content, trigger: trigger) + let request = UNNotificationRequest( + identifier: uuid + type.rawValue, + content: content, + trigger: trigger + ) UNUserNotificationCenter.current().add(request, withCompletionHandler: nil) }) @@ -402,59 +406,59 @@ extension RuuviNotificationLocalImpl { private func startObserving() { alertDidChangeToken = NotificationCenter .default - .addObserver(forName: .RuuviServiceAlertDidChange, - object: nil, - queue: .main) - { [weak self] notification in - if let userInfo = notification.userInfo, - let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType - { - let physicalSensor = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor - - var isOn = false - if let physicalSensor { - isOn = self?.ruuviAlertService.isOn(type: type, for: physicalSensor) ?? false - } + .addObserver( + forName: .RuuviServiceAlertDidChange, + object: nil, + queue: .main + ) { [weak self] notification in + if let userInfo = notification.userInfo, + let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType { + let physicalSensor = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor + + var isOn = false + if let physicalSensor { + isOn = self?.ruuviAlertService.isOn(type: type, for: physicalSensor) ?? false + } - if let uuid = physicalSensor?.luid?.value ?? physicalSensor?.macId?.value { - switch type { - case .temperature: - self?.lowTemperatureAlerts[uuid] = nil - self?.highTemperatureAlerts[uuid] = nil - if !isOn { - self?.cancel(.temperature, for: uuid) - } - case .relativeHumidity: - self?.lowRelativeHumidityAlerts[uuid] = nil - self?.highRelativeHumidityAlerts[uuid] = nil - if !isOn { - self?.cancel(.relativeHumidity, for: uuid) + if let uuid = physicalSensor?.luid?.value ?? physicalSensor?.macId?.value { + switch type { + case .temperature: + self?.lowTemperatureAlerts[uuid] = nil + self?.highTemperatureAlerts[uuid] = nil + if !isOn { + self?.cancel(.temperature, for: uuid) + } + case .relativeHumidity: + self?.lowRelativeHumidityAlerts[uuid] = nil + self?.highRelativeHumidityAlerts[uuid] = nil + if !isOn { + self?.cancel(.relativeHumidity, for: uuid) + } + case .humidity: + self?.lowHumidityAlerts[uuid] = nil + self?.highHumidityAlerts[uuid] = nil + if !isOn { + self?.cancel(.humidity, for: uuid) + } + case .pressure: + self?.lowPressureAlerts[uuid] = nil + self?.highPressureAlerts[uuid] = nil + if !isOn { + self?.cancel(.pressure, for: uuid) + } + case .signal: + self?.lowSignalAlerts[uuid] = nil + self?.highSignalAlerts[uuid] = nil + if !isOn { + self?.cancel(.signal, for: uuid) + } + case .connection, .cloudConnection, .movement: + // do nothing + break } - case .humidity: - self?.lowHumidityAlerts[uuid] = nil - self?.highHumidityAlerts[uuid] = nil - if !isOn { - self?.cancel(.humidity, for: uuid) - } - case .pressure: - self?.lowPressureAlerts[uuid] = nil - self?.highPressureAlerts[uuid] = nil - if !isOn { - self?.cancel(.pressure, for: uuid) - } - case .signal: - self?.lowSignalAlerts[uuid] = nil - self?.highSignalAlerts[uuid] = nil - if !isOn { - self?.cancel(.signal, for: uuid) - } - case .connection, .cloudConnection, .movement: - // do nothing - break } } } - } } } @@ -520,8 +524,7 @@ extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { let userInfo = response.notification.request.content.userInfo if let uuid = userInfo[lowHigh.uuidKey] as? String, let typeString = userInfo[lowHigh.typeKey] as? String, - let type = LowHighNotificationType(rawValue: typeString) - { + let type = LowHighNotificationType(rawValue: typeString) { switch response.actionIdentifier { case lowHigh.disable: // TODO: @rinat go with sensors instead of pure uuid @@ -546,11 +549,9 @@ extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { default: break } - } else if let uuid = userInfo[blast.uuidKey] as? String, let typeString = userInfo[blast.typeKey] as? String, - let type = BlastNotificationType(rawValue: typeString) - { + let type = BlastNotificationType(rawValue: typeString) { switch response.actionIdentifier { case blast.disable: // TODO: @rinat go with sensors instead of pure uuid @@ -578,8 +579,7 @@ extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { } if let uuid = userInfo[lowHigh.uuidKey] as? String - ?? userInfo[blast.uuidKey] as? String - { + ?? userInfo[blast.uuidKey] as? String { NotificationCenter.default.post(name: .LNMDidReceive, object: nil, userInfo: [LNMDidReceiveKey.uuid: uuid]) output?.notificationDidTap(for: uuid) } @@ -599,7 +599,8 @@ extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { } private func mute(type: LowHighNotificationType, uuid: String) { - guard let date = muteOffset() else { + guard let date = muteOffset() + else { assertionFailure(); return } // TODO: @rinat go with sensors instead of pure uuid @@ -626,7 +627,8 @@ extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { } private func mute(type: BlastNotificationType, uuid: String) { - guard let date = muteOffset() else { + guard let date = muteOffset() + else { assertionFailure(); return } // TODO: @rinat go with sensors instead of pure uuid diff --git a/Packages/RuuviNotifier/Package.swift b/Packages/RuuviNotifier/Package.swift index 76b97422c..c6ab4b7e7 100644 --- a/Packages/RuuviNotifier/Package.swift +++ b/Packages/RuuviNotifier/Package.swift @@ -25,7 +25,7 @@ let package = Package( .target( name: "RuuviNotifier", dependencies: [ - "RuuviOntology", + "RuuviOntology" ] ), .target( diff --git a/Packages/RuuviNotifier/Sources/RuuviNotifier/RuuviNotifier.swift b/Packages/RuuviNotifier/Sources/RuuviNotifier/RuuviNotifier.swift index ba6c750c9..5e61c5a77 100644 --- a/Packages/RuuviNotifier/Sources/RuuviNotifier/RuuviNotifier.swift +++ b/Packages/RuuviNotifier/Sources/RuuviNotifier/RuuviNotifier.swift @@ -12,18 +12,22 @@ public protocol RuuviNotifier { public protocol RuuviNotifierObserver: AnyObject { func ruuvi(notifier: RuuviNotifier, isTriggered: Bool, for uuid: String) // Optional method - func ruuvi(notifier: RuuviNotifier, - alertType: AlertType, - isTriggered: Bool, - for uuid: String) + func ruuvi( + notifier: RuuviNotifier, + alertType: AlertType, + isTriggered: Bool, + for uuid: String + ) } public extension RuuviNotifierObserver { // Optional method implementation - func ruuvi(notifier _: RuuviNotifier, - alertType _: AlertType, - isTriggered _: Bool, - for _: String) {} + func ruuvi( + notifier _: RuuviNotifier, + alertType _: AlertType, + isTriggered _: Bool, + for _: String + ) {} } public protocol RuuviNotifierTitles { diff --git a/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl+Process.swift b/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl+Process.swift index 57e9e1e4e..517a18726 100644 --- a/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl+Process.swift +++ b/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl+Process.swift @@ -54,9 +54,11 @@ public extension RuuviNotifierImpl { isTriggered = isTriggered || isSignal notify(alertType: type, uuid: luid.value, isTriggered: isSignal) case .movement: - let isMovement = process(movement: type, - record: record, - trigger: trigger) + let isMovement = process( + movement: type, + record: record, + trigger: trigger + ) isTriggered = isTriggered || isMovement notify(alertType: type, uuid: luid.value, isTriggered: isMovement) default: @@ -77,11 +79,13 @@ public extension RuuviNotifierImpl { public extension RuuviNotifierImpl { // swiftlint:disable:next function_body_length - func processNetwork(record: RuuviTagSensorRecord, - trigger: Bool, - for identifier: MACIdentifier) - { - guard ruuviAlertService.hasRegistrations(for: record) else { + func processNetwork( + record: RuuviTagSensorRecord, + trigger: Bool, + for identifier: MACIdentifier + ) { + guard ruuviAlertService.hasRegistrations(for: record) + else { return } @@ -89,14 +93,18 @@ public extension RuuviNotifierImpl { AlertType.allCases.forEach { type in switch type { case .temperature: - let isTemperature = process(temperature: record.temperature, - alertType: type, - identifier: identifier, - trigger: trigger) + let isTemperature = process( + temperature: record.temperature, + alertType: type, + identifier: identifier, + trigger: trigger + ) isTriggered = isTriggered || isTemperature - notify(alertType: type, - uuid: identifier.value, - isTriggered: isTemperature) + notify( + alertType: type, + uuid: identifier.value, + isTriggered: isTemperature + ) case .relativeHumidity: let isRelativeHumidity = process( relativeHumidity: record.humidity, @@ -106,36 +114,48 @@ public extension RuuviNotifierImpl { trigger: trigger ) isTriggered = isTriggered || isRelativeHumidity - notify(alertType: type, - uuid: identifier.value, - isTriggered: isRelativeHumidity) + notify( + alertType: type, + uuid: identifier.value, + isTriggered: isRelativeHumidity + ) case .pressure: - let isPressure = process(pressure: record.pressure, - alertType: type, - identifier: identifier, - trigger: trigger) + let isPressure = process( + pressure: record.pressure, + alertType: type, + identifier: identifier, + trigger: trigger + ) isTriggered = isTriggered || isPressure - notify(alertType: type, - uuid: identifier.value, - isTriggered: isPressure) + notify( + alertType: type, + uuid: identifier.value, + isTriggered: isPressure + ) case .signal: - let isSignal = process(signal: record.rssi, - alertType: type, - identifier: identifier, - trigger: trigger) + let isSignal = process( + signal: record.rssi, + alertType: type, + identifier: identifier, + trigger: trigger + ) isTriggered = isTriggered || isSignal - notify(alertType: type, - uuid: identifier.value, - isTriggered: isSignal) + notify( + alertType: type, + uuid: identifier.value, + isTriggered: isSignal + ) case .cloudConnection: let isCloudConnection = processCloudConnection( alertType: type, identifier: identifier ) isTriggered = isTriggered || isCloudConnection - notify(alertType: type, - uuid: identifier.value, - isTriggered: isCloudConnection) + notify( + alertType: type, + uuid: identifier.value, + isTriggered: isCloudConnection + ) default: break } @@ -155,8 +175,7 @@ extension RuuviNotifierImpl { for i in 0 ..< observers.count { if let pointer = observers.pointer(at: i), let observer = Unmanaged.fromOpaque(pointer).takeUnretainedValue() - as? RuuviNotifierObserver - { + as? RuuviNotifierObserver { observer.ruuvi( notifier: sSelf, isTriggered: isTriggered, @@ -175,8 +194,7 @@ extension RuuviNotifierImpl { for i in 0 ..< observers.count { if let pointer = observers.pointer(at: i), let observer = Unmanaged.fromOpaque(pointer).takeUnretainedValue() - as? RuuviNotifierObserver - { + as? RuuviNotifierObserver { observer.ruuvi( notifier: sSelf, alertType: alertType, @@ -203,8 +221,7 @@ extension RuuviNotifierImpl { if case let .temperature(lower, upper) = ruuviAlertService.alert(for: identifier.value, of: alertType), let l = Temperature(lower), let u = Temperature(upper), - let t = temperature - { + let t = temperature { let isLower = t < l let isUpper = t > u if trigger { @@ -246,8 +263,7 @@ extension RuuviNotifierImpl { guard let identifier else { return false } if case let .relativeHumidity(lower, upper) = ruuviAlertService.alert(for: identifier.value, of: alertType), let t = temperature, - let rh = relativeHumidity?.converted(to: .relative(temperature: t)) - { + let rh = relativeHumidity?.converted(to: .relative(temperature: t)) { let isLower = rh.value < lower let isUpper = rh.value > upper if trigger { @@ -289,8 +305,7 @@ extension RuuviNotifierImpl { if case let .pressure(lower, upper) = ruuviAlertService.alert(for: identifier.value, of: alertType), let l = Pressure(lower), let u = Pressure(upper), - let pressure - { + let pressure { let isLower = pressure < l let isUpper = pressure > u if trigger { @@ -330,10 +345,11 @@ extension RuuviNotifierImpl { ) -> Bool { guard let identifier else { return false } if case let .signal(lower, upper) = ruuviAlertService - .alert(for: identifier.value, - of: alertType), - let signal - { + .alert( + for: identifier.value, + of: alertType + ), + let signal { let isLower = Double(signal) < lower let isUpper = Double(signal) > upper if trigger { @@ -372,8 +388,7 @@ extension RuuviNotifierImpl { ) -> Bool { guard let luid = record.luid else { return false } if case let .movement(last) = ruuviAlertService.alert(for: luid.value, of: movement), - let movementCounter = record.movementCounter - { + let movementCounter = record.movementCounter { let isGreater = movementCounter > last if trigger { if isGreater { @@ -401,9 +416,10 @@ extension RuuviNotifierImpl { guard let identifier else { return false } if case let .cloudConnection(unseenDuration) = ruuviAlertService - .alert(for: identifier.value, - of: alertType) - { + .alert( + for: identifier.value, + of: alertType + ) { let calendar = Calendar.current let thresholdDateTime = calendar.date( byAdding: .second, value: -Int(unseenDuration), to: Date() diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Alert/AlertType.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Alert/AlertType.swift index 5860de324..137818ac8 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Alert/AlertType.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Alert/AlertType.swift @@ -11,15 +11,19 @@ public enum AlertType: CaseIterable { case movement(last: Int) public static var allCases: [AlertType] { - [.temperature(lower: 0, upper: 0), - .relativeHumidity(lower: 0, upper: 0), - .humidity(lower: Humidity.zeroAbsolute, - upper: Humidity.zeroAbsolute), - .pressure(lower: 0, upper: 0), - .signal(lower: 0, upper: 0), - .connection, - .cloudConnection(unseenDuration: 0), - .movement(last: 0)] + [ + .temperature(lower: 0, upper: 0), + .relativeHumidity(lower: 0, upper: 0), + .humidity( + lower: Humidity.zeroAbsolute, + upper: Humidity.zeroAbsolute + ), + .pressure(lower: 0, upper: 0), + .signal(lower: 0, upper: 0), + .connection, + .cloudConnection(unseenDuration: 0), + .movement(last: 0), + ] } } diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Common/Reorderable.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Common/Reorderable.swift index fb0ab5039..53d0a807a 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Common/Reorderable.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Common/Reorderable.swift @@ -8,10 +8,12 @@ public protocol Reorderable { public extension Array where Element: Reorderable { func reorder(by preferredOrder: [Element.OrderElement]) -> [Element] { sorted { - guard let first = preferredOrder.firstIndex(of: $0.orderElement) else { + guard let first = preferredOrder.firstIndex(of: $0.orderElement) + else { return false } - guard let second = preferredOrder.firstIndex(of: $1.orderElement) else { + guard let second = preferredOrder.firstIndex(of: $1.orderElement) + else { return true } return first < second diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Identifier/Identifier.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Identifier/Identifier.swift index 9cfa8e651..3dae4a3da 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Identifier/Identifier.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Identifier/Identifier.swift @@ -79,14 +79,16 @@ public extension String { public extension String? { var luid: LocalIdentifier? { - guard let self else { + guard let self + else { return nil } return LocalIdentifierStruct(value: self).any } var mac: MACIdentifier? { - guard let self else { + guard let self + else { return nil } return MACIdentifierStruct(value: self).any diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTag+RuuviTagSensorRecord.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTag+RuuviTagSensorRecord.swift index 0ae310125..b6db280bb 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTag+RuuviTagSensorRecord.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Mappers/RuuviTag+RuuviTagSensorRecord.swift @@ -24,14 +24,16 @@ extension RuuviTag: RuuviTagSensorRecord { } public var humidity: Humidity? { - guard let rH = relativeHumidity else { + guard let rH = relativeHumidity + else { return nil } return Humidity(relative: rH / 100.0, temperature: temperature) } public var pressure: Pressure? { - guard let hectopascals else { + guard let hectopascals + else { return nil } return Pressure(value: hectopascals, unit: .hectopascals) @@ -44,15 +46,23 @@ extension RuuviTag: RuuviTagSensorRecord { else { return nil } - return Acceleration(x: - AccelerationMeasurement(value: accelerationX, - unit: .metersPerSecondSquared), + return Acceleration( + x: + AccelerationMeasurement( + value: accelerationX, + unit: .metersPerSecondSquared + ), y: - AccelerationMeasurement(value: accelerationY, - unit: .metersPerSecondSquared), + AccelerationMeasurement( + value: accelerationY, + unit: .metersPerSecondSquared + ), z: - AccelerationMeasurement(value: accelerationZ, - unit: .metersPerSecondSquared)) + AccelerationMeasurement( + value: accelerationZ, + unit: .metersPerSecondSquared + ) + ) } public var voltage: Voltage? { diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/Measurement.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/Measurement.swift index 724aa5cef..56ec29eb6 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/Measurement.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/Measurement.swift @@ -70,8 +70,7 @@ public extension Pressure { public extension Humidity { init?(relative value: Double?, temperature: Temperature?) { if let relativeHumidity = value, - let temperature - { + let temperature { self = Humidity(value: relativeHumidity, unit: .relative(temperature: temperature)) } else { return nil diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/RuuviMeasurement.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/RuuviMeasurement.swift index ffaf514b0..e2bf581da 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/RuuviMeasurement.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Measurement/RuuviMeasurement.swift @@ -4,8 +4,7 @@ import Humidity public struct RuuviMeasurement { public var id: String { if let macId, - !macId.value.isEmpty - { + !macId.value.isEmpty { macId.value } else if let luid { luid.value diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Notification/RuuviCloudPNToken.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Notification/RuuviCloudPNToken.swift index d1736039b..fb6e9c9de 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Notification/RuuviCloudPNToken.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Notification/RuuviCloudPNToken.swift @@ -11,10 +11,11 @@ public struct RuuviCloudPNTokenStruct: RuuviCloudPNToken { public var lastAccessed: TimeInterval? public var name: String? - public init(id: Int, - lastAccessed: TimeInterval? = nil, - name: String? = nil) - { + public init( + id: Int, + lastAccessed: TimeInterval? = nil, + name: String? = nil + ) { self.id = id self.lastAccessed = lastAccessed self.name = name diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/CloudSensorDense.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/CloudSensorDense.swift index 33774105c..02bbef92d 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/CloudSensorDense.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/CloudSensorDense.swift @@ -6,11 +6,12 @@ public struct RuuviCloudSensorDense { public let alerts: RuuviCloudSensorAlerts public let subscription: CloudSensorSubscription? - public init(sensor: CloudSensor, - record: RuuviTagSensorRecord?, - alerts: RuuviCloudSensorAlerts, - subscription: CloudSensorSubscription?) - { + public init( + sensor: CloudSensor, + record: RuuviTagSensorRecord?, + alerts: RuuviCloudSensorAlerts, + subscription: CloudSensorSubscription? + ) { self.sensor = sensor self.record = record self.alerts = alerts @@ -23,10 +24,11 @@ public struct AnyCloudSensorDense: CloudSensor, Equatable, Hashable, Reorderable private let record: RuuviTagSensorRecord private let subscription: CloudSensorSubscription? - public init(sensor: CloudSensor, - record: RuuviTagSensorRecord, - subscription: CloudSensorSubscription?) - { + public init( + sensor: CloudSensor, + record: RuuviTagSensorRecord, + subscription: CloudSensorSubscription? + ) { self.sensor = sensor self.record = record self.subscription = subscription diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/PhysicalSensor.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/PhysicalSensor.swift index d7bc4e57a..330a741bd 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/PhysicalSensor.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/PhysicalSensor.swift @@ -8,8 +8,7 @@ public protocol PhysicalSensor: Sensor { public struct PhysicalSensorStruct: PhysicalSensor { public var id: String { if let macId, - !macId.value.isEmpty - { + !macId.value.isEmpty { macId.value } else if let luid { luid.value diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensor.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensor.swift index 4295be8cb..8e8e0a95f 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensor.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensor.swift @@ -6,8 +6,7 @@ public protocol RuuviTagSensor: PhysicalSensor, Versionable, Claimable, Connecta public extension RuuviTagSensor { var id: String { if let macId, - !macId.value.isEmpty - { + !macId.value.isEmpty { macId.value } else if let luid { luid.value diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensorRecord.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensorRecord.swift index e0c8b1e72..d43a9ffaf 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensorRecord.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensorRecord.swift @@ -36,8 +36,7 @@ public protocol RuuviTagSensorRecord: PhysicalSensor { public extension RuuviTagSensorRecord { var id: String { if let macId, - !macId.value.isEmpty - { + !macId.value.isEmpty { macId.value + "\(date.timeIntervalSince1970)" } else if let luid { luid.value + "\(date.timeIntervalSince1970)" @@ -48,8 +47,7 @@ public extension RuuviTagSensorRecord { var uuid: String { if let macId, - !macId.value.isEmpty - { + !macId.value.isEmpty { macId.value } else if let luid { luid.value diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+Extension.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+Extension.swift index 58a80678e..5b10e20ed 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+Extension.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+Extension.swift @@ -5,11 +5,14 @@ import RuuviOntology public extension RuuviTagDataRealm { var unitTemperature: Temperature? { - guard let celsius = celsius.value else { + guard let celsius = celsius.value + else { return nil } - return Temperature(value: celsius, - unit: .celsius) + return Temperature( + value: celsius, + unit: .celsius + ) } var unitHumidity: Humidity? { @@ -18,16 +21,21 @@ public extension RuuviTagDataRealm { else { return nil } - return Humidity(relative: relativeHumidity, - temperature: Temperature(value: celsius, unit: .celsius)) + return Humidity( + relative: relativeHumidity, + temperature: Temperature(value: celsius, unit: .celsius) + ) } var unitPressure: Pressure? { - guard let pressure = pressure.value else { + guard let pressure = pressure.value + else { return nil } - return Pressure(value: pressure, - unit: .hectopascals) + return Pressure( + value: pressure, + unit: .hectopascals + ) } var acceleration: Acceleration? { @@ -37,15 +45,23 @@ public extension RuuviTagDataRealm { else { return nil } - return Acceleration(x: - AccelerationMeasurement(value: accelerationX, - unit: .metersPerSecondSquared), + return Acceleration( + x: + AccelerationMeasurement( + value: accelerationX, + unit: .metersPerSecondSquared + ), y: - AccelerationMeasurement(value: accelerationY, - unit: .metersPerSecondSquared), + AccelerationMeasurement( + value: accelerationY, + unit: .metersPerSecondSquared + ), z: - AccelerationMeasurement(value: accelerationZ, - unit: .metersPerSecondSquared)) + AccelerationMeasurement( + value: accelerationZ, + unit: .metersPerSecondSquared + ) + ) } var unitVoltage: Voltage? { diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+Extension.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+Extension.swift index cce889eb4..b60d3354b 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+Extension.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+Extension.swift @@ -5,11 +5,14 @@ import RuuviOntology public extension RuuviTagLatestDataRealm { var unitTemperature: Temperature? { - guard let celsius = celsius.value else { + guard let celsius = celsius.value + else { return nil } - return Temperature(value: celsius, - unit: .celsius) + return Temperature( + value: celsius, + unit: .celsius + ) } var unitHumidity: Humidity? { @@ -18,16 +21,21 @@ public extension RuuviTagLatestDataRealm { else { return nil } - return Humidity(relative: relativeHumidity, - temperature: Temperature(value: celsius, unit: .celsius)) + return Humidity( + relative: relativeHumidity, + temperature: Temperature(value: celsius, unit: .celsius) + ) } var unitPressure: Pressure? { - guard let pressure = pressure.value else { + guard let pressure = pressure.value + else { return nil } - return Pressure(value: pressure, - unit: .hectopascals) + return Pressure( + value: pressure, + unit: .hectopascals + ) } var acceleration: Acceleration? { @@ -37,15 +45,23 @@ public extension RuuviTagLatestDataRealm { else { return nil } - return Acceleration(x: - AccelerationMeasurement(value: accelerationX, - unit: .metersPerSecondSquared), + return Acceleration( + x: + AccelerationMeasurement( + value: accelerationX, + unit: .metersPerSecondSquared + ), y: - AccelerationMeasurement(value: accelerationY, - unit: .metersPerSecondSquared), + AccelerationMeasurement( + value: accelerationY, + unit: .metersPerSecondSquared + ), z: - AccelerationMeasurement(value: accelerationZ, - unit: .metersPerSecondSquared)) + AccelerationMeasurement( + value: accelerationZ, + unit: .metersPerSecondSquared + ) + ) } var unitVoltage: Voltage? { diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviCloudQueuedRequestSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviCloudQueuedRequestSQLite.swift index af270adc6..c70b8fc07 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviCloudQueuedRequestSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviCloudQueuedRequestSQLite.swift @@ -86,8 +86,10 @@ extension RuuviCloudQueuedRequestSQLite: PersistableRecord { public extension RuuviCloudQueuedRequestSQLite { static func createTable(in db: Database) throws { try db.create(table: RuuviCloudQueuedRequestSQLite.databaseTableName, body: { table in - table.autoIncrementedPrimaryKey(RuuviCloudQueuedRequestSQLite.idColumn.name, - onConflict: .fail) + table.autoIncrementedPrimaryKey( + RuuviCloudQueuedRequestSQLite.idColumn.name, + onConflict: .fail + ) table.column(RuuviCloudQueuedRequestSQLite.typeColumn.name, .integer) table.column(RuuviCloudQueuedRequestSQLite.statusColumn.name, .integer) table.column(RuuviCloudQueuedRequestSQLite.uniqueKeyColumn.name, .text) diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagDataSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagDataSQLite.swift index 81641c1ba..5dabf2e64 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagDataSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagDataSQLite.swift @@ -108,10 +108,11 @@ extension RuuviTagDataSQLite: FetchableRecord { temperature = Temperature(value: celsius, unit: .celsius) if let relativeHumidity = Double.fromDatabaseValue(row[RuuviTagDataSQLite.relativeHumidityInPercentColumn]), - let temperature - { - humidity = Humidity(value: relativeHumidity, - unit: .relative(temperature: temperature)) + let temperature { + humidity = Humidity( + value: relativeHumidity, + unit: .relative(temperature: temperature) + ) } } if let hectopascals = Double.fromDatabaseValue(row[RuuviTagDataSQLite.hectopascalsColumn]) { @@ -119,11 +120,12 @@ extension RuuviTagDataSQLite: FetchableRecord { } if let accelerationX = Double.fromDatabaseValue(row[RuuviTagDataSQLite.accelerationXColumn]), let accelerationY = Double.fromDatabaseValue(row[RuuviTagDataSQLite.accelerationYColumn]), - let accelerationZ = Double.fromDatabaseValue(row[RuuviTagDataSQLite.accelerationZColumn]) - { - acceleration = Acceleration(x: AccelerationMeasurement(value: accelerationX, unit: .metersPerSecondSquared), - y: AccelerationMeasurement(value: accelerationY, unit: .metersPerSecondSquared), - z: AccelerationMeasurement(value: accelerationZ, unit: .metersPerSecondSquared)) + let accelerationZ = Double.fromDatabaseValue(row[RuuviTagDataSQLite.accelerationZColumn]) { + acceleration = Acceleration( + x: AccelerationMeasurement(value: accelerationX, unit: .metersPerSecondSquared), + y: AccelerationMeasurement(value: accelerationY, unit: .metersPerSecondSquared), + z: AccelerationMeasurement(value: accelerationZ, unit: .metersPerSecondSquared) + ) } if let volts = Double.fromDatabaseValue(row[RuuviTagDataSQLite.voltsColumn]) { voltage = Voltage(value: volts, unit: .volts) diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagLatestDataSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagLatestDataSQLite.swift index 1f61d3d6a..9ab62c1f9 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagLatestDataSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagLatestDataSQLite.swift @@ -112,10 +112,11 @@ extension RuuviTagLatestDataSQLite: FetchableRecord { temperature = Temperature(value: celsius, unit: .celsius) if let relativeHumidity = Double.fromDatabaseValue(row[RuuviTagLatestDataSQLite.relativeHumidityInPercentColumn]), - let temperature - { - humidity = Humidity(value: relativeHumidity, - unit: .relative(temperature: temperature)) + let temperature { + humidity = Humidity( + value: relativeHumidity, + unit: .relative(temperature: temperature) + ) } } if let hectopascals = Double.fromDatabaseValue(row[RuuviTagLatestDataSQLite.hectopascalsColumn]) { @@ -123,11 +124,12 @@ extension RuuviTagLatestDataSQLite: FetchableRecord { } if let accelerationX = Double.fromDatabaseValue(row[RuuviTagLatestDataSQLite.accelerationXColumn]), let accelerationY = Double.fromDatabaseValue(row[RuuviTagLatestDataSQLite.accelerationYColumn]), - let accelerationZ = Double.fromDatabaseValue(row[RuuviTagLatestDataSQLite.accelerationZColumn]) - { - acceleration = Acceleration(x: AccelerationMeasurement(value: accelerationX, unit: .metersPerSecondSquared), - y: AccelerationMeasurement(value: accelerationY, unit: .metersPerSecondSquared), - z: AccelerationMeasurement(value: accelerationZ, unit: .metersPerSecondSquared)) + let accelerationZ = Double.fromDatabaseValue(row[RuuviTagLatestDataSQLite.accelerationZColumn]) { + acceleration = Acceleration( + x: AccelerationMeasurement(value: accelerationX, unit: .metersPerSecondSquared), + y: AccelerationMeasurement(value: accelerationY, unit: .metersPerSecondSquared), + z: AccelerationMeasurement(value: accelerationZ, unit: .metersPerSecondSquared) + ) } if let volts = Double.fromDatabaseValue(row[RuuviTagLatestDataSQLite.voltsColumn]) { voltage = Voltage(value: volts, unit: .volts) diff --git a/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift b/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift index c073d9d25..cfec0c094 100644 --- a/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift +++ b/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift @@ -278,9 +278,11 @@ public class RuuviPersistenceRealm: RuuviPersistence { .filter("ruuviTag.uuid == %@", ruuviTagId) .sorted(byKeyPath: "date") let result: [RuuviTagSensorRecord] = realmRecords.map { realmRecord in - self.constructRecordStruct(from: realmRecord, - luid: realmRecord.ruuviTag?.luid, - sequenceNumber: realmRecord.measurementSequenceNumber.value) + self.constructRecordStruct( + from: realmRecord, + luid: realmRecord.ruuviTag?.luid, + sequenceNumber: realmRecord.measurementSequenceNumber.value + ) } promise.succeed(value: result) } @@ -300,14 +302,17 @@ public class RuuviPersistenceRealm: RuuviPersistence { var previousDate = ruuviTagDataRealms.first?.date ?? Date() for tagDataRealm in ruuviTagDataRealms { autoreleasepool { - guard tagDataRealm.date >= previousDate.addingTimeInterval(interval) else { + guard tagDataRealm.date >= previousDate.addingTimeInterval(interval) + else { return } previousDate = tagDataRealm.date results.append( - self.constructRecordStruct(from: tagDataRealm, - luid: tagDataRealm.ruuviTag?.luid, - sequenceNumber: tagDataRealm.measurementSequenceNumber.value) + self.constructRecordStruct( + from: tagDataRealm, + luid: tagDataRealm.ruuviTag?.luid, + sequenceNumber: tagDataRealm.measurementSequenceNumber.value + ) ) } } @@ -329,14 +334,17 @@ public class RuuviPersistenceRealm: RuuviPersistence { var previousDate = realmRecords.first?.date ?? Date() for realmRecord in realmRecords { autoreleasepool { - guard realmRecord.date >= previousDate else { + guard realmRecord.date >= previousDate + else { return } previousDate = realmRecord.date results.append( - self.constructRecordStruct(from: realmRecord, - luid: realmRecord.ruuviTag?.luid, - sequenceNumber: realmRecord.measurementSequenceNumber.value) + self.constructRecordStruct( + from: realmRecord, + luid: realmRecord.ruuviTag?.luid, + sequenceNumber: realmRecord.measurementSequenceNumber.value + ) ) } } @@ -359,14 +367,17 @@ public class RuuviPersistenceRealm: RuuviPersistence { var previousDate = realmRecords.first?.date ?? Date() for realmRecord in realmRecords { autoreleasepool { - guard realmRecord.date >= previousDate.addingTimeInterval(interval) else { + guard realmRecord.date >= previousDate.addingTimeInterval(interval) + else { return } previousDate = realmRecord.date results.append( - self.constructRecordStruct(from: realmRecord, - luid: realmRecord.ruuviTag?.luid, - sequenceNumber: realmRecord.measurementSequenceNumber.value) + self.constructRecordStruct( + from: realmRecord, + luid: realmRecord.ruuviTag?.luid, + sequenceNumber: realmRecord.measurementSequenceNumber.value + ) ) } } @@ -394,14 +405,18 @@ public class RuuviPersistenceRealm: RuuviPersistence { context.bgWorker.enqueue { let realmRecords = self.context.bg .objects(RuuviTagDataRealm.self) - .filter("ruuviTag.uuid == %@ AND date > %@", - ruuviTagId, - Date(timeIntervalSince1970: from)) + .filter( + "ruuviTag.uuid == %@ AND date > %@", + ruuviTagId, + Date(timeIntervalSince1970: from) + ) .sorted(byKeyPath: "date") let result: [RuuviTagSensorRecord] = realmRecords.map { record in - self.constructRecordStruct(from: record, - luid: record.ruuviTag?.luid, - sequenceNumber: record.measurementSequenceNumber.value) + self.constructRecordStruct( + from: record, + luid: record.ruuviTag?.luid, + sequenceNumber: record.measurementSequenceNumber.value + ) } promise.succeed(value: result) } @@ -420,12 +435,13 @@ public class RuuviPersistenceRealm: RuuviPersistence { if let lastRecord = self.context.bg.objects(RuuviTagDataRealm.self) .filter("ruuviTag.uuid == %@", luid.value) .sorted(byKeyPath: "date", ascending: false) - .first - { + .first { let sequenceNumber = lastRecord.measurementSequenceNumber.value - let lastRecordResult = self.constructRecordStruct(from: lastRecord, - luid: luid, - sequenceNumber: sequenceNumber) + let lastRecordResult = self.constructRecordStruct( + from: lastRecord, + luid: luid, + sequenceNumber: sequenceNumber + ) promise.succeed(value: lastRecordResult) } else { promise.succeed(value: nil) @@ -446,12 +462,13 @@ public class RuuviPersistenceRealm: RuuviPersistence { if let lastRecord = self.context.bg.objects(RuuviTagLatestDataRealm.self) .filter("ruuviTag.uuid == %@", luid.value) .sorted(byKeyPath: "date", ascending: false) - .first - { + .first { let sequenceNumber = lastRecord.measurementSequenceNumber.value - let lastRecordResult = self.constructRecordStruct(from: lastRecord, - luid: luid, - sequenceNumber: sequenceNumber) + let lastRecordResult = self.constructRecordStruct( + from: lastRecord, + luid: luid, + sequenceNumber: sequenceNumber + ) promise.succeed(value: lastRecordResult) } else { promise.succeed(value: nil) @@ -491,8 +508,7 @@ public class RuuviPersistenceRealm: RuuviPersistence { .first(where: { ($0.luid != nil && $0.luid == ruuviTag.luid?.value) || ($0.macId != nil && $0.macId == ruuviTag.macId?.value) - }) - { + }) { promise.succeed(value: record.sensorSettings) } else { promise.succeed(value: nil) @@ -534,8 +550,7 @@ public class RuuviPersistenceRealm: RuuviPersistence { .first(where: { ($0.luid != nil && $0.luid == ruuviTag.luid?.value) || ($0.macId != nil && $0.macId == ruuviTag.macId?.value) - }) - { + }) { try self.context.bg.write { switch type { case .humidity: @@ -586,8 +601,7 @@ public class RuuviPersistenceRealm: RuuviPersistence { .first(where: { ($0.luid != nil && $0.luid == ruuviTag.luid?.value) || ($0.macId != nil && $0.macId == ruuviTag.macId?.value) - }) - { + }) { try self.context.bg.write { self.context.bg.delete(sensorSettingRealm) } @@ -690,10 +704,11 @@ extension RuuviPersistenceRealm { ).any } - private func constructRecordStruct(from lastRecord: RuuviTagDataRealm, - luid: LocalIdentifier?, - sequenceNumber: Int?) -> RuuviTagSensorRecordStruct - { + private func constructRecordStruct( + from lastRecord: RuuviTagDataRealm, + luid: LocalIdentifier?, + sequenceNumber: Int? + ) -> RuuviTagSensorRecordStruct { let lastRecordResult = RuuviTagSensorRecordStruct( luid: luid, date: lastRecord.date, @@ -715,10 +730,11 @@ extension RuuviPersistenceRealm { return lastRecordResult } - private func constructRecordStruct(from lastRecord: RuuviTagLatestDataRealm, - luid: LocalIdentifier, - sequenceNumber: Int?) -> RuuviTagSensorRecordStruct - { + private func constructRecordStruct( + from lastRecord: RuuviTagLatestDataRealm, + luid: LocalIdentifier, + sequenceNumber: Int? + ) -> RuuviTagSensorRecordStruct { let lastRecordResult = RuuviTagSensorRecordStruct( luid: luid, date: lastRecord.date, diff --git a/Packages/RuuviPersistence/Sources/RuuviPersistenceSQLite/RuuviPersistenceSQLite.swift b/Packages/RuuviPersistence/Sources/RuuviPersistenceSQLite/RuuviPersistenceSQLite.swift index fe7d2cfa7..6da3727f2 100644 --- a/Packages/RuuviPersistence/Sources/RuuviPersistenceSQLite/RuuviPersistenceSQLite.swift +++ b/Packages/RuuviPersistence/Sources/RuuviPersistenceSQLite/RuuviPersistenceSQLite.swift @@ -30,8 +30,10 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { private let context: SQLiteContext private let readQueue: DispatchQueue = - .init(label: "RuuviTagPersistenceSQLite.readQueue", - qos: .default) + .init( + label: "RuuviTagPersistenceSQLite.readQueue", + qos: .default + ) public init(context: SQLiteContext) { self.context = context } @@ -258,9 +260,11 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { with intervalMinutes: Int, pick points: Double ) -> Future<[RuuviTagSensorRecord], RuuviPersistenceError> { - let highDensityDate = Calendar.current.date(byAdding: .minute, - value: -intervalMinutes, - to: Date()) ?? Date() + let highDensityDate = Calendar.current.date( + byAdding: .minute, + value: -intervalMinutes, + to: Date() + ) ?? Date() let pruningInterval = (highDensityDate.timeIntervalSince1970 - date.timeIntervalSince1970) / points @@ -677,8 +681,7 @@ public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { @discardableResult public func readQueuedRequests() - -> Future<[RuuviCloudQueuedRequest], RuuviPersistenceError> - { + -> Future<[RuuviCloudQueuedRequest], RuuviPersistenceError> { let promise = Promise<[RuuviCloudQueuedRequest], RuuviPersistenceError>() readQueue.async { [weak self] in var sqliteEntities = [RuuviCloudQueuedRequest]() @@ -820,8 +823,7 @@ extension RuuviPersistenceSQLite { newRequest: RuuviCloudQueuedRequest, existingRequest: RuuviCloudQueuedRequest? ) - -> Future - { + -> Future { let promise = Promise() if isCreate { do { @@ -835,7 +837,8 @@ extension RuuviPersistenceSQLite { promise.fail(error: .grdb(error)) } } else { - guard let existingRequest else { + guard let existingRequest + else { return promise.future } diff --git a/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolCoordinator.swift b/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolCoordinator.swift index d31bfb3fb..f30a8a47d 100644 --- a/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolCoordinator.swift +++ b/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolCoordinator.swift @@ -30,13 +30,11 @@ final class RuuviPoolCoordinator: RuuviPool { func create(_ ruuviTag: RuuviTagSensor) -> Future { let promise = Promise() if let macId = ruuviTag.macId, - let luid = ruuviTag.luid - { + let luid = ruuviTag.luid { idPersistence.set(mac: macId, for: luid) } if ruuviTag.macId != nil, - ruuviTag.macId?.value.isEmpty == false - { + ruuviTag.macId?.value.isEmpty == false { sqlite.create(ruuviTag).on(success: { result in promise.succeed(value: result) }, failure: { error in @@ -115,8 +113,7 @@ final class RuuviPoolCoordinator: RuuviPool { promise.fail(error: .ruuviPersistence(error)) }) } else if let luid = record.luid, - let macId = idPersistence.mac(for: luid) - { + let macId = idPersistence.mac(for: luid) { sqlite.create(record.with(macId: macId)).on(success: { success in promise.succeed(value: success) }, failure: { error in @@ -141,8 +138,7 @@ final class RuuviPoolCoordinator: RuuviPool { promise.fail(error: .ruuviPersistence(error)) }) } else if let luid = record.luid, - let macId = idPersistence.mac(for: luid) - { + let macId = idPersistence.mac(for: luid) { sqlite.createLast(record.with(macId: macId)).on(success: { success in promise.succeed(value: success) }, failure: { error in @@ -167,8 +163,7 @@ final class RuuviPoolCoordinator: RuuviPool { promise.fail(error: .ruuviPersistence(error)) }) } else if let luid = record.luid, - let macId = idPersistence.mac(for: luid) - { + let macId = idPersistence.mac(for: luid) { sqlite.updateLast(record.with(macId: macId)).on(success: { success in promise.succeed(value: success) }, failure: { error in diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLastRecordSubjectCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLastRecordSubjectCombine.swift index 2e2ed6999..c1c6ff646 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLastRecordSubjectCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLastRecordSubjectCombine.swift @@ -56,9 +56,11 @@ final class RuuviTagLastRecordSubjectCombine { } } let results = realm.main.objects(RuuviTagDataRealm.self) - .filter("ruuviTag.uuid == %@ || ruuviTag.mac == %@", - luid?.value ?? "invalid", - macId?.value ?? "invalid") + .filter( + "ruuviTag.uuid == %@ || ruuviTag.mac == %@", + luid?.value ?? "invalid", + macId?.value ?? "invalid" + ) .sorted(byKeyPath: "date") ruuviTagDataRealmToken = results.observe { [weak self] change in guard let sSelf = self else { return } diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLatestRecordSubjectCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLatestRecordSubjectCombine.swift index 9652486e2..90c927418 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLatestRecordSubjectCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLatestRecordSubjectCombine.swift @@ -56,9 +56,11 @@ final class RuuviTagLatestRecordSubjectCombine { } } let results = realm.main.objects(RuuviTagLatestDataRealm.self) - .filter("ruuviTag.uuid == %@ || ruuviTag.mac == %@", - luid?.value ?? "invalid", - macId?.value ?? "invalid") + .filter( + "ruuviTag.uuid == %@ || ruuviTag.mac == %@", + luid?.value ?? "invalid", + macId?.value ?? "invalid" + ) .sorted(byKeyPath: "date") ruuviTagDataRealmToken = results.observe { [weak self] change in guard let sSelf = self else { return } diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagRecordSubjectCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagRecordSubjectCombine.swift index 5afecbba7..d12dab71c 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagRecordSubjectCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagRecordSubjectCombine.swift @@ -57,9 +57,11 @@ final class RuuviTagRecordSubjectCombine { } let results = realm.main.objects(RuuviTagDataRealm.self) - .filter("ruuviTag.uuid == %@ || ruuviTag.mac == %@", - luid?.value ?? "invalid", - macId?.value ?? "invalid") + .filter( + "ruuviTag.uuid == %@ || ruuviTag.mac == %@", + luid?.value ?? "invalid", + macId?.value ?? "invalid" + ) .sorted(byKeyPath: "date") ruuviTagDataRealmCache = results.compactMap(\.any) ruuviTagDataRealmToken = results.observe { [weak self] change in diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/SensorSettingsCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/SensorSettingsCombine.swift index 971b17f83..4e1fccba0 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/SensorSettingsCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/SensorSettingsCombine.swift @@ -66,9 +66,11 @@ final class SensorSettingsCombine { DispatchQueue.main.async { [weak self] in guard let sSelf = self else { return } let results = sSelf.realm.main.objects(SensorSettingsRealm.self) - .filter("luid == %@ || macId == %@", - luid?.value ?? "invalid", - macId?.value ?? "invalid") + .filter( + "luid == %@ || macId == %@", + luid?.value ?? "invalid", + macId?.value ?? "invalid" + ) sSelf.ruuviTagRealmCache = results.map(\.sensorSettings) sSelf.ruuviTagsRealmToken = results.observe { [weak self] change in guard let sSelf = self else { return } diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift index 36ebfabe9..693cd7f0b 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift @@ -42,9 +42,10 @@ class RuuviReactorImpl: RuuviReactor { private lazy var latestRecordCombines = [String: RuuviTagLatestRecordSubjectCombine]() private lazy var sensorSettingsCombines = [String: SensorSettingsCombine]() - func observe(_ luid: LocalIdentifier, - _ block: @escaping ([AnyRuuviTagSensorRecord]) -> Void) -> RuuviReactorToken - { + func observe( + _ luid: LocalIdentifier, + _ block: @escaping ([AnyRuuviTagSensorRecord]) -> Void + ) -> RuuviReactorToken { var recordCombine: RuuviTagRecordSubjectCombine if let combine = recordCombines[luid.value] { recordCombine = combine @@ -96,9 +97,10 @@ class RuuviReactorImpl: RuuviReactor { } } - func observeLast(_ ruuviTag: RuuviTagSensor, - _ block: @escaping (RuuviReactorChange) -> Void) -> RuuviReactorToken - { + func observeLast( + _ ruuviTag: RuuviTagSensor, + _ block: @escaping (RuuviReactorChange) -> Void + ) -> RuuviReactorToken { let sqliteOperation = sqlitePersistence.readLast(ruuviTag) let realmOperation = realmPersistence.readLast(ruuviTag) Future.zip(realmOperation, sqliteOperation).on(success: { realmRecord, sqliteRecord in @@ -129,9 +131,10 @@ class RuuviReactorImpl: RuuviReactor { } } - func observeLatest(_ ruuviTag: RuuviTagSensor, - _ block: @escaping (RuuviReactorChange) -> Void) -> RuuviReactorToken - { + func observeLatest( + _ ruuviTag: RuuviTagSensor, + _ block: @escaping (RuuviReactorChange) -> Void + ) -> RuuviReactorToken { let sqliteOperation = sqlitePersistence.readLatest(ruuviTag) let realmOperation = realmPersistence.readLatest(ruuviTag) Future.zip(realmOperation, sqliteOperation).on(success: { realmRecord, sqliteRecord in @@ -162,9 +165,10 @@ class RuuviReactorImpl: RuuviReactor { } } - func observe(_ ruuviTag: RuuviTagSensor, - _ block: @escaping (RuuviReactorChange) -> Void) -> RuuviReactorToken - { + func observe( + _ ruuviTag: RuuviTagSensor, + _ block: @escaping (RuuviReactorChange) -> Void + ) -> RuuviReactorToken { sqlitePersistence.readSensorSettings(ruuviTag).on { [weak self] sqliteRecord in if let sensorSettings = sqliteRecord { block(.update(sensorSettings)) diff --git a/Packages/RuuviService/Package.swift b/Packages/RuuviService/Package.swift index dad58263d..c3326a589 100644 --- a/Packages/RuuviService/Package.swift +++ b/Packages/RuuviService/Package.swift @@ -93,13 +93,13 @@ let package = Package( .target( name: "RuuviServiceAlert", dependencies: [ - "RuuviService", + "RuuviService" ] ), .target( name: "RuuviServiceAuth", dependencies: [ - "RuuviService", + "RuuviService" ] ), .target( @@ -115,43 +115,43 @@ let package = Package( .target( name: "RuuviServiceAppSettings", dependencies: [ - "RuuviService", + "RuuviService" ] ), .target( name: "RuuviServiceCloudSync", dependencies: [ - "RuuviService", + "RuuviService" ] ), .target( name: "RuuviServiceOffsetCalibration", dependencies: [ - "RuuviService", + "RuuviService" ] ), .target( name: "RuuviServiceOwnership", dependencies: [ - "RuuviService", + "RuuviService" ] ), .target( name: "RuuviServiceSensorProperties", dependencies: [ - "RuuviService", + "RuuviService" ] ), .target( name: "RuuviServiceSensorRecords", dependencies: [ - "RuuviService", + "RuuviService" ] ), .target( name: "RuuviServiceExport", dependencies: [ - "RuuviService", + "RuuviService" ] ), .target( diff --git a/Packages/RuuviService/Sources/RuuviService/RuuviServiceCloudNotification.swift b/Packages/RuuviService/Sources/RuuviService/RuuviServiceCloudNotification.swift index dffb3d0bb..5dd90abc6 100644 --- a/Packages/RuuviService/Sources/RuuviService/RuuviServiceCloudNotification.swift +++ b/Packages/RuuviService/Sources/RuuviService/RuuviServiceCloudNotification.swift @@ -4,27 +4,35 @@ import RuuviOntology public protocol RuuviServiceCloudNotification { @discardableResult - func set(token: String?, - name: String?, - data: String?, - language: Language, - sound: RuuviAlertSound) -> Future + func set( + token: String?, + name: String?, + data: String?, + language: Language, + sound: RuuviAlertSound + ) -> Future @discardableResult - func set(sound: RuuviAlertSound, - language: Language, - deviceName: String?) -> Future + func set( + sound: RuuviAlertSound, + language: Language, + deviceName: String? + ) -> Future @discardableResult - func register(token: String, - type: String, - name: String?, - data: String?, - params: [String: String]?) -> Future + func register( + token: String, + type: String, + name: String?, + data: String?, + params: [String: String]? + ) -> Future @discardableResult - func unregister(token: String?, - tokenId: Int?) -> Future + func unregister( + token: String?, + tokenId: Int? + ) -> Future @discardableResult func listTokens() -> Future<[RuuviCloudPNToken], RuuviServiceError> diff --git a/Packages/RuuviService/Sources/RuuviService/RuuviServiceMeasurement.swift b/Packages/RuuviService/Sources/RuuviService/RuuviServiceMeasurement.swift index 52c1f8a08..ee779725c 100644 --- a/Packages/RuuviService/Sources/RuuviService/RuuviServiceMeasurement.swift +++ b/Packages/RuuviService/Sources/RuuviService/RuuviServiceMeasurement.swift @@ -35,14 +35,20 @@ public protocol RuuviServiceMeasurement { func stringWithoutSign(temperature: Double?) -> String // Humidity - func double(for humidity: Humidity, - temperature: Temperature, - isDecimal: Bool) -> Double? - func string(for humidity: Humidity?, - temperature: Temperature?, - allowSettings: Bool) -> String - func stringWithoutSign(for humidity: Humidity?, - temperature: Temperature?) -> String + func double( + for humidity: Humidity, + temperature: Temperature, + isDecimal: Bool + ) -> Double? + func string( + for humidity: Humidity?, + temperature: Temperature?, + allowSettings: Bool + ) -> String + func stringWithoutSign( + for humidity: Humidity?, + temperature: Temperature? + ) -> String func stringWithoutSign(humidity: Double?) -> String // Pressure @@ -70,35 +76,41 @@ public protocol RuuviServiceMeasurement { public extension RuuviServiceMeasurement { func double(for temperature: Temperature?) -> Double? { - guard let temperature else { + guard let temperature + else { return nil } return double(for: temperature) } - func double(for humidity: Humidity?, - temperature: Temperature?, - isDecimal: Bool) -> Double? - { + func double( + for humidity: Humidity?, + temperature: Temperature?, + isDecimal: Bool + ) -> Double? { guard let temperature, let humidity else { return nil } - return double(for: humidity, - temperature: temperature, - isDecimal: isDecimal) + return double( + for: humidity, + temperature: temperature, + isDecimal: isDecimal + ) } func double(for pressure: Pressure?) -> Double? { - guard let pressure else { + guard let pressure + else { return nil } return double(for: pressure) } func double(for voltage: Voltage?) -> Double? { - guard let voltage else { + guard let voltage + else { return nil } return double(for: voltage) diff --git a/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/AlertPersistenceUserDefaults.swift b/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/AlertPersistenceUserDefaults.swift index 814514115..91ab2c1d7 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/AlertPersistenceUserDefaults.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/AlertPersistenceUserDefaults.swift @@ -127,8 +127,7 @@ class AlertPersistenceUserDefaults: AlertPersistence { case .temperature: if prefs.bool(forKey: temperatureAlertIsOnUDKeyPrefix + uuid), let lower = prefs.optionalDouble(forKey: temperatureLowerBoundUDKeyPrefix + uuid), - let upper = prefs.optionalDouble(forKey: temperatureUpperBoundUDKeyPrefix + uuid) - { + let upper = prefs.optionalDouble(forKey: temperatureUpperBoundUDKeyPrefix + uuid) { .temperature(lower: lower, upper: upper) } else { nil @@ -136,8 +135,7 @@ class AlertPersistenceUserDefaults: AlertPersistence { case .relativeHumidity: if prefs.bool(forKey: relativeHumidityAlertIsOnUDKeyPrefix + uuid), let lower = prefs.optionalDouble(forKey: relativeHumidityLowerBoundUDKeyPrefix + uuid), - let upper = prefs.optionalDouble(forKey: relativeHumidityUpperBoundUDKeyPrefix + uuid) - { + let upper = prefs.optionalDouble(forKey: relativeHumidityUpperBoundUDKeyPrefix + uuid) { .relativeHumidity(lower: lower, upper: upper) } else { nil @@ -147,8 +145,7 @@ class AlertPersistenceUserDefaults: AlertPersistence { let lower = prefs.data(forKey: humidityLowerBoundUDKeyPrefix + uuid), let upper = prefs.data(forKey: humidityUpperBoundUDKeyPrefix + uuid), let lowerHumidity = KeyedArchiver.unarchive(lower, with: Humidity.self), - let upperHumidity = KeyedArchiver.unarchive(upper, with: Humidity.self) - { + let upperHumidity = KeyedArchiver.unarchive(upper, with: Humidity.self) { .humidity(lower: lowerHumidity, upper: upperHumidity) } else { nil @@ -156,8 +153,7 @@ class AlertPersistenceUserDefaults: AlertPersistence { case .pressure: if prefs.bool(forKey: pressureAlertIsOnUDKeyPrefix + uuid), let lower = prefs.optionalDouble(forKey: pressureLowerBoundUDKeyPrefix + uuid), - let upper = prefs.optionalDouble(forKey: pressureUpperBoundUDKeyPrefix + uuid) - { + let upper = prefs.optionalDouble(forKey: pressureUpperBoundUDKeyPrefix + uuid) { .pressure(lower: lower, upper: upper) } else { nil @@ -165,8 +161,7 @@ class AlertPersistenceUserDefaults: AlertPersistence { case .signal: if prefs.bool(forKey: signalAlertIsOnUDKeyPrefix + uuid), let lower = prefs.optionalDouble(forKey: signalLowerBoundUDKeyPrefix + uuid), - let upper = prefs.optionalDouble(forKey: signalUpperBoundUDKeyPrefix + uuid) - { + let upper = prefs.optionalDouble(forKey: signalUpperBoundUDKeyPrefix + uuid) { .signal(lower: lower, upper: upper) } else { nil @@ -181,16 +176,14 @@ class AlertPersistenceUserDefaults: AlertPersistence { if prefs.bool(forKey: cloudConnectionAlertIsOnUDKeyPrefix + uuid), let unseenDuration = prefs.optionalDouble( forKey: cloudConnectionAlertUnseenDurationUDPrefix + uuid - ) - { + ) { .cloudConnection(unseenDuration: unseenDuration) } else { nil } case .movement: if prefs.bool(forKey: movementAlertIsOnUDKeyPrefix + uuid), - let counter = prefs.optionalInt(forKey: movementAlertCounterUDPrefix + uuid) - { + let counter = prefs.optionalInt(forKey: movementAlertCounterUDPrefix + uuid) { .movement(last: counter) } else { nil @@ -519,7 +512,8 @@ extension AlertPersistenceUserDefaults { extension AlertPersistenceUserDefaults { func lowerHumidity(for uuid: String) -> Humidity? { - guard let data = prefs.data(forKey: humidityLowerBoundUDKeyPrefix + uuid) else { + guard let data = prefs.data(forKey: humidityLowerBoundUDKeyPrefix + uuid) + else { return nil } return KeyedArchiver.unarchive(data, with: Humidity.self) @@ -534,7 +528,8 @@ extension AlertPersistenceUserDefaults { } func upperHumidity(for uuid: String) -> Humidity? { - guard let data = prefs.data(forKey: humidityUpperBoundUDKeyPrefix + uuid) else { + guard let data = prefs.data(forKey: humidityUpperBoundUDKeyPrefix + uuid) + else { return nil } return KeyedArchiver.unarchive(data, with: Humidity.self) diff --git a/Packages/RuuviService/Sources/RuuviServiceAlert/RuuviServiceAlertImpl.swift b/Packages/RuuviService/Sources/RuuviServiceAlert/RuuviServiceAlertImpl.swift index a2fa95419..27816b780 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAlert/RuuviServiceAlertImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAlert/RuuviServiceAlertImpl.swift @@ -338,8 +338,10 @@ public extension RuuviServiceAlertImpl { cloud.setAlert( type: .signal, settingType: .lowerBound, - isEnabled: isOn(type: .signal(lower: 0, upper: 0), - for: ruuviTag), + isEnabled: isOn( + type: .signal(lower: 0, upper: 0), + for: ruuviTag + ), min: signal ?? 0, max: upperSignal(for: ruuviTag) ?? 0, counter: nil, @@ -356,8 +358,10 @@ public extension RuuviServiceAlertImpl { cloud.setAlert( type: .signal, settingType: .upperBound, - isEnabled: isOn(type: .signal(lower: 0, upper: 0), - for: ruuviTag), + isEnabled: isOn( + type: .signal(lower: 0, upper: 0), + for: ruuviTag + ), min: lowerSignal(for: ruuviTag) ?? 0, max: signal ?? 0, counter: nil, @@ -374,8 +378,10 @@ public extension RuuviServiceAlertImpl { cloud.setAlert( type: .signal, settingType: .description, - isEnabled: isOn(type: .signal(lower: 0, upper: 0), - for: ruuviTag), + isEnabled: isOn( + type: .signal(lower: 0, upper: 0), + for: ruuviTag + ), min: lowerSignal(for: ruuviTag) ?? 0, max: upperSignal(for: ruuviTag) ?? 0, counter: nil, @@ -489,8 +495,10 @@ public final class RuuviServiceAlertImpl: RuuviServiceAlert { setMovement(description: cloudAlert.description, for: physicalSensor) case .signal: guard let min = cloudAlert.min, let max = cloudAlert.max else { return } - type = .signal(lower: min, - upper: max) + type = .signal( + lower: min, + upper: max + ) setSignal(description: cloudAlert.description, for: physicalSensor) case .offline: guard let unseenDuration = cloudAlert.max else { return } @@ -1045,8 +1053,7 @@ public extension RuuviServiceAlertImpl { } if let l = lowerHumidity(for: sensor), - let u = upperHumidity(for: sensor) - { + let u = upperHumidity(for: sensor) { postAlertDidChange(with: sensor, of: .humidity(lower: l, upper: u)) } } diff --git a/Packages/RuuviService/Sources/RuuviServiceAppSettings/RuuviServiceAppSettingsImpl.swift b/Packages/RuuviService/Sources/RuuviServiceAppSettings/RuuviServiceAppSettingsImpl.swift index 852d676e3..e339fa5c6 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAppSettings/RuuviServiceAppSettingsImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAppSettings/RuuviServiceAppSettingsImpl.swift @@ -187,8 +187,7 @@ public final class RuuviServiceAppSettingsImpl: RuuviServiceAppSettings { @discardableResult public func set(dashboardTapActionType: DashboardTapActionType) -> - Future - { + Future { let promise = Promise() cloud.set(dashboardTapActionType: dashboardTapActionType) .on(success: { type in diff --git a/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift b/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift index f963cb946..a39e2d810 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift @@ -40,7 +40,8 @@ public final class RuuviServiceAuthImpl: RuuviServiceAuth { storage.readAll() .on(success: { [weak self] localSensors in guard let sSelf = self else { return } - guard localSensors.count != 0 else { + guard localSensors.count != 0 + else { promise.succeed(value: true) return } @@ -59,16 +60,18 @@ public final class RuuviServiceAuthImpl: RuuviServiceAuth { sSelf.alertService.remove(type: type, ruuviTag: sensor) } - Future.zip([deleteSensorOperation, - deleteRecordsOperation, - deleteLatestRecordOperation, - deleteQueuedRequestsOperation, - cleanUpOperation]) - .on(success: { _ in - promise.succeed(value: true) - }, failure: { error in - promise.fail(error: .ruuviPool(error)) - }) + Future.zip([ + deleteSensorOperation, + deleteRecordsOperation, + deleteLatestRecordOperation, + deleteQueuedRequestsOperation, + cleanUpOperation, + ]) + .on(success: { _ in + promise.succeed(value: true) + }, failure: { error in + promise.fail(error: .ruuviPool(error)) + }) } }, failure: { error in promise.fail(error: .ruuviStorage(error)) diff --git a/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift b/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift index 8033fa8b8..64f7498cf 100644 --- a/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift @@ -34,29 +34,31 @@ public final class RuuviServiceCloudNotificationImpl: RuuviServiceCloudNotificat } @discardableResult - public func set(token: String?, - name: String?, - data: String?, - language: Language, - sound: RuuviAlertSound) -> Future - { + public func set( + token: String?, + name: String?, + data: String?, + language: Language, + sound: RuuviAlertSound + ) -> Future { let promise = Promise() - guard ruuviUser.isAuthorized, let token else { + guard ruuviUser.isAuthorized, let token + else { return promise.future } var refreshable = false if let lastRefreshed = pnManager.fcmTokenLastRefreshed { if let daysFromNow = lastRefreshed.numberOfDaysFromNow(), - daysFromNow > 7 - { + daysFromNow > 7 { refreshable = true } } else { refreshable = true } - guard refreshable else { + guard refreshable + else { return promise.future } @@ -82,12 +84,14 @@ public final class RuuviServiceCloudNotificationImpl: RuuviServiceCloudNotificat } @discardableResult - public func set(sound: RuuviAlertSound, - language: Language, - deviceName: String?) -> Future - { + public func set( + sound: RuuviAlertSound, + language: Language, + deviceName: String? + ) -> Future { let promise = Promise() - guard ruuviUser.isAuthorized, let token = pnManager.fcmToken else { + guard ruuviUser.isAuthorized, let token = pnManager.fcmToken + else { return promise.future } @@ -113,38 +117,44 @@ public final class RuuviServiceCloudNotificationImpl: RuuviServiceCloudNotificat } @discardableResult - public func register(token: String, - type: String, - name: String?, - data: String?, - params: [String: String]?) -> Future - { + public func register( + token: String, + type: String, + name: String?, + data: String?, + params: [String: String]? + ) -> Future { let promise = Promise() - cloud.registerPNToken(token: token, - type: type, - name: name, - data: data, - params: params) - .on(success: { tokenId in - promise.succeed(value: tokenId) - }, failure: { error in - promise.fail(error: .ruuviCloud(error)) - }) + cloud.registerPNToken( + token: token, + type: type, + name: name, + data: data, + params: params + ) + .on(success: { tokenId in + promise.succeed(value: tokenId) + }, failure: { error in + promise.fail(error: .ruuviCloud(error)) + }) return promise.future } @discardableResult - public func unregister(token: String?, - tokenId: Int?) -> Future - { + public func unregister( + token: String?, + tokenId: Int? + ) -> Future { let promise = Promise() - cloud.unregisterPNToken(token: token, - tokenId: tokenId) - .on(success: { success in - promise.succeed(value: success) - }, failure: { error in - promise.fail(error: .ruuviCloud(error)) - }) + cloud.unregisterPNToken( + token: token, + tokenId: tokenId + ) + .on(success: { success in + promise.succeed(value: success) + }, failure: { error in + promise.fail(error: .ruuviCloud(error)) + }) return promise.future } diff --git a/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift b/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift index d856e3dea..56e3db61f 100644 --- a/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift @@ -54,86 +54,70 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { .on(success: { [weak self] cloudSettings in guard let cloudSettings, let sSelf = self else { return } if let unitTemperature = cloudSettings.unitTemperature, - unitTemperature != sSelf.ruuviLocalSettings.temperatureUnit - { + unitTemperature != sSelf.ruuviLocalSettings.temperatureUnit { sSelf.ruuviLocalSettings.temperatureUnit = unitTemperature } if let accuracyTemperature = cloudSettings.accuracyTemperature, - accuracyTemperature != sSelf.ruuviLocalSettings.temperatureAccuracy - { + accuracyTemperature != sSelf.ruuviLocalSettings.temperatureAccuracy { sSelf.ruuviLocalSettings.temperatureAccuracy = accuracyTemperature } if let unitHumidity = cloudSettings.unitHumidity, - unitHumidity != sSelf.ruuviLocalSettings.humidityUnit - { + unitHumidity != sSelf.ruuviLocalSettings.humidityUnit { sSelf.ruuviLocalSettings.humidityUnit = unitHumidity } if let accuracyHumidity = cloudSettings.accuracyHumidity, - accuracyHumidity != sSelf.ruuviLocalSettings.humidityAccuracy - { + accuracyHumidity != sSelf.ruuviLocalSettings.humidityAccuracy { sSelf.ruuviLocalSettings.humidityAccuracy = accuracyHumidity } if let unitPressure = cloudSettings.unitPressure, - unitPressure != sSelf.ruuviLocalSettings.pressureUnit - { + unitPressure != sSelf.ruuviLocalSettings.pressureUnit { sSelf.ruuviLocalSettings.pressureUnit = unitPressure } if let accuracyPressure = cloudSettings.accuracyPressure, - accuracyPressure != sSelf.ruuviLocalSettings.pressureAccuracy - { + accuracyPressure != sSelf.ruuviLocalSettings.pressureAccuracy { sSelf.ruuviLocalSettings.pressureAccuracy = accuracyPressure } if let chartShowAllData = cloudSettings.chartShowAllPoints, - chartShowAllData != !sSelf.ruuviLocalSettings.chartDownsamplingOn - { + chartShowAllData != !sSelf.ruuviLocalSettings.chartDownsamplingOn { sSelf.ruuviLocalSettings.chartDownsamplingOn = !chartShowAllData } if let chartDrawDots = cloudSettings.chartDrawDots, - chartDrawDots != sSelf.ruuviLocalSettings.chartDrawDotsOn - { + chartDrawDots != sSelf.ruuviLocalSettings.chartDrawDotsOn { // Draw dots feature is disabled from v1.3.0 onwards to // maintain better performance until we find a better approach to do it. sSelf.ruuviLocalSettings.chartDrawDotsOn = false } if let chartShowMinMaxAvg = cloudSettings.chartShowMinMaxAvg, - chartShowMinMaxAvg != sSelf.ruuviLocalSettings.chartStatsOn - { + chartShowMinMaxAvg != sSelf.ruuviLocalSettings.chartStatsOn { sSelf.ruuviLocalSettings.chartStatsOn = chartShowMinMaxAvg } if let cloudModeEnabled = cloudSettings.cloudModeEnabled, - cloudModeEnabled != sSelf.ruuviLocalSettings.cloudModeEnabled - { + cloudModeEnabled != sSelf.ruuviLocalSettings.cloudModeEnabled { sSelf.ruuviLocalSettings.cloudModeEnabled = cloudModeEnabled } if let dashboardEnabled = cloudSettings.dashboardEnabled, - dashboardEnabled != sSelf.ruuviLocalSettings.dashboardEnabled - { + dashboardEnabled != sSelf.ruuviLocalSettings.dashboardEnabled { sSelf.ruuviLocalSettings.dashboardEnabled = dashboardEnabled } if let dashboardType = cloudSettings.dashboardType, - dashboardType != sSelf.ruuviLocalSettings.dashboardType - { + dashboardType != sSelf.ruuviLocalSettings.dashboardType { sSelf.ruuviLocalSettings.dashboardType = dashboardType } if let dashboardTapActionType = cloudSettings.dashboardTapActionType, - dashboardTapActionType != sSelf.ruuviLocalSettings.dashboardTapActionType - { + dashboardTapActionType != sSelf.ruuviLocalSettings.dashboardTapActionType { sSelf.ruuviLocalSettings.dashboardTapActionType = dashboardTapActionType } if let pushAlertEnabled = cloudSettings.pushAlertEnabled, - pushAlertEnabled != sSelf.ruuviLocalSettings.pushAlertEnabled - { + pushAlertEnabled != sSelf.ruuviLocalSettings.pushAlertEnabled { sSelf.ruuviLocalSettings.pushAlertEnabled = pushAlertEnabled } if let emailAlertEnabled = cloudSettings.emailAlertEnabled, - emailAlertEnabled != sSelf.ruuviLocalSettings.emailAlertEnabled - { + emailAlertEnabled != sSelf.ruuviLocalSettings.emailAlertEnabled { sSelf.ruuviLocalSettings.emailAlertEnabled = emailAlertEnabled } if let cloudProfileLanguageCode = cloudSettings.profileLanguageCode { if cloudProfileLanguageCode != - sSelf.ruuviLocalSettings.cloudProfileLanguageCode - { + sSelf.ruuviLocalSettings.cloudProfileLanguageCode { sSelf.ruuviLocalSettings.cloudProfileLanguageCode = cloudProfileLanguageCode } } else { @@ -154,7 +138,8 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { @discardableResult public func syncImage(sensor: CloudSensor) -> Future { let promise = Promise() - guard let pictureUrl = sensor.picture else { + guard let pictureUrl = sensor.picture + else { promise.fail(error: .pictureUrlIsNil) return promise.future } @@ -246,7 +231,8 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { public func executePendingRequests() -> Future { let promise = Promise() ruuviStorage.readQueuedRequests().on(success: { [weak self] requests in - guard requests.count > 0 else { + guard requests.count > 0 + else { return promise.succeed(value: true) } @@ -268,8 +254,7 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { let temperatureSyncs: [Future] = cloudSensors.compactMap { cloudSensor in if let updatedSensor = updatedSensors - .first(where: { $0.id == cloudSensor.id }) - { + .first(where: { $0.id == cloudSensor.id }) { self.ruuviPool.updateOffsetCorrection( type: .temperature, with: cloudSensor.offsetTemperature, @@ -284,8 +269,7 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { = cloudSensors.compactMap { cloudSensor in if let updatedSensor = updatedSensors .first(where: { $0.id == cloudSensor.id }), - let offsetHumidity = cloudSensor.offsetHumidity - { + let offsetHumidity = cloudSensor.offsetHumidity { self.ruuviPool.updateOffsetCorrection( type: .humidity, with: offsetHumidity / 100, @@ -300,8 +284,7 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { = cloudSensors.compactMap { cloudSensor in if let updatedSensor = updatedSensors .first(where: { $0.id == cloudSensor.id }), - let offsetPressure = cloudSensor.offsetPressure - { + let offsetPressure = cloudSensor.offsetPressure { self.ruuviPool.updateOffsetCorrection( type: .pressure, with: offsetPressure / 100, @@ -324,8 +307,7 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { var syncFullHistory = false if let syncFull = ruuviLocalSyncState.downloadFullHistory(for: sensor.macId), - syncFull - { + syncFull { syncFullHistory = true } @@ -403,7 +385,8 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { ).on(success: { [weak self] denseSensors in guard let sSelf = self else { return } - guard denseSensors.count > 0 else { + guard denseSensors.count > 0 + else { promise.succeed(value: []) return } @@ -420,14 +403,16 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { sensors.on(success: { updatedSensors in let filteredDenseSensorsWithHistory = denseSensors.filter { sensor in - guard let maxHistoryDays = sensor.subscription?.maxHistoryDays else { + guard let maxHistoryDays = sensor.subscription?.maxHistoryDays + else { return false } return maxHistoryDays > 0 } let filteredDenseSensorsWithoutHistory = denseSensors.filter { sensor in - guard let maxHistoryDays = sensor.subscription?.maxHistoryDays else { + guard let maxHistoryDays = sensor.subscription?.maxHistoryDays + else { return false } return maxHistoryDays <= 0 @@ -495,8 +480,7 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { // TODO: @priyonto - Need to improve this once backend flattens and improves the plans // If user goes from free to pro or above plan, download full history if localSensor.ownersPlan?.lowercased() == "free", - localSensor.ownersPlan?.lowercased() != cloudSensor.ownersPlan?.lowercased() - { + localSensor.ownersPlan?.lowercased() != cloudSensor.ownersPlan?.lowercased() { self.ruuviLocalSyncState.setDownloadFullHistory(for: localSensor.macId, downloadFull: true) } @@ -563,12 +547,14 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { /// This method updates the latest data table if a record already exists for the mac address. /// Otherwise it creates a new record. - private func updateLatestRecord(ruuviTag: RuuviTagSensor, - cloudRecord: RuuviTagSensorRecord?) - -> Future - { + private func updateLatestRecord( + ruuviTag: RuuviTagSensor, + cloudRecord: RuuviTagSensorRecord? + ) + -> Future { let promise = Promise() - guard let cloudRecord else { + guard let cloudRecord + else { // If there's no cloud record return // It is possible that a sensor doesn't have a record if it's a few years old ruuviLocalSyncState.setSyncStatus(.complete, for: ruuviTag.id.mac) @@ -580,8 +566,7 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { guard let sSelf = self else { return } // If the latest table already have a data point for the mac update that record if let record, - record.macId?.value == cloudRecord.macId?.value - { + record.macId?.value == cloudRecord.macId?.value { // Store cloud point only if the cloud data is newer than the local data let isMeasurementNew = cloudRecord.date > record.date if sSelf.ruuviLocalSettings.cloudModeEnabled || isMeasurementNew { @@ -615,12 +600,14 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { } /// This method writes the latest data point to the history/records table - private func addLatestRecordToHistory(ruuviTag: RuuviTagSensor, - cloudRecord: RuuviTagSensorRecord?) - -> Future - { + private func addLatestRecordToHistory( + ruuviTag: RuuviTagSensor, + cloudRecord: RuuviTagSensorRecord? + ) + -> Future { let promise = Promise() - guard let cloudRecord else { + guard let cloudRecord + else { // If there's no cloud record return // It is possible that a sensor doesn't have a record if it's a few years old promise.succeed(value: false) @@ -674,9 +661,11 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { private func postNotification() { DispatchQueue.main.async { - NotificationCenter.default.post(name: .NetworkSyncDidFailForAuthorization, - object: nil, - userInfo: nil) + NotificationCenter.default.post( + name: .NetworkSyncDidFailForAuthorization, + object: nil, + userInfo: nil + ) } } } diff --git a/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncRecordsOperation.swift b/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncRecordsOperation.swift index 88b2b84b9..8c38942eb 100644 --- a/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncRecordsOperation.swift +++ b/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncRecordsOperation.swift @@ -15,14 +15,15 @@ final class RuuviServiceCloudSyncRecordsOperation: AsyncOperation { private var ruuviRepository: RuuviRepository private var ruuviLocalIDs: RuuviLocalIDs - init(sensor: RuuviTagSensor, - since: Date, - until: Date? = nil, - ruuviCloud: RuuviCloud, - ruuviRepository: RuuviRepository, - syncState _: RuuviLocalSyncState, - ruuviLocalIDs: RuuviLocalIDs) - { + init( + sensor: RuuviTagSensor, + since: Date, + until: Date? = nil, + ruuviCloud: RuuviCloud, + ruuviRepository: RuuviRepository, + syncState _: RuuviLocalSyncState, + ruuviLocalIDs: RuuviLocalIDs + ) { self.sensor = sensor self.since = since self.until = until @@ -32,7 +33,8 @@ final class RuuviServiceCloudSyncRecordsOperation: AsyncOperation { } override func main() { - guard let macId = sensor.macId else { + guard let macId = sensor.macId + else { error = .macIdIsNil state = .finished return @@ -40,15 +42,15 @@ final class RuuviServiceCloudSyncRecordsOperation: AsyncOperation { let op = ruuviCloud.loadRecords(macId: macId, since: since, until: until) op.on(success: { [weak self] loadedRecords in guard let sSelf = self else { return } - guard !loadedRecords.isEmpty else { + guard !loadedRecords.isEmpty + else { sSelf.state = .finished return } let recordsWithLuid: [AnyRuuviTagSensorRecord] = loadedRecords.map { record in if record.luid == nil, let macId = record.macId, - let luid = sSelf.ruuviLocalIDs.luid(for: macId) - { + let luid = sSelf.ruuviLocalIDs.luid(for: macId) { record.with(luid: luid).any } else { record diff --git a/Packages/RuuviService/Sources/RuuviServiceExport/RuuviServiceExportImpl.swift b/Packages/RuuviService/Sources/RuuviServiceExport/RuuviServiceExportImpl.swift index db884708f..1c38d94e8 100644 --- a/Packages/RuuviService/Sources/RuuviServiceExport/RuuviServiceExportImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceExport/RuuviServiceExportImpl.swift @@ -83,7 +83,8 @@ extension RuuviServiceExportImpl { var csvText = headersString + "\n" func toString(_ value: Double?, format: String) -> String { - guard let v = value else { + guard let v = value + else { return self.emptyValueString } return String(format: format, v) @@ -96,9 +97,11 @@ extension RuuviServiceExportImpl { let t = self.measurementService.double(for: log.temperature) let temperature: String = toString(t, format: "%.2f") - let h = self.measurementService.double(for: log.humidity, - temperature: log.temperature, - isDecimal: false) + let h = self.measurementService.double( + for: log.humidity, + temperature: log.temperature, + isDecimal: false + ) let humidity: String = toString(h, format: "%.2f") var pressure: String diff --git a/Packages/RuuviService/Sources/RuuviServiceGATT/Operations/RuuviTagReadLogsOperation.swift b/Packages/RuuviService/Sources/RuuviServiceGATT/Operations/RuuviTagReadLogsOperation.swift index f7bc77536..690819818 100644 --- a/Packages/RuuviService/Sources/RuuviServiceGATT/Operations/RuuviTagReadLogsOperation.swift +++ b/Packages/RuuviService/Sources/RuuviServiceGATT/Operations/RuuviTagReadLogsOperation.swift @@ -41,14 +41,17 @@ final class RuuviTagReadLogsOperation: AsyncOperation { override func main() { post(started: from, with: uuid) - background.services.ruuvi.nus.log(for: self, - uuid: uuid, - from: from, - options: [.callbackQueue(.untouch), - .connectionTimeout(connectionTimeout ?? 0), - .serviceTimeout(serviceTimeout ?? 0)], - progress: progress) - { observer, result in + background.services.ruuvi.nus.log( + for: self, + uuid: uuid, + from: from, + options: [ + .callbackQueue(.untouch), + .connectionTimeout(connectionTimeout ?? 0), + .serviceTimeout(serviceTimeout ?? 0), + ], + progress: progress + ) { observer, result in switch result { case let .success(logResult): switch logResult { @@ -88,41 +91,57 @@ final class RuuviTagReadLogsOperation: AsyncOperation { private func post(started date: Date, with uuid: String) { DispatchQueue.main.async { - NotificationCenter.default.post(name: .RuuviTagReadLogsOperationDidStart, - object: nil, - userInfo: - [RuuviTagReadLogsOperationDidStartKey.uuid: uuid, - RuuviTagReadLogsOperationDidStartKey.fromDate: date]) + NotificationCenter.default.post( + name: .RuuviTagReadLogsOperationDidStart, + object: nil, + userInfo: + [ + RuuviTagReadLogsOperationDidStartKey.uuid: uuid, + RuuviTagReadLogsOperationDidStartKey.fromDate: date, + ] + ) } } private func post(points: Int, with uuid: String) { DispatchQueue.main.async { - NotificationCenter.default.post(name: .RuuviTagReadLogsOperationProgress, - object: nil, - userInfo: - [RuuviTagReadLogsOperationProgressKey.uuid: uuid, - RuuviTagReadLogsOperationProgressKey.progress: points]) + NotificationCenter.default.post( + name: .RuuviTagReadLogsOperationProgress, + object: nil, + userInfo: + [ + RuuviTagReadLogsOperationProgressKey.uuid: uuid, + RuuviTagReadLogsOperationProgressKey.progress: points, + ] + ) } } private func post(logs: [RuuviTagEnvLogFull], with uuid: String) { DispatchQueue.main.async { - NotificationCenter.default.post(name: .RuuviTagReadLogsOperationDidFinish, - object: nil, - userInfo: - [RuuviTagReadLogsOperationDidFinishKey.uuid: uuid, - RuuviTagReadLogsOperationDidFinishKey.logs: logs]) + NotificationCenter.default.post( + name: .RuuviTagReadLogsOperationDidFinish, + object: nil, + userInfo: + [ + RuuviTagReadLogsOperationDidFinishKey.uuid: uuid, + RuuviTagReadLogsOperationDidFinishKey.logs: logs, + ] + ) } } private func post(error: Error, with uuid: String) { DispatchQueue.main.async { - NotificationCenter.default.post(name: .RuuviTagReadLogsOperationDidFail, - object: nil, - userInfo: - [RuuviTagReadLogsOperationDidFailKey.uuid: uuid, - RuuviTagReadLogsOperationDidFailKey.error: error]) + NotificationCenter.default.post( + name: .RuuviTagReadLogsOperationDidFail, + object: nil, + userInfo: + [ + RuuviTagReadLogsOperationDidFailKey.uuid: uuid, + RuuviTagReadLogsOperationDidFailKey.error: error, + ] + ) } } } diff --git a/Packages/RuuviService/Sources/RuuviServiceMeasurement/RuuviServiceMeasurementImpl.swift b/Packages/RuuviService/Sources/RuuviServiceMeasurement/RuuviServiceMeasurementImpl.swift index 3af524168..f3ca5f90f 100644 --- a/Packages/RuuviService/Sources/RuuviServiceMeasurement/RuuviServiceMeasurementImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceMeasurement/RuuviServiceMeasurementImpl.swift @@ -147,7 +147,8 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } public func string(for temperature: Temperature?, allowSettings: Bool) -> String { - guard let temperature else { + guard let temperature + else { return emptyValueString } let value = temperature.converted(to: units.temperatureUnit).value @@ -164,18 +165,20 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } if temperatureFormatter.unitStyle == .medium, settings.language == .english, - let valueString = numberFormatter.string(from: number) - { - return String(format: "%@\(String.nbsp)%@", - valueString, - units.temperatureUnit.symbol) + let valueString = numberFormatter.string(from: number) { + return String( + format: "%@\(String.nbsp)%@", + valueString, + units.temperatureUnit.symbol + ) } else { return measurementFormatter.string(from: temperature.converted(to: units.temperatureUnit)) } } public func stringWithoutSign(for temperature: Temperature?) -> String { - guard let temperature else { + guard let temperature + else { return emptyValueString } let value = temperature.converted(to: units.temperatureUnit).value @@ -185,7 +188,8 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } public func stringWithoutSign(temperature: Double?) -> String { - guard let temperature else { + guard let temperature + else { return emptyValueString } let number = NSNumber(value: temperature) @@ -203,10 +207,12 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } } - public func string(for pressure: Pressure?, - allowSettings: Bool) -> String - { - guard let pressure else { + public func string( + for pressure: Pressure?, + allowSettings: Bool + ) -> String { + guard let pressure + else { return emptyValueString } if allowSettings { @@ -217,7 +223,8 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } public func stringWithoutSign(for pressure: Pressure?) -> String { - guard let pressure else { + guard let pressure + else { return emptyValueString } let pressureValue = pressure.converted(to: units.pressureUnit).value @@ -225,7 +232,8 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } public func stringWithoutSign(pressure: Double?) -> String { - guard let pressure else { + guard let pressure + else { return emptyValueString } let number = NSNumber(value: pressure) @@ -240,16 +248,18 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } public func string(for voltage: Voltage?) -> String { - guard let voltage else { + guard let voltage + else { return emptyValueString } return commonFormatter.string(from: voltage.converted(to: .volts)) } - public func double(for humidity: Humidity, - temperature: Temperature, - isDecimal: Bool) -> Double? - { + public func double( + for humidity: Humidity, + temperature: Temperature, + isDecimal: Bool + ) -> Double? { let humidityWithTemperature = Humidity( value: humidity.value, unit: .relative(temperature: temperature) @@ -274,10 +284,11 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } } - public func string(for humidity: Humidity?, - temperature: Temperature?, - allowSettings: Bool) -> String - { + public func string( + for humidity: Humidity?, + temperature: Temperature?, + allowSettings: Bool + ) -> String { guard let humidity, let temperature else { @@ -299,20 +310,23 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { case .gm3: return humidityFormatter.string(from: humidityWithTemperature.converted(to: .absolute)) case .dew: - guard let dp = try? humidityWithTemperature.dewPoint(temperature: temperature) else { + guard let dp = try? humidityWithTemperature.dewPoint(temperature: temperature) + else { return emptyValueString } let value = dp.converted(to: settings.temperatureUnit.unitTemperature).value - guard let value = humidityNumberFormatter.string(from: NSNumber(value: value)) else { + guard let value = humidityNumberFormatter.string(from: NSNumber(value: value)) + else { return emptyValueString } return value + " " + settings.temperatureUnit.symbol } } - public func stringWithoutSign(for humidity: Humidity?, - temperature: Temperature?) -> String - { + public func stringWithoutSign( + for humidity: Humidity?, + temperature: Temperature? + ) -> String { guard let humidity, let temperature else { @@ -343,7 +357,8 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } public func stringWithoutSign(humidity: Double?) -> String { - guard let humidity else { + guard let humidity + else { return emptyValueString } let number = NSNumber(value: humidity) @@ -351,7 +366,8 @@ extension RuuviServiceMeasurementImpl: RuuviServiceMeasurement { } public func string(for measurement: Double?) -> String { - guard let measurement else { + guard let measurement + else { return "" } let number = NSNumber(value: measurement) @@ -378,21 +394,24 @@ extension RuuviServiceMeasurementImpl { } public func updateUnits() { - units = RuuviServiceMeasurementSettingsUnit(temperatureUnit: settings.temperatureUnit.unitTemperature, - humidityUnit: settings.humidityUnit, - pressureUnit: settings.pressureUnit) + units = RuuviServiceMeasurementSettingsUnit( + temperatureUnit: settings.temperatureUnit.unitTemperature, + humidityUnit: settings.humidityUnit, + pressureUnit: settings.pressureUnit + ) } private func startSettingsObserving() { notificationsNamesToObserve.forEach { let observer = NotificationCenter .default - .addObserver(forName: $0, - object: nil, - queue: .main) - { [weak self] _ in - self?.updateCache() - } + .addObserver( + forName: $0, + object: nil, + queue: .main + ) { [weak self] _ in + self?.updateCache() + } self.observers.append(observer) } } @@ -424,8 +443,10 @@ public extension RuuviServiceMeasurementImpl { from: Humidity( value: humidityOffsetCorrection(for: humidity) * 100, unit: UnitHumidity.relative( - temperature: Temperature(value: 0.0, - unit: UnitTemperature.celsius) + temperature: Temperature( + value: 0.0, + unit: UnitTemperature.celsius + ) ) ) ) diff --git a/Packages/RuuviService/Sources/RuuviServiceOwnership/RuuviServiceOwnershipImpl.swift b/Packages/RuuviService/Sources/RuuviServiceOwnership/RuuviServiceOwnershipImpl.swift index ca16ec663..d8f4c1af7 100644 --- a/Packages/RuuviService/Sources/RuuviServiceOwnership/RuuviServiceOwnershipImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceOwnership/RuuviServiceOwnershipImpl.swift @@ -88,11 +88,13 @@ public final class RuuviServiceOwnershipImpl: RuuviServiceOwnership { @discardableResult public func claim(sensor: RuuviTagSensor) -> Future { let promise = Promise() - guard let macId = sensor.macId else { + guard let macId = sensor.macId + else { promise.fail(error: .macIdIsNil) return promise.future } - guard let owner = ruuviUser.email else { + guard let owner = ruuviUser.email + else { promise.fail(error: .ruuviCloud(.notAuthorized)) return promise.future } @@ -116,12 +118,14 @@ public final class RuuviServiceOwnershipImpl: RuuviServiceOwnership { secret: String ) -> Future { let promise = Promise() - guard let macId = sensor.macId else { + guard let macId = sensor.macId + else { promise.fail(error: .macIdIsNil) return promise.future } - guard let owner = ruuviUser.email else { + guard let owner = ruuviUser.email + else { promise.fail(error: .ruuviCloud(.notAuthorized)) return promise.future } @@ -146,7 +150,8 @@ public final class RuuviServiceOwnershipImpl: RuuviServiceOwnership { removeCloudHistory: Bool ) -> Future { let promise = Promise() - guard let macId = sensor.macId else { + guard let macId = sensor.macId + else { promise.fail(error: .macIdIsNil) return promise.future } @@ -205,8 +210,7 @@ public final class RuuviServiceOwnershipImpl: RuuviServiceOwnership { var unshareOperation: Future? var unclaimOperation: Future? if let macId = sensor.macId, - sensor.isCloud - { + sensor.isCloud { if sensor.isOwner { unclaimOperation = unclaim( sensor: sensor, @@ -218,24 +222,26 @@ public final class RuuviServiceOwnershipImpl: RuuviServiceOwnership { } propertiesService.removeImage(for: sensor) localIDs.clear(sensor: sensor) - Future.zip([deleteTagOperation, - deleteRecordsOperation, - deleteLastRecordOperation]) - .on(success: { _ in - if let unclaimOperation { - unclaimOperation.on() - promise.succeed(value: sensor.any) - } else if let unshareOperation { - unshareOperation.on() - promise.succeed(value: sensor.any) - } else { - promise.succeed(value: sensor.any) - } - }, failure: { error in - promise.fail(error: .ruuviPool(error)) - }, completion: { - cleanUpOperation.on() - }) + Future.zip([ + deleteTagOperation, + deleteRecordsOperation, + deleteLastRecordOperation, + ]) + .on(success: { _ in + if let unclaimOperation { + unclaimOperation.on() + promise.succeed(value: sensor.any) + } else if let unshareOperation { + unshareOperation.on() + promise.succeed(value: sensor.any) + } else { + promise.succeed(value: sensor.any) + } + }, failure: { error in + promise.fail(error: .ruuviPool(error)) + }, completion: { + cleanUpOperation.on() + }) return promise.future } diff --git a/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift b/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift index c74111a3d..6d81ebb6f 100644 --- a/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift @@ -40,7 +40,6 @@ public final class RuuviServiceSensorPropertiesImpl: RuuviServiceSensorPropertie }, failure: { error in promise.fail(error: .ruuviPool(error)) }) - } else { let namedSensor = sensor.with(name: name) pool.update(namedSensor) @@ -89,7 +88,8 @@ public final class RuuviServiceSensorPropertiesImpl: RuuviServiceSensorPropertie ) -> Future { let promise = Promise() let croppedImage = coreImage.cropped(image: image, to: maxSize) - guard let jpegData = croppedImage.jpegData(compressionQuality: 0.6) else { + guard let jpegData = croppedImage.jpegData(compressionQuality: 0.6) + else { promise.fail(error: .failedToGetJpegRepresentation) return promise.future } @@ -179,7 +179,8 @@ public final class RuuviServiceSensorPropertiesImpl: RuuviServiceSensorPropertie @discardableResult private func resetCloudImage(for sensor: RuuviTagSensor) -> Future { let promise = Promise() - guard let macId = sensor.macId else { + guard let macId = sensor.macId + else { promise.fail(error: .macIdIsNil) return promise.future } diff --git a/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageCoordinator.swift b/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageCoordinator.swift index c65119efd..c70c22645 100644 --- a/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageCoordinator.swift +++ b/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageCoordinator.swift @@ -85,9 +85,12 @@ final class RuuviStorageCoordinator: RuuviStorage { pick points: Double ) -> Future<[RuuviTagSensorRecord], RuuviStorageError> { let promise = Promise<[RuuviTagSensorRecord], RuuviStorageError>() - let sqliteOperation = sqlite.readDownsampled(id, after: date, - with: intervalMinutes, - pick: points) + let sqliteOperation = sqlite.readDownsampled( + id, + after: date, + with: intervalMinutes, + pick: points + ) sqliteOperation.on(success: { sqliteEntities in promise.succeed(value: sqliteEntities) }, failure: { error in @@ -224,8 +227,7 @@ final class RuuviStorageCoordinator: RuuviStorage { // MARK: - Queued cloud requests func readQueuedRequests() - -> Future<[RuuviCloudQueuedRequest], RuuviStorageError> - { + -> Future<[RuuviCloudQueuedRequest], RuuviStorageError> { let promise = Promise<[RuuviCloudQueuedRequest], RuuviStorageError>() sqlite.readQueuedRequests().on(success: { requests in promise.succeed(value: requests) diff --git a/Packages/RuuviUser/Package.swift b/Packages/RuuviUser/Package.swift index c1a1caf3a..bf56f86fc 100644 --- a/Packages/RuuviUser/Package.swift +++ b/Packages/RuuviUser/Package.swift @@ -17,7 +17,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/kishikawakatsumi/KeychainAccess", from: "4.2.1"), + .package(url: "https://github.com/kishikawakatsumi/KeychainAccess", from: "4.2.1") ], targets: [ .target( @@ -26,7 +26,7 @@ let package = Package( .target( name: "RuuviUserCoordinator", dependencies: [ - "KeychainAccess", + "KeychainAccess" ] ), .testTarget( diff --git a/Packages/RuuviUser/Sources/RuuviUserCoordinator/RuuviUserCoordinator.swift b/Packages/RuuviUser/Sources/RuuviUserCoordinator/RuuviUserCoordinator.swift index fe7b81468..4f1801831 100644 --- a/Packages/RuuviUser/Sources/RuuviUserCoordinator/RuuviUserCoordinator.swift +++ b/Packages/RuuviUser/Sources/RuuviUserCoordinator/RuuviUserCoordinator.swift @@ -44,9 +44,11 @@ final class RuuviUserCoordinator: RuuviUser { isAuthorized = true NotificationCenter .default - .post(name: .RuuviUserDidAuthorized, - object: self, - userInfo: nil) + .post( + name: .RuuviUserDidAuthorized, + object: self, + userInfo: nil + ) } func logout() { diff --git a/intents/IntentHandler.swift b/intents/IntentHandler.swift index 5a4476dcf..07d0e2ab3 100644 --- a/intents/IntentHandler.swift +++ b/intents/IntentHandler.swift @@ -2,10 +2,13 @@ import Intents class IntentHandler: INExtension, RuuviTagSelectionIntentHandling { private let viewModel = WidgetViewModel() - func provideRuuviWidgetTagOptionsCollection(for _: RuuviTagSelectionIntent, - with completion: @escaping (INObjectCollection?, - Error?) -> Void) - { + func provideRuuviWidgetTagOptionsCollection( + for _: RuuviTagSelectionIntent, + with completion: @escaping ( + INObjectCollection?, + Error? + ) -> Void + ) { viewModel.fetchRuuviTags(completion: { response in let newValues = response.compactMap { sensor in RuuviWidgetTag(identifier: sensor.sensor.id, display: sensor.sensor.name) diff --git a/pnservice/NotificationService.swift b/pnservice/NotificationService.swift index 2c05b14b9..bbce08154 100644 --- a/pnservice/NotificationService.swift +++ b/pnservice/NotificationService.swift @@ -24,10 +24,11 @@ class NotificationService: UNNotificationServiceExtension { var bestAttemptContent: UNMutableNotificationContent? var currentRequest: UNNotificationRequest? - override func didReceive(_ request: UNNotificationRequest, - withContentHandler contentHandler: - @escaping (UNNotificationContent) -> Void) - { + override func didReceive( + _ request: UNNotificationRequest, + withContentHandler contentHandler: + @escaping (UNNotificationContent) -> Void + ) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) currentRequest = request @@ -41,8 +42,7 @@ class NotificationService: UNNotificationServiceExtension { private func processNotification() { if let contentHandler, let userInfo = currentRequest?.content.userInfo, - let bestAttemptContent - { + let bestAttemptContent { // If this value is not available on data, show formatted message. // Otherwise don't do anything. let showLocallyFormattedMessage = userInfo["showLocallyFormatted"] as? Bool ?? true @@ -51,11 +51,12 @@ class NotificationService: UNNotificationServiceExtension { let alertType = userInfo["alertType"] as? String, let triggerType = userInfo["triggerType"] as? String, let threshold = userInfo["thresholdValue"] as? String, - let alertMessage = userInfo["alertData"] as? String - { - let title = titleForAlert(from: triggerType, - alertType: alertType, - threshold: threshold) + let alertMessage = userInfo["alertData"] as? String { + let title = titleForAlert( + from: triggerType, + alertType: alertType, + threshold: threshold + ) bestAttemptContent.subtitle = alertMessage bestAttemptContent.title = title bestAttemptContent.body = sensorName @@ -97,10 +98,11 @@ extension NotificationService { } // swiftlint:disable:next cyclomatic_complexity - private func titleForAlert(from triggerType: String, - alertType: String, - threshold: String) -> String - { + private func titleForAlert( + from triggerType: String, + alertType: String, + threshold: String + ) -> String { guard let triggerType = getTriggerType(from: triggerType), let alertType = getAlertType(from: alertType) else { @@ -158,9 +160,11 @@ extension NotificationService { return NSLocalizedString(value, comment: value) } - return NSLocalizedString(value, - tableName: nil, - bundle: languageBundle, - comment: value) + return NSLocalizedString( + value, + tableName: nil, + bundle: languageBundle, + comment: value + ) } } diff --git a/ruuvi-widgets/Assembly/WidgetAssembly.swift b/ruuvi-widgets/Assembly/WidgetAssembly.swift index 7b06a4f90..ec266fbde 100644 --- a/ruuvi-widgets/Assembly/WidgetAssembly.swift +++ b/ruuvi-widgets/Assembly/WidgetAssembly.swift @@ -16,7 +16,7 @@ final class WidgetAssembly { init() { assembler = Assembler( [ - NetworkingAssembly(), + NetworkingAssembly() ]) } } diff --git a/ruuvi-widgets/Helper/Extensions.swift b/ruuvi-widgets/Helper/Extensions.swift index 7707dfe01..a2f2cda51 100644 --- a/ruuvi-widgets/Helper/Extensions.swift +++ b/ruuvi-widgets/Helper/Extensions.swift @@ -131,8 +131,10 @@ extension String { } subscript(r: Range) -> String { - let range = Range(uncheckedBounds: (lower: max(0, min(length, r.lowerBound)), - upper: min(length, max(0, r.upperBound)))) + let range = Range(uncheckedBounds: ( + lower: max(0, min(length, r.lowerBound)), + upper: min(length, max(0, r.upperBound)) + )) let start = index(startIndex, offsetBy: range.lowerBound) let end = index(start, offsetBy: range.upperBound - range.lowerBound) return String(self[start ..< end]) diff --git a/ruuvi-widgets/Helper/MeasurementService.swift b/ruuvi-widgets/Helper/MeasurementService.swift index ef330f95e..526358d60 100644 --- a/ruuvi-widgets/Helper/MeasurementService.swift +++ b/ruuvi-widgets/Helper/MeasurementService.swift @@ -75,7 +75,8 @@ final class MeasurementService: NSObject { extension MeasurementService { public func temperature(for temperature: Temperature?) -> String { - guard let temperature else { + guard let temperature + else { return emptyValueString } let value = temperature @@ -88,7 +89,8 @@ extension MeasurementService { } public func pressure(for pressure: Pressure?) -> String { - guard let pressure else { + guard let pressure + else { return emptyValueString } let value = pressure @@ -101,7 +103,8 @@ extension MeasurementService { } public func voltage(for voltage: Voltage?) -> String { - guard let voltage else { + guard let voltage + else { return emptyValueString } let value = voltage @@ -111,10 +114,11 @@ extension MeasurementService { return formattedValue(from: value, formatter: commonFormatter) } - public func humidity(for humidity: Humidity?, - temperature: Temperature?, - isDecimal: Bool) -> String - { + public func humidity( + for humidity: Humidity?, + temperature: Temperature?, + isDecimal: Bool + ) -> String { guard let humidity, let temperature else { @@ -151,7 +155,8 @@ extension MeasurementService { } public func acceleration(for acceleration: Double?) -> String { - guard let acceleration else { + guard let acceleration + else { return emptyValueString } let value = acceleration.round(to: commonFormatter.maximumFractionDigits) @@ -159,7 +164,8 @@ extension MeasurementService { } public func movements(for movements: Int?) -> String { - guard let movements else { + guard let movements + else { return emptyValueString } return movements.value @@ -169,9 +175,10 @@ extension MeasurementService { // MARK: - MeasurementService Helper methods extension MeasurementService { - private func formattedValue(from value: Double?, - formatter: NumberFormatter) -> String - { + private func formattedValue( + from value: Double?, + formatter: NumberFormatter + ) -> String { guard let value, let formattedValue = formatter.string(from: value.nsNumber) else { diff --git a/ruuvi-widgets/Model/Model+Extension.swift b/ruuvi-widgets/Model/Model+Extension.swift index bb905e0fb..43335c6c3 100644 --- a/ruuvi-widgets/Model/Model+Extension.swift +++ b/ruuvi-widgets/Model/Model+Extension.swift @@ -10,28 +10,32 @@ extension RuuviTagSelectionIntent { extension RuuviTagSensorRecordStruct { static func preview() -> RuuviTagSensorRecordStruct { - RuuviTagSensorRecordStruct(luid: nil, - date: Date(), - source: .ruuviNetwork, - macId: nil, - rssi: nil, - temperature: Temperature(69.50), - humidity: nil, - pressure: nil, - acceleration: nil, - voltage: nil, - movementCounter: nil, - measurementSequenceNumber: nil, - txPower: nil, - temperatureOffset: 0, - humidityOffset: 0, - pressureOffset: 0) + RuuviTagSensorRecordStruct( + luid: nil, + date: Date(), + source: .ruuviNetwork, + macId: nil, + rssi: nil, + temperature: Temperature(69.50), + humidity: nil, + pressure: nil, + acceleration: nil, + voltage: nil, + movementCounter: nil, + measurementSequenceNumber: nil, + txPower: nil, + temperatureOffset: 0, + humidityOffset: 0, + pressureOffset: 0 + ) } } extension RuuviWidgetTag { - static var preview: RuuviWidgetTag = .init(identifier: nil, - display: "Sauna") + static var preview: RuuviWidgetTag = .init( + identifier: nil, + display: "Sauna" + ) } extension WidgetSensor { @@ -40,13 +44,15 @@ extension WidgetSensor { extension SensorSettingsStruct { static func settings(from ruuviTag: AnyCloudSensor) -> SensorSettingsStruct { - SensorSettingsStruct(luid: ruuviTag.ruuviTagSensor.luid, - macId: ruuviTag.ruuviTagSensor.macId, - temperatureOffset: ruuviTag.offsetTemperature, - temperatureOffsetDate: nil, - humidityOffset: ruuviTag.offsetHumidity, - humidityOffsetDate: nil, - pressureOffset: ruuviTag.offsetPressure, - pressureOffsetDate: nil) + SensorSettingsStruct( + luid: ruuviTag.ruuviTagSensor.luid, + macId: ruuviTag.ruuviTagSensor.macId, + temperatureOffset: ruuviTag.offsetTemperature, + temperatureOffsetDate: nil, + humidityOffset: ruuviTag.offsetHumidity, + humidityOffsetDate: nil, + pressureOffset: ruuviTag.offsetPressure, + pressureOffsetDate: nil + ) } } diff --git a/ruuvi-widgets/Model/WidgetEntry.swift b/ruuvi-widgets/Model/WidgetEntry.swift index c8b07ef61..a642d771e 100644 --- a/ruuvi-widgets/Model/WidgetEntry.swift +++ b/ruuvi-widgets/Model/WidgetEntry.swift @@ -13,40 +13,49 @@ struct WidgetEntry: TimelineEntry { extension WidgetEntry { static func placeholder() -> WidgetEntry { - WidgetEntry(date: Date(), - isAuthorized: true, - tag: .preview, - record: RuuviTagSensorRecordStruct.preview(), - settings: nil, - config: .preview) + WidgetEntry( + date: Date(), + isAuthorized: true, + tag: .preview, + record: RuuviTagSensorRecordStruct.preview(), + settings: nil, + config: .preview + ) } static func unauthorized() -> WidgetEntry { - WidgetEntry(date: Date(), - isAuthorized: false, - tag: .preview, - record: nil, - settings: nil, - config: .preview) + WidgetEntry( + date: Date(), + isAuthorized: false, + tag: .preview, + record: nil, + settings: nil, + config: .preview + ) } static func empty() -> WidgetEntry { - WidgetEntry(date: Date(), - isAuthorized: true, - tag: .preview, - record: nil, - settings: nil, - config: .preview) + WidgetEntry( + date: Date(), + isAuthorized: true, + tag: .preview, + record: nil, + settings: nil, + config: .preview + ) } - static func empty(with configuration: RuuviTagSelectionIntent, - authorized: Bool = false) -> WidgetEntry - { - WidgetEntry(date: Date(), - isAuthorized: authorized, - tag: .preview, - record: nil, - settings: nil, - config: authorized ? configuration : .preview) + static func empty( + with configuration: RuuviTagSelectionIntent, + authorized: Bool = false + ) -> WidgetEntry { + WidgetEntry( + date: Date(), + isAuthorized: authorized, + tag: .preview, + record: nil, + settings: nil, + config: authorized ? configuration : .preview + ) } } diff --git a/ruuvi-widgets/Provider/WidgetProvider.swift b/ruuvi-widgets/Provider/WidgetProvider.swift index a92c882a3..559d24c7c 100644 --- a/ruuvi-widgets/Provider/WidgetProvider.swift +++ b/ruuvi-widgets/Provider/WidgetProvider.swift @@ -11,20 +11,25 @@ final class WidgetProvider: IntentTimelineProvider { WidgetEntry.placeholder() } - func getSnapshot(for _: RuuviTagSelectionIntent, - in _: Context, - completion: @escaping (WidgetEntry) -> Void) - { + func getSnapshot( + for _: RuuviTagSelectionIntent, + in _: Context, + completion: @escaping (WidgetEntry) -> Void + ) { completion(.placeholder()) } - func getTimeline(for configuration: RuuviTagSelectionIntent, - in _: Context, - completion: @escaping (Timeline) -> Void) - { - guard networkManager.isConnected, viewModel.isAuthorized() else { - return emptyTimeline(for: configuration, - completion: completion) + func getTimeline( + for configuration: RuuviTagSelectionIntent, + in _: Context, + completion: @escaping (Timeline) -> Void + ) { + guard networkManager.isConnected, viewModel.isAuthorized() + else { + return emptyTimeline( + for: configuration, + completion: completion + ) } viewModel.fetchRuuviTags(completion: { [weak self] tags in guard let sSelf = self else { return } @@ -33,50 +38,65 @@ final class WidgetProvider: IntentTimelineProvider { result.sensor.id == configuredTag.identifier }) else { - return sSelf.emptyTimeline(for: configuration, - completion: completion) + return sSelf.emptyTimeline( + for: configuration, + completion: completion + ) } - guard let record = tag.record else { - return sSelf.emptyTimeline(for: configuration, - completion: completion) + guard let record = tag.record + else { + return sSelf.emptyTimeline( + for: configuration, + completion: completion + ) } - sSelf.timeline(from: tag.sensor.any, - configuration: configuration, - record: record, - completion: completion) + sSelf.timeline( + from: tag.sensor.any, + configuration: configuration, + record: record, + completion: completion + ) }) } } extension WidgetProvider { - private func emptyTimeline(for configuration: RuuviTagSelectionIntent, - completion: @escaping (Timeline) -> Void) - { + private func emptyTimeline( + for configuration: RuuviTagSelectionIntent, + completion: @escaping (Timeline) -> Void + ) { var entries: [WidgetEntry] = [] - let entry = WidgetEntry.empty(with: configuration, - authorized: viewModel.isAuthorized()) + let entry = WidgetEntry.empty( + with: configuration, + authorized: viewModel.isAuthorized() + ) entries.append(entry) - let timeline = Timeline(entries: entries, - policy: .atEnd) + let timeline = Timeline( + entries: entries, + policy: .atEnd + ) return completion(timeline) } - private func timeline(from ruuviTag: AnyCloudSensor, - configuration: RuuviTagSelectionIntent, - record: RuuviTagSensorRecord, - completion: @escaping (Timeline) -> Void) - { + private func timeline( + from ruuviTag: AnyCloudSensor, + configuration: RuuviTagSelectionIntent, + record: RuuviTagSensorRecord, + completion: @escaping (Timeline) -> Void + ) { var entries: [WidgetEntry] = [] let settings = SensorSettingsStruct.settings(from: ruuviTag) - let entry = WidgetEntry(date: Date(), - isAuthorized: viewModel.isAuthorized(), - tag: RuuviWidgetTag(identifier: ruuviTag.id, display: ruuviTag.name), - record: record, - settings: settings, - config: configuration) + let entry = WidgetEntry( + date: Date(), + isAuthorized: viewModel.isAuthorized(), + tag: RuuviWidgetTag(identifier: ruuviTag.id, display: ruuviTag.name), + record: record, + settings: settings, + config: configuration + ) entries.append(entry) let timeline = Timeline(entries: entries, policy: .atEnd) completion(timeline) diff --git a/ruuvi-widgets/RuuviWidgets.swift b/ruuvi-widgets/RuuviWidgets.swift index 05fcaf83b..d6e788670 100644 --- a/ruuvi-widgets/RuuviWidgets.swift +++ b/ruuvi-widgets/RuuviWidgets.swift @@ -45,7 +45,7 @@ struct RuuviWidgets: Widget { ] } else { [ - .systemSmall, + .systemSmall ] } } diff --git a/ruuvi-widgets/View Model/WidgetViewModel.swift b/ruuvi-widgets/View Model/WidgetViewModel.swift index e5c8bcf82..38933ee87 100644 --- a/ruuvi-widgets/View Model/WidgetViewModel.swift +++ b/ruuvi-widgets/View Model/WidgetViewModel.swift @@ -21,14 +21,17 @@ public final class WidgetViewModel: ObservableObject { public extension WidgetViewModel { func fetchRuuviTags(completion: @escaping ([RuuviCloudSensorDense]) -> Void) { - guard isAuthorized(), hasCloudSensors() else { + guard isAuthorized(), hasCloudSensors() + else { return } - ruuviCloud.loadSensorsDense(for: nil, - measurements: true, - sharedToOthers: nil, - sharedToMe: true, - alerts: nil).on(success: { sensors in + ruuviCloud.loadSensorsDense( + for: nil, + measurements: true, + sharedToOthers: nil, + sharedToMe: true, + alerts: nil + ).on(success: { sensors in let sensorsWithRecord = sensors.filter { $0.record != nil } completion(sensorsWithRecord) }) @@ -42,10 +45,11 @@ public extension WidgetViewModel { appGroupDefaults?.bool(forKey: Constants.isAuthorizedUDKey.rawValue) ?? false } - func getValue(from record: RuuviTagSensorRecord?, - settings: SensorSettings?, - config: RuuviTagSelectionIntent) -> String - { + func getValue( + from record: RuuviTagSensorRecord?, + settings: SensorSettings?, + config: RuuviTagSelectionIntent + ) -> String { let measurementService = MeasurementService(settings: getAppSettings()) guard let sensor = WidgetSensorEnum(rawValue: config.sensor.rawValue), let record @@ -59,9 +63,11 @@ public extension WidgetViewModel { case .humidity: let temperature = record.temperature?.plus(sensorSettings: settings) let humidity = record.humidity?.plus(sensorSettings: settings) - return measurementService.humidity(for: humidity, - temperature: temperature, - isDecimal: false) + return measurementService.humidity( + for: humidity, + temperature: temperature, + isDecimal: false + ) case .pressure: let pressure = record.pressure?.plus(sensorSettings: settings) return measurementService.pressure(for: pressure) @@ -79,7 +85,8 @@ public extension WidgetViewModel { } func getUnit(for sensor: WidgetSensorEnum?) -> String { - guard let sensor else { + guard let sensor + else { return "°C" // Default unit to show on the preview } let settings = getAppSettings() @@ -92,9 +99,11 @@ public extension WidgetViewModel { /// Returns value for inline widget internal func getInlineWidgetValue(from entry: WidgetEntry) -> String { - let value = getValue(from: entry.record, - settings: entry.settings, - config: entry.config) + let value = getValue( + from: entry.record, + settings: entry.settings, + config: entry.config + ) let unit = getUnit(for: WidgetSensorEnum(rawValue: entry.config.sensor.rawValue)) return value + " " + unit } @@ -102,7 +111,8 @@ public extension WidgetViewModel { /// Returns SF Symbol based on sensor since we /// can not use Image in inline widget internal func symbol(from entry: WidgetEntry) -> Image { - guard let sensor = WidgetSensorEnum(rawValue: entry.config.sensor.rawValue) else { + guard let sensor = WidgetSensorEnum(rawValue: entry.config.sensor.rawValue) + else { return Image(systemName: "thermometer.medium.slash") } switch sensor { @@ -146,13 +156,15 @@ extension WidgetViewModel { let humidityAccuracy = humidityAccuracy(from: appGroupDefaults) let pressureUnit = pressureUnit(from: appGroupDefaults) let pressureAccuracy = pressureAccuracy(from: appGroupDefaults) - return MeasurementServiceSettings(temperatureUnit: temperatureUnit, - temperatureAccuracy: temperatureAccuracy, - humidityUnit: humidityUnit, - humidityAccuracy: humidityAccuracy, - pressureUnit: pressureUnit, - pressureAccuracy: pressureAccuracy, - language: getLanguage()) + return MeasurementServiceSettings( + temperatureUnit: temperatureUnit, + temperatureAccuracy: temperatureAccuracy, + humidityUnit: humidityUnit, + humidityAccuracy: humidityAccuracy, + pressureUnit: pressureUnit, + pressureAccuracy: pressureAccuracy, + language: getLanguage() + ) } private func getLanguage() -> Language { diff --git a/ruuvi-widgets/View/EmptyWidgetView.swift b/ruuvi-widgets/View/EmptyWidgetView.swift index 815c6a6d1..b743ba514 100644 --- a/ruuvi-widgets/View/EmptyWidgetView.swift +++ b/ruuvi-widgets/View/EmptyWidgetView.swift @@ -46,9 +46,11 @@ struct EmptyWidgetView: View { (isSimple ? texts.messageSimple.localized : texts.messageRectangular.localized) : texts.loading.localized) - .font(.custom(Constants.muliBold.rawValue, - size: family == .systemSmall ? 16 : 10, - relativeTo: .subheadline)) + .font(.custom( + Constants.muliBold.rawValue, + size: family == .systemSmall ? 16 : 10, + relativeTo: .subheadline + )) .foregroundColor(.sensorNameColor1) .multilineTextAlignment(.center) }.padding(4) @@ -70,15 +72,19 @@ struct EmptyWidgetView: View { .renderingMode(.template) .resizable() .aspectRatio(contentMode: .fit) - .padding(.init(top: 4, - leading: 8, - bottom: -4, - trailing: 8)) + .padding(.init( + top: 4, + leading: 8, + bottom: -4, + trailing: 8 + )) Text(entry.config.ruuviWidgetTag == nil ? texts.messageCircular.localized : texts.loading.localized) - .font(.custom(Constants.muliBold.rawValue, - size: 8, - relativeTo: .headline)) + .font(.custom( + Constants.muliBold.rawValue, + size: 8, + relativeTo: .headline + )) .foregroundColor(.sensorNameColor1) .multilineTextAlignment(.center) }.padding(4) diff --git a/ruuvi-widgets/View/SimpleWidgetView.swift b/ruuvi-widgets/View/SimpleWidgetView.swift index d6b3cacd4..30d2b1c61 100644 --- a/ruuvi-widgets/View/SimpleWidgetView.swift +++ b/ruuvi-widgets/View/SimpleWidgetView.swift @@ -43,20 +43,26 @@ struct SimpleWidgetView: View { } HStack(spacing: 2) { - Text(viewModel.getValue(from: entry.record, - settings: entry.settings, - config: entry.config)) - .environment(\.locale, viewModel.locale()) - .foregroundColor(.bodyTextColor) - .font(.custom(Constants.oswaldBold.rawValue, - size: canShowBackground ? 36 : 66, - relativeTo: .largeTitle)) - .minimumScaleFactor(0.5) + Text(viewModel.getValue( + from: entry.record, + settings: entry.settings, + config: entry.config + )) + .environment(\.locale, viewModel.locale()) + .foregroundColor(.bodyTextColor) + .font(.custom( + Constants.oswaldBold.rawValue, + size: canShowBackground ? 36 : 66, + relativeTo: .largeTitle + )) + .minimumScaleFactor(0.5) Text(viewModel.getUnit(for: WidgetSensorEnum(rawValue: entry.config.sensor.rawValue))) .foregroundColor(Color.unitTextColor) - .font(.custom(Constants.oswaldExtraLight.rawValue, - size: canShowBackground ? 16 : 24, - relativeTo: .title3)) + .font(.custom( + Constants.oswaldExtraLight.rawValue, + size: canShowBackground ? 16 : 24, + relativeTo: .title3 + )) .baselineOffset(14) .minimumScaleFactor(0.5) Spacer() diff --git a/ruuvi-widgets/View/SimpleWidgetViewCircular.swift b/ruuvi-widgets/View/SimpleWidgetViewCircular.swift index 2ee89931a..c2cf27061 100644 --- a/ruuvi-widgets/View/SimpleWidgetViewCircular.swift +++ b/ruuvi-widgets/View/SimpleWidgetViewCircular.swift @@ -10,29 +10,37 @@ struct SimpleWidgetViewCircular: View { VStack(spacing: 0) { Text(entry.tag.displayString.substring(toIndex: 8).capitalized) - .font(.custom(Constants.muliBold.rawValue, - size: 8, - relativeTo: .subheadline)) + .font(.custom( + Constants.muliBold.rawValue, + size: 8, + relativeTo: .subheadline + )) .foregroundColor(.sensorNameColor1) .frame(maxWidth: .infinity, alignment: .center) - Text(viewModel.getValue(from: entry.record, - settings: entry.settings, - config: entry.config)) - .environment(\.locale, viewModel.locale()) - .foregroundColor(.white) - .font(.custom(Constants.oswaldBold.rawValue, - size: 18, - relativeTo: .subheadline)) - .minimumScaleFactor(0.6) - .padding(.top, -4) + Text(viewModel.getValue( + from: entry.record, + settings: entry.settings, + config: entry.config + )) + .environment(\.locale, viewModel.locale()) + .foregroundColor(.white) + .font(.custom( + Constants.oswaldBold.rawValue, + size: 18, + relativeTo: .subheadline + )) + .minimumScaleFactor(0.6) + .padding(.top, -4) Text(viewModel.getUnit(for: WidgetSensorEnum( rawValue: entry.config.sensor.rawValue))) .foregroundColor(Color.unitTextColor) - .font(.custom(Constants.muliBold.rawValue, - size: 10, - relativeTo: .body)) + .font(.custom( + Constants.muliBold.rawValue, + size: 10, + relativeTo: .body + )) .minimumScaleFactor(0.5) .padding(.top, -2) diff --git a/ruuvi-widgets/View/SimpleWidgetViewRectangle.swift b/ruuvi-widgets/View/SimpleWidgetViewRectangle.swift index 1c19bce89..c27e73d9c 100644 --- a/ruuvi-widgets/View/SimpleWidgetViewRectangle.swift +++ b/ruuvi-widgets/View/SimpleWidgetViewRectangle.swift @@ -7,35 +7,45 @@ struct SimpleWidgetViewRectangle: View { VStack { VStack { Text(entry.tag.displayString.capitalized) - .font(.custom(Constants.muliBold.rawValue, - size: 16, - relativeTo: .subheadline)) + .font(.custom( + Constants.muliBold.rawValue, + size: 16, + relativeTo: .subheadline + )) .foregroundColor(Color.sensorNameColor1) .frame(maxWidth: .infinity, alignment: .leading) .padding(.leading, 4) .padding(.top, 10) HStack(spacing: 2) { - Text(viewModel.getValue(from: entry.record, - settings: entry.settings, - config: entry.config)) - .environment(\.locale, viewModel.locale()) - .foregroundColor(.bodyTextColor) - .font(.custom(Constants.oswaldBold.rawValue, - size: 36, - relativeTo: .title)) + Text(viewModel.getValue( + from: entry.record, + settings: entry.settings, + config: entry.config + )) + .environment(\.locale, viewModel.locale()) + .foregroundColor(.bodyTextColor) + .font(.custom( + Constants.oswaldBold.rawValue, + size: 36, + relativeTo: .title + )) Text(viewModel.getUnit(for: WidgetSensorEnum(rawValue: entry.config.sensor.rawValue))) .foregroundColor(Color.unitTextColor) - .font(.custom(Constants.oswaldExtraLight.rawValue, - size: 20, - relativeTo: .title3)) + .font(.custom( + Constants.oswaldExtraLight.rawValue, + size: 20, + relativeTo: .title3 + )) .baselineOffset(8) Spacer() } - .padding(EdgeInsets(top: -20, - leading: 4, - bottom: 8, - trailing: 4)) + .padding(EdgeInsets( + top: -20, + leading: 4, + bottom: 8, + trailing: 4 + )) } }.edgesIgnoringSafeArea(.all) .widgetURL(URL(string: "\(entry.tag.identifier.unwrapped)")) diff --git a/ruuvi-widgets/View/UnauthorizedView.swift b/ruuvi-widgets/View/UnauthorizedView.swift index 97563af65..22efcdb89 100644 --- a/ruuvi-widgets/View/UnauthorizedView.swift +++ b/ruuvi-widgets/View/UnauthorizedView.swift @@ -38,9 +38,11 @@ struct UnauthorizedView: View { .cornerRadius(8) VStack { Text(texts.unauthorizedRegular.localized) - .font(.custom(Constants.muliBold.rawValue, - size: family == .systemSmall ? 16 : 10, - relativeTo: .subheadline)) + .font(.custom( + Constants.muliBold.rawValue, + size: family == .systemSmall ? 16 : 10, + relativeTo: .subheadline + )) .foregroundColor(.sensorNameColor1) .multilineTextAlignment(.center) }.padding(4) @@ -64,9 +66,11 @@ struct UnauthorizedView: View { .padding([.leading, .trailing], 8) .padding(.bottom, -4) Text(texts.unauthorizedSmall.localized) - .font(.custom(Constants.muliBold.rawValue, - size: 8, - relativeTo: .headline)) + .font(.custom( + Constants.muliBold.rawValue, + size: 8, + relativeTo: .headline + )) .foregroundColor(.sensorNameColor1) .multilineTextAlignment(.center) }.padding(4) diff --git a/station/Classes/Application/AppDelegate.swift b/station/Classes/Application/AppDelegate.swift index 29308149a..fecd4b110 100644 --- a/station/Classes/Application/AppDelegate.swift +++ b/station/Classes/Application/AppDelegate.swift @@ -27,9 +27,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { private var appRouter: AppRouter? - func application(_ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool - { + func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { let r = AppAssembly.shared.assembler.resolver settings = r.resolve(RuuviLocalSettings.self) setPreferrerdLanguage() @@ -99,9 +100,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate { appStateService.applicationDidBecomeActive(application) } - func application(_: UIApplication, - supportedInterfaceOrientationsFor _: UIWindow?) -> UIInterfaceOrientationMask - { + func application( + _: UIApplication, + supportedInterfaceOrientationsFor _: UIWindow? + ) -> UIInterfaceOrientationMask { orientationLock } } @@ -139,17 +141,18 @@ extension AppDelegate: MessagingDelegate { return } - cloudNotificationService.set(token: fcmToken, - name: UIDevice.modelName, - data: nil, - language: settings.language, - sound: settings.alertSound) + cloudNotificationService.set( + token: fcmToken, + name: UIDevice.modelName, + data: nil, + language: settings.language, + sound: settings.alertSound + ) } fileprivate func setPreferrerdLanguage() { if let languageCode = Bundle.main.preferredLocalizations.first, - let language = Language(rawValue: languageCode) - { + let language = Language(rawValue: languageCode) { if settings.language != language { settings.language = language } @@ -162,10 +165,11 @@ extension AppDelegate: MessagingDelegate { // MARK: - UniversalLins extension AppDelegate { - func application(_ application: UIApplication, - continue userActivity: NSUserActivity, - restorationHandler _: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool - { + func application( + _ application: UIApplication, + continue userActivity: NSUserActivity, + restorationHandler _: @escaping ([UIUserActivityRestoring]?) -> Void + ) -> Bool { guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, let url = userActivity.webpageURL else { @@ -179,10 +183,11 @@ extension AppDelegate { // MARK: - Widget Deeplink Handler extension AppDelegate { - func application(_ app: UIApplication, - open url: URL, - options _: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool - { + func application( + _ app: UIApplication, + open url: URL, + options _: [UIApplication.OpenURLOptionsKey: Any] = [:] + ) -> Bool { let macId = url.absoluteString openSelectedCard(for: macId, application: app) return true @@ -199,15 +204,15 @@ extension AppDelegate: RuuviNotificationLocalOutput { // TODO: - SEE IF WE CAN MOVE THIS TO APP_STATE_SERVICE extension AppDelegate { - private func openSelectedCard(for uuid: String, - application _: UIApplication? = nil) - { + private func openSelectedCard( + for uuid: String, + application _: UIApplication? = nil + ) { appRouter?.prepareRootViewControllerWidgets() window?.rootViewController = appRouter?.viewController if let navigationController = appRouter?.viewController as? UINavigationController, - let controller = navigationController.viewControllers.last as? DashboardViewController - { + let controller = navigationController.viewControllers.last as? DashboardViewController { if let viewModel = controller.viewModels.first(where: { viewModel in viewModel.mac.value?.value == uuid || viewModel.luid.value == uuid.luid.any }) { diff --git a/station/Classes/Application/AppState/AppStateService.swift b/station/Classes/Application/AppState/AppStateService.swift index a93e64250..de214b5ba 100644 --- a/station/Classes/Application/AppState/AppStateService.swift +++ b/station/Classes/Application/AppState/AppStateService.swift @@ -1,8 +1,10 @@ import UIKit protocol AppStateService { - func application(_ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) + func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) func applicationWillResignActive(_ application: UIApplication) func applicationDidBecomeActive(_ application: UIApplication) func applicationDidEnterBackground(_ application: UIApplication) diff --git a/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift b/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift index af57c64ac..476e31d7f 100644 --- a/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift +++ b/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift @@ -23,9 +23,10 @@ class AppStateServiceImpl: AppStateService { #endif var universalLinkCoordinator: UniversalLinkCoordinator! - func application(_: UIApplication, - didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) - { + func application( + _: UIApplication, + didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? + ) { if settings.isAdvertisementDaemonOn { advertisementDaemon.start() } diff --git a/station/Classes/Application/Features/FeatureToggleService.swift b/station/Classes/Application/Features/FeatureToggleService.swift index 294cc0087..39f993bfe 100644 --- a/station/Classes/Application/Features/FeatureToggleService.swift +++ b/station/Classes/Application/Features/FeatureToggleService.swift @@ -21,8 +21,7 @@ public final class FeatureToggleService { private var remoteToggles: [FeatureToggle] { get { if let storedRemoteToggles = UserDefaults.standard.object(forKey: remoteTogglesUDKey) as? Data, - let toggles = try? JSONDecoder().decode([FeatureToggle].self, from: storedRemoteToggles) - { + let toggles = try? JSONDecoder().decode([FeatureToggle].self, from: storedRemoteToggles) { toggles } else { [] diff --git a/station/Classes/Application/Features/Providers/FallbackFeatureToggleProvider.swift b/station/Classes/Application/Features/Providers/FallbackFeatureToggleProvider.swift index cdabe3873..71babb181 100644 --- a/station/Classes/Application/Features/Providers/FallbackFeatureToggleProvider.swift +++ b/station/Classes/Application/Features/Providers/FallbackFeatureToggleProvider.swift @@ -44,8 +44,7 @@ public struct JSONParsingService: ParsingService { if let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments), let jsonContainer = json as? [String: Any], let featureToggles = jsonContainer[containerName], - let featureTogglesData = try? JSONSerialization.data(withJSONObject: featureToggles) - { + let featureTogglesData = try? JSONSerialization.data(withJSONObject: featureToggles) { toggleData = featureTogglesData } diff --git a/station/Classes/Application/UniversalLinks/Coordinator/Impl/UniversalLinkCoordinatormpl.swift b/station/Classes/Application/UniversalLinks/Coordinator/Impl/UniversalLinkCoordinatormpl.swift index 1898a1d1a..6dff3467e 100644 --- a/station/Classes/Application/UniversalLinks/Coordinator/Impl/UniversalLinkCoordinatormpl.swift +++ b/station/Classes/Application/UniversalLinks/Coordinator/Impl/UniversalLinkCoordinatormpl.swift @@ -28,8 +28,10 @@ class UniversalLinkCoordinatorImpl { extension UniversalLinkCoordinatorImpl: UniversalLinkCoordinator { func processUniversalLink(url: URL) { - guard let urlComponents = URLComponents(url: url, - resolvingAgainstBaseURL: false), + guard let urlComponents = URLComponents( + url: url, + resolvingAgainstBaseURL: false + ), let path = UniversalLinkType(rawValue: urlComponents.path) else { return @@ -40,9 +42,11 @@ extension UniversalLinkCoordinatorImpl: UniversalLinkCoordinator { func processWidgetLink(macId: String) { settings.setCardToOpenFromWidget(for: macId) - NotificationCenter.default.post(name: .DidOpenWithWidgetDeepLink, - object: nil, - userInfo: [WidgetDeepLinkMacIdKey.macId: macId]) + NotificationCenter.default.post( + name: .DidOpenWithWidgetDeepLink, + object: nil, + userInfo: [WidgetDeepLinkMacIdKey.macId: macId] + ) } } @@ -51,7 +55,8 @@ extension UniversalLinkCoordinatorImpl: UniversalLinkCoordinator { extension UniversalLinkCoordinatorImpl { private func detectViewController(for path: UniversalLinkType) { DispatchQueue.main.async { [weak self] in - guard let topViewController = UIApplication.shared.topViewController() else { + guard let topViewController = UIApplication.shared.topViewController() + else { return } if topViewController.isMember(of: path.handlerType) { @@ -73,9 +78,11 @@ extension UniversalLinkCoordinatorImpl { .value, !ruuviUser.isAuthorized else { - NotificationCenter.default.post(name: .DidOpenWithUniversalLink, - object: nil, - userInfo: nil) + NotificationCenter.default.post( + name: .DidOpenWithUniversalLink, + object: nil, + userInfo: nil + ) return } router.openSignInVerify(with: token, from: topViewController) @@ -88,13 +95,15 @@ extension UniversalLinkCoordinatorImpl { private func postNotification(with path: UniversalLinkType) { var userInfo: [String: Any] = [ - "path": path, + "path": path ] urlComponents.queryItems?.forEach { userInfo[$0.name] = $0.value } - NotificationCenter.default.post(name: .DidOpenWithUniversalLink, - object: nil, - userInfo: userInfo) + NotificationCenter.default.post( + name: .DidOpenWithUniversalLink, + object: nil, + userInfo: userInfo + ) } } diff --git a/station/Classes/Presentation/Binding/NSObject+Observable.swift b/station/Classes/Presentation/Binding/NSObject+Observable.swift index 015dbdbff..9b791a2d9 100644 --- a/station/Classes/Presentation/Binding/NSObject+Observable.swift +++ b/station/Classes/Presentation/Binding/NSObject+Observable.swift @@ -1,10 +1,11 @@ import Foundation extension NSObjectProtocol where Self: NSObject { - func bind(_ observable: Observable, - fire: Bool = true, - block: @escaping (Self, T.WrappedType?) -> Void) - { + func bind( + _ observable: Observable, + fire: Bool = true, + block: @escaping (Self, T.WrappedType?) -> Void + ) { if fire { block(self, observable.value) } diff --git a/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift b/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift index 43dcffad1..5c3a391af 100644 --- a/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift +++ b/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift @@ -55,26 +55,34 @@ extension AboutPresenter { let attrString = NSMutableAttributedString(string: text) let range = NSString(string: attrString.string).range(of: attrString.string) - attrString.addAttribute(NSAttributedString.Key.font, - value: UIFont.Muli(.regular, size: 14), - range: range) + attrString.addAttribute( + NSAttributedString.Key.font, + value: UIFont.Muli(.regular, size: 14), + range: range + ) // Change changelog color let changelogFont = UIFont.Muli(.regular, size: 13) let changelogRange = NSString(string: attrString.string).range(of: changelogString) - attrString.addAttribute(NSAttributedString.Key.font, - value: changelogFont, - range: changelogRange) - attrString.addAttribute(.foregroundColor, - value: RuuviColor.ruuviTintColor ?? UIColor.blue, - range: changelogRange) + attrString.addAttribute( + NSAttributedString.Key.font, + value: changelogFont, + range: changelogRange + ) + attrString.addAttribute( + .foregroundColor, + value: RuuviColor.ruuviTintColor ?? UIColor.blue, + range: changelogRange + ) // Change rest of the text color let regularRange = NSString(string: attrString.string) .range(of: versionText) - attrString.addAttribute(.foregroundColor, - value: RuuviColor.dashboardIndicatorTextColor ?? UIColor.label, - range: regularRange) + attrString.addAttribute( + .foregroundColor, + value: RuuviColor.dashboardIndicatorTextColor ?? UIColor.label, + range: regularRange + ) return attrString } @@ -102,7 +110,8 @@ extension AboutPresenter { } func getRealmFileSize() -> Int64 { - guard let realmPath = realmContext.main.configuration.fileURL?.relativePath else { + guard let realmPath = realmContext.main.configuration.fileURL?.relativePath + else { return 0 } return fileSize(at: realmPath) diff --git a/station/Classes/Presentation/Modules/About/Router/AboutRouter.swift b/station/Classes/Presentation/Modules/About/Router/AboutRouter.swift index ca3fe2f40..52e04aab8 100644 --- a/station/Classes/Presentation/Modules/About/Router/AboutRouter.swift +++ b/station/Classes/Presentation/Modules/About/Router/AboutRouter.swift @@ -11,7 +11,8 @@ class AboutRouter: AboutRouterInput { } func openChangelogPage() { - guard let url = URL(string: RuuviLocalization.changelogIosUrl) else { + guard let url = URL(string: RuuviLocalization.changelogIosUrl) + else { return } UIApplication.shared.open(url, options: [:], completionHandler: nil) diff --git a/station/Classes/Presentation/Modules/About/View/AboutViewController.swift b/station/Classes/Presentation/Modules/About/View/AboutViewController.swift index 0e7a05adc..fb3155b27 100644 --- a/station/Classes/Presentation/Modules/About/View/AboutViewController.swift +++ b/station/Classes/Presentation/Modules/About/View/AboutViewController.swift @@ -71,11 +71,12 @@ extension AboutViewController { // MARK: - UITextViewDelegate extension AboutViewController: UITextViewDelegate { - func textView(_: UITextView, - shouldInteractWith URL: URL, - in _: NSRange, - interaction _: UITextItemInteraction) -> Bool - { + func textView( + _: UITextView, + shouldInteractWith URL: URL, + in _: NSRange, + interaction _: UITextItemInteraction + ) -> Bool { UIApplication.shared.open(URL, options: [:]) return false } @@ -121,16 +122,20 @@ extension AboutViewController { let attrString = NSMutableAttributedString(string: text) let range = NSString(string: attrString.string).range(of: attrString.string) - attrString.addAttribute(NSAttributedString.Key.font, - value: UIFont.Muli(.regular, size: 16), - range: range) + attrString.addAttribute( + NSAttributedString.Key.font, + value: UIFont.Muli(.regular, size: 16), + range: range + ) // make headers bold - let makeBold = [RuuviLocalization.About.OperationsManual.header, - RuuviLocalization.About.Troubleshooting.header, - RuuviLocalization.About.OpenSource.header, - RuuviLocalization.About.More.header, - RuuviLocalization.About.Privacy.header] + let makeBold = [ + RuuviLocalization.About.OperationsManual.header, + RuuviLocalization.About.Troubleshooting.header, + RuuviLocalization.About.OpenSource.header, + RuuviLocalization.About.More.header, + RuuviLocalization.About.Privacy.header, + ] let boldFont = UIFont.Muli(.bold, size: 16) for bold in makeBold { let range = NSString(string: attrString.string).range(of: bold) @@ -139,15 +144,19 @@ extension AboutViewController { // reduce the linespacing below the titles let smallFont = UIFont.Muli(.regular, size: 8) for range in attrString.string.ranges(of: "\n") { - attrString.addAttribute(NSAttributedString.Key.font, - value: smallFont, - range: NSRange(range, in: attrString.string)) + attrString.addAttribute( + NSAttributedString.Key.font, + value: smallFont, + range: NSRange(range, in: attrString.string) + ) } // make text color white - attrString.addAttribute(.foregroundColor, - value: RuuviColor.ruuviTextColor ?? UIColor.label, - range: NSRange(location: 0, length: attrString.length)) + attrString.addAttribute( + .foregroundColor, + value: RuuviColor.ruuviTextColor ?? UIColor.label, + range: NSRange(location: 0, length: attrString.length) + ) aboutTextView.attributedText = attrString aboutTextView.textColor = RuuviColor.ruuviTextColor @@ -172,11 +181,12 @@ private extension String { func ranges(of substring: String, options: CompareOptions = [], locale: Locale? = nil) -> [Range] { var ranges: [Range] = [] while ranges.last.map({ $0.upperBound < self.endIndex }) ?? true, - let range = range(of: substring, - options: options, - range: (ranges.last?.upperBound ?? startIndex) ..< endIndex, - locale: locale) - { + let range = range( + of: substring, + options: options, + range: (ranges.last?.upperBound ?? startIndex) ..< endIndex, + locale: locale + ) { ranges.append(range) } return ranges diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift index 03deb696d..d65c60f15 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift @@ -85,76 +85,78 @@ extension BackgroundSelectionPresenter { private func startSubscribeToBackgroundUploadProgressChanges() { backgroundUploadProgressToken = NotificationCenter .default - .addObserver(forName: .BackgroundPersistenceDidUpdateBackgroundUploadProgress, - object: nil, - queue: .main) - { [weak self] notification in - guard let sSelf = self else { return } - if let userInfo = notification.userInfo, let ruuviTag = sSelf.ruuviTag { - let luid = userInfo[BPDidUpdateBackgroundUploadProgressKey.luid] as? LocalIdentifier - let macId = userInfo[BPDidUpdateBackgroundUploadProgressKey.macId] as? MACIdentifier - if (ruuviTag.luid?.value != nil && ruuviTag.luid?.value == luid?.value) - || (ruuviTag.macId?.value != nil && ruuviTag.macId?.value == macId?.value) - { - if let percentage = userInfo[BPDidUpdateBackgroundUploadProgressKey.progress] as? Double { - sSelf.viewModel.uploadingBackgroundPercentage.value = percentage - sSelf.viewModel.isUploadingBackground.value = percentage < 1.0 - if percentage == 1.0 { - if let weakView = sSelf.weakView as? BackgroundSelectionViewController { - weakView.viewShouldDismiss() + .addObserver( + forName: .BackgroundPersistenceDidUpdateBackgroundUploadProgress, + object: nil, + queue: .main + ) { [weak self] notification in + guard let sSelf = self else { return } + if let userInfo = notification.userInfo, let ruuviTag = sSelf.ruuviTag { + let luid = userInfo[BPDidUpdateBackgroundUploadProgressKey.luid] as? LocalIdentifier + let macId = userInfo[BPDidUpdateBackgroundUploadProgressKey.macId] as? MACIdentifier + if (ruuviTag.luid?.value != nil && ruuviTag.luid?.value == luid?.value) + || (ruuviTag.macId?.value != nil && ruuviTag.macId?.value == macId?.value) { + if let percentage = userInfo[BPDidUpdateBackgroundUploadProgressKey.progress] as? Double { + sSelf.viewModel.uploadingBackgroundPercentage.value = percentage + sSelf.viewModel.isUploadingBackground.value = percentage < 1.0 + if percentage == 1.0 { + if let weakView = sSelf.weakView as? BackgroundSelectionViewController { + weakView.viewShouldDismiss() + } } + } else { + sSelf.viewModel.uploadingBackgroundPercentage.value = nil + sSelf.viewModel.isUploadingBackground.value = false } - } else { - sSelf.viewModel.uploadingBackgroundPercentage.value = nil - sSelf.viewModel.isUploadingBackground.value = false } } } - } backgroundToken = NotificationCenter .default - .addObserver(forName: .BackgroundPersistenceDidChangeBackground, - object: nil, - queue: .main) - { [weak self] notification in - - guard let sSelf = self else { return } - if let userInfo = notification.userInfo, let ruuviTag = sSelf.ruuviTag { - let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier - let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier - if (ruuviTag.luid?.value != nil && ruuviTag.luid?.value == luid?.value) - || (ruuviTag.macId?.value != nil && ruuviTag.macId?.value == macId?.value) - { - sSelf.ruuviSensorPropertiesService.getImage(for: ruuviTag) - .on(success: { [weak sSelf] image in - guard let sSelf else { return } - sSelf.viewModel.background.value = image - var isLocalSensor: Bool = true - if let isCloudSensor = sSelf.ruuviTag?.isCloudSensor { - isLocalSensor = !isCloudSensor - } + .addObserver( + forName: .BackgroundPersistenceDidChangeBackground, + object: nil, + queue: .main + ) { [weak self] notification in + + guard let sSelf = self else { return } + if let userInfo = notification.userInfo, let ruuviTag = sSelf.ruuviTag { + let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier + let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier + if (ruuviTag.luid?.value != nil && ruuviTag.luid?.value == luid?.value) + || (ruuviTag.macId?.value != nil && ruuviTag.macId?.value == macId?.value) { + sSelf.ruuviSensorPropertiesService.getImage(for: ruuviTag) + .on(success: { [weak sSelf] image in + guard let sSelf else { return } + sSelf.viewModel.background.value = image + var isLocalSensor: Bool = true + if let isCloudSensor = sSelf.ruuviTag?.isCloudSensor { + isLocalSensor = !isCloudSensor + } - if isLocalSensor, !sSelf.didUploadBackground { - sSelf.didUploadBackground = true - if let weakView = sSelf.weakView as? BackgroundSelectionViewController { - weakView.viewShouldDismiss() + if isLocalSensor, !sSelf.didUploadBackground { + sSelf.didUploadBackground = true + if let weakView = sSelf.weakView as? BackgroundSelectionViewController { + weakView.viewShouldDismiss() + } } - } - }, failure: { [weak sSelf] error in - sSelf?.errorPresenter.present(error: error) - }) + }, failure: { [weak sSelf] error in + sSelf?.errorPresenter.present(error: error) + }) + } } } - } } private func prepareDefaultImages() { var defaultImages: [DefaultBackgroundModel] = [] for i in (1 ... 16).reversed() { let image = UIImage(named: "bg\(i)") - let model = DefaultBackgroundModel(id: i, - image: image, - thumbnail: image.resize()) + let model = DefaultBackgroundModel( + id: i, + image: image, + thumbnail: image.resize() + ) defaultImages.append(model) } viewModel.defaultImages.value = defaultImages diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift index 0b27a9481..9843f9aac 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift @@ -31,10 +31,11 @@ class BackgroundSelectionButtonView: UIView { super.init(frame: frame) } - convenience init(title: String, - icon: String, - delegate: BackgroundSelectionButtonViewDelegate? = nil) - { + convenience init( + title: String, + icon: String, + delegate: BackgroundSelectionButtonViewDelegate? = nil + ) { self.init() titleLabel.text = title buttonIcon.image = UIImage(systemName: icon) @@ -53,33 +54,43 @@ private extension BackgroundSelectionButtonView { backgroundColor = .clear addSubview(titleLabel) - titleLabel.anchor(top: topAnchor, - leading: safeLeftAnchor, - bottom: bottomAnchor, - trailing: nil, - padding: .init(top: 8, - left: 0, - bottom: 8, - right: 0)) + titleLabel.anchor( + top: topAnchor, + leading: safeLeftAnchor, + bottom: bottomAnchor, + trailing: nil, + padding: .init( + top: 8, + left: 0, + bottom: 8, + right: 0 + ) + ) addSubview(buttonIcon) - buttonIcon.anchor(top: nil, - leading: titleLabel.trailingAnchor, - bottom: nil, - trailing: safeRightAnchor, - padding: .init(top: 0, - left: 8, - bottom: 8, - right: 0), - size: .init(width: 24, height: 24)) + buttonIcon.anchor( + top: nil, + leading: titleLabel.trailingAnchor, + bottom: nil, + trailing: safeRightAnchor, + padding: .init( + top: 0, + left: 8, + bottom: 8, + right: 0 + ), + size: .init(width: 24, height: 24) + ) buttonIcon.centerYInSuperview() addSubview(seprator) - seprator.anchor(top: nil, - leading: leadingAnchor, - bottom: bottomAnchor, - trailing: trailingAnchor, - size: .init(width: 0, height: 1)) + seprator.anchor( + top: nil, + leading: leadingAnchor, + bottom: bottomAnchor, + trailing: trailingAnchor, + size: .init(width: 0, height: 1) + ) isUserInteractionEnabled = true let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap)) diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift index b0f8bda0d..2aae72c97 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift @@ -47,25 +47,33 @@ private extension BackgroundSelectionUploadProgressView { clipsToBounds = true addSubview(progressLabel) - progressLabel.anchor(top: topAnchor, - leading: safeLeftAnchor, - bottom: bottomAnchor, - trailing: nil, - padding: .init(top: 8, - left: 8, - bottom: 8, - right: 0)) + progressLabel.anchor( + top: topAnchor, + leading: safeLeftAnchor, + bottom: bottomAnchor, + trailing: nil, + padding: .init( + top: 8, + left: 8, + bottom: 8, + right: 0 + ) + ) addSubview(cancelButton) - cancelButton.anchor(top: nil, - leading: progressLabel.trailingAnchor, - bottom: nil, - trailing: safeRightAnchor, - padding: .init(top: 0, - left: 24, - bottom: 8, - right: 8), - size: .init(width: 24, height: 24)) + cancelButton.anchor( + top: nil, + leading: progressLabel.trailingAnchor, + bottom: nil, + trailing: safeRightAnchor, + padding: .init( + top: 0, + left: 24, + bottom: 8, + right: 8 + ), + size: .init(width: 24, height: 24) + ) cancelButton.centerYInSuperview() } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift index e8731fab9..43907f7f4 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift @@ -24,8 +24,10 @@ class BackgroundSelectionViewController: UIViewController { }() private lazy var collectionView: UICollectionView = { - let cv = UICollectionView(frame: .zero, - collectionViewLayout: createLayout()) + let cv = UICollectionView( + frame: .zero, + collectionViewLayout: createLayout() + ) cv.backgroundColor = .clear cv.showsVerticalScrollIndicator = false cv.delegate = self @@ -85,91 +87,119 @@ private extension BackgroundSelectionViewController { let leftBarButtonView = UIView(color: .clear) leftBarButtonView.addSubview(backButton) - backButton.anchor(top: leftBarButtonView.topAnchor, - leading: leftBarButtonView.leadingAnchor, - bottom: leftBarButtonView.bottomAnchor, - trailing: leftBarButtonView.trailingAnchor, - padding: .init(top: 0, left: -12, bottom: 0, right: 0), - size: .init(width: 40, height: 40)) + backButton.anchor( + top: leftBarButtonView.topAnchor, + leading: leftBarButtonView.leadingAnchor, + bottom: leftBarButtonView.bottomAnchor, + trailing: leftBarButtonView.trailingAnchor, + padding: .init(top: 0, left: -12, bottom: 0, right: 0), + size: .init(width: 40, height: 40) + ) navigationItem.leftBarButtonItem = UIBarButtonItem(customView: leftBarButtonView) } func setUpContentView() { view.addSubview(collectionView) - collectionView.anchor(top: view.safeTopAnchor, - leading: view.safeLeftAnchor, - bottom: view.bottomAnchor, - trailing: view.safeRightAnchor, - padding: .init(top: 0, - left: 12, - bottom: 0, - right: 12)) + collectionView.anchor( + top: view.safeTopAnchor, + leading: view.safeLeftAnchor, + bottom: view.bottomAnchor, + trailing: view.safeRightAnchor, + padding: .init( + top: 0, + left: 12, + bottom: 0, + right: 12 + ) + ) collectionView.dataSource = self - collectionView.register(BackgroundSelectionViewCell.self, - forCellWithReuseIdentifier: cvCellIdentifier) - collectionView.register(BackgroundSelectionViewHeader.self, - forSupplementaryViewOfKind: sectionHeaderKind, - withReuseIdentifier: sectionHeaderIdentifier) + collectionView.register( + BackgroundSelectionViewCell.self, + forCellWithReuseIdentifier: cvCellIdentifier + ) + collectionView.register( + BackgroundSelectionViewHeader.self, + forSupplementaryViewOfKind: sectionHeaderKind, + withReuseIdentifier: sectionHeaderIdentifier + ) } func setUpUploadProgressView() { view.addSubview(uploadProgressView) - uploadProgressView.anchor(top: nil, - leading: nil, - bottom: view.safeBottomAnchor, - trailing: nil, - padding: .init(top: 0, left: 0, bottom: 8, right: 0), - size: .init(width: 0, height: 44)) + uploadProgressView.anchor( + top: nil, + leading: nil, + bottom: view.safeBottomAnchor, + trailing: nil, + padding: .init(top: 0, left: 0, bottom: 8, right: 0), + size: .init(width: 0, height: 44) + ) uploadProgressView.centerXInSuperview() uploadProgressView.delegate = self uploadProgressView.isHidden = true } func createLayout() -> UICollectionViewLayout { - let sectionProvider = { [weak self] (_: Int, - _: NSCollectionLayoutEnvironment) - -> NSCollectionLayoutSection? in - guard let sSelf = self else { return nil } - - let widthMultiplier = sSelf.itemWidthMultiplier() - let itemEstimatedHeight: CGFloat = sSelf.itemEstimatedHeight() - - let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(widthMultiplier), - heightDimension: .absolute(itemEstimatedHeight)) - let item = NSCollectionLayoutItem(layoutSize: itemSize) - item.contentInsets = NSDirectionalEdgeInsets(top: 0, - leading: sSelf.itemHorizontalSpacing, - bottom: 0, - trailing: sSelf.itemHorizontalSpacing) - - let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), - heightDimension: .absolute(itemEstimatedHeight)) - let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) - - let section = NSCollectionLayoutSection(group: group) - section.interGroupSpacing = sSelf.itemGroupSpacing - section.contentInsets = NSDirectionalEdgeInsets(top: sSelf.sectionTopPadding, - leading: 0, - bottom: sSelf.sectionBottomPadding, - trailing: 0) - return section + let sectionProvider = { [weak self] ( + _: Int, + _: NSCollectionLayoutEnvironment + ) + -> NSCollectionLayoutSection? in + guard let sSelf = self else { return nil } + + let widthMultiplier = sSelf.itemWidthMultiplier() + let itemEstimatedHeight: CGFloat = sSelf.itemEstimatedHeight() + + let itemSize = NSCollectionLayoutSize( + widthDimension: .fractionalWidth(widthMultiplier), + heightDimension: .absolute(itemEstimatedHeight) + ) + let item = NSCollectionLayoutItem(layoutSize: itemSize) + item.contentInsets = NSDirectionalEdgeInsets( + top: 0, + leading: sSelf.itemHorizontalSpacing, + bottom: 0, + trailing: sSelf.itemHorizontalSpacing + ) + + let groupSize = NSCollectionLayoutSize( + widthDimension: .fractionalWidth(1.0), + heightDimension: .absolute(itemEstimatedHeight) + ) + let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) + + let section = NSCollectionLayoutSection(group: group) + section.interGroupSpacing = sSelf.itemGroupSpacing + section.contentInsets = NSDirectionalEdgeInsets( + top: sSelf.sectionTopPadding, + leading: 0, + bottom: sSelf.sectionBottomPadding, + trailing: 0 + ) + return section } // Header - let globalHeaderSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), - heightDimension: .estimated(1)) - let globalHeader = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: globalHeaderSize, - elementKind: sectionHeaderKind, - alignment: .top) + let globalHeaderSize = NSCollectionLayoutSize( + widthDimension: .fractionalWidth(1), + heightDimension: .estimated(1) + ) + let globalHeader = NSCollectionLayoutBoundarySupplementaryItem( + layoutSize: globalHeaderSize, + elementKind: sectionHeaderKind, + alignment: .top + ) globalHeader.pinToVisibleBounds = false let config = UICollectionViewCompositionalLayoutConfiguration() config.scrollDirection = .vertical config.boundarySupplementaryItems = [globalHeader] - let layout = UICollectionViewCompositionalLayout(sectionProvider: sectionProvider, - configuration: config) + let layout = UICollectionViewCompositionalLayout( + sectionProvider: sectionProvider, + configuration: config + ) return layout } @@ -229,13 +259,15 @@ extension BackgroundSelectionViewController: UICollectionViewDataSource { viewModel?.defaultImages.value?.count ?? 0 } - func collectionView(_ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath) -> UICollectionViewCell - { + func collectionView( + _ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath + ) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell( withReuseIdentifier: cvCellIdentifier, for: indexPath - ) as? BackgroundSelectionViewCell else { + ) as? BackgroundSelectionViewCell + else { fatalError() } @@ -246,21 +278,26 @@ extension BackgroundSelectionViewController: UICollectionViewDataSource { } extension BackgroundSelectionViewController: UICollectionViewDelegate { - func collectionView(_: UICollectionView, - didSelectItemAt indexPath: IndexPath) - { + func collectionView( + _: UICollectionView, + didSelectItemAt indexPath: IndexPath + ) { if let model = viewModel?.defaultImages.value?[indexPath.item] { output.viewDidSelectDefaultPhoto(model: model) } } - func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind _: String, - at indexPath: IndexPath) -> UICollectionReusableView - { + func collectionView( + _ collectionView: UICollectionView, + viewForSupplementaryElementOfKind _: String, + at indexPath: IndexPath + ) -> UICollectionReusableView { guard let headerView = collectionView - .dequeueReusableSupplementaryView(ofKind: sectionHeaderKind, - withReuseIdentifier: sectionHeaderIdentifier, - for: indexPath) as? BackgroundSelectionViewHeader + .dequeueReusableSupplementaryView( + ofKind: sectionHeaderKind, + withReuseIdentifier: sectionHeaderIdentifier, + for: indexPath + ) as? BackgroundSelectionViewHeader else { fatalError() } diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift index f0b2ce740..626e872c8 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift @@ -61,43 +61,55 @@ private extension BackgroundSelectionViewHeader { backgroundColor = .clear addSubview(descriptionLabel) - descriptionLabel.anchor(top: safeTopAnchor, - leading: safeLeftAnchor, - bottom: nil, - trailing: safeRightAnchor, - padding: .init(top: 8, - left: 4, - bottom: 0, - right: 4)) + descriptionLabel.anchor( + top: safeTopAnchor, + leading: safeLeftAnchor, + bottom: nil, + trailing: safeRightAnchor, + padding: .init( + top: 8, + left: 4, + bottom: 0, + right: 4 + ) + ) addSubview(seprator) - seprator.anchor(top: descriptionLabel.bottomAnchor, - leading: descriptionLabel.leadingAnchor, - bottom: nil, - trailing: descriptionLabel.trailingAnchor, - padding: .init(top: 12, left: 0, bottom: 0, right: 0), - size: .init(width: 0, height: 1)) + seprator.anchor( + top: descriptionLabel.bottomAnchor, + leading: descriptionLabel.leadingAnchor, + bottom: nil, + trailing: descriptionLabel.trailingAnchor, + padding: .init(top: 12, left: 0, bottom: 0, right: 0), + size: .init(width: 0, height: 1) + ) addSubview(takePhotoButton) - takePhotoButton.anchor(top: seprator.bottomAnchor, - leading: seprator.leadingAnchor, - bottom: nil, - trailing: seprator.trailingAnchor, - size: .init(width: 0, height: 44)) + takePhotoButton.anchor( + top: seprator.bottomAnchor, + leading: seprator.leadingAnchor, + bottom: nil, + trailing: seprator.trailingAnchor, + size: .init(width: 0, height: 44) + ) addSubview(selectFromGalleryButton) - selectFromGalleryButton.anchor(top: takePhotoButton.bottomAnchor, - leading: seprator.leadingAnchor, - bottom: nil, - trailing: seprator.trailingAnchor, - size: .init(width: 0, height: 44)) + selectFromGalleryButton.anchor( + top: takePhotoButton.bottomAnchor, + leading: seprator.leadingAnchor, + bottom: nil, + trailing: seprator.trailingAnchor, + size: .init(width: 0, height: 44) + ) addSubview(selectFromDefaultLabel) - selectFromDefaultLabel.anchor(top: selectFromGalleryButton.bottomAnchor, - leading: seprator.leadingAnchor, - bottom: safeBottomAnchor, - trailing: seprator.trailingAnchor, - size: .init(width: 0, height: 44)) + selectFromDefaultLabel.anchor( + top: selectFromGalleryButton.bottomAnchor, + leading: seprator.leadingAnchor, + bottom: safeBottomAnchor, + trailing: seprator.trailingAnchor, + size: .init(width: 0, height: 44) + ) } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractor.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractor.swift index f501b74ec..e10a9515b 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractor.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractor.swift @@ -12,9 +12,10 @@ class CardsInteractor { } extension CardsInteractor: CardsInteractorInput { - func checkAndUpdateFirmwareVersion(for ruuviTag: RuuviTagSensor, - settings _: RuuviLocalSettings) - { + func checkAndUpdateFirmwareVersion( + for ruuviTag: RuuviTagSensor, + settings _: RuuviLocalSettings + ) { guard let luid = ruuviTag.luid, ruuviTag.firmwareVersion == nil || !ruuviTag.firmwareVersion.hasText() diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractorInput.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractorInput.swift index f4fc637cd..288e7fe3d 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractorInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractorInput.swift @@ -4,6 +4,8 @@ import RuuviLocal import RuuviOntology protocol CardsInteractorInput: AnyObject { - func checkAndUpdateFirmwareVersion(for ruuviTag: RuuviTagSensor, - settings: RuuviLocalSettings) + func checkAndUpdateFirmwareVersion( + for ruuviTag: RuuviTagSensor, + settings: RuuviLocalSettings + ) } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleInput.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleInput.swift index 95ec86d4f..88996abbc 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleInput.swift @@ -2,11 +2,15 @@ import Foundation import RuuviOntology protocol CardsModuleInput: AnyObject { - func configure(viewModels: [CardsViewModel], - ruuviTagSensors: [AnyRuuviTagSensor], - sensorSettings: [SensorSettings]) - func configure(scrollTo: CardsViewModel?, - openChart: Bool) + func configure( + viewModels: [CardsViewModel], + ruuviTagSensors: [AnyRuuviTagSensor], + sensorSettings: [SensorSettings] + ) + func configure( + scrollTo: CardsViewModel?, + openChart: Bool + ) func configure(output: CardsModuleOutput) func dismiss(completion: (() -> Void)?) } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift index 9f7035c44..6b8f85731 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift @@ -116,12 +116,15 @@ extension CardsPresenter: CardsModuleInput { self.output = output } - func configure(scrollTo: CardsViewModel?, - openChart: Bool) - { - updateVisibleCard(from: scrollTo, - openChart: openChart, - triggerScroll: true) + func configure( + scrollTo: CardsViewModel?, + openChart: Bool + ) { + updateVisibleCard( + from: scrollTo, + openChart: openChart, + triggerScroll: true + ) } } @@ -143,20 +146,23 @@ extension CardsPresenter { private func startObservingAppState() { NotificationCenter .default - .addObserver(self, - selector: #selector(handleAppEnterForgroundState), - name: UIApplication.willEnterForegroundNotification, - object: nil) + .addObserver( + self, + selector: #selector(handleAppEnterForgroundState), + name: UIApplication.willEnterForegroundNotification, + object: nil + ) } @objc private func handleAppEnterForgroundState() { view?.scroll(to: visibleViewModelIndex) } - private func updateVisibleCard(from viewModel: CardsViewModel?, - openChart: Bool = false, - triggerScroll: Bool = false) - { + private func updateVisibleCard( + from viewModel: CardsViewModel?, + openChart: Bool = false, + triggerScroll: Bool = false + ) { if let index = viewModels.firstIndex(where: { ($0.luid.value != nil && $0.luid.value == viewModel?.luid.value) || ($0.mac.value != nil && $0.mac.value == viewModel?.mac.value) @@ -188,8 +194,10 @@ extension CardsPresenter { ($0.luid.value != nil && $0.luid.value == sensor.luid?.any) || ($0.mac.value != nil && $0.mac.value == sensor.macId?.any) }) { - sSelf.updateVisibleCard(from: viewModel, - triggerScroll: true) + sSelf.updateVisibleCard( + from: viewModel, + triggerScroll: true + ) sSelf.view?.scroll(to: sSelf.visibleViewModelIndex) } case let .update(sensor): @@ -199,16 +207,17 @@ extension CardsPresenter { where: { ($0.macId != nil && $0.macId?.any == sensor.macId?.any) || ($0.luid != nil && $0.luid?.any == sensor.luid?.any) - }) - { + }) { sSelf.ruuviTags[index] = sensor sSelf.syncViewModels() if let viewModel = sSelf.viewModels.first(where: { ($0.luid.value != nil && $0.luid.value == sensor.luid?.any) || ($0.mac.value != nil && $0.mac.value == sensor.macId?.any) }) { - sSelf.updateVisibleCard(from: viewModel, - triggerScroll: true) + sSelf.updateVisibleCard( + from: viewModel, + triggerScroll: true + ) sSelf.view?.scroll(to: sSelf.visibleViewModelIndex) } } @@ -218,7 +227,8 @@ extension CardsPresenter { sSelf.syncViewModels() // If a sensor is deleted, and there's no more sensor take // user to dashboard. - guard sSelf.viewModels.count > 0 else { + guard sSelf.viewModels.count > 0 + else { sSelf.viewShouldDismiss() return } @@ -243,17 +253,15 @@ extension CardsPresenter { ruuviTagObserveLastRecordTokens.removeAll() for viewModel in viewModels { if viewModel.type == .ruuvi, - let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) - { + let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) { let token = ruuviReactor.observeLatest(ruuviTagSensor) { [weak self] changes in if case let .update(anyRecord) = changes, let viewModel = self?.viewModels - .first(where: { - ($0.luid.value != nil && ($0.luid.value == anyRecord?.luid?.any)) - || ($0.mac.value != nil && ($0.mac.value == anyRecord?.macId?.any)) - }), - let record = anyRecord - { + .first(where: { + ($0.luid.value != nil && ($0.luid.value == anyRecord?.luid?.any)) + || ($0.mac.value != nil && ($0.mac.value == anyRecord?.macId?.any)) + }), + let record = anyRecord { let sensorSettings = self?.sensorSettings .first(where: { ($0.luid?.any != nil && $0.luid?.any == viewModel.luid.value) @@ -292,36 +300,41 @@ extension CardsPresenter { alertDidChangeToken?.invalidate() alertDidChangeToken = NotificationCenter .default - .addObserver(forName: .RuuviServiceAlertDidChange, - object: nil, - queue: .main, - using: { [weak self] notification in - guard let sSelf = self else { return } - if let userInfo = notification.userInfo { - if let physicalSensor - = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor, - let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType - { - sSelf.viewModels.filter { - ($0.luid.value != nil && ($0.luid.value == physicalSensor.luid?.any)) - || ($0.mac.value != nil && ($0.mac.value == physicalSensor.macId?.any)) - }.forEach { viewModel in - if sSelf.alertService.hasRegistrations(for: physicalSensor) { - viewModel.alertState.value = .registered - } else { - viewModel.alertState.value = .empty - } - sSelf.updateIsOnState(of: type, - for: physicalSensor.id, - viewModel: viewModel) - sSelf.updateMutedTill(of: type, - for: physicalSensor.id, - viewModel: viewModel) - self?.notifyUpdate(for: viewModel) - } - } - } - }) + .addObserver( + forName: .RuuviServiceAlertDidChange, + object: nil, + queue: .main, + using: { [weak self] notification in + guard let sSelf = self else { return } + if let userInfo = notification.userInfo { + if let physicalSensor + = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor, + let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType { + sSelf.viewModels.filter { + ($0.luid.value != nil && ($0.luid.value == physicalSensor.luid?.any)) + || ($0.mac.value != nil && ($0.mac.value == physicalSensor.macId?.any)) + }.forEach { viewModel in + if sSelf.alertService.hasRegistrations(for: physicalSensor) { + viewModel.alertState.value = .registered + } else { + viewModel.alertState.value = .empty + } + sSelf.updateIsOnState( + of: type, + for: physicalSensor.id, + viewModel: viewModel + ) + sSelf.updateMutedTill( + of: type, + for: physicalSensor.id, + viewModel: viewModel + ) + self?.notifyUpdate(for: viewModel) + } + } + } + } + ) } private func startMutedTillTimer() { @@ -347,35 +360,44 @@ extension CardsPresenter { continue } if viewModel.type == .ruuvi, - let luid = viewModel.luid.value - { - advertisementTokens.append(foreground.observe(self, - uuid: luid.value, - closure: { [weak self] _, device in - if let tag = device.ruuvi?.tag { - self?.handleMeasurementPoint(tag: tag, - source: .advertisement) - } - })) - - heartbeatTokens.append(background.observe(self, - uuid: luid.value, - closure: { [weak self] _, device in - if let tag = device.ruuvi?.tag { - self?.handleMeasurementPoint(tag: tag, - source: .heartbeat) - } - })) + let luid = viewModel.luid.value { + advertisementTokens.append(foreground.observe( + self, + uuid: luid.value, + closure: { [weak self] _, device in + if let tag = device.ruuvi?.tag { + self?.handleMeasurementPoint( + tag: tag, + source: .advertisement + ) + } + } + )) + + heartbeatTokens.append(background.observe( + self, + uuid: luid.value, + closure: { [weak self] _, device in + if let tag = device.ruuvi?.tag { + self?.handleMeasurementPoint( + tag: tag, + source: .heartbeat + ) + } + } + )) } } } - private func handleMeasurementPoint(tag: RuuviTag, - source: RuuviTagSensorRecordSource) - { + private func handleMeasurementPoint( + tag: RuuviTag, + source: RuuviTagSensorRecordSource + ) { guard let viewModel = viewModels.first( where: { $0.luid.value == tag.uuid.luid.any } - ) else { + ) + else { return } let sensorSettings = sensorSettings @@ -399,8 +421,7 @@ extension CardsPresenter { sensorSettingsTokens.removeAll() for viewModel in viewModels { if viewModel.type == .ruuvi, - let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) - { + let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) { sensorSettingsTokens.append( ruuviReactor.observe(ruuviTagSensor) { [weak self] change in guard let sSelf = self else { return } @@ -458,7 +479,8 @@ extension CardsPresenter { ) { let currentRecord = viewModel.latestMeasurement.value let updatedRecord = currentRecord?.with(sensorSettings: sensorSettings) - guard let updatedRecord else { + guard let updatedRecord + else { return } viewModel.update(updatedRecord) @@ -482,37 +504,38 @@ extension CardsPresenter { backgroundToken?.invalidate() backgroundToken = NotificationCenter .default - .addObserver(forName: .BackgroundPersistenceDidChangeBackground, - object: nil, - queue: .main) - { [weak self] notification in + .addObserver( + forName: .BackgroundPersistenceDidChangeBackground, + object: nil, + queue: .main + ) { [weak self] notification in - guard let sSelf = self else { return } - if let userInfo = notification.userInfo { - let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier - let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier - - let viewModel = sSelf.view?.viewModels - .first(where: { $0.luid.value != nil && $0.luid.value == luid?.any }) - ?? sSelf.view?.viewModels - .first(where: { $0.mac.value != nil && $0.mac.value == macId?.any }) - if let viewModel { - let ruuviTag = sSelf.ruuviTags - .first(where: { $0.luid != nil && $0.luid?.any == luid?.any }) - ?? sSelf.ruuviTags - .first(where: { $0.macId != nil && $0.macId?.any == macId?.any }) - if let ruuviTag { - sSelf.ruuviSensorPropertiesService.getImage(for: ruuviTag) - .on(success: { image in - viewModel.background.value = image - self?.view?.changeCardBackground(of: viewModel, to: image) - }, failure: { [weak self] error in - self?.errorPresenter.present(error: error) - }) + guard let sSelf = self else { return } + if let userInfo = notification.userInfo { + let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier + let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier + + let viewModel = sSelf.view?.viewModels + .first(where: { $0.luid.value != nil && $0.luid.value == luid?.any }) + ?? sSelf.view?.viewModels + .first(where: { $0.mac.value != nil && $0.mac.value == macId?.any }) + if let viewModel { + let ruuviTag = sSelf.ruuviTags + .first(where: { $0.luid != nil && $0.luid?.any == luid?.any }) + ?? sSelf.ruuviTags + .first(where: { $0.macId != nil && $0.macId?.any == macId?.any }) + if let ruuviTag { + sSelf.ruuviSensorPropertiesService.getImage(for: ruuviTag) + .on(success: { image in + viewModel.background.value = image + self?.view?.changeCardBackground(of: viewModel, to: image) + }, failure: { [weak self] error in + self?.errorPresenter.present(error: error) + }) + } } } } - } } // swiftlint:disable:next cyclomatic_complexity function_body_length @@ -520,100 +543,108 @@ extension CardsPresenter { ruuviTagAdvertisementDaemonFailureToken?.invalidate() ruuviTagAdvertisementDaemonFailureToken = NotificationCenter .default - .addObserver(forName: .RuuviTagAdvertisementDaemonDidFail, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let error = userInfo[RuuviTagAdvertisementDaemonDidFailKey.error] as? RUError - { - self?.errorPresenter.present(error: error) - } - }) + .addObserver( + forName: .RuuviTagAdvertisementDaemonDidFail, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let error = userInfo[RuuviTagAdvertisementDaemonDidFailKey.error] as? RUError { + self?.errorPresenter.present(error: error) + } + } + ) ruuviTagPropertiesDaemonFailureToken?.invalidate() ruuviTagPropertiesDaemonFailureToken = NotificationCenter .default - .addObserver(forName: .RuuviTagPropertiesDaemonDidFail, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let error = userInfo[RuuviTagPropertiesDaemonDidFailKey.error] as? RUError - { - self?.errorPresenter.present(error: error) - } - }) + .addObserver( + forName: .RuuviTagPropertiesDaemonDidFail, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let error = userInfo[RuuviTagPropertiesDaemonDidFailKey.error] as? RUError { + self?.errorPresenter.present(error: error) + } + } + ) ruuviTagHeartbeatDaemonFailureToken?.invalidate() ruuviTagHeartbeatDaemonFailureToken = NotificationCenter .default - .addObserver(forName: .RuuviTagHeartbeatDaemonDidFail, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let error = userInfo[RuuviTagHeartbeatDaemonDidFailKey.error] as? RUError - { - self?.errorPresenter.present(error: error) - } - }) + .addObserver( + forName: .RuuviTagHeartbeatDaemonDidFail, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let error = userInfo[RuuviTagHeartbeatDaemonDidFailKey.error] as? RUError { + self?.errorPresenter.present(error: error) + } + } + ) ruuviTagReadLogsOperationFailureToken?.invalidate() ruuviTagReadLogsOperationFailureToken = NotificationCenter .default - .addObserver(forName: .RuuviTagReadLogsOperationDidFail, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let error = userInfo[RuuviTagReadLogsOperationDidFailKey.error] as? RUError - { - self?.errorPresenter.present(error: error) - } - }) + .addObserver( + forName: .RuuviTagReadLogsOperationDidFail, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let error = userInfo[RuuviTagReadLogsOperationDidFailKey.error] as? RUError { + self?.errorPresenter.present(error: error) + } + } + ) } func startObservingDidConnectDisconnectNotifications() { didConnectToken?.invalidate() didConnectToken = NotificationCenter .default - .addObserver(forName: .BTBackgroundDidConnect, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let uuid = userInfo[BTBackgroundDidConnectKey.uuid] as? String, - let viewModel = self?.viewModels.first(where: { $0.luid.value == uuid.luid.any }) - { - viewModel.isConnected.value = true - self?.notifyUpdate(for: viewModel) - } - }) + .addObserver( + forName: .BTBackgroundDidConnect, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let uuid = userInfo[BTBackgroundDidConnectKey.uuid] as? String, + let viewModel = self?.viewModels.first(where: { $0.luid.value == uuid.luid.any }) { + viewModel.isConnected.value = true + self?.notifyUpdate(for: viewModel) + } + } + ) didDisconnectToken?.invalidate() didDisconnectToken = NotificationCenter .default - .addObserver(forName: .BTBackgroundDidDisconnect, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let uuid = userInfo[BTBackgroundDidDisconnectKey.uuid] as? String, - let viewModel = self?.viewModels.first(where: { $0.luid.value == uuid.luid.any }) - { - viewModel.isConnected.value = false - self?.notifyUpdate(for: viewModel) - } - }) + .addObserver( + forName: .BTBackgroundDidDisconnect, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let uuid = userInfo[BTBackgroundDidDisconnectKey.uuid] as? String, + let viewModel = self?.viewModels.first(where: { $0.luid.value == uuid.luid.any }) { + viewModel.isConnected.value = false + self?.notifyUpdate(for: viewModel) + } + } + ) } private func startObservingCloudModeNotification() { cloudModeToken?.invalidate() cloudModeToken = NotificationCenter .default - .addObserver(forName: .CloudModeDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.handleCloudModeState() - }) + .addObserver( + forName: .CloudModeDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.handleCloudModeState() + } + ) } /// The method handles all the operations when cloud mode toggle is turned on/off @@ -668,7 +699,8 @@ extension CardsPresenter { viewModels = reorder(ruuviViewModels) - guard viewModels.count > 0 else { + guard viewModels.count > 0 + else { output?.cardsViewDidDismiss(module: self) return } @@ -717,20 +749,23 @@ extension CardsPresenter { viewDidTriggerShowChart(for: viewModel) } - private func processAlert(record: RuuviTagSensorRecord, - viewModel: CardsViewModel) - { + private func processAlert( + record: RuuviTagSensorRecord, + viewModel: CardsViewModel + ) { if let isCloud = viewModel.isCloud.value, isCloud, - let macId = viewModel.mac.value - { - alertHandler.processNetwork(record: record, - trigger: false, - for: macId) + let macId = viewModel.mac.value { + alertHandler.processNetwork( + record: record, + trigger: false, + for: macId + ) } else { if viewModel.luid.value != nil { alertHandler.process(record: record, trigger: false) } else { - guard let macId = viewModel.mac.value else { + guard let macId = viewModel.mac.value + else { return } alertHandler.processNetwork(record: record, trigger: false, for: macId) @@ -781,7 +816,8 @@ extension CardsPresenter: CardsViewOutput { } func viewWillAppear() { - guard viewModels.count > 0 else { + guard viewModels.count > 0 + else { return } view?.scroll(to: visibleViewModelIndex) @@ -803,8 +839,7 @@ extension CardsPresenter: CardsViewOutput { || background.isConnected(uuid: luid.value) || !viewModel.isConnectable.value.bound || !viewModel.isOwner.value.bound - || (settings.cloudModeEnabled && viewModel.isCloud.value.bound) - { + || (settings.cloudModeEnabled && viewModel.isCloud.value.bound) { openTagSettingsScreens(viewModel: viewModel) } else { view?.showKeepConnectionDialogSettings(for: viewModel) @@ -821,13 +856,11 @@ extension CardsPresenter: CardsViewOutput { || background.isConnected(uuid: luid.value) || !viewModel.isConnectable.value.bound || !viewModel.isOwner.value.bound - || (settings.cloudModeEnabled && viewModel.isCloud.value.bound) - { + || (settings.cloudModeEnabled && viewModel.isCloud.value.bound) { if let sensor = ruuviTags .first(where: { $0.macId != nil && ($0.macId?.any == viewModel.mac.value) - }) - { + }) { showCharts(for: sensor) } } else { @@ -837,8 +870,7 @@ extension CardsPresenter: CardsViewOutput { if let sensor = ruuviTags .first(where: { $0.macId != nil && ($0.macId?.any == viewModel.mac.value) - }) - { + }) { showCharts(for: sensor) } } else { @@ -850,15 +882,15 @@ extension CardsPresenter: CardsViewOutput { if let tagCharts, let sensor = ruuviTags .first(where: { $0.macId != nil && ($0.macId?.any == viewModel.mac.value) - }) - { + }) { tagCharts.scrollTo(ruuviTag: sensor) } } - func viewDidTriggerDismissChart(for _: CardsViewModel, - dismissParent: Bool) - { + func viewDidTriggerDismissChart( + for _: CardsViewModel, + dismissParent: Bool + ) { tagCharts?.notifyDismissInstruction(dismissParent: dismissParent) } @@ -880,8 +912,7 @@ extension CardsPresenter: CardsViewOutput { if let sensor = ruuviTags .first(where: { $0.macId != nil && ($0.macId?.any == viewModel.mac.value) - }) - { + }) { showCharts(for: sensor) } } else { @@ -896,8 +927,7 @@ extension CardsPresenter: CardsViewOutput { if let sensor = ruuviTags .first(where: { $0.macId != nil && ($0.macId?.any == viewModel.mac.value) - }) - { + }) { showCharts(for: sensor) } } else { @@ -941,8 +971,7 @@ extension CardsPresenter: CardsViewOutput { if let sensor = ruuviTags .first(where: { $0.luid != nil && ($0.luid?.any == viewModel.luid.value) - }) - { + }) { router.openUpdateFirmware(ruuviTag: sensor) } } @@ -961,8 +990,7 @@ extension CardsPresenter: CardsViewOutput { .first(where: { ($0.luid != nil && ($0.luid?.any == viewModel.luid.value)) || ($0.macId != nil && ($0.macId?.any == viewModel.mac.value)) - }) - { + }) { updateVisibleCard(from: viewModel) checkFirmwareVersion(for: sensor) } @@ -977,9 +1005,10 @@ extension CardsPresenter: CardsViewOutput { // MARK: - TagChartsModuleOutput extension CardsPresenter: TagChartsViewModuleOutput { - func tagChartSafeToClose(module: TagChartsViewModuleInput, - dismissParent: Bool) - { + func tagChartSafeToClose( + module: TagChartsViewModuleInput, + dismissParent: Bool + ) { module.dismiss(completion: { [weak self] in if dismissParent { self?.viewShouldDismiss() @@ -996,8 +1025,10 @@ extension CardsPresenter: TagChartsViewModuleOutput { ($0.luid.value != nil && $0.luid.value == ruuviTag.luid?.any) || ($0.mac.value != nil && $0.mac.value == ruuviTag.macId?.any) }) { - updateVisibleCard(from: viewModel, - triggerScroll: true) + updateVisibleCard( + from: viewModel, + triggerScroll: true + ) view?.scroll(to: visibleViewModelIndex) } } @@ -1020,9 +1051,10 @@ extension CardsPresenter: RuuviNotifierObserver { // MARK: - TagSettingsModuleOutput extension CardsPresenter: TagSettingsModuleOutput { - func tagSettingsDidDeleteTag(module: TagSettingsModuleInput, - ruuviTag: RuuviTagSensor) - { + func tagSettingsDidDeleteTag( + module: TagSettingsModuleInput, + ruuviTag: RuuviTagSensor + ) { module.dismiss(completion: { [weak self] in guard let self else { return } view?.dismissChart() @@ -1036,8 +1068,7 @@ extension CardsPresenter: TagSettingsModuleOutput { } if viewModels.count > 0, - let first = viewModels.first - { + let first = viewModels.first { updateVisibleCard(from: first, triggerScroll: true) } else { viewShouldDismiss() @@ -1056,8 +1087,10 @@ extension CardsPresenter { private func checkFirmwareVersion(for ruuviTag: RuuviTagSensor) { DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let sSelf = self else { return } - sSelf.interactor.checkAndUpdateFirmwareVersion(for: ruuviTag, - settings: sSelf.settings) + sSelf.interactor.checkAndUpdateFirmwareVersion( + for: ruuviTag, + settings: sSelf.settings + ) } } @@ -1065,8 +1098,11 @@ extension CardsPresenter { AlertType.allCases.forEach { type in switch type { case .temperature: - sync(temperature: type, - ruuviTag: ruuviTag, viewModel: viewModel) + sync( + temperature: type, + ruuviTag: ruuviTag, + viewModel: viewModel + ) case .relativeHumidity: sync(relativeHumidity: type, ruuviTag: ruuviTag, viewModel: viewModel) case .pressure: @@ -1108,13 +1144,15 @@ extension CardsPresenter { notifyUpdate(for: viewModel) } - private func sync(temperature: AlertType, - ruuviTag: RuuviTagSensor, - viewModel: CardsViewModel) - { - if case .temperature = alertService.alert(for: ruuviTag, - of: temperature) - { + private func sync( + temperature: AlertType, + ruuviTag: RuuviTagSensor, + viewModel: CardsViewModel + ) { + if case .temperature = alertService.alert( + for: ruuviTag, + of: temperature + ) { viewModel.isTemperatureAlertOn.value = true } else { viewModel.isTemperatureAlertOn.value = false @@ -1122,10 +1160,11 @@ extension CardsPresenter { viewModel.temperatureAlertMutedTill.value = alertService.mutedTill(type: temperature, for: ruuviTag) } - private func sync(relativeHumidity: AlertType, - ruuviTag: RuuviTagSensor, - viewModel: CardsViewModel) - { + private func sync( + relativeHumidity: AlertType, + ruuviTag: RuuviTagSensor, + viewModel: CardsViewModel + ) { if case .relativeHumidity = alertService.alert( for: ruuviTag, of: relativeHumidity @@ -1135,74 +1174,91 @@ extension CardsPresenter { viewModel.isRelativeHumidityAlertOn.value = false } viewModel.relativeHumidityAlertMutedTill.value = alertService - .mutedTill(type: relativeHumidity, - for: ruuviTag) + .mutedTill( + type: relativeHumidity, + for: ruuviTag + ) } - private func sync(pressure: AlertType, - ruuviTag: RuuviTagSensor, - viewModel: CardsViewModel) - { - if case .pressure = alertService.alert(for: ruuviTag, - of: pressure) - { + private func sync( + pressure: AlertType, + ruuviTag: RuuviTagSensor, + viewModel: CardsViewModel + ) { + if case .pressure = alertService.alert( + for: ruuviTag, + of: pressure + ) { viewModel.isPressureAlertOn.value = true } else { viewModel.isPressureAlertOn.value = false } viewModel.pressureAlertMutedTill.value = alertService - .mutedTill(type: pressure, - for: ruuviTag) + .mutedTill( + type: pressure, + for: ruuviTag + ) } - private func sync(signal: AlertType, - ruuviTag: RuuviTagSensor, - viewModel: CardsViewModel) - { - if case .signal = alertService.alert(for: ruuviTag, - of: signal) - { + private func sync( + signal: AlertType, + ruuviTag: RuuviTagSensor, + viewModel: CardsViewModel + ) { + if case .signal = alertService.alert( + for: ruuviTag, + of: signal + ) { viewModel.isSignalAlertOn.value = true } else { viewModel.isSignalAlertOn.value = false } viewModel.signalAlertMutedTill.value = - alertService.mutedTill(type: signal, - for: ruuviTag) + alertService.mutedTill( + type: signal, + for: ruuviTag + ) } - private func sync(connection: AlertType, - ruuviTag: RuuviTagSensor, - viewModel: CardsViewModel) - { + private func sync( + connection: AlertType, + ruuviTag: RuuviTagSensor, + viewModel: CardsViewModel + ) { if case .connection = alertService.alert(for: ruuviTag, of: connection) { viewModel.isConnectionAlertOn.value = true } else { viewModel.isConnectionAlertOn.value = false } viewModel.connectionAlertMutedTill.value = alertService - .mutedTill(type: connection, - for: ruuviTag) + .mutedTill( + type: connection, + for: ruuviTag + ) } - private func sync(movement: AlertType, - ruuviTag: RuuviTagSensor, - viewModel: CardsViewModel) - { + private func sync( + movement: AlertType, + ruuviTag: RuuviTagSensor, + viewModel: CardsViewModel + ) { if case .movement = alertService.alert(for: ruuviTag, of: movement) { viewModel.isMovementAlertOn.value = true } else { viewModel.isMovementAlertOn.value = false } viewModel.movementAlertMutedTill.value = alertService - .mutedTill(type: movement, - for: ruuviTag) + .mutedTill( + type: movement, + for: ruuviTag + ) } - private func sync(cloudConnection: AlertType, - ruuviTag: PhysicalSensor, - viewModel: CardsViewModel) - { + private func sync( + cloudConnection: AlertType, + ruuviTag: PhysicalSensor, + viewModel: CardsViewModel + ) { if case .cloudConnection = alertService.alert(for: ruuviTag, of: cloudConnection) { viewModel.isCloudConnectionAlertOn.value = true } else { @@ -1213,47 +1269,42 @@ extension CardsPresenter { private func reloadMutedTill() { for viewModel in viewModels { if let mutedTill = viewModel.temperatureAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.temperatureAlertMutedTill.value = nil } if let mutedTill = viewModel.relativeHumidityAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.relativeHumidityAlertMutedTill.value = nil } if let mutedTill = viewModel.pressureAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.pressureAlertMutedTill.value = nil } if let mutedTill = viewModel.signalAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.signalAlertMutedTill.value = nil } if let mutedTill = viewModel.connectionAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.connectionAlertMutedTill.value = nil } if let mutedTill = viewModel.movementAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.movementAlertMutedTill.value = nil } } } - private func updateMutedTill(of type: AlertType, - for uuid: String, - viewModel: CardsViewModel) - { + private func updateMutedTill( + of type: AlertType, + for uuid: String, + viewModel: CardsViewModel + ) { var observable: Observable = switch type { case .temperature: viewModel.temperatureAlertMutedTill @@ -1278,10 +1329,11 @@ extension CardsPresenter { } } - private func updateIsOnState(of type: AlertType, - for uuid: String, - viewModel: CardsViewModel) - { + private func updateIsOnState( + of type: AlertType, + for uuid: String, + viewModel: CardsViewModel + ) { var observable: Observable = switch type { case .temperature: viewModel.isTemperatureAlertOn @@ -1312,18 +1364,22 @@ extension CardsPresenter { // Notify daemon to restart NotificationCenter .default - .post(name: .RuuviTagAdvertisementDaemonShouldRestart, - object: nil, - userInfo: nil) + .post( + name: .RuuviTagAdvertisementDaemonShouldRestart, + object: nil, + userInfo: nil + ) } private func notifyRestartHeartBeatDaemon() { // Notify daemon to restart NotificationCenter .default - .post(name: .RuuviTagHeartBeatDaemonShouldRestart, - object: nil, - userInfo: nil) + .post( + name: .RuuviTagHeartBeatDaemonShouldRestart, + object: nil, + userInfo: nil + ) } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift index 9b4a86590..63ce7ae9d 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift @@ -14,11 +14,12 @@ class CardsRouter: NSObject, CardsRouterInput { .popToRootViewController(animated: true) } - func openTagSettings(ruuviTag: RuuviTagSensor, - latestMeasurement: RuuviTagSensorRecord?, - sensorSettings: SensorSettings?, - output: TagSettingsModuleOutput) - { + func openTagSettings( + ruuviTag: RuuviTagSensor, + latestMeasurement: RuuviTagSensorRecord?, + sensorSettings: SensorSettings?, + output: TagSettingsModuleOutput + ) { let factory: TagSettingsModuleFactory = TagSettingsModuleFactoryImpl() let module = factory.create() transitionHandler? @@ -29,9 +30,11 @@ class CardsRouter: NSObject, CardsRouterInput { ) if let presenter = module.output as? TagSettingsModuleInput { presenter.configure(output: output) - presenter.configure(ruuviTag: ruuviTag, - latestMeasurement: latestMeasurement, - sensorSettings: sensorSettings) + presenter.configure( + ruuviTag: ruuviTag, + latestMeasurement: latestMeasurement, + sensorSettings: sensorSettings + ) } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift index aafdcb6e1..7dd26c521 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift @@ -106,8 +106,10 @@ struct CardsViewModel { source.value = record.source batteryNeedsReplacement.value = batteryStatusProvider - .batteryNeedsReplacement(temperature: record.temperature, - voltage: record.voltage) + .batteryNeedsReplacement( + temperature: record.temperature, + voltage: record.voltage + ) isAlertAvailable.value = isCloud.value ?? false || isConnected.value ?? false } @@ -116,8 +118,7 @@ struct CardsViewModel { isConnectable.value = ruuviTag.isConnectable if let isChart = isChartAvailable.value, !isChart, - ruuviTag.isConnectable - { + ruuviTag.isConnectable { isChartAvailable.value = true } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift index da2e85f4f..02a7e1ca5 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift @@ -38,16 +38,20 @@ class CardsBackgroundView: UIView { } extension CardsBackgroundView { - func setBackgroundImage(with image: UIImage?, - withAnimation: Bool = true) - { + func setBackgroundImage( + with image: UIImage?, + withAnimation: Bool = true + ) { if withAnimation { - UIView.transition(with: cardImageView, - duration: 0.3, - options: .transitionCrossDissolve, - animations: { [weak self] in - self?.cardImageView.image = image - }, completion: nil) + UIView.transition( + with: cardImageView, + duration: 0.3, + options: .transitionCrossDissolve, + animations: { [weak self] in + self?.cardImageView.image = image + }, + completion: nil + ) } else { cardImageView.image = image } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsIndicatorView.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsIndicatorView.swift index 2c72ce66c..adcc14708 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsIndicatorView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsIndicatorView.swift @@ -44,10 +44,12 @@ class CardsIndicatorView: UIView { fileprivate func setUpUI() { addSubview(indicatorIconView) - indicatorIconView.anchor(top: nil, - leading: leadingAnchor, - bottom: nil, - trailing: nil) + indicatorIconView.anchor( + top: nil, + leading: leadingAnchor, + bottom: nil, + trailing: nil + ) indicatorIconView.heightAnchor.constraint( lessThanOrEqualToConstant: 50 ).isActive = true diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift index 06c2cb737..c6170474f 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift @@ -84,72 +84,96 @@ class CardsLargeImageCell: UICollectionViewCell { container.fillSuperview() container.addSubview(temperatureLabel) - temperatureLabel.anchor(top: container.topAnchor, - leading: nil, - bottom: nil, - trailing: nil, - padding: .init(top: 52, - left: 0, - bottom: 0, - right: 0)) + temperatureLabel.anchor( + top: container.topAnchor, + leading: nil, + bottom: nil, + trailing: nil, + padding: .init( + top: 52, + left: 0, + bottom: 0, + right: 0 + ) + ) temperatureLabel.centerXInSuperview() container.addSubview(temperatureUnitLabel) - temperatureUnitLabel.anchor(top: temperatureLabel.topAnchor, - leading: temperatureLabel.trailingAnchor, - bottom: nil, - trailing: nil, - padding: .init(top: 22, - left: 0, - bottom: 0, - right: 0), - size: .init(width: 0, height: 44)) + temperatureUnitLabel.anchor( + top: temperatureLabel.topAnchor, + leading: temperatureLabel.trailingAnchor, + bottom: nil, + trailing: nil, + padding: .init( + top: 22, + left: 0, + bottom: 0, + right: 0 + ), + size: .init(width: 0, height: 44) + ) container.addSubview(humidityView) - humidityView.anchor(top: nil, - leading: container.leadingAnchor, - bottom: nil, - trailing: container.trailingAnchor, - padding: .init(top: 0, - left: 16, - bottom: 0, - right: 16)) + humidityView.anchor( + top: nil, + leading: container.leadingAnchor, + bottom: nil, + trailing: container.trailingAnchor, + padding: .init( + top: 0, + left: 16, + bottom: 0, + right: 16 + ) + ) humidityViewHeight = humidityView.heightAnchor.constraint(equalToConstant: 66) humidityViewHeight.isActive = true container.addSubview(pressureView) - pressureView.anchor(top: humidityView.bottomAnchor, - leading: container.leadingAnchor, - bottom: nil, - trailing: container.trailingAnchor, - padding: .init(top: 0, - left: 16, - bottom: 0, - right: 16)) + pressureView.anchor( + top: humidityView.bottomAnchor, + leading: container.leadingAnchor, + bottom: nil, + trailing: container.trailingAnchor, + padding: .init( + top: 0, + left: 16, + bottom: 0, + right: 16 + ) + ) pressureViewHeight = pressureView.heightAnchor.constraint(equalToConstant: 66) pressureViewHeight.isActive = true container.addSubview(movementView) - movementView.anchor(top: pressureView.bottomAnchor, - leading: container.leadingAnchor, - bottom: nil, - trailing: container.trailingAnchor, - padding: .init(top: 0, - left: 16, - bottom: 0, - right: 16)) + movementView.anchor( + top: pressureView.bottomAnchor, + leading: container.leadingAnchor, + bottom: nil, + trailing: container.trailingAnchor, + padding: .init( + top: 0, + left: 16, + bottom: 0, + right: 16 + ) + ) movementViewHeight = movementView.heightAnchor.constraint(equalToConstant: 66) movementViewHeight.isActive = true container.addSubview(batteryLevelView) - batteryLevelView.anchor(top: movementView.bottomAnchor, - leading: nil, - bottom: nil, - trailing: container.trailingAnchor, - padding: .init(top: 8, - left: 0, - bottom: 0, - right: 12)) + batteryLevelView.anchor( + top: movementView.bottomAnchor, + leading: nil, + bottom: nil, + trailing: container.trailingAnchor, + padding: .init( + top: 8, + left: 0, + bottom: 0, + right: 12 + ) + ) batteryLevelView.updateTextColor(with: .white.withAlphaComponent(0.8)) batteryLevelViewHeight = batteryLevelView.heightAnchor.constraint(equalToConstant: 0) batteryLevelViewHeight.isActive = true @@ -157,43 +181,57 @@ class CardsLargeImageCell: UICollectionViewCell { let footerView = UIView(color: .clear) container.addSubview(footerView) - footerView.anchor(top: batteryLevelView.bottomAnchor, - leading: container.leadingAnchor, - bottom: container.bottomAnchor, - trailing: container.trailingAnchor, - padding: .init(top: 4, - left: 16, - bottom: 0, - right: 12), - size: .init(width: 0, height: 24)) + footerView.anchor( + top: batteryLevelView.bottomAnchor, + leading: container.leadingAnchor, + bottom: container.bottomAnchor, + trailing: container.trailingAnchor, + padding: .init( + top: 4, + left: 16, + bottom: 0, + right: 12 + ), + size: .init(width: 0, height: 24) + ) footerView.addSubview(syncStateLabel) - syncStateLabel.anchor(top: footerView.topAnchor, - leading: footerView.leadingAnchor, - bottom: footerView.bottomAnchor, - trailing: nil) + syncStateLabel.anchor( + top: footerView.topAnchor, + leading: footerView.leadingAnchor, + bottom: footerView.bottomAnchor, + trailing: nil + ) footerView.addSubview(updatedAtLabel) - updatedAtLabel.anchor(top: footerView.topAnchor, - leading: syncStateLabel.trailingAnchor, - bottom: footerView.bottomAnchor, - trailing: nil, - padding: .init(top: 0, - left: 12, - bottom: 0, - right: 0)) + updatedAtLabel.anchor( + top: footerView.topAnchor, + leading: syncStateLabel.trailingAnchor, + bottom: footerView.bottomAnchor, + trailing: nil, + padding: .init( + top: 0, + left: 12, + bottom: 0, + right: 0 + ) + ) footerView.addSubview(dataSourceIconView) // TODO: - Use larger icon size for iPads - dataSourceIconView.anchor(top: nil, - leading: updatedAtLabel.trailingAnchor, - bottom: nil, - trailing: footerView.trailingAnchor, - padding: .init(top: 0, - left: 6, - bottom: 0, - right: 0), - size: .init(width: 22, height: 22)) + dataSourceIconView.anchor( + top: nil, + leading: updatedAtLabel.trailingAnchor, + bottom: nil, + trailing: footerView.trailingAnchor, + padding: .init( + top: 0, + left: 6, + bottom: 0, + right: 0 + ), + size: .init(width: 22, height: 22) + ) dataSourceIconView.centerYInSuperview() } } @@ -219,9 +257,10 @@ extension CardsLargeImageCell { extension CardsLargeImageCell { // swiftlint:disable:next function_body_length cyclomatic_complexity - func configure(with viewModel: CardsViewModel, - measurementService: RuuviServiceMeasurement?) - { + func configure( + with viewModel: CardsViewModel, + measurementService: RuuviServiceMeasurement? + ) { // Temp if let temp = measurementService?.stringWithoutSign(for: viewModel.temperature.value) { temperatureLabel.text = temp.components(separatedBy: String.nbsp).first @@ -237,8 +276,7 @@ extension CardsLargeImageCell { // Humidity if let humidity = viewModel.humidity.value, - let measurementService - { + let measurementService { hideHumidityView(hide: false) let humidityValue = measurementService.stringWithoutSign( for: humidity, @@ -249,8 +287,10 @@ extension CardsLargeImageCell { let temperatureUnitSymbol = measurementService.units.temperatureUnit.symbol let unit = humidityUnit == .dew ? temperatureUnitSymbol : humidityUnitSymbol - humidityView.setValue(with: humidityValue, - unit: unit) + humidityView.setValue( + with: humidityValue, + unit: unit + ) } else { hideHumidityView(hide: true) } @@ -259,8 +299,10 @@ extension CardsLargeImageCell { if let pressure = viewModel.pressure.value { hidePressureView(hide: false) let pressureValue = measurementService?.stringWithoutSign(for: pressure) - pressureView.setValue(with: pressureValue, - unit: measurementService?.units.pressureUnit.symbol) + pressureView.setValue( + with: pressureValue, + unit: measurementService?.units.pressureUnit.symbol + ) } else { hidePressureView(hide: true) } @@ -309,8 +351,7 @@ extension CardsLargeImageCell { // Battery stat if let batteryLow = viewModel.batteryNeedsReplacement.value, - batteryLow - { + batteryLow { batteryLevelView.isHidden = false batteryLevelViewHeight.constant = 24 } else { @@ -319,7 +360,8 @@ extension CardsLargeImageCell { } // Sync status - guard let macId = viewModel.mac.value else { + guard let macId = viewModel.mac.value + else { return } startObservingNetworkSyncNotification(for: macId.any) @@ -331,11 +373,13 @@ extension CardsLargeImageCell { timer?.invalidate() timer = nil - timer = Timer.scheduledTimer(withTimeInterval: 1, - repeats: true, - block: { [weak self] _ in - self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message - }) + timer = Timer.scheduledTimer( + withTimeInterval: 1, + repeats: true, + block: { [weak self] _ in + self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message + } + ) } private func startObservingNetworkSyncNotification(for macId: AnyMACIdentifier) { @@ -344,18 +388,20 @@ extension CardsLargeImageCell { notificationToken = NotificationCenter .default - .addObserver(forName: .NetworkSyncDidChangeStatus, - object: nil, - queue: .main, - using: { [weak self] notification in - guard let mac = notification.userInfo?[NetworkSyncStatusKey.mac] as? MACIdentifier, - let status = notification.userInfo?[NetworkSyncStatusKey.status] as? NetworkSyncStatus, - mac.any == macId - else { - return - } - self?.updateSyncLabel(with: status) - }) + .addObserver( + forName: .NetworkSyncDidChangeStatus, + object: nil, + queue: .main, + using: { [weak self] notification in + guard let mac = notification.userInfo?[NetworkSyncStatusKey.mac] as? MACIdentifier, + let status = notification.userInfo?[NetworkSyncStatusKey.status] as? NetworkSyncStatus, + mac.any == macId + else { + return + } + self?.updateSyncLabel(with: status) + } + ) } private func updateSyncLabel(with status: NetworkSyncStatus) { diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift index e72b1f337..621143818 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift @@ -31,10 +31,11 @@ class CardsViewController: UIViewController { private static let reuseIdentifier: String = "reuseIdentifier" - func cell(collectionView: UICollectionView, - indexPath: IndexPath, - viewModel: CardsViewModel) -> UICollectionViewCell? - { + func cell( + collectionView: UICollectionView, + indexPath: IndexPath, + viewModel: CardsViewModel + ) -> UICollectionViewCell? { let cell = collectionView.dequeueReusableCell( withReuseIdentifier: Self.reuseIdentifier, for: indexPath @@ -60,8 +61,10 @@ class CardsViewController: UIViewController { // Header View // Ruuvi Logo private lazy var ruuviLogoView: UIImageView = { - let iv = UIImageView(image: UIImage(named: "ruuvi_logo_"), - contentMode: .scaleAspectFit) + let iv = UIImageView( + image: UIImage(named: "ruuvi_logo_"), + contentMode: .scaleAspectFit + ) iv.tintColor = .white return iv }() @@ -160,8 +163,10 @@ class CardsViewController: UIViewController { }() private lazy var collectionView: UICollectionView = { - let cv = UICollectionView(frame: .zero, - collectionViewLayout: createLayout()) + let cv = UICollectionView( + frame: .zero, + collectionViewLayout: createLayout() + ) cv.backgroundColor = .clear cv.showsHorizontalScrollIndicator = false cv.decelerationRate = .fast @@ -169,8 +174,10 @@ class CardsViewController: UIViewController { cv.alwaysBounceVertical = false cv.delegate = self cv.dataSource = self - cv.register(CardsLargeImageCell.self, - forCellWithReuseIdentifier: Self.reuseIdentifier) + cv.register( + CardsLargeImageCell.self, + forCellWithReuseIdentifier: Self.reuseIdentifier + ) return cv }() @@ -267,47 +274,57 @@ private extension CardsViewController { let leftBarButtonView = UIView(color: .clear) leftBarButtonView.addSubview(backButton) - backButton.anchor(top: leftBarButtonView.topAnchor, - leading: leftBarButtonView.leadingAnchor, - bottom: leftBarButtonView.bottomAnchor, - trailing: nil, - padding: .init(top: 0, left: -12, bottom: 0, right: 0), - size: .init(width: 40, height: 40)) + backButton.anchor( + top: leftBarButtonView.topAnchor, + leading: leftBarButtonView.leadingAnchor, + bottom: leftBarButtonView.bottomAnchor, + trailing: nil, + padding: .init(top: 0, left: -12, bottom: 0, right: 0), + size: .init(width: 40, height: 40) + ) leftBarButtonView.addSubview(ruuviLogoView) - ruuviLogoView.anchor(top: nil, - leading: backButton.trailingAnchor, - bottom: nil, - trailing: leftBarButtonView.trailingAnchor, - padding: .init(top: 0, left: 12, bottom: 0, right: 0), - size: .init(width: 110, height: 22)) + ruuviLogoView.anchor( + top: nil, + leading: backButton.trailingAnchor, + bottom: nil, + trailing: leftBarButtonView.trailingAnchor, + padding: .init(top: 0, left: 12, bottom: 0, right: 0), + size: .init(width: 110, height: 22) + ) ruuviLogoView.centerYInSuperview() let rightBarButtonView = UIView(color: .clear) // Right action buttons rightBarButtonView.addSubview(alertButton) - alertButton.anchor(top: rightBarButtonView.topAnchor, - leading: rightBarButtonView.leadingAnchor, - bottom: rightBarButtonView.bottomAnchor, - trailing: nil) + alertButton.anchor( + top: rightBarButtonView.topAnchor, + leading: rightBarButtonView.leadingAnchor, + bottom: rightBarButtonView.bottomAnchor, + trailing: nil + ) alertButton.centerYInSuperview() rightBarButtonView.addSubview(alertButtonHidden) alertButtonHidden.match(view: alertButton) rightBarButtonView.addSubview(chartButton) - chartButton.anchor(top: nil, - leading: alertButton.trailingAnchor, - bottom: nil, - trailing: nil) + chartButton.anchor( + top: nil, + leading: alertButton.trailingAnchor, + bottom: nil, + trailing: nil + ) chartButton.centerYInSuperview() rightBarButtonView.addSubview(settingsButton) - settingsButton.anchor(top: nil, - leading: chartButton.trailingAnchor, - bottom: nil, - trailing: rightBarButtonView.trailingAnchor, - padding: .init(top: 0, left: 0, bottom: 0, right: -14)) + settingsButton.anchor( + top: nil, + leading: chartButton.trailingAnchor, + bottom: nil, + trailing: rightBarButtonView.trailingAnchor, + padding: .init(top: 0, left: 0, bottom: 0, right: -14) + ) settingsButton.centerYInSuperview() navigationItem.leftBarButtonItem = UIBarButtonItem(customView: leftBarButtonView) @@ -345,39 +362,51 @@ private extension CardsViewController { ) view.addSubview(swipeToolbarView) - swipeToolbarView.anchor(top: view.safeTopAnchor, - leading: view.safeLeftAnchor, - bottom: nil, - trailing: view.safeRightAnchor) + swipeToolbarView.anchor( + top: view.safeTopAnchor, + leading: view.safeLeftAnchor, + bottom: nil, + trailing: view.safeRightAnchor + ) view.addSubview(collectionView) - collectionView.anchor(top: swipeToolbarView.bottomAnchor, - leading: view.safeLeftAnchor, - bottom: view.safeBottomAnchor, - trailing: view.safeRightAnchor) + collectionView.anchor( + top: swipeToolbarView.bottomAnchor, + leading: view.safeLeftAnchor, + bottom: view.safeBottomAnchor, + trailing: view.safeRightAnchor + ) } func createLayout() -> UICollectionViewLayout { - let sectionProvider = { (_: Int, - _: NSCollectionLayoutEnvironment) - -> NSCollectionLayoutSection? in - let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), - heightDimension: .fractionalHeight(1.0)) - let item = NSCollectionLayoutItem(layoutSize: itemSize) - item.contentInsets = NSDirectionalEdgeInsets(top: 4, leading: 4, bottom: 4, trailing: 4) + let sectionProvider = { ( + _: Int, + _: NSCollectionLayoutEnvironment + ) + -> NSCollectionLayoutSection? in + let itemSize = NSCollectionLayoutSize( + widthDimension: .fractionalWidth(1.0), + heightDimension: .fractionalHeight(1.0) + ) + let item = NSCollectionLayoutItem(layoutSize: itemSize) + item.contentInsets = NSDirectionalEdgeInsets(top: 4, leading: 4, bottom: 4, trailing: 4) - let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), - heightDimension: .fractionalHeight(1.0)) - let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) + let groupSize = NSCollectionLayoutSize( + widthDimension: .fractionalWidth(1.0), + heightDimension: .fractionalHeight(1.0) + ) + let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) - let section = NSCollectionLayoutSection(group: group) - return section + let section = NSCollectionLayoutSection(group: group) + return section } let config = UICollectionViewCompositionalLayoutConfiguration() config.scrollDirection = .horizontal - let layout = UICollectionViewCompositionalLayout(sectionProvider: sectionProvider, - configuration: config) + let layout = UICollectionViewCompositionalLayout( + sectionProvider: sectionProvider, + configuration: config + ) return layout } @@ -388,12 +417,13 @@ private extension CardsViewController { private func configureRestartAnimationsOnAppDidBecomeActive() { appDidBecomeActiveToken = NotificationCenter .default - .addObserver(forName: UIApplication.didBecomeActiveNotification, - object: nil, - queue: .main) - { [weak self] _ in - self?.restartAnimations() - } + .addObserver( + forName: UIApplication.didBecomeActiveNotification, + object: nil, + queue: .main + ) { [weak self] _ in + self?.restartAnimations() + } } } @@ -409,20 +439,23 @@ extension CardsViewController: UICollectionViewDelegate { } extension CardsViewController: UICollectionViewDataSource { - func collectionView(_: UICollectionView, - numberOfItemsInSection _: Int) -> Int - { + func collectionView( + _: UICollectionView, + numberOfItemsInSection _: Int + ) -> Int { viewModels.count } - func collectionView(_ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath) -> UICollectionViewCell - { + func collectionView( + _ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath + ) -> UICollectionViewCell { guard let cell = cell( collectionView: collectionView, indexPath: indexPath, viewModel: viewModels[indexPath.item] - ) else { + ) + else { fatalError() } return cell @@ -433,31 +466,38 @@ extension CardsViewController { @objc private func backButtonDidTap() { // TODO: Handle the case when chart visible and sync ongoing. if isChartsShowing { - guard let viewModel = currentVisibleItem else { + guard let viewModel = currentVisibleItem + else { return } - output.viewDidTriggerDismissChart(for: viewModel, - dismissParent: true) + output.viewDidTriggerDismissChart( + for: viewModel, + dismissParent: true + ) } else { output.viewShouldDismiss() } } @objc private func alertButtonDidTap() { - guard let viewModel = currentVisibleItem else { + guard let viewModel = currentVisibleItem + else { return } output.viewDidTriggerSettings(for: viewModel) } @objc private func chartButtonDidTap() { - guard let viewModel = currentVisibleItem else { + guard let viewModel = currentVisibleItem + else { return } if isChartsShowing { - output.viewDidTriggerDismissChart(for: viewModel, - dismissParent: false) + output.viewDidTriggerDismissChart( + for: viewModel, + dismissParent: false + ) } else { output.viewDidTriggerShowChart(for: viewModel) } @@ -488,7 +528,8 @@ extension CardsViewController { } @objc private func settingsButtonDidTap() { - guard let viewModel = currentVisibleItem else { + guard let viewModel = currentVisibleItem + else { return } navigationController?.setNavigationBarHidden(false, animated: false) @@ -526,8 +567,7 @@ extension CardsViewController: CardsViewInput { }) { let indexPath = IndexPath(item: index, section: 0) if let cell = collectionView - .cellForItem(at: indexPath) as? CardsLargeImageCell - { + .cellForItem(at: indexPath) as? CardsLargeImageCell { cell.configure( with: viewModel, measurementService: measurementService ) @@ -537,9 +577,10 @@ extension CardsViewController: CardsViewInput { } } - func changeCardBackground(of viewModel: CardsViewModel, - to image: UIImage?) - { + func changeCardBackground( + of viewModel: CardsViewModel, + to image: UIImage? + ) { if viewModel == currentVisibleItem { updateCardInfo(with: viewModel.name.value, image: image) } @@ -553,16 +594,19 @@ extension CardsViewController: CardsViewInput { let title = RuuviLocalization.Cards.BluetoothDisabledAlert.title let message = RuuviLocalization.Cards.BluetoothDisabledAlert.message let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: RuuviLocalization.PermissionPresenter.settings, - style: .default, handler: { _ in - guard let url = URL(string: userDeclined ? - UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), - UIApplication.shared.canOpenURL(url) - else { - return - } - UIApplication.shared.open(url) - })) + alertVC.addAction(UIAlertAction( + title: RuuviLocalization.PermissionPresenter.settings, + style: .default, + handler: { _ in + guard let url = URL(string: userDeclined ? + UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), + UIApplication.shared.canOpenURL(url) + else { + return + } + UIApplication.shared.open(url) + } + )) alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) } @@ -678,7 +722,8 @@ extension CardsViewController { } private func bindCurrentVisibleItem() { - guard let currentVisibleItem else { + guard let currentVisibleItem + else { return } @@ -762,13 +807,17 @@ extension CardsViewController { alertButton.alpha = 1.0 alertButton.image = RuuviAssets.alertActiveImage DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - UIView.animate(withDuration: 0.5, - delay: 0, - options: [.repeat, - .autoreverse], - animations: { [weak self] in - self?.alertButton.alpha = 0.0 - }) + UIView.animate( + withDuration: 0.5, + delay: 0, + options: [ + .repeat, + .autoreverse, + ], + animations: { [weak self] in + self?.alertButton.alpha = 0.0 + } + ) } } } else { @@ -785,7 +834,8 @@ extension CardsViewController { } private func updateTopActionButtonVisibility() { - guard let viewModel = currentVisibleItem else { + guard let viewModel = currentVisibleItem + else { return } diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsViewConfigurator.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsViewConfigurator.swift index 0aeb856e0..7ea9eb121 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsViewConfigurator.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsViewConfigurator.swift @@ -10,9 +10,10 @@ import RuuviService import RuuviStorage class TagChartsViewConfigurator { - func configure(view: TagChartsViewController, - ruuviTag: AnyRuuviTagSensor) - { + func configure( + view: TagChartsViewController, + ruuviTag: AnyRuuviTagSensor + ) { let r = AppAssembly.shared.assembler.resolver let interactor = TagChartsViewInteractor() diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift index 2d228f932..004a21c4f 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift @@ -10,9 +10,10 @@ public class CustomXAxisRenderer: XAxisRenderer { from = time } - override public func computeAxisValues(min: Double, - max: Double) - { + override public func computeAxisValues( + min: Double, + max: Double + ) { let labelCount = axis.labelCount let range = abs(max - min) diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift index 70aa2f3a2..45acf3092 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift @@ -36,7 +36,8 @@ class CustomYAxisRenderer: YAxisRenderer { ] override func computeAxisValues(min: Double, max: Double) { - guard min != CGFloat.greatestFiniteMagnitude && max != CGFloat.greatestFiniteMagnitude else { + guard min != CGFloat.greatestFiniteMagnitude && max != CGFloat.greatestFiniteMagnitude + else { super.computeAxisValues(min: min, max: max) return } diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift index a95d2543b..8980d432b 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift @@ -13,7 +13,8 @@ public class YAxisValueFormatter: NSObject, AxisValueFormatter { } public func stringForValue(_ value: Double, axis _: AxisBase?) -> String { - guard let value = numberFormatter.string(from: NSNumber(value: value)) else { + guard let value = numberFormatter.string(from: NSNumber(value: value)) + else { return "" } return value diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractor.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractor.swift index f04545e5c..bc53155bc 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractor.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractor.swift @@ -55,16 +55,14 @@ extension TagChartsViewInteractor: TagChartsViewInteractorInput { case let .initial(sensors): self?.sensors = sensors if let id = self?.ruuviTagSensor.id, - let sensor = sensors.first(where: { $0.id == id }) - { + let sensor = sensors.first(where: { $0.id == id }) { self?.ruuviTagSensor = sensor } case let .insert(sensor): self?.sensors.append(sensor) case let .update(sensor): if self?.ruuviTagSensor.id == sensor.id, - let index = self?.sensors.firstIndex(where: { $0.id == sensor.id }) - { + let index = self?.sensors.firstIndex(where: { $0.id == sensor.id }) { self?.ruuviTagSensor = sensor self?.sensors[index] = sensor self?.presenter.interactorDidUpdate(sensor: sensor) @@ -80,9 +78,10 @@ extension TagChartsViewInteractor: TagChartsViewInteractorInput { ruuviTagSensorObservationToken = nil } - func configure(withTag ruuviTag: AnyRuuviTagSensor, - andSettings settings: SensorSettings?) - { + func configure( + withTag ruuviTag: AnyRuuviTagSensor, + andSettings settings: SensorSettings? + ) { ruuviTagSensor = ruuviTag sensorSettings = settings lastMeasurement = nil @@ -117,7 +116,8 @@ extension TagChartsViewInteractor: TagChartsViewInteractorInput { func export() -> Future { let promise = Promise() - guard let sensorSettings else { + guard let sensorSettings + else { return promise.future } let op = exportService.csvLog(for: ruuviTagSensor.id, settings: sensorSettings) @@ -130,7 +130,8 @@ extension TagChartsViewInteractor: TagChartsViewInteractorInput { } func isSyncingRecords() -> Bool { - guard let luid = ruuviTagSensor.luid else { + guard let luid = ruuviTagSensor.luid + else { return false } if gattService.isSyncingLogs(with: luid.value) { @@ -142,7 +143,8 @@ extension TagChartsViewInteractor: TagChartsViewInteractorInput { func syncRecords(progress: ((BTServiceProgress) -> Void)?) -> Future { let promise = Promise() - guard let luid = ruuviTagSensor.luid else { + guard let luid = ruuviTagSensor.luid + else { promise.fail(error: .unexpected(.callbackErrorAndResultAreNil)) return promise.future } @@ -158,18 +160,19 @@ extension TagChartsViewInteractor: TagChartsViewInteractorInput { syncFrom = historyLength } else if let from = syncFrom, let history = historyLength, - from < history - { + from < history { syncFrom = history } - let op = gattService.syncLogs(uuid: luid.value, - mac: ruuviTagSensor.macId?.value, - from: syncFrom ?? Date.distantPast, - settings: sensorSettings, - progress: progress, - connectionTimeout: connectionTimeout, - serviceTimeout: serviceTimeout) + let op = gattService.syncLogs( + uuid: luid.value, + mac: ruuviTagSensor.macId?.value, + from: syncFrom ?? Date.distantPast, + settings: sensorSettings, + progress: progress, + connectionTimeout: connectionTimeout, + serviceTimeout: serviceTimeout + ) op.on(success: { [weak self] _ in if let isInterrupted = self?.gattSyncInterruptedByUser, !isInterrupted { self?.localSyncState.setGattSyncDate(Date(), for: self?.ruuviTagSensor.macId) @@ -184,7 +187,8 @@ extension TagChartsViewInteractor: TagChartsViewInteractorInput { func stopSyncRecords() -> Future { let promise = Promise() - guard let luid = ruuviTagSensor.luid else { + guard let luid = ruuviTagSensor.luid + else { promise.fail(error: .unexpected(.callbackErrorAndResultAreNil)) return promise.future } @@ -246,13 +250,15 @@ extension TagChartsViewInteractor { } private func fetchLast() { - guard ruuviTagSensor != nil else { + guard ruuviTagSensor != nil + else { return } let op = ruuviStorage.readLatest(ruuviTagSensor) op.on(success: { [weak self] record in guard let sSelf = self else { return } - guard let record else { + guard let record + else { sSelf.presenter.createChartModules(from: []) return } @@ -303,7 +309,8 @@ extension TagChartsViewInteractor { private func fetchPoints(_ completion: (() -> Void)? = nil) { if settings.chartDownsamplingOn { fetchAll { [weak self] in - guard let self else { + guard let self + else { return } if ruuviTagData.count < minimumDownsampleThreshold { @@ -318,7 +325,8 @@ extension TagChartsViewInteractor { } private func fetchAll(_ completion: (() -> Void)? = nil) { - guard ruuviTagSensor != nil else { + guard ruuviTagSensor != nil + else { return } @@ -340,7 +348,8 @@ extension TagChartsViewInteractor { } private func fetchDownSampled(_ competion: (() -> Void)? = nil) { - guard ruuviTagSensor != nil else { + guard ruuviTagSensor != nil + else { return } diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorInput.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorInput.swift index eb4c587d3..e8185dea8 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorInput.swift @@ -6,8 +6,10 @@ import RuuviOntology protocol TagChartsViewInteractorInput: AnyObject { var ruuviTagData: [RuuviMeasurement] { get } var lastMeasurement: RuuviMeasurement? { get } - func configure(withTag ruuviTag: AnyRuuviTagSensor, - andSettings settings: SensorSettings?) + func configure( + withTag ruuviTag: AnyRuuviTagSensor, + andSettings settings: SensorSettings? + ) func updateSensorSettings(settings: SensorSettings?) func restartObservingTags() func stopObservingTags() diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleOutput.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleOutput.swift index 0cb7ee2e9..bbb958c62 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleOutput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleOutput.swift @@ -2,8 +2,10 @@ import Foundation import RuuviOntology protocol TagChartsViewModuleOutput: AnyObject { - func tagChartSafeToClose(module: TagChartsViewModuleInput, - dismissParent: Bool) + func tagChartSafeToClose( + module: TagChartsViewModuleInput, + dismissParent: Bool + ) func tagChartSafeToSwipe( to ruuviTag: AnyRuuviTagSensor, module: TagChartsViewModuleInput ) diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift index 24e2ab955..b790267c2 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift @@ -19,9 +19,10 @@ class TagChartViewData: NSObject { var chartType: MeasurementType var chartData: LineChartData? - init(chartType: MeasurementType, - chartData: LineChartData?) - { + init( + chartType: MeasurementType, + chartData: LineChartData? + ) { self.chartType = chartType self.chartData = chartData } @@ -133,8 +134,10 @@ class TagChartsViewPresenter: NSObject, TagChartsViewModuleInput { if interactor.isSyncingRecords() { view?.showSyncAbortAlert(dismiss: dismissParent) } else { - output?.tagChartSafeToClose(module: self, - dismissParent: dismissParent) + output?.tagChartSafeToClose( + module: self, + dismissParent: dismissParent + ) } } @@ -191,14 +194,16 @@ extension TagChartsViewPresenter: TagChartsViewOutput { func viewDidStartSync(for viewModel: TagChartsViewModel) { // Check bluetooth - guard foreground.bluetoothState == .poweredOn || !isBluetoothPermissionGranted else { + guard foreground.bluetoothState == .poweredOn || !isBluetoothPermissionGranted + else { view?.showBluetoothDisabled(userDeclined: !isBluetoothPermissionGranted) return } isSyncing = true let op = interactor.syncRecords { [weak self] progress in DispatchQueue.main.async { [weak self] in - guard let syncing = self?.isSyncing, syncing else { + guard let syncing = self?.isSyncing, syncing + else { self?.view?.setSync(progress: nil, for: viewModel) return } @@ -237,8 +242,10 @@ extension TagChartsViewPresenter: TagChartsViewOutput { func viewDidConfirmAbortSync(dismiss: Bool) { if dismiss { - output?.tagChartSafeToClose(module: self, - dismissParent: dismiss) + output?.tagChartSafeToClose( + module: self, + dismissParent: dismiss + ) } else { stopGattSync() } @@ -351,12 +358,12 @@ extension TagChartsViewPresenter { } private func observeLastOpenedChart() { - guard ruuviTag != nil else { + guard ruuviTag != nil + else { return } if let lastOpenedChart = settings.lastOpenedChart(), - lastOpenedChart != ruuviTag.id - { + lastOpenedChart != ruuviTag.id { view?.clearChartHistory() } settings.setLastOpenedChart(with: ruuviTag.id) @@ -364,8 +371,7 @@ extension TagChartsViewPresenter { private func tryToShowSwipeUpHint() { if UIWindow.isLandscape, - !settings.tagChartsLandscapeSwipeInstructionWasShown - { + !settings.tagChartsLandscapeSwipeInstructionWasShown { settings.tagChartsLandscapeSwipeInstructionWasShown = true view?.showSwipeUpInstruction() } @@ -406,7 +412,8 @@ extension TagChartsViewPresenter { private func startObservingRuuviTag() { advertisementToken?.invalidate() heartbeatToken?.invalidate() - guard let luid = ruuviTag.luid else { + guard let luid = ruuviTag.luid + else { return } advertisementToken = foreground.observe(self, uuid: luid.value, closure: { [weak self] _, device in @@ -422,9 +429,10 @@ extension TagChartsViewPresenter { }) } - private func sync(device: RuuviTag, - source: RuuviTagSensorRecordSource) - { + private func sync( + device: RuuviTag, + source: RuuviTagSensorRecordSource + ) { if device.isConnected { if source == .heartbeat { if viewModel.isConnectable.value != device.isConnectable { @@ -446,87 +454,101 @@ extension TagChartsViewPresenter { private func startListeningToSettings() { temperatureUnitToken = NotificationCenter .default - .addObserver(forName: .TemperatureUnitDidChange, - object: nil, - queue: .main) - { [weak self] _ in - self?.interactor.restartObservingData() - } + .addObserver( + forName: .TemperatureUnitDidChange, + object: nil, + queue: .main + ) { [weak self] _ in + self?.interactor.restartObservingData() + } humidityUnitToken = NotificationCenter .default - .addObserver(forName: .HumidityUnitDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.interactor.restartObservingData() - }) + .addObserver( + forName: .HumidityUnitDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.interactor.restartObservingData() + } + ) pressureUnitToken = NotificationCenter .default - .addObserver(forName: .PressureUnitDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.interactor.restartObservingData() - }) + .addObserver( + forName: .PressureUnitDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.interactor.restartObservingData() + } + ) downsampleDidChangeToken = NotificationCenter .default - .addObserver(forName: .DownsampleOnDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.interactor.restartObservingData() - }) + .addObserver( + forName: .DownsampleOnDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.interactor.restartObservingData() + } + ) chartDurationHourDidChangeToken = NotificationCenter .default - .addObserver(forName: .ChartDurationHourDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - guard let sSelf = self else { return } - sSelf.interactor.restartObservingData() - }) + .addObserver( + forName: .ChartDurationHourDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + guard let sSelf = self else { return } + sSelf.interactor.restartObservingData() + } + ) chartShowStatsStateDidChangeToken = NotificationCenter .default - .addObserver(forName: .ChartStatsOnDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - guard let sSelf = self else { return } - DispatchQueue.main.async { - sSelf.view?.showChartStat = sSelf.settings.chartStatsOn - } - }) + .addObserver( + forName: .ChartStatsOnDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + guard let sSelf = self else { return } + DispatchQueue.main.async { + sSelf.view?.showChartStat = sSelf.settings.chartStatsOn + } + } + ) chartDrawDotsDidChangeToken = NotificationCenter .default - .addObserver(forName: .ChartDrawDotsOnDidChange, - object: nil, - queue: .main, - using: { _ in - // TODO: Add this implemention when draw dots is back. - }) + .addObserver( + forName: .ChartDrawDotsOnDidChange, + object: nil, + queue: .main, + using: { _ in + // TODO: Add this implemention when draw dots is back. + } + ) } private func startObservingBackgroundChanges() { backgroundToken = NotificationCenter .default - .addObserver(forName: .BackgroundPersistenceDidChangeBackground, - object: nil, - queue: .main) - { [weak self] notification in - guard let sSelf = self else { return } - if let userInfo = notification.userInfo { - let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier - let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier - if sSelf.viewModel.uuid.value == luid?.value || sSelf.viewModel.mac.value == macId?.value { - sSelf.ruuviSensorPropertiesService.getImage(for: sSelf.ruuviTag) - .on(success: { [weak sSelf] image in - sSelf?.viewModel.background.value = image - }, failure: { [weak sSelf] error in - sSelf?.errorPresenter.present(error: error) - }) + .addObserver( + forName: .BackgroundPersistenceDidChangeBackground, + object: nil, + queue: .main + ) { [weak self] notification in + guard let sSelf = self else { return } + if let userInfo = notification.userInfo { + let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier + let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier + if sSelf.viewModel.uuid.value == luid?.value || sSelf.viewModel.mac.value == macId?.value { + sSelf.ruuviSensorPropertiesService.getImage(for: sSelf.ruuviTag) + .on(success: { [weak sSelf] image in + sSelf?.viewModel.background.value = image + }, failure: { [weak sSelf] error in + sSelf?.errorPresenter.present(error: error) + }) + } } } - } } private func startObservingBluetoothState() { @@ -545,22 +567,23 @@ extension TagChartsViewPresenter { private func startObservingAlertChanges() { alertDidChangeToken = NotificationCenter .default - .addObserver(forName: .RuuviServiceAlertDidChange, - object: nil, - queue: .main, - using: { [weak self] notification in - if let sSelf = self, - let userInfo = notification.userInfo, - let physicalSensor = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor, - self?.viewModel.mac.value == physicalSensor.macId?.value - { - if sSelf.alertService.hasRegistrations(for: physicalSensor) { - self?.viewModel.alertState.value = .registered - } else { - self?.viewModel.alertState.value = .empty - } - } - }) + .addObserver( + forName: .RuuviServiceAlertDidChange, + object: nil, + queue: .main, + using: { [weak self] notification in + if let sSelf = self, + let userInfo = notification.userInfo, + let physicalSensor = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor, + self?.viewModel.mac.value == physicalSensor.macId?.value { + if sSelf.alertService.hasRegistrations(for: physicalSensor) { + self?.viewModel.alertState.value = .registered + } else { + self?.viewModel.alertState.value = .empty + } + } + } + ) } private func startListeningToAlertStatus() { @@ -576,31 +599,33 @@ extension TagChartsViewPresenter { func startObservingDidConnectDisconnectNotifications() { didConnectToken = NotificationCenter .default - .addObserver(forName: .BTBackgroundDidConnect, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let uuid = userInfo[BTBackgroundDidConnectKey.uuid] as? String, - self?.viewModel.uuid.value == uuid - { - self?.viewModel.isConnected.value = true - } - }) + .addObserver( + forName: .BTBackgroundDidConnect, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let uuid = userInfo[BTBackgroundDidConnectKey.uuid] as? String, + self?.viewModel.uuid.value == uuid { + self?.viewModel.isConnected.value = true + } + } + ) didDisconnectToken = NotificationCenter .default - .addObserver(forName: .BTBackgroundDidDisconnect, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let uuid = userInfo[BTBackgroundDidDisconnectKey.uuid] as? String, - self?.viewModel.uuid.value == uuid - { - self?.viewModel.isConnected.value = false - } - }) + .addObserver( + forName: .BTBackgroundDidDisconnect, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let uuid = userInfo[BTBackgroundDidDisconnectKey.uuid] as? String, + self?.viewModel.uuid.value == uuid { + self?.viewModel.isConnected.value = false + } + } + ) } private func startObservingSensorSettingsChanges() { @@ -620,32 +645,35 @@ extension TagChartsViewPresenter { private func startObservingLocalNotificationsManager() { lnmDidReceiveToken = NotificationCenter .default - .addObserver(forName: .LNMDidReceive, - object: nil, - queue: .main, - using: { [weak self] notification in - if let uuid = notification.userInfo?[LNMDidReceiveKey.uuid] as? String, - self?.viewModel.uuid.value != uuid - { - self?.dismiss() - } - }) + .addObserver( + forName: .LNMDidReceive, + object: nil, + queue: .main, + using: { [weak self] notification in + if let uuid = notification.userInfo?[LNMDidReceiveKey.uuid] as? String, + self?.viewModel.uuid.value != uuid { + self?.dismiss() + } + } + ) } private func startObservingCloudSyncNotification() { historySyncToken = NotificationCenter .default - .addObserver(forName: .NetworkHistorySyncDidCompleteForSensor, - object: nil, - queue: .main, - using: { [weak self] notification in - guard let mac = notification.userInfo?[NetworkSyncStatusKey.mac] as? MACIdentifier, - mac.any == self?.ruuviTag.macId?.any - else { - return - } - self?.interactor.restartObservingData() - }) + .addObserver( + forName: .NetworkHistorySyncDidCompleteForSensor, + object: nil, + queue: .main, + using: { [weak self] notification in + guard let mac = notification.userInfo?[NetworkSyncStatusKey.mac] as? MACIdentifier, + mac.any == self?.ruuviTag.macId?.any + else { + return + } + self?.interactor.restartObservingData() + } + ) } private func reloadChartsWithSensorSettingsChanges(with _: SensorSettings) { @@ -687,21 +715,29 @@ extension TagChartsViewPresenter { } // Update new measurements on the chart - view?.updateChartViewData(temperatureEntries: temparatureData, - humidityEntries: humidityData, - pressureEntries: pressureData, - isFirstEntry: ruuviTagData.count == 1, - settings: settings) + view?.updateChartViewData( + temperatureEntries: temparatureData, + humidityEntries: humidityData, + pressureEntries: pressureData, + isFirstEntry: ruuviTagData.count == 1, + settings: settings + ) // Update the latest measurement label. if let lastMeasurement = newValues.last { view?.updateLatestMeasurement( - temperature: chartEntry(for: lastMeasurement, - type: .temperature), - humidity: chartEntry(for: lastMeasurement, - type: .humidity), - pressure: chartEntry(for: lastMeasurement, - type: .pressure), + temperature: chartEntry( + for: lastMeasurement, + type: .temperature + ), + humidity: chartEntry( + for: lastMeasurement, + type: .humidity + ), + pressure: chartEntry( + for: lastMeasurement, + type: .pressure + ), settings: settings ) } @@ -739,22 +775,28 @@ extension TagChartsViewPresenter { // Create datasets only if collection has at least one chart entry if temparatureData.count > 0 { let temperatureDataSet = TagChartsHelper.newDataSet(entries: temparatureData) - let temperatureChartData = TagChartViewData(chartType: .temperature, - chartData: LineChartData(dataSet: temperatureDataSet)) + let temperatureChartData = TagChartViewData( + chartType: .temperature, + chartData: LineChartData(dataSet: temperatureDataSet) + ) datasource.append(temperatureChartData) } if humidityData.count > 0 { let humidityChartDataSet = TagChartsHelper.newDataSet(entries: humidityData) - let humidityChartData = TagChartViewData(chartType: .humidity, - chartData: LineChartData(dataSet: humidityChartDataSet)) + let humidityChartData = TagChartViewData( + chartType: .humidity, + chartData: LineChartData(dataSet: humidityChartDataSet) + ) datasource.append(humidityChartData) } if pressureData.count > 0 { let pressureChartDataSet = TagChartsHelper.newDataSet(entries: pressureData) - let pressureChartData = TagChartViewData(chartType: .pressure, - chartData: LineChartData(dataSet: pressureChartDataSet)) + let pressureChartData = TagChartViewData( + chartType: .pressure, + chartData: LineChartData(dataSet: pressureChartDataSet) + ) datasource.append(pressureChartData) } @@ -764,12 +806,18 @@ extension TagChartsViewPresenter { // Update the latest measurement label. if let lastMeasurement = ruuviTagData.last { view?.updateLatestMeasurement( - temperature: chartEntry(for: lastMeasurement, - type: .temperature), - humidity: chartEntry(for: lastMeasurement, - type: .humidity), - pressure: chartEntry(for: lastMeasurement, - type: .pressure), + temperature: chartEntry( + for: lastMeasurement, + type: .temperature + ), + humidity: chartEntry( + for: lastMeasurement, + type: .humidity + ), + pressure: chartEntry( + for: lastMeasurement, + type: .pressure + ), settings: settings ) } @@ -802,8 +850,7 @@ extension TagChartsViewPresenter { // Backword compatibility for the users who used earlier versions than 0.7.7 // 1: If local record has temperature offset added, calculate and get original temp data // 2: Apply current sensor settings - = if let offset = data.temperatureOffset, offset != 0 - { + = if let offset = data.temperatureOffset, offset != 0 { data.temperature? .minus(value: offset)? .plus(sensorSettings: sensorSettings) @@ -816,24 +863,24 @@ extension TagChartsViewPresenter { // Backword compatibility for the users who used earlier versions than 0.7.7 // 1: If local record has humidity offset added, calculate and get original humidity data // 2: Apply current sensor settings - = if let offset = data.humidityOffset, offset != 0 - { + = if let offset = data.humidityOffset, offset != 0 { data.humidity? .minus(value: offset)? .plus(sensorSettings: sensorSettings) } else { data.humidity?.plus(sensorSettings: sensorSettings) } - value = measurementService.double(for: humidity, - temperature: data.temperature, - isDecimal: false) + value = measurementService.double( + for: humidity, + temperature: data.temperature, + isDecimal: false + ) case .pressure: var pressure: Pressure? // Backword compatibility for the users who used earlier versions than 0.7.7 // 1: If local record has pressure offset added, calculate and get original pressure data // 2: Apply current sensor settings - = if let offset = data.pressureOffset, offset != 0 - { + = if let offset = data.pressureOffset, offset != 0 { data.pressure? .minus(value: offset)? .plus(sensorSettings: sensorSettings) @@ -848,7 +895,8 @@ extension TagChartsViewPresenter { default: fatalError("before need implement chart with current type!") } - guard let y = value else { + guard let y = value + else { return nil } return ChartDataEntry(x: data.date.timeIntervalSince1970, y: y) diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift index 360638c60..2ebd66e7f 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift @@ -12,17 +12,23 @@ protocol TagChartsViewInput: ViewInput { var viewIsVisible: Bool { get } func createChartViews(from: [MeasurementType]) func clearChartHistory() - func setChartViewData(from chartViewData: [TagChartViewData], - settings: RuuviLocalSettings) - func updateChartViewData(temperatureEntries: [ChartDataEntry], - humidityEntries: [ChartDataEntry], - pressureEntries: [ChartDataEntry], - isFirstEntry: Bool, - settings: RuuviLocalSettings) - func updateLatestMeasurement(temperature: ChartDataEntry?, - humidity: ChartDataEntry?, - pressure: ChartDataEntry?, - settings: RuuviLocalSettings) + func setChartViewData( + from chartViewData: [TagChartViewData], + settings: RuuviLocalSettings + ) + func updateChartViewData( + temperatureEntries: [ChartDataEntry], + humidityEntries: [ChartDataEntry], + pressureEntries: [ChartDataEntry], + isFirstEntry: Bool, + settings: RuuviLocalSettings + ) + func updateLatestMeasurement( + temperature: ChartDataEntry?, + humidity: ChartDataEntry?, + pressure: ChartDataEntry?, + settings: RuuviLocalSettings + ) func updateLatestRecordStatus(with record: RuuviTagSensorRecord) func showBluetoothDisabled(userDeclined: Bool) func showClearConfirmationDialog(for viewModel: TagChartsViewModel) diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift index de04792b4..ee362a0f7 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift @@ -20,10 +20,11 @@ class TagChartsMarkerView: MarkerImage { private let cornerRadius: CGFloat = 4.0 private let yBottomPadding: CGFloat = 32.0 - init(color: UIColor? = RuuviColor.ruuviGraphMarkerColor, - font: UIFont = UIFont.Muli(.regular, size: 8), - textColor: UIColor = .white) - { + init( + color: UIColor? = RuuviColor.ruuviGraphMarkerColor, + font: UIFont = UIFont.Muli(.regular, size: 8), + textColor: UIColor = .white + ) { if let color { self.color = color } else { @@ -35,15 +36,18 @@ class TagChartsMarkerView: MarkerImage { let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = .center - attrs = [.font: font, - .paragraphStyle: paragraphStyle, - .foregroundColor: textColor, - .baselineOffset: NSNumber(value: baselineOffset)] + attrs = [ + .font: font, + .paragraphStyle: paragraphStyle, + .foregroundColor: textColor, + .baselineOffset: NSNumber(value: baselineOffset), + ] super.init() } override func draw(context: CGContext, point: CGPoint) { - guard let attrs else { + guard let attrs + else { return } // Padding for the label. @@ -51,10 +55,12 @@ class TagChartsMarkerView: MarkerImage { let labelHeight = labelText.size(withAttributes: attrs).height + vPadding // Set position of the marker view container - var rectangle = CGRect(x: point.x, - y: point.y, - width: labelWidth, - height: labelHeight) + var rectangle = CGRect( + x: point.x, + y: point.y, + width: labelWidth, + height: labelHeight + ) let screenSize: CGRect = UIScreen.main.bounds if (point.x + rectangle.width) >= screenSize.width { rectangle.origin.x -= rectangle.width @@ -77,8 +83,10 @@ class TagChartsMarkerView: MarkerImage { } // Rounded corner - let clipPath = UIBezierPath(roundedRect: rectangle, - cornerRadius: cornerRadius).cgPath + let clipPath = UIBezierPath( + roundedRect: rectangle, + cornerRadius: cornerRadius + ).cgPath context.addPath(clipPath) context.setFillColor(color.cgColor) context.setStrokeColor(UIColor.clear.cgColor) @@ -86,10 +94,12 @@ class TagChartsMarkerView: MarkerImage { context.drawPath(using: .fillStroke) // Draw - labelText.draw(with: rectangle, - options: .usesLineFragmentOrigin, - attributes: attrs, - context: nil) + labelText.draw( + with: rectangle, + options: .usesLineFragmentOrigin, + attributes: attrs, + context: nil + ) } override func refreshContent(entry: ChartDataEntry, highlight _: Highlight) { @@ -111,11 +121,12 @@ class TagChartsMarkerView: MarkerImage { } extension TagChartsMarkerView { - func initialise(with unit: String, - type: MeasurementType, - measurementService: RuuviServiceMeasurement, - parentFrame: CGRect) - { + func initialise( + with unit: String, + type: MeasurementType, + measurementService: RuuviServiceMeasurement, + parentFrame: CGRect + ) { self.unit = unit self.type = type self.measurementService = measurementService diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift index 0d0ed4657..dfcb29db0 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift @@ -7,9 +7,11 @@ import UIKit protocol TagChartsViewDelegate: NSObjectProtocol { func chartDidTranslate(_ chartView: TagChartsView) - func chartValueDidSelect(_ chartView: TagChartsView, - entry: ChartDataEntry, - highlight: Highlight) + func chartValueDidSelect( + _ chartView: TagChartsView, + entry: ChartDataEntry, + highlight: Highlight + ) func chartValueDidDeselect(_ chartView: TagChartsView) } @@ -141,27 +143,32 @@ class TagChartsView: LineChartView { } extension TagChartsView: ChartViewDelegate { - func chartTranslated(_: ChartViewBase, - dX _: CGFloat, - dY _: CGFloat) - { + func chartTranslated( + _: ChartViewBase, + dX _: CGFloat, + dY _: CGFloat + ) { chartDelegate?.chartDidTranslate(self) } - func chartScaled(_: ChartViewBase, - scaleX _: CGFloat, - scaleY _: CGFloat) - { + func chartScaled( + _: ChartViewBase, + scaleX _: CGFloat, + scaleY _: CGFloat + ) { chartDelegate?.chartDidTranslate(self) } - func chartValueSelected(_: ChartViewBase, - entry: ChartDataEntry, - highlight: Highlight) - { - chartDelegate?.chartValueDidSelect(self, - entry: entry, - highlight: highlight) + func chartValueSelected( + _: ChartViewBase, + entry: ChartDataEntry, + highlight: Highlight + ) { + chartDelegate?.chartValueDidSelect( + self, + entry: entry, + highlight: highlight + ) } func chartValueNothingSelected(_: ChartViewBase) { @@ -224,9 +231,10 @@ extension TagChartsView { // MARK: - UpdateUI - func updateDataSet(with newData: [ChartDataEntry], - isFirstEntry: Bool) - { + func updateDataSet( + with newData: [ChartDataEntry], + isFirstEntry: Bool + ) { if isFirstEntry { let emptyDataSet = LineChartData(dataSet: TagChartsHelper.newDataSet()) data = emptyDataSet @@ -239,11 +247,12 @@ extension TagChartsView { reloadData() } - func updateLatest(with entry: ChartDataEntry?, - type: MeasurementType, - measurementService: RuuviServiceMeasurement, - unit: String) - { + func updateLatest( + with entry: ChartDataEntry?, + type: MeasurementType, + measurementService: RuuviServiceMeasurement, + unit: String + ) { guard let entry else { return } switch type { case .temperature: @@ -259,18 +268,21 @@ extension TagChartsView { } } - func setChartLabel(with name: String, - type: MeasurementType, - measurementService: RuuviServiceMeasurement, - unit: String) - { + func setChartLabel( + with name: String, + type: MeasurementType, + measurementService: RuuviServiceMeasurement, + unit: String + ) { chartName = name chartNameLabel.text = name if let marker = marker as? TagChartsMarkerView { - marker.initialise(with: unit, - type: type, - measurementService: measurementService, - parentFrame: frame) + marker.initialise( + with: unit, + type: type, + measurementService: measurementService, + parentFrame: frame + ) } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift index 90a3b8f16..9d21ccd2c 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift @@ -79,13 +79,15 @@ class TagChartsViewController: UIViewController { // Chart toolbar private lazy var historySelectionButton: RuuviContextMenuButton = - .init(menu: historyLengthOptions(), - titleColor: .white, - title: RuuviLocalization.day1, - icon: RuuviAssets.dropDownArrowImage, - iconTintColor: RuuviColor.logoTintColor, - iconSize: .init(width: 14, height: 14), - preccedingIcon: false) + .init( + menu: historyLengthOptions(), + titleColor: .white, + title: RuuviLocalization.day1, + icon: RuuviAssets.dropDownArrowImage, + iconTintColor: RuuviColor.logoTintColor, + iconSize: .init(width: 14, height: 14), + preccedingIcon: false + ) // Chart toolbar private lazy var moreButton: UIButton = { @@ -141,8 +143,11 @@ class TagChartsViewController: UIViewController { preccedingIcon: true ) button.button.showsMenuAsPrimaryAction = false - button.button.addTarget(self, action: #selector(syncButtonDidTap), - for: .touchUpInside) + button.button.addTarget( + self, + action: #selector(syncButtonDidTap), + for: .touchUpInside + ) return button }() @@ -216,8 +221,10 @@ class TagChartsViewController: UIViewController { coordinator.animate(alongsideTransition: { _ in }, completion: { [weak self] _ in self?.updateScrollviewBehaviour() - self?.updateChartsCollectionConstaints(from: self?.chartModules ?? [], - withAnimation: true) + self?.updateChartsCollectionConstaints( + from: self?.chartModules ?? [], + withAnimation: true + ) self?.output.viewDidTransition() }) super.viewWillTransition(to: size, with: coordinator) @@ -232,156 +239,204 @@ class TagChartsViewController: UIViewController { fileprivate func setUpContentView() { let chartToolbarView = UIView(color: .clear) view.addSubview(chartToolbarView) - chartToolbarView.anchor(top: view.safeTopAnchor, - leading: view.safeLeftAnchor, - bottom: nil, - trailing: view.safeRightAnchor, - padding: .init(top: 8, - left: 12, - bottom: 0, - right: 8), - size: .init(width: 0, height: 36)) + chartToolbarView.anchor( + top: view.safeTopAnchor, + leading: view.safeLeftAnchor, + bottom: nil, + trailing: view.safeRightAnchor, + padding: .init( + top: 8, + left: 12, + bottom: 0, + right: 8 + ), + size: .init(width: 0, height: 36) + ) chartToolbarView.addSubview(moreButton) - moreButton.anchor(top: nil, - leading: nil, - bottom: nil, - trailing: chartToolbarView.trailingAnchor, - padding: .init(top: 0, - left: 0, - bottom: 0, - right: 8), - size: .init(width: 18, height: 18)) + moreButton.anchor( + top: nil, + leading: nil, + bottom: nil, + trailing: chartToolbarView.trailingAnchor, + padding: .init( + top: 0, + left: 0, + bottom: 0, + right: 8 + ), + size: .init(width: 18, height: 18) + ) moreButton.centerYInSuperview() chartToolbarView.addSubview(historySelectionButton) - historySelectionButton.anchor(top: nil, - leading: nil, - bottom: nil, - trailing: moreButton.leadingAnchor, - padding: .init(top: 0, - left: 0, - bottom: 0, - right: 8), - size: .init(width: 0, - height: 24)) + historySelectionButton.anchor( + top: nil, + leading: nil, + bottom: nil, + trailing: moreButton.leadingAnchor, + padding: .init( + top: 0, + left: 0, + bottom: 0, + right: 8 + ), + size: .init( + width: 0, + height: 24 + ) + ) historySelectionButton.centerYInSuperview() chartToolbarView.addSubview(syncProgressView) - syncProgressView.anchor(top: chartToolbarView.topAnchor, - leading: chartToolbarView.leadingAnchor, - bottom: chartToolbarView.bottomAnchor, - trailing: historySelectionButton.leadingAnchor, - padding: .init(top: 0, - left: 0, - bottom: 0, - right: 8)) + syncProgressView.anchor( + top: chartToolbarView.topAnchor, + leading: chartToolbarView.leadingAnchor, + bottom: chartToolbarView.bottomAnchor, + trailing: historySelectionButton.leadingAnchor, + padding: .init( + top: 0, + left: 0, + bottom: 0, + right: 8 + ) + ) syncProgressView.addSubview(syncCancelButton) - syncCancelButton.anchor(top: nil, - leading: syncProgressView.leadingAnchor, - bottom: nil, - trailing: nil, - size: .init(width: 32, height: 32)) + syncCancelButton.anchor( + top: nil, + leading: syncProgressView.leadingAnchor, + bottom: nil, + trailing: nil, + size: .init(width: 32, height: 32) + ) syncCancelButton.centerYInSuperview() syncProgressView.alpha = 0 syncProgressView.addSubview(syncStatusLabel) - syncStatusLabel.anchor(top: nil, - leading: syncCancelButton.trailingAnchor, - bottom: nil, - trailing: syncProgressView.trailingAnchor, - padding: .init(top: 0, left: 6, bottom: 0, right: 0)) + syncStatusLabel.anchor( + top: nil, + leading: syncCancelButton.trailingAnchor, + bottom: nil, + trailing: syncProgressView.trailingAnchor, + padding: .init(top: 0, left: 6, bottom: 0, right: 0) + ) syncStatusLabel.centerYInSuperview() chartToolbarView.addSubview(syncButton) - syncButton.anchor(top: nil, - leading: chartToolbarView.leadingAnchor, - bottom: nil, - trailing: nil, - padding: .init(top: 0, left: 8, bottom: 0, right: 0), - size: .init(width: 0, - height: 28)) + syncButton.anchor( + top: nil, + leading: chartToolbarView.leadingAnchor, + bottom: nil, + trailing: nil, + padding: .init(top: 0, left: 8, bottom: 0, right: 0), + size: .init( + width: 0, + height: 28 + ) + ) syncButton.centerYInSuperview() syncButton.alpha = 1 view.addSubview(scrollView) - scrollView.anchor(top: chartToolbarView.bottomAnchor, - leading: view.safeLeftAnchor, - bottom: view.safeBottomAnchor, - trailing: view.safeRightAnchor, - padding: .init(top: 6, left: 0, bottom: 28, right: 0)) + scrollView.anchor( + top: chartToolbarView.bottomAnchor, + leading: view.safeLeftAnchor, + bottom: view.safeBottomAnchor, + trailing: view.safeRightAnchor, + padding: .init(top: 6, left: 0, bottom: 28, right: 0) + ) scrollView.addSubview(temperatureChartView) - temperatureChartView.anchor(top: scrollView.topAnchor, - leading: scrollView.leadingAnchor, - bottom: nil, - trailing: scrollView.trailingAnchor) + temperatureChartView.anchor( + top: scrollView.topAnchor, + leading: scrollView.leadingAnchor, + bottom: nil, + trailing: scrollView.trailingAnchor + ) temperatureChartView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true temperatureChartViewHeight = temperatureChartView.heightAnchor.constraint(equalToConstant: 0) temperatureChartViewHeight.isActive = true temperatureChartView.chartDelegate = self scrollView.addSubview(humidityChartView) - humidityChartView.anchor(top: temperatureChartView.bottomAnchor, - leading: scrollView.leadingAnchor, - bottom: nil, - trailing: scrollView.trailingAnchor) + humidityChartView.anchor( + top: temperatureChartView.bottomAnchor, + leading: scrollView.leadingAnchor, + bottom: nil, + trailing: scrollView.trailingAnchor + ) humidityChartView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true humidityChartViewHeight = humidityChartView.heightAnchor.constraint(equalToConstant: 0) humidityChartViewHeight.isActive = true humidityChartView.chartDelegate = self scrollView.addSubview(pressureChartView) - pressureChartView.anchor(top: humidityChartView.bottomAnchor, - leading: scrollView.leadingAnchor, - bottom: scrollView.bottomAnchor, - trailing: scrollView.trailingAnchor) + pressureChartView.anchor( + top: humidityChartView.bottomAnchor, + leading: scrollView.leadingAnchor, + bottom: scrollView.bottomAnchor, + trailing: scrollView.trailingAnchor + ) pressureChartView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true pressureChartViewHeight = pressureChartView.heightAnchor.constraint(equalToConstant: 0) pressureChartViewHeight.isActive = true pressureChartView.chartDelegate = self view.addSubview(noDataLabel) - noDataLabel.anchor(top: nil, - leading: view.safeLeftAnchor, - bottom: nil, - trailing: view.safeRightAnchor) + noDataLabel.anchor( + top: nil, + leading: view.safeLeftAnchor, + bottom: nil, + trailing: view.safeRightAnchor + ) noDataLabel.centerYInSuperview() noDataLabel.alpha = 0 let footerView = UIView(color: .clear) view.addSubview(footerView) - footerView.anchor(top: scrollView.bottomAnchor, - leading: view.safeLeftAnchor, - bottom: view.safeBottomAnchor, - trailing: view.safeRightAnchor, - padding: .init(top: 4, - left: 16, - bottom: 8, - right: 16), - size: .init(width: 0, height: 26)) + footerView.anchor( + top: scrollView.bottomAnchor, + leading: view.safeLeftAnchor, + bottom: view.safeBottomAnchor, + trailing: view.safeRightAnchor, + padding: .init( + top: 4, + left: 16, + bottom: 8, + right: 16 + ), + size: .init(width: 0, height: 26) + ) footerView.addSubview(updatedAtLabel) - updatedAtLabel.anchor(top: footerView.topAnchor, - leading: nil, - bottom: footerView.bottomAnchor, - trailing: nil, - padding: .init(top: 0, - left: 12, - bottom: 0, - right: 0)) + updatedAtLabel.anchor( + top: footerView.topAnchor, + leading: nil, + bottom: footerView.bottomAnchor, + trailing: nil, + padding: .init( + top: 0, + left: 12, + bottom: 0, + right: 0 + ) + ) footerView.addSubview(dataSourceIconView) - dataSourceIconView.anchor(top: nil, - leading: updatedAtLabel.trailingAnchor, - bottom: nil, - trailing: footerView.trailingAnchor, - padding: .init(top: 0, - left: 6, - bottom: 0, - right: 0), - size: .init(width: 22, height: 22)) + dataSourceIconView.anchor( + top: nil, + leading: updatedAtLabel.trailingAnchor, + bottom: nil, + trailing: footerView.trailingAnchor, + padding: .init( + top: 0, + left: 6, + bottom: 0, + right: 0 + ), + size: .init(width: 22, height: 22) + ) dataSourceIconView.centerYInSuperview() } @@ -436,8 +491,10 @@ class TagChartsViewController: UIViewController { } actions.append(more_action) - return UIMenu(title: "", - children: actions) + return UIMenu( + title: "", + children: actions + ) } fileprivate func handleHistoryLengthSelection(hours: Int?) { @@ -499,7 +556,8 @@ class TagChartsViewController: UIViewController { extension TagChartsViewController: TagChartsViewDelegate { func chartDidTranslate(_ chartView: TagChartsView) { - guard chartViews.count > 1 else { + guard chartViews.count > 1 + else { calculateMinMaxForChart(for: chartView) return } @@ -520,11 +578,13 @@ extension TagChartsViewController: TagChartsViewDelegate { } } - func chartValueDidSelect(_ chartView: TagChartsView, - entry _: ChartDataEntry, - highlight: Highlight) - { - guard chartViews.count > 1 else { + func chartValueDidSelect( + _ chartView: TagChartsView, + entry _: ChartDataEntry, + highlight: Highlight + ) { + guard chartViews.count > 1 + else { return } @@ -534,7 +594,8 @@ extension TagChartsViewController: TagChartsViewDelegate { } func chartValueDidDeselect(_: TagChartsView) { - guard chartViews.count > 1 else { + guard chartViews.count > 1 + else { return } @@ -560,9 +621,10 @@ extension TagChartsViewController: TagChartsViewInput { updateChartsCollectionConstaints(from: from) } - func setChartViewData(from chartViewData: [TagChartViewData], - settings: RuuviLocalSettings) - { + func setChartViewData( + from chartViewData: [TagChartViewData], + settings: RuuviLocalSettings + ) { if chartViewData.count == 0 { clearChartData() showNoDataLabel() @@ -576,73 +638,93 @@ extension TagChartsViewController: TagChartsViewInput { for data in chartViewData { switch data.chartType { case .temperature: - populateChartView(from: data.chartData, - title: RuuviLocalization.TagSettings.OffsetCorrection.temperature, - type: data.chartType, - unit: settings.temperatureUnit.symbol, - settings: settings, - view: temperatureChartView) + populateChartView( + from: data.chartData, + title: RuuviLocalization.TagSettings.OffsetCorrection.temperature, + type: data.chartType, + unit: settings.temperatureUnit.symbol, + settings: settings, + view: temperatureChartView + ) case .humidity: - populateChartView(from: data.chartData, - title: RuuviLocalization.TagSettings.OffsetCorrection.humidity, - type: data.chartType, - unit: settings.humidityUnit.symbol, - settings: settings, - view: humidityChartView) + populateChartView( + from: data.chartData, + title: RuuviLocalization.TagSettings.OffsetCorrection.humidity, + type: data.chartType, + unit: settings.humidityUnit.symbol, + settings: settings, + view: humidityChartView + ) case .pressure: - populateChartView(from: data.chartData, - title: RuuviLocalization.TagSettings.OffsetCorrection.pressure, - type: data.chartType, - unit: settings.pressureUnit.symbol, - settings: settings, - view: pressureChartView) + populateChartView( + from: data.chartData, + title: RuuviLocalization.TagSettings.OffsetCorrection.pressure, + type: data.chartType, + unit: settings.pressureUnit.symbol, + settings: settings, + view: pressureChartView + ) default: break } } } - func updateChartViewData(temperatureEntries: [ChartDataEntry], - humidityEntries: [ChartDataEntry], - pressureEntries: [ChartDataEntry], - isFirstEntry: Bool, - settings: RuuviLocalSettings) - { + func updateChartViewData( + temperatureEntries: [ChartDataEntry], + humidityEntries: [ChartDataEntry], + pressureEntries: [ChartDataEntry], + isFirstEntry: Bool, + settings: RuuviLocalSettings + ) { hideNoDataLabel() showChartViews() temperatureChartView.setSettings(settings: settings) - temperatureChartView.updateDataSet(with: temperatureEntries, - isFirstEntry: isFirstEntry) + temperatureChartView.updateDataSet( + with: temperatureEntries, + isFirstEntry: isFirstEntry + ) humidityChartView.setSettings(settings: settings) - humidityChartView.updateDataSet(with: humidityEntries, - isFirstEntry: isFirstEntry) + humidityChartView.updateDataSet( + with: humidityEntries, + isFirstEntry: isFirstEntry + ) pressureChartView.setSettings(settings: settings) - pressureChartView.updateDataSet(with: pressureEntries, - isFirstEntry: isFirstEntry) + pressureChartView.updateDataSet( + with: pressureEntries, + isFirstEntry: isFirstEntry + ) } - func updateLatestMeasurement(temperature: ChartDataEntry?, - humidity: ChartDataEntry?, - pressure: ChartDataEntry?, - settings: RuuviLocalSettings) - { - temperatureChartView.updateLatest(with: temperature, - type: .temperature, - measurementService: measurementService, - unit: settings.temperatureUnit.symbol) - humidityChartView.updateLatest(with: humidity, - type: .humidity, - measurementService: measurementService, - unit: settings.humidityUnit == .dew ? - settings.temperatureUnit.symbol : - settings.humidityUnit.symbol) - pressureChartView.updateLatest(with: pressure, - type: .pressure, - measurementService: measurementService, - unit: settings.pressureUnit.symbol) + func updateLatestMeasurement( + temperature: ChartDataEntry?, + humidity: ChartDataEntry?, + pressure: ChartDataEntry?, + settings: RuuviLocalSettings + ) { + temperatureChartView.updateLatest( + with: temperature, + type: .temperature, + measurementService: measurementService, + unit: settings.temperatureUnit.symbol + ) + humidityChartView.updateLatest( + with: humidity, + type: .humidity, + measurementService: measurementService, + unit: settings.humidityUnit == .dew ? + settings.temperatureUnit.symbol : + settings.humidityUnit.symbol + ) + pressureChartView.updateLatest( + with: pressure, + type: .pressure, + measurementService: measurementService, + unit: settings.pressureUnit.symbol + ) } func updateLatestRecordStatus(with record: RuuviTagSensorRecord) { @@ -675,16 +757,19 @@ extension TagChartsViewController: TagChartsViewInput { let title = RuuviLocalization.TagCharts.BluetoothDisabledAlert.title let message = RuuviLocalization.TagCharts.BluetoothDisabledAlert.message let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: RuuviLocalization.PermissionPresenter.settings, - style: .default, handler: { _ in - guard let url = URL(string: userDeclined ? - UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), - UIApplication.shared.canOpenURL(url) - else { - return - } - UIApplication.shared.open(url) - })) + alertVC.addAction(UIAlertAction( + title: RuuviLocalization.PermissionPresenter.settings, + style: .default, + handler: { _ in + guard let url = URL(string: userDeclined ? + UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), + UIApplication.shared.canOpenURL(url) + else { + return + } + UIApplication.shared.open(url) + } + )) alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) } @@ -734,12 +819,14 @@ extension TagChartsViewController: TagChartsViewInput { let message = RuuviLocalization.TagCharts.FailedToSyncDialog.message let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) - alertVC.addAction(UIAlertAction(title: RuuviLocalization.TagCharts.TryAgain.title, - style: .default, - handler: { [weak self] _ in - guard let self else { return } - output.viewDidTriggerSync(for: viewModel) - })) + alertVC.addAction(UIAlertAction( + title: RuuviLocalization.TagCharts.TryAgain.title, + style: .default, + handler: { [weak self] _ in + guard let self else { return } + output.viewDidTriggerSync(for: viewModel) + } + )) present(alertVC, animated: true) } @@ -753,12 +840,13 @@ extension TagChartsViewController: TagChartsViewInput { let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) alertVC.addAction(UIAlertAction(title: RuuviLocalization.close, style: .cancel, handler: nil)) let actionTitle = RuuviLocalization.doNotShowAgain - alertVC.addAction(UIAlertAction(title: actionTitle, - style: .default, - handler: { [weak self] _ in - self?.output.viewDidTriggerDoNotShowSyncDialog() - - })) + alertVC.addAction(UIAlertAction( + title: actionTitle, + style: .default, + handler: { [weak self] _ in + self?.output.viewDidTriggerDoNotShowSyncDialog() + } + )) present(alertVC, animated: true) } @@ -788,8 +876,10 @@ extension TagChartsViewController: TagChartsViewInput { } func showExportSheet(with path: URL) { - let vc = UIActivityViewController(activityItems: [path], - applicationActivities: []) + let vc = UIActivityViewController( + activityItems: [path], + applicationActivities: [] + ) vc.excludedActivityTypes = [ UIActivity.ActivityType.assignToContact, UIActivity.ActivityType.saveToCameraRoll, @@ -808,21 +898,26 @@ extension TagChartsViewController: TagChartsViewInput { func showLongerHistoryDialog() { let title = RuuviLocalization.longerHistoryTitle let message = RuuviLocalization.longerHistoryMessage - let controller = UIAlertController(title: title, - message: message, - preferredStyle: .alert) - controller.addAction(UIAlertAction(title: RuuviLocalization.ok, - style: .cancel, - handler: nil)) + let controller = UIAlertController( + title: title, + message: message, + preferredStyle: .alert + ) + controller.addAction(UIAlertAction( + title: RuuviLocalization.ok, + style: .cancel, + handler: nil + )) present(controller, animated: true) } } extension TagChartsViewController { // swiftlint:disable:next cyclomatic_complexity function_body_length - private func updateChartsCollectionConstaints(from: [MeasurementType], - withAnimation: Bool = false) - { + private func updateChartsCollectionConstaints( + from: [MeasurementType], + withAnimation: Bool = false + ) { if from.count == 0 { noDataLabel.alpha = 1 return @@ -831,7 +926,8 @@ extension TagChartsViewController { noDataLabel.alpha = 0 chartViews.removeAll() let scrollViewHeight = scrollView.frame.height - guard viewIsVisible, scrollViewHeight > 0, from.count > 0 else { + guard viewIsVisible, scrollViewHeight > 0, from.count > 0 + else { return } updateScrollviewBehaviour() @@ -862,22 +958,28 @@ extension TagChartsViewController { switch item { case .temperature: chartViews.append(temperatureChartView) - updateChartViewConstaints(constaint: temperatureChartViewHeight, - totalHeight: scrollViewHeight, - itemCount: from.count, - withAnimation: withAnimation) + updateChartViewConstaints( + constaint: temperatureChartViewHeight, + totalHeight: scrollViewHeight, + itemCount: from.count, + withAnimation: withAnimation + ) case .humidity: chartViews.append(humidityChartView) - updateChartViewConstaints(constaint: humidityChartViewHeight, - totalHeight: scrollViewHeight, - itemCount: from.count, - withAnimation: withAnimation) + updateChartViewConstaints( + constaint: humidityChartViewHeight, + totalHeight: scrollViewHeight, + itemCount: from.count, + withAnimation: withAnimation + ) case .pressure: chartViews.append(pressureChartView) - updateChartViewConstaints(constaint: pressureChartViewHeight, - totalHeight: scrollViewHeight, - itemCount: from.count, - withAnimation: withAnimation) + updateChartViewConstaints( + constaint: pressureChartViewHeight, + totalHeight: scrollViewHeight, + itemCount: from.count, + withAnimation: withAnimation + ) default: break } @@ -906,36 +1008,44 @@ extension TagChartsViewController { } } - private func updateChartViewConstaints(constaint: NSLayoutConstraint, - totalHeight: CGFloat, - itemCount: Int, - withAnimation: Bool) - { + private func updateChartViewConstaints( + constaint: NSLayoutConstraint, + totalHeight: CGFloat, + itemCount: Int, + withAnimation: Bool + ) { if withAnimation { UIView.animate(withDuration: 0.2, animations: { [weak self] in guard let sSelf = self else { return } - constaint.constant = sSelf.getItemHeight(from: totalHeight, - count: CGFloat(itemCount)) + constaint.constant = sSelf.getItemHeight( + from: totalHeight, + count: CGFloat(itemCount) + ) sSelf.view.layoutIfNeeded() }) } else { - constaint.constant = getItemHeight(from: totalHeight, - count: CGFloat(itemCount)) + constaint.constant = getItemHeight( + from: totalHeight, + count: CGFloat(itemCount) + ) } } // swiftlint:disable:next function_parameter_count - private func populateChartView(from data: LineChartData?, - title: String, - type: MeasurementType, - unit: String, - settings: RuuviLocalSettings, - view: TagChartsView) - { - view.setChartLabel(with: title, - type: type, - measurementService: measurementService, - unit: unit) + private func populateChartView( + from data: LineChartData?, + title: String, + type: MeasurementType, + unit: String, + settings: RuuviLocalSettings, + view: TagChartsView + ) { + view.setChartLabel( + with: title, + type: type, + measurementService: measurementService, + unit: unit + ) view.data = data view.setSettings(settings: settings) view.localize() @@ -999,17 +1109,18 @@ extension TagChartsViewController { timer?.invalidate() timer = nil - timer = Timer.scheduledTimer(withTimeInterval: 1, - repeats: true, - block: { [weak self] _ in - self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message - }) + timer = Timer.scheduledTimer( + withTimeInterval: 1, + repeats: true, + block: { [weak self] _ in + self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message + } + ) } private func calculateMinMaxForChart(for view: TagChartsView) { if let data = view.data, - let dataSet = data.dataSets.first as? LineChartDataSet - { + let dataSet = data.dataSets.first as? LineChartDataSet { let lowestVisibleX = view.lowestVisibleX let highestVisibleX = view.highestVisibleX @@ -1043,26 +1154,26 @@ extension TagChartsViewController { } /** - Calculate the average value of visible data points on a `LineChartView`. - This function computes the average by considering the area under the curve - formed by the visible data points and then divides it by the width of the visible x-range. - The area under the curve is approximated using the trapezoidal rule. - - - Parameters: - - chartView: The `LineChartView` instance whose visible range's average needs to be calculated. - - dataSet: The `LineChartDataSet` containing data points to be considered. - - - Returns: The average value of visible data points. - - - Note: - The function uses the trapezoidal rule for approximation. The formula for the trapezoidal rule is: - A = (b - a) * (f(a) + f(b)) / 2 - Where: - - A is the area of the trapezium. - - a and b are the x-coordinates of the two data points. - - f(a) and f(b) are the y-coordinates (or values) of the two data points. - - The average is then computed as the total area divided by the width of the visible x-range. + Calculate the average value of visible data points on a `LineChartView`. + This function computes the average by considering the area under the curve + formed by the visible data points and then divides it by the width of the visible x-range. + The area under the curve is approximated using the trapezoidal rule. + + - Parameters: + - chartView: The `LineChartView` instance whose visible range's average needs to be calculated. + - dataSet: The `LineChartDataSet` containing data points to be considered. + + - Returns: The average value of visible data points. + + - Note: + The function uses the trapezoidal rule for approximation. The formula for the trapezoidal rule is: + A = (b - a) * (f(a) + f(b)) / 2 + Where: + - A is the area of the trapezium. + - a and b are the x-coordinates of the two data points. + - f(a) and f(b) are the y-coordinates (or values) of the two data points. + + The average is then computed as the total area divided by the width of the visible x-range. */ private func calculateVisibleAverage(chartView: LineChartView, dataSet: LineChartDataSet) -> Double { // Get the x-values defining the visible range of the chart. diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift index f570fa142..5b8a80212 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift @@ -71,9 +71,11 @@ final class DashboardModuleFactoryImpl: DashboardModuleFactory { // MARK: - MENU // swiftlint:disable force_cast - let menu = UIStoryboard(name: "Menu", - bundle: .main) - .instantiateInitialViewController() as! UINavigationController + let menu = UIStoryboard( + name: "Menu", + bundle: .main + ) + .instantiateInitialViewController() as! UINavigationController menu.modalPresentationStyle = .custom let menuTable = menu.topViewController as! MenuTableViewController let menuPresenter = menuTable.output as! MenuPresenter diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift index 8813a6805..34f927ea4 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift @@ -58,17 +58,18 @@ extension DashboardInteractor: DashboardInteractorInput { // Check in every 15 days if the tag doesn't have any owner. if let checkedDate = settings.ownerCheckDate(for: macId), - let days = checkedDate.numberOfDaysFromNow(), days < 15 - { + let days = checkedDate.numberOfDaysFromNow(), days < 15 { return } ruuviOwnershipService.checkOwner(macId: macId) .on(success: { [weak self] owner in - guard let sSelf = self else { + guard let sSelf = self + else { return } - guard let owner, !owner.isEmpty else { + guard let owner, !owner.isEmpty + else { NotificationCenter.default.post( name: .RuuviTagOwnershipCheckDidEnd, object: nil, diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift index 1075c53bb..1ae69ce52 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift @@ -193,8 +193,7 @@ extension DashboardPresenter: DashboardViewOutput { || background.isConnected(uuid: luid.value) || !viewModel.isConnectable.value.bound || !viewModel.isOwner.value.bound - || (settings.cloudModeEnabled && viewModel.isCloud.value.bound) - { + || (settings.cloudModeEnabled && viewModel.isCloud.value.bound) { openTagSettingsScreens(viewModel: viewModel) } else { view?.showKeepConnectionDialogSettings(for: viewModel) @@ -211,8 +210,7 @@ extension DashboardPresenter: DashboardViewOutput { || background.isConnected(uuid: luid.value) || !viewModel.isConnectable.value.bound || !viewModel.isOwner.value.bound - || (settings.cloudModeEnabled && viewModel.isCloud.value.bound) - { + || (settings.cloudModeEnabled && viewModel.isCloud.value.bound) { openCardView(viewModel: viewModel, showCharts: true) } else { view?.showKeepConnectionDialogChart(for: viewModel) @@ -320,7 +318,8 @@ extension DashboardPresenter: DashboardViewOutput { func viewDidRenameTag(to name: String, viewModel: CardsViewModel) { guard let ruuviTag = ruuviTags.first(where: { $0.id == viewModel.id.value - }) else { + }) + else { return } @@ -363,9 +362,11 @@ extension DashboardPresenter: MenuModuleOutput { module.dismiss() infoProvider.summary { [weak self] summary in guard let sSelf = self else { return } - sSelf.mailComposerPresenter.present(email: sSelf.feedbackEmail, - subject: sSelf.feedbackSubject, - body: "\n\n" + summary) + sSelf.mailComposerPresenter.present( + email: sSelf.feedbackEmail, + subject: sSelf.feedbackSubject, + body: "\n\n" + summary + ) } } @@ -387,9 +388,10 @@ extension DashboardPresenter: MenuModuleOutput { // MARK: - SignInBenefitsModuleOutput extension DashboardPresenter: SignInBenefitsModuleOutput { - func signIn(module: SignInBenefitsModuleInput, - didSuccessfulyLogin _: Any?) - { + func signIn( + module: SignInBenefitsModuleInput, + didSuccessfulyLogin _: Any? + ) { startObservingRuuviTags() startObservingCloudModeNotification() module.dismiss(completion: { @@ -397,17 +399,19 @@ extension DashboardPresenter: SignInBenefitsModuleOutput { }) } - func signIn(module: SignInBenefitsModuleInput, - didCloseSignInWithoutAttempt _: Any?) - { + func signIn( + module: SignInBenefitsModuleInput, + didCloseSignInWithoutAttempt _: Any? + ) { module.dismiss(completion: { AppUtility.lockOrientation(.all) }) } - func signIn(module: SignInBenefitsModuleInput, - didSelectUseWithoutAccount _: Any?) - { + func signIn( + module: SignInBenefitsModuleInput, + didSelectUseWithoutAccount _: Any? + ) { module.dismiss(completion: { AppUtility.lockOrientation(.all) }) @@ -427,12 +431,14 @@ extension DashboardPresenter: DiscoverRouterDelegate { if let viewModel = viewModels.first(where: { $0.id.value == ruuviTag.id }) { - self.router.openCardImageView(with: viewModels, - ruuviTagSensors: ruuviTags, - sensorSettings: sensorSettingsList, - scrollTo: viewModel, - showCharts: false, - output: self) + self.router.openCardImageView( + with: viewModels, + ruuviTagSensors: ruuviTags, + sensorSettings: sensorSettingsList, + scrollTo: viewModel, + showCharts: false, + output: self + ) } } } @@ -453,11 +459,12 @@ extension DashboardPresenter: RuuviNotifierObserver { } // swiftlint:disable:next function_body_length - func ruuvi(notifier _: RuuviNotifier, - alertType: AlertType, - isTriggered: Bool, - for uuid: String) - { + func ruuvi( + notifier _: RuuviNotifier, + alertType: AlertType, + isTriggered: Bool, + for uuid: String + ) { viewModels .filter { $0.luid.value?.value == uuid || $0.mac.value?.value == uuid } .forEach { viewModel in @@ -532,9 +539,10 @@ extension DashboardPresenter: CardsModuleOutput { // MARK: - TagSettingsModuleOutput extension DashboardPresenter: TagSettingsModuleOutput { - func tagSettingsDidDeleteTag(module: TagSettingsModuleInput, - ruuviTag _: RuuviTagSensor) - { + func tagSettingsDidDeleteTag( + module: TagSettingsModuleInput, + ruuviTag _: RuuviTagSensor + ) { module.dismiss(completion: { [weak self] in self?.startObservingRuuviTags() }) @@ -634,20 +642,23 @@ extension DashboardPresenter { } } - private func processAlert(record: RuuviTagSensorRecord, - viewModel: CardsViewModel) - { + private func processAlert( + record: RuuviTagSensorRecord, + viewModel: CardsViewModel + ) { if let isCloud = viewModel.isCloud.value, isCloud, - let macId = viewModel.mac.value - { - alertHandler.processNetwork(record: record, - trigger: false, - for: macId) + let macId = viewModel.mac.value { + alertHandler.processNetwork( + record: record, + trigger: false, + for: macId + ) } else { if viewModel.luid.value != nil { alertHandler.process(record: record, trigger: false) } else { - guard let macId = viewModel.mac.value else { + guard let macId = viewModel.mac.value + else { return } alertHandler.processNetwork(record: record, trigger: false, for: macId) @@ -778,8 +789,7 @@ extension DashboardPresenter { }.forEach { luid in heartbeatTokens.append(background.observe(self, uuid: luid.value) { [weak self] _, device in if let ruuviTag = device.ruuvi?.tag, - let viewModel = self?.viewModels.first(where: { $0.luid.value == ruuviTag.uuid.luid.any }) - { + let viewModel = self?.viewModels.first(where: { $0.luid.value == ruuviTag.uuid.luid.any }) { let sensorSettings = self?.sensorSettingsList .first(where: { ($0.luid?.any != nil && $0.luid?.any == viewModel.luid.value) @@ -810,12 +820,10 @@ extension DashboardPresenter { continue } if viewModel.type == .ruuvi, - let luid = viewModel.luid.value - { + let luid = viewModel.luid.value { advertisementTokens.append(foreground.observe(self, uuid: luid.value) { [weak self] _, device in if let ruuviTag = device.ruuvi?.tag, - let viewModel = self?.viewModels.first(where: { $0.luid.value == ruuviTag.uuid.luid.any }) - { + let viewModel = self?.viewModels.first(where: { $0.luid.value == ruuviTag.uuid.luid.any }) { let sensorSettings = self?.sensorSettingsList .first(where: { ($0.luid?.any != nil && $0.luid?.any == viewModel.luid.value) @@ -839,8 +847,7 @@ extension DashboardPresenter { sensorSettingsTokens.removeAll() for viewModel in viewModels { if viewModel.type == .ruuvi, - let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) - { + let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) { sensorSettingsTokens.append( ruuviReactor.observe(ruuviTagSensor) { [weak self] change in guard let sSelf = self else { return } @@ -898,7 +905,8 @@ extension DashboardPresenter { ) { let currentRecord = viewModel.latestMeasurement.value let updatedRecord = currentRecord?.with(sensorSettings: sensorSettings) - guard let updatedRecord else { + guard let updatedRecord + else { return } viewModel.update(updatedRecord) @@ -910,17 +918,15 @@ extension DashboardPresenter { ruuviTagObserveLastRecordTokens.removeAll() for viewModel in viewModels { if viewModel.type == .ruuvi, - let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) - { + let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) { let token = ruuviReactor.observeLatest(ruuviTagSensor) { [weak self] changes in if case let .update(anyRecord) = changes, let viewModel = self?.viewModels - .first(where: { - ($0.luid.value != nil && ($0.luid.value == anyRecord?.luid?.any)) - || ($0.mac.value != nil && ($0.mac.value == anyRecord?.macId?.any)) - }), - let record = anyRecord - { + .first(where: { + ($0.luid.value != nil && ($0.luid.value == anyRecord?.luid?.any)) + || ($0.mac.value != nil && ($0.mac.value == anyRecord?.macId?.any)) + }), + let record = anyRecord { let sensorSettings = self?.sensorSettingsList .first(where: { ($0.luid?.any != nil && $0.luid?.any == viewModel.luid.value) @@ -972,8 +978,7 @@ extension DashboardPresenter { let viewModel = sSelf.viewModels.first(where: { ($0.luid.value != nil && $0.luid.value == sensor.luid?.any) || ($0.mac.value != nil && $0.mac.value == sensor.macId?.any) - }) - { + }) { let op = sSelf.ruuviStorage.readLatest(sensor.any) op.on { [weak self] record in if let record { @@ -1006,8 +1011,7 @@ extension DashboardPresenter { where: { ($0.macId != nil && $0.macId?.any == sensor.macId?.any) || ($0.luid != nil && $0.luid?.any == sensor.luid?.any) - }) - { + }) { sSelf.ruuviTags[index] = sensor sSelf.syncViewModels() sSelf.restartObserveRuuviTagAdvertisements() @@ -1021,36 +1025,37 @@ extension DashboardPresenter { backgroundToken?.invalidate() backgroundToken = NotificationCenter .default - .addObserver(forName: .BackgroundPersistenceDidChangeBackground, - object: nil, - queue: .main) - { [weak self] notification in + .addObserver( + forName: .BackgroundPersistenceDidChangeBackground, + object: nil, + queue: .main + ) { [weak self] notification in - guard let sSelf = self else { return } - if let userInfo = notification.userInfo { - let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier - let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier - let viewModel = sSelf.view?.viewModels - .first(where: { $0.luid.value != nil && $0.luid.value == luid?.any }) - ?? sSelf.view?.viewModels - .first(where: { $0.mac.value != nil && $0.mac.value == macId?.any }) - if let viewModel { - let ruuviTag = sSelf.ruuviTags - .first(where: { $0.luid != nil && $0.luid?.any == luid?.any }) - ?? sSelf.ruuviTags - .first(where: { $0.macId != nil && $0.macId?.any == macId?.any }) - if let ruuviTag { - sSelf.ruuviSensorPropertiesService.getImage(for: ruuviTag) - .on(success: { image in - viewModel.background.value = image - self?.notifyViewModelUpdate(for: viewModel) - }, failure: { [weak self] error in - self?.errorPresenter.present(error: error) - }) + guard let sSelf = self else { return } + if let userInfo = notification.userInfo { + let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier + let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier + let viewModel = sSelf.view?.viewModels + .first(where: { $0.luid.value != nil && $0.luid.value == luid?.any }) + ?? sSelf.view?.viewModels + .first(where: { $0.mac.value != nil && $0.mac.value == macId?.any }) + if let viewModel { + let ruuviTag = sSelf.ruuviTags + .first(where: { $0.luid != nil && $0.luid?.any == luid?.any }) + ?? sSelf.ruuviTags + .first(where: { $0.macId != nil && $0.macId?.any == macId?.any }) + if let ruuviTag { + sSelf.ruuviSensorPropertiesService.getImage(for: ruuviTag) + .on(success: { image in + viewModel.background.value = image + self?.notifyViewModelUpdate(for: viewModel) + }, failure: { [weak self] error in + self?.errorPresenter.present(error: error) + }) + } } } } - } } // swiftlint:disable:next cyclomatic_complexity function_body_length @@ -1058,117 +1063,131 @@ extension DashboardPresenter { ruuviTagAdvertisementDaemonFailureToken?.invalidate() ruuviTagAdvertisementDaemonFailureToken = NotificationCenter .default - .addObserver(forName: .RuuviTagAdvertisementDaemonDidFail, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let error = userInfo[RuuviTagAdvertisementDaemonDidFailKey.error] as? RUError - { - self?.errorPresenter.present(error: error) - } - }) + .addObserver( + forName: .RuuviTagAdvertisementDaemonDidFail, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let error = userInfo[RuuviTagAdvertisementDaemonDidFailKey.error] as? RUError { + self?.errorPresenter.present(error: error) + } + } + ) ruuviTagPropertiesDaemonFailureToken?.invalidate() ruuviTagPropertiesDaemonFailureToken = NotificationCenter .default - .addObserver(forName: .RuuviTagPropertiesDaemonDidFail, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let error = userInfo[RuuviTagPropertiesDaemonDidFailKey.error] as? RUError - { - self?.errorPresenter.present(error: error) - } - }) + .addObserver( + forName: .RuuviTagPropertiesDaemonDidFail, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let error = userInfo[RuuviTagPropertiesDaemonDidFailKey.error] as? RUError { + self?.errorPresenter.present(error: error) + } + } + ) ruuviTagHeartbeatDaemonFailureToken?.invalidate() ruuviTagHeartbeatDaemonFailureToken = NotificationCenter .default - .addObserver(forName: .RuuviTagHeartbeatDaemonDidFail, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let error = userInfo[RuuviTagHeartbeatDaemonDidFailKey.error] as? RUError - { - self?.errorPresenter.present(error: error) - } - }) + .addObserver( + forName: .RuuviTagHeartbeatDaemonDidFail, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let error = userInfo[RuuviTagHeartbeatDaemonDidFailKey.error] as? RUError { + self?.errorPresenter.present(error: error) + } + } + ) ruuviTagReadLogsOperationFailureToken?.invalidate() ruuviTagReadLogsOperationFailureToken = NotificationCenter .default - .addObserver(forName: .RuuviTagReadLogsOperationDidFail, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let error = userInfo[RuuviTagReadLogsOperationDidFailKey.error] as? RUError - { - self?.errorPresenter.present(error: error) - } - }) + .addObserver( + forName: .RuuviTagReadLogsOperationDidFail, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let error = userInfo[RuuviTagReadLogsOperationDidFailKey.error] as? RUError { + self?.errorPresenter.present(error: error) + } + } + ) } func startObservingConnectionPersistenceNotifications() { startKeepingConnectionToken?.invalidate() startKeepingConnectionToken = NotificationCenter .default - .addObserver(forName: .ConnectionPersistenceDidStartToKeepConnection, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.observeRuuviTagHeartbeats() - }) + .addObserver( + forName: .ConnectionPersistenceDidStartToKeepConnection, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.observeRuuviTagHeartbeats() + } + ) stopKeepingConnectionToken?.invalidate() stopKeepingConnectionToken = NotificationCenter .default - .addObserver(forName: .ConnectionPersistenceDidStopToKeepConnection, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.observeRuuviTagHeartbeats() - }) + .addObserver( + forName: .ConnectionPersistenceDidStopToKeepConnection, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.observeRuuviTagHeartbeats() + } + ) } func startObservingDidConnectDisconnectNotifications() { didConnectToken?.invalidate() didConnectToken = NotificationCenter .default - .addObserver(forName: .BTBackgroundDidConnect, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let uuid = userInfo[BTBackgroundDidConnectKey.uuid] as? String, - let viewModel = self?.viewModels.first(where: { $0.luid.value == uuid.luid.any }) - { - viewModel.isConnected.value = true - self?.notifyViewModelUpdate(for: viewModel) - if let latestRecord = viewModel.latestMeasurement.value { - self?.processAlert(record: latestRecord, - viewModel: viewModel) - } - } - }) + .addObserver( + forName: .BTBackgroundDidConnect, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let uuid = userInfo[BTBackgroundDidConnectKey.uuid] as? String, + let viewModel = self?.viewModels.first(where: { $0.luid.value == uuid.luid.any }) { + viewModel.isConnected.value = true + self?.notifyViewModelUpdate(for: viewModel) + if let latestRecord = viewModel.latestMeasurement.value { + self?.processAlert( + record: latestRecord, + viewModel: viewModel + ) + } + } + } + ) didDisconnectToken?.invalidate() didDisconnectToken = NotificationCenter .default - .addObserver(forName: .BTBackgroundDidDisconnect, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let uuid = userInfo[BTBackgroundDidDisconnectKey.uuid] as? String, - let viewModel = self?.viewModels.first(where: { $0.luid.value == uuid.luid.any }) - { - viewModel.isConnected.value = false - self?.notifyViewModelUpdate(for: viewModel) - if let latestRecord = viewModel.latestMeasurement.value { - self?.processAlert(record: latestRecord, - viewModel: viewModel) - } - } - }) + .addObserver( + forName: .BTBackgroundDidDisconnect, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let uuid = userInfo[BTBackgroundDidDisconnectKey.uuid] as? String, + let viewModel = self?.viewModels.first(where: { $0.luid.value == uuid.luid.any }) { + viewModel.isConnected.value = false + self?.notifyViewModelUpdate(for: viewModel) + if let latestRecord = viewModel.latestMeasurement.value { + self?.processAlert( + record: latestRecord, + viewModel: viewModel + ) + } + } + } + ) } // swiftlint:disable:next function_body_length @@ -1176,43 +1195,49 @@ extension DashboardPresenter { alertDidChangeToken?.invalidate() alertDidChangeToken = NotificationCenter .default - .addObserver(forName: .RuuviServiceAlertDidChange, - object: nil, - queue: .main, - using: { [weak self] notification in - guard let sSelf = self else { return } - if let userInfo = notification.userInfo { - if let physicalSensor - = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor, - let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType - { - sSelf.viewModels.filter { - ($0.luid.value != nil && ($0.luid.value == physicalSensor.luid?.any)) - || ($0.mac.value != nil && ($0.mac.value == physicalSensor.macId?.any)) - }.forEach { viewModel in - if sSelf.alertService.hasRegistrations(for: physicalSensor) { - viewModel.rhAlertLowerBound.value = sSelf.alertService - .lowerRelativeHumidity(for: physicalSensor) - viewModel.rhAlertUpperBound.value = sSelf.alertService - .upperRelativeHumidity(for: physicalSensor) - - } else { - viewModel.rhAlertLowerBound.value = 0 - viewModel.rhAlertUpperBound.value = 100 - } - sSelf.syncAlerts(ruuviTag: physicalSensor, - viewModel: viewModel) - sSelf.updateIsOnState(of: type, - for: physicalSensor.id, - viewModel: viewModel) - sSelf.updateMutedTill(of: type, - for: physicalSensor.id, - viewModel: viewModel) - sSelf.triggerAlertsIfNeeded() - } - } - } - }) + .addObserver( + forName: .RuuviServiceAlertDidChange, + object: nil, + queue: .main, + using: { [weak self] notification in + guard let sSelf = self else { return } + if let userInfo = notification.userInfo { + if let physicalSensor + = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor, + let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType { + sSelf.viewModels.filter { + ($0.luid.value != nil && ($0.luid.value == physicalSensor.luid?.any)) + || ($0.mac.value != nil && ($0.mac.value == physicalSensor.macId?.any)) + }.forEach { viewModel in + if sSelf.alertService.hasRegistrations(for: physicalSensor) { + viewModel.rhAlertLowerBound.value = sSelf.alertService + .lowerRelativeHumidity(for: physicalSensor) + viewModel.rhAlertUpperBound.value = sSelf.alertService + .upperRelativeHumidity(for: physicalSensor) + } else { + viewModel.rhAlertLowerBound.value = 0 + viewModel.rhAlertUpperBound.value = 100 + } + sSelf.syncAlerts( + ruuviTag: physicalSensor, + viewModel: viewModel + ) + sSelf.updateIsOnState( + of: type, + for: physicalSensor.id, + viewModel: viewModel + ) + sSelf.updateMutedTill( + of: type, + for: physicalSensor.id, + viewModel: viewModel + ) + sSelf.triggerAlertsIfNeeded() + } + } + } + } + ) } private func startListeningToRuuviTagsAlertStatus() { @@ -1266,30 +1291,34 @@ extension DashboardPresenter { } private func openCardView(viewModel: CardsViewModel, showCharts: Bool) { - router.openCardImageView(with: viewModels, - ruuviTagSensors: ruuviTags, - sensorSettings: sensorSettingsList, - scrollTo: viewModel, - showCharts: showCharts, - output: self) + router.openCardImageView( + with: viewModels, + ruuviTagSensors: ruuviTags, + sensorSettings: sensorSettingsList, + scrollTo: viewModel, + showCharts: showCharts, + output: self + ) } private func startObservingUniversalLinks() { universalLinkObservationToken = NotificationCenter .default - .addObserver(forName: .DidOpenWithUniversalLink, - object: nil, - queue: .main, - using: { [weak self] notification in - guard let self, - let userInfo = notification.userInfo - else { - guard let email = self?.ruuviUser.email else { return } - self?.view?.showAlreadyLoggedInAlert(with: email) - return - } - processLink(userInfo) - }) + .addObserver( + forName: .DidOpenWithUniversalLink, + object: nil, + queue: .main, + using: { [weak self] notification in + guard let self, + let userInfo = notification.userInfo + else { + guard let email = self?.ruuviUser.email else { return } + self?.view?.showAlreadyLoggedInAlert(with: email) + return + } + processLink(userInfo) + } + ) } private func processLink(_ userInfo: [AnyHashable: Any]) { @@ -1303,12 +1332,14 @@ extension DashboardPresenter { cloudModeToken?.invalidate() cloudModeToken = NotificationCenter .default - .addObserver(forName: .CloudModeDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.handleCloudModeState() - }) + .addObserver( + forName: .CloudModeDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.handleCloudModeState() + } + ) } /// The method handles all the operations when cloud mode toggle is turned on/off @@ -1335,94 +1366,110 @@ extension DashboardPresenter { private func startListeningToSettings() { temperatureUnitToken = NotificationCenter .default - .addObserver(forName: .TemperatureUnitDidChange, - object: nil, - queue: .main) - { [weak self] _ in - self?.syncAppSettingsToAppGroupContainer() - } + .addObserver( + forName: .TemperatureUnitDidChange, + object: nil, + queue: .main + ) { [weak self] _ in + self?.syncAppSettingsToAppGroupContainer() + } temperatureAccuracyToken = NotificationCenter .default - .addObserver(forName: .TemperatureAccuracyDidChange, - object: nil, - queue: .main) - { [weak self] _ in - self?.syncAppSettingsToAppGroupContainer() - } + .addObserver( + forName: .TemperatureAccuracyDidChange, + object: nil, + queue: .main + ) { [weak self] _ in + self?.syncAppSettingsToAppGroupContainer() + } humidityUnitToken = NotificationCenter .default - .addObserver(forName: .HumidityUnitDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.syncAppSettingsToAppGroupContainer() - }) + .addObserver( + forName: .HumidityUnitDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.syncAppSettingsToAppGroupContainer() + } + ) humidityAccuracyToken = NotificationCenter .default - .addObserver(forName: .HumidityAccuracyDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.syncAppSettingsToAppGroupContainer() - }) + .addObserver( + forName: .HumidityAccuracyDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.syncAppSettingsToAppGroupContainer() + } + ) pressureUnitToken = NotificationCenter .default - .addObserver(forName: .PressureUnitDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.syncAppSettingsToAppGroupContainer() - }) + .addObserver( + forName: .PressureUnitDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.syncAppSettingsToAppGroupContainer() + } + ) pressureAccuracyToken = NotificationCenter .default - .addObserver(forName: .PressureUnitAccuracyChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.syncAppSettingsToAppGroupContainer() - }) + .addObserver( + forName: .PressureUnitAccuracyChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.syncAppSettingsToAppGroupContainer() + } + ) languageToken = NotificationCenter .default - .addObserver(forName: .LanguageDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.syncAppSettingsToAppGroupContainer() - }) + .addObserver( + forName: .LanguageDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.syncAppSettingsToAppGroupContainer() + } + ) systemLanguageChangeToken = NotificationCenter .default - .addObserver(forName: NSLocale.currentLocaleDidChangeNotification, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.systemLocaleDidChange() - }) + .addObserver( + forName: NSLocale.currentLocaleDidChangeNotification, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.systemLocaleDidChange() + } + ) dashboardTypeToken = NotificationCenter .default - .addObserver(forName: .DashboardTypeDidChange, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let type = userInfo[DashboardTypeKey.type] as? DashboardType - { - self?.view?.dashboardType = type - } - }) + .addObserver( + forName: .DashboardTypeDidChange, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let type = userInfo[DashboardTypeKey.type] as? DashboardType { + self?.view?.dashboardType = type + } + } + ) dashboardTapActionTypeToken = NotificationCenter .default - .addObserver(forName: .DashboardTapActionTypeDidChange, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let type = userInfo[DashboardTapActionTypeKey.type] as? - DashboardTapActionType - { - self?.view?.dashboardTapActionType = type - } - }) + .addObserver( + forName: .DashboardTapActionTypeDidChange, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let type = userInfo[DashboardTapActionTypeKey.type] as? + DashboardTapActionType { + self?.view?.dashboardTapActionType = type + } + } + ) } private func startObservingCloudSyncSuccessTokenState() { @@ -1430,12 +1477,14 @@ extension DashboardPresenter { cloudSyncSuccessStateToken = nil cloudSyncSuccessStateToken = NotificationCenter .default - .addObserver(forName: .NetworkSyncDidComplete, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.triggerAlertsIfNeeded() - }) + .addObserver( + forName: .NetworkSyncDidComplete, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.triggerAlertsIfNeeded() + } + ) } private func startObservingCloudSyncFailTokenState() { @@ -1443,12 +1492,14 @@ extension DashboardPresenter { cloudSyncFailStateToken = nil cloudSyncFailStateToken = NotificationCenter .default - .addObserver(forName: .NetworkSyncDidFailForAuthorization, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.forceLogoutUser() - }) + .addObserver( + forName: .NetworkSyncDidFailForAuthorization, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.forceLogoutUser() + } + ) } @objc private func systemLocaleDidChange() { @@ -1471,13 +1522,15 @@ extension DashboardPresenter { private func startObserveCalibrationSettingsChange() { calibrationSettingsToken = NotificationCenter .default - .addObserver(forName: .SensorCalibrationDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - guard let sSelf = self else { return } - sSelf.restartObservingRuuviTagLastRecords() - }) + .addObserver( + forName: .SensorCalibrationDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + guard let sSelf = self else { return } + sSelf.restartObservingRuuviTagLastRecords() + } + ) } private func checkFirmwareVersion(for ruuviTag: RuuviTagSensor) { @@ -1534,98 +1587,117 @@ extension DashboardPresenter { } } - private func sync(temperature: AlertType, - ruuviTag: PhysicalSensor, - viewModel: CardsViewModel) - { + private func sync( + temperature: AlertType, + ruuviTag: PhysicalSensor, + viewModel: CardsViewModel + ) { if case .temperature = alertService - .alert(for: ruuviTag, of: temperature) - { + .alert(for: ruuviTag, of: temperature) { viewModel.isTemperatureAlertOn.value = true } else { viewModel.isTemperatureAlertOn.value = false } viewModel.temperatureAlertMutedTill.value = alertService - .mutedTill(type: temperature, - for: ruuviTag) + .mutedTill( + type: temperature, + for: ruuviTag + ) } - private func sync(relativeHumidity: AlertType, - ruuviTag: PhysicalSensor, - viewModel: CardsViewModel) - { - if case .relativeHumidity = alertService.alert(for: ruuviTag, - of: relativeHumidity) - { + private func sync( + relativeHumidity: AlertType, + ruuviTag: PhysicalSensor, + viewModel: CardsViewModel + ) { + if case .relativeHumidity = alertService.alert( + for: ruuviTag, + of: relativeHumidity + ) { viewModel.isRelativeHumidityAlertOn.value = true } else { viewModel.isRelativeHumidityAlertOn.value = false } viewModel.relativeHumidityAlertMutedTill.value = alertService - .mutedTill(type: relativeHumidity, - for: ruuviTag) + .mutedTill( + type: relativeHumidity, + for: ruuviTag + ) } - private func sync(pressure: AlertType, - ruuviTag: PhysicalSensor, - viewModel: CardsViewModel) - { + private func sync( + pressure: AlertType, + ruuviTag: PhysicalSensor, + viewModel: CardsViewModel + ) { if case .pressure = alertService.alert(for: ruuviTag, of: pressure) { viewModel.isPressureAlertOn.value = true } else { viewModel.isPressureAlertOn.value = false } viewModel.pressureAlertMutedTill.value = alertService - .mutedTill(type: pressure, - for: ruuviTag) + .mutedTill( + type: pressure, + for: ruuviTag + ) } - private func sync(signal: AlertType, - ruuviTag: PhysicalSensor, - viewModel: CardsViewModel) - { + private func sync( + signal: AlertType, + ruuviTag: PhysicalSensor, + viewModel: CardsViewModel + ) { if case .signal = alertService.alert(for: ruuviTag, of: signal) { viewModel.isSignalAlertOn.value = true } else { viewModel.isSignalAlertOn.value = false } viewModel.signalAlertMutedTill.value = - alertService.mutedTill(type: signal, - for: ruuviTag) + alertService.mutedTill( + type: signal, + for: ruuviTag + ) } - private func sync(connection: AlertType, - ruuviTag: PhysicalSensor, - viewModel: CardsViewModel) - { + private func sync( + connection: AlertType, + ruuviTag: PhysicalSensor, + viewModel: CardsViewModel + ) { if case .connection = alertService.alert(for: ruuviTag, of: connection) { viewModel.isConnectionAlertOn.value = true } else { viewModel.isConnectionAlertOn.value = false } viewModel.connectionAlertMutedTill.value = alertService - .mutedTill(type: connection, - for: ruuviTag) + .mutedTill( + type: connection, + for: ruuviTag + ) } - private func sync(movement: AlertType, - ruuviTag: PhysicalSensor, - viewModel: CardsViewModel) - { + private func sync( + movement: AlertType, + ruuviTag: PhysicalSensor, + viewModel: CardsViewModel + ) { if case .movement = alertService.alert(for: ruuviTag, of: movement) { viewModel.isMovementAlertOn.value = true } else { viewModel.isMovementAlertOn.value = false } viewModel.movementAlertMutedTill.value = alertService - .mutedTill(type: movement, - for: ruuviTag) + .mutedTill( + type: movement, + for: ruuviTag + ) } - private func sync(cloudConnection: AlertType, - ruuviTag: PhysicalSensor, - viewModel: CardsViewModel) - { + private func sync( + cloudConnection: AlertType, + ruuviTag: PhysicalSensor, + viewModel: CardsViewModel + ) { if case .cloudConnection = alertService.alert(for: ruuviTag, of: cloudConnection) { viewModel.isCloudConnectionAlertOn.value = true } else { @@ -1636,38 +1708,32 @@ extension DashboardPresenter { private func reloadMutedTill() { for viewModel in viewModels { if let mutedTill = viewModel.temperatureAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.temperatureAlertMutedTill.value = nil } if let mutedTill = viewModel.relativeHumidityAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.relativeHumidityAlertMutedTill.value = nil } if let mutedTill = viewModel.pressureAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.pressureAlertMutedTill.value = nil } if let mutedTill = viewModel.signalAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.signalAlertMutedTill.value = nil } if let mutedTill = viewModel.connectionAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.connectionAlertMutedTill.value = nil } if let mutedTill = viewModel.movementAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.movementAlertMutedTill.value = nil } @@ -1675,10 +1741,11 @@ extension DashboardPresenter { } } - private func updateMutedTill(of type: AlertType, - for uuid: String, - viewModel: CardsViewModel) - { + private func updateMutedTill( + of type: AlertType, + for uuid: String, + viewModel: CardsViewModel + ) { var observable: Observable = switch type { case .temperature: viewModel.temperatureAlertMutedTill @@ -1704,10 +1771,11 @@ extension DashboardPresenter { notifyViewModelUpdate(for: viewModel) } - private func updateIsOnState(of type: AlertType, - for uuid: String, - viewModel: CardsViewModel) - { + private func updateIsOnState( + of type: AlertType, + for uuid: String, + viewModel: CardsViewModel + ) { var observable: Observable = switch type { case .temperature: viewModel.isTemperatureAlertOn @@ -1777,24 +1845,29 @@ extension DashboardPresenter { // Notify daemon to restart NotificationCenter .default - .post(name: .RuuviTagAdvertisementDaemonShouldRestart, - object: nil, - userInfo: nil) + .post( + name: .RuuviTagAdvertisementDaemonShouldRestart, + object: nil, + userInfo: nil + ) } private func notifyRestartHeartBeatDaemon() { // Notify daemon to restart NotificationCenter .default - .post(name: .RuuviTagHeartBeatDaemonShouldRestart, - object: nil, - userInfo: nil) + .post( + name: .RuuviTagHeartBeatDaemonShouldRestart, + object: nil, + userInfo: nil + ) } private func triggerAlertsIfNeeded() { for viewModel in viewModels { if let latestRecord = viewModel.latestMeasurement.value { - guard let macId = viewModel.mac.value else { + guard let macId = viewModel.mac.value + else { continue } alertHandler.processNetwork( diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift index 664730b1a..ba01991fa 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift @@ -57,21 +57,24 @@ class DashboardRouter: NSObject, DashboardRouterInput { } func openWhatToMeasurePage() { - guard let url = URL(string: RuuviLocalization.Menu.Measure.Url.ios) else { + guard let url = URL(string: RuuviLocalization.Menu.Measure.Url.ios) + else { return } UIApplication.shared.open(url, options: [:], completionHandler: nil) } func openRuuviProductsPage() { - guard let url = URL(string: RuuviLocalization.Ruuvi.BuySensors.Url.ios) else { + guard let url = URL(string: RuuviLocalization.Ruuvi.BuySensors.Url.ios) + else { return } UIApplication.shared.open(url, options: [:], completionHandler: nil) } func openRuuviProductsPageFromMenu() { - guard let url = URL(string: RuuviLocalization.Ruuvi.BuySensors.Menu.Url.ios) else { + guard let url = URL(string: RuuviLocalization.Ruuvi.BuySensors.Menu.Url.ios) + else { return } UIApplication.shared.open(url, options: [:], completionHandler: nil) @@ -92,11 +95,12 @@ class DashboardRouter: NSObject, DashboardRouterInput { AppUtility.lockOrientation(.portrait) } - func openTagSettings(ruuviTag: RuuviTagSensor, - latestMeasurement: RuuviTagSensorRecord?, - sensorSettings: SensorSettings?, - output: TagSettingsModuleOutput) - { + func openTagSettings( + ruuviTag: RuuviTagSensor, + latestMeasurement: RuuviTagSensorRecord?, + sensorSettings: SensorSettings?, + output: TagSettingsModuleOutput + ) { let factory: TagSettingsModuleFactory = TagSettingsModuleFactoryImpl() let module = factory.create() transitionHandler @@ -107,20 +111,23 @@ class DashboardRouter: NSObject, DashboardRouterInput { ) if let presenter = module.output as? TagSettingsModuleInput { presenter.configure(output: output) - presenter.configure(ruuviTag: ruuviTag, - latestMeasurement: latestMeasurement, - sensorSettings: sensorSettings) + presenter.configure( + ruuviTag: ruuviTag, + latestMeasurement: latestMeasurement, + sensorSettings: sensorSettings + ) } } // swiftlint:disable:next function_parameter_count - func openCardImageView(with viewModels: [CardsViewModel], - ruuviTagSensors: [AnyRuuviTagSensor], - sensorSettings: [SensorSettings], - scrollTo: CardsViewModel?, - showCharts: Bool, - output: CardsModuleOutput) - { + func openCardImageView( + with viewModels: [CardsViewModel], + ruuviTagSensors: [AnyRuuviTagSensor], + sensorSettings: [SensorSettings], + scrollTo: CardsViewModel?, + showCharts: Bool, + output: CardsModuleOutput + ) { let factory: CardsViewModuleFactory = CardsViewModuleFactoryImpl() let module = factory.create() if let output = module.output as? CardsModuleInput { @@ -130,8 +137,7 @@ class DashboardRouter: NSObject, DashboardRouterInput { // Remove any cards view controller from stack if exists already if let navigationController = transitionHandler.navigationController, navigationController - .containsViewController(ofKind: CardsViewController.self) - { + .containsViewController(ofKind: CardsViewController.self) { transitionHandler .navigationController? .removeAnyViewControllers(ofKind: CardsViewController.self) @@ -145,24 +151,29 @@ class DashboardRouter: NSObject, DashboardRouterInput { ) if let cards { cards.configure(output: output) - cards.configure(viewModels: viewModels, - ruuviTagSensors: ruuviTagSensors, - sensorSettings: sensorSettings) - cards.configure(scrollTo: scrollTo, - openChart: showCharts) + cards.configure( + viewModels: viewModels, + ruuviTagSensors: ruuviTagSensors, + sensorSettings: sensorSettings + ) + cards.configure( + scrollTo: scrollTo, + openChart: showCharts + ) } } // swiftlint:disable:next function_parameter_count - func openTagSettings(with viewModels: [CardsViewModel], - ruuviTagSensors: [AnyRuuviTagSensor], - sensorSettings: [SensorSettings], - scrollTo: CardsViewModel?, - ruuviTag: RuuviTagSensor, - latestMeasurement: RuuviTagSensorRecord?, - sensorSetting: SensorSettings?, - output: CardsModuleOutput) - { + func openTagSettings( + with viewModels: [CardsViewModel], + ruuviTagSensors: [AnyRuuviTagSensor], + sensorSettings: [SensorSettings], + scrollTo: CardsViewModel?, + ruuviTag: RuuviTagSensor, + latestMeasurement: RuuviTagSensorRecord?, + sensorSetting: SensorSettings?, + output: CardsModuleOutput + ) { let cardsFactory: CardsViewModuleFactory = CardsViewModuleFactoryImpl() let cardsModule = cardsFactory.create() @@ -171,26 +182,31 @@ class DashboardRouter: NSObject, DashboardRouterInput { if let cardsPresenter = cardsModule.output as? CardsModuleInput, let cardsPresenterOutput = cardsPresenter as? TagSettingsModuleOutput, - let settingsPresenter = settingsModule.output as? TagSettingsModuleInput - { + let settingsPresenter = settingsModule.output as? TagSettingsModuleInput { cardsPresenter.configure(output: output) - cardsPresenter.configure(viewModels: viewModels, - ruuviTagSensors: ruuviTagSensors, - sensorSettings: sensorSettings) - cardsPresenter.configure(scrollTo: scrollTo, - openChart: false) + cardsPresenter.configure( + viewModels: viewModels, + ruuviTagSensors: ruuviTagSensors, + sensorSettings: sensorSettings + ) + cardsPresenter.configure( + scrollTo: scrollTo, + openChart: false + ) if let cardsOutput = cardsModule as? CardsViewOutput { cardsOutput.viewDidLoad() } settingsPresenter.configure(output: cardsPresenterOutput) - settingsPresenter.configure(ruuviTag: ruuviTag, - latestMeasurement: latestMeasurement, - sensorSettings: sensorSetting) + settingsPresenter.configure( + ruuviTag: ruuviTag, + latestMeasurement: latestMeasurement, + sensorSettings: sensorSetting + ) } transitionHandler.navigationController?.setViewControllers([ - transitionHandler, cardsModule, settingsModule, + transitionHandler, cardsModule, settingsModule ], animated: true) } @@ -233,8 +249,10 @@ class DashboardRouter: NSObject, DashboardRouterInput { let restorationId = "ShareViewController" let factory = StoryboardFactory(storyboardName: "Share", bundle: .main, restorationId: restorationId) try! transitionHandler - .forStoryboard(factory: factory, - to: ShareModuleInput.self) + .forStoryboard( + factory: factory, + to: ShareModuleInput.self + ) .to(preferred: .navigation(style: .push)) .then { module -> Any? in module.configure(sensor: sensor) diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift index 21b3c4425..a3a896ae0 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift @@ -125,123 +125,155 @@ class DashboardImageCell: UICollectionViewCell { // swiftlint:disable:next function_body_length fileprivate func setUpUI() { - let container = UIView(color: RuuviColor.dashboardCardBGColor, - cornerRadius: 8) + let container = UIView( + color: RuuviColor.dashboardCardBGColor, + cornerRadius: 8 + ) contentView.addSubview(container) container.fillSuperview() container.addSubview(cardBackgroundView) - cardBackgroundView.anchor(top: container.topAnchor, - leading: container.leadingAnchor, - bottom: container.bottomAnchor, - trailing: nil) + cardBackgroundView.anchor( + top: container.topAnchor, + leading: container.leadingAnchor, + bottom: container.bottomAnchor, + trailing: nil + ) cardBackgroundView.widthAnchor.constraint( equalTo: container.widthAnchor, multiplier: 0.25 ).isActive = true container.addSubview(ruuviTagNameLabel) - ruuviTagNameLabel.anchor(top: container.topAnchor, - leading: cardBackgroundView.trailingAnchor, - bottom: nil, - trailing: nil, - padding: .init(top: 8, left: 8, bottom: 0, right: 0)) + ruuviTagNameLabel.anchor( + top: container.topAnchor, + leading: cardBackgroundView.trailingAnchor, + bottom: nil, + trailing: nil, + padding: .init(top: 8, left: 8, bottom: 0, right: 0) + ) ruuviTagNameLabel.heightAnchor.constraint( greaterThanOrEqualToConstant: 14 ).isActive = true container.addSubview(alertIcon) - alertIcon.anchor(top: ruuviTagNameLabel.topAnchor, - leading: ruuviTagNameLabel.trailingAnchor, - bottom: nil, - trailing: nil, - padding: .init(top: 4, left: 12, bottom: 0, right: 0), - size: .init(width: 18, height: 18)) + alertIcon.anchor( + top: ruuviTagNameLabel.topAnchor, + leading: ruuviTagNameLabel.trailingAnchor, + bottom: nil, + trailing: nil, + padding: .init(top: 4, left: 12, bottom: 0, right: 0), + size: .init(width: 18, height: 18) + ) container.addSubview(alertButton) alertButton.match(view: alertIcon) container.addSubview(moreIcon) - moreIcon.anchor(top: alertIcon.topAnchor, - leading: alertIcon.trailingAnchor, - bottom: nil, - trailing: container.trailingAnchor, - padding: .init(top: 0, left: 10, bottom: 0, right: 14), - size: .init(width: 18, height: 18)) + moreIcon.anchor( + top: alertIcon.topAnchor, + leading: alertIcon.trailingAnchor, + bottom: nil, + trailing: container.trailingAnchor, + padding: .init(top: 0, left: 10, bottom: 0, right: 14), + size: .init(width: 18, height: 18) + ) container.addSubview(moreButton) moreButton.match(view: moreIcon) container.addSubview(temperatureLabel) - temperatureLabel.anchor(top: ruuviTagNameLabel.bottomAnchor, - leading: ruuviTagNameLabel.leadingAnchor, - bottom: nil, - trailing: nil, - padding: .init(top: -4, left: 0, bottom: 0, right: 0)) + temperatureLabel.anchor( + top: ruuviTagNameLabel.bottomAnchor, + leading: ruuviTagNameLabel.leadingAnchor, + bottom: nil, + trailing: nil, + padding: .init(top: -4, left: 0, bottom: 0, right: 0) + ) container.addSubview(temperatureUnitLabel) - temperatureUnitLabel.anchor(top: temperatureLabel.topAnchor, - leading: temperatureLabel.trailingAnchor, - bottom: nil, - trailing: nil, - padding: .init(top: 6, - left: 2, - bottom: 0, - right: 0)) + temperatureUnitLabel.anchor( + top: temperatureLabel.topAnchor, + leading: temperatureLabel.trailingAnchor, + bottom: nil, + trailing: nil, + padding: .init( + top: 6, + left: 2, + bottom: 0, + right: 0 + ) + ) let leftContainerView = UIView() container.addSubview(leftContainerView) - leftContainerView.anchor(top: nil, - leading: ruuviTagNameLabel.leadingAnchor, - bottom: nil, - trailing: nil, - padding: .init(top: 4, - left: 0, - bottom: 0, - right: 0)) + leftContainerView.anchor( + top: nil, + leading: ruuviTagNameLabel.leadingAnchor, + bottom: nil, + trailing: nil, + padding: .init( + top: 4, + left: 0, + bottom: 0, + right: 0 + ) + ) leftContainerView.addSubview(humidityView) - humidityView.anchor(top: leftContainerView.topAnchor, - leading: leftContainerView.leadingAnchor, - bottom: nil, - trailing: leftContainerView.trailingAnchor) + humidityView.anchor( + top: leftContainerView.topAnchor, + leading: leftContainerView.leadingAnchor, + bottom: nil, + trailing: leftContainerView.trailingAnchor + ) humidityViewHeight = humidityView.heightAnchor.constraint(equalToConstant: indicatorViewHeight()) humidityViewHeight.isActive = true leftContainerView.addSubview(movementView) - movementView.anchor(top: humidityView.bottomAnchor, - leading: leftContainerView.leadingAnchor, - bottom: leftContainerView.bottomAnchor, - trailing: leftContainerView.trailingAnchor) + movementView.anchor( + top: humidityView.bottomAnchor, + leading: leftContainerView.leadingAnchor, + bottom: leftContainerView.bottomAnchor, + trailing: leftContainerView.trailingAnchor + ) movementViewHeight = movementView.heightAnchor.constraint(equalToConstant: indicatorViewHeight()) movementViewHeight.isActive = true let rightContainerView = UIView() container.addSubview(rightContainerView) - rightContainerView.anchor(top: nil, - leading: leftContainerView.trailingAnchor, - bottom: leftContainerView.bottomAnchor, - trailing: container.trailingAnchor, - padding: .init(top: 0, - left: 4, - bottom: 0, - right: 4)) + rightContainerView.anchor( + top: nil, + leading: leftContainerView.trailingAnchor, + bottom: leftContainerView.bottomAnchor, + trailing: container.trailingAnchor, + padding: .init( + top: 0, + left: 4, + bottom: 0, + right: 4 + ) + ) rightContainerView.addSubview(pressureView) - pressureView.anchor(top: rightContainerView.topAnchor, - leading: rightContainerView.leadingAnchor, - bottom: nil, - trailing: rightContainerView.trailingAnchor) + pressureView.anchor( + top: rightContainerView.topAnchor, + leading: rightContainerView.leadingAnchor, + bottom: nil, + trailing: rightContainerView.trailingAnchor + ) pressureViewHeight = pressureView.heightAnchor.constraint(equalToConstant: indicatorViewHeight()) pressureViewHeight.isActive = true let emptySpacer = UIView() emptySpacer.backgroundColor = .clear rightContainerView.addSubview(emptySpacer) - emptySpacer.anchor(top: pressureView.bottomAnchor, - leading: rightContainerView.leadingAnchor, - bottom: rightContainerView.bottomAnchor, - trailing: rightContainerView.trailingAnchor) + emptySpacer.anchor( + top: pressureView.bottomAnchor, + leading: rightContainerView.leadingAnchor, + bottom: rightContainerView.bottomAnchor, + trailing: rightContainerView.trailingAnchor + ) emptyViewHeight = emptySpacer.heightAnchor.constraint(equalToConstant: indicatorViewHeight()) emptyViewHeight.isActive = true @@ -251,7 +283,7 @@ class DashboardImageCell: UICollectionViewCell { .isActive = true let sourceAndUpdateStack = UIStackView(arrangedSubviews: [ - dataSourceIconView, updatedAtLabel, + dataSourceIconView, updatedAtLabel ]) sourceAndUpdateStack.axis = .horizontal sourceAndUpdateStack.spacing = 6 @@ -263,21 +295,25 @@ class DashboardImageCell: UICollectionViewCell { dataSourceIconViewWidthConstraint.isActive = true let footerStack = UIStackView(arrangedSubviews: [ - sourceAndUpdateStack, batteryLevelView, + sourceAndUpdateStack, batteryLevelView ]) footerStack.spacing = 4 footerStack.axis = .horizontal footerStack.distribution = .fillProportionally container.addSubview(footerStack) - footerStack.anchor(top: leftContainerView.bottomAnchor, - leading: ruuviTagNameLabel.leadingAnchor, - bottom: container.bottomAnchor, - trailing: container.trailingAnchor, - padding: .init(top: 4, - left: 0, - bottom: 6, - right: 12)) + footerStack.anchor( + top: leftContainerView.bottomAnchor, + leading: ruuviTagNameLabel.leadingAnchor, + bottom: container.bottomAnchor, + trailing: container.trailingAnchor, + padding: .init( + top: 4, + left: 0, + bottom: 6, + right: 12 + ) + ) batteryLevelView.isHidden = true } } @@ -304,14 +340,17 @@ extension DashboardImageCell { extension DashboardImageCell { // swiftlint:disable:next function_body_length cyclomatic_complexity - func configure(with viewModel: CardsViewModel, - measurementService: RuuviServiceMeasurement?) - { + func configure( + with viewModel: CardsViewModel, + measurementService: RuuviServiceMeasurement? + ) { self.viewModel = viewModel cardBackgroundView - .setBackgroundImage(with: viewModel.background.value, - withAnimation: false) + .setBackgroundImage( + with: viewModel.background.value, + withAnimation: false + ) // Name ruuviTagNameLabel.text = viewModel.name.value @@ -331,8 +370,7 @@ extension DashboardImageCell { // Humidity if let humidity = viewModel.humidity.value, - let measurementService - { + let measurementService { hideHumidityView(hide: false) let humidityValue = measurementService.stringWithoutSign( for: humidity, @@ -343,8 +381,10 @@ extension DashboardImageCell { let temperatureUnitSymbol = measurementService.units.temperatureUnit.symbol let unit = humidityUnit == .dew ? temperatureUnitSymbol : humidityUnitSymbol - humidityView.setValue(with: humidityValue, - unit: unit) + humidityView.setValue( + with: humidityValue, + unit: unit + ) } else { hideHumidityView(hide: true) } @@ -353,8 +393,10 @@ extension DashboardImageCell { if let pressure = viewModel.pressure.value { hidePressureView(hide: false) let pressureValue = measurementService?.stringWithoutSign(for: pressure) - pressureView.setValue(with: pressureValue, - unit: measurementService?.units.pressureUnit.symbol) + pressureView.setValue( + with: pressureValue, + unit: measurementService?.units.pressureUnit.symbol + ) } else { hidePressureView(hide: true) } @@ -364,8 +406,10 @@ extension DashboardImageCell { case .ruuvi: if let movement = viewModel.movementCounter.value { hideMovementView(hide: false) - movementView.setValue(with: "\(movement)", - unit: RuuviLocalization.Cards.Movements.title) + movementView.setValue( + with: "\(movement)", + unit: RuuviLocalization.Cards.Movements.title + ) } else { hideMovementView(hide: true) } @@ -412,8 +456,7 @@ extension DashboardImageCell { // Battery state if let batteryLow = viewModel.batteryNeedsReplacement.value, - batteryLow - { + batteryLow { batteryLevelView.isHidden = false } else { batteryLevelView.isHidden = true @@ -442,32 +485,28 @@ extension DashboardImageCell { } if let isOn = viewModel.isTemperatureAlertOn.value, isOn, - let temperatureAlertState = viewModel.temperatureAlertState.value - { + let temperatureAlertState = viewModel.temperatureAlertState.value { highlightTemperatureValues(highlight: temperatureAlertState == .firing) } else { highlightTemperatureValues(highlight: false) } if let isOn = viewModel.isRelativeHumidityAlertOn.value, isOn, - let rhAlertState = viewModel.relativeHumidityAlertState.value - { + let rhAlertState = viewModel.relativeHumidityAlertState.value { humidityView.changeColor(highlight: rhAlertState == .firing) } else { humidityView.changeColor(highlight: false) } if let isOn = viewModel.isPressureAlertOn.value, isOn, - let pressureAlertState = viewModel.pressureAlertState.value - { + let pressureAlertState = viewModel.pressureAlertState.value { pressureView.changeColor(highlight: pressureAlertState == .firing) } else { pressureView.changeColor(highlight: false) } if let isOn = viewModel.isMovementAlertOn.value, isOn, - let movementAlertState = viewModel.movementAlertState.value - { + let movementAlertState = viewModel.movementAlertState.value { movementView.changeColor(highlight: movementAlertState == .firing) } else { movementView.changeColor(highlight: false) @@ -498,13 +537,17 @@ extension DashboardImageCell { alertIcon.image = RuuviAssets.alertActiveImage } DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - UIView.animate(withDuration: 0.5, - delay: 0, - options: [.repeat, - .autoreverse], - animations: { [weak self] in - self?.alertIcon.alpha = 0.0 - }) + UIView.animate( + withDuration: 0.5, + delay: 0, + options: [ + .repeat, + .autoreverse, + ], + animations: { [weak self] in + self?.alertIcon.alpha = 0.0 + } + ) } } } else { @@ -527,15 +570,17 @@ extension DashboardImageCell { timer?.invalidate() timer = nil - timer = Timer.scheduledTimer(withTimeInterval: 1, - repeats: true, - block: { [weak self] _ in - if let date = date?.ruuviAgo() { - self?.updatedAtLabel.text = date - } else { - self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message - } - }) + timer = Timer.scheduledTimer( + withTimeInterval: 1, + repeats: true, + block: { [weak self] _ in + if let date = date?.ruuviAgo() { + self?.updatedAtLabel.text = date + } else { + self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message + } + } + ) } private func hideHumidityView(hide: Bool) { @@ -573,7 +618,8 @@ extension DashboardImageCell { } @objc private func alertButtonDidTap() { - guard let viewModel else { + guard let viewModel + else { return } delegate?.didTapAlertButton(for: viewModel) diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift index 3d12fe7b9..fd974bed6 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift @@ -33,20 +33,26 @@ class DashboardIndicatorView: UIView { fileprivate func setUpUI() { addSubview(indicatorValueLabel) - indicatorValueLabel.anchor(top: topAnchor, - leading: leadingAnchor, - bottom: bottomAnchor, - trailing: nil) + indicatorValueLabel.anchor( + top: topAnchor, + leading: leadingAnchor, + bottom: bottomAnchor, + trailing: nil + ) addSubview(indicatorUnitLabel) - indicatorUnitLabel.anchor(top: nil, - leading: indicatorValueLabel.trailingAnchor, - bottom: indicatorValueLabel.bottomAnchor, - trailing: nil, - padding: .init(top: 0, - left: 4, - bottom: 0, - right: 0)) + indicatorUnitLabel.anchor( + top: nil, + leading: indicatorValueLabel.trailingAnchor, + bottom: indicatorValueLabel.bottomAnchor, + trailing: nil, + padding: .init( + top: 0, + left: 4, + bottom: 0, + right: 0 + ) + ) indicatorUnitLabel .topAnchor .constraint( diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift index 0d9d52a73..226bd8784 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift @@ -106,50 +106,64 @@ class DashboardPlainCell: UICollectionViewCell { // swiftlint:disable:next function_body_length fileprivate func setUpUI() { - let container = UIView(color: RuuviColor.dashboardCardBGColor, - cornerRadius: 8) + let container = UIView( + color: RuuviColor.dashboardCardBGColor, + cornerRadius: 8 + ) contentView.addSubview(container) container.fillSuperview() container.addSubview(ruuviTagNameLabel) - ruuviTagNameLabel.anchor(top: container.topAnchor, - leading: container.leadingAnchor, - bottom: nil, - trailing: nil, - padding: .init(top: 8, left: 8, - bottom: 0, right: 0)) + ruuviTagNameLabel.anchor( + top: container.topAnchor, + leading: container.leadingAnchor, + bottom: nil, + trailing: nil, + padding: .init( + top: 8, + left: 8, + bottom: 0, + right: 0 + ) + ) ruuviTagNameLabel.heightAnchor.constraint( greaterThanOrEqualToConstant: 14 ).isActive = true container.addSubview(alertIcon) - alertIcon.anchor(top: ruuviTagNameLabel.topAnchor, - leading: ruuviTagNameLabel.trailingAnchor, - bottom: nil, - trailing: nil, - padding: .init(top: 4, left: 12, bottom: 0, right: 0), - size: .init(width: 18, height: 18)) + alertIcon.anchor( + top: ruuviTagNameLabel.topAnchor, + leading: ruuviTagNameLabel.trailingAnchor, + bottom: nil, + trailing: nil, + padding: .init(top: 4, left: 12, bottom: 0, right: 0), + size: .init(width: 18, height: 18) + ) container.addSubview(alertButton) alertButton.match(view: alertIcon) container.addSubview(moreIcon) - moreIcon.anchor(top: alertIcon.topAnchor, - leading: alertIcon.trailingAnchor, - bottom: nil, - trailing: container.trailingAnchor, - padding: .init(top: 0, left: 10, bottom: 0, right: 14), - size: .init(width: 18, height: 18)) + moreIcon.anchor( + top: alertIcon.topAnchor, + leading: alertIcon.trailingAnchor, + bottom: nil, + trailing: container.trailingAnchor, + padding: .init(top: 0, left: 10, bottom: 0, right: 14), + size: .init(width: 18, height: 18) + ) container.addSubview(moreButton) moreButton.match(view: moreIcon) let leftContainerView = UIView() container.addSubview(leftContainerView) - leftContainerView.anchor(top: nil, - leading: ruuviTagNameLabel.leadingAnchor, - bottom: nil, - trailing: nil) + leftContainerView.anchor( + top: nil, + leading: ruuviTagNameLabel.leadingAnchor, + bottom: nil, + trailing: nil + ) leftContainerView .topAnchor .constraint( @@ -161,55 +175,69 @@ class DashboardPlainCell: UICollectionViewCell { let emptySpacer = UIView() emptySpacer.backgroundColor = .clear leftContainerView.addSubview(emptySpacer) - emptySpacer.anchor(top: leftContainerView.topAnchor, - leading: leftContainerView.leadingAnchor, - bottom: nil, - trailing: leftContainerView.trailingAnchor) + emptySpacer.anchor( + top: leftContainerView.topAnchor, + leading: leftContainerView.leadingAnchor, + bottom: nil, + trailing: leftContainerView.trailingAnchor + ) emptyViewHeight = emptySpacer.heightAnchor.constraint(equalToConstant: 0) emptyViewHeight.isActive = true leftContainerView.addSubview(temperatureView) - temperatureView.anchor(top: emptySpacer.bottomAnchor, - leading: leftContainerView.leadingAnchor, - bottom: nil, - trailing: leftContainerView.trailingAnchor) + temperatureView.anchor( + top: emptySpacer.bottomAnchor, + leading: leftContainerView.leadingAnchor, + bottom: nil, + trailing: leftContainerView.trailingAnchor + ) temperatureViewHeight = temperatureView .heightAnchor .constraint(equalToConstant: indicatorViewHeight()) temperatureViewHeight.isActive = true leftContainerView.addSubview(humidityView) - humidityView.anchor(top: temperatureView.bottomAnchor, - leading: leftContainerView.leadingAnchor, - bottom: leftContainerView.bottomAnchor, - trailing: leftContainerView.trailingAnchor) + humidityView.anchor( + top: temperatureView.bottomAnchor, + leading: leftContainerView.leadingAnchor, + bottom: leftContainerView.bottomAnchor, + trailing: leftContainerView.trailingAnchor + ) humidityViewHeight = humidityView.heightAnchor.constraint(equalToConstant: indicatorViewHeight()) humidityViewHeight.isActive = true let rightContainerView = UIView() container.addSubview(rightContainerView) - rightContainerView.anchor(top: nil, - leading: leftContainerView.trailingAnchor, - bottom: leftContainerView.bottomAnchor, - trailing: container.trailingAnchor, - padding: .init(top: 0, - left: 4, - bottom: 0, - right: 4)) + rightContainerView.anchor( + top: nil, + leading: leftContainerView.trailingAnchor, + bottom: leftContainerView.bottomAnchor, + trailing: container.trailingAnchor, + padding: .init( + top: 0, + left: 4, + bottom: 0, + right: 4 + ) + ) rightContainerView.addSubview(pressureView) - pressureView.anchor(top: rightContainerView.topAnchor, - leading: rightContainerView.leadingAnchor, - bottom: nil, - trailing: rightContainerView.trailingAnchor) + pressureView.anchor( + top: rightContainerView.topAnchor, + leading: rightContainerView.leadingAnchor, + bottom: nil, + trailing: rightContainerView.trailingAnchor + ) pressureViewHeight = pressureView.heightAnchor.constraint(equalToConstant: indicatorViewHeight()) pressureViewHeight.isActive = true rightContainerView.addSubview(movementView) - movementView.anchor(top: pressureView.bottomAnchor, - leading: rightContainerView.leadingAnchor, - bottom: rightContainerView.bottomAnchor, - trailing: rightContainerView.trailingAnchor) + movementView.anchor( + top: pressureView.bottomAnchor, + leading: rightContainerView.leadingAnchor, + bottom: rightContainerView.bottomAnchor, + trailing: rightContainerView.trailingAnchor + ) movementViewHeight = movementView.heightAnchor.constraint(equalToConstant: indicatorViewHeight()) movementViewHeight.isActive = true @@ -219,7 +247,7 @@ class DashboardPlainCell: UICollectionViewCell { .isActive = true let sourceAndUpdateStack = UIStackView(arrangedSubviews: [ - dataSourceIconView, updatedAtLabel, + dataSourceIconView, updatedAtLabel ]) sourceAndUpdateStack.axis = .horizontal sourceAndUpdateStack.spacing = 6 @@ -231,21 +259,25 @@ class DashboardPlainCell: UICollectionViewCell { dataSourceIconViewWidthConstraint.isActive = true let footerStack = UIStackView(arrangedSubviews: [ - sourceAndUpdateStack, batteryLevelView, + sourceAndUpdateStack, batteryLevelView ]) footerStack.spacing = 4 footerStack.axis = .horizontal footerStack.distribution = .fillProportionally container.addSubview(footerStack) - footerStack.anchor(top: leftContainerView.bottomAnchor, - leading: ruuviTagNameLabel.leadingAnchor, - bottom: container.bottomAnchor, - trailing: container.trailingAnchor, - padding: .init(top: 4, - left: 0, - bottom: 6, - right: 12)) + footerStack.anchor( + top: leftContainerView.bottomAnchor, + leading: ruuviTagNameLabel.leadingAnchor, + bottom: container.bottomAnchor, + trailing: container.trailingAnchor, + padding: .init( + top: 4, + left: 0, + bottom: 6, + right: 12 + ) + ) batteryLevelView.isHidden = true } } @@ -271,9 +303,10 @@ extension DashboardPlainCell { extension DashboardPlainCell { // swiftlint:disable:next function_body_length cyclomatic_complexity - func configure(with viewModel: CardsViewModel, - measurementService: RuuviServiceMeasurement?) - { + func configure( + with viewModel: CardsViewModel, + measurementService: RuuviServiceMeasurement? + ) { self.viewModel = viewModel // Name @@ -281,8 +314,7 @@ extension DashboardPlainCell { // Temp if let temp = measurementService?.stringWithoutSign(for: viewModel.temperature.value), - let temperatureUnit = measurementService?.units.temperatureUnit - { + let temperatureUnit = measurementService?.units.temperatureUnit { temperatureView.setValue(with: temp, unit: temperatureUnit.symbol) } else { temperatureView.setValue(with: RuuviLocalization.na) @@ -290,8 +322,7 @@ extension DashboardPlainCell { // Humidity if let humidity = viewModel.humidity.value, - let measurementService - { + let measurementService { hideHumidityView(hide: false) let humidityValue = measurementService.stringWithoutSign( for: humidity, @@ -302,8 +333,10 @@ extension DashboardPlainCell { let temperatureUnitSymbol = measurementService.units.temperatureUnit.symbol let unit = humidityUnit == .dew ? temperatureUnitSymbol : humidityUnitSymbol - humidityView.setValue(with: humidityValue, - unit: unit) + humidityView.setValue( + with: humidityValue, + unit: unit + ) } else { hideHumidityView(hide: true) } @@ -312,8 +345,10 @@ extension DashboardPlainCell { if let pressure = viewModel.pressure.value { hidePressureView(hide: false) let pressureValue = measurementService?.stringWithoutSign(for: pressure) - pressureView.setValue(with: pressureValue, - unit: measurementService?.units.pressureUnit.symbol) + pressureView.setValue( + with: pressureValue, + unit: measurementService?.units.pressureUnit.symbol + ) } else { hidePressureView(hide: true) } @@ -323,8 +358,10 @@ extension DashboardPlainCell { case .ruuvi: if let movement = viewModel.movementCounter.value { hideMovementView(hide: false) - movementView.setValue(with: "\(movement)", - unit: RuuviLocalization.Cards.Movements.title) + movementView.setValue( + with: "\(movement)", + unit: RuuviLocalization.Cards.Movements.title + ) } else { hideMovementView(hide: true) } @@ -372,8 +409,7 @@ extension DashboardPlainCell { // Battery stat if let batteryLow = viewModel.batteryNeedsReplacement.value, - batteryLow - { + batteryLow { batteryLevelView.isHidden = false } else { batteryLevelView.isHidden = true @@ -403,32 +439,28 @@ extension DashboardPlainCell { } if let isOn = viewModel.isTemperatureAlertOn.value, isOn, - let temperatureAlertState = viewModel.temperatureAlertState.value - { + let temperatureAlertState = viewModel.temperatureAlertState.value { temperatureView.changeColor(highlight: temperatureAlertState == .firing) } else { temperatureView.changeColor(highlight: false) } if let isOn = viewModel.isRelativeHumidityAlertOn.value, isOn, - let rhAlertState = viewModel.relativeHumidityAlertState.value - { + let rhAlertState = viewModel.relativeHumidityAlertState.value { humidityView.changeColor(highlight: rhAlertState == .firing) } else { humidityView.changeColor(highlight: false) } if let isOn = viewModel.isPressureAlertOn.value, isOn, - let pressureAlertState = viewModel.pressureAlertState.value - { + let pressureAlertState = viewModel.pressureAlertState.value { pressureView.changeColor(highlight: pressureAlertState == .firing) } else { pressureView.changeColor(highlight: false) } if let isOn = viewModel.isMovementAlertOn.value, isOn, - let movementAlertState = viewModel.movementAlertState.value - { + let movementAlertState = viewModel.movementAlertState.value { movementView.changeColor(highlight: movementAlertState == .firing) } else { movementView.changeColor(highlight: false) @@ -459,14 +491,18 @@ extension DashboardPlainCell { alertIcon.image = RuuviAssets.alertActiveImage } DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - UIView.animate(withDuration: 0.5, - delay: 0, - options: [.repeat, - .autoreverse, - .beginFromCurrentState], - animations: { [weak self] in - self?.alertIcon.alpha = 0.0 - }) + UIView.animate( + withDuration: 0.5, + delay: 0, + options: [ + .repeat, + .autoreverse, + .beginFromCurrentState, + ], + animations: { [weak self] in + self?.alertIcon.alpha = 0.0 + } + ) } } } else { @@ -489,15 +525,17 @@ extension DashboardPlainCell { timer?.invalidate() timer = nil - timer = Timer.scheduledTimer(withTimeInterval: 1, - repeats: true, - block: { [weak self] _ in - if let date = date?.ruuviAgo() { - self?.updatedAtLabel.text = date - } else { - self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message - } - }) + timer = Timer.scheduledTimer( + withTimeInterval: 1, + repeats: true, + block: { [weak self] _ in + if let date = date?.ruuviAgo() { + self?.updatedAtLabel.text = date + } else { + self?.updatedAtLabel.text = date?.ruuviAgo() ?? RuuviLocalization.Cards.UpdatedLabel.NoData.message + } + } + ) } private func hideHumidityView(hide: Bool) { @@ -535,7 +573,8 @@ extension DashboardPlainCell { } @objc private func alertButtonDidTap() { - guard let viewModel else { + guard let viewModel + else { return } delegate?.didTapAlertButton(for: viewModel) diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift index dc52af0cd..54b170355 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift @@ -42,10 +42,11 @@ class DashboardViewController: UIViewController { } } - private func cell(collectionView: UICollectionView, - indexPath: IndexPath, - viewModel: CardsViewModel) -> UICollectionViewCell? - { + private func cell( + collectionView: UICollectionView, + indexPath: IndexPath, + viewModel: CardsViewModel + ) -> UICollectionViewCell? { switch dashboardType { case .image: let cell = collectionView.dequeueReusableCell( @@ -86,8 +87,10 @@ class DashboardViewController: UIViewController { // Header View // Ruuvi Logo private lazy var ruuviLogoView: UIImageView = { - let iv = UIImageView(image: UIImage(named: "ruuvi_logo_"), - contentMode: .scaleAspectFit) + let iv = UIImageView( + image: UIImage(named: "ruuvi_logo_"), + contentMode: .scaleAspectFit + ) iv.backgroundColor = .clear iv.tintColor = RuuviColor.logoTintColor return iv @@ -101,20 +104,24 @@ class DashboardViewController: UIViewController { button.setImage(menuImage, for: .normal) button.setImage(menuImage, for: .highlighted) button.backgroundColor = .clear - button.addTarget(self, - action: #selector(handleMenuButtonTap), - for: .touchUpInside) + button.addTarget( + self, + action: #selector(handleMenuButtonTap), + for: .touchUpInside + ) return button }() private lazy var viewButton: RuuviContextMenuButton = - .init(menu: viewToggleMenuOptions(), - titleColor: RuuviColor.dashboardIndicatorTextColor, - title: RuuviLocalization.view, - icon: RuuviAssets.dropDownArrowImage, - iconTintColor: RuuviColor.logoTintColor, - iconSize: .init(width: 14, height: 14), - preccedingIcon: false) + .init( + menu: viewToggleMenuOptions(), + titleColor: RuuviColor.dashboardIndicatorTextColor, + title: RuuviLocalization.view, + icon: RuuviAssets.dropDownArrowImage, + iconTintColor: RuuviColor.logoTintColor, + iconSize: .init(width: 14, height: 14), + preccedingIcon: false + ) // BODY private lazy var collectionView: UICollectionView = { @@ -183,10 +190,11 @@ extension DashboardViewController { output.viewWillDisappear() } - override func viewWillTransition(to size: CGSize, - with coordinator: - UIViewControllerTransitionCoordinator) - { + override func viewWillTransition( + to size: CGSize, + with coordinator: + UIViewControllerTransitionCoordinator + ) { super.viewWillTransition(to: size, with: coordinator) reloadCollectionView(redrawLayout: true) } @@ -208,9 +216,11 @@ private extension DashboardViewController { completion: { _ in guard self.viewModels.count > 0 else { return } let indexPath = IndexPath(item: 0, section: 0) - self.collectionView.scrollToItem(at: indexPath, - at: .top, - animated: false) + self.collectionView.scrollToItem( + at: indexPath, + at: .top, + animated: false + ) self.collectionView.contentOffset.y = -8 } ) @@ -220,7 +230,8 @@ private extension DashboardViewController { } @objc func didPullToRefresh() { - guard !isRefreshing else { + guard !isRefreshing + else { refresher.endRefreshing() return } @@ -255,11 +266,13 @@ extension DashboardViewController { simpleViewTypeAction.state = dashboardType == .simple ? .on : .off imageViewTypeAction.state = dashboardType == .image ? .on : .off - let cardTypeMenu = UIMenu(title: RuuviLocalization.cardType, - options: .displayInline, - children: [ - imageViewTypeAction, simpleViewTypeAction, - ]) + let cardTypeMenu = UIMenu( + title: RuuviLocalization.cardType, + options: .displayInline, + children: [ + imageViewTypeAction, simpleViewTypeAction + ] + ) // Card action let openSensorViewAction = UIAction(title: RuuviLocalization.openSensorView) { @@ -277,16 +290,18 @@ extension DashboardViewController { openSensorViewAction.state = dashboardTapActionType == .card ? .on : .off openHistoryViewAction.state = dashboardTapActionType == .chart ? .on : .off - let cardActionMenu = UIMenu(title: RuuviLocalization.cardAction, - options: .displayInline, - children: [ - openSensorViewAction, openHistoryViewAction, - ]) + let cardActionMenu = UIMenu( + title: RuuviLocalization.cardAction, + options: .displayInline, + children: [ + openSensorViewAction, openHistoryViewAction + ] + ) return UIMenu( title: "", children: [ - cardTypeMenu, cardActionMenu, + cardTypeMenu, cardActionMenu ] ) } @@ -344,8 +359,7 @@ extension DashboardViewController { let viewModel = viewModels[index] if let canShare = viewModel.canShareTag.value, - canShare - { + canShare { contextMenuActions.append(shareSensorAction) } @@ -370,14 +384,18 @@ private extension DashboardViewController { view.backgroundColor = RuuviColor.dashboardBGColor view.addSubview(noSensorView) - noSensorView.anchor(top: view.safeTopAnchor, - leading: view.safeLeftAnchor, - bottom: view.safeBottomAnchor, - trailing: view.safeRightAnchor, - padding: .init(top: 12, - left: 12, - bottom: 12, - right: 12)) + noSensorView.anchor( + top: view.safeTopAnchor, + leading: view.safeLeftAnchor, + bottom: view.safeBottomAnchor, + trailing: view.safeRightAnchor, + padding: .init( + top: 12, + left: 12, + bottom: 12, + right: 12 + ) + ) noSensorView.isHidden = true } @@ -385,31 +403,39 @@ private extension DashboardViewController { let leftBarButtonView = UIView(color: .clear) leftBarButtonView.addSubview(menuButton) - menuButton.anchor(top: leftBarButtonView.topAnchor, - leading: leftBarButtonView.leadingAnchor, - bottom: leftBarButtonView.bottomAnchor, - trailing: nil, - padding: .init(top: 0, left: 0, bottom: 0, right: 0), - size: .init(width: 32, height: 32)) + menuButton.anchor( + top: leftBarButtonView.topAnchor, + leading: leftBarButtonView.leadingAnchor, + bottom: leftBarButtonView.bottomAnchor, + trailing: nil, + padding: .init(top: 0, left: 0, bottom: 0, right: 0), + size: .init(width: 32, height: 32) + ) leftBarButtonView.addSubview(ruuviLogoView) - ruuviLogoView.anchor(top: nil, - leading: menuButton.trailingAnchor, - bottom: nil, - trailing: leftBarButtonView.trailingAnchor, - padding: .init(top: 0, left: 8, bottom: 0, right: 0), - size: .init(width: 110, height: 22)) + ruuviLogoView.anchor( + top: nil, + leading: menuButton.trailingAnchor, + bottom: nil, + trailing: leftBarButtonView.trailingAnchor, + padding: .init(top: 0, left: 8, bottom: 0, right: 0), + size: .init(width: 110, height: 22) + ) ruuviLogoView.centerYInSuperview() let rightBarButtonView = UIView(color: .clear) rightBarButtonView.addSubview(viewButton) - viewButton.anchor(top: rightBarButtonView.topAnchor, - leading: rightBarButtonView.leadingAnchor, - bottom: rightBarButtonView.bottomAnchor, - trailing: rightBarButtonView.trailingAnchor, - padding: .init(top: 0, left: 0, bottom: 0, right: 4), - size: .init(width: 0, - height: 32)) + viewButton.anchor( + top: rightBarButtonView.topAnchor, + leading: rightBarButtonView.leadingAnchor, + bottom: rightBarButtonView.bottomAnchor, + trailing: rightBarButtonView.trailingAnchor, + padding: .init(top: 0, left: 0, bottom: 0, right: 4), + size: .init( + width: 0, + height: 32 + ) + ) navigationItem.leftBarButtonItem = UIBarButtonItem(customView: leftBarButtonView) navigationItem.rightBarButtonItem = UIBarButtonItem(customView: rightBarButtonView) @@ -417,14 +443,18 @@ private extension DashboardViewController { func setUpContentView() { view.addSubview(collectionView) - collectionView.anchor(top: view.safeTopAnchor, - leading: view.safeLeftAnchor, - bottom: view.bottomAnchor, - trailing: view.safeRightAnchor, - padding: .init(top: 12, - left: 12, - bottom: 0, - right: 12)) + collectionView.anchor( + top: view.safeTopAnchor, + leading: view.safeLeftAnchor, + bottom: view.bottomAnchor, + trailing: view.safeRightAnchor, + padding: .init( + top: 12, + left: 12, + bottom: 0, + right: 12 + ) + ) collectionView.showsVerticalScrollIndicator = false collectionView.register(DashboardImageCell.self, forCellWithReuseIdentifier: "cellId") @@ -443,43 +473,45 @@ private extension DashboardViewController { break } - let sectionProvider = { (_: Int, - _: NSCollectionLayoutEnvironment) - -> NSCollectionLayoutSection? in - let widthMultiplier = GlobalHelpers.isDeviceTablet() ? - (!GlobalHelpers.isDeviceLandscape() ? 0.5 : 0.3333) : - (GlobalHelpers.isDeviceLandscape() ? 0.5 : 1.0) - - let itemSize = NSCollectionLayoutSize( - widthDimension: .fractionalWidth(widthMultiplier), - heightDimension: .absolute(itemEstimatedHeight) - ) - let item = NSCollectionLayoutItem(layoutSize: itemSize) - let itemHorizontalSpacing: CGFloat = GlobalHelpers.isDeviceTablet() ? 6 : 4 - item.contentInsets = NSDirectionalEdgeInsets( - top: 0, - leading: itemHorizontalSpacing, - bottom: 0, - trailing: itemHorizontalSpacing - ) + let sectionProvider = { ( + _: Int, + _: NSCollectionLayoutEnvironment + ) + -> NSCollectionLayoutSection? in + let widthMultiplier = GlobalHelpers.isDeviceTablet() ? + (!GlobalHelpers.isDeviceLandscape() ? 0.5 : 0.3333) : + (GlobalHelpers.isDeviceLandscape() ? 0.5 : 1.0) + + let itemSize = NSCollectionLayoutSize( + widthDimension: .fractionalWidth(widthMultiplier), + heightDimension: .absolute(itemEstimatedHeight) + ) + let item = NSCollectionLayoutItem(layoutSize: itemSize) + let itemHorizontalSpacing: CGFloat = GlobalHelpers.isDeviceTablet() ? 6 : 4 + item.contentInsets = NSDirectionalEdgeInsets( + top: 0, + leading: itemHorizontalSpacing, + bottom: 0, + trailing: itemHorizontalSpacing + ) - let groupSize = NSCollectionLayoutSize( - widthDimension: .fractionalWidth(1.0), - heightDimension: .absolute(itemEstimatedHeight) - ) - let group = NSCollectionLayoutGroup.horizontal( - layoutSize: groupSize, subitems: [item] - ) + let groupSize = NSCollectionLayoutSize( + widthDimension: .fractionalWidth(1.0), + heightDimension: .absolute(itemEstimatedHeight) + ) + let group = NSCollectionLayoutGroup.horizontal( + layoutSize: groupSize, subitems: [item] + ) - let section = NSCollectionLayoutSection(group: group) - section.interGroupSpacing = GlobalHelpers.isDeviceTablet() ? 12 : 8 - section.contentInsets = NSDirectionalEdgeInsets( - top: 0, - leading: 0, - bottom: 12, - trailing: 0 - ) - return section + let section = NSCollectionLayoutSection(group: group) + section.interGroupSpacing = GlobalHelpers.isDeviceTablet() ? 12 : 8 + section.contentInsets = NSDirectionalEdgeInsets( + top: 0, + leading: 0, + bottom: 12, + trailing: 0 + ) + return section } let config = UICollectionViewCompositionalLayoutConfiguration() @@ -494,30 +526,34 @@ private extension DashboardViewController { private func configureRestartAnimationsOnAppDidBecomeActive() { appDidBecomeActiveToken = NotificationCenter .default - .addObserver(forName: UIApplication.didBecomeActiveNotification, - object: nil, - queue: .main) - { [weak self] _ in - self?.reloadCollectionView() - } + .addObserver( + forName: UIApplication.didBecomeActiveNotification, + object: nil, + queue: .main + ) { [weak self] _ in + self?.reloadCollectionView() + } } } extension DashboardViewController: UICollectionViewDataSource { - func collectionView(_: UICollectionView, - numberOfItemsInSection _: Int) -> Int - { + func collectionView( + _: UICollectionView, + numberOfItemsInSection _: Int + ) -> Int { viewModels.count } - func collectionView(_ collectionView: UICollectionView, - cellForItemAt indexPath: IndexPath) -> UICollectionViewCell - { + func collectionView( + _ collectionView: UICollectionView, + cellForItemAt indexPath: IndexPath + ) -> UICollectionViewCell { guard let cell = cell( collectionView: collectionView, indexPath: indexPath, viewModel: viewModels[indexPath.item] - ) else { + ) + else { fatalError() } return cell @@ -525,17 +561,19 @@ extension DashboardViewController: UICollectionViewDataSource { } extension DashboardViewController: UICollectionViewDelegate { - func collectionView(_: UICollectionView, - contextMenuConfigurationForItemAt indexPath: IndexPath, - point _: CGPoint) -> UIContextMenuConfiguration? - { + func collectionView( + _: UICollectionView, + contextMenuConfigurationForItemAt indexPath: IndexPath, + point _: CGPoint + ) -> UIContextMenuConfiguration? { configureContextMenu(index: indexPath.row) } func configureContextMenu(index: Int) -> UIContextMenuConfiguration { - let context = UIContextMenuConfiguration(identifier: nil, - previewProvider: nil) - { [weak self] + let context = UIContextMenuConfiguration( + identifier: nil, + previewProvider: nil + ) { [weak self] _ -> UIMenu? in self?.highlightedViewModel = self?.viewModels[index] return self?.cardContextMenuOption(for: index) @@ -543,17 +581,19 @@ extension DashboardViewController: UICollectionViewDelegate { return context } - func collectionView(_: UICollectionView, - willEndContextMenuInteraction _: UIContextMenuConfiguration, + func collectionView( + _: UICollectionView, + willEndContextMenuInteraction _: UIContextMenuConfiguration, - animator _: UIContextMenuInteractionAnimating?) - { + animator _: UIContextMenuInteractionAnimating? + ) { highlightedViewModel = nil } - func collectionView(_: UICollectionView, - didSelectItemAt indexPath: IndexPath) - { + func collectionView( + _: UICollectionView, + didSelectItemAt indexPath: IndexPath + ) { let viewModel = viewModels[indexPath.item] output.viewDidTriggerDashboardCard(for: viewModel) } @@ -575,9 +615,11 @@ extension DashboardViewController: UICollectionViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { NSObject.cancelPreviousPerformRequests(withTarget: self) - perform(#selector(UIScrollViewDelegate.scrollViewDidEndScrollingAnimation), - with: nil, - afterDelay: 0.3) + perform( + #selector(UIScrollViewDelegate.scrollViewDidEndScrollingAnimation), + with: nil, + afterDelay: 0.3 + ) if scrollView.isDragging { refresher.fadeIn() isListRefreshable = false @@ -596,12 +638,12 @@ extension DashboardViewController: DashboardViewInput { func applyUpdate(to viewModel: CardsViewModel) { if let highlightedViewModel, highlightedViewModel.luid.value != nil && highlightedViewModel.luid.value == viewModel.luid.value || - highlightedViewModel.mac.value != nil && highlightedViewModel.mac.value == viewModel.mac.value - { + highlightedViewModel.mac.value != nil && highlightedViewModel.mac.value == viewModel.mac.value { return } - guard isListRefreshable else { + guard isListRefreshable + else { return } @@ -611,15 +653,13 @@ extension DashboardViewController: DashboardViewInput { }) { let indexPath = IndexPath(item: index, section: 0) if let cell = collectionView - .cellForItem(at: indexPath) as? DashboardImageCell - { + .cellForItem(at: indexPath) as? DashboardImageCell { cell.configure( with: viewModel, measurementService: measurementService ) cell.restartAlertAnimation(for: viewModel) } else if let cell = collectionView - .cellForItem(at: indexPath) as? DashboardPlainCell - { + .cellForItem(at: indexPath) as? DashboardPlainCell { cell.configure( with: viewModel, measurementService: measurementService ) @@ -636,16 +676,19 @@ extension DashboardViewController: DashboardViewInput { let title = RuuviLocalization.Cards.BluetoothDisabledAlert.title let message = RuuviLocalization.Cards.BluetoothDisabledAlert.message let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: RuuviLocalization.PermissionPresenter.settings, - style: .default, handler: { _ in - guard let url = URL(string: userDeclined ? - UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), - UIApplication.shared.canOpenURL(url) - else { - return - } - UIApplication.shared.open(url) - })) + alertVC.addAction(UIAlertAction( + title: RuuviLocalization.PermissionPresenter.settings, + style: .default, + handler: { _ in + guard let url = URL(string: userDeclined ? + UIApplication.openSettingsURLString : "App-prefs:Bluetooth"), + UIApplication.shared.canOpenURL(url) + else { + return + } + UIApplication.shared.open(url) + } + )) alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) } @@ -703,9 +746,11 @@ extension DashboardViewController: DashboardViewInput { from: viewModel.mac.value?.mac, luid: viewModel.luid.value?.value ) - let alert = UIAlertController(title: RuuviLocalization.TagSettings.TagNameTitleLabel.text, - message: RuuviLocalization.TagSettings.TagNameTitleLabel.Rename.text, - preferredStyle: .alert) + let alert = UIAlertController( + title: RuuviLocalization.TagSettings.TagNameTitleLabel.text, + message: RuuviLocalization.TagSettings.TagNameTitleLabel.Rename.text, + preferredStyle: .alert + ) alert.addTextField { [weak self] alertTextField in guard let self else { return } alertTextField.delegate = self @@ -730,7 +775,8 @@ extension DashboardViewController: DashboardViewInput { extension DashboardViewController: RuuviServiceMeasurementDelegate { func measurementServiceDidUpdateUnit() { - guard isViewLoaded else { + guard isViewLoaded + else { return } reloadCollectionView() @@ -767,11 +813,14 @@ private extension DashboardViewController { // MARK: - UITextFieldDelegate extension DashboardViewController: UITextFieldDelegate { - func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, - - replacementString string: String) -> Bool - { - guard let text = textField.text else { + func textField( + _ textField: UITextField, + shouldChangeCharactersIn range: NSRange, + + replacementString string: String + ) -> Bool { + guard let text = textField.text + else { return true } let limit = text.utf16.count + string.utf16.count - range.length diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift index 5b40c6653..7bc284348 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift @@ -43,7 +43,7 @@ class BatteryLevelView: UIView { clipsToBounds = true let stack = UIStackView(arrangedSubviews: [ - batteryLevelLabel, batteryLevelIcon, + batteryLevelLabel, batteryLevelIcon ]) stack.spacing = 4 stack.axis = .horizontal diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift index d9279393c..ce9c82765 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift @@ -47,43 +47,65 @@ class NoSensorView: UIView { }() private lazy var signInButton: UIButton = { - let button = UIButton(color: RuuviColor.ruuviTintColor, - cornerRadius: UIDevice.isiPhoneSE() ? 20 : 25) - button.setTitle(RuuviLocalization.SignIn.Title.text, - for: .normal) + let button = UIButton( + color: RuuviColor.ruuviTintColor, + cornerRadius: UIDevice.isiPhoneSE() ? 20 : 25 + ) + button.setTitle( + RuuviLocalization.SignIn.Title.text, + for: .normal + ) button.setTitleColor(.white, for: .normal) - button.titleLabel?.font = UIFont.Muli(.bold, - size: UIDevice.isiPhoneSE() ? 14 : 16) - button.addTarget(self, - action: #selector(handleSignInTap), - for: .touchUpInside) + button.titleLabel?.font = UIFont.Muli( + .bold, + size: UIDevice.isiPhoneSE() ? 14 : 16 + ) + button.addTarget( + self, + action: #selector(handleSignInTap), + for: .touchUpInside + ) return button }() private lazy var addSensorButton: UIButton = { - let button = UIButton(color: RuuviColor.ruuviTintColor, - cornerRadius: UIDevice.isiPhoneSE() ? 20 : 25) - button.setTitle(RuuviLocalization.addASensor, - for: .normal) + let button = UIButton( + color: RuuviColor.ruuviTintColor, + cornerRadius: UIDevice.isiPhoneSE() ? 20 : 25 + ) + button.setTitle( + RuuviLocalization.addASensor, + for: .normal + ) button.setTitleColor(.white, for: .normal) - button.titleLabel?.font = UIFont.Muli(.bold, - size: UIDevice.isiPhoneSE() ? 14 : 16) - button.addTarget(self, - action: #selector(handleAddSensorTap), - for: .touchUpInside) + button.titleLabel?.font = UIFont.Muli( + .bold, + size: UIDevice.isiPhoneSE() ? 14 : 16 + ) + button.addTarget( + self, + action: #selector(handleAddSensorTap), + for: .touchUpInside + ) return button }() private lazy var buySensorButton: UIButton = { let button = UIButton() button.setTitleColor(RuuviColor.ruuviTextColor, for: .normal) - button.setTitle(RuuviLocalization.DiscoverTable.GetMoreSensors.Button.title, - for: .normal) - button.titleLabel?.font = UIFont.Muli(.bold, - size: 14) - button.addTarget(self, - action: #selector(handleBuySensorTap), - for: .touchUpInside) + button.setTitle( + RuuviLocalization.DiscoverTable.GetMoreSensors.Button.title, + for: .normal + ) + button.titleLabel?.font = UIFont.Muli( + .bold, + size: 14 + ) + button.addTarget( + self, + action: #selector(handleBuySensorTap), + for: .touchUpInside + ) button.underline() return button }() @@ -149,12 +171,18 @@ extension NoSensorView { ).isActive = true container.addSubview(messageLabel) - messageLabel.anchor(top: nil, - leading: container.safeLeftAnchor, - bottom: nil, - trailing: container.safeRightAnchor, - padding: .init(top: 0, left: 30, - bottom: 0, right: 30)) + messageLabel.anchor( + top: nil, + leading: container.safeLeftAnchor, + bottom: nil, + trailing: container.safeRightAnchor, + padding: .init( + top: 0, + left: 30, + bottom: 0, + right: 30 + ) + ) messageLabelTopAnchor = messageLabel .topAnchor .constraint( @@ -167,11 +195,13 @@ extension NoSensorView { container.addSubview(centerButtonStackView) addSensorButton.constrainHeight(constant: UIDevice.isiPhoneSE() ? 40 : 50) if UIDevice.isiPhoneSE() { - centerButtonStackView.anchor(top: nil, - leading: container.leadingAnchor, - bottom: nil, - trailing: container.trailingAnchor, - padding: .init(top: 0, left: 8, bottom: 0, right: 8)) + centerButtonStackView.anchor( + top: nil, + leading: container.leadingAnchor, + bottom: nil, + trailing: container.trailingAnchor, + padding: .init(top: 0, left: 8, bottom: 0, right: 8) + ) } else { centerButtonStackView.widthAnchor.constraint( greaterThanOrEqualToConstant: 300 @@ -193,12 +223,18 @@ extension NoSensorView { centerButtonCenterYAnchor.isActive = activateCenterButtonStackConstraint() container.addSubview(buySensorButton) - buySensorButton.anchor(top: centerButtonStackView.bottomAnchor, - leading: container.safeLeftAnchor, - bottom: nil, - trailing: container.safeRightAnchor, - padding: .init(top: 24, left: 30, - bottom: 0, right: 30)) + buySensorButton.anchor( + top: centerButtonStackView.bottomAnchor, + leading: container.safeLeftAnchor, + bottom: nil, + trailing: container.safeRightAnchor, + padding: .init( + top: 24, + left: 30, + bottom: 0, + right: 30 + ) + ) buySensorsButtonBottomAnchor = buySensorButton .bottomAnchor .constraint( diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviContextMenuButton.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviContextMenuButton.swift index 4ee7c4665..ea9c5a3be 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviContextMenuButton.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviContextMenuButton.swift @@ -34,15 +34,16 @@ class RuuviContextMenuButton: UIView { fatalError("init(coder:) has not been implemented") } - convenience init(menu: UIMenu?, - titleColor: UIColor?, - title: String?, - icon: UIImage?, - iconTintColor: UIColor?, - iconSize: CGSize = .init(width: 16, height: 16), - interimSpacing: CGFloat = 6.0, - preccedingIcon: Bool = false) - { + convenience init( + menu: UIMenu?, + titleColor: UIColor?, + title: String?, + icon: UIImage?, + iconTintColor: UIColor?, + iconSize: CGSize = .init(width: 16, height: 16), + interimSpacing: CGFloat = 6.0, + preccedingIcon: Bool = false + ) { self.init() self.preccedingIcon = preccedingIcon button.menu = menu @@ -63,12 +64,12 @@ private extension RuuviContextMenuButton { if preccedingIcon { buttonTitleLabel.textAlignment = .left stackView = UIStackView(arrangedSubviews: [ - buttonIconView, buttonTitleLabel, + buttonIconView, buttonTitleLabel ]) } else { buttonTitleLabel.textAlignment = .right stackView = UIStackView(arrangedSubviews: [ - buttonTitleLabel, buttonIconView, + buttonTitleLabel, buttonIconView ]) } buttonIconView.heightAnchor.constraint( diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviSimpleViewCompositionalLayout.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviSimpleViewCompositionalLayout.swift index 7623a81e5..6ecac8f97 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviSimpleViewCompositionalLayout.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviSimpleViewCompositionalLayout.swift @@ -45,8 +45,10 @@ class RuuviSimpleViewCompositionalLayout: UICollectionViewCompositionalLayout { largests[row] = max(largests[row] ?? 0, height) - let size = CGSize(width: layoutAttributes.frame.width, - height: largests[row] ?? 0) + let size = CGSize( + width: layoutAttributes.frame.width, + height: largests[row] ?? 0 + ) layoutAttributes.frame = .init(origin: layoutAttributes.frame.origin, size: size) } } diff --git a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableDismissTransitionAnimation.swift b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableDismissTransitionAnimation.swift index 4a8bc2b05..69c35f306 100644 --- a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableDismissTransitionAnimation.swift +++ b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableDismissTransitionAnimation.swift @@ -42,25 +42,30 @@ class MenuTableDismissTransitionAnimation: UIPercentDrivenInteractiveTransition, let appearedFrame = transitionContext.finalFrame(for: fromVC) let initialFrame = appearedFrame - let finalFrame = CGRect(x: -appearedFrame.size.width, - y: appearedFrame.origin.y, - width: appearedFrame.size.width, - height: appearedFrame.size.height) + let finalFrame = CGRect( + x: -appearedFrame.size.width, + y: appearedFrame.origin.y, + width: appearedFrame.size.width, + height: appearedFrame.size.height + ) fromView.frame = initialFrame let duration = transitionDuration(using: transitionContext) - UIView.animate(withDuration: duration, - delay: 0, - usingSpringWithDamping: 1, - initialSpringVelocity: 1, - options: .curveEaseInOut, - animations: { - fromView.frame = finalFrame - }, completion: { _ in - if !transitionContext.transitionWasCancelled { - fromView.removeFromSuperview() - } - transitionContext.completeTransition(!transitionContext.transitionWasCancelled) - }) + UIView.animate( + withDuration: duration, + delay: 0, + usingSpringWithDamping: 1, + initialSpringVelocity: 1, + options: .curveEaseInOut, + animations: { + fromView.frame = finalFrame + }, + completion: { _ in + if !transitionContext.transitionWasCancelled { + fromView.removeFromSuperview() + } + transitionContext.completeTransition(!transitionContext.transitionWasCancelled) + } + ) } } diff --git a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentTransitionAnimation.swift b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentTransitionAnimation.swift index b0e982671..eca64c59a 100644 --- a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentTransitionAnimation.swift +++ b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentTransitionAnimation.swift @@ -24,28 +24,34 @@ class MenuTablePresentTransitionAnimation: UIPercentDrivenInteractiveTransition, containerView.addSubview(toView) let appearedFrame = transitionContext.finalFrame(for: toVC) - let initialFrame = CGRect(x: -appearedFrame.size.width, - y: appearedFrame.origin.y, - width: appearedFrame.size.width, - height: appearedFrame.size.height) + let initialFrame = CGRect( + x: -appearedFrame.size.width, + y: appearedFrame.origin.y, + width: appearedFrame.size.width, + height: appearedFrame.size.height + ) let finalFrame = appearedFrame toView.frame = initialFrame let duration = transitionDuration(using: transitionContext) - UIView.animate(withDuration: duration, - delay: 0, - usingSpringWithDamping: 1, - initialSpringVelocity: 1, - options: .curveEaseInOut, - animations: { - toView.frame = finalFrame - }, completion: { _ in - transitionContext.completeTransition(!transitionContext.transitionWasCancelled) - }) + UIView.animate( + withDuration: duration, + delay: 0, + usingSpringWithDamping: 1, + initialSpringVelocity: 1, + options: .curveEaseInOut, + animations: { + toView.frame = finalFrame + }, + completion: { _ in + transitionContext.completeTransition(!transitionContext.transitionWasCancelled) + } + ) } func handlePresentMenuPan(_ pan: UIPanGestureRecognizer) { - guard let view = pan.view else { + guard let view = pan.view + else { return } diff --git a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentationController.swift b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentationController.swift index baec4aac7..f7ff271bc 100644 --- a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentationController.swift +++ b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentationController.swift @@ -29,16 +29,20 @@ class MenuTablePresentationController: UIPresentationController { }() private lazy var tapGestureRecognizer: UITapGestureRecognizer = { - let tap = UITapGestureRecognizer(target: self, - action: #selector(MenuTablePresentationController.dimmingViewTapped(_:))) + let tap = UITapGestureRecognizer( + target: self, + action: #selector(MenuTablePresentationController.dimmingViewTapped(_:)) + ) return tap }() private lazy var panGestureRecognizer: UIPanGestureRecognizer = { let exitPanGesture = UIPanGestureRecognizer() exitPanGesture.cancelsTouchesInView = false - exitPanGesture.addTarget(dismissTransition as Any, - action: #selector(MenuTableDismissTransitionAnimation.handleHideMenuPan(_:))) + exitPanGesture.addTarget( + dismissTransition as Any, + action: #selector(MenuTableDismissTransitionAnimation.handleHideMenuPan(_:)) + ) return exitPanGesture }() @@ -50,17 +54,20 @@ class MenuTablePresentationController: UIPresentationController { .overFullScreen } - override func size(forChildContentContainer _: UIContentContainer, - withParentContainerSize parentSize: CGSize) -> CGSize - { + override func size( + forChildContentContainer _: UIContentContainer, + withParentContainerSize parentSize: CGSize + ) -> CGSize { CGSize(width: menuWidth, height: parentSize.height) } override var frameOfPresentedViewInContainerView: CGRect { var presentedViewFrame = CGRect.zero if let containerBounds = containerView?.bounds { - let size = self.size(forChildContentContainer: presentedViewController, - withParentContainerSize: containerBounds.size) + let size = self.size( + forChildContentContainer: presentedViewController, + withParentContainerSize: containerBounds.size + ) presentedViewFrame.size = size presentedViewFrame.origin.x = containerBounds.origin.x presentedViewFrame.origin.y = containerBounds.origin.y @@ -110,8 +117,7 @@ class MenuTablePresentationController: UIPresentationController { @objc func dimmingViewTapped(_: UITapGestureRecognizer) { if let navigationController = presentedViewController as? UINavigationController, - let menuTable = navigationController.topViewController as? MenuTableViewController - { + let menuTable = navigationController.topViewController as? MenuTableViewController { menuTable.output.viewDidTapOnDimmingView() } } diff --git a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitioningDelegate.swift b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitioningDelegate.swift index 0d9dc21aa..fc7a154f8 100644 --- a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitioningDelegate.swift +++ b/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitioningDelegate.swift @@ -11,20 +11,22 @@ class MenuTableTransitioningDelegate: NSObject, UIViewControllerTransitioningDel self.manager = manager } - func presentationController(forPresented presented: UIViewController, - presenting: UIViewController?, - source _: UIViewController) -> UIPresentationController? - { + func presentationController( + forPresented presented: UIViewController, + presenting: UIViewController?, + source _: UIViewController + ) -> UIPresentationController? { let controller = MenuTablePresentationController(presentedViewController: presented, presenting: presenting) controller.menuWidth = manager.menuWidth controller.dismissTransition = dismiss return controller } - func animationController(forPresented _: UIViewController, - presenting _: UIViewController, - source _: UIViewController) -> UIViewControllerAnimatedTransitioning? - { + func animationController( + forPresented _: UIViewController, + presenting _: UIViewController, + source _: UIViewController + ) -> UIViewControllerAnimatedTransitioning? { present } @@ -33,14 +35,12 @@ class MenuTableTransitioningDelegate: NSObject, UIViewControllerTransitioningDel } func interactionControllerForPresentation(using _: UIViewControllerAnimatedTransitioning) - -> UIViewControllerInteractiveTransitioning? - { + -> UIViewControllerInteractiveTransitioning? { manager.isInteractive ? present : nil } func interactionControllerForDismissal(using _: UIViewControllerAnimatedTransitioning) - -> UIViewControllerInteractiveTransitioning? - { + -> UIViewControllerInteractiveTransitioning? { manager.isInteractive ? dismiss : nil } } diff --git a/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift b/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift index 30c7d8c82..8e6fcec53 100644 --- a/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift +++ b/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift @@ -45,14 +45,11 @@ extension MenuTableEmbededViewController { // MARK: - UITableViewDelegate extension MenuTableEmbededViewController { - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - super.tableView(tableView, numberOfRowsInSection: section) - } - - override func tableView(_: UITableView, - willDisplay cell: UITableViewCell, - forRowAt _: IndexPath) - { + override func tableView( + _: UITableView, + willDisplay cell: UITableViewCell, + forRowAt _: IndexPath + ) { if cell == accountCell { accountAuthLabel.text = output.userIsAuthorized ? RuuviLocalization.Menu.Label.MyRuuviAccount.text diff --git a/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift b/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift index 2aee201d7..93077b07a 100644 --- a/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift +++ b/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift @@ -42,8 +42,10 @@ extension MenuTableViewController { if let transitioningDelegate = navigationController?.transitioningDelegate as? MenuTableTransitioningDelegate { let exitPanGesture = UIPanGestureRecognizer() exitPanGesture.cancelsTouchesInView = false - exitPanGesture.addTarget(transitioningDelegate.dismiss, - action: #selector(MenuTableDismissTransitionAnimation.handleHideMenuPan(_:))) + exitPanGesture.addTarget( + transitioningDelegate.dismiss, + action: #selector(MenuTableDismissTransitionAnimation.handleHideMenuPan(_:)) + ) view.addGestureRecognizer(exitPanGesture) } } diff --git a/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift b/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift index d7107dad3..47be122c2 100644 --- a/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift +++ b/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift @@ -76,9 +76,10 @@ extension MyRuuviAccountPresenter { let message = RuuviLocalization.TagsManagerPresenter.SignOutConfirmAlert.message let confirmActionTitle = RuuviLocalization.ok let cancelActionTitle = RuuviLocalization.cancel - let confirmAction = UIAlertAction(title: confirmActionTitle, - style: .default) - { [weak self] _ in + let confirmAction = UIAlertAction( + title: confirmActionTitle, + style: .default + ) { [weak self] _ in guard let sSelf = self else { return } sSelf.activityPresenter.show(with: .loading(message: nil)) sSelf.cloudNotificationService.unregister( @@ -100,14 +101,18 @@ extension MyRuuviAccountPresenter { self?.activityPresenter.dismiss() }) } - let cancleAction = UIAlertAction(title: cancelActionTitle, - style: .cancel, - handler: nil) + let cancleAction = UIAlertAction( + title: cancelActionTitle, + style: .cancel, + handler: nil + ) let actions = [confirmAction, cancleAction] - let alertViewModel = AlertViewModel(title: title, - message: message, - style: .alert, - actions: actions) + let alertViewModel = AlertViewModel( + title: title, + message: message, + style: .alert, + actions: actions + ) alertPresenter.showAlert(alertViewModel) } diff --git a/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift b/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift index fa5bc235b..6af673f20 100644 --- a/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift +++ b/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift @@ -51,7 +51,8 @@ extension MyRuuviAccountViewController: MyRuuviAccountViewInput { extension MyRuuviAccountViewController { private func bindViewModel() { - guard let viewModel, isViewLoaded else { + guard let viewModel, isViewLoaded + else { return } usernameLabel.bind(viewModel.username) { label, username in diff --git a/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift index 8f8394214..8cd8f70ea 100644 --- a/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift @@ -37,12 +37,14 @@ extension SettingsPresenter: SettingsViewOutput { languageToken = NotificationCenter .default - .addObserver(forName: .LanguageDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.view.language = self?.settings.language ?? .english - }) + .addObserver( + forName: .LanguageDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.view.language = self?.settings.language ?? .english + } + ) view.experimentalFunctionsEnabled = settings.experimentalFeaturesEnabled ruuviStorage.readAll().on(success: { [weak self] tags in @@ -59,9 +61,11 @@ extension SettingsPresenter: SettingsViewOutput { .fahrenheit, .kelvin, ] - let viewModel = UnitSettingsViewModel(title: RuuviLocalization.TagSettings.OffsetCorrection.temperature, - items: selectionItems, - measurementType: .temperature) + let viewModel = UnitSettingsViewModel( + title: RuuviLocalization.TagSettings.OffsetCorrection.temperature, + items: selectionItems, + measurementType: .temperature + ) router.openUnitSettings(with: viewModel, output: nil) } @@ -71,9 +75,11 @@ extension SettingsPresenter: SettingsViewOutput { .gm3, .dew, ] - let viewModel = UnitSettingsViewModel(title: RuuviLocalization.TagSettings.OffsetCorrection.humidity, - items: selectionItems, - measurementType: .humidity) + let viewModel = UnitSettingsViewModel( + title: RuuviLocalization.TagSettings.OffsetCorrection.humidity, + items: selectionItems, + measurementType: .humidity + ) router.openUnitSettings(with: viewModel, output: nil) } @@ -83,9 +89,11 @@ extension SettingsPresenter: SettingsViewOutput { .inchesOfMercury, .millimetersOfMercury, ] - let viewModel = UnitSettingsViewModel(title: RuuviLocalization.TagSettings.OffsetCorrection.pressure, - items: selectionItems, - measurementType: .pressure) + let viewModel = UnitSettingsViewModel( + title: RuuviLocalization.TagSettings.OffsetCorrection.pressure, + items: selectionItems, + measurementType: .pressure + ) router.openUnitSettings(with: viewModel, output: nil) } @@ -98,7 +106,8 @@ extension SettingsPresenter: SettingsViewOutput { } func viewDidSelectChangeLanguage() { - guard let settingsURL = URL(string: UIApplication.openSettingsURLString) else { + guard let settingsURL = URL(string: UIApplication.openSettingsURLString) + else { return } UIApplication.shared.open(settingsURL) @@ -125,7 +134,8 @@ extension SettingsPresenter: SettingsViewOutput { } func viewDidTriggerShake() { - guard !settings.experimentalFeaturesEnabled else { + guard !settings.experimentalFeaturesEnabled + else { return } settings.experimentalFeaturesEnabled = true diff --git a/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift index bc177e3de..ed372aa76 100644 --- a/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift @@ -148,8 +148,7 @@ extension SettingsTableViewController { // Add the logic for the cloud mode cell here if !showDefaults && cell == defaultsCell || (!showDevices || !cloudModeVisible) && cell == devicesCell || - !cloudModeVisible && cell == ruuviCloudCell - { + !cloudModeVisible && cell == ruuviCloudCell { return 0 } else { return super.tableView(tableView, heightForRowAt: indexPath) @@ -157,9 +156,10 @@ extension SettingsTableViewController { } // swiftlint:disable:next cyclomatic_complexity - override func tableView(_ tableView: UITableView, - didSelectRowAt indexPath: IndexPath) - { + override func tableView( + _ tableView: UITableView, + didSelectRowAt indexPath: IndexPath + ) { guard let cell = tableView.cellForRow(at: indexPath) else { return } switch cell { case temperatureCell: diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift index 032ec5895..6dfce4c85 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift @@ -56,23 +56,27 @@ extension AppearanceSettingsPresenter { private func startObservingThemeSetting() { themeToken = NotificationCenter .default - .addObserver(forName: .AppearanceSettingsDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.configure() - self?.updateTheme() - }) + .addObserver( + forName: .AppearanceSettingsDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.configure() + self?.updateTheme() + } + ) } private func updateTheme() { - UIView.animate(withDuration: 0.3, - delay: 0.0, - options: .curveLinear, - animations: { [weak self] in - guard let sSelf = self else { return } - UIWindow.key?.overrideUserInterfaceStyle = - sSelf.settings.theme.uiInterfaceStyle - }) + UIView.animate( + withDuration: 0.3, + delay: 0.0, + options: .curveLinear, + animations: { [weak self] in + guard let sSelf = self else { return } + UIWindow.key?.overrideUserInterfaceStyle = + sSelf.settings.theme.uiInterfaceStyle + } + ) } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionPresenter.swift index b3eaca54e..5010dc5f3 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionPresenter.swift @@ -20,9 +20,10 @@ extension ASSelectionPresenter: ASSelectionViewOutput { // No op. } - func viewDidSelectItem(item: SelectionItemProtocol, - type: AppearanceSettingType) - { + func viewDidSelectItem( + item: SelectionItemProtocol, + type: AppearanceSettingType + ) { update(with: item, type: type) } } @@ -34,14 +35,14 @@ extension ASSelectionPresenter: ASSelectionModuleInput { } extension ASSelectionPresenter { - private func update(with selection: SelectionItemProtocol, - type: AppearanceSettingType) - { + private func update( + with selection: SelectionItemProtocol, + type: AppearanceSettingType + ) { switch type { case .theme: if let theme = selection as? RuuviTheme, - let viewModel - { + let viewModel { settings.theme = theme let updatedViewModel = AppearanceSettingsViewModel( title: viewModel.title, diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/ASSelectionViewOutput.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/ASSelectionViewOutput.swift index 2ea4c0970..3b8ae3628 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/ASSelectionViewOutput.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/ASSelectionViewOutput.swift @@ -2,6 +2,8 @@ import Foundation protocol ASSelectionViewOutput { func viewDidLoad() - func viewDidSelectItem(item: SelectionItemProtocol, - type: AppearanceSettingType) + func viewDidSelectItem( + item: SelectionItemProtocol, + type: AppearanceSettingType + ) } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift index 16d687e91..71401485b 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift @@ -10,11 +10,14 @@ class ASSelectionTableViewCell: UITableViewCell { return label }() - override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) - { - super.init(style: style, - reuseIdentifier: reuseIdentifier) + override init( + style: UITableViewCell.CellStyle, + reuseIdentifier: String? + ) { + super.init( + style: style, + reuseIdentifier: reuseIdentifier + ) setUpUI() } @@ -28,11 +31,13 @@ class ASSelectionTableViewCell: UITableViewCell { tintColor = RuuviColor.ruuviTintColor addSubview(titleLabel) - titleLabel.anchor(top: safeTopAnchor, - leading: safeLeftAnchor, - bottom: safeBottomAnchor, - trailing: contentView.safeRightAnchor, - padding: .init(top: 12, left: 20, bottom: 12, right: 8)) + titleLabel.anchor( + top: safeTopAnchor, + leading: safeLeftAnchor, + bottom: safeBottomAnchor, + trailing: contentView.safeRightAnchor, + padding: .init(top: 12, left: 20, bottom: 12, right: 8) + ) } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift index d35a67b3a..b7d0df9dd 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift @@ -46,8 +46,10 @@ private extension ASSelectionTableViewController { func setUpTableView() { tableView.sectionFooterHeight = UITableView.automaticDimension - tableView.register(ASSelectionTableViewCell.self, - forCellReuseIdentifier: reuseIdentifier) + tableView.register( + ASSelectionTableViewCell.self, + forCellReuseIdentifier: reuseIdentifier + ) } func updateUI() { @@ -66,13 +68,15 @@ extension ASSelectionTableViewController { viewModel?.items.count ?? 0 } - override func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell - { + override func tableView( + _ tableView: UITableView, + cellForRowAt indexPath: IndexPath + ) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell( withIdentifier: reuseIdentifier, for: indexPath - ) as? ASSelectionTableViewCell else { + ) as? ASSelectionTableViewCell + else { fatalError() } if let viewModel { @@ -89,13 +93,16 @@ extension ASSelectionTableViewController { // MARK: - UITableViewDelegate extension ASSelectionTableViewController { - override func tableView(_ tableView: UITableView, - didSelectRowAt indexPath: IndexPath) - { + override func tableView( + _ tableView: UITableView, + didSelectRowAt indexPath: IndexPath + ) { tableView.deselectRow(at: indexPath, animated: true) if let viewModel { - output.viewDidSelectItem(item: viewModel.items[indexPath.row], - type: viewModel.type) + output.viewDidSelectItem( + item: viewModel.items[indexPath.row], + type: viewModel.type + ) } } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift index bf8e9d995..e344ce6af 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift @@ -19,11 +19,14 @@ class AppearanceSettingsTableViewBasicCell: UITableViewCell { return label }() - override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) - { - super.init(style: style, - reuseIdentifier: reuseIdentifier) + override init( + style: UITableViewCell.CellStyle, + reuseIdentifier: String? + ) { + super.init( + style: style, + reuseIdentifier: reuseIdentifier + ) setUpUI() } @@ -37,7 +40,7 @@ class AppearanceSettingsTableViewBasicCell: UITableViewCell { accessoryType = .disclosureIndicator let stack = UIStackView(arrangedSubviews: [ - titleLabel, valueLabel, + titleLabel, valueLabel ]) stack.spacing = 4 stack.distribution = .fillProportionally diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift index c6ebf1253..5428b946a 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift @@ -46,8 +46,10 @@ private extension AppearanceSettingsTableViewController { func setUpTableView() { tableView.sectionFooterHeight = UITableView.automaticDimension - tableView.register(AppearanceSettingsTableViewBasicCell.self, - forCellReuseIdentifier: reuseIdentifier) + tableView.register( + AppearanceSettingsTableViewBasicCell.self, + forCellReuseIdentifier: reuseIdentifier + ) } func updateUI() { @@ -66,13 +68,15 @@ extension AppearanceSettingsTableViewController { viewModels.count } - override func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell - { + override func tableView( + _ tableView: UITableView, + cellForRowAt indexPath: IndexPath + ) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell( withIdentifier: reuseIdentifier, for: indexPath - ) as? AppearanceSettingsTableViewBasicCell else { + ) as? AppearanceSettingsTableViewBasicCell + else { fatalError() } let viewModel = viewModels[indexPath.row] @@ -84,9 +88,10 @@ extension AppearanceSettingsTableViewController { // MARK: - UITableViewDelegate extension AppearanceSettingsTableViewController { - override func tableView(_ tableView: UITableView, - didSelectRowAt indexPath: IndexPath) - { + override func tableView( + _ tableView: UITableView, + didSelectRowAt indexPath: IndexPath + ) { tableView.deselectRow(at: indexPath, animated: true) let viewModel = viewModels[indexPath.row] output.viewDidTriggerViewModel(viewModel: viewModel) diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift index 698958d54..19b80543c 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift @@ -18,7 +18,7 @@ class ChartSettingsPresenter: NSObject, ChartSettingsModuleInput { func configure() { let sections: [ChartSettingsSection] = [ - buildDisplayAllDataSection(), + buildDisplayAllDataSection() ] viewModel = ChartSettingsViewModel(sections: sections) } @@ -27,7 +27,7 @@ class ChartSettingsPresenter: NSObject, ChartSettingsModuleInput { ChartSettingsSection( note: RuuviLocalization.ChartSettings.AllPoints.description, cells: [ - buildChartDownsampling(), + buildChartDownsampling() ] ) } @@ -38,7 +38,7 @@ class ChartSettingsPresenter: NSObject, ChartSettingsModuleInput { ChartSettingsSection( note: RuuviLocalization.ChartSettings.DrawDots.description, cells: [ - buildChartDotsDrawing(), + buildChartDotsDrawing() ] ) } @@ -58,8 +58,10 @@ extension ChartSettingsPresenter { private func buildChartDownsampling() -> ChartSettingsCell { let title = RuuviLocalization.ChartSettings.AllPoints.title let value = !settings.chartDownsamplingOn - let type: ChartSettingsCellType = .switcher(title: title, - value: value) + let type: ChartSettingsCellType = .switcher( + title: title, + value: value + ) let cell = ChartSettingsCell(type: type) cell.boolean.value = value bind(cell.boolean, fire: false) { [weak self] observer, value in @@ -73,8 +75,10 @@ extension ChartSettingsPresenter { private func buildChartDotsDrawing() -> ChartSettingsCell { let title = RuuviLocalization.ChartSettings.DrawDots.title let value = settings.chartDrawDotsOn - let type: ChartSettingsCellType = .switcher(title: title, - value: value) + let type: ChartSettingsCellType = .switcher( + title: title, + value: value + ) let cell = ChartSettingsCell(type: type) cell.boolean.value = value bind(cell.boolean, fire: false) { [weak self] observer, value in diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift index b8419fc06..b6eab4eec 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift @@ -32,9 +32,11 @@ enum ChartSettingsIntegerUnit { enum ChartSettingsCellType { case disclosure(title: String) - case stepper(title: String, - value: Int, - unitSingular: ChartSettingsIntegerUnit, - unitPlural: ChartSettingsIntegerUnit) + case stepper( + title: String, + value: Int, + unitSingular: ChartSettingsIntegerUnit, + unitPlural: ChartSettingsIntegerUnit + ) case switcher(title: String, value: Bool) } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift index 0b28ee4b0..135f15728 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift @@ -58,8 +58,10 @@ extension ChartSettingsTableViewController { return cell case let .stepper(title, value, unitSingular, unitPlural): let cell = tableView - .dequeueReusableCell(with: ChartSettingsStepperTableViewCell.self, - for: indexPath) + .dequeueReusableCell( + with: ChartSettingsStepperTableViewCell.self, + for: indexPath + ) let title = title let unit = value > 1 ? unitPlural : unitSingular cell.titleLabel.text = title + " " diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift index abfd2d73b..7e52b11d7 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift @@ -16,27 +16,29 @@ class DefaultsPresenter: NSObject, DefaultsModuleInput { ) func configure(output: DefaultsModuleOutput) { - view.viewModels = [buildWelcomeShown(), - buildChartsSwipeInstruction(), - buildConnectionTimeout(), - buildServiceTimeout(), - buildCardsSwipeHint(), - buildAlertsMuteInterval(), - buildWebPullInterval(), - buildPruningOffsetHours(), - buildChartIntervalSeconds(), - buildChartDurationHours(), - saveAdvertisementsInterval(), - buildAskForReviewFirstTime(), - buildAskForReviewLater(), - buildDashboardCardTapAction(), - buildConnectToDevServer(), - buildHideNFCButtonInSensorContents(), - buildIsAuthorized(), - buildAuthToken(), - buildShowEmailAlertSettings(), - buildShowPushAlertSettings(), - buildIsAuthorized()] + view.viewModels = [ + buildWelcomeShown(), + buildChartsSwipeInstruction(), + buildConnectionTimeout(), + buildServiceTimeout(), + buildCardsSwipeHint(), + buildAlertsMuteInterval(), + buildWebPullInterval(), + buildPruningOffsetHours(), + buildChartIntervalSeconds(), + buildChartDurationHours(), + saveAdvertisementsInterval(), + buildAskForReviewFirstTime(), + buildAskForReviewLater(), + buildDashboardCardTapAction(), + buildConnectToDevServer(), + buildHideNFCButtonInSensorContents(), + buildIsAuthorized(), + buildAuthToken(), + buildShowEmailAlertSettings(), + buildShowPushAlertSettings(), + buildIsAuthorized(), + ] self.output = output } @@ -271,9 +273,10 @@ extension DefaultsPresenter { // This also has to be loaded in the AppAssembly. So, we can't really use // local settings module for this since we load the whole Local settings in // the AppAssembly. - bind(viewModel.boolean, - fire: false) - { [weak self] _, useDevServer in + bind( + viewModel.boolean, + fire: false + ) { [weak self] _, useDevServer in self?.view .showEndpointChangeConfirmationDialog( useDevServer: useDevServer @@ -288,9 +291,10 @@ extension DefaultsPresenter { viewModel.boolean.value = settings.hideNFCForSensorContest viewModel.type.value = .switcher - bind(viewModel.boolean, - fire: false) - { observer, hideNFC in + bind( + viewModel.boolean, + fire: false + ) { observer, hideNFC in observer.settings.hideNFCForSensorContest = hideNFC.bound } return viewModel @@ -334,9 +338,11 @@ extension DefaultsPresenter { ) NotificationCenter .default - .post(name: .NetworkSyncDidFailForAuthorization, - object: self, - userInfo: nil) + .post( + name: .NetworkSyncDidFailForAuthorization, + object: self, + userInfo: nil + ) output?.defaultsModuleDidDismiss(module: self) } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift index 4a1304cf3..68f217505 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift @@ -45,8 +45,10 @@ extension DefaultsTableViewController { case .plain: // swiftlint:disable force_cast let cell = tableView - .dequeueReusableCell(withIdentifier: plainCellReuseIdentifier, - for: indexPath) as! DefaultsPlainTableViewCell + .dequeueReusableCell( + withIdentifier: plainCellReuseIdentifier, + for: indexPath + ) as! DefaultsPlainTableViewCell // swiftlint:enable force_cast cell.titleLabel.text = viewModel.title cell.valueLabel.text = viewModel.value.value ?? RuuviLocalization.na @@ -54,8 +56,10 @@ extension DefaultsTableViewController { case .switcher: // swiftlint:disable force_cast let cell = tableView - .dequeueReusableCell(withIdentifier: switchCellReuseIdentifier, - for: indexPath) as! DefaultsSwitchTableViewCell + .dequeueReusableCell( + withIdentifier: switchCellReuseIdentifier, + for: indexPath + ) as! DefaultsSwitchTableViewCell // swiftlint:enable force_cast cell.titleLabel.text = viewModel.title cell.isOnSwitch.isOn = viewModel.boolean.value ?? false @@ -64,8 +68,10 @@ extension DefaultsTableViewController { case .stepper: // swiftlint:disable force_cast let cell = tableView - .dequeueReusableCell(withIdentifier: stepperCellReuseIdentifier, - for: indexPath) as! DefaultsStepperTableViewCell + .dequeueReusableCell( + withIdentifier: stepperCellReuseIdentifier, + for: indexPath + ) as! DefaultsStepperTableViewCell // swiftlint:enable force_cast let title = viewModel.title ?? "" let unitString: String diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift index 52e1242d0..6286107b7 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift @@ -55,13 +55,15 @@ private extension DevicesTableViewCell { backgroundColor = .clear selectionStyle = .none - let container = UIView(color: RuuviColor.dashboardCardBGColor, - cornerRadius: 8) + let container = UIView( + color: RuuviColor.dashboardCardBGColor, + cornerRadius: 8 + ) contentView.addSubview(container) container.fillSuperview(padding: .init(top: 4, left: 8, bottom: 4, right: 8)) let textStack = UIStackView(arrangedSubviews: [ - deviceNameLabel, tokenIdLabel, lastAccessedLabel, + deviceNameLabel, tokenIdLabel, lastAccessedLabel ]) textStack.spacing = 4 textStack.distribution = .fill diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift index f0a53fdf0..45be1de76 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift @@ -42,32 +42,41 @@ extension DevicesTableViewController: DevicesViewInput { } func showTokenIdDialog(for viewModel: DevicesViewModel) { - guard let tokenId = viewModel.id.value else { + guard let tokenId = viewModel.id.value + else { return } let title = RuuviLocalization.Devices.tokenId - let controller = UIAlertController(title: title, - message: tokenId.stringValue, - preferredStyle: .alert) - controller.addAction(UIAlertAction(title: RuuviLocalization.copy, - style: .default, - handler: { _ in - UIPasteboard.general.string = tokenId.stringValue - })) + let controller = UIAlertController( + title: title, + message: tokenId.stringValue, + preferredStyle: .alert + ) + controller.addAction(UIAlertAction( + title: RuuviLocalization.copy, + style: .default, + handler: { _ in + UIPasteboard.general.string = tokenId.stringValue + } + )) controller.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) present(controller, animated: true) } func showTokenFetchError(with error: RUError) { - let controller = UIAlertController(title: nil, - message: error.localizedDescription, - preferredStyle: .alert) - controller.addAction(UIAlertAction(title: RuuviLocalization.ok, - style: .default, - handler: { [weak self] _ in - self?.navigationController?.popViewController(animated: true) - })) + let controller = UIAlertController( + title: nil, + message: error.localizedDescription, + preferredStyle: .alert + ) + controller.addAction(UIAlertAction( + title: RuuviLocalization.ok, + style: .default, + handler: { [weak self] _ in + self?.navigationController?.popViewController(animated: true) + } + )) present(controller, animated: true) } } @@ -87,8 +96,10 @@ private extension DevicesTableViewController { tableView.estimatedRowHeight = 50 tableView.separatorStyle = .none - tableView.register(DevicesTableViewCell.self, - forCellReuseIdentifier: reuseIndentifier) + tableView.register( + DevicesTableViewCell.self, + forCellReuseIdentifier: reuseIndentifier + ) } } @@ -99,11 +110,14 @@ extension DevicesTableViewController { viewModels.count } - override func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell - { - guard let cell = tableView.dequeueReusableCell(withIdentifier: reuseIndentifier, - for: indexPath) as? DevicesTableViewCell + override func tableView( + _ tableView: UITableView, + cellForRowAt indexPath: IndexPath + ) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell( + withIdentifier: reuseIndentifier, + for: indexPath + ) as? DevicesTableViewCell else { fatalError() } @@ -115,9 +129,10 @@ extension DevicesTableViewController { // MARK: - TABLEVIEW DELEGATE extension DevicesTableViewController { - override func tableView(_: UITableView, - didSelectRowAt indexPath: IndexPath) - { + override func tableView( + _: UITableView, + didSelectRowAt indexPath: IndexPath + ) { output.viewDidTapDevice(viewModel: viewModels[indexPath.row]) } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift index 02b12bda9..ca622865a 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift @@ -13,11 +13,13 @@ import RuuviLocalization } if env.viewModel.bgScanningState.value.bound { - Stepper(RuuviLocalization.Heartbeat.Interval.Every.string - + " " + "\(env.viewModel.bgScanningInterval.value.bound)" - + " " + RuuviLocalization.Heartbeat.Interval.Min.string, + Stepper( + RuuviLocalization.Heartbeat.Interval.Every.string + + " " + "\(env.viewModel.bgScanningInterval.value.bound)" + + " " + RuuviLocalization.Heartbeat.Interval.Min.string, value: $env.viewModel.bgScanningInterval.value.bound, - in: 0 ... 3600) + in: 0 ... 3600 + ) } } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift index 874f00a3d..ce0745e5a 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift @@ -132,42 +132,48 @@ extension NotificationsSettingsPresenter { private func startObservingAlertSoundSetting() { soundSettingsToken = NotificationCenter .default - .addObserver(forName: .AlertSoundSettingsDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.configure() - guard let sSelf = self else { return } - DispatchQueue.main.async { - sSelf.cloudNotificationService.set( - sound: sSelf.settings.alertSound, - language: sSelf.settings.language, - deviceName: UIDevice.modelName - ) - } - }) + .addObserver( + forName: .AlertSoundSettingsDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.configure() + guard let sSelf = self else { return } + DispatchQueue.main.async { + sSelf.cloudNotificationService.set( + sound: sSelf.settings.alertSound, + language: sSelf.settings.language, + deviceName: UIDevice.modelName + ) + } + } + ) } private func startObservingEmailAlertSetting() { emailAlertsSettingsToken = NotificationCenter .default - .addObserver(forName: .EmailAlertSettingsDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.updateEmailViewModel() - }) + .addObserver( + forName: .EmailAlertSettingsDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.updateEmailViewModel() + } + ) } private func startObservingPushAlertSetting() { pushAlertsSettingsToken = NotificationCenter .default - .addObserver(forName: .PushAlertSettingsDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.updatePushViewModel() - }) + .addObserver( + forName: .PushAlertSettingsDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.updatePushViewModel() + } + ) } private func updateEmailViewModel() { diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionPresenter.swift index 8e0edf8a1..4a70d8b28 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionPresenter.swift @@ -22,8 +22,7 @@ extension PushAlertSoundSelectionPresenter: PushAlertSoundSelectionViewOutput { func viewDidSelectItem(item: SelectionItemProtocol) { if let selectedSound = item as? RuuviAlertSound, - let viewModel - { + let viewModel { settings.alertSound = selectedSound let updatedViewModel = PushAlertSoundSelectionViewModel( title: viewModel.title, diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift index 46b2dc270..775ff356e 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift @@ -10,11 +10,14 @@ class PushAlertSelectionTableViewCell: UITableViewCell { return label }() - override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) - { - super.init(style: style, - reuseIdentifier: reuseIdentifier) + override init( + style: UITableViewCell.CellStyle, + reuseIdentifier: String? + ) { + super.init( + style: style, + reuseIdentifier: reuseIdentifier + ) setUpUI() } @@ -28,11 +31,13 @@ class PushAlertSelectionTableViewCell: UITableViewCell { tintColor = RuuviColor.ruuviTintColor addSubview(titleLabel) - titleLabel.anchor(top: safeTopAnchor, - leading: safeLeftAnchor, - bottom: safeBottomAnchor, - trailing: contentView.safeRightAnchor, - padding: .init(top: 12, left: 20, bottom: 12, right: 8)) + titleLabel.anchor( + top: safeTopAnchor, + leading: safeLeftAnchor, + bottom: safeBottomAnchor, + trailing: contentView.safeRightAnchor, + padding: .init(top: 12, left: 20, bottom: 12, right: 8) + ) } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift index c2130f36f..76f5a24e8 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift @@ -65,8 +65,10 @@ private extension PushAlertSoundSelectionTableViewController { func setUpTableView() { tableView.sectionFooterHeight = UITableView.automaticDimension - tableView.register(PushAlertSelectionTableViewCell.self, - forCellReuseIdentifier: reuseIdentifier) + tableView.register( + PushAlertSelectionTableViewCell.self, + forCellReuseIdentifier: reuseIdentifier + ) } func updateUI() { @@ -85,13 +87,15 @@ extension PushAlertSoundSelectionTableViewController { viewModel?.items.count ?? 0 } - override func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell - { + override func tableView( + _ tableView: UITableView, + cellForRowAt indexPath: IndexPath + ) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell( withIdentifier: reuseIdentifier, for: indexPath - ) as? PushAlertSelectionTableViewCell else { + ) as? PushAlertSelectionTableViewCell + else { fatalError() } if let viewModel { @@ -108,9 +112,10 @@ extension PushAlertSoundSelectionTableViewController { // MARK: - UITableViewDelegate extension PushAlertSoundSelectionTableViewController { - override func tableView(_ tableView: UITableView, - didSelectRowAt indexPath: IndexPath) - { + override func tableView( + _ tableView: UITableView, + didSelectRowAt indexPath: IndexPath + ) { tableView.deselectRow(at: indexPath, animated: true) if let viewModel { output.viewDidSelectItem(item: viewModel.items[indexPath.row]) @@ -128,7 +133,8 @@ extension PushAlertSoundSelectionTableViewController { guard let audioURL = Bundle.main.url( forResource: sound.fileName, withExtension: "caf" - ) else { + ) + else { return } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift index fabf1a9d6..e0131e90a 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift @@ -30,17 +30,22 @@ class NotificationsSettingsSwitchCell: UITableViewCell { lazy var statusSwitch: RuuviUISwitch = { let toggle = RuuviUISwitch() toggle.isOn = false - toggle.addTarget(self, - action: #selector(handleStatusToggle), - for: .valueChanged) + toggle.addTarget( + self, + action: #selector(handleStatusToggle), + for: .valueChanged + ) return toggle }() - override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) - { - super.init(style: style, - reuseIdentifier: reuseIdentifier) + override init( + style: UITableViewCell.CellStyle, + reuseIdentifier: String? + ) { + super.init( + style: style, + reuseIdentifier: reuseIdentifier + ) setUpUI() } @@ -56,7 +61,7 @@ class NotificationsSettingsSwitchCell: UITableViewCell { backgroundColor = .clear let textStack = UIStackView(arrangedSubviews: [ - titleLabel, subtitleLabel, + titleLabel, subtitleLabel ]) textStack.spacing = 4 textStack.distribution = .fillProportionally @@ -67,10 +72,12 @@ class NotificationsSettingsSwitchCell: UITableViewCell { leading: contentView.safeLeftAnchor, bottom: contentView.safeBottomAnchor, trailing: nil, - padding: .init(top: 12, - left: 20, - bottom: 12, - right: 0) + padding: .init( + top: 12, + left: 20, + bottom: 12, + right: 0 + ) ) contentView.addSubview(statusSwitch) diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift index 872314e0b..dac9c4d8d 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift @@ -72,22 +72,25 @@ private extension NotificationsSettingsTableViewController { // MARK: - UITableViewDataSource extension NotificationsSettingsTableViewController { - override func tableView(_: UITableView, - numberOfRowsInSection _: Int) -> Int - { + override func tableView( + _: UITableView, + numberOfRowsInSection _: Int + ) -> Int { viewModels.count } - override func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell - { + override func tableView( + _ tableView: UITableView, + cellForRowAt indexPath: IndexPath + ) -> UITableViewCell { let viewModel = viewModels[indexPath.row] switch viewModel.configType.value { case .plain: guard let cell = tableView.dequeueReusableCell( withIdentifier: Self.reuseIdentifierTextCell, for: indexPath - ) as? NotificationsSettingsTextCell else { + ) as? NotificationsSettingsTextCell + else { fatalError() } cell.configure( @@ -100,7 +103,8 @@ extension NotificationsSettingsTableViewController { guard let cell = tableView.dequeueReusableCell( withIdentifier: Self.reuseIdentifierSwitchCell, for: indexPath - ) as? NotificationsSettingsSwitchCell else { + ) as? NotificationsSettingsSwitchCell + else { fatalError() } cell.configure( @@ -115,15 +119,17 @@ extension NotificationsSettingsTableViewController { } } - override func tableView(_: UITableView, - estimatedHeightForFooterInSection _: Int) -> CGFloat - { + override func tableView( + _: UITableView, + estimatedHeightForFooterInSection _: Int + ) -> CGFloat { 100 } - override func tableView(_: UITableView, - viewForFooterInSection _: Int) -> UIView? - { + override func tableView( + _: UITableView, + viewForFooterInSection _: Int + ) -> UIView? { let footerView = UIView() let footerTextView = RuuviLinkTextView( fullTextString: RuuviLocalization.settingsAlertsFooterDescription, @@ -140,9 +146,10 @@ extension NotificationsSettingsTableViewController { // MARK: - UITableViewDelegate extension NotificationsSettingsTableViewController { - override func tableView(_ tableView: UITableView, - didSelectRowAt indexPath: IndexPath) - { + override func tableView( + _ tableView: UITableView, + didSelectRowAt indexPath: IndexPath + ) { tableView.deselectRow(at: indexPath, animated: true) let viewModel = viewModels[indexPath.row] switch viewModel.settingsType.value { @@ -166,7 +173,8 @@ extension NotificationsSettingsTableViewController: NotificationsSettingsSwitchC extension NotificationsSettingsTableViewController: RuuviLinkTextViewDelegate { func didTapLink(url: String) { - guard let settingsURL = URL(string: url) else { + guard let settingsURL = URL(string: url) + else { return } UIApplication.shared.open(settingsURL) diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift index 295fe464d..4b8fc5a53 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift @@ -30,11 +30,14 @@ class NotificationsSettingsTextCell: UITableViewCell { return label }() - override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) - { - super.init(style: style, - reuseIdentifier: reuseIdentifier) + override init( + style: UITableViewCell.CellStyle, + reuseIdentifier: String? + ) { + super.init( + style: style, + reuseIdentifier: reuseIdentifier + ) setUpUI() } @@ -48,14 +51,14 @@ class NotificationsSettingsTextCell: UITableViewCell { accessoryType = .disclosureIndicator let leftStack = UIStackView(arrangedSubviews: [ - titleLabel, subtitleLabel, + titleLabel, subtitleLabel ]) leftStack.spacing = 4 leftStack.distribution = .fillProportionally leftStack.axis = .vertical let fullStack = UIStackView(arrangedSubviews: [ - leftStack, valueLabel, + leftStack, valueLabel ]) fullStack.spacing = 4 fullStack.distribution = .fillProportionally diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift index 93cfc8ad5..7b1b8acd6 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift @@ -19,17 +19,22 @@ class RuuviCloudTableViewCell: UITableViewCell { lazy var statusSwitch: RuuviUISwitch = { let toggle = RuuviUISwitch() toggle.isOn = false - toggle.addTarget(self, - action: #selector(handleStatusToggle), - for: .valueChanged) + toggle.addTarget( + self, + action: #selector(handleStatusToggle), + for: .valueChanged + ) return toggle }() - override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) - { - super.init(style: style, - reuseIdentifier: reuseIdentifier) + override init( + style: UITableViewCell.CellStyle, + reuseIdentifier: String? + ) { + super.init( + style: style, + reuseIdentifier: reuseIdentifier + ) setUpUI() } @@ -45,21 +50,27 @@ class RuuviCloudTableViewCell: UITableViewCell { backgroundColor = .clear addSubview(titleLabel) - titleLabel.anchor(top: safeTopAnchor, - leading: safeLeftAnchor, - bottom: safeBottomAnchor, - trailing: nil, - padding: .init(top: 12, - left: 20, - bottom: 12, - right: 0)) + titleLabel.anchor( + top: safeTopAnchor, + leading: safeLeftAnchor, + bottom: safeBottomAnchor, + trailing: nil, + padding: .init( + top: 12, + left: 20, + bottom: 12, + right: 0 + ) + ) addSubview(statusSwitch) - statusSwitch.anchor(top: nil, - leading: titleLabel.trailingAnchor, - bottom: nil, - trailing: safeRightAnchor, - padding: .init(top: 0, left: 8, bottom: 0, right: 12)) + statusSwitch.anchor( + top: nil, + leading: titleLabel.trailingAnchor, + bottom: nil, + trailing: safeRightAnchor, + padding: .init(top: 0, left: 8, bottom: 0, right: 12) + ) statusSwitch.centerYInSuperview() } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift index 2b1131af3..912edbcd0 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift @@ -51,8 +51,10 @@ private extension RuuviCloudTableViewController { func setUpTableView() { tableView.sectionFooterHeight = UITableView.automaticDimension - tableView.register(RuuviCloudTableViewCell.self, - forCellReuseIdentifier: reuseIdentifier) + tableView.register( + RuuviCloudTableViewCell.self, + forCellReuseIdentifier: reuseIdentifier + ) } func updateUI() { @@ -71,13 +73,15 @@ extension RuuviCloudTableViewController { viewModels.count } - override func tableView(_ tableView: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell - { + override func tableView( + _ tableView: UITableView, + cellForRowAt indexPath: IndexPath + ) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell( withIdentifier: reuseIdentifier, for: indexPath - ) as? RuuviCloudTableViewCell else { + ) as? RuuviCloudTableViewCell + else { fatalError() } let viewModel = viewModels[indexPath.row] diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift index 0f3a6462c..45c4cb226 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift @@ -63,15 +63,16 @@ extension SelectionTableViewController { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let item = viewModel?.items[indexPath.row], let cell = tableView - .dequeueReusableCell(withIdentifier: cellReuseIdentifier, - for: indexPath) as? SelectionTableViewCell + .dequeueReusableCell( + withIdentifier: cellReuseIdentifier, + for: indexPath + ) as? SelectionTableViewCell else { return .init() } if viewModel?.unitSettingsType == .accuracy, - let item = item as? MeasurementAccuracyType - { + let item = item as? MeasurementAccuracyType { let titleProvider = MeasurementAccuracyTitles() let title = titleProvider.formattedTitle(type: item, settings: settings) switch viewModel?.measurementType { @@ -89,7 +90,6 @@ extension SelectionTableViewController { cell.nameLabel.text = RuuviLocalization.na } updateCellStyle(with: title, cell: cell) - } else { if let humidityUnit = item as? HumidityUnit, humidityUnit == .dew { cell.nameLabel.text = item.title(settings.temperatureUnit.symbol) @@ -129,9 +129,10 @@ extension SelectionTableViewController { } } - private func updateCellStyle(with title: String?, - cell: SelectionTableViewCell) - { + private func updateCellStyle( + with title: String?, + cell: SelectionTableViewCell + ) { if title == viewModel?.selection { cell.accessoryType = .checkmark cell.nameLabel.textColor = RuuviColor.ruuviMenuTextColor diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift index 45ff547ce..91e3bfa80 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift @@ -55,13 +55,15 @@ extension UnitSettingsPresenter: UnitSettingsViewOutput { func viewDidSelect(type: UnitSettingsType) { switch type { case .unit: - guard let viewModel = unitViewModel() else { + guard let viewModel = unitViewModel() + else { return } router.openSelection(with: viewModel, output: self) case .accuracy: - guard let viewModel = accuracyViewModel() else { + guard let viewModel = accuracyViewModel() + else { return } router.openSelection(with: viewModel, output: self) @@ -113,34 +115,41 @@ extension UnitSettingsPresenter: SelectionModuleOutput { extension UnitSettingsPresenter { private func unitViewModel() -> SelectionViewModel? { - guard let viewModel else { + guard let viewModel + else { return nil } switch viewModel.measurementType { case .temperature: - return SelectionViewModel(title: RuuviLocalization.Settings.Label.TemperatureUnit.text, - items: viewModel.items, - description: RuuviLocalization.Settings.ChooseTemperatureUnit.text, - selection: settings.temperatureUnit.title(""), - measurementType: viewModel.measurementType, - unitSettingsType: .unit) + return SelectionViewModel( + title: RuuviLocalization.Settings.Label.TemperatureUnit.text, + items: viewModel.items, + description: RuuviLocalization.Settings.ChooseTemperatureUnit.text, + selection: settings.temperatureUnit.title(""), + measurementType: viewModel.measurementType, + unitSettingsType: .unit + ) case .humidity: - return SelectionViewModel(title: RuuviLocalization.Settings.Label.HumidityUnit.text, - items: viewModel.items, - description: RuuviLocalization.Settings.ChooseHumidityUnit.text, - selection: settings.humidityUnit.title(""), - measurementType: viewModel.measurementType, - unitSettingsType: .unit) + return SelectionViewModel( + title: RuuviLocalization.Settings.Label.HumidityUnit.text, + items: viewModel.items, + description: RuuviLocalization.Settings.ChooseHumidityUnit.text, + selection: settings.humidityUnit.title(""), + measurementType: viewModel.measurementType, + unitSettingsType: .unit + ) case .pressure: - return SelectionViewModel(title: RuuviLocalization.Settings.Label.PressureUnit.text, - items: viewModel.items, - description: RuuviLocalization.Settings.ChoosePressureUnit.text, - selection: settings.pressureUnit.title(""), - measurementType: viewModel.measurementType, - unitSettingsType: .unit) + return SelectionViewModel( + title: RuuviLocalization.Settings.Label.PressureUnit.text, + items: viewModel.items, + description: RuuviLocalization.Settings.ChoosePressureUnit.text, + selection: settings.pressureUnit.title(""), + measurementType: viewModel.measurementType, + unitSettingsType: .unit + ) default: return nil @@ -150,7 +159,8 @@ extension UnitSettingsPresenter { private func accuracyViewModel() -> SelectionViewModel? { var accuracyTitle: String var selection: String - guard let measurementType = viewModel?.measurementType else { + guard let measurementType = viewModel?.measurementType + else { return nil } let titleProvider = MeasurementAccuracyTitles() @@ -174,70 +184,82 @@ extension UnitSettingsPresenter { .two, ] - return SelectionViewModel(title: accuracyTitle, - items: selectionItems, - description: RuuviLocalization.Settings.Measurement.Resolution.description, - selection: selection, - measurementType: measurementType, - unitSettingsType: .accuracy) + return SelectionViewModel( + title: accuracyTitle, + items: selectionItems, + description: RuuviLocalization.Settings.Measurement.Resolution.description, + selection: selection, + measurementType: measurementType, + unitSettingsType: .accuracy + ) } // swiftlint:disable:next function_body_length private func observeUnitChanges() { temperatureUnitToken = NotificationCenter .default - .addObserver(forName: .TemperatureUnitDidChange, - object: nil, - queue: .main) - { [weak self] _ in - guard let sSelf = self else { return } - sSelf.view.temperatureUnit = sSelf.settings.temperatureUnit - } + .addObserver( + forName: .TemperatureUnitDidChange, + object: nil, + queue: .main + ) { [weak self] _ in + guard let sSelf = self else { return } + sSelf.view.temperatureUnit = sSelf.settings.temperatureUnit + } temperatureAccuracyToken = NotificationCenter .default - .addObserver(forName: .TemperatureAccuracyDidChange, - object: nil, - queue: .main) - { [weak self] _ in - guard let sSelf = self else { return } - sSelf.view.temperatureAccuracy = sSelf.settings.temperatureAccuracy - } + .addObserver( + forName: .TemperatureAccuracyDidChange, + object: nil, + queue: .main + ) { [weak self] _ in + guard let sSelf = self else { return } + sSelf.view.temperatureAccuracy = sSelf.settings.temperatureAccuracy + } humidityUnitToken = NotificationCenter .default - .addObserver(forName: .HumidityUnitDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - guard let sSelf = self else { return } - sSelf.view.humidityUnit = sSelf.settings.humidityUnit - }) + .addObserver( + forName: .HumidityUnitDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + guard let sSelf = self else { return } + sSelf.view.humidityUnit = sSelf.settings.humidityUnit + } + ) humidityAccuracyToken = NotificationCenter .default - .addObserver(forName: .HumidityAccuracyDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - guard let sSelf = self else { return } - sSelf.view.humidityAccuracy = sSelf.settings.humidityAccuracy - }) + .addObserver( + forName: .HumidityAccuracyDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + guard let sSelf = self else { return } + sSelf.view.humidityAccuracy = sSelf.settings.humidityAccuracy + } + ) pressureUnitToken = NotificationCenter .default - .addObserver(forName: .PressureUnitDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - guard let sSelf = self else { return } - sSelf.view.pressureUnit = sSelf.settings.pressureUnit - }) + .addObserver( + forName: .PressureUnitDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + guard let sSelf = self else { return } + sSelf.view.pressureUnit = sSelf.settings.pressureUnit + } + ) pressureAccuracyToken = NotificationCenter .default - .addObserver(forName: .PressureUnitAccuracyChange, - object: nil, - queue: .main, - using: { [weak self] _ in - guard let sSelf = self else { return } - sSelf.view.pressureAccuracy = sSelf.settings.pressureAccuracy - }) + .addObserver( + forName: .PressureUnitAccuracyChange, + object: nil, + queue: .main, + using: { [weak self] _ in + guard let sSelf = self else { return } + sSelf.view.pressureAccuracy = sSelf.settings.pressureAccuracy + } + ) } private func updateUnits() { diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift index 6b23c4ac4..6c5d8b809 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift @@ -81,8 +81,10 @@ extension UnitSettingsTableViewController { // swiftlint:disable:next cyclomatic_complexity override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - guard let cell = tableView.dequeueReusableCell(withIdentifier: unitSettingsCellReuseIdentifier, - for: indexPath) as? UnitSettingsTableViewCell + guard let cell = tableView.dequeueReusableCell( + withIdentifier: unitSettingsCellReuseIdentifier, + for: indexPath + ) as? UnitSettingsTableViewCell else { return .init() } @@ -103,25 +105,32 @@ extension UnitSettingsTableViewController { default: cell.valueLbl.text = RuuviLocalization.na } - } else { cell.titleLbl.text = RuuviLocalization.Settings.Measurement.Resolution.title let titleProvider = MeasurementAccuracyTitles() switch viewModel?.measurementType { case .temperature: - cell.valueLbl.text = titleProvider.formattedTitle(type: temperatureAccuracy, - settings: settings) + " \(temperatureUnit.symbol)" + cell.valueLbl.text = titleProvider.formattedTitle( + type: temperatureAccuracy, + settings: settings + ) + " \(temperatureUnit.symbol)" case .humidity: if humidityUnit == .dew { - cell.valueLbl.text = titleProvider.formattedTitle(type: humidityAccuracy, - settings: settings) + " \(temperatureUnit.symbol)" + cell.valueLbl.text = titleProvider.formattedTitle( + type: humidityAccuracy, + settings: settings + ) + " \(temperatureUnit.symbol)" } else { - cell.valueLbl.text = titleProvider.formattedTitle(type: humidityAccuracy, - settings: settings) + " \(humidityUnit.symbol)" + cell.valueLbl.text = titleProvider.formattedTitle( + type: humidityAccuracy, + settings: settings + ) + " \(humidityUnit.symbol)" } case .pressure: - cell.valueLbl.text = titleProvider.formattedTitle(type: pressureAccuracy, - settings: settings) + " \(pressureUnit.symbol)" + cell.valueLbl.text = titleProvider.formattedTitle( + type: pressureAccuracy, + settings: settings + ) + " \(pressureUnit.symbol)" default: cell.valueLbl.text = RuuviLocalization.na } diff --git a/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift b/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift index 8db83dc48..9498d5256 100644 --- a/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift +++ b/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift @@ -95,20 +95,25 @@ extension SharePresenter: ShareViewOutput { let message = RuuviLocalization.SharePresenter.UnshareSensor.message(email) let confirmActionTitle = RuuviLocalization.yes let cancelActionTitle = RuuviLocalization.no - let confirmAction = UIAlertAction(title: confirmActionTitle, - style: .default) - { [weak self] _ in + let confirmAction = UIAlertAction( + title: confirmActionTitle, + style: .default + ) { [weak self] _ in self?.unshareTag(email) } - let cancleAction = UIAlertAction(title: cancelActionTitle, - style: .cancel, - handler: nil) + let cancleAction = UIAlertAction( + title: cancelActionTitle, + style: .cancel, + handler: nil + ) let actions = [confirmAction, cancleAction] - let alertViewModel = AlertViewModel(title: title, - message: message, - style: .alert, - actions: actions) + let alertViewModel = AlertViewModel( + title: title, + message: message, + style: .alert, + actions: actions + ) alertPresenter.showAlert(alertViewModel) } } @@ -139,8 +144,7 @@ extension SharePresenter { sensor.luid?.any == self?.sensor.luid?.any) || (sensor.macId?.any != nil && - sensor.macId?.any == self?.sensor.macId?.any) - { + sensor.macId?.any == self?.sensor.macId?.any) { self?.sensor = sensor } default: return @@ -149,7 +153,8 @@ extension SharePresenter { } private func fetchShared() { - guard !sensor.canShare else { + guard !sensor.canShare + else { updateViewModel() return } @@ -161,9 +166,9 @@ extension SharePresenter { if let shareable = shareableSensors .first(where: { $0.id == sSelf.sensor.id - }) - { - guard shareable.canShare else { + }) { + guard shareable.canShare + else { return } diff --git a/station/Classes/Presentation/Modules/Share/View/Cells/ShareEmailTableViewCell.swift b/station/Classes/Presentation/Modules/Share/View/Cells/ShareEmailTableViewCell.swift index f4ae7987b..e3ab3df49 100644 --- a/station/Classes/Presentation/Modules/Share/View/Cells/ShareEmailTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Share/View/Cells/ShareEmailTableViewCell.swift @@ -10,7 +10,8 @@ class ShareEmailTableViewCell: UITableViewCell { weak var delegate: ShareEmailTableViewCellDelegate? @IBAction func didTapUnshareButton(_: UIButton) { - guard let email = emailLabel.text else { + guard let email = emailLabel.text + else { return } delegate?.didTapUnshare(for: email) diff --git a/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift b/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift index b5503d5e7..066df855c 100644 --- a/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift +++ b/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift @@ -23,10 +23,8 @@ extension ShareViewController { switch self { case .description: nil - case .addFriend: - { _, _ in RuuviLocalization.ShareViewController.AddFriend.title } - case .sharedEmails: - { a, b in RuuviLocalization.ShareViewController.SharedEmails.title(a, b) } + case .addFriend: { _, _ in RuuviLocalization.ShareViewController.AddFriend.title } + case .sharedEmails: { a, b in RuuviLocalization.ShareViewController.SharedEmails.title(a, b) } } } } @@ -82,9 +80,10 @@ class ShareViewController: UITableViewController { } } - override func tableView(_: UITableView, - viewForHeaderInSection section: Int) -> UIView? - { + override func tableView( + _: UITableView, + viewForHeaderInSection section: Int + ) -> UIView? { let section = Section(value: section) let headerView = UIView(color: .clear) let titleLabel = UILabel() @@ -94,8 +93,7 @@ class ShareViewController: UITableViewController { switch section { case .sharedEmails: if let count = viewModel.sharedEmails.value?.count, - let title = section.title - { + let title = section.title { titleLabel.text = title(count, viewModel.maxCount) } default: @@ -103,8 +101,12 @@ class ShareViewController: UITableViewController { } headerView.addSubview(titleLabel) titleLabel.fillSuperviewToSafeArea( - padding: .init(top: 0, left: 20, - bottom: 8, right: 20) + padding: .init( + top: 0, + left: 20, + bottom: 8, + right: 20 + ) ) return headerView } @@ -139,7 +141,8 @@ extension ShareViewController: ShareViewInput { func clearInput() { let indexPath = IndexPath(row: 0, section: Section.addFriend.rawValue) - guard let cell = tableView.cellForRow(at: indexPath) as? ShareEmailInputTableViewCell else { + guard let cell = tableView.cellForRow(at: indexPath) as? ShareEmailInputTableViewCell + else { return } cell.emailTextField.text = nil @@ -194,8 +197,10 @@ extension ShareViewController { } private func getDescriptionCell(_ tableView: UITableView, indexPath: IndexPath) -> ShareDescriptionTableViewCell { - let cell = tableView.dequeueReusableCell(with: ShareDescriptionTableViewCell.self, - for: indexPath) + let cell = tableView.dequeueReusableCell( + with: ShareDescriptionTableViewCell.self, + for: indexPath + ) if let canShare = viewModel.canShare.value, canShare { cell.sharingDisabledLabel.text = "" } else { @@ -233,8 +238,10 @@ extension ShareViewController { } @objc private func didTapSendButton(_: UIButton) { - guard let cell = tableView.cellForRow(at: IndexPath(row: 0, - section: Section.addFriend.rawValue)) + guard let cell = tableView.cellForRow(at: IndexPath( + row: 0, + section: Section.addFriend.rawValue + )) as? ShareEmailInputTableViewCell else { return @@ -248,12 +255,14 @@ extension ShareViewController { private func setupCustomBackButton() { let backBarButtonItemView = UIView() backBarButtonItemView.addSubview(backButton) - backButton.anchor(top: backBarButtonItemView.topAnchor, - leading: backBarButtonItemView.leadingAnchor, - bottom: backBarButtonItemView.bottomAnchor, - trailing: backBarButtonItemView.trailingAnchor, - padding: .init(top: 0, left: -12, bottom: 0, right: 0), - size: .init(width: 40, height: 40)) + backButton.anchor( + top: backBarButtonItemView.topAnchor, + leading: backBarButtonItemView.leadingAnchor, + bottom: backBarButtonItemView.bottomAnchor, + trailing: backBarButtonItemView.trailingAnchor, + padding: .init(top: 0, left: -12, bottom: 0, right: 0), + size: .init(width: 40, height: 40) + ) navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backBarButtonItemView) } diff --git a/station/Classes/Presentation/Modules/SignIn/Presenter/SignInModuleInput.swift b/station/Classes/Presentation/Modules/SignIn/Presenter/SignInModuleInput.swift index 2bf53dc8b..f7a133f01 100644 --- a/station/Classes/Presentation/Modules/SignIn/Presenter/SignInModuleInput.swift +++ b/station/Classes/Presentation/Modules/SignIn/Presenter/SignInModuleInput.swift @@ -1,7 +1,9 @@ import Foundation protocol SignInModuleInput: AnyObject { - func configure(with state: SignInPresenter.State, - output: SignInModuleOutput?) + func configure( + with state: SignInPresenter.State, + output: SignInModuleOutput? + ) func dismiss(completion: (() -> Void)?) } diff --git a/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift b/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift index 770658e19..0aeebd76f 100644 --- a/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift +++ b/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift @@ -67,7 +67,8 @@ extension SignInPresenter: SignInViewOutput { } func viewDidTapRequestCodeButton(for email: String?) { - guard let email, isValidEmail(email) else { + guard let email, isValidEmail(email) + else { view.showInvalidEmailEntered() return } @@ -84,8 +85,10 @@ extension SignInPresenter: SignInViewOutput { } func viewDidTapUseWithoutAccount() { - output?.signIn(module: self, - didSelectUseWithoutAccount: nil) + output?.signIn( + module: self, + didSelectUseWithoutAccount: nil + ) } } @@ -121,7 +124,8 @@ extension SignInPresenter { } private func isValidEmail(_ email: String?) -> Bool { - guard let email else { + guard let email + else { return false } let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}" @@ -189,32 +193,38 @@ extension SignInPresenter { private func startObservingUniversalLinks() { universalLinkObservationToken = NotificationCenter .default - .addObserver(forName: .DidOpenWithUniversalLink, - object: nil, - queue: .main, - using: { [weak self] notification in - guard let self, - let userInfo = notification.userInfo - else { - return - } - processLink(userInfo) - }) + .addObserver( + forName: .DidOpenWithUniversalLink, + object: nil, + queue: .main, + using: { [weak self] notification in + guard let self, + let userInfo = notification.userInfo + else { + return + } + processLink(userInfo) + } + ) } private func startObservingAppState() { NotificationCenter .default - .addObserver(self, - selector: #selector(handleAppEnterForgroundState), - name: UIApplication.willEnterForegroundNotification, - object: nil) + .addObserver( + self, + selector: #selector(handleAppEnterForgroundState), + name: UIApplication.willEnterForegroundNotification, + object: nil + ) NotificationCenter .default - .addObserver(self, - selector: #selector(handleAppEnterBackgroundState), - name: UIApplication.didEnterBackgroundNotification, - object: nil) + .addObserver( + self, + selector: #selector(handleAppEnterBackgroundState), + name: UIApplication.didEnterBackgroundNotification, + object: nil + ) } @objc private func handleAppEnterForgroundState() { @@ -269,11 +279,13 @@ extension SignInPresenter { let sound = settings.alertSound let language = settings.language Messaging.messaging().token { [weak self] fcmToken, _ in - self?.cloudNotificationService.set(token: fcmToken, - name: UIDevice.modelName, - data: nil, - language: language, - sound: sound) + self?.cloudNotificationService.set( + token: fcmToken, + name: UIDevice.modelName, + data: nil, + language: language, + sound: sound + ) } } } diff --git a/station/Classes/Presentation/Modules/SignIn/Router/SignInRouter.swift b/station/Classes/Presentation/Modules/SignIn/Router/SignInRouter.swift index 04025894d..3608d17bc 100644 --- a/station/Classes/Presentation/Modules/SignIn/Router/SignInRouter.swift +++ b/station/Classes/Presentation/Modules/SignIn/Router/SignInRouter.swift @@ -11,8 +11,7 @@ class SignInRouter: SignInRouterInput { func popViewController(animated: Bool, completion: (() -> Void)?) { if let navigationController = transitionHandler.navigationController, - navigationController.viewControllers.count > 1 - { + navigationController.viewControllers.count > 1 { // There is at least one view controller that can be popped navigationController.popViewController(animated: animated) } else { diff --git a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsModuleOutput.swift b/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsModuleOutput.swift index b9ceaa1ff..0c51d720b 100644 --- a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsModuleOutput.swift +++ b/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsModuleOutput.swift @@ -1,10 +1,16 @@ import Foundation protocol SignInBenefitsModuleOutput: AnyObject { - func signIn(module: SignInBenefitsModuleInput, - didCloseSignInWithoutAttempt sender: Any?) - func signIn(module: SignInBenefitsModuleInput, - didSelectUseWithoutAccount sender: Any?) - func signIn(module: SignInBenefitsModuleInput, - didSuccessfulyLogin sender: Any?) + func signIn( + module: SignInBenefitsModuleInput, + didCloseSignInWithoutAttempt sender: Any? + ) + func signIn( + module: SignInBenefitsModuleInput, + didSelectUseWithoutAccount sender: Any? + ) + func signIn( + module: SignInBenefitsModuleInput, + didSuccessfulyLogin sender: Any? + ) } diff --git a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift b/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift index b231109b5..73be92e39 100644 --- a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift +++ b/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift @@ -8,10 +8,12 @@ class SignInBenefitsViewController: UIViewController, SignInBenefitsViewInput { // UI Componenets starts private lazy var closeButton: UIBarButtonItem = { - let button = UIBarButtonItem(image: RuuviAssets.closeButtonImage, - style: .plain, - target: self, - action: #selector(handleCloseButtonTap)) + let button = UIBarButtonItem( + image: RuuviAssets.closeButtonImage, + style: .plain, + target: self, + action: #selector(handleCloseButtonTap) + ) button.tintColor = .white return button }() @@ -72,15 +74,21 @@ class SignInBenefitsViewController: UIViewController, SignInBenefitsViewInput { }() private lazy var continueButton: UIButton = { - let button = UIButton(color: RuuviColor.ruuviTintColor, - cornerRadius: 25) - button.setTitle(RuuviLocalization.signInContinue, - for: .normal) + let button = UIButton( + color: RuuviColor.ruuviTintColor, + cornerRadius: 25 + ) + button.setTitle( + RuuviLocalization.signInContinue, + for: .normal + ) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, size: 16) - button.addTarget(self, - action: #selector(handleContinueTap), - for: .touchUpInside) + button.addTarget( + self, + action: #selector(handleContinueTap), + for: .touchUpInside + ) return button }() @@ -156,19 +164,25 @@ extension SignInBenefitsViewController { container.centerInSuperview() titleStack = UIStackView(arrangedSubviews: [ - titleLabel, subtitleLabel, + titleLabel, subtitleLabel ]) titleStack.axis = .vertical titleStack.distribution = .fillProportionally titleStack.spacing = UIDevice.isiPhoneSE() ? 16 : 24 container.addSubview(titleStack) - titleStack.anchor(top: container.safeTopAnchor, - leading: container.safeLeftAnchor, - bottom: nil, - trailing: container.safeRightAnchor, - padding: .init(top: 0, left: !UIDevice.isTablet() ? 20 : 80, - bottom: 0, right: !UIDevice.isTablet() ? 20 : 80)) + titleStack.anchor( + top: container.safeTopAnchor, + leading: container.safeLeftAnchor, + bottom: nil, + trailing: container.safeRightAnchor, + padding: .init( + top: 0, + left: !UIDevice.isTablet() ? 20 : 80, + bottom: 0, + right: !UIDevice.isTablet() ? 20 : 80 + ) + ) container.addSubview(featuresLabel) featuresLabel.anchor( @@ -187,33 +201,47 @@ extension SignInBenefitsViewController { featuresLabel.centerXInSuperview() container.addSubview(noteLabel) - noteLabel.anchor(top: featuresLabel.bottomAnchor, - leading: titleStack.leadingAnchor, - bottom: nil, - trailing: titleStack.trailingAnchor, - padding: .init(top: UIDevice.isiPhoneSE() ? 20 : 30, left: 0, - bottom: 0, right: 0)) + noteLabel.anchor( + top: featuresLabel.bottomAnchor, + leading: titleStack.leadingAnchor, + bottom: nil, + trailing: titleStack.trailingAnchor, + padding: .init( + top: UIDevice.isiPhoneSE() ? 20 : 30, + left: 0, + bottom: 0, + right: 0 + ) + ) container.addSubview(continueButton) - continueButton.anchor(top: noteLabel.bottomAnchor, - leading: container.safeLeftAnchor, - bottom: nil, - trailing: container.safeRightAnchor, - padding: .init(top: UIDevice.isiPhoneSE() ? 20 : 30, - left: !UIDevice.isTablet() ? 50 : 150, - bottom: 0, - right: !UIDevice.isTablet() ? 50 : 150), - size: .init(width: 0, height: 50)) + continueButton.anchor( + top: noteLabel.bottomAnchor, + leading: container.safeLeftAnchor, + bottom: nil, + trailing: container.safeRightAnchor, + padding: .init( + top: UIDevice.isiPhoneSE() ? 20 : 30, + left: !UIDevice.isTablet() ? 50 : 150, + bottom: 0, + right: !UIDevice.isTablet() ? 50 : 150 + ), + size: .init(width: 0, height: 50) + ) container.addSubview(signInOptionalLabel) - signInOptionalLabel.anchor(top: continueButton.bottomAnchor, - leading: container.safeLeftAnchor, - bottom: nil, - trailing: container.safeRightAnchor, - padding: .init(top: UIDevice.isiPhoneSE() ? 6 : 10, - left: 30, - bottom: 0, - right: 30)) + signInOptionalLabel.anchor( + top: continueButton.bottomAnchor, + leading: container.safeLeftAnchor, + bottom: nil, + trailing: container.safeRightAnchor, + padding: .init( + top: UIDevice.isiPhoneSE() ? 6 : 10, + left: 30, + bottom: 0, + right: 30 + ) + ) signInOptionalLabel.bottomAnchor.constraint( lessThanOrEqualTo: container.bottomAnchor, constant: -30 @@ -238,27 +266,35 @@ extension SignInBenefitsViewController { let attrString = NSMutableAttributedString(string: text) let range = NSString(string: attrString.string).range(of: attrString.string) - attrString.addAttribute(NSAttributedString.Key.font, - value: UIFont.Muli(.regular, size: UIDevice.isiPhoneSE() ? 16 : 18), - range: range) + attrString.addAttribute( + NSAttributedString.Key.font, + value: UIFont.Muli(.regular, size: UIDevice.isiPhoneSE() ? 16 : 18), + range: range + ) // Make note bold and orange color let makeBoldOrange = RuuviLocalization.note let boldFont = UIFont.Muli(.bold, size: UIDevice.isiPhoneSE() ? 16 : 18) let boldRange = NSString(string: attrString.string).range(of: makeBoldOrange) - attrString.addAttribute(NSAttributedString.Key.font, - value: boldFont, - range: boldRange) - attrString.addAttribute(.foregroundColor, - value: RuuviColor.ruuviOrangeColor ?? UIColor.systemOrange, - range: boldRange) + attrString.addAttribute( + NSAttributedString.Key.font, + value: boldFont, + range: boldRange + ) + attrString.addAttribute( + .foregroundColor, + value: RuuviColor.ruuviOrangeColor ?? UIColor.systemOrange, + range: boldRange + ) // Make rest of the text white let regularRange = NSString(string: attrString.string) .range(of: RuuviLocalization.claimWarning) - attrString.addAttribute(.foregroundColor, - value: UIColor.white, - range: regularRange) + attrString.addAttribute( + .foregroundColor, + value: UIColor.white, + range: regularRange + ) return attrString } diff --git a/station/Classes/Presentation/Modules/SignIn/View/SignInViewInput.swift b/station/Classes/Presentation/Modules/SignIn/View/SignInViewInput.swift index 2afac9c77..46fc0f5f3 100644 --- a/station/Classes/Presentation/Modules/SignIn/View/SignInViewInput.swift +++ b/station/Classes/Presentation/Modules/SignIn/View/SignInViewInput.swift @@ -3,8 +3,10 @@ import Foundation protocol SignInViewInput: ViewInput { var viewModel: SignInViewModel! { get set } var fromDeepLink: Bool { get set } - func showEmailsAreDifferent(requestedEmail: String, - validatedEmail: String) + func showEmailsAreDifferent( + requestedEmail: String, + validatedEmail: String + ) func showFailedToGetRequestedEmail() func showInvalidTokenEntered() func showInvalidEmailEntered() diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeView.swift b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeView.swift index 9861d7735..708dcd65e 100644 --- a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeView.swift +++ b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeView.swift @@ -38,7 +38,8 @@ class RuuviCodeView: UIStackView { extension RuuviCodeView { // Fill the view with pasted code func autofill(with code: String?) { - guard let code else { + guard let code + else { return } populateRuuviCodeFields(with: code) @@ -148,7 +149,8 @@ extension RuuviCodeView: UITextFieldDelegate { shouldChangeCharactersIn range: NSRange, replacementString string: String ) -> Bool { - guard let textField = textField as? RuuviCodeTextField else { + guard let textField = textField as? RuuviCodeTextField + else { return true } @@ -167,7 +169,8 @@ extension RuuviCodeView: UITextFieldDelegate { populateRuuviCodeFields(with: code) return false } else { - guard textField.previousEntry == nil || textField.previousEntry?.text != "" else { + guard textField.previousEntry == nil || textField.previousEntry?.text != "" + else { return false } if range.length == 0, code.isEmpty { diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift index 63dbf3d60..432a46f74 100644 --- a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift +++ b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift @@ -67,19 +67,25 @@ extension SignInVerifyView { container.fillSuperview() titleStack = UIStackView(arrangedSubviews: [ - titleLabel, subtitleLabel, + titleLabel, subtitleLabel ]) titleStack.axis = .vertical titleStack.distribution = .fillProportionally titleStack.spacing = 16 container.addSubview(titleStack) - titleStack.anchor(top: nil, - leading: container.safeLeftAnchor, - bottom: nil, - trailing: container.safeRightAnchor, - padding: .init(top: 0, left: !UIDevice.isTablet() ? 20 : 80, - bottom: 0, right: !UIDevice.isTablet() ? 20 : 80)) + titleStack.anchor( + top: nil, + leading: container.safeLeftAnchor, + bottom: nil, + trailing: container.safeRightAnchor, + padding: .init( + top: 0, + left: !UIDevice.isTablet() ? 20 : 80, + bottom: 0, + right: !UIDevice.isTablet() ? 20 : 80 + ) + ) titleStack.topAnchor.constraint( equalTo: container.safeTopAnchor ).isActive = true @@ -88,11 +94,14 @@ extension SignInVerifyView { private func setUpCodeEnterView() { container.addSubview(ruuviCodeView) ruuviCodeView.delegate = self - ruuviCodeView.anchor(top: titleStack.bottomAnchor, - leading: nil, - bottom: nil, trailing: nil, - padding: .init(top: 30, left: 0, bottom: 0, right: 0), - size: .init(width: 0, height: 50)) + ruuviCodeView.anchor( + top: titleStack.bottomAnchor, + leading: nil, + bottom: nil, + trailing: nil, + padding: .init(top: 30, left: 0, bottom: 0, right: 0), + size: .init(width: 0, height: 50) + ) ruuviCodeView.centerXInSuperview() } @@ -100,16 +109,20 @@ extension SignInVerifyView { let beaverContainerView = UIView(color: .clear) container.addSubview(beaverContainerView) - beaverContainerView.anchor(top: ruuviCodeView.bottomAnchor, - leading: container.leadingAnchor, - bottom: container.bottomAnchor, - trailing: container.trailingAnchor) + beaverContainerView.anchor( + top: ruuviCodeView.bottomAnchor, + leading: container.leadingAnchor, + bottom: container.bottomAnchor, + trailing: container.trailingAnchor + ) beaverContainerView.addSubview(beaverImageView) - beaverImageView.anchor(top: nil, - leading: beaverContainerView.leadingAnchor, - bottom: nil, - trailing: beaverContainerView.trailingAnchor) + beaverImageView.anchor( + top: nil, + leading: beaverContainerView.leadingAnchor, + bottom: nil, + trailing: beaverContainerView.trailingAnchor + ) beaverImageView.constrainHeight(constant: 400) beaverImageView.image = RuuviAssets.signInBeaver.resize(targetHeight: 400) beaverImageView.centerYInSuperview() @@ -124,7 +137,8 @@ extension SignInVerifyView { extension SignInVerifyView: RuuviCodeViewDelegate { func didFinishTypingCode() { - guard ruuviCodeView.isValidCode else { + guard ruuviCodeView.isValidCode + else { return } let code = ruuviCodeView.ruuviCode() diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift index a5a8f5af5..fdd764b40 100644 --- a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift +++ b/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift @@ -27,8 +27,10 @@ class SignInView: UIView { label.textAlignment = .center label.numberOfLines = 0 label.text = RuuviLocalization.signInOrCreateFreeAccount - label.font = UIFont.Montserrat(.extraBold, - size: UIDevice.isiPhoneSE() ? 24 : 30) + label.font = UIFont.Montserrat( + .extraBold, + size: UIDevice.isiPhoneSE() ? 24 : 30 + ) return label }() @@ -61,15 +63,21 @@ class SignInView: UIView { }() private lazy var requestCodeButton: UIButton = { - let button = UIButton(color: RuuviColor.ruuviTintColor, - cornerRadius: 25) - button.setTitle(RuuviLocalization.requestCode, - for: .normal) + let button = UIButton( + color: RuuviColor.ruuviTintColor, + cornerRadius: 25 + ) + button.setTitle( + RuuviLocalization.requestCode, + for: .normal + ) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, size: UIDevice.isiPhoneSE() ? 14 : 16) - button.addTarget(self, - action: #selector(handleRequestTap), - for: .touchUpInside) + button.addTarget( + self, + action: #selector(handleRequestTap), + for: .touchUpInside + ) return button }() @@ -102,19 +110,25 @@ extension SignInView { container.fillSuperview() titleStack = UIStackView(arrangedSubviews: [ - titleLabel, subtitleLabel, + titleLabel, subtitleLabel ]) titleStack.axis = .vertical titleStack.distribution = .fillProportionally titleStack.spacing = 16 container.addSubview(titleStack) - titleStack.anchor(top: nil, - leading: container.safeLeftAnchor, - bottom: nil, - trailing: container.safeRightAnchor, - padding: .init(top: 0, left: !UIDevice.isTablet() ? 20 : 80, - bottom: 0, right: !UIDevice.isTablet() ? 20 : 80)) + titleStack.anchor( + top: nil, + leading: container.safeLeftAnchor, + bottom: nil, + trailing: container.safeRightAnchor, + padding: .init( + top: 0, + left: !UIDevice.isTablet() ? 20 : 80, + bottom: 0, + right: !UIDevice.isTablet() ? 20 : 80 + ) + ) titleStack.topAnchor.constraint( greaterThanOrEqualTo: container.safeTopAnchor ).isActive = true @@ -122,7 +136,7 @@ extension SignInView { private func setUpTextFieldView() { let textFieldStack = UIStackView(arrangedSubviews: [ - emailTextField, requestCodeButton, + emailTextField, requestCodeButton ]) textFieldStack.axis = .vertical textFieldStack.distribution = .fillEqually @@ -130,21 +144,33 @@ extension SignInView { emailTextField.constrainHeight(constant: 50) container.addSubview(textFieldStack) - textFieldStack.anchor(top: titleStack.bottomAnchor, - leading: container.safeLeftAnchor, - bottom: nil, - trailing: container.safeRightAnchor, - padding: .init(top: 30, left: !UIDevice.isTablet() ? 30 : 100, - bottom: 0, right: !UIDevice.isTablet() ? 30 : 100)) + textFieldStack.anchor( + top: titleStack.bottomAnchor, + leading: container.safeLeftAnchor, + bottom: nil, + trailing: container.safeRightAnchor, + padding: .init( + top: 30, + left: !UIDevice.isTablet() ? 30 : 100, + bottom: 0, + right: !UIDevice.isTablet() ? 30 : 100 + ) + ) textFieldStack.centerYInSuperview() container.addSubview(noPasswordLabel) - noPasswordLabel.anchor(top: textFieldStack.bottomAnchor, - leading: container.safeLeftAnchor, - bottom: nil, - trailing: container.safeRightAnchor, - padding: .init(top: 30, left: !UIDevice.isTablet() ? 30 : 100, - bottom: 0, right: !UIDevice.isTablet() ? 30 : 100)) + noPasswordLabel.anchor( + top: textFieldStack.bottomAnchor, + leading: container.safeLeftAnchor, + bottom: nil, + trailing: container.safeRightAnchor, + padding: .init( + top: 30, + left: !UIDevice.isTablet() ? 30 : 100, + bottom: 0, + right: !UIDevice.isTablet() ? 30 : 100 + ) + ) noPasswordLabel.bottomAnchor.constraint( lessThanOrEqualTo: container.bottomAnchor, constant: 20 ).isActive = true diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift b/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift index 7244d9405..1c968c348 100644 --- a/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift +++ b/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift @@ -20,10 +20,12 @@ class SignInViewController: UIViewController { // UI Componenets starts private lazy var backButton: UIBarButtonItem = { - let button = UIBarButtonItem(image: RuuviAssets.backButtonImage, - style: .plain, - target: self, - action: #selector(handleBackButtonTap)) + let button = UIBarButtonItem( + image: RuuviAssets.backButtonImage, + style: .plain, + target: self, + action: #selector(handleBackButtonTap) + ) button.tintColor = .white return button }() @@ -46,14 +48,18 @@ class SignInViewController: UIViewController { private lazy var useWithoutAccountButton: UIButton = { let button = UIButton() button.setTitleColor(.white, for: .normal) - button.setTitle(RuuviLocalization.useWithoutAccount, - for: .normal) + button.setTitle( + RuuviLocalization.useWithoutAccount, + for: .normal + ) button.titleLabel?.font = UIFont.Muli(.semiBoldItalic, size: 14) button.titleLabel?.numberOfLines = 0 button.titleLabel?.textAlignment = .center - button.addTarget(self, - action: #selector(handleUseWithoutAccountTap), - for: .touchUpInside) + button.addTarget( + self, + action: #selector(handleUseWithoutAccountTap), + for: .touchUpInside + ) button.underline() return button }() @@ -92,7 +98,8 @@ private extension SignInViewController { } private func bindViewModel() { - guard isViewLoaded else { + guard isViewLoaded + else { return } @@ -180,10 +187,12 @@ extension SignInViewController { bgLayer.fillSuperview() view.addSubview(scrollView) - scrollView.anchor(top: view.safeTopAnchor, - leading: nil, - bottom: view.bottomAnchor, - trailing: nil) + scrollView.anchor( + top: view.safeTopAnchor, + leading: nil, + bottom: view.bottomAnchor, + trailing: nil + ) scrollView.centerXInSuperview() scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true } @@ -194,10 +203,12 @@ extension SignInViewController { private func setUpSignInView() { scrollView.addSubview(signInView) - signInView.anchor(top: scrollView.topAnchor, - leading: nil, - bottom: nil, - trailing: nil) + signInView.anchor( + top: scrollView.topAnchor, + leading: nil, + bottom: nil, + trailing: nil + ) signInView.centerXInSuperview() signInView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true signInView.alpha = 1 @@ -206,14 +217,16 @@ extension SignInViewController { private func setUpSignInVerifyView() { scrollView.addSubview(signInVerifyView) - signInVerifyView.anchor(top: scrollView.topAnchor, - leading: scrollView.leadingAnchor, - bottom: scrollView.safeBottomAnchor, - trailing: scrollView.trailingAnchor, - size: .init( - width: 0, - height: view.bounds.height - )) + signInVerifyView.anchor( + top: scrollView.topAnchor, + leading: scrollView.leadingAnchor, + bottom: scrollView.safeBottomAnchor, + trailing: scrollView.trailingAnchor, + size: .init( + width: 0, + height: view.bounds.height + ) + ) signInVerifyView.centerXInSuperview() signInVerifyView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true signInVerifyView.alpha = 0 @@ -222,11 +235,17 @@ extension SignInViewController { private func setUpFooterView() { scrollView.addSubview(useWithoutAccountButton) - useWithoutAccountButton.anchor(top: signInView.bottomAnchor, - leading: view.safeLeftAnchor, - bottom: view.safeBottomAnchor, - trailing: view.safeRightAnchor, - padding: .init(top: 8, left: 20, - bottom: 16, right: 20)) + useWithoutAccountButton.anchor( + top: signInView.bottomAnchor, + leading: view.safeLeftAnchor, + bottom: view.safeBottomAnchor, + trailing: view.safeRightAnchor, + padding: .init( + top: 8, + left: 20, + bottom: 16, + right: 20 + ) + ) } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleInput.swift b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleInput.swift index f6a1e8b93..46aaab8ce 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleInput.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleInput.swift @@ -2,9 +2,11 @@ import Foundation import RuuviOntology protocol TagSettingsModuleInput: AnyObject { - func configure(ruuviTag: RuuviTagSensor, - latestMeasurement: RuuviTagSensorRecord?, - sensorSettings: SensorSettings?) + func configure( + ruuviTag: RuuviTagSensor, + latestMeasurement: RuuviTagSensorRecord?, + sensorSettings: SensorSettings? + ) func configure(output: TagSettingsModuleOutput) func dismiss(completion: (() -> Void)?) } diff --git a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleOutput.swift b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleOutput.swift index f6d3a2101..c531a65ca 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleOutput.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleOutput.swift @@ -2,7 +2,9 @@ import Foundation import RuuviOntology protocol TagSettingsModuleOutput: AnyObject { - func tagSettingsDidDeleteTag(module: TagSettingsModuleInput, - ruuviTag: RuuviTagSensor) + func tagSettingsDidDeleteTag( + module: TagSettingsModuleInput, + ruuviTag: RuuviTagSensor + ) func tagSettingsDidDismiss(module: TagSettingsModuleInput) } diff --git a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift index 8b9cead0b..ef789a61f 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift @@ -113,10 +113,11 @@ class TagSettingsPresenter: NSObject, TagSettingsModuleInput { NotificationCenter.default.removeObserver(self) } - func configure(ruuviTag: RuuviTagSensor, - latestMeasurement: RuuviTagSensorRecord?, - sensorSettings: SensorSettings?) - { + func configure( + ruuviTag: RuuviTagSensor, + latestMeasurement: RuuviTagSensorRecord?, + sensorSettings: SensorSettings? + ) { // TODO: - Check if this can be improved. // Note:(Temporary solution) ViewModel should not depend on this. let tagViewModel = TagSettingsViewModel() @@ -174,23 +175,26 @@ extension TagSettingsPresenter: TagSettingsViewOutput { private func startObservingAppState() { NotificationCenter .default - .addObserver(self, - selector: #selector(handleAppEnterForgroundState), - name: UIApplication.willEnterForegroundNotification, - object: nil) + .addObserver( + self, + selector: #selector(handleAppEnterForgroundState), + name: UIApplication.willEnterForegroundNotification, + object: nil + ) NotificationCenter .default - .addObserver(self, - selector: #selector(handleAppEnterBackgroundState), - name: UIApplication.didEnterBackgroundNotification, - object: nil) + .addObserver( + self, + selector: #selector(handleAppEnterBackgroundState), + name: UIApplication.didEnterBackgroundNotification, + object: nil + ) } @objc private func handleAppEnterForgroundState() { syncAllAlerts() if let keep = viewModel.keepConnection.value, - let connected = viewModel.isConnected.value - { + let connected = viewModel.isConnected.value { if keep, !connected { view.startKeepConnectionAnimatingDots() } @@ -199,8 +203,7 @@ extension TagSettingsPresenter: TagSettingsViewOutput { @objc private func handleAppEnterBackgroundState() { if let keep = viewModel.keepConnection.value, - let connected = viewModel.isConnected.value - { + let connected = viewModel.isConnected.value { if keep, !connected { view.stopKeepConnectionAnimatingDots() } @@ -256,7 +259,8 @@ extension TagSettingsPresenter: TagSettingsViewOutput { } func viewDidTriggerFirmwareUpdateDialog() { - guard let luid = ruuviTag.luid else { + guard let luid = ruuviTag.luid + else { return } if !settings.firmwareUpdateDialogWasShown(for: luid) { @@ -265,7 +269,8 @@ extension TagSettingsPresenter: TagSettingsViewOutput { } func viewDidConfirmFirmwareUpdate() { - guard ruuviTag.luid != nil else { + guard ruuviTag.luid != nil + else { return } router.openUpdateFirmware(ruuviTag: ruuviTag) @@ -556,8 +561,7 @@ extension TagSettingsPresenter { if ruuviTag.name == ruuviTag.luid?.value || ruuviTag.name == ruuviTag.macId?.value, - !ruuviTag.isCloud - { + !ruuviTag.isCloud { viewModel.name.value = nil } else { viewModel.name.value = ruuviTag.name @@ -760,27 +764,27 @@ extension TagSettingsPresenter { private func startSubscribeToBackgroundUploadProgressChanges() { backgroundToken = NotificationCenter .default - .addObserver(forName: .BackgroundPersistenceDidChangeBackground, - object: nil, - queue: .main) - { [weak self] notification in - - guard let sSelf = self else { return } - if let userInfo = notification.userInfo { - let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier - let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier - if (sSelf.ruuviTag.luid?.value != nil && sSelf.ruuviTag.luid?.value == luid?.value) - || (sSelf.ruuviTag.macId?.value != nil && sSelf.ruuviTag.macId?.value == macId?.value) - { - sSelf.ruuviSensorPropertiesService.getImage(for: sSelf.ruuviTag) - .on(success: { [weak sSelf] image in - sSelf?.viewModel.background.value = image - }, failure: { [weak sSelf] error in - sSelf?.errorPresenter.present(error: error) - }) + .addObserver( + forName: .BackgroundPersistenceDidChangeBackground, + object: nil, + queue: .main + ) { [weak self] notification in + + guard let sSelf = self else { return } + if let userInfo = notification.userInfo { + let luid = userInfo[BPDidChangeBackgroundKey.luid] as? LocalIdentifier + let macId = userInfo[BPDidChangeBackgroundKey.macId] as? MACIdentifier + if (sSelf.ruuviTag.luid?.value != nil && sSelf.ruuviTag.luid?.value == luid?.value) + || (sSelf.ruuviTag.macId?.value != nil && sSelf.ruuviTag.macId?.value == macId?.value) { + sSelf.ruuviSensorPropertiesService.getImage(for: sSelf.ruuviTag) + .on(success: { [weak sSelf] image in + sSelf?.viewModel.background.value = image + }, failure: { [weak sSelf] error in + sSelf?.errorPresenter.present(error: error) + }) + } } } - } } private func startObservingRuuviTag() { @@ -789,14 +793,12 @@ extension TagSettingsPresenter { switch change { case let .insert(sensor): if (sensor.luid?.any != nil && sensor.luid?.any == self?.ruuviTag.luid?.any) - || (sensor.macId?.any != nil && sensor.macId?.any == self?.ruuviTag.macId?.any) - { + || (sensor.macId?.any != nil && sensor.macId?.any == self?.ruuviTag.macId?.any) { self?.ruuviTag = sensor } case let .update(sensor): if (sensor.luid?.any != nil && sensor.luid?.any == self?.ruuviTag.luid?.any) - || (sensor.macId?.any != nil && sensor.macId?.any == self?.ruuviTag.macId?.any) - { + || (sensor.macId?.any != nil && sensor.macId?.any == self?.ruuviTag.macId?.any) { self?.ruuviTag = sensor } case let .error(error): @@ -832,29 +834,33 @@ extension TagSettingsPresenter { ruuviTagSensorOwnerCheckToken = NotificationCenter .default - .addObserver(forName: .RuuviTagOwnershipCheckDidEnd, - object: nil, - queue: .main, - using: { [weak self] notification in - guard let sSelf = self, - let userInfo = notification.userInfo, - let hasOwner = userInfo[RuuviTagOwnershipCheckResultKey.hasOwner] as? Bool, - !hasOwner - else { - return - } - sSelf.view.showTagClaimDialog() - }) + .addObserver( + forName: .RuuviTagOwnershipCheckDidEnd, + object: nil, + queue: .main, + using: { [weak self] notification in + guard let sSelf = self, + let userInfo = notification.userInfo, + let hasOwner = userInfo[RuuviTagOwnershipCheckResultKey.hasOwner] as? Bool, + !hasOwner + else { + return + } + sSelf.view.showTagClaimDialog() + } + ) } private func startScanningRuuviTag() { advertisementToken?.invalidate() heartbeatToken?.invalidate() - guard let luid = ruuviTag.luid else { + guard let luid = ruuviTag.luid + else { return } let skip = settings.cloudModeEnabled && ruuviTag.isCloud - guard !skip else { + guard !skip + else { return } advertisementToken = foreground.observe(self, uuid: luid.value, closure: { [weak self] _, device in @@ -870,10 +876,11 @@ extension TagSettingsPresenter { }) } - private func handleMeasurementPoint(tag: RuuviTag, - luid: LocalIdentifier, - source: RuuviTagSensorRecordSource) - { + private func handleMeasurementPoint( + tag: RuuviTag, + luid: LocalIdentifier, + source: RuuviTagSensorRecordSource + ) { // Trigger firmware aler dialog for DF3 tags. if !firmwareUpdateDialogShown, tag.version < 5 { view.showFirmwareUpdateDialog() @@ -895,10 +902,11 @@ extension TagSettingsPresenter { } } - private func sync(device: RuuviTag, - luid _: LocalIdentifier, - source: RuuviTagSensorRecordSource) - { + private func sync( + device: RuuviTag, + luid _: LocalIdentifier, + source: RuuviTagSensorRecordSource + ) { let record = RuuviTagSensorRecordStruct( luid: device.luid, date: device.date, @@ -945,7 +953,8 @@ extension TagSettingsPresenter { viewModel.isConnectable.value = device.isConnectable } } else { - guard !device.isConnected else { + guard !device.isConnected + else { return } viewModel.isConnected.value = false @@ -1006,69 +1015,78 @@ extension TagSettingsPresenter { private func startObservingSettingsChanges() { temperatureUnitToken = NotificationCenter .default - .addObserver(forName: .TemperatureUnitDidChange, - object: nil, - queue: .main) - { [weak self] _ in - self?.viewModel.temperatureUnit.value = self?.settings.temperatureUnit - } + .addObserver( + forName: .TemperatureUnitDidChange, + object: nil, + queue: .main + ) { [weak self] _ in + self?.viewModel.temperatureUnit.value = self?.settings.temperatureUnit + } humidityUnitToken = NotificationCenter .default - .addObserver(forName: .HumidityUnitDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.viewModel.humidityUnit.value = self?.settings.humidityUnit - }) + .addObserver( + forName: .HumidityUnitDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.viewModel.humidityUnit.value = self?.settings.humidityUnit + } + ) pressureUnitToken = NotificationCenter .default - .addObserver(forName: .PressureUnitDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.viewModel.pressureUnit.value = self?.settings.pressureUnit - }) + .addObserver( + forName: .PressureUnitDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.viewModel.pressureUnit.value = self?.settings.pressureUnit + } + ) } private func startObservingConnectionStatus() { connectToken = NotificationCenter .default - .addObserver(forName: .BTBackgroundDidConnect, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let uuid = userInfo[BTBackgroundDidConnectKey.uuid] as? String, - uuid == self?.ruuviTag.luid?.value - { - self?.viewModel.isConnected.value = true - } - }) + .addObserver( + forName: .BTBackgroundDidConnect, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let uuid = userInfo[BTBackgroundDidConnectKey.uuid] as? String, + uuid == self?.ruuviTag.luid?.value { + self?.viewModel.isConnected.value = true + } + } + ) disconnectToken = NotificationCenter .default - .addObserver(forName: .BTBackgroundDidDisconnect, - object: nil, - queue: .main, - using: { [weak self] notification in - if let userInfo = notification.userInfo, - let uuid = userInfo[BTBackgroundDidDisconnectKey.uuid] as? String, - uuid == self?.ruuviTag.luid?.value - { - self?.viewModel.isConnected.value = false - } - }) + .addObserver( + forName: .BTBackgroundDidDisconnect, + object: nil, + queue: .main, + using: { [weak self] notification in + if let userInfo = notification.userInfo, + let uuid = userInfo[BTBackgroundDidDisconnectKey.uuid] as? String, + uuid == self?.ruuviTag.luid?.value { + self?.viewModel.isConnected.value = false + } + } + ) } private func startObservingApplicationState() { appDidBecomeActiveToken = NotificationCenter .default - .addObserver(forName: UIApplication.didBecomeActiveNotification, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.checkPushNotificationsStatus() - }) + .addObserver( + forName: UIApplication.didBecomeActiveNotification, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.checkPushNotificationsStatus() + } + ) } private func checkPushNotificationsStatus() { @@ -1093,55 +1111,52 @@ extension TagSettingsPresenter { private func startObservingAlertChanges() { alertDidChangeToken = NotificationCenter .default - .addObserver(forName: .RuuviServiceAlertDidChange, - object: nil, - queue: .main, - using: { [weak self] notification in - guard let isSyncing = self?.settings.isSyncing, isSyncing else { - return - } - if let userInfo = notification.userInfo { - if let physicalSensor - = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor, - physicalSensor.id == self?.viewModel.uuid.value, - let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType - { - self?.updateIsOnState(of: type, for: physicalSensor.id) - self?.updateMutedTill(of: type, for: physicalSensor.id) - self?.syncAlerts(of: type) - } - } - }) + .addObserver( + forName: .RuuviServiceAlertDidChange, + object: nil, + queue: .main, + using: { [weak self] notification in + guard let isSyncing = self?.settings.isSyncing, isSyncing + else { + return + } + if let userInfo = notification.userInfo { + if let physicalSensor + = userInfo[RuuviServiceAlertDidChangeKey.physicalSensor] as? PhysicalSensor, + physicalSensor.id == self?.viewModel.uuid.value, + let type = userInfo[RuuviServiceAlertDidChangeKey.type] as? AlertType { + self?.updateIsOnState(of: type, for: physicalSensor.id) + self?.updateMutedTill(of: type, for: physicalSensor.id) + self?.syncAlerts(of: type) + } + } + } + ) } private func reloadMutedTill() { if let mutedTill = viewModel.temperatureAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.temperatureAlertMutedTill.value = nil } if let mutedTill = viewModel.pressureAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.pressureAlertMutedTill.value = nil } if let mutedTill = viewModel.signalAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.signalAlertMutedTill.value = nil } if let mutedTill = viewModel.connectionAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.connectionAlertMutedTill.value = nil } if let mutedTill = viewModel.movementAlertMutedTill.value, - mutedTill < Date() - { + mutedTill < Date() { viewModel.movementAlertMutedTill.value = nil } } @@ -1202,27 +1217,34 @@ extension TagSettingsPresenter { } private func processAlerts() { - guard let lastMeasurement else { + guard let lastMeasurement + else { return } if ruuviTag.isCloud, - let macId = ruuviTag.macId - { - alertHandler.processNetwork(record: lastMeasurement, - trigger: false, - for: macId) + let macId = ruuviTag.macId { + alertHandler.processNetwork( + record: lastMeasurement, + trigger: false, + for: macId + ) } else { if ruuviTag.luid?.value != nil { - alertHandler.process(record: lastMeasurement, - trigger: false) + alertHandler.process( + record: lastMeasurement, + trigger: false + ) } else { - guard let macId = ruuviTag.macId else { + guard let macId = ruuviTag.macId + else { return } - alertHandler.processNetwork(record: lastMeasurement, - trigger: false, - for: macId) + alertHandler.processNetwork( + record: lastMeasurement, + trigger: false, + for: macId + ) } } } @@ -1233,8 +1255,7 @@ extension TagSettingsPresenter { guard let self else { return } invalidateTimer() if let isConnected = viewModel.isConnected.value, - !isConnected - { + !isConnected { viewModel.keepConnection.value = false view.resetKeepConnectionSwitch() view.showKeepConnectionTimeoutDialog() @@ -1256,11 +1277,12 @@ extension TagSettingsPresenter: RuuviNotifierObserver { // No op here. } - func ruuvi(notifier _: RuuviNotifier, - alertType: AlertType, - isTriggered: Bool, - for uuid: String) - { + func ruuvi( + notifier _: RuuviNotifier, + alertType: AlertType, + isTriggered: Bool, + for uuid: String + ) { if ruuviTag.luid?.value == uuid || ruuviTag.macId?.value == uuid { let isFireable = ruuviTag.isCloud || viewModel.isConnected.value ?? false switch alertType { @@ -1317,8 +1339,7 @@ extension TagSettingsPresenter { let temperatureUpper = viewModel.temperatureUpperBound.value if let l = temperatureLower?.converted(to: .celsius).value, - let u = temperatureUpper?.converted(to: .celsius).value - { + let u = temperatureUpper?.converted(to: .celsius).value { let type: AlertType = .temperature(lower: l, upper: u) let currentState = alertService.isOn( type: type, for: ruuviTag @@ -1451,8 +1472,7 @@ extension TagSettingsPresenter { let pressureUpper = viewModel.pressureUpperBound.value if let l = pressureLower?.converted(to: .hectopascals).value, - let u = pressureUpper?.converted(to: .hectopascals).value - { + let u = pressureUpper?.converted(to: .hectopascals).value { let type: AlertType = .pressure(lower: l, upper: u) let currentState = alertService.isOn(type: type, for: ruuviTag) if currentState != isOn { @@ -1678,18 +1698,22 @@ extension TagSettingsPresenter { // Notify daemon to restart NotificationCenter .default - .post(name: .RuuviTagAdvertisementDaemonShouldRestart, - object: nil, - userInfo: nil) + .post( + name: .RuuviTagAdvertisementDaemonShouldRestart, + object: nil, + userInfo: nil + ) } private func notifyRestartHeartBeatDaemon() { // Notify daemon to restart NotificationCenter .default - .post(name: .RuuviTagHeartBeatDaemonShouldRestart, - object: nil, - userInfo: nil) + .post( + name: .RuuviTagHeartBeatDaemonShouldRestart, + object: nil, + userInfo: nil + ) } func checkAndUpdateFirmwareVersion() { @@ -1721,8 +1745,7 @@ extension TagSettingsPresenter { // Otherwise proceed to removal directly. if let luid = ruuviTag.luid, let isConnected = viewModel.isConnected.value, - isConnected - { + isConnected { connectionPersistence.setKeepConnection(false, for: luid) notifyRestartHeartBeatDaemon() } @@ -1730,8 +1753,7 @@ extension TagSettingsPresenter { if ruuviTag.isOwner { notifyRestartAdvertisementDaemon() if let isConnected = viewModel.isConnected.value, - isConnected - { + isConnected { notifyRestartHeartBeatDaemon() } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift b/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift index 7fe6d6b3a..92711f5dd 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift @@ -35,18 +35,21 @@ class TagSettingsRouter: NSObject, TagSettingsRouterInput { let restorationId = "ShareViewController" let factory = StoryboardFactory(storyboardName: "Share", bundle: .main, restorationId: restorationId) try? transitionHandler - .forStoryboard(factory: factory, - to: ShareModuleInput.self) + .forStoryboard( + factory: factory, + to: ShareModuleInput.self + ) .to(preferred: .navigation(style: .push)) .then { module -> Any? in module.configure(sensor: sensor) } } - func openOffsetCorrection(type: OffsetCorrectionType, - ruuviTag: RuuviTagSensor, - sensorSettings: SensorSettings?) - { + func openOffsetCorrection( + type: OffsetCorrectionType, + ruuviTag: RuuviTagSensor, + sensorSettings: SensorSettings? + ) { let factory = StoryboardFactory(storyboardName: "OffsetCorrection") try? transitionHandler .forStoryboard(factory: factory, to: OffsetCorrectionModuleInput.self) diff --git a/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouterInput.swift b/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouterInput.swift index 78a3b6411..235886e8a 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouterInput.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouterInput.swift @@ -7,9 +7,11 @@ protocol TagSettingsRouterInput { func dismissToRoot(completion: (() -> Void)?) func openBackgroundSelectionView(ruuviTag: RuuviTagSensor) func openShare(for sensor: RuuviTagSensor) - func openOffsetCorrection(type: OffsetCorrectionType, - ruuviTag: RuuviTagSensor, - sensorSettings: SensorSettings?) + func openOffsetCorrection( + type: OffsetCorrectionType, + ruuviTag: RuuviTagSensor, + sensorSettings: SensorSettings? + ) func openUpdateFirmware(ruuviTag: RuuviTagSensor) func openOwner(ruuviTag: RuuviTagSensor, mode: OwnershipMode) func openContest(ruuviTag: RuuviTagSensor) diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift index c9a7aec26..3b6b98b9e 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift @@ -34,19 +34,22 @@ extension DFUInteractor: DFUInteractorInput { firmwareUrl = fullUrl } - guard let firmware = ruuviDFU.firmwareFromUrl(url: firmwareUrl) else { + guard let firmware = ruuviDFU.firmwareFromUrl(url: firmwareUrl) + else { return Fail(error: DFUError.failedToConstructFirmwareFromFile).eraseToAnyPublisher() } return ruuviDFU.flashFirmware(uuid: uuid, with: firmware).eraseToAnyPublisher() } func read(release: LatestRelease) -> AnyPublisher<(appUrl: URL, fullUrl: URL), Error> { - guard let fullName = release.defaultFullZipName else { + guard let fullName = release.defaultFullZipName + else { return Fail<(appUrl: URL, fullUrl: URL), Error>( error: DFUError.failedToGetFirmwareName ).eraseToAnyPublisher() } - guard let appName = release.defaultAppZipName else { + guard let appName = release.defaultAppZipName + else { return Fail<(appUrl: URL, fullUrl: URL), Error>( error: DFUError.failedToGetFirmwareName ).eraseToAnyPublisher() @@ -116,22 +119,24 @@ extension DFUInteractor: DFUInteractorInput { func loadLatestRelease() -> AnyPublisher { let urlString = "https://api.github.com/repos/ruuvi/ruuvi.firmware.c/releases/latest" - guard let url = URL(string: urlString) else { + guard let url = URL(string: urlString) + else { return Fail(error: URLError(.badURL)).eraseToAnyPublisher() } return URLSession.shared.dataTaskPublisher(for: url) - .map(\.data) - .decode(type: LatestRelease.self, decoder: JSONDecoder()) - .catch { error in Fail(error: error) } - .receive(on: RunLoop.main) - .eraseToAnyPublisher() + .map(\.data) + .decode(type: LatestRelease.self, decoder: JSONDecoder()) + .catch { error in Fail(error: error) } + .receive(on: RunLoop.main) + .eraseToAnyPublisher() } func serveCurrentRelease(for ruuviTag: RuuviTagSensor) -> Future { Future { [weak self] promise in guard let sSelf = self else { return } - guard let uuid = ruuviTag.luid?.value else { + guard let uuid = ruuviTag.luid?.value + else { promise(.failure(DFUError.failedToGetLuid)) return } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift index a3a36cf2c..650ba3fea 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift @@ -114,7 +114,8 @@ final class DFUViewModel: ObservableObject { // Usually tags without macId are stored in the realm database // For tags with macId don't need migration if ruuviTag.macId != nil { - guard let currentRelease else { + guard let currentRelease + else { return } isLoading = true @@ -146,19 +147,22 @@ final class DFUViewModel: ObservableObject { } private func startObserving() { - guard let luid = ruuviTag.luid else { + guard let luid = ruuviTag.luid + else { isLoading = false return } ruuviTagObserveToken?.invalidate() - ruuviTagObserveToken = foreground.observe(self, - uuid: luid.value, - options: [.callbackQueue(.untouch)]) - { + ruuviTagObserveToken = foreground.observe( + self, + uuid: luid.value, + options: [.callbackQueue(.untouch)] + ) { [weak self] _, device in guard let sSelf = self else { return } if let tag = device.ruuvi?.tag { - guard !sSelf.isMigrating else { + guard !sSelf.isMigrating + else { return } sSelf.ruuviTagObserveToken?.invalidate() @@ -178,9 +182,10 @@ final class DFUViewModel: ObservableObject { } /// This method creates the updated instance of the Ruuvi Tag after firmware update. - private func moveTagToSqlite(mac: MACIdentifier, - pair: RuuviTagPropertiesDaemonPair) - { + private func moveTagToSqlite( + mac: MACIdentifier, + pair: RuuviTagPropertiesDaemonPair + ) { sqiltePersistence.create( pair.ruuviTag .with(macId: mac) @@ -196,12 +201,14 @@ final class DFUViewModel: ObservableObject { /// This method fetches the latest record from the Realm and creates the same record to SQLite. /// If there's no record move to the next step. - private func moveLatestRecordToSqlite(mac: MACIdentifier, - pair: RuuviTagPropertiesDaemonPair) - { + private func moveLatestRecordToSqlite( + mac: MACIdentifier, + pair: RuuviTagPropertiesDaemonPair + ) { realmPersistence.readLatest(pair.ruuviTag).on(success: { [weak self] record in // If there's no record move to next action - guard let record else { + guard let record + else { self?.moveRecordsHistoryToSqlite(mac: mac, pair: pair) return } @@ -217,11 +224,13 @@ final class DFUViewModel: ObservableObject { /// This method fetches the all the records from the Realm and creates the same records to SQLite. /// If there are no records move to the next step. - private func moveRecordsHistoryToSqlite(mac: MACIdentifier, - pair: RuuviTagPropertiesDaemonPair) - { + private func moveRecordsHistoryToSqlite( + mac: MACIdentifier, + pair: RuuviTagPropertiesDaemonPair + ) { realmPersistence.readAll(pair.device.uuid).on(success: { [weak self] realmRecords in - guard realmRecords.count > 0 else { + guard realmRecords.count > 0 + else { self?.moveSettingsToSqlite(mac: mac, pair: pair) return } @@ -239,9 +248,10 @@ final class DFUViewModel: ObservableObject { /// This method fetches the sensor settings from the Realm and creates the same sensor settings record to SQLite. /// If there's no record move to the next step. - private func moveSettingsToSqlite(mac: MACIdentifier, - pair: RuuviTagPropertiesDaemonPair) - { + private func moveSettingsToSqlite( + mac: MACIdentifier, + pair: RuuviTagPropertiesDaemonPair + ) { realmPersistence.readSensorSettings(pair.ruuviTag.withoutMac()) .on(success: { [weak self] sensorSettings in if let withMacSettings = sensorSettings?.with(macId: mac) { @@ -296,8 +306,10 @@ final class DFUViewModel: ObservableObject { .readLatest(ruuviTag) .on(success: { record in let batteryNeedsReplacement = batteryStatusProvider - .batteryNeedsReplacement(temperature: record?.temperature, - voltage: record?.voltage) + .batteryNeedsReplacement( + temperature: record?.temperature, + voltage: record?.voltage + ) completion(batteryNeedsReplacement) }, failure: { _ in completion(false) @@ -522,7 +534,8 @@ extension DFUViewModel { uuid, appUrl, fullUrl - ) = state, let sSelf = self else { + ) = state, let sSelf = self + else { return Empty().eraseToAnyPublisher() } return sSelf.interactor.flash( @@ -617,7 +630,8 @@ extension DFUViewModel { func whenServing() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in - guard case .serving = state, let sSelf = self else { + guard case .serving = state, let sSelf = self + else { return Empty().eraseToAnyPublisher() } return sSelf.interactor.serveCurrentRelease(for: sSelf.ruuviTag) @@ -630,7 +644,8 @@ extension DFUViewModel { func whenLoading() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in - guard case .loading = state, let sSelf = self else { + guard case .loading = state, let sSelf = self + else { return Empty().eraseToAnyPublisher() } return sSelf.interactor.loadLatestRelease() @@ -643,7 +658,8 @@ extension DFUViewModel { func whenDownloading() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in - guard case let .downloading(latestRelease, currentRelease) = state, let sSelf = self else { + guard case let .downloading(latestRelease, currentRelease) = state, let sSelf = self + else { return Empty().eraseToAnyPublisher() } return sSelf.interactor.download(release: latestRelease) @@ -664,7 +680,8 @@ extension DFUViewModel { func whenFlashed() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in - guard case .successfulyFlashed = state, let sSelf = self else { + guard case .successfulyFlashed = state, let sSelf = self + else { return Empty().eraseToAnyPublisher() } return sSelf.interactor.serveCurrentRelease(for: sSelf.ruuviTag) @@ -677,7 +694,8 @@ extension DFUViewModel { func whenServingAfterUpdate() -> Feedback { Feedback { [weak self] (state: State) -> AnyPublisher in - guard case .servingAfterUpdate = state, let sSelf = self else { + guard case .servingAfterUpdate = state, let sSelf = self + else { return Empty().eraseToAnyPublisher() } return sSelf.interactor.serveCurrentRelease(for: sSelf.ruuviTag) diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift index 0280f84c5..e897bf587 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift @@ -43,9 +43,11 @@ struct DFUUIView: View { VStack { content .alert(isPresented: $viewModel.isMigrationFailed) { - Alert(title: Text(texts.errorTitle), - message: Text(texts.dbMigrationErrorTitle), - dismissButton: .cancel(Text(texts.okTitle))) + Alert( + title: Text(texts.errorTitle), + message: Text(texts.dbMigrationErrorTitle), + dismissButton: .cancel(Text(texts.okTitle)) + ) } } .background(Color(RuuviColor.ruuviPrimarySUI!).edgesIgnoringSafeArea(.all)) @@ -228,9 +230,11 @@ struct DFUUIView: View { }) }) .alert(isPresented: $isBatteryLow) { - Alert(title: Text(""), - message: Text(texts.lowBatteryWarningMessage), - dismissButton: .cancel(Text(texts.okTitle))) + Alert( + title: Text(""), + message: Text(texts.lowBatteryWarningMessage), + dismissButton: .cancel(Text(texts.okTitle)) + ) } .padding() .eraseToAnyView() diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift index 5cd7b6e44..27c9c613d 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift @@ -96,7 +96,8 @@ extension SensorForceClaimPresenter { } private func getTagSecretFromGatt() { - guard let luid = ruuviTag?.luid else { + guard let luid = ruuviTag?.luid + else { return } activityPresenter.show(with: .loading(message: nil)) diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift index f262c72b3..7c936fca1 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift @@ -27,14 +27,18 @@ class SensorForceClaimViewController: UIViewController { }() private lazy var claimSensorButton: UIButton = { - let button = UIButton(color: RuuviColor.ruuviTintColor, - cornerRadius: 25) + let button = UIButton( + color: RuuviColor.ruuviTintColor, + cornerRadius: 25 + ) button.setTitle(RuuviLocalization.forceClaim, for: .normal) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, size: 16) - button.addTarget(self, - action: #selector(handleClaimSensorTap), - for: .touchUpInside) + button.addTarget( + self, + action: #selector(handleClaimSensorTap), + for: .touchUpInside + ) return button }() @@ -55,32 +59,40 @@ class SensorForceClaimViewController: UIViewController { }() private lazy var useNFCButton: UIButton = { - let button = UIButton(color: RuuviColor.ruuviTintColor, - cornerRadius: 25) + let button = UIButton( + color: RuuviColor.ruuviTintColor, + cornerRadius: 25 + ) button.setTitle( RuuviLocalization.useNfc, for: .normal ) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, size: 16) - button.addTarget(self, - action: #selector(handleUseNFCButtonTap), - for: .touchUpInside) + button.addTarget( + self, + action: #selector(handleUseNFCButtonTap), + for: .touchUpInside + ) return button }() private lazy var useBluetoothButton: UIButton = { - let button = UIButton(color: RuuviColor.ruuviTintColor, - cornerRadius: 25) + let button = UIButton( + color: RuuviColor.ruuviTintColor, + cornerRadius: 25 + ) button.setTitle( RuuviLocalization.useBluetooth, for: .normal ) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, size: 16) - button.addTarget(self, - action: #selector(handleUseBluetoothButtonTap), - for: .touchUpInside) + button.addTarget( + self, + action: #selector(handleUseBluetoothButtonTap), + for: .touchUpInside + ) return button }() @@ -164,12 +176,14 @@ extension SensorForceClaimViewController { let backBarButtonItemView = UIView() backBarButtonItemView.addSubview(backButton) - backButton.anchor(top: backBarButtonItemView.topAnchor, - leading: backBarButtonItemView.leadingAnchor, - bottom: backBarButtonItemView.bottomAnchor, - trailing: backBarButtonItemView.trailingAnchor, - padding: .init(top: 0, left: -12, bottom: 0, right: 0), - size: .init(width: 40, height: 40)) + backButton.anchor( + top: backBarButtonItemView.topAnchor, + leading: backBarButtonItemView.leadingAnchor, + bottom: backBarButtonItemView.bottomAnchor, + trailing: backBarButtonItemView.trailingAnchor, + padding: .init(top: 0, left: -12, bottom: 0, right: 0), + size: .init(width: 40, height: 40) + ) navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backBarButtonItemView) } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionPresenter.swift index 3a3342390..b28d3bfb7 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionPresenter.swift @@ -149,13 +149,16 @@ extension OffsetCorrectionPresenter: OffsetCorrectionViewOutput { } private func notifyCalibrationSettingsUpdate() { - NotificationCenter.default.post(name: .SensorCalibrationDidChange, - object: self, - userInfo: nil) + NotificationCenter.default.post( + name: .SensorCalibrationDidChange, + object: self, + userInfo: nil + ) } private func observeRuuviTagUpdate() { - guard let luid = ruuviTag.luid?.value else { + guard let luid = ruuviTag.luid?.value + else { return } if !(settings.cloudModeEnabled && ruuviTag.isCloud) { @@ -173,8 +176,7 @@ extension OffsetCorrectionPresenter: OffsetCorrectionViewOutput { ruuviTagObserveLastRecordToken?.invalidate() ruuviTagObserveLastRecordToken = ruuviReactor.observeLatest(ruuviTag) { [weak self] changes in if case let .update(anyRecord) = changes, - let record = anyRecord - { + let record = anyRecord { self?.lastSensorRecord = record self?.view.viewModel.update( ruuviTagRecord: record.with(sensorSettings: self?.sensorSettings) @@ -186,25 +188,30 @@ extension OffsetCorrectionPresenter: OffsetCorrectionViewOutput { private func startObservingSettingsChanges() { temperatureUnitSettingToken = NotificationCenter.default - .addObserver(forName: .TemperatureUnitDidChange, - object: nil, - queue: .main) - { [weak self] _ in - self?.view.viewModel.temperatureUnit.value = self?.settings.temperatureUnit - } + .addObserver( + forName: .TemperatureUnitDidChange, + object: nil, + queue: .main + ) { [weak self] _ in + self?.view.viewModel.temperatureUnit.value = self?.settings.temperatureUnit + } humidityUnitSettingToken = NotificationCenter.default - .addObserver(forName: .HumidityUnitDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.view.viewModel.humidityUnit.value = self?.settings.humidityUnit - }) + .addObserver( + forName: .HumidityUnitDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.view.viewModel.humidityUnit.value = self?.settings.humidityUnit + } + ) pressureUnitSettingToken = NotificationCenter.default - .addObserver(forName: .PressureUnitDidChange, - object: nil, - queue: .main, - using: { [weak self] _ in - self?.view.viewModel.pressureUnit.value = self?.settings.pressureUnit - }) + .addObserver( + forName: .PressureUnitDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + self?.view.viewModel.pressureUnit.value = self?.settings.pressureUnit + } + ) } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift index b8a8ebeb3..7034efe01 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift @@ -59,12 +59,14 @@ class OffsetCorrectionAppleViewController: UIViewController { let backBarButtonItemView = UIView() backBarButtonItemView.addSubview(backButton) - backButton.anchor(top: backBarButtonItemView.topAnchor, - leading: backBarButtonItemView.leadingAnchor, - bottom: backBarButtonItemView.bottomAnchor, - trailing: backBarButtonItemView.trailingAnchor, - padding: .init(top: 0, left: -12, bottom: 0, right: 0), - size: .init(width: 40, height: 40)) + backButton.anchor( + top: backBarButtonItemView.topAnchor, + leading: backBarButtonItemView.leadingAnchor, + bottom: backBarButtonItemView.bottomAnchor, + trailing: backBarButtonItemView.trailingAnchor, + padding: .init(top: 0, left: -12, bottom: 0, right: 0), + size: .init(width: 40, height: 40) + ) navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backBarButtonItemView) output.viewDidLoad() @@ -97,11 +99,15 @@ class OffsetCorrectionAppleViewController: UIViewController { case .humidity: label.text = "\((value.bound * 100).round(to: 2))%)" case .pressure: - label.text = self?.measurementService.string(for: Pressure(value, unit: .hectopascals), - allowSettings: false) + label.text = self?.measurementService.string( + for: Pressure(value, unit: .hectopascals), + allowSettings: false + ) default: - label.text = self?.measurementService.string(for: Temperature(value, unit: .celsius), - allowSettings: false) + label.text = self?.measurementService.string( + for: Temperature(value, unit: .celsius), + allowSettings: false + ) } } originalValueUpdateTimeLabel.bind(viewModel.updateAt) { [weak self] label, date in @@ -127,11 +133,15 @@ class OffsetCorrectionAppleViewController: UIViewController { case .humidity: label.text = "\((value.bound * 100).round(to: 2))%" case .pressure: - label.text = self?.measurementService.string(for: Pressure(value, unit: .hectopascals), - allowSettings: false) + label.text = self?.measurementService.string( + for: Pressure(value, unit: .hectopascals), + allowSettings: false + ) default: - label.text = self?.measurementService.string(for: Temperature(value, unit: .celsius), - allowSettings: false) + label.text = self?.measurementService.string( + for: Temperature(value, unit: .celsius), + allowSettings: false + ) } } } @@ -155,9 +165,11 @@ extension OffsetCorrectionAppleViewController: OffsetCorrectionViewInput { let range = NSString(string: attrString.string).range(of: attrString.string) attrString.addAttribute(NSAttributedString.Key.font, value: muliRegular, range: range) // make text color gray - attrString.addAttribute(.foregroundColor, - value: RuuviColor.ruuviTextColor ?? UIColor.secondaryLabel, - range: NSRange(location: 0, length: attrString.length)) + attrString.addAttribute( + .foregroundColor, + value: RuuviColor.ruuviTextColor ?? UIColor.secondaryLabel, + range: NSRange(location: 0, length: attrString.length) + ) descriptionTextView.attributedText = attrString descriptionTextView.textColor = RuuviColor.ruuviTextColor @@ -183,12 +195,14 @@ extension OffsetCorrectionAppleViewController: OffsetCorrectionViewInput { controller.addTextField { textfield in textfield.keyboardType = .numbersAndPunctuation } - controller.addAction(UIAlertAction(title: RuuviLocalization.confirm, - style: .destructive, - handler: { [weak self] _ in - let text = controller.textFields?.first?.text ?? "0.0" - self?.output.viewDidSetCorrectValue(correctValue: text.doubleValue) - })) + controller.addAction(UIAlertAction( + title: RuuviLocalization.confirm, + style: .destructive, + handler: { [weak self] _ in + let text = controller.textFields?.first?.text ?? "0.0" + self?.output.viewDidSetCorrectValue(correctValue: text.doubleValue) + } + )) controller.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) present(controller, animated: true) } @@ -197,11 +211,13 @@ extension OffsetCorrectionAppleViewController: OffsetCorrectionViewInput { let title = RuuviLocalization.OffsetCorrection.Dialog.Calibration.title let message = RuuviLocalization.OffsetCorrection.Dialog.Calibration.clearConfirm let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: RuuviLocalization.confirm, - style: .destructive, - handler: { [weak self] _ in - self?.output.viewDidClearOffsetValue() - })) + controller.addAction(UIAlertAction( + title: RuuviLocalization.confirm, + style: .destructive, + handler: { [weak self] _ in + self?.output.viewDidClearOffsetValue() + } + )) controller.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) present(controller, animated: true) } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift index 5bfeaa087..6fa90d908 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift @@ -36,9 +36,10 @@ class OffsetCorrectionViewModel { hasOffsetValue.value = false } - convenience init(type: OffsetCorrectionType, - sensorSettings: SensorSettings) - { + convenience init( + type: OffsetCorrectionType, + sensorSettings: SensorSettings + ) { self.init() self.type = type update(sensorSettings: sensorSettings) diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift index 105ea4dac..b20f985b8 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift @@ -85,7 +85,8 @@ extension OwnerPresenter: OwnerViewOutput { extension OwnerPresenter { private func removeConnection() { - guard settings.cloudModeEnabled else { + guard settings.cloudModeEnabled + else { return } if let luid = ruuviTag.luid { diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift index 9c5a76afc..73b2d24ae 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift @@ -126,12 +126,14 @@ extension OwnerViewController: OwnerViewInput { let title = RuuviLocalization.dialogAreYouSure let message = RuuviLocalization.dialogOperationUndone let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: RuuviLocalization.confirm, - style: .destructive, - handler: { [weak self] _ in - guard let self else { return } - output?.viewDidConfirmUnclaim(removeCloudHistory: removeCloudHistorySwitch.isOn) - })) + controller.addAction(UIAlertAction( + title: RuuviLocalization.confirm, + style: .destructive, + handler: { [weak self] _ in + guard let self else { return } + output?.viewDidConfirmUnclaim(removeCloudHistory: removeCloudHistorySwitch.isOn) + } + )) controller.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) present(controller, animated: true) } @@ -141,18 +143,20 @@ extension OwnerViewController { private func setUpCustomBackButton() { let backBarButtonItemView = UIView() backBarButtonItemView.addSubview(backButton) - backButton.anchor(top: backBarButtonItemView.topAnchor, - leading: backBarButtonItemView.leadingAnchor, - bottom: backBarButtonItemView.bottomAnchor, - trailing: backBarButtonItemView.trailingAnchor, - padding: .init(top: 0, left: -12, bottom: 0, right: 0), - size: .init(width: 40, height: 40)) + backButton.anchor( + top: backBarButtonItemView.topAnchor, + leading: backBarButtonItemView.leadingAnchor, + bottom: backBarButtonItemView.bottomAnchor, + trailing: backBarButtonItemView.trailingAnchor, + padding: .init(top: 0, left: -12, bottom: 0, right: 0), + size: .init(width: 40, height: 40) + ) navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backBarButtonItemView) } private func setUpCloudHistoryContentView() { let horizontalStackView = UIStackView(arrangedSubviews: [ - removeCloudHistoryTitleLabel, removeCloudHistorySwitch, + removeCloudHistoryTitleLabel, removeCloudHistorySwitch ]) horizontalStackView.spacing = 8 horizontalStackView.distribution = .fill @@ -160,7 +164,7 @@ extension OwnerViewController { removeCloudHistorySwitch.constrainWidth(constant: 51) let verticalStackView = UIStackView(arrangedSubviews: [ - horizontalStackView, removeCloudHistoryDescriptionLabel, + horizontalStackView, removeCloudHistoryDescriptionLabel ]) verticalStackView.spacing = 10 verticalStackView.distribution = .fill diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift index 42e2a7c4b..309441752 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift @@ -53,14 +53,18 @@ class SensorRemovalViewController: UIViewController { }() private lazy var removeButton: UIButton = { - let button = UIButton(color: RuuviColor.ruuviTintColor, - cornerRadius: 25) + let button = UIButton( + color: RuuviColor.ruuviTintColor, + cornerRadius: 25 + ) button.setTitle(RuuviLocalization.remove, for: .normal) button.setTitleColor(.white, for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, size: 16) - button.addTarget(self, - action: #selector(handleRemoveButtonTap), - for: .touchUpInside) + button.addTarget( + self, + action: #selector(handleRemoveButtonTap), + for: .touchUpInside + ) return button }() @@ -113,12 +117,14 @@ extension SensorRemovalViewController: SensorRemovalViewInput { let title = RuuviLocalization.dialogAreYouSure let message = RuuviLocalization.dialogOperationUndone let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: RuuviLocalization.confirm, - style: .destructive, - handler: { [weak self] _ in - guard let self else { return } - output?.viewDidConfirmTagRemoval(with: removeCloudHistorySwitch.isOn) - })) + controller.addAction(UIAlertAction( + title: RuuviLocalization.confirm, + style: .destructive, + handler: { [weak self] _ in + guard let self else { return } + output?.viewDidConfirmTagRemoval(with: removeCloudHistorySwitch.isOn) + } + )) controller.addAction(UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil)) present(controller, animated: true) } @@ -139,12 +145,14 @@ extension SensorRemovalViewController { let backBarButtonItemView = UIView() backBarButtonItemView.addSubview(backButton) - backButton.anchor(top: backBarButtonItemView.topAnchor, - leading: backBarButtonItemView.leadingAnchor, - bottom: backBarButtonItemView.bottomAnchor, - trailing: backBarButtonItemView.trailingAnchor, - padding: .init(top: 0, left: -12, bottom: 0, right: 0), - size: .init(width: 40, height: 40)) + backButton.anchor( + top: backBarButtonItemView.topAnchor, + leading: backBarButtonItemView.leadingAnchor, + bottom: backBarButtonItemView.bottomAnchor, + trailing: backBarButtonItemView.trailingAnchor, + padding: .init(top: 0, left: -12, bottom: 0, right: 0), + size: .init(width: 40, height: 40) + ) navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backBarButtonItemView) } @@ -160,7 +168,7 @@ extension SensorRemovalViewController { ) let horizontalStackView = UIStackView(arrangedSubviews: [ - removeCloudHistoryTitleLabel, removeCloudHistorySwitch, + removeCloudHistoryTitleLabel, removeCloudHistorySwitch ]) horizontalStackView.spacing = 8 horizontalStackView.distribution = .fill @@ -168,7 +176,7 @@ extension SensorRemovalViewController { removeCloudHistorySwitch.constrainWidth(constant: 51) let verticalStackView = UIStackView(arrangedSubviews: [ - horizontalStackView, removeCloudHistoryDescriptionLabel, + horizontalStackView, removeCloudHistoryDescriptionLabel ]) verticalStackView.spacing = 10 verticalStackView.distribution = .fill diff --git a/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift b/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift index 63381e91f..5ea259b62 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift @@ -111,8 +111,10 @@ struct TagSettingsViewModel { txPower.value = record.txPower source.value = record.source let batteryStatusProvider = RuuviTagBatteryStatusProvider() - batteryNeedsReplacement.value = batteryStatusProvider.batteryNeedsReplacement(temperature: record.temperature, - voltage: record.voltage) + batteryNeedsReplacement.value = batteryStatusProvider.batteryNeedsReplacement( + temperature: record.temperature, + voltage: record.voltage + ) latestMeasurement.value = record } diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift index ab87e0c71..7639fe97a 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift @@ -43,27 +43,35 @@ extension RUAlertDetailsCellChildView { backgroundColor = .clear addSubview(titleLabel) - titleLabel.anchor(top: topAnchor, - leading: leadingAnchor, - bottom: bottomAnchor, - trailing: nil, - padding: .init(top: 8, - left: 14, - bottom: 8, - right: 0)) + titleLabel.anchor( + top: topAnchor, + leading: leadingAnchor, + bottom: bottomAnchor, + trailing: nil, + padding: .init( + top: 8, + left: 14, + bottom: 8, + right: 0 + ) + ) addSubview(imageView) - imageView.anchor(top: nil, - leading: titleLabel.trailingAnchor, - bottom: nil, - trailing: trailingAnchor, - padding: .init(top: 0, left: 16, bottom: 0, right: 16), - size: .init(width: 16, height: 16)) + imageView.anchor( + top: nil, + leading: titleLabel.trailingAnchor, + bottom: nil, + trailing: trailingAnchor, + padding: .init(top: 0, left: 16, bottom: 0, right: 16), + size: .init(width: 16, height: 16) + ) imageView.centerYInSuperview() isUserInteractionEnabled = true - let tapGesture = UITapGestureRecognizer(target: self, - action: #selector(handleViewTap)) + let tapGesture = UITapGestureRecognizer( + target: self, + action: #selector(handleViewTap) + ) addGestureRecognizer(tapGesture) } } diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift index 91bcddbb0..bb5d2070e 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift @@ -5,17 +5,23 @@ import UIKit protocol TagSettingsAlertConfigCellDelegate: AnyObject { func didSelectSetCustomDescription(sender: TagSettingsAlertConfigCell) func didSelectAlertLimitDescription(sender: TagSettingsAlertConfigCell) - func didChangeAlertState(sender: TagSettingsAlertConfigCell, - didToggle isOn: Bool) + func didChangeAlertState( + sender: TagSettingsAlertConfigCell, + didToggle isOn: Bool + ) // When slider is changing we would like to update the labels. // But, we will not make endpoint calls. - func didChangeAlertRange(sender: TagSettingsAlertConfigCell, - didSlideTo minValue: CGFloat, - maxValue: CGFloat) + func didChangeAlertRange( + sender: TagSettingsAlertConfigCell, + didSlideTo minValue: CGFloat, + maxValue: CGFloat + ) // We will make endpoind calls for this method only. - func didSetAlertRange(sender: TagSettingsAlertConfigCell, - minValue: CGFloat, - maxValue: CGFloat) + func didSetAlertRange( + sender: TagSettingsAlertConfigCell, + minValue: CGFloat, + maxValue: CGFloat + ) } class TagSettingsAlertConfigCell: UITableViewCell { @@ -98,9 +104,10 @@ class TagSettingsAlertConfigCell: UITableViewCell { private var additionalTextViewHiddenHeight: NSLayoutConstraint! // Init - override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) - { + override init( + style: UITableViewCell.CellStyle, + reuseIdentifier: String? + ) { super.init(style: style, reuseIdentifier: reuseIdentifier) setUpUI() } @@ -129,100 +136,124 @@ extension TagSettingsAlertConfigCell { backgroundColor = RuuviColor.ruuviPrimary addSubview(noticeView) - noticeView.anchor(top: topAnchor, - leading: safeLeftAnchor, - bottom: nil, - trailing: safeRightAnchor) + noticeView.anchor( + top: topAnchor, + leading: safeLeftAnchor, + bottom: nil, + trailing: safeRightAnchor + ) noticeViewHiddenHeight = noticeView.heightAnchor.constraint(equalToConstant: 0) noticeViewHiddenHeight.isActive = true noticeView.addSubview(noticeLabel) - noticeLabel.fillSuperview(padding: .init(top: 8, - left: 8, - bottom: 8, - right: 8)) + noticeLabel.fillSuperview(padding: .init( + top: 8, + left: 8, + bottom: 8, + right: 8 + )) let statusContainerView = UIView(color: .clear) addSubview(statusContainerView) - statusContainerView.anchor(top: noticeView.bottomAnchor, - leading: safeLeftAnchor, - bottom: nil, - trailing: safeRightAnchor, - padding: .init(top: 0, - left: 18, - bottom: 0, - right: 16), - size: .init(width: 0, height: 44)) + statusContainerView.anchor( + top: noticeView.bottomAnchor, + leading: safeLeftAnchor, + bottom: nil, + trailing: safeRightAnchor, + padding: .init( + top: 0, + left: 18, + bottom: 0, + right: 16 + ), + size: .init(width: 0, height: 44) + ) statusContainerView.addSubview(statusLabel) - statusLabel.anchor(top: statusContainerView.topAnchor, - leading: statusContainerView.leadingAnchor, - bottom: statusContainerView.bottomAnchor, - trailing: nil) + statusLabel.anchor( + top: statusContainerView.topAnchor, + leading: statusContainerView.leadingAnchor, + bottom: statusContainerView.bottomAnchor, + trailing: nil + ) statusContainerView.addSubview(statusSwitch) - statusSwitch.anchor(top: nil, - leading: statusLabel.trailingAnchor, - bottom: nil, - trailing: statusContainerView.trailingAnchor, - padding: .init(top: 0, left: 12, bottom: 0, right: 4)) + statusSwitch.anchor( + top: nil, + leading: statusLabel.trailingAnchor, + bottom: nil, + trailing: statusContainerView.trailingAnchor, + padding: .init(top: 0, left: 12, bottom: 0, right: 4) + ) statusSwitch.sizeToFit() statusSwitch.centerYInSuperview() let statusSeparator = UIView() statusSeparator.backgroundColor = RuuviColor.ruuviLineColor addSubview(statusSeparator) - statusSeparator.anchor(top: statusContainerView.bottomAnchor, - leading: safeLeftAnchor, - bottom: nil, - trailing: safeRightAnchor, - padding: .init(top: 0, left: 16, bottom: 0, right: 16), - size: .init(width: 0, height: 1)) + statusSeparator.anchor( + top: statusContainerView.bottomAnchor, + leading: safeLeftAnchor, + bottom: nil, + trailing: safeRightAnchor, + padding: .init(top: 0, left: 16, bottom: 0, right: 16), + size: .init(width: 0, height: 1) + ) addSubview(setCustomDescriptionView) - setCustomDescriptionView.anchor(top: statusSeparator.bottomAnchor, - leading: safeLeftAnchor, - bottom: nil, - trailing: safeRightAnchor, - size: .init(width: 0, height: 44)) + setCustomDescriptionView.anchor( + top: statusSeparator.bottomAnchor, + leading: safeLeftAnchor, + bottom: nil, + trailing: safeRightAnchor, + size: .init(width: 0, height: 44) + ) let customDescriptionSeparator = UIView() customDescriptionSeparator.backgroundColor = RuuviColor.ruuviLineColor addSubview(customDescriptionSeparator) - customDescriptionSeparator.anchor(top: setCustomDescriptionView.bottomAnchor, - leading: safeLeftAnchor, - bottom: nil, - trailing: safeRightAnchor, - padding: .init(top: 0, left: 16, bottom: 0, right: 16), - size: .init(width: 0, height: 1)) + customDescriptionSeparator.anchor( + top: setCustomDescriptionView.bottomAnchor, + leading: safeLeftAnchor, + bottom: nil, + trailing: safeRightAnchor, + padding: .init(top: 0, left: 16, bottom: 0, right: 16), + size: .init(width: 0, height: 1) + ) addSubview(alertLimitDescriptionView) - alertLimitDescriptionView.anchor(top: customDescriptionSeparator.bottomAnchor, - leading: safeLeftAnchor, - bottom: nil, - trailing: safeRightAnchor) + alertLimitDescriptionView.anchor( + top: customDescriptionSeparator.bottomAnchor, + leading: safeLeftAnchor, + bottom: nil, + trailing: safeRightAnchor + ) alertLimitDescriptionViewHiddenHeight = alertLimitDescriptionView .heightAnchor .constraint(equalToConstant: 0) addSubview(alertLimitSliderView) - alertLimitSliderView.anchor(top: alertLimitDescriptionView.bottomAnchor, - leading: safeLeftAnchor, - bottom: nil, - trailing: safeRightAnchor, - padding: .init(top: 0, left: 0, bottom: 0, right: 4), - size: .init(width: 0, height: 40)) + alertLimitSliderView.anchor( + top: alertLimitDescriptionView.bottomAnchor, + leading: safeLeftAnchor, + bottom: nil, + trailing: safeRightAnchor, + padding: .init(top: 0, left: 0, bottom: 0, right: 4), + size: .init(width: 0, height: 40) + ) alertLimitSliderViewHiddenHeight = alertLimitSliderView .heightAnchor .constraint(equalToConstant: 0) addSubview(additionalTextView) - additionalTextView.anchor(top: alertLimitSliderView.bottomAnchor, - leading: safeLeftAnchor, - bottom: safeBottomAnchor, - trailing: safeRightAnchor, - size: .init(width: 0, height: 44)) + additionalTextView.anchor( + top: alertLimitSliderView.bottomAnchor, + leading: safeLeftAnchor, + bottom: safeBottomAnchor, + trailing: safeRightAnchor, + size: .init(width: 0, height: 44) + ) additionalTextViewHiddenHeight = additionalTextView .heightAnchor .constraint(equalToConstant: 0) @@ -267,11 +298,12 @@ extension TagSettingsAlertConfigCell { alertLimitDescriptionView.configure(with: description) } - func setAlertRange(minValue: CGFloat? = nil, - selectedMinValue: CGFloat? = nil, - maxValue: CGFloat? = nil, - selectedMaxValue: CGFloat? = nil) - { + func setAlertRange( + minValue: CGFloat? = nil, + selectedMinValue: CGFloat? = nil, + maxValue: CGFloat? = nil, + selectedMaxValue: CGFloat? = nil + ) { if let minValue { alertLimitSliderView.minValue = minValue } @@ -348,9 +380,10 @@ extension TagSettingsAlertConfigCell { noticeView.alpha = 1 } - func disableEditing(disable: Bool, - identifier: TagSettingsSectionIdentifier) - { + func disableEditing( + disable: Bool, + identifier: TagSettingsSectionIdentifier + ) { statusSwitch.disable(disable) statusLabel.disable(disable) setCustomDescriptionView.disable(disable) @@ -384,14 +417,18 @@ extension TagSettingsAlertConfigCell: RUAlertDetailsCellChildViewDelegate { extension TagSettingsAlertConfigCell: RangeSeekSliderDelegate { func rangeSeekSlider(_: RangeSeekSlider, didChange minValue: CGFloat, maxValue: CGFloat) { - delegate?.didChangeAlertRange(sender: self, - didSlideTo: minValue, - maxValue: maxValue) + delegate?.didChangeAlertRange( + sender: self, + didSlideTo: minValue, + maxValue: maxValue + ) } func didEndTouches(in _: RangeSeekSlider) { - delegate?.didSetAlertRange(sender: self, - minValue: alertLimitSliderView.selectedMinValue, - maxValue: alertLimitSliderView.selectedMaxValue) + delegate?.didSetAlertRange( + sender: self, + minValue: alertLimitSliderView.selectedMinValue, + maxValue: alertLimitSliderView.selectedMaxValue + ) } } diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift index 51f98a0b7..c6810a81f 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift @@ -21,8 +21,10 @@ class TagSettingsBackgroundSelectionView: UIView { }() private lazy var cameraIconContainer: UIView = { - let container = UIView(color: RuuviColor.ruuviTintColor, - cornerRadius: 30) + let container = UIView( + color: RuuviColor.ruuviTintColor, + cornerRadius: 30 + ) let cameraIconView = UIImageView() cameraIconView.image = UIImage(systemName: "camera.fill") cameraIconView.tintColor = .white @@ -49,26 +51,32 @@ class TagSettingsBackgroundSelectionView: UIView { let iconAndLabelContainer = UIView(color: .clear) iconAndLabelContainer.addSubview(cameraIconContainer) - cameraIconContainer.anchor(top: iconAndLabelContainer.topAnchor, - leading: nil, - bottom: nil, - trailing: nil, - size: .init(width: 60, height: 60)) + cameraIconContainer.anchor( + top: iconAndLabelContainer.topAnchor, + leading: nil, + bottom: nil, + trailing: nil, + size: .init(width: 60, height: 60) + ) cameraIconContainer.centerXInSuperview() iconAndLabelContainer.addSubview(titleLabel) - titleLabel.anchor(top: cameraIconContainer.bottomAnchor, - leading: iconAndLabelContainer.leadingAnchor, - bottom: iconAndLabelContainer.bottomAnchor, - trailing: iconAndLabelContainer.trailingAnchor, - padding: .init(top: 8, left: 8, bottom: 0, right: 8)) + titleLabel.anchor( + top: cameraIconContainer.bottomAnchor, + leading: iconAndLabelContainer.leadingAnchor, + bottom: iconAndLabelContainer.bottomAnchor, + trailing: iconAndLabelContainer.trailingAnchor, + padding: .init(top: 8, left: 8, bottom: 0, right: 8) + ) addSubview(iconAndLabelContainer) - iconAndLabelContainer.anchor(top: nil, - leading: safeLeftAnchor, - bottom: nil, - trailing: safeRightAnchor, - padding: .init(top: 0, left: 8, bottom: 0, right: 8)) + iconAndLabelContainer.anchor( + top: nil, + leading: safeLeftAnchor, + bottom: nil, + trailing: safeRightAnchor, + padding: .init(top: 0, left: 8, bottom: 0, right: 8) + ) iconAndLabelContainer.centerYInSuperview() addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleViewTap(_:)))) @@ -81,7 +89,9 @@ class TagSettingsBackgroundSelectionView: UIView { extension TagSettingsBackgroundSelectionView { func setBackgroundImage(with image: UIImage?) { - backgroundView.setBackgroundImage(with: image, - withAnimation: false) + backgroundView.setBackgroundImage( + with: image, + withAnimation: false + ) } } diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift index 43d32fc32..1ef4b1a80 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift @@ -37,11 +37,14 @@ class TagSettingsBasicCell: UITableViewCell { private lazy var separator = UIView(color: RuuviColor.ruuviLineColor) - override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) - { - super.init(style: style, - reuseIdentifier: reuseIdentifier) + override init( + style: UITableViewCell.CellStyle, + reuseIdentifier: String? + ) { + super.init( + style: style, + reuseIdentifier: reuseIdentifier + ) setUpUI() } @@ -54,25 +57,29 @@ class TagSettingsBasicCell: UITableViewCell { backgroundColor = .clear let stack = UIStackView(arrangedSubviews: [ - titleLabel, valueLabel, + titleLabel, valueLabel ]) stack.spacing = 4 stack.distribution = .fill stack.axis = .horizontal addSubview(stack) - stack.anchor(top: safeTopAnchor, - leading: safeLeftAnchor, - bottom: safeBottomAnchor, - trailing: nil, - padding: .init(top: 12, left: 8, bottom: 12, right: 0)) + stack.anchor( + top: safeTopAnchor, + leading: safeLeftAnchor, + bottom: safeBottomAnchor, + trailing: nil, + padding: .init(top: 12, left: 8, bottom: 12, right: 0) + ) addSubview(iconView) - iconView.anchor(top: nil, - leading: stack.trailingAnchor, - bottom: nil, - trailing: safeRightAnchor, - padding: .init(top: 0, left: 8, bottom: 0, right: 12), - size: .init(width: 16, height: 16)) + iconView.anchor( + top: nil, + leading: stack.trailingAnchor, + bottom: nil, + trailing: safeRightAnchor, + padding: .init(top: 0, left: 8, bottom: 0, right: 12), + size: .init(width: 16, height: 16) + ) iconView.centerYInSuperview() iconHiddenWidthConstraints = [ iconView.widthAnchor.constraint(equalToConstant: 0), @@ -80,11 +87,13 @@ class TagSettingsBasicCell: UITableViewCell { ] addSubview(separator) - separator.anchor(top: nil, - leading: safeLeftAnchor, - bottom: bottomAnchor, - trailing: safeRightAnchor, - size: .init(width: 0, height: 1)) + separator.anchor( + top: nil, + leading: safeLeftAnchor, + bottom: bottomAnchor, + trailing: safeRightAnchor, + size: .init(width: 0, height: 1) + ) } func configure(title: String?, value: String?) { diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift index b87458739..475eb6dd1 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift @@ -4,8 +4,10 @@ import UIKit // swiftlint:disable:next type_name protocol TagSettingsExpandableSectionHeaderDelegate: NSObjectProtocol { - func toggleSection(_ header: TagSettingsExpandableSectionHeader, - section: Int) + func toggleSection( + _ header: TagSettingsExpandableSectionHeader, + section: Int + ) func didTapSectionMoreInfo(headerView: TagSettingsExpandableSectionHeader) } @@ -81,48 +83,60 @@ class TagSettingsExpandableSectionHeader: UIView { private func setUpUI() { backgroundColor = RuuviColor.tagSettingsSectionHeaderColor addSubview(titleLabel) - titleLabel.anchor(top: topAnchor, - leading: safeLeftAnchor, - bottom: bottomAnchor, - trailing: nil, - padding: .init(top: 8, left: 8, bottom: 9, right: 0)) + titleLabel.anchor( + top: topAnchor, + leading: safeLeftAnchor, + bottom: bottomAnchor, + trailing: nil, + padding: .init(top: 8, left: 8, bottom: 9, right: 0) + ) addSubview(alertIcon) alertIcon.size(width: 20, height: 20) alertIcon.centerYInSuperview() addSubview(mutedTillLabel) - mutedTillLabel.anchor(top: nil, - leading: alertIcon.trailingAnchor, - bottom: nil, - trailing: nil, - padding: .init(top: 0, - left: 8, - bottom: 0, - right: 0)) + mutedTillLabel.anchor( + top: nil, + leading: alertIcon.trailingAnchor, + bottom: nil, + trailing: nil, + padding: .init( + top: 0, + left: 8, + bottom: 0, + right: 0 + ) + ) mutedTillLabel.centerYInSuperview() addSubview(arrowView) - arrowView.anchor(top: nil, - leading: mutedTillLabel.trailingAnchor, - bottom: nil, - trailing: safeRightAnchor, - padding: .init(top: 0, - left: 8, - bottom: 0, - right: 12), - size: .init(width: 14, height: 14)) + arrowView.anchor( + top: nil, + leading: mutedTillLabel.trailingAnchor, + bottom: nil, + trailing: safeRightAnchor, + padding: .init( + top: 0, + left: 8, + bottom: 0, + right: 12 + ), + size: .init(width: 14, height: 14) + ) arrowView.centerYInSuperview() addSubview(seprator) - seprator.anchor(top: nil, - leading: safeLeftAnchor, - bottom: bottomAnchor, - trailing: safeRightAnchor, - size: .init(width: 0, height: 1)) + seprator.anchor( + top: nil, + leading: safeLeftAnchor, + bottom: bottomAnchor, + trailing: safeRightAnchor, + size: .init(width: 0, height: 1) + ) let noValueStack = UIStackView(arrangedSubviews: [ - noValueLabel, iconView, + noValueLabel, iconView ]) iconView.size(width: 16, height: 16) noValueStack.axis = .horizontal @@ -133,23 +147,30 @@ class TagSettingsExpandableSectionHeader: UIView { noValueStack.fillSuperview() addSubview(noValueContainer) - noValueContainer.anchor(top: nil, - leading: nil, - bottom: nil, - trailing: arrowView.leadingAnchor, - padding: .init(top: 0, left: 8, bottom: 0, right: 8)) + noValueContainer.anchor( + top: nil, + leading: nil, + bottom: nil, + trailing: arrowView.leadingAnchor, + padding: .init(top: 0, left: 8, bottom: 0, right: 8) + ) noValueContainer.centerYInSuperview() noValueContainer.addGestureRecognizer( - UITapGestureRecognizer(target: self, - action: #selector(tapNoValuesView(_:)))) + UITapGestureRecognizer( + target: self, + action: #selector(tapNoValuesView(_:)) + )) addGestureRecognizer( - UITapGestureRecognizer(target: self, - action: #selector(tapHeader(_:)))) + UITapGestureRecognizer( + target: self, + action: #selector(tapHeader(_:)) + )) } @objc private func tapHeader(_ gestureRecognizer: UITapGestureRecognizer) { - guard let cell = gestureRecognizer.view as? TagSettingsExpandableSectionHeader else { + guard let cell = gestureRecognizer.view as? TagSettingsExpandableSectionHeader + else { return } @@ -166,12 +187,13 @@ extension TagSettingsExpandableSectionHeader { titleLabel.text = string } - func setTitle(with string: String?, - section: Int, - collapsed: Bool, - backgroundColor: UIColor? = nil, - font: UIFont?) - { + func setTitle( + with string: String?, + section: Int, + collapsed: Bool, + backgroundColor: UIColor? = nil, + font: UIFont? + ) { titleLabel.text = string self.section = section setCollapsed(collapsed) @@ -212,10 +234,11 @@ extension TagSettingsExpandableSectionHeader { noValueContainer.isHidden = !show } - func setAlertState(with date: Date?, - isOn: Bool, - alertState: AlertState?) - { + func setAlertState( + with date: Date?, + isOn: Bool, + alertState: AlertState? + ) { // Show alert icon only when alert is on alertIcon.alpha = isOn ? 1 : 0 @@ -237,7 +260,8 @@ extension TagSettingsExpandableSectionHeader { } // Check the state and show alert bell based on the state if alert is on. - guard isOn, let state = alertState else { + guard isOn, let state = alertState + else { return } switch state { @@ -250,13 +274,17 @@ extension TagSettingsExpandableSectionHeader { alertIcon.tintColor = RuuviColor.ruuviOrangeColor alertIcon.image = RuuviAssets.alertActiveImage DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - UIView.animate(withDuration: 0.5, - delay: 0, - options: [.repeat, - .autoreverse], - animations: { [weak self] in - self?.alertIcon.alpha = 0.0 - }) + UIView.animate( + withDuration: 0.5, + delay: 0, + options: [ + .repeat, + .autoreverse, + ], + animations: { [weak self] in + self?.alertIcon.alpha = 0.0 + } + ) } default: alertIcon.image = nil diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsFooterCell.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsFooterCell.swift index ed57db689..5900d4046 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsFooterCell.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsFooterCell.swift @@ -10,11 +10,14 @@ class TagSettingsFooterCell: UITableViewCell { return label }() - override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) - { - super.init(style: style, - reuseIdentifier: reuseIdentifier) + override init( + style: UITableViewCell.CellStyle, + reuseIdentifier: String? + ) { + super.init( + style: style, + reuseIdentifier: reuseIdentifier + ) setUpUI() } diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift index 2518fe9b1..546217cd1 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift @@ -30,11 +30,14 @@ class TagSettingsPlainCell: UITableViewCell { return label }() - override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) - { - super.init(style: style, - reuseIdentifier: reuseIdentifier) + override init( + style: UITableViewCell.CellStyle, + reuseIdentifier: String? + ) { + super.init( + style: style, + reuseIdentifier: reuseIdentifier + ) setUpUI() } @@ -47,42 +50,47 @@ class TagSettingsPlainCell: UITableViewCell { backgroundColor = .clear let stack = UIStackView(arrangedSubviews: [ - titleLabel, noteLabel, valueLabel, + titleLabel, noteLabel, valueLabel ]) stack.spacing = 8 stack.distribution = .fill stack.axis = .horizontal addSubview(stack) - stack.anchor(top: safeTopAnchor, - leading: safeLeftAnchor, - bottom: safeBottomAnchor, - trailing: safeRightAnchor, - padding: .init(top: 8, left: 8, bottom: 8, right: 12)) + stack.anchor( + top: safeTopAnchor, + leading: safeLeftAnchor, + bottom: safeBottomAnchor, + trailing: safeRightAnchor, + padding: .init(top: 8, left: 8, bottom: 8, right: 12) + ) } - func configure(title: String?, - value: String?, - note: String? = nil, - noteColor: UIColor? = nil) - { + func configure( + title: String?, + value: String?, + note: String? = nil, + noteColor: UIColor? = nil + ) { titleLabel.text = title valueLabel.text = value noteLabel.text = note noteLabel.textColor = noteColor } - func configure(value: String?, - note: String? = nil, - noteColor: UIColor? = nil) - { + func configure( + value: String?, + note: String? = nil, + noteColor: UIColor? = nil + ) { valueLabel.text = value noteLabel.text = note noteLabel.textColor = noteColor } - func configure(note: String? = nil, - noteColor: UIColor? = nil) - { + func configure( + note: String? = nil, + noteColor: UIColor? = nil + ) { noteLabel.text = note noteLabel.textColor = noteColor } diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift index ee5cf0a4f..f19011c3f 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift @@ -32,10 +32,11 @@ class TagSettingsSimpleSectionHeader: UIView { padding: .init(top: 8, left: 8, bottom: 8, right: 8)) } - func setTitle(with string: String?, - section: Int, - backgroundColor: UIColor? = nil) - { + func setTitle( + with string: String?, + section: Int, + backgroundColor: UIColor? = nil + ) { titleLabel.text = string self.section = section if let color = backgroundColor { diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift index 4cd2896dd..ebcf00450 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift @@ -31,11 +31,14 @@ class TagSettingsSwitchCell: UITableViewCell { lazy var seprator = UIView(color: RuuviColor.ruuviLineColor) - override init(style: UITableViewCell.CellStyle, - reuseIdentifier: String?) - { - super.init(style: style, - reuseIdentifier: reuseIdentifier) + override init( + style: UITableViewCell.CellStyle, + reuseIdentifier: String? + ) { + super.init( + style: style, + reuseIdentifier: reuseIdentifier + ) setUpUI() } @@ -50,39 +53,53 @@ class TagSettingsSwitchCell: UITableViewCell { backgroundColor = .clear addSubview(titleLabel) - titleLabel.anchor(top: safeTopAnchor, - leading: safeLeftAnchor, - bottom: safeBottomAnchor, - trailing: nil, - padding: .init(top: 12, - left: 8, - bottom: 12, - right: 0)) + titleLabel.anchor( + top: safeTopAnchor, + leading: safeLeftAnchor, + bottom: safeBottomAnchor, + trailing: nil, + padding: .init( + top: 12, + left: 8, + bottom: 12, + right: 0 + ) + ) addSubview(pairingAnimationView) - pairingAnimationView.anchor(top: nil, - leading: titleLabel.trailingAnchor, - bottom: nil, - trailing: nil, - size: .init(width: 16, height: 16)) + pairingAnimationView.anchor( + top: nil, + leading: titleLabel.trailingAnchor, + bottom: nil, + trailing: nil, + size: .init(width: 16, height: 16) + ) pairingAnimationView.centerYInSuperview() addSubview(statusSwitch) - statusSwitch.anchor(top: nil, - leading: pairingAnimationView.trailingAnchor, - bottom: nil, - trailing: safeRightAnchor, - padding: .init(top: 0, left: 8, - bottom: 0, right: 12), - size: .init(width: 51, height: 0)) + statusSwitch.anchor( + top: nil, + leading: pairingAnimationView.trailingAnchor, + bottom: nil, + trailing: safeRightAnchor, + padding: .init( + top: 0, + left: 8, + bottom: 0, + right: 12 + ), + size: .init(width: 51, height: 0) + ) statusSwitch.centerYInSuperview() addSubview(seprator) - seprator.anchor(top: nil, - leading: safeLeftAnchor, - bottom: bottomAnchor, - trailing: safeRightAnchor, - size: .init(width: 0, height: 1)) + seprator.anchor( + top: nil, + leading: safeLeftAnchor, + bottom: bottomAnchor, + trailing: safeRightAnchor, + size: .init(width: 0, height: 1) + ) } @objc private func handleStatusToggle(_ sender: RuuviUISwitch) { diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift index b15df35e7..3495f9b38 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift @@ -37,14 +37,15 @@ enum TagSettingsItemCellIdentifier: Int { } class TagSettingsSection { - init(identifier: TagSettingsSectionIdentifier, - title: String, - cells: [TagSettingsItem], - collapsed: Bool, - headerType: TagSettingsSectionHeaderType, - backgroundColor: UIColor? = nil, - font: UIFont? = nil) - { + init( + identifier: TagSettingsSectionIdentifier, + title: String, + cells: [TagSettingsItem], + collapsed: Bool, + headerType: TagSettingsSectionHeaderType, + backgroundColor: UIColor? = nil, + font: UIFont? = nil + ) { self.identifier = identifier self.title = title self.cells = cells @@ -143,21 +144,31 @@ class TagSettingsViewController: UIViewController { // Weak reference to the cells // General section - private lazy var tagNameCell: TagSettingsBasicCell? = TagSettingsBasicCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - - private lazy var tagOwnerCell: TagSettingsBasicCell? = TagSettingsBasicCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - - private lazy var tagOwnersPlanCell: TagSettingsBasicCell? = TagSettingsBasicCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - - private lazy var tagShareCell: TagSettingsBasicCell? = TagSettingsBasicCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) + private lazy var tagNameCell: TagSettingsBasicCell? = TagSettingsBasicCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) + + private lazy var tagOwnerCell: TagSettingsBasicCell? = TagSettingsBasicCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) + + private lazy var tagOwnersPlanCell: TagSettingsBasicCell? = TagSettingsBasicCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) + + private lazy var tagShareCell: TagSettingsBasicCell? = TagSettingsBasicCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) // Bluetooth section - private lazy var btPairCell: TagSettingsSwitchCell? = TagSettingsSwitchCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) + private lazy var btPairCell: TagSettingsSwitchCell? = TagSettingsSwitchCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) // Alerts // Temperature @@ -172,7 +183,7 @@ class TagSettingsViewController: UIViewController { identifier: .alertTemperature, title: sectionTitle, cells: [ - termperatureAlertItem(), + termperatureAlertItem() ], collapsed: true, headerType: .expandable @@ -180,8 +191,10 @@ class TagSettingsViewController: UIViewController { return section }() - private lazy var temperatureAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) + private lazy var temperatureAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) // Humidity private lazy var humidityAlertSectionHeaderView: @@ -194,7 +207,7 @@ class TagSettingsViewController: UIViewController { identifier: .alertHumidity, title: sectionTitle, cells: [ - humidityAlertItem(), + humidityAlertItem() ], collapsed: true, headerType: .expandable @@ -216,7 +229,7 @@ class TagSettingsViewController: UIViewController { identifier: .alertPressure, title: sectionTitle, cells: [ - pressureAlertItem(), + pressureAlertItem() ], collapsed: true, headerType: .expandable @@ -224,84 +237,122 @@ class TagSettingsViewController: UIViewController { return section }() - private lazy var pressureAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) + private lazy var pressureAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) // RSSI private lazy var rssiAlertSectionHeaderView: TagSettingsExpandableSectionHeader? = TagSettingsExpandableSectionHeader() - private lazy var rssiAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) + private lazy var rssiAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) // Movement private lazy var movementAlertSectionHeaderView: TagSettingsExpandableSectionHeader? = TagSettingsExpandableSectionHeader() - private lazy var movementAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) + private lazy var movementAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) // Connection private lazy var connectionAlertSectionHeaderView: TagSettingsExpandableSectionHeader? = TagSettingsExpandableSectionHeader() - private lazy var connectionAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) + private lazy var connectionAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) // Cloud Connection private lazy var cloudConnectionAlertSectionHeaderView: TagSettingsExpandableSectionHeader? = TagSettingsExpandableSectionHeader() - private lazy var cloudConnectionAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) + private lazy var cloudConnectionAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) // Offset correction - private lazy var tempOffsetCorrectionCell: TagSettingsBasicCell? = TagSettingsBasicCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) + private lazy var tempOffsetCorrectionCell: TagSettingsBasicCell? = TagSettingsBasicCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) - private lazy var humidityOffsetCorrectionCell: TagSettingsBasicCell? = TagSettingsBasicCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) + private lazy var humidityOffsetCorrectionCell: TagSettingsBasicCell? = TagSettingsBasicCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) - private lazy var pressureOffsetCorrectionCell: TagSettingsBasicCell? = TagSettingsBasicCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) + private lazy var pressureOffsetCorrectionCell: TagSettingsBasicCell? = TagSettingsBasicCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) // More Info section private lazy var moreInfoSectionHeaderView: TagSettingsExpandableSectionHeader? = TagSettingsExpandableSectionHeader() - private lazy var moreInfoMacAddressCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - - private lazy var moreInfoDataFormatCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - - private lazy var moreInfoDataSourceCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - - private lazy var moreInfoBatteryVoltageCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - - private lazy var moreInfoAccXCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - - private lazy var moreInfoAccYCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - - private lazy var moreInfoAccZCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - - private lazy var moreInfoTxPowerCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - - private lazy var moreInfoRSSICell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) - - private lazy var moreInfoMSNCell: TagSettingsPlainCell? = TagSettingsPlainCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) + private lazy var moreInfoMacAddressCell: TagSettingsPlainCell? = TagSettingsPlainCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) + + private lazy var moreInfoDataFormatCell: TagSettingsPlainCell? = TagSettingsPlainCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) + + private lazy var moreInfoDataSourceCell: TagSettingsPlainCell? = TagSettingsPlainCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) + + private lazy var moreInfoBatteryVoltageCell: TagSettingsPlainCell? = TagSettingsPlainCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) + + private lazy var moreInfoAccXCell: TagSettingsPlainCell? = TagSettingsPlainCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) + + private lazy var moreInfoAccYCell: TagSettingsPlainCell? = TagSettingsPlainCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) + + private lazy var moreInfoAccZCell: TagSettingsPlainCell? = TagSettingsPlainCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) + + private lazy var moreInfoTxPowerCell: TagSettingsPlainCell? = TagSettingsPlainCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) + + private lazy var moreInfoRSSICell: TagSettingsPlainCell? = TagSettingsPlainCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) + + private lazy var moreInfoMSNCell: TagSettingsPlainCell? = TagSettingsPlainCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) // Firmware section - private lazy var firmwareVersionCell: TagSettingsBasicCell? = TagSettingsBasicCell(style: .value1, - reuseIdentifier: Self.ReuseIdentifier) + private lazy var firmwareVersionCell: TagSettingsBasicCell? = TagSettingsBasicCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) deinit { tagNameCell = nil @@ -557,7 +608,8 @@ extension TagSettingsViewController { extension TagSettingsViewController { private func bindBackgroundView() { - guard let viewModel else { + guard let viewModel + else { return } @@ -571,7 +623,8 @@ extension TagSettingsViewController { extension TagSettingsViewController { private func bindGeneralSection() { - guard let viewModel else { + guard let viewModel + else { return } @@ -615,14 +668,13 @@ extension TagSettingsViewController { private func itemsForGeneralSection(showPlan: Bool = false) -> [TagSettingsItem] { var availableItems: [TagSettingsItem] = [ - tagNameSettingItem(), + tagNameSettingItem() ] if showOwner() { availableItems.append(tagOwnerSettingItem()) if let isOwner = viewModel?.isOwner.value, !isOwner, let isCloudTag = viewModel?.isNetworkConnected.value, - isCloudTag, showPlan - { + isCloudTag, showPlan { availableItems.append(tagOwnersPlanSettingItem()) } } @@ -648,8 +700,10 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( identifier: .generalName, createdCell: { [weak self] in - self?.tagNameCell?.configure(title: RuuviLocalization.TagSettings.TagNameTitleLabel.text, - value: self?.viewModel?.name.value) + self?.tagNameCell?.configure( + title: RuuviLocalization.TagSettings.TagNameTitleLabel.text, + value: self?.viewModel?.name.value + ) self?.tagNameCell?.setAccessory(type: .pencil) return self?.tagNameCell ?? UITableViewCell() }, @@ -664,8 +718,10 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( identifier: .generalOwner, createdCell: { [weak self] in - self?.tagOwnerCell?.configure(title: RuuviLocalization.TagSettings.NetworkInfo.owner, - value: self?.viewModel?.owner.value) + self?.tagOwnerCell?.configure( + title: RuuviLocalization.TagSettings.NetworkInfo.owner, + value: self?.viewModel?.owner.value + ) self?.tagOwnerCell?.setAccessory(type: .chevron) self?.tagOwnerCell?.hideSeparator(hide: false) return self?.tagOwnerCell ?? UITableViewCell() @@ -741,7 +797,8 @@ extension TagSettingsViewController { extension TagSettingsViewController: TagSettingsSwitchCellDelegate { private func bindBluetoothSection() { - guard let viewModel else { + guard let viewModel + else { return } @@ -866,7 +923,8 @@ extension TagSettingsViewController: TagSettingsSwitchCellDelegate { extension TagSettingsViewController { // swiftlint:disable:next function_body_length cyclomatic_complexity private func bindAlertsSection() { - guard let viewModel else { + guard let viewModel + else { return } @@ -891,15 +949,19 @@ extension TagSettingsViewController { temperatureAlertCell.bind(viewModel.temperatureUpperBound) { [weak self] cell, _ in cell.setAlertLimitDescription(description: self?.temperatureAlertRangeDescription()) - cell.setAlertRange(selectedMinValue: self?.temperatureLowerBound(), - selectedMaxValue: self?.temperatureUpperBound()) + cell.setAlertRange( + selectedMinValue: self?.temperatureLowerBound(), + selectedMaxValue: self?.temperatureUpperBound() + ) } temperatureAlertCell.bind(viewModel.temperatureLowerBound) { [weak self] cell, _ in cell.setAlertLimitDescription(description: self?.temperatureAlertRangeDescription()) - cell.setAlertRange(selectedMinValue: self?.temperatureLowerBound(), - selectedMaxValue: self?.temperatureUpperBound()) + cell.setAlertRange( + selectedMinValue: self?.temperatureLowerBound(), + selectedMaxValue: self?.temperatureUpperBound() + ) } temperatureAlertCell.bind(viewModel.temperatureUnit) { @@ -907,15 +969,19 @@ extension TagSettingsViewController { guard let sSelf = self else { return } let (minRange, maxRange) = sSelf.temperatureMinMaxForSliders() cell.setAlertLimitDescription(description: sSelf.temperatureAlertRangeDescription()) - cell.setAlertRange(minValue: minRange, - selectedMinValue: sSelf.temperatureLowerBound(), - maxValue: maxRange, - selectedMaxValue: sSelf.temperatureUpperBound()) + cell.setAlertRange( + minValue: minRange, + selectedMinValue: sSelf.temperatureLowerBound(), + maxValue: maxRange, + selectedMaxValue: sSelf.temperatureUpperBound() + ) } temperatureAlertCell.bind(viewModel.latestMeasurement) { cell, measurement in - cell.disableEditing(disable: measurement == nil, - identifier: .alertTemperature) + cell.disableEditing( + disable: measurement == nil, + identifier: .alertTemperature + ) } } @@ -930,13 +996,12 @@ extension TagSettingsViewController { } temperatureAlertSectionHeaderView.bind( - viewModel.temperatureAlertMutedTill) - { header, mutedTill in - let isOn = self.alertsAvailable() && - GlobalHelpers.getBool(from: viewModel.isTemperatureAlertOn.value) - let alertState = viewModel.temperatureAlertState.value - header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) - } + viewModel.temperatureAlertMutedTill) { header, mutedTill in + let isOn = self.alertsAvailable() && + GlobalHelpers.getBool(from: viewModel.isTemperatureAlertOn.value) + let alertState = viewModel.temperatureAlertState.value + header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) + } temperatureAlertSectionHeaderView .bind(viewModel.isTemperatureAlertOn) { [weak self] header, isOn in @@ -973,15 +1038,19 @@ extension TagSettingsViewController { humidityAlertCell.bind(viewModel.relativeHumidityUpperBound) { [weak self] cell, _ in cell.setAlertLimitDescription(description: self?.humidityAlertRangeDescription()) - cell.setAlertRange(selectedMinValue: self?.humidityLowerBound(), - selectedMaxValue: self?.humidityUpperBound()) + cell.setAlertRange( + selectedMinValue: self?.humidityLowerBound(), + selectedMaxValue: self?.humidityUpperBound() + ) } humidityAlertCell.bind(viewModel.relativeHumidityLowerBound) { [weak self] cell, _ in cell.setAlertLimitDescription(description: self?.humidityAlertRangeDescription()) - cell.setAlertRange(selectedMinValue: self?.humidityLowerBound(), - selectedMaxValue: self?.humidityUpperBound()) + cell.setAlertRange( + selectedMinValue: self?.humidityLowerBound(), + selectedMaxValue: self?.humidityUpperBound() + ) } humidityAlertCell.bind(viewModel.humidityUnit) { @@ -989,10 +1058,12 @@ extension TagSettingsViewController { guard let sSelf = self else { return } let (minRange, maxRange) = sSelf.humidityMinMaxForSliders() cell.setAlertLimitDescription(description: sSelf.humidityAlertRangeDescription()) - cell.setAlertRange(minValue: minRange, - selectedMinValue: sSelf.humidityLowerBound(), - maxValue: maxRange, - selectedMaxValue: sSelf.humidityUpperBound()) + cell.setAlertRange( + minValue: minRange, + selectedMinValue: sSelf.humidityLowerBound(), + maxValue: maxRange, + selectedMaxValue: sSelf.humidityUpperBound() + ) } humidityAlertCell.bind(viewModel.latestMeasurement) { @@ -1007,14 +1078,13 @@ extension TagSettingsViewController { if let humidityAlertSectionHeaderView { humidityAlertSectionHeaderView.bind( - viewModel.relativeHumidityAlertMutedTill) - { [weak self] header, mutedTill in - guard let self else { return } - let isOn = alertsAvailable() && - GlobalHelpers.getBool(from: viewModel.isRelativeHumidityAlertOn.value) - let alertState = viewModel.relativeHumidityAlertState.value - header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) - } + viewModel.relativeHumidityAlertMutedTill) { [weak self] header, mutedTill in + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: viewModel.isRelativeHumidityAlertOn.value) + let alertState = viewModel.relativeHumidityAlertState.value + header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) + } humidityAlertSectionHeaderView .bind(viewModel.isRelativeHumidityAlertOn) { [weak self] header, isOn in @@ -1057,15 +1127,19 @@ extension TagSettingsViewController { pressureAlertCell.bind(viewModel.pressureUpperBound) { [weak self] cell, _ in cell.setAlertLimitDescription(description: self?.pressureAlertRangeDescription()) - cell.setAlertRange(selectedMinValue: self?.pressureLowerBound(), - selectedMaxValue: self?.pressureUpperBound()) + cell.setAlertRange( + selectedMinValue: self?.pressureLowerBound(), + selectedMaxValue: self?.pressureUpperBound() + ) } pressureAlertCell.bind(viewModel.pressureLowerBound) { [weak self] cell, _ in cell.setAlertLimitDescription(description: self?.pressureAlertRangeDescription()) - cell.setAlertRange(selectedMinValue: self?.pressureLowerBound(), - selectedMaxValue: self?.pressureUpperBound()) + cell.setAlertRange( + selectedMinValue: self?.pressureLowerBound(), + selectedMaxValue: self?.pressureUpperBound() + ) } pressureAlertCell.bind(viewModel.pressureUnit) { @@ -1073,10 +1147,12 @@ extension TagSettingsViewController { guard let sSelf = self else { return } let (minRange, maxRange) = sSelf.pressureMinMaxForSliders() cell.setAlertLimitDescription(description: sSelf.humidityAlertRangeDescription()) - cell.setAlertRange(minValue: minRange, - selectedMinValue: sSelf.pressureLowerBound(), - maxValue: maxRange, - selectedMaxValue: sSelf.pressureUpperBound()) + cell.setAlertRange( + minValue: minRange, + selectedMinValue: sSelf.pressureLowerBound(), + maxValue: maxRange, + selectedMaxValue: sSelf.pressureUpperBound() + ) } pressureAlertCell.bind(viewModel.latestMeasurement) { @@ -1100,13 +1176,12 @@ extension TagSettingsViewController { } pressureAlertSectionHeaderView.bind( - viewModel.pressureAlertMutedTill) - { header, mutedTill in - let isOn = self.alertsAvailable() && - GlobalHelpers.getBool(from: viewModel.isPressureAlertOn.value) - let alertState = viewModel.pressureAlertState.value - header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) - } + viewModel.pressureAlertMutedTill) { header, mutedTill in + let isOn = self.alertsAvailable() && + GlobalHelpers.getBool(from: viewModel.isPressureAlertOn.value) + let alertState = viewModel.pressureAlertState.value + header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) + } pressureAlertSectionHeaderView .bind(viewModel.isPressureAlertOn) { [weak self] header, isOn in @@ -1143,15 +1218,19 @@ extension TagSettingsViewController { rssiAlertCell.bind(viewModel.signalUpperBound) { [weak self] cell, _ in cell.setAlertLimitDescription(description: self?.rssiAlertRangeDescription()) - cell.setAlertRange(selectedMinValue: self?.rssiLowerBound(), - selectedMaxValue: self?.rssiUpperBound()) + cell.setAlertRange( + selectedMinValue: self?.rssiLowerBound(), + selectedMaxValue: self?.rssiUpperBound() + ) } rssiAlertCell.bind(viewModel.signalLowerBound) { [weak self] cell, _ in cell.setAlertLimitDescription(description: self?.rssiAlertRangeDescription()) - cell.setAlertRange(selectedMinValue: self?.rssiLowerBound(), - selectedMaxValue: self?.rssiUpperBound()) + cell.setAlertRange( + selectedMinValue: self?.rssiLowerBound(), + selectedMaxValue: self?.rssiUpperBound() + ) } rssiAlertCell.bind(viewModel.latestMeasurement) { cell, measurement in @@ -1164,14 +1243,13 @@ extension TagSettingsViewController { if let rssiAlertSectionHeaderView { rssiAlertSectionHeaderView.bind( - viewModel.signalAlertMutedTill) - { [weak self] header, mutedTill in - guard let self else { return } - let isOn = alertsAvailable() && - GlobalHelpers.getBool(from: viewModel.isSignalAlertOn.value) - let alertState = viewModel.signalAlertState.value - header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) - } + viewModel.signalAlertMutedTill) { [weak self] header, mutedTill in + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: viewModel.isSignalAlertOn.value) + let alertState = viewModel.signalAlertState.value + header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) + } rssiAlertSectionHeaderView .bind(viewModel.isSignalAlertOn) { [weak self] header, isOn in @@ -1216,14 +1294,13 @@ extension TagSettingsViewController { if let movementAlertSectionHeaderView { movementAlertSectionHeaderView.bind( - viewModel.movementAlertMutedTill) - { [weak self] header, mutedTill in - guard let self else { return } - let isOn = alertsAvailable() && - GlobalHelpers.getBool(from: viewModel.isMovementAlertOn.value) - let alertState = viewModel.movementAlertState.value - header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) - } + viewModel.movementAlertMutedTill) { [weak self] header, mutedTill in + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: viewModel.isMovementAlertOn.value) + let alertState = viewModel.movementAlertState.value + header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) + } movementAlertSectionHeaderView .bind(viewModel.isMovementAlertOn) { [weak self] header, isOn in @@ -1266,14 +1343,13 @@ extension TagSettingsViewController { if let connectionAlertSectionHeaderView { connectionAlertSectionHeaderView.bind( - viewModel.connectionAlertMutedTill) - { [weak self] header, mutedTill in - guard let self else { return } - let isOn = alertsAvailable() && - GlobalHelpers.getBool(from: viewModel.isConnectionAlertOn.value) - let alertState = viewModel.connectionAlertState.value - header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) - } + viewModel.connectionAlertMutedTill) { [weak self] header, mutedTill in + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: viewModel.isConnectionAlertOn.value) + let alertState = viewModel.connectionAlertState.value + header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) + } connectionAlertSectionHeaderView .bind(viewModel.isConnectionAlertOn) { [weak self] header, isOn in @@ -1308,7 +1384,8 @@ extension TagSettingsViewController { cloudConnectionAlertCell.bind(viewModel.cloudConnectionAlertUnseenDuration) { [weak self] cell, duration in - guard let durationInt = duration?.intValue, durationInt >= 60 else { + guard let durationInt = duration?.intValue, durationInt >= 60 + else { return } @@ -1325,14 +1402,13 @@ extension TagSettingsViewController { if let cloudConnectionAlertSectionHeaderView { cloudConnectionAlertSectionHeaderView.bind( - viewModel.cloudConnectionAlertMutedTill) - { [weak self] header, mutedTill in - guard let self else { return } - let isOn = alertsAvailable() && - GlobalHelpers.getBool(from: viewModel.isCloudConnectionAlertOn.value) - let alertState = viewModel.cloudConnectionAlertState.value - header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) - } + viewModel.cloudConnectionAlertMutedTill) { [weak self] header, mutedTill in + guard let self else { return } + let isOn = alertsAvailable() && + GlobalHelpers.getBool(from: viewModel.isCloudConnectionAlertOn.value) + let alertState = viewModel.cloudConnectionAlertState.value + header.setAlertState(with: mutedTill, isOn: isOn, alertState: alertState) + } cloudConnectionAlertSectionHeaderView .bind(viewModel.isCloudConnectionAlertOn) { [weak self] header, isOn in @@ -1371,7 +1447,7 @@ extension TagSettingsViewController { if cloudConnectionAlertVisible() { sections += [ - configureCloudConnectionAlertSection(), + configureCloudConnectionAlertSection() ] } @@ -1407,10 +1483,12 @@ extension TagSettingsViewController { .temperatureAlertDescription.value)) self?.temperatureAlertCell? .setAlertLimitDescription(description: self?.temperatureAlertRangeDescription()) - self?.temperatureAlertCell?.setAlertRange(minValue: minRange, - selectedMinValue: self?.temperatureLowerBound(), - maxValue: maxRange, - selectedMaxValue: self?.temperatureUpperBound()) + self?.temperatureAlertCell?.setAlertRange( + minValue: minRange, + selectedMinValue: self?.temperatureLowerBound(), + maxValue: maxRange, + selectedMaxValue: self?.temperatureUpperBound() + ) self?.temperatureAlertCell?.disableEditing( disable: disableTemperature, identifier: .alertTemperature @@ -1444,10 +1522,12 @@ extension TagSettingsViewController { .setAlertLimitDescription( description: self?.humidityAlertRangeDescription()) self?.humidityAlertCell? - .setAlertRange(minValue: minRange, - selectedMinValue: self?.humidityLowerBound(), - maxValue: maxRange, - selectedMaxValue: self?.humidityUpperBound()) + .setAlertRange( + minValue: minRange, + selectedMinValue: self?.humidityLowerBound(), + maxValue: maxRange, + selectedMaxValue: self?.humidityUpperBound() + ) self?.humidityAlertCell?.disableEditing( disable: disableHumidity, identifier: .alertHumidity @@ -1479,10 +1559,12 @@ extension TagSettingsViewController { .pressureAlertDescription.value)) self?.pressureAlertCell? .setAlertLimitDescription(description: self?.pressureAlertRangeDescription()) - self?.pressureAlertCell?.setAlertRange(minValue: minRange, - selectedMinValue: self?.pressureLowerBound(), - maxValue: maxRange, - selectedMaxValue: self?.pressureUpperBound()) + self?.pressureAlertCell?.setAlertRange( + minValue: minRange, + selectedMinValue: self?.pressureLowerBound(), + maxValue: maxRange, + selectedMaxValue: self?.pressureUpperBound() + ) self?.pressureAlertCell?.disableEditing( disable: disablePressure, identifier: .alertPressure @@ -1502,7 +1584,7 @@ extension TagSettingsViewController { identifier: .alertRSSI, title: RuuviLocalization.signalStrengthDbm, cells: [ - rssiAlertItem(), + rssiAlertItem() ], collapsed: true, headerType: .expandable @@ -1527,10 +1609,12 @@ extension TagSettingsViewController { .signalAlertDescription.value)) self?.rssiAlertCell? .setAlertLimitDescription(description: self?.rssiAlertRangeDescription()) - self?.rssiAlertCell?.setAlertRange(minValue: minRange, - selectedMinValue: self?.rssiLowerBound(), - maxValue: maxRange, - selectedMaxValue: self?.rssiUpperBound()) + self?.rssiAlertCell?.setAlertRange( + minValue: minRange, + selectedMinValue: self?.rssiLowerBound(), + maxValue: maxRange, + selectedMaxValue: self?.rssiUpperBound() + ) self?.rssiAlertCell?.disableEditing( disable: disableRssi, identifier: .alertRSSI @@ -1550,7 +1634,7 @@ extension TagSettingsViewController { identifier: .alertMovement, title: RuuviLocalization.TagSettings.MovementAlert.title, cells: [ - movementAlertItem(), + movementAlertItem() ], collapsed: true, headerType: .expandable @@ -1587,7 +1671,7 @@ extension TagSettingsViewController { identifier: .alertConnection, title: RuuviLocalization.TagSettings.ConnectionAlert.title, cells: [ - connectionAlertItem(), + connectionAlertItem() ], collapsed: true, headerType: .expandable @@ -1623,7 +1707,7 @@ extension TagSettingsViewController { identifier: .alertCloudConnection, title: RuuviLocalization.alertCloudConnectionTitle, cells: [ - cloudConnectionAlertItem(), + cloudConnectionAlertItem() ], collapsed: true, headerType: .expandable @@ -1680,9 +1764,11 @@ extension TagSettingsViewController { let mutedTill = viewModel?.temperatureAlertMutedTill.value let alertState = viewModel?.temperatureAlertState.value temperatureAlertSectionHeaderView? - .setAlertState(with: mutedTill, - isOn: isOn, - alertState: alertState) + .setAlertState( + with: mutedTill, + isOn: isOn, + alertState: alertState + ) } private func reloadRHAlertSectionHeader() { @@ -1692,9 +1778,11 @@ extension TagSettingsViewController { let mutedTill = viewModel?.relativeHumidityAlertMutedTill.value let alertState = viewModel?.relativeHumidityAlertState.value humidityAlertSectionHeaderView? - .setAlertState(with: mutedTill, - isOn: isOn, - alertState: alertState) + .setAlertState( + with: mutedTill, + isOn: isOn, + alertState: alertState + ) } private func reloadPressureAlertSectionHeader() { @@ -1704,9 +1792,11 @@ extension TagSettingsViewController { let mutedTill = viewModel?.pressureAlertMutedTill.value let alertState = viewModel?.pressureAlertState.value pressureAlertSectionHeaderView? - .setAlertState(with: mutedTill, - isOn: isOn, - alertState: alertState) + .setAlertState( + with: mutedTill, + isOn: isOn, + alertState: alertState + ) } private func reloadSignalAlertSectionHeader() { @@ -1716,9 +1806,11 @@ extension TagSettingsViewController { let mutedTill = viewModel?.signalAlertMutedTill.value let alertState = viewModel?.signalAlertState.value rssiAlertSectionHeaderView? - .setAlertState(with: mutedTill, - isOn: isOn, - alertState: alertState) + .setAlertState( + with: mutedTill, + isOn: isOn, + alertState: alertState + ) } private func reloadMovementAlertSectionHeader() { @@ -1728,9 +1820,11 @@ extension TagSettingsViewController { let mutedTill = viewModel?.movementAlertMutedTill.value let alertState = viewModel?.movementAlertState.value movementAlertSectionHeaderView? - .setAlertState(with: mutedTill, - isOn: isOn, - alertState: alertState) + .setAlertState( + with: mutedTill, + isOn: isOn, + alertState: alertState + ) } private func reloadConnectionAlertSectionHeader() { @@ -1740,9 +1834,11 @@ extension TagSettingsViewController { let mutedTill = viewModel?.connectionAlertMutedTill.value let alertState = viewModel?.connectionAlertState.value connectionAlertSectionHeaderView? - .setAlertState(with: mutedTill, - isOn: isOn, - alertState: alertState) + .setAlertState( + with: mutedTill, + isOn: isOn, + alertState: alertState + ) } private func reloadCloudConnectionAlertSectionHeader() { @@ -1752,9 +1848,11 @@ extension TagSettingsViewController { let mutedTill = viewModel?.cloudConnectionAlertMutedTill.value let alertState = viewModel?.cloudConnectionAlertState.value cloudConnectionAlertSectionHeaderView? - .setAlertState(with: mutedTill, - isOn: isOn, - alertState: alertState) + .setAlertState( + with: mutedTill, + isOn: isOn, + alertState: alertState + ) } private func alertCustomDescription(from string: String?) -> String? { @@ -1762,39 +1860,47 @@ extension TagSettingsViewController { return string.hasText() ? string : alertPlaceholder } - private func temperatureAlertRangeDescription(from min: CGFloat? = nil, - max: CGFloat? = nil) -> NSMutableAttributedString? - { + private func temperatureAlertRangeDescription( + from min: CGFloat? = nil, + max: CGFloat? = nil + ) -> NSMutableAttributedString? { guard isViewLoaded else { return nil } var format = RuuviLocalization.TagSettings.Alerts.Temperature.description if let min, let max { - return attributedString(from: String(format: format, - locale: Locale.autoupdatingCurrent, - min, max)) + return attributedString(from: String( + format: format, + locale: Locale.autoupdatingCurrent, + min, + max + )) } if let tu = viewModel?.temperatureUnit.value?.unitTemperature, let l = viewModel?.temperatureLowerBound.value?.converted(to: tu), - let u = viewModel?.temperatureUpperBound.value?.converted(to: tu) - { + let u = viewModel?.temperatureUpperBound.value?.converted(to: tu) { if l.value.decimalPoint > 0 { let decimalPointToConsider = l.value.decimalPoint > 2 ? 2 : l.value.decimalPoint - format = format.replacingFirstOccurrence(of: "%0.f", - with: "%0.\(decimalPointToConsider)f") + format = format.replacingFirstOccurrence( + of: "%0.f", + with: "%0.\(decimalPointToConsider)f" + ) } if u.value.decimalPoint > 0 { let decimalPointToConsider = u.value.decimalPoint > 2 ? 2 : u.value.decimalPoint - format = format.replacingLastOccurrence(of: "%0.f", - with: "%0.\(decimalPointToConsider)f") + format = format.replacingLastOccurrence( + of: "%0.f", + with: "%0.\(decimalPointToConsider)f" + ) } - let message = String(format: format, - locale: Locale.autoupdatingCurrent, - l.value.round(to: 2), - u.value.round(to: 2)) + let message = String( + format: format, + locale: Locale.autoupdatingCurrent, + l.value.round(to: 2), + u.value.round(to: 2) + ) return attributedString(from: message) - } else { return nil } @@ -1802,7 +1908,8 @@ extension TagSettingsViewController { private func temperatureLowerBound() -> CGFloat { guard isViewLoaded else { return 0 } - guard let temperatureUnit = viewModel?.temperatureUnit.value else { + guard let temperatureUnit = viewModel?.temperatureUnit.value + else { let range = TemperatureUnit.celsius.alertRange return CGFloat(range.lowerBound) } @@ -1815,7 +1922,8 @@ extension TagSettingsViewController { private func temperatureUpperBound() -> CGFloat { guard isViewLoaded else { return 0 } - guard let temperatureUnit = viewModel?.temperatureUnit.value else { + guard let temperatureUnit = viewModel?.temperatureUnit.value + else { let range = TemperatureUnit.celsius.alertRange return CGFloat(range.upperBound) } @@ -1828,24 +1936,29 @@ extension TagSettingsViewController { private func temperatureMinMaxForSliders() -> (minimum: CGFloat, maximum: CGFloat) { let tu = viewModel?.temperatureUnit.value ?? .celsius - return (minimum: CGFloat(tu.alertRange.lowerBound), - maximum: CGFloat(tu.alertRange.upperBound)) + return ( + minimum: CGFloat(tu.alertRange.lowerBound), + maximum: CGFloat(tu.alertRange.upperBound) + ) } // Humidity - private func humidityAlertRangeDescription(from min: CGFloat? = nil, - max: CGFloat? = nil) -> NSMutableAttributedString? - { + private func humidityAlertRangeDescription( + from min: CGFloat? = nil, + max: CGFloat? = nil + ) -> NSMutableAttributedString? { guard isViewLoaded else { return nil } var format = RuuviLocalization.TagSettings.Alerts.Temperature.description if let min, let max { - return attributedString(from: String(format: format, - locale: Locale.autoupdatingCurrent, - min, max)) + return attributedString(from: String( + format: format, + locale: Locale.autoupdatingCurrent, + min, + max + )) } if let l = viewModel?.relativeHumidityLowerBound.value, - let u = viewModel?.relativeHumidityUpperBound.value - { + let u = viewModel?.relativeHumidityUpperBound.value { if l.decimalPoint > 0 { let decimalPointToConsider = l.decimalPoint > 2 ? 2 : l.decimalPoint format = format.replacingFirstOccurrence(of: "%0.f", with: "%0.\(decimalPointToConsider)f") @@ -1855,9 +1968,12 @@ extension TagSettingsViewController { let decimalPointToConsider = u.decimalPoint > 2 ? 2 : u.decimalPoint format = format.replacingLastOccurrence(of: "%0.f", with: "%0.\(decimalPointToConsider)f") } - let message = String(format: format, - locale: Locale.autoupdatingCurrent, - l.round(to: 2), u.round(to: 2)) + let message = String( + format: format, + locale: Locale.autoupdatingCurrent, + l.round(to: 2), + u.round(to: 2) + ) return attributedString(from: message) } else { return nil @@ -1886,27 +2002,32 @@ extension TagSettingsViewController { private func humidityMinMaxForSliders() -> (minimum: CGFloat, maximum: CGFloat) { let rhRange = HumidityUnit.percent.alertRange - return (minimum: CGFloat(rhRange.lowerBound), - maximum: CGFloat(rhRange.upperBound)) + return ( + minimum: CGFloat(rhRange.lowerBound), + maximum: CGFloat(rhRange.upperBound) + ) } // Pressure - private func pressureAlertRangeDescription(from minValue: CGFloat? = nil, - maxValue: CGFloat? = nil) -> NSMutableAttributedString? - { + private func pressureAlertRangeDescription( + from minValue: CGFloat? = nil, + maxValue: CGFloat? = nil + ) -> NSMutableAttributedString? { guard isViewLoaded else { return nil } var format = RuuviLocalization.TagSettings.Alerts.Temperature.description if let minValue, let maxValue { - return attributedString(from: String(format: format, - locale: Locale.autoupdatingCurrent, - minValue, maxValue)) + return attributedString(from: String( + format: format, + locale: Locale.autoupdatingCurrent, + minValue, + maxValue + )) } if let pu = viewModel?.pressureUnit.value, let lower = viewModel?.pressureLowerBound.value?.converted(to: pu).value, - let upper = viewModel?.pressureUpperBound.value?.converted(to: pu).value - { + let upper = viewModel?.pressureUpperBound.value?.converted(to: pu).value { let l = min( max(lower, pu.alertRange.lowerBound), pu.alertRange.upperBound @@ -1924,9 +2045,12 @@ extension TagSettingsViewController { let decimalPointToConsider = u.decimalPoint > 2 ? 2 : u.decimalPoint format = format.replacingLastOccurrence(of: "%0.f", with: "%0.\(decimalPointToConsider)f") } - let message = String(format: format, - locale: Locale.autoupdatingCurrent, - l.round(to: 2), u.round(to: 2)) + let message = String( + format: format, + locale: Locale.autoupdatingCurrent, + l.round(to: 2), + u.round(to: 2) + ) return attributedString(from: message) } else { return nil @@ -1935,7 +2059,8 @@ extension TagSettingsViewController { private func pressureLowerBound() -> CGFloat { guard isViewLoaded else { return 0 } - guard let pu = viewModel?.pressureUnit.value else { + guard let pu = viewModel?.pressureUnit.value + else { let range = UnitPressure.hectopascals.alertRange return CGFloat(range.lowerBound) } @@ -1952,7 +2077,8 @@ extension TagSettingsViewController { private func pressureUpperBound() -> CGFloat { guard isViewLoaded else { return 0 } - guard let pu = viewModel?.pressureUnit.value else { + guard let pu = viewModel?.pressureUnit.value + else { let range = UnitPressure.hectopascals.alertRange return CGFloat(range.upperBound) } @@ -1969,29 +2095,37 @@ extension TagSettingsViewController { private func pressureMinMaxForSliders() -> (minimum: CGFloat, maximum: CGFloat) { let p = viewModel?.pressureUnit.value ?? .hectopascals - return (minimum: CGFloat(p.alertRange.lowerBound), - maximum: CGFloat(p.alertRange.upperBound)) + return ( + minimum: CGFloat(p.alertRange.lowerBound), + maximum: CGFloat(p.alertRange.upperBound) + ) } // RSSI - private func rssiAlertRangeDescription(from min: CGFloat? = nil, - max: CGFloat? = nil) -> NSMutableAttributedString? - { + private func rssiAlertRangeDescription( + from min: CGFloat? = nil, + max: CGFloat? = nil + ) -> NSMutableAttributedString? { guard isViewLoaded else { return nil } let format = RuuviLocalization.TagSettings.Alerts.Temperature.description if let min, let max { - return attributedString(from: String(format: format, - locale: Locale.autoupdatingCurrent, - min, max)) + return attributedString(from: String( + format: format, + locale: Locale.autoupdatingCurrent, + min, + max + )) } if let lower = viewModel?.signalLowerBound.value, - let upper = viewModel?.signalUpperBound.value - { - let message = String(format: format, - locale: Locale.autoupdatingCurrent, - lower, upper) + let upper = viewModel?.signalUpperBound.value { + let message = String( + format: format, + locale: Locale.autoupdatingCurrent, + lower, + upper + ) return attributedString(from: message) } else { return nil @@ -2018,11 +2152,14 @@ extension TagSettingsViewController { } } - private func rssiMinMaxForSliders() -> (minimum: CGFloat, - maximum: CGFloat) - { - (minimum: CGFloat(-105), - maximum: CGFloat(0)) + private func rssiMinMaxForSliders() -> ( + minimum: CGFloat, + maximum: CGFloat + ) { + ( + minimum: CGFloat(-105), + maximum: CGFloat(0) + ) } private func attributedString(from message: String?) -> NSMutableAttributedString? { @@ -2162,10 +2299,11 @@ extension TagSettingsViewController: TagSettingsAlertConfigCellDelegate { } // swiftlint:disable:next cyclomatic_complexity function_body_length - func didSetAlertRange(sender: TagSettingsAlertConfigCell, - minValue: CGFloat, - maxValue: CGFloat) - { + func didSetAlertRange( + sender: TagSettingsAlertConfigCell, + minValue: CGFloat, + maxValue: CGFloat + ) { guard minValue < maxValue else { return } switch sender { case temperatureAlertCell: @@ -2233,27 +2371,36 @@ extension TagSettingsViewController: TagSettingsAlertConfigCellDelegate { } } - func didChangeAlertRange(sender: TagSettingsAlertConfigCell, - didSlideTo minValue: CGFloat, - maxValue: CGFloat) - { + func didChangeAlertRange( + sender: TagSettingsAlertConfigCell, + didSlideTo minValue: CGFloat, + maxValue: CGFloat + ) { switch sender { case temperatureAlertCell: temperatureAlertCell?.setAlertLimitDescription( - description: temperatureAlertRangeDescription(from: minValue, - max: maxValue)) + description: temperatureAlertRangeDescription( + from: minValue, + max: maxValue + )) case humidityAlertCell: humidityAlertCell?.setAlertLimitDescription( - description: humidityAlertRangeDescription(from: minValue, - max: maxValue)) + description: humidityAlertRangeDescription( + from: minValue, + max: maxValue + )) case pressureAlertCell: pressureAlertCell?.setAlertLimitDescription( - description: pressureAlertRangeDescription(from: minValue, - maxValue: maxValue)) + description: pressureAlertRangeDescription( + from: minValue, + maxValue: maxValue + )) case rssiAlertCell: rssiAlertCell?.setAlertLimitDescription( - description: rssiAlertRangeDescription(from: minValue, - max: maxValue)) + description: rssiAlertRangeDescription( + from: minValue, + max: maxValue + )) default: break } @@ -2270,12 +2417,14 @@ extension TagSettingsViewController { let (minimumRange, maximumRange) = temperatureAlertRange() let (minimumValue, maximumValue) = temperatureValue() - showSensorCustomAlertRangeDialog(title: title, - minimumBound: minimumRange, - maximumBound: maximumRange, - currentLowerBound: minimumValue, - currentUpperBound: maximumValue, - sender: sender) + showSensorCustomAlertRangeDialog( + title: title, + minimumBound: minimumRange, + maximumBound: maximumRange, + currentLowerBound: minimumValue, + currentUpperBound: maximumValue, + sender: sender + ) } private func showHumidityAlertSetDialog(sender: TagSettingsAlertConfigCell) { @@ -2285,12 +2434,14 @@ extension TagSettingsViewController { let (minimumRange, maximumRange) = humidityAlertRange() let (minimumValue, maximumValue) = humidityValue() - showSensorCustomAlertRangeDialog(title: title, - minimumBound: minimumRange, - maximumBound: maximumRange, - currentLowerBound: minimumValue, - currentUpperBound: maximumValue, - sender: sender) + showSensorCustomAlertRangeDialog( + title: title, + minimumBound: minimumRange, + maximumBound: maximumRange, + currentLowerBound: minimumValue, + currentUpperBound: maximumValue, + sender: sender + ) } private func showPressureAlertSetDialog(sender: TagSettingsAlertConfigCell) { @@ -2300,12 +2451,14 @@ extension TagSettingsViewController { let (minimumRange, maximumRange) = pressureAlertRange() let (minimumValue, maximumValue) = pressureValue() - showSensorCustomAlertRangeDialog(title: title, - minimumBound: minimumRange, - maximumBound: maximumRange, - currentLowerBound: minimumValue, - currentUpperBound: maximumValue, - sender: sender) + showSensorCustomAlertRangeDialog( + title: title, + minimumBound: minimumRange, + maximumBound: maximumRange, + currentLowerBound: minimumValue, + currentUpperBound: maximumValue, + sender: sender + ) } private func showRSSIAlertSetDialog(sender: TagSettingsAlertConfigCell) { @@ -2315,12 +2468,14 @@ extension TagSettingsViewController { let (minimumRange, maximumRange) = rssiAlertRange() let (minimumValue, maximumValue) = rssiValue() - showSensorCustomAlertRangeDialog(title: title, - minimumBound: minimumRange, - maximumBound: maximumRange, - currentLowerBound: minimumValue, - currentUpperBound: maximumValue, - sender: sender) + showSensorCustomAlertRangeDialog( + title: title, + minimumBound: minimumRange, + maximumBound: maximumRange, + currentLowerBound: minimumValue, + currentUpperBound: maximumValue, + sender: sender + ) } private func showCloudConnectionAlertSetDialog(sender: TagSettingsAlertConfigCell) { @@ -2343,20 +2498,25 @@ extension TagSettingsViewController { private func temperatureAlertRange() -> (minimum: Double, maximum: Double) { let temperatureUnit = viewModel?.temperatureUnit.value ?? .celsius - return (minimum: temperatureUnit.alertRange.lowerBound, - maximum: temperatureUnit.alertRange.upperBound) + return ( + minimum: temperatureUnit.alertRange.lowerBound, + maximum: temperatureUnit.alertRange.upperBound + ) } private func temperatureValue() -> (minimum: Double?, maximum: Double?) { if let unit = viewModel?.temperatureUnit.value?.unitTemperature, let l = viewModel?.temperatureLowerBound.value?.converted(to: unit), - let u = viewModel?.temperatureUpperBound.value?.converted(to: unit) - { - (minimum: l.value, - maximum: u.value) + let u = viewModel?.temperatureUpperBound.value?.converted(to: unit) { + ( + minimum: l.value, + maximum: u.value + ) } else { - (minimum: nil, - maximum: nil) + ( + minimum: nil, + maximum: nil + ) } } @@ -2367,8 +2527,7 @@ extension TagSettingsViewController { private func humidityValue() -> (minimum: Double?, maximum: Double?) { if let l = viewModel?.relativeHumidityLowerBound.value, - let u = viewModel?.relativeHumidityUpperBound.value - { + let u = viewModel?.relativeHumidityUpperBound.value { (minimum: l, maximum: u) } else { (minimum: nil, maximum: nil) @@ -2377,16 +2536,17 @@ extension TagSettingsViewController { private func pressureAlertRange() -> (minimum: Double, maximum: Double) { let pressureUnit = viewModel?.pressureUnit.value ?? .hectopascals - return (minimum: pressureUnit.alertRange.lowerBound, - maximum: pressureUnit.alertRange.upperBound) + return ( + minimum: pressureUnit.alertRange.lowerBound, + maximum: pressureUnit.alertRange.upperBound + ) } private func pressureValue() -> (minimum: Double?, maximum: Double?) { let (minimumRange, maximumRange) = pressureAlertRange() if let pressureUnit = viewModel?.pressureUnit.value, let lower = viewModel?.pressureLowerBound.value?.converted(to: pressureUnit).value, - let upper = viewModel?.pressureUpperBound.value?.converted(to: pressureUnit).value - { + let upper = viewModel?.pressureUpperBound.value?.converted(to: pressureUnit).value { let l = min( max(lower, minimumRange), maximumRange @@ -2403,14 +2563,15 @@ extension TagSettingsViewController { // TODO: - Move the values to a separate constant file private func rssiAlertRange() -> (minimum: Double, maximum: Double) { - (minimum: -105, - maximum: 0) + ( + minimum: -105, + maximum: 0 + ) } private func rssiValue() -> (minimum: Double?, maximum: Double?) { if let lower = viewModel?.signalLowerBound.value, - let upper = viewModel?.signalUpperBound.value - { + let upper = viewModel?.signalUpperBound.value { (minimum: lower, maximum: upper) } else { (minimum: nil, maximum: nil) @@ -2423,7 +2584,8 @@ extension TagSettingsViewController { extension TagSettingsViewController { // swiftlint:disable:next function_body_length private func bindOffsetCorrectionSection() { - guard let viewModel else { + guard let viewModel + else { return } @@ -2437,12 +2599,11 @@ extension TagSettingsViewController { if let tempOffsetCorrectionCell { tempOffsetCorrectionCell.bind(viewModel - .temperatureOffsetCorrection) - { [weak self] cell, value in - cell.configure(value: self? - .measurementService - .temperatureOffsetCorrectionString(for: value ?? 0)) - } + .temperatureOffsetCorrection) { [weak self] cell, value in + cell.configure(value: self? + .measurementService + .temperatureOffsetCorrectionString(for: value ?? 0)) + } tempOffsetCorrectionCell.bind(viewModel.latestMeasurement) { cell, measurement in cell.disableEditing(measurement == nil) @@ -2465,26 +2626,23 @@ extension TagSettingsViewController { } humidityOffsetCorrectionCell.bind(viewModel - .humidityOffsetCorrectionVisible) - { cell, visible in - cell.disableEditing(!GlobalHelpers.getBool(from: visible)) - } + .humidityOffsetCorrectionVisible) { cell, visible in + cell.disableEditing(!GlobalHelpers.getBool(from: visible)) + } } if let pressureOffsetCorrectionCell { pressureOffsetCorrectionCell.bind(viewModel - .pressureOffsetCorrection) - { [weak self] cell, value in - cell.configure(value: self? - .measurementService - .pressureOffsetCorrectionString(for: value ?? 0)) - } + .pressureOffsetCorrection) { [weak self] cell, value in + cell.configure(value: self? + .measurementService + .pressureOffsetCorrectionString(for: value ?? 0)) + } pressureOffsetCorrectionCell.bind(viewModel - .pressureOffsetCorrectionVisible) - { cell, visible in - cell.disableEditing(!GlobalHelpers.getBool(from: visible)) - } + .pressureOffsetCorrectionVisible) { cell, visible in + cell.disableEditing(!GlobalHelpers.getBool(from: visible)) + } pressureOffsetCorrectionCell.bind(viewModel.latestMeasurement) { [weak self] cell, measurement in @@ -2520,9 +2678,11 @@ extension TagSettingsViewController { let settingItem = TagSettingsItem( identifier: .offsetTemperature, createdCell: { [weak self] in - self?.tempOffsetCorrectionCell?.configure(title: RuuviLocalization.TagSettings.OffsetCorrection.temperature, - value: self?.measurementService - .temperatureOffsetCorrectionString(for: tempOffset)) + self?.tempOffsetCorrectionCell?.configure( + title: RuuviLocalization.TagSettings.OffsetCorrection.temperature, + value: self?.measurementService + .temperatureOffsetCorrectionString(for: tempOffset) + ) self?.tempOffsetCorrectionCell?.setAccessory(type: .chevron) self?.tempOffsetCorrectionCell?.disableEditing(!hasMeasurement) return self?.tempOffsetCorrectionCell ?? UITableViewCell() @@ -2543,15 +2703,18 @@ extension TagSettingsViewController { createdCell: { [weak self] in self? .humidityOffsetCorrectionCell? - .configure(title: RuuviLocalization.TagSettings.OffsetCorrection.humidity, - value: self?.measurementService - .humidityOffsetCorrectionString(for: humOffset)) + .configure( + title: RuuviLocalization.TagSettings.OffsetCorrection.humidity, + value: self?.measurementService + .humidityOffsetCorrectionString(for: humOffset) + ) self?.humidityOffsetCorrectionCell?.setAccessory(type: .chevron) self?.humidityOffsetCorrectionCell?.disableEditing(disableHumidity) return self?.humidityOffsetCorrectionCell ?? UITableViewCell() }, action: { [weak self] _ in - guard !disableHumidity else { + guard !disableHumidity + else { return } self?.output.viewDidTapHumidityOffsetCorrection() @@ -2568,15 +2731,18 @@ extension TagSettingsViewController { createdCell: { [weak self] in self? .pressureOffsetCorrectionCell? - .configure(title: RuuviLocalization.TagSettings.OffsetCorrection.pressure, - value: self?.measurementService.pressureOffsetCorrectionString(for: pressureOffset)) + .configure( + title: RuuviLocalization.TagSettings.OffsetCorrection.pressure, + value: self?.measurementService.pressureOffsetCorrectionString(for: pressureOffset) + ) self?.pressureOffsetCorrectionCell?.setAccessory(type: .chevron) self?.pressureOffsetCorrectionCell?.hideSeparator(hide: true) self?.pressureOffsetCorrectionCell?.disableEditing(disablePressure) return self?.pressureOffsetCorrectionCell ?? UITableViewCell() }, action: { [weak self] _ in - guard !disablePressure else { + guard !disablePressure + else { return } self?.output.viewDidTapOnPressureOffsetCorrection() @@ -2620,7 +2786,8 @@ extension TagSettingsViewController { extension TagSettingsViewController { // swiftlint:disable:next cyclomatic_complexity function_body_length private func bindMoreInfoSection() { - guard let viewModel else { + guard let viewModel + else { return } @@ -2748,8 +2915,10 @@ extension TagSettingsViewController { private func moreInfoMacAddressItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoMacAddressCell?.configure(title: RuuviLocalization.TagSettings.MacAddressTitleLabel.text, - value: self?.viewModel?.mac.value ?? RuuviLocalization.na) + self?.moreInfoMacAddressCell?.configure( + title: RuuviLocalization.TagSettings.MacAddressTitleLabel.text, + value: self?.viewModel?.mac.value ?? RuuviLocalization.na + ) return self?.moreInfoMacAddressCell ?? UITableViewCell() }, action: { [weak self] _ in @@ -2762,8 +2931,10 @@ extension TagSettingsViewController { private func moreInfoDataFormatItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoDataFormatCell?.configure(title: RuuviLocalization.TagSettings.DataFormatTitleLabel.text, - value: self?.viewModel?.version.value?.stringValue) + self?.moreInfoDataFormatCell?.configure( + title: RuuviLocalization.TagSettings.DataFormatTitleLabel.text, + value: self?.viewModel?.version.value?.stringValue + ) self?.moreInfoDataFormatCell?.selectionStyle = .none return self?.moreInfoDataFormatCell ?? UITableViewCell() }, @@ -2775,8 +2946,10 @@ extension TagSettingsViewController { private func moreInfoDataSourceItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoDataSourceCell?.configure(title: RuuviLocalization.TagSettings.DataSourceTitleLabel.text, - value: self?.formattedDataSource(from: self?.viewModel?.source.value)) + self?.moreInfoDataSourceCell?.configure( + title: RuuviLocalization.TagSettings.DataSourceTitleLabel.text, + value: self?.formattedDataSource(from: self?.viewModel?.source.value) + ) self?.moreInfoDataSourceCell?.selectionStyle = .none return self?.moreInfoDataSourceCell ?? UITableViewCell() }, @@ -2806,8 +2979,10 @@ extension TagSettingsViewController { private func moreInfoAccXItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoAccXCell?.configure(title: RuuviLocalization.TagSettings.AccelerationXTitleLabel.text, - value: self?.formattedAccelerationValue(from: self?.viewModel?.accelerationX.value)) + self?.moreInfoAccXCell?.configure( + title: RuuviLocalization.TagSettings.AccelerationXTitleLabel.text, + value: self?.formattedAccelerationValue(from: self?.viewModel?.accelerationX.value) + ) self?.moreInfoAccXCell?.selectionStyle = .none return self?.moreInfoAccXCell ?? UITableViewCell() }, @@ -2819,8 +2994,10 @@ extension TagSettingsViewController { private func moreInfoAccYItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoAccYCell?.configure(title: RuuviLocalization.TagSettings.AccelerationYTitleLabel.text, - value: self?.formattedAccelerationValue(from: self?.viewModel?.accelerationY.value)) + self?.moreInfoAccYCell?.configure( + title: RuuviLocalization.TagSettings.AccelerationYTitleLabel.text, + value: self?.formattedAccelerationValue(from: self?.viewModel?.accelerationY.value) + ) self?.moreInfoAccYCell?.selectionStyle = .none return self?.moreInfoAccYCell ?? UITableViewCell() }, @@ -2832,8 +3009,10 @@ extension TagSettingsViewController { private func moreInfoAccZItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoAccZCell?.configure(title: RuuviLocalization.TagSettings.AccelerationZTitleLabel.text, - value: self?.formattedAccelerationValue(from: self?.viewModel?.accelerationZ.value)) + self?.moreInfoAccZCell?.configure( + title: RuuviLocalization.TagSettings.AccelerationZTitleLabel.text, + value: self?.formattedAccelerationValue(from: self?.viewModel?.accelerationZ.value) + ) self?.moreInfoAccZCell?.selectionStyle = .none return self?.moreInfoAccZCell ?? UITableViewCell() }, @@ -2845,8 +3024,10 @@ extension TagSettingsViewController { private func moreInfoTxPowerItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoTxPowerCell?.configure(title: RuuviLocalization.TagSettings.TxPowerTitleLabel.text, - value: self?.formattedTXPower(from: self?.viewModel?.txPower.value)) + self?.moreInfoTxPowerCell?.configure( + title: RuuviLocalization.TagSettings.TxPowerTitleLabel.text, + value: self?.formattedTXPower(from: self?.viewModel?.txPower.value) + ) self?.moreInfoTxPowerCell?.selectionStyle = .none return self?.moreInfoTxPowerCell ?? UITableViewCell() }, @@ -2858,8 +3039,10 @@ extension TagSettingsViewController { private func moreInfoRSSIItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoRSSICell?.configure(title: RuuviLocalization.TagSettings.RssiTitleLabel.text, - value: self?.viewModel?.rssi.value.stringValue) + self?.moreInfoRSSICell?.configure( + title: RuuviLocalization.TagSettings.RssiTitleLabel.text, + value: self?.viewModel?.rssi.value.stringValue + ) return self?.moreInfoRSSICell ?? UITableViewCell() }, action: { [weak self] _ in @@ -2872,8 +3055,10 @@ extension TagSettingsViewController { private func moreInfoMeasurementSequenceItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.moreInfoMSNCell?.configure(title: RuuviLocalization.TagSettings.MsnTitleLabel.text, - value: self?.viewModel?.measurementSequenceNumber.value.stringValue) + self?.moreInfoMSNCell?.configure( + title: RuuviLocalization.TagSettings.MsnTitleLabel.text, + value: self?.viewModel?.measurementSequenceNumber.value.stringValue + ) return self?.moreInfoMSNCell ?? UITableViewCell() }, action: { [weak self] _ in @@ -2947,7 +3132,8 @@ extension TagSettingsViewController { extension TagSettingsViewController { private func bindFirmwareSection() { - guard let viewModel else { + guard let viewModel + else { return } @@ -2977,8 +3163,10 @@ extension TagSettingsViewController { private func tagFirmwareVersionItem() -> TagSettingsItem { let settingItem = TagSettingsItem( createdCell: { [weak self] in - self?.firmwareVersionCell?.configure(title: RuuviLocalization.TagSettings.Firmware.currentVersion, - value: self?.viewModel?.firmwareVersion.value ?? RuuviLocalization.na) + self?.firmwareVersionCell?.configure( + title: RuuviLocalization.TagSettings.Firmware.currentVersion, + value: self?.viewModel?.firmwareVersion.value ?? RuuviLocalization.na + ) self?.firmwareVersionCell?.setAccessory(type: .none) self?.firmwareVersionCell?.selectionStyle = .none return self?.firmwareVersionCell ?? UITableViewCell() @@ -2992,8 +3180,10 @@ extension TagSettingsViewController { let cell = TagSettingsBasicCell(style: .value1, reuseIdentifier: Self.ReuseIdentifier) let settingItem = TagSettingsItem( createdCell: { - cell.configure(title: RuuviLocalization.TagSettings.Firmware.updateFirmware, - value: nil) + cell.configure( + title: RuuviLocalization.TagSettings.Firmware.updateFirmware, + value: nil + ) cell.setAccessory(type: .chevron) cell.hideSeparator(hide: true) return cell @@ -3014,7 +3204,7 @@ extension TagSettingsViewController { identifier: .remove, title: RuuviLocalization.remove.capitalized, cells: [ - tagRemoveItem(), + tagRemoveItem() ], collapsed: true, headerType: .expandable, @@ -3044,15 +3234,17 @@ extension TagSettingsViewController { // MARK: - TableView delegate and datasource extension TagSettingsViewController: UITableViewDelegate, UITableViewDataSource { - func tableView(_: UITableView, - numberOfRowsInSection section: Int) -> Int - { + func tableView( + _: UITableView, + numberOfRowsInSection section: Int + ) -> Int { tableViewSections[section].collapsed ? 0 : tableViewSections[section].cells.count } - func tableView(_: UITableView, - cellForRowAt indexPath: IndexPath) -> UITableViewCell - { + func tableView( + _: UITableView, + cellForRowAt indexPath: IndexPath + ) -> UITableViewCell { let cell = tableViewSections[indexPath.section].cells[indexPath.row] return cell.createdCell() } @@ -3072,15 +3264,18 @@ extension TagSettingsViewController: UITableViewDelegate, UITableViewDataSource } // swiftlint:disable:next function_body_length cyclomatic_complexity - func tableView(_: UITableView, - viewForHeaderInSection section: Int) -> UIView? - { + func tableView( + _: UITableView, + viewForHeaderInSection section: Int + ) -> UIView? { let sectionItem = tableViewSections[section] switch sectionItem.headerType { case .simple: let view = TagSettingsSimpleSectionHeader() - view.setTitle(with: sectionItem.title, - section: section) + view.setTitle( + with: sectionItem.title, + section: section + ) return view case .expandable: @@ -3164,11 +3359,13 @@ extension TagSettingsViewController: UITableViewDelegate, UITableViewDataSource ) case .moreInfo: moreInfoSectionHeaderView?.delegate = self - moreInfoSectionHeaderView?.setTitle(with: sectionItem.title, - section: section, - collapsed: sectionItem.collapsed, - backgroundColor: sectionItem.backgroundColor, - font: sectionItem.font) + moreInfoSectionHeaderView?.setTitle( + with: sectionItem.title, + section: section, + collapsed: sectionItem.collapsed, + backgroundColor: sectionItem.backgroundColor, + font: sectionItem.font + ) moreInfoSectionHeaderView? .hideSeparator(hide: tableViewSections.count == section) moreInfoSectionHeaderView?.hideAlertComponents() @@ -3185,11 +3382,13 @@ extension TagSettingsViewController: UITableViewDelegate, UITableViewDataSource default: let view = TagSettingsExpandableSectionHeader() view.delegate = self - view.setTitle(with: sectionItem.title, - section: section, - collapsed: sectionItem.collapsed, - backgroundColor: sectionItem.backgroundColor, - font: sectionItem.font) + view.setTitle( + with: sectionItem.title, + section: section, + collapsed: sectionItem.collapsed, + backgroundColor: sectionItem.backgroundColor, + font: sectionItem.font + ) view.hideSeparator(hide: tableViewSections.count == section) view.hideAlertComponents() view.showNoValueView(show: false) @@ -3209,14 +3408,18 @@ extension TagSettingsViewController: UITableViewDelegate, UITableViewDataSource ) -> TagSettingsExpandableSectionHeader { if let header { header.delegate = self - header.setTitle(with: sectionItem.title, - section: section, - collapsed: sectionItem.collapsed, - backgroundColor: sectionItem.backgroundColor, - font: sectionItem.font) - header.setAlertState(with: mutedTill, - isOn: isAlertOn, - alertState: alertState) + header.setTitle( + with: sectionItem.title, + section: section, + collapsed: sectionItem.collapsed, + backgroundColor: sectionItem.backgroundColor, + font: sectionItem.font + ) + header.setAlertState( + with: mutedTill, + isOn: isAlertOn, + alertState: alertState + ) header.hideSeparator(hide: tableViewSections.count == section) header.showNoValueView(show: false) return header @@ -3266,10 +3469,12 @@ extension TagSettingsViewController: TagSettingsExpandableSectionHeaderDelegate if let temperatureAlertCell { let (minRange, maxRange) = temperatureMinMaxForSliders() temperatureAlertCell.setAlertLimitDescription(description: temperatureAlertRangeDescription()) - temperatureAlertCell.setAlertRange(minValue: minRange, - selectedMinValue: temperatureLowerBound(), - maxValue: maxRange, - selectedMaxValue: temperatureUpperBound()) + temperatureAlertCell.setAlertRange( + minValue: minRange, + selectedMinValue: temperatureLowerBound(), + maxValue: maxRange, + selectedMaxValue: temperatureUpperBound() + ) temperatureAlertCell.disableEditing( disable: GlobalHelpers.getBool(from: !hasMeasurement()), identifier: currentSection.identifier @@ -3279,10 +3484,12 @@ extension TagSettingsViewController: TagSettingsExpandableSectionHeaderDelegate if let humidityAlertCell { let (minRange, maxRange) = humidityMinMaxForSliders() humidityAlertCell.setAlertLimitDescription(description: humidityAlertRangeDescription()) - humidityAlertCell.setAlertRange(minValue: minRange, - selectedMinValue: humidityLowerBound(), - maxValue: maxRange, - selectedMaxValue: humidityUpperBound()) + humidityAlertCell.setAlertRange( + minValue: minRange, + selectedMinValue: humidityLowerBound(), + maxValue: maxRange, + selectedMaxValue: humidityUpperBound() + ) humidityAlertCell.disableEditing( disable: GlobalHelpers.getBool( from: !showHumidityOffsetCorrection() || !hasMeasurement() @@ -3294,10 +3501,12 @@ extension TagSettingsViewController: TagSettingsExpandableSectionHeaderDelegate if let pressureAlertCell { let (minRange, maxRange) = pressureMinMaxForSliders() pressureAlertCell.setAlertLimitDescription(description: pressureAlertRangeDescription()) - pressureAlertCell.setAlertRange(minValue: minRange, - selectedMinValue: pressureLowerBound(), - maxValue: maxRange, - selectedMaxValue: pressureUpperBound()) + pressureAlertCell.setAlertRange( + minValue: minRange, + selectedMinValue: pressureLowerBound(), + maxValue: maxRange, + selectedMaxValue: pressureUpperBound() + ) pressureAlertCell.disableEditing( disable: GlobalHelpers.getBool( from: !showPressureOffsetCorrection() || !hasMeasurement() @@ -3309,10 +3518,12 @@ extension TagSettingsViewController: TagSettingsExpandableSectionHeaderDelegate if let rssiAlertCell { let (minRange, maxRange) = rssiMinMaxForSliders() rssiAlertCell.setAlertLimitDescription(description: rssiAlertRangeDescription()) - rssiAlertCell.setAlertRange(minValue: minRange, - selectedMinValue: rssiLowerBound(), - maxValue: maxRange, - selectedMaxValue: rssiUpperBound()) + rssiAlertCell.setAlertRange( + minValue: minRange, + selectedMinValue: rssiLowerBound(), + maxValue: maxRange, + selectedMaxValue: rssiUpperBound() + ) rssiAlertCell.disableEditing( disable: GlobalHelpers.getBool(from: !hasMeasurement()), identifier: currentSection.identifier @@ -3375,39 +3586,47 @@ private extension TagSettingsViewController { let backBarButtonItemView = UIView() backBarButtonItemView.addSubview(backButton) - backButton.anchor(top: backBarButtonItemView.topAnchor, - leading: backBarButtonItemView.leadingAnchor, - bottom: backBarButtonItemView.bottomAnchor, - trailing: backBarButtonItemView.trailingAnchor, - padding: .init(top: 0, left: -12, bottom: 0, right: 0), - size: .init(width: 40, height: 40)) + backButton.anchor( + top: backBarButtonItemView.topAnchor, + leading: backBarButtonItemView.leadingAnchor, + bottom: backBarButtonItemView.bottomAnchor, + trailing: backBarButtonItemView.trailingAnchor, + padding: .init(top: 0, left: -12, bottom: 0, right: 0), + size: .init(width: 40, height: 40) + ) navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backBarButtonItemView) let rightBarButtonItemView = UIView() rightBarButtonItemView.addSubview(exportButton) - exportButton.anchor(top: rightBarButtonItemView.topAnchor, - leading: rightBarButtonItemView.leadingAnchor, - bottom: rightBarButtonItemView.bottomAnchor, - trailing: rightBarButtonItemView.trailingAnchor, - padding: .init(top: 0, left: 0, bottom: 0, right: -8), - size: .init(width: 40, height: 40)) + exportButton.anchor( + top: rightBarButtonItemView.topAnchor, + leading: rightBarButtonItemView.leadingAnchor, + bottom: rightBarButtonItemView.bottomAnchor, + trailing: rightBarButtonItemView.trailingAnchor, + padding: .init(top: 0, left: 0, bottom: 0, right: -8), + size: .init(width: 40, height: 40) + ) navigationItem.rightBarButtonItem = UIBarButtonItem(customView: rightBarButtonItemView) let container = UIView(color: .clear) view.addSubview(container) - container.anchor(top: view.safeTopAnchor, - leading: view.leadingAnchor, - bottom: view.bottomAnchor, - trailing: view.trailingAnchor) + container.anchor( + top: view.safeTopAnchor, + leading: view.leadingAnchor, + bottom: view.bottomAnchor, + trailing: view.trailingAnchor + ) container.addSubview(tableView) tableView.fillSuperview() let tableHeaderView = UIView(color: .clear) - tableHeaderView.frame = CGRect(x: 0, - y: 0, - width: view.bounds.width, - height: GlobalHelpers.isDeviceTablet() ? 350 : 200) + tableHeaderView.frame = CGRect( + x: 0, + y: 0, + width: view.bounds.width, + height: GlobalHelpers.isDeviceTablet() ? 350 : 200 + ) tableHeaderView.addSubview(headerContentView) headerContentView.fillSuperview() headerContentView.delegate = self @@ -3447,9 +3666,11 @@ extension TagSettingsViewController { from: viewModel?.mac.value, luid: viewModel?.uuid.value ) - let alert = UIAlertController(title: RuuviLocalization.TagSettings.TagNameTitleLabel.text, - message: RuuviLocalization.TagSettings.TagNameTitleLabel.Rename.text, - preferredStyle: .alert) + let alert = UIAlertController( + title: RuuviLocalization.TagSettings.TagNameTitleLabel.text, + message: RuuviLocalization.TagSettings.TagNameTitleLabel.Rename.text, + preferredStyle: .alert + ) alert.addTextField { [weak self] alertTextField in guard let self else { return } alertTextField.delegate = self @@ -3476,12 +3697,15 @@ extension TagSettingsViewController { extension TagSettingsViewController { // swiftlint:disable:next function_body_length - private func showSensorCustomAlertDescriptionDialog(description: String?, - sender: TagSettingsAlertConfigCell) - { - let alert = UIAlertController(title: RuuviLocalization.TagSettings.Alert.CustomDescription.title, - message: nil, - preferredStyle: .alert) + private func showSensorCustomAlertDescriptionDialog( + description: String?, + sender: TagSettingsAlertConfigCell + ) { + let alert = UIAlertController( + title: RuuviLocalization.TagSettings.Alert.CustomDescription.title, + message: nil, + preferredStyle: .alert + ) alert.addTextField { [weak self] alertTextField in guard let self else { return } alertTextField.delegate = self @@ -3547,23 +3771,28 @@ extension TagSettingsViewController { extension TagSettingsViewController { // swiftlint:disable:next function_parameter_count function_body_length cyclomatic_complexity - private func showSensorCustomAlertRangeDialog(title: String?, - minimumBound: Double, - maximumBound: Double, - currentLowerBound: Double?, - currentUpperBound: Double?, - sender: TagSettingsAlertConfigCell) - { - let alert = UIAlertController(title: title, - message: nil, - preferredStyle: .alert) + private func showSensorCustomAlertRangeDialog( + title: String?, + minimumBound: Double, + maximumBound: Double, + currentLowerBound: Double?, + currentUpperBound: Double?, + sender: TagSettingsAlertConfigCell + ) { + let alert = UIAlertController( + title: title, + message: nil, + preferredStyle: .alert + ) alert.addTextField { [weak self] alertTextField in guard let self else { return } alertTextField.delegate = self let format = RuuviLocalization.TagSettings.AlertSettings.Dialog.min - alertTextField.placeholder = String(format: format, - locale: Locale.autoupdatingCurrent, - minimumBound) + alertTextField.placeholder = String( + format: format, + locale: Locale.autoupdatingCurrent, + minimumBound + ) alertTextField.keyboardType = .decimalPad alertMinRangeTextField = alertTextField if minimumBound < 0 { @@ -3578,9 +3807,11 @@ extension TagSettingsViewController { guard let self else { return } alertTextField.delegate = self let format = RuuviLocalization.TagSettings.AlertSettings.Dialog.max - alertTextField.placeholder = String(format: format, - locale: Locale.autoupdatingCurrent, - maximumBound) + alertTextField.placeholder = String( + format: format, + locale: Locale.autoupdatingCurrent, + maximumBound + ) alertTextField.keyboardType = .decimalPad alertMaxRangeTextField = alertTextField if maximumBound < 0 { @@ -3605,9 +3836,11 @@ extension TagSettingsViewController { return } - didSetAlertRange(sender: sender, - minValue: minimumInputText.doubleValue, - maxValue: maximumInputText.doubleValue) + didSetAlertRange( + sender: sender, + minValue: minimumInputText.doubleValue, + maxValue: maximumInputText.doubleValue + ) } let cancelAction = UIAlertAction(title: RuuviLocalization.cancel, style: .cancel) alert.addAction(action) @@ -3620,16 +3853,19 @@ extension TagSettingsViewController { extension TagSettingsViewController { // swiftlint:disable:next function_parameter_count - private func showSensorCustomAlertRangeDialog(title: String?, - message: String?, - minimum: Int, - default _: Int, - current: Int?, - sender _: TagSettingsAlertConfigCell) - { - let alert = UIAlertController(title: title, - message: message, - preferredStyle: .alert) + private func showSensorCustomAlertRangeDialog( + title: String?, + message: String?, + minimum: Int, + default _: Int, + current: Int?, + sender _: TagSettingsAlertConfigCell + ) { + let alert = UIAlertController( + title: title, + message: message, + preferredStyle: .alert + ) alert.addTextField { [weak self] alertTextField in guard let self else { return } alertTextField.delegate = self @@ -3669,11 +3905,13 @@ extension TagSettingsViewController: TagSettingsViewInput { let title = RuuviLocalization.claimSensorOwnership let message = RuuviLocalization.doYouOwnSensor let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: RuuviLocalization.yes, - style: .default, - handler: { [weak self] _ in - self?.output.viewDidConfirmClaimTag() - })) + controller.addAction(UIAlertAction( + title: RuuviLocalization.yes, + style: .default, + handler: { [weak self] _ in + self?.output.viewDidConfirmClaimTag() + } + )) controller.addAction(UIAlertAction(title: RuuviLocalization.no, style: .cancel, handler: nil)) present(controller, animated: true) } @@ -3733,11 +3971,13 @@ extension TagSettingsViewController: TagSettingsViewInput { func showKeepConnectionCloudModeDialog() { let message = RuuviLocalization.TagSettings.PairError.CloudMode.description let controller = UIAlertController(title: nil, message: message, preferredStyle: .alert) - controller.addAction(UIAlertAction(title: RuuviLocalization.ok, - style: .cancel, - handler: { [weak self] _ in - self?.resetKeepConnectionSwitch() - })) + controller.addAction(UIAlertAction( + title: RuuviLocalization.ok, + style: .cancel, + handler: { [weak self] _ in + self?.resetKeepConnectionSwitch() + } + )) present(controller, animated: true) } @@ -3756,12 +3996,16 @@ extension TagSettingsViewController: TagSettingsViewInput { func showCSVExportLocationDialog() { let title = RuuviLocalization.exportHistory let message = RuuviLocalization.exportCsvFeatureLocation - let controller = UIAlertController(title: title, - message: message, - preferredStyle: .alert) - controller.addAction(UIAlertAction(title: RuuviLocalization.ok, - style: .cancel, - handler: nil)) + let controller = UIAlertController( + title: title, + message: message, + preferredStyle: .alert + ) + controller.addAction(UIAlertAction( + title: RuuviLocalization.ok, + style: .cancel, + handler: nil + )) present(controller, animated: true) } } @@ -3770,11 +4014,14 @@ extension TagSettingsViewController: TagSettingsViewInput { extension TagSettingsViewController: UITextFieldDelegate { // swiftlint:disable:next cyclomatic_complexity - func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, - - replacementString string: String) -> Bool - { - guard let text = textField.text else { + func textField( + _ textField: UITextField, + shouldChangeCharactersIn range: NSRange, + + replacementString string: String + ) -> Bool { + guard let text = textField.text + else { return true } let limit = text.utf16.count + string.utf16.count - range.length @@ -3791,7 +4038,8 @@ extension TagSettingsViewController: UITextFieldDelegate { return false } } else if textField == alertMinRangeTextField || textField == alertMaxRangeTextField { - guard let text = textField.text, let decimalSeparator = NSLocale.current.decimalSeparator else { + guard let text = textField.text, let decimalSeparator = NSLocale.current.decimalSeparator + else { return true } @@ -3804,8 +4052,7 @@ extension TagSettingsViewController: UITextFieldDelegate { // Check if we will exceed 2 dp if splitText.last?.count ?? 0 > 1, string.count != 0, - isEditingEnd - { + isEditingEnd { return false } @@ -3821,7 +4068,6 @@ extension TagSettingsViewController: UITextFieldDelegate { default: return false } - } else if textField == cloudConnectionAlertDelayTextField { if limit <= cloudConnectionAlertDelayCharaterLimit { return true diff --git a/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift b/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift index 43e406b69..72fb9272e 100644 --- a/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift +++ b/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift @@ -3,9 +3,11 @@ import UIKit class AlertPresenterImpl: AlertPresenter { func showAlert(_ viewModel: AlertViewModel) { - let alert = UIAlertController(title: viewModel.title, - message: viewModel.message, - preferredStyle: viewModel.style) + let alert = UIAlertController( + title: viewModel.title, + message: viewModel.message, + preferredStyle: viewModel.style + ) viewModel.actions.forEach { alert.addAction($0) } let group = DispatchGroup() DispatchQueue.main.async { diff --git a/station/Classes/Presentation/Presenters/MailComposer/MessageUI/MailComposerPresenterMessageUI.swift b/station/Classes/Presentation/Presenters/MailComposer/MessageUI/MailComposerPresenterMessageUI.swift index b2bb27e61..5e70ef30a 100644 --- a/station/Classes/Presentation/Presenters/MailComposer/MessageUI/MailComposerPresenterMessageUI.swift +++ b/station/Classes/Presentation/Presenters/MailComposer/MessageUI/MailComposerPresenterMessageUI.swift @@ -21,10 +21,11 @@ class MailComposerPresenterMessageUI: NSObject, MailComposerPresenter { // MARK: - MFMailComposeViewControllerDelegate extension MailComposerPresenterMessageUI: MFMailComposeViewControllerDelegate { - func mailComposeController(_ controller: MFMailComposeViewController, - didFinishWith _: MFMailComposeResult, - error _: Error?) - { + func mailComposeController( + _ controller: MFMailComposeViewController, + didFinishWith _: MFMailComposeResult, + error _: Error? + ) { controller.dismiss(animated: true) } } @@ -38,7 +39,7 @@ extension MailComposerPresenterMessageUI { guard let toEncoded = email .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let subjectEncoded = subject - .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) + .addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else { return nil } diff --git a/station/Classes/Presentation/Presenters/PhotoPicker/Sheet/PhotoPickerPresenterSheet.swift b/station/Classes/Presentation/Presenters/PhotoPicker/Sheet/PhotoPickerPresenterSheet.swift index 3e2a0fae1..6b5f99a27 100644 --- a/station/Classes/Presentation/Presenters/PhotoPicker/Sheet/PhotoPickerPresenterSheet.swift +++ b/station/Classes/Presentation/Presenters/PhotoPicker/Sheet/PhotoPickerPresenterSheet.swift @@ -20,9 +20,10 @@ class PhotoPickerPresenterSheet: NSObject, PhotoPickerPresenter { // MARK: - UIImagePickerControllerDelegate extension PhotoPickerPresenterSheet: UIImagePickerControllerDelegate, UINavigationControllerDelegate { - func imagePickerController(_ picker: UIImagePickerController, - didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) - { + func imagePickerController( + _ picker: UIImagePickerController, + didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any] + ) { picker.dismiss(animated: true, completion: { [weak self] in guard let sSelf = self else { return } if let photo = info[.originalImage] as? UIImage { diff --git a/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissNavigationController.swift b/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissNavigationController.swift index 1fe140c1b..30c325309 100644 --- a/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissNavigationController.swift +++ b/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissNavigationController.swift @@ -2,9 +2,11 @@ import UIKit class SwipeDownToDismissNavigationController: UINavigationController, UIGestureRecognizerDelegate { lazy var panGR: UIPanGestureRecognizer = { - let panGR = UIPanGestureRecognizer(target: self, - action: #selector - (SwipeDownToDismissNavigationController.handlePanGesture(_:))) + let panGR = UIPanGestureRecognizer( + target: self, + action: #selector + (SwipeDownToDismissNavigationController.handlePanGesture(_:)) + ) panGR.delegate = self panGR.isEnabled = true return panGR @@ -15,9 +17,10 @@ class SwipeDownToDismissNavigationController: UINavigationController, UIGestureR view.addGestureRecognizer(panGR) } - func gestureRecognizer(_: UIGestureRecognizer, - shouldRecognizeSimultaneouslyWith _: UIGestureRecognizer) -> Bool - { + func gestureRecognizer( + _: UIGestureRecognizer, + shouldRecognizeSimultaneouslyWith _: UIGestureRecognizer + ) -> Bool { true } @@ -36,8 +39,7 @@ class SwipeDownToDismissNavigationController: UINavigationController, UIGestureR switch sender.state { case .began: if let tagSettings = topViewController as? UITableViewController, - tagSettings.tableView.contentOffset.y <= 0 - { + tagSettings.tableView.contentOffset.y <= 0 { interactor.hasStarted = true dismiss(animated: true) } diff --git a/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitioningDelegate.swift b/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitioningDelegate.swift index b3bb27c80..5e3bf5a0a 100644 --- a/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitioningDelegate.swift +++ b/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitioningDelegate.swift @@ -8,8 +8,7 @@ class SwipeDownToDismissTransitioningDelegate: NSObject, UIViewControllerTransit } func interactionControllerForDismissal(using _: UIViewControllerAnimatedTransitioning) - -> UIViewControllerInteractiveTransitioning? - { + -> UIViewControllerInteractiveTransitioning? { interactionControllerForDismissal.hasStarted ? interactionControllerForDismissal : nil } } diff --git a/station/Classes/Routers/AppRouter.swift b/station/Classes/Routers/AppRouter.swift index 0aba657d9..49590e9ef 100644 --- a/station/Classes/Routers/AppRouter.swift +++ b/station/Classes/Routers/AppRouter.swift @@ -89,9 +89,10 @@ final class AppRouter { } extension AppRouter: OnboardRouterDelegate { - func onboardRouterDidShowSignIn(_: OnboardRouter, - output: SignInBenefitsModuleOutput) - { + func onboardRouterDidShowSignIn( + _: OnboardRouter, + output: SignInBenefitsModuleOutput + ) { let factory: SignInBenefitsModuleFactory = SignInPromoModuleFactoryImpl() let module = factory.create() @@ -108,10 +109,11 @@ extension AppRouter: OnboardRouterDelegate { presentDashboard() } - func onboardRouterDidFinish(_: OnboardRouter, - module: SignInBenefitsModuleInput, - showDashboard: Bool) - { + func onboardRouterDidFinish( + _: OnboardRouter, + module: SignInBenefitsModuleInput, + showDashboard: Bool + ) { module.dismiss(completion: { [weak self] in if showDashboard { self?.presentDashboard() @@ -131,8 +133,10 @@ extension AppRouter: OnboardRouterDelegate { extension AppRouter: DiscoverRouterDelegate { func discoverRouterWantsClose(_: DiscoverRouter) { if let weakDashboardController { - navigationController.pushViewController(weakDashboardController, - animated: true) + navigationController.pushViewController( + weakDashboardController, + animated: true + ) } else { let controller = dashboardViewController() navigationController.setViewControllers([controller], animated: true) diff --git a/station/Classes/Routers/OnboardRouter.swift b/station/Classes/Routers/OnboardRouter.swift index 7fe282c01..4a0bee7f7 100644 --- a/station/Classes/Routers/OnboardRouter.swift +++ b/station/Classes/Routers/OnboardRouter.swift @@ -4,11 +4,15 @@ import UIKit protocol OnboardRouterDelegate: AnyObject { func onboardRouterDidFinish(_ router: OnboardRouter) - func onboardRouterDidFinish(_ router: OnboardRouter, - module: SignInBenefitsModuleInput, - showDashboard: Bool) - func onboardRouterDidShowSignIn(_ router: OnboardRouter, - output: SignInBenefitsModuleOutput) + func onboardRouterDidFinish( + _ router: OnboardRouter, + module: SignInBenefitsModuleInput, + showDashboard: Bool + ) + func onboardRouterDidShowSignIn( + _ router: OnboardRouter, + output: SignInBenefitsModuleOutput + ) } final class OnboardRouter { diff --git a/station/Extensions/Color+Ruuvi.swift b/station/Extensions/Color+Ruuvi.swift index e5f9b30c0..2b2e19a89 100644 --- a/station/Extensions/Color+Ruuvi.swift +++ b/station/Extensions/Color+Ruuvi.swift @@ -2,10 +2,12 @@ import UIKit extension UIColor { static var normalButtonBackground: UIColor { - UIColor(red: 21.0 / 255, - green: 141.0 / 255, - blue: 165.0 / 255, - alpha: 1) + UIColor( + red: 21.0 / 255, + green: 141.0 / 255, + blue: 165.0 / 255, + alpha: 1 + ) } static var disableButtonBackground: UIColor { diff --git a/station/Extensions/Double+Extension.swift b/station/Extensions/Double+Extension.swift index 8da2911a3..12f95a463 100644 --- a/station/Extensions/Double+Extension.swift +++ b/station/Extensions/Double+Extension.swift @@ -15,7 +15,8 @@ extension Double { extension Double? { var intValue: Int { - guard let self else { + guard let self + else { return 0 } return Int(self) diff --git a/station/Extensions/FileManager+Date.swift b/station/Extensions/FileManager+Date.swift index e52fbdbda..8c0ca681a 100644 --- a/station/Extensions/FileManager+Date.swift +++ b/station/Extensions/FileManager+Date.swift @@ -3,12 +3,13 @@ import Foundation extension FileManager { var appInstalledDate: Date { if - let urlToDocumentsFolder = FileManager.default.urls(for: .documentDirectory, - in: .userDomainMask).last, + let urlToDocumentsFolder = FileManager.default.urls( + for: .documentDirectory, + in: .userDomainMask + ).last, let installDateAny = try? FileManager.default.attributesOfItem(atPath: urlToDocumentsFolder.path)[.creationDate], - let installDate = installDateAny as? Date - { + let installDate = installDateAny as? Date { installDate } else { Date() diff --git a/station/Extensions/HumidityUnit+Localization.swift b/station/Extensions/HumidityUnit+Localization.swift index 46bb3c816..922004d74 100644 --- a/station/Extensions/HumidityUnit+Localization.swift +++ b/station/Extensions/HumidityUnit+Localization.swift @@ -5,10 +5,8 @@ import RuuviOntology extension HumidityUnit: SelectionItemProtocol { var title: (String) -> String { switch self { - case .percent: - { _ in RuuviLocalization.HumidityUnit.Percent.title } - case .gm3: - { _ in RuuviLocalization.HumidityUnit.Gm3.title } + case .percent: { _ in RuuviLocalization.HumidityUnit.Percent.title } + case .gm3: { _ in RuuviLocalization.HumidityUnit.Gm3.title } case .dew: RuuviLocalization.HumidityUnit.Dew.title } diff --git a/station/Extensions/MeasurementAccuracyType+Extension.swift b/station/Extensions/MeasurementAccuracyType+Extension.swift index ff9b4aa37..baaaf8d67 100644 --- a/station/Extensions/MeasurementAccuracyType+Extension.swift +++ b/station/Extensions/MeasurementAccuracyType+Extension.swift @@ -4,12 +4,9 @@ import RuuviOntology extension MeasurementAccuracyType: SelectionItemProtocol { public var title: (String) -> String { switch self { - case .zero: - { _ in "1" } - case .one: - { _ in "0.1" } - case .two: - { _ in "0.01" } + case .zero: { _ in "1" } + case .one: { _ in "0.1" } + case .two: { _ in "0.01" } } } } diff --git a/station/Extensions/RuuviAlertSound+Extension.swift b/station/Extensions/RuuviAlertSound+Extension.swift index db7b958b0..5e2daa4bc 100644 --- a/station/Extensions/RuuviAlertSound+Extension.swift +++ b/station/Extensions/RuuviAlertSound+Extension.swift @@ -5,10 +5,8 @@ import RuuviOntology extension RuuviAlertSound: SelectionItemProtocol { var title: (String) -> String { switch self { - case .systemDefault: - { _ in RuuviLocalization.settingsAlertSoundDefault } - case .ruuviSpeak: - { _ in RuuviLocalization.settingsAlertSoundRuuviSpeak } + case .systemDefault: { _ in RuuviLocalization.settingsAlertSoundDefault } + case .ruuviSpeak: { _ in RuuviLocalization.settingsAlertSoundRuuviSpeak } } } } diff --git a/station/Extensions/RuuviTheme+Extension.swift b/station/Extensions/RuuviTheme+Extension.swift index 6d6aafd63..6b6ec3193 100644 --- a/station/Extensions/RuuviTheme+Extension.swift +++ b/station/Extensions/RuuviTheme+Extension.swift @@ -5,12 +5,9 @@ import RuuviOntology extension RuuviTheme: SelectionItemProtocol { var title: (String) -> String { switch self { - case .light: - { _ in RuuviLocalization.lightTheme } - case .dark: - { _ in RuuviLocalization.darkTheme } - case .system: - { _ in RuuviLocalization.followSystemTheme } + case .light: { _ in RuuviLocalization.lightTheme } + case .dark: { _ in RuuviLocalization.darkTheme } + case .system: { _ in RuuviLocalization.followSystemTheme } } } } diff --git a/station/Extensions/String+Replace.swift b/station/Extensions/String+Replace.swift index ebfea7a40..300b7ac98 100644 --- a/station/Extensions/String+Replace.swift +++ b/station/Extensions/String+Replace.swift @@ -41,11 +41,12 @@ extension String { func replacingLastOccurrence(of target: String, with replacement: String) -> String { let options: String.CompareOptions = [.backwards] - if let range = range(of: target, - options: options, - range: nil, - locale: nil) - { + if let range = range( + of: target, + options: options, + range: nil, + locale: nil + ) { return replacingCharacters(in: range, with: replacement) } return self diff --git a/station/Extensions/Structs/AppUtility.swift b/station/Extensions/Structs/AppUtility.swift index 8e3ee226b..a9eec9ba3 100644 --- a/station/Extensions/Structs/AppUtility.swift +++ b/station/Extensions/Structs/AppUtility.swift @@ -8,9 +8,10 @@ enum AppUtility { } /// OPTIONAL Added method to adjust lock and rotate to the desired orientation - static func lockOrientation(_ orientation: UIInterfaceOrientationMask, - andRotateTo rotateOrientation: UIInterfaceOrientation) - { + static func lockOrientation( + _ orientation: UIInterfaceOrientationMask, + andRotateTo rotateOrientation: UIInterfaceOrientation + ) { lockOrientation(orientation) UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation") UINavigationController.attemptRotationToDeviceOrientation() diff --git a/station/Extensions/Structs/MeasurementAccuracyTitles.swift b/station/Extensions/Structs/MeasurementAccuracyTitles.swift index f3919d2cf..9bb671afb 100644 --- a/station/Extensions/Structs/MeasurementAccuracyTitles.swift +++ b/station/Extensions/Structs/MeasurementAccuracyTitles.swift @@ -3,9 +3,10 @@ import RuuviLocal import RuuviOntology struct MeasurementAccuracyTitles { - func formattedTitle(type: MeasurementAccuracyType, - settings _: RuuviLocalSettings) -> String - { + func formattedTitle( + type: MeasurementAccuracyType, + settings _: RuuviLocalSettings + ) -> String { let formatter = NumberFormatter() formatter.locale = Locale.autoupdatingCurrent formatter.numberStyle = .decimal diff --git a/station/Extensions/Structs/RuuviTagBatteryStatusProvider.swift b/station/Extensions/Structs/RuuviTagBatteryStatusProvider.swift index 5817cc256..a9394e472 100644 --- a/station/Extensions/Structs/RuuviTagBatteryStatusProvider.swift +++ b/station/Extensions/Structs/RuuviTagBatteryStatusProvider.swift @@ -2,12 +2,12 @@ import Foundation import RuuviOntology struct RuuviTagBatteryStatusProvider { - func batteryNeedsReplacement(temperature: Temperature?, - voltage: Voltage?) -> Bool - { + func batteryNeedsReplacement( + temperature: Temperature?, + voltage: Voltage? + ) -> Bool { if let temperature = temperature?.value, - let voltage = voltage?.value - { + let voltage = voltage?.value { if temperature < 0, temperature >= -20 { voltage < 2.3 } else if temperature < -20 { diff --git a/station/Extensions/TemperatureUnit+Localization.swift b/station/Extensions/TemperatureUnit+Localization.swift index c476db890..1719cb684 100644 --- a/station/Extensions/TemperatureUnit+Localization.swift +++ b/station/Extensions/TemperatureUnit+Localization.swift @@ -5,12 +5,9 @@ import RuuviOntology extension TemperatureUnit: SelectionItemProtocol { var title: (String) -> String { switch self { - case .celsius: - { _ in RuuviLocalization.TemperatureUnit.Celsius.title } - case .fahrenheit: - { _ in RuuviLocalization.TemperatureUnit.Fahrenheit.title } - case .kelvin: - { _ in RuuviLocalization.TemperatureUnit.Kelvin.title } + case .celsius: { _ in RuuviLocalization.TemperatureUnit.Celsius.title } + case .fahrenheit: { _ in RuuviLocalization.TemperatureUnit.Fahrenheit.title } + case .kelvin: { _ in RuuviLocalization.TemperatureUnit.Kelvin.title } } } } @@ -18,14 +15,10 @@ extension TemperatureUnit: SelectionItemProtocol { extension UnitTemperature: SelectionItemProtocol { var title: (String) -> String { switch self { - case .celsius: - { _ in RuuviLocalization.TemperatureUnit.Celsius.title } - case .fahrenheit: - { _ in RuuviLocalization.TemperatureUnit.Fahrenheit.title } - case .kelvin: - { _ in RuuviLocalization.TemperatureUnit.Kelvin.title } - default: - { _ in RuuviLocalization.na } + case .celsius: { _ in RuuviLocalization.TemperatureUnit.Celsius.title } + case .fahrenheit: { _ in RuuviLocalization.TemperatureUnit.Fahrenheit.title } + case .kelvin: { _ in RuuviLocalization.TemperatureUnit.Kelvin.title } + default: { _ in RuuviLocalization.na } } } } diff --git a/station/Extensions/UIButton+Extension.swift b/station/Extensions/UIButton+Extension.swift index fde26ce82..49a4e0b40 100644 --- a/station/Extensions/UIButton+Extension.swift +++ b/station/Extensions/UIButton+Extension.swift @@ -5,16 +5,24 @@ extension UIButton { guard let text = titleLabel?.text, let titleColor = titleColor(for: .normal) else { return } let attributedString = NSMutableAttributedString(string: text) - attributedString.addAttribute(NSAttributedString.Key.underlineColor, - value: titleColor, - range: NSRange(location: 0, - length: text.count)) - attributedString.addAttribute(NSAttributedString.Key.foregroundColor, - value: titleColor, - range: NSRange(location: 0, length: text.count)) - attributedString.addAttribute(NSAttributedString.Key.underlineStyle, - value: NSUnderlineStyle.single.rawValue, - range: NSRange(location: 0, length: text.count)) + attributedString.addAttribute( + NSAttributedString.Key.underlineColor, + value: titleColor, + range: NSRange( + location: 0, + length: text.count + ) + ) + attributedString.addAttribute( + NSAttributedString.Key.foregroundColor, + value: titleColor, + range: NSRange(location: 0, length: text.count) + ) + attributedString.addAttribute( + NSAttributedString.Key.underlineStyle, + value: NSUnderlineStyle.single.rawValue, + range: NSRange(location: 0, length: text.count) + ) setAttributedTitle(attributedString, for: .normal) } } diff --git a/station/Extensions/UICollectionView+Extension.swift b/station/Extensions/UICollectionView+Extension.swift index e5cb24dba..1dcced49e 100644 --- a/station/Extensions/UICollectionView+Extension.swift +++ b/station/Extensions/UICollectionView+Extension.swift @@ -13,10 +13,14 @@ extension UICollectionView { func scrollTo(index: Int, section: Int = 0, animated: Bool = false) { guard numberOfSections > 0, numberOfItems(inSection: section) > 0 else { return } - let indexPath = IndexPath(item: index, - section: section) - scrollToItem(at: indexPath, - at: .centeredHorizontally, - animated: animated) + let indexPath = IndexPath( + item: index, + section: section + ) + scrollToItem( + at: indexPath, + at: .centeredHorizontally, + animated: animated + ) } } diff --git a/station/Extensions/UIColor+Extension.swift b/station/Extensions/UIColor+Extension.swift index 16f3c54d0..3c413a605 100644 --- a/station/Extensions/UIColor+Extension.swift +++ b/station/Extensions/UIColor+Extension.swift @@ -2,10 +2,12 @@ import UIKit extension UIColor { convenience init(hex: Int, alpha: CGFloat = 1.0) { - self.init(red: CGFloat((hex >> 16) & 0xFF) / 255.0, - green: CGFloat((hex >> 8) & 0xFF) / 255.0, - blue: CGFloat(hex & 0xFF) / 255.0, - alpha: CGFloat(255 * alpha) / 255) + self.init( + red: CGFloat((hex >> 16) & 0xFF) / 255.0, + green: CGFloat((hex >> 8) & 0xFF) / 255.0, + blue: CGFloat(hex & 0xFF) / 255.0, + alpha: CGFloat(255 * alpha) / 255 + ) } convenience init(hexString: String, alpha: CGFloat = 1.0) { @@ -20,10 +22,12 @@ extension UIColor { var rgbValue: UInt64 = 0 Scanner(string: hexFormatted).scanHexInt64(&rgbValue) - self.init(red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0, - green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0, - blue: CGFloat(rgbValue & 0x0000FF) / 255.0, - alpha: alpha) + self.init( + red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0, + green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0, + blue: CGFloat(rgbValue & 0x0000FF) / 255.0, + alpha: alpha + ) } } diff --git a/station/Extensions/UIDevice+ReadableModel.swift b/station/Extensions/UIDevice+ReadableModel.swift index e336e873e..0c31c7021 100644 --- a/station/Extensions/UIDevice+ReadableModel.swift +++ b/station/Extensions/UIDevice+ReadableModel.swift @@ -9,9 +9,13 @@ extension UIDevice { var sysinfo = utsname() uname(&sysinfo) - let deviceModel = String(bytes: Data(bytes: &sysinfo.machine, - count: Int(_SYS_NAMELEN)), - encoding: .ascii)! + let deviceModel = String( + bytes: Data( + bytes: &sysinfo.machine, + count: Int(_SYS_NAMELEN) + ), + encoding: .ascii + )! .trimmingCharacters(in: .controlCharacters) var modelReadable = iOSDevices?.value(forKey: deviceModel) as? String @@ -149,15 +153,18 @@ extension UIDevice { fileprivate static func modelIdentifier() -> String { if let simulatorModelIdentifier = ProcessInfo() - .environment["SIMULATOR_MODEL_IDENTIFIER"] - { + .environment["SIMULATOR_MODEL_IDENTIFIER"] { return simulatorModelIdentifier } var sysinfo = utsname() uname(&sysinfo) // ignore return value - return String(bytes: Data(bytes: &sysinfo.machine, - count: Int(_SYS_NAMELEN)), - encoding: .ascii)!.trimmingCharacters(in: .controlCharacters) + return String( + bytes: Data( + bytes: &sysinfo.machine, + count: Int(_SYS_NAMELEN) + ), + encoding: .ascii + )!.trimmingCharacters(in: .controlCharacters) } } diff --git a/station/Extensions/UIFont+Extension.swift b/station/Extensions/UIFont+Extension.swift index 1b906c966..ca7b30e57 100644 --- a/station/Extensions/UIFont+Extension.swift +++ b/station/Extensions/UIFont+Extension.swift @@ -21,30 +21,41 @@ public extension UIFont { // MARK: - FUNCTIONS - static func Montserrat(_ type: MontserratStyles = .regular, - size: CGFloat = UIFont.systemFontSize) -> UIFont - { - UIFont(name: "Montserrat-\(type.rawValue)", - size: size.adjustedSize()) ?? + static func Montserrat( + _ type: MontserratStyles = .regular, + size: CGFloat = UIFont.systemFontSize + ) -> UIFont { + UIFont( + name: "Montserrat-\(type.rawValue)", + size: size.adjustedSize() + ) ?? UIFont.systemFont(ofSize: size.adjustedSize()) } - static func Muli(_ type: MuliStyles = .regular, - size: CGFloat = UIFont.systemFontSize) -> UIFont - { + static func Muli( + _ type: MuliStyles = .regular, + size: CGFloat = UIFont.systemFontSize + ) -> UIFont { let prefix = (type == .semiBoldItalic || type == .extraBold) ? "Mulish" : "Muli" - return UIFont(name: "\(prefix)-\(type.rawValue)", - size: size.adjustedSize()) ?? + return UIFont( + name: "\(prefix)-\(type.rawValue)", + size: size.adjustedSize() + ) ?? UIFont.systemFont(ofSize: size.adjustedSize()) } - static func Oswald(_ type: OswaldStyles = .extraLight, - size: CGFloat = UIFont.systemFontSize) -> UIFont - { - UIFont(name: "Oswald-\(type.rawValue)", - size: size.adjustedSize()) ?? - UIFont.systemFont(ofSize: size.adjustedSize(), - weight: .ultraLight) + static func Oswald( + _ type: OswaldStyles = .extraLight, + size: CGFloat = UIFont.systemFontSize + ) -> UIFont { + UIFont( + name: "Oswald-\(type.rawValue)", + size: size.adjustedSize() + ) ?? + UIFont.systemFont( + ofSize: size.adjustedSize(), + weight: .ultraLight + ) } } diff --git a/station/Extensions/UIImage+Extension.swift b/station/Extensions/UIImage+Extension.swift index bccd26b05..90d491053 100644 --- a/station/Extensions/UIImage+Extension.swift +++ b/station/Extensions/UIImage+Extension.swift @@ -2,7 +2,8 @@ import UIKit extension UIImage? { func resize(targetWidth: CGFloat = 100) -> UIImage? { - guard let self else { + guard let self + else { return nil } @@ -18,7 +19,8 @@ extension UIImage? { } func resize(targetHeight: CGFloat) -> UIImage? { - guard let self else { + guard let self + else { return nil } diff --git a/station/Extensions/UIImageView+Init.swift b/station/Extensions/UIImageView+Init.swift index d13e35b68..2cfc6f435 100644 --- a/station/Extensions/UIImageView+Init.swift +++ b/station/Extensions/UIImageView+Init.swift @@ -1,11 +1,12 @@ import UIKit extension UIImageView { - convenience init(image: UIImage? = nil, - backgroundColor: UIColor = .clear, - contentMode: ContentMode = .scaleAspectFill, - cornerRadius: CGFloat = 0) - { + convenience init( + image: UIImage? = nil, + backgroundColor: UIColor = .clear, + contentMode: ContentMode = .scaleAspectFill, + cornerRadius: CGFloat = 0 + ) { self.init() self.image = image self.backgroundColor = backgroundColor diff --git a/station/Extensions/UITableViewCell+ReusableView.swift b/station/Extensions/UITableViewCell+ReusableView.swift index 11a546dff..571174aae 100644 --- a/station/Extensions/UITableViewCell+ReusableView.swift +++ b/station/Extensions/UITableViewCell+ReusableView.swift @@ -17,17 +17,20 @@ extension UITableViewCell: ReusableView {} extension UITableViewHeaderFooterView: ReusableView {} extension UITableView { - func dequeueReusableCell(with _: T.Type, - for indexPath: IndexPath) -> T - { - guard let cell = dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as? T else { + func dequeueReusableCell( + with _: T.Type, + for indexPath: IndexPath + ) -> T { + guard let cell = dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as? T + else { preconditionFailure("Unable to dequeue \(T.description()) for indexPath: \(indexPath)") } return cell } func dequeueReusableHeaderFooterView(with _: T.Type) -> T { - guard let cell = dequeueReusableHeaderFooterView(withIdentifier: T.reuseIdentifier) as? T else { + guard let cell = dequeueReusableHeaderFooterView(withIdentifier: T.reuseIdentifier) as? T + else { preconditionFailure("Unable to dequeue \(T.description())") } return cell diff --git a/station/Extensions/UITextField+Extension.swift b/station/Extensions/UITextField+Extension.swift index c7388b064..9cb5b0257 100644 --- a/station/Extensions/UITextField+Extension.swift +++ b/station/Extensions/UITextField+Extension.swift @@ -7,10 +7,12 @@ extension UITextField { var accessories: [UIBarButtonItem] = [] accessories.append(UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)) accessories.append(UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)) - let minusButton = UIBarButtonItem(title: "-", - style: UIBarButtonItem.Style.plain, - target: self, - action: #selector(handleMinusTap)) + let minusButton = UIBarButtonItem( + title: "-", + style: UIBarButtonItem.Style.plain, + target: self, + action: #selector(handleMinusTap) + ) minusButton.tintColor = .label accessories.append(minusButton) numberToolbar.items = accessories @@ -19,7 +21,8 @@ extension UITextField { } @objc func handleMinusTap() { - guard let currentText = text else { + guard let currentText = text + else { return } if currentText.hasPrefix("-") { diff --git a/station/Extensions/UIView+Extension.swift b/station/Extensions/UIView+Extension.swift index fb15685fd..27753b221 100644 --- a/station/Extensions/UIView+Extension.swift +++ b/station/Extensions/UIView+Extension.swift @@ -11,13 +11,15 @@ extension UIView { func fadeIn(animated: Bool = true) { guard alpha == 0 else { return } if animated { - UIView.animate(withDuration: 0.3, - delay: 0.0, - options: .curveLinear, - animations: { [weak self] in - self?.alpha = 1 - self?.layoutIfNeeded() - }) + UIView.animate( + withDuration: 0.3, + delay: 0.0, + options: .curveLinear, + animations: { [weak self] in + self?.alpha = 1 + self?.layoutIfNeeded() + } + ) } else { alpha = 1 } @@ -26,13 +28,15 @@ extension UIView { func fadeOut(animated: Bool = true) { guard alpha == 1 else { return } if animated { - UIView.animate(withDuration: 0.3, - delay: 0.0, - options: .curveLinear, - animations: { [weak self] in - self?.alpha = 0 - self?.layoutIfNeeded() - }) + UIView.animate( + withDuration: 0.3, + delay: 0.0, + options: .curveLinear, + animations: { [weak self] in + self?.alpha = 0 + self?.layoutIfNeeded() + } + ) } else { alpha = 0 } diff --git a/station/Extensions/UIView+Init.swift b/station/Extensions/UIView+Init.swift index 046e18f21..608bde0cf 100644 --- a/station/Extensions/UIView+Init.swift +++ b/station/Extensions/UIView+Init.swift @@ -1,11 +1,12 @@ import UIKit extension UIView { - convenience init(color: UIColor? = .clear, - cornerRadius: CGFloat = 0, - borderWidth: CGFloat = 0, - borderColor: UIColor = .clear) - { + convenience init( + color: UIColor? = .clear, + cornerRadius: CGFloat = 0, + borderWidth: CGFloat = 0, + borderColor: UIColor = .clear + ) { self.init() layer.cornerRadius = cornerRadius layer.borderWidth = borderWidth diff --git a/station/Extensions/UIView+Layout.swift b/station/Extensions/UIView+Layout.swift index 888fc7f5c..43fc8de28 100644 --- a/station/Extensions/UIView+Layout.swift +++ b/station/Extensions/UIView+Layout.swift @@ -5,33 +5,43 @@ import UIKit extension UIView { @discardableResult - func anchor(top: NSLayoutYAxisAnchor?, - leading: NSLayoutXAxisAnchor?, - bottom: NSLayoutYAxisAnchor?, - trailing: NSLayoutXAxisAnchor?, - padding: UIEdgeInsets = .zero, size: CGSize = .zero) -> AnchoredConstraints - { + func anchor( + top: NSLayoutYAxisAnchor?, + leading: NSLayoutXAxisAnchor?, + bottom: NSLayoutYAxisAnchor?, + trailing: NSLayoutXAxisAnchor?, + padding: UIEdgeInsets = .zero, + size: CGSize = .zero + ) -> AnchoredConstraints { translatesAutoresizingMaskIntoConstraints = false var anchoredConstraints = AnchoredConstraints() if let top { - anchoredConstraints.top = topAnchor.constraint(equalTo: top, - constant: padding.top) + anchoredConstraints.top = topAnchor.constraint( + equalTo: top, + constant: padding.top + ) } if let leading { - anchoredConstraints.leading = leadingAnchor.constraint(equalTo: leading, - constant: padding.left) + anchoredConstraints.leading = leadingAnchor.constraint( + equalTo: leading, + constant: padding.left + ) } if let bottom { - anchoredConstraints.bottom = bottomAnchor.constraint(equalTo: bottom, - constant: -padding.bottom) + anchoredConstraints.bottom = bottomAnchor.constraint( + equalTo: bottom, + constant: -padding.bottom + ) } if let trailing { - anchoredConstraints.trailing = trailingAnchor.constraint(equalTo: trailing, - constant: -padding.right) + anchoredConstraints.trailing = trailingAnchor.constraint( + equalTo: trailing, + constant: -padding.right + ) } if size.width != 0 { @@ -42,24 +52,27 @@ extension UIView { anchoredConstraints.height = heightAnchor.constraint(equalToConstant: size.height) } - [anchoredConstraints.top, - anchoredConstraints.leading, - anchoredConstraints.bottom, - anchoredConstraints.trailing, - anchoredConstraints.width, - anchoredConstraints.height].forEach { $0?.isActive = true } + [ + anchoredConstraints.top, + anchoredConstraints.leading, + anchoredConstraints.bottom, + anchoredConstraints.trailing, + anchoredConstraints.width, + anchoredConstraints.height, + ].forEach { $0?.isActive = true } return anchoredConstraints } @discardableResult - func anchorLeading(top: NSLayoutYAxisAnchor?, - leading: NSLayoutXAxisAnchor?, - bottom: NSLayoutYAxisAnchor?, - trailing: NSLayoutXAxisAnchor?, - padding: UIEdgeInsets = .zero, - size: CGSize = .zero) -> AnchoredConstraints - { + func anchorLeading( + top: NSLayoutYAxisAnchor?, + leading: NSLayoutXAxisAnchor?, + bottom: NSLayoutYAxisAnchor?, + trailing: NSLayoutXAxisAnchor?, + padding: UIEdgeInsets = .zero, + size: CGSize = .zero + ) -> AnchoredConstraints { translatesAutoresizingMaskIntoConstraints = false var anchoredConstraints = AnchoredConstraints() @@ -69,20 +82,26 @@ extension UIView { if let leading { anchoredConstraints.leading = - leadingAnchor.constraint(greaterThanOrEqualTo: leading, - constant: padding.left) + leadingAnchor.constraint( + greaterThanOrEqualTo: leading, + constant: padding.left + ) } if let bottom { anchoredConstraints.bottom = - bottomAnchor.constraint(equalTo: bottom, - constant: -padding.bottom) + bottomAnchor.constraint( + equalTo: bottom, + constant: -padding.bottom + ) } if let trailing { anchoredConstraints.trailing = - trailingAnchor.constraint(lessThanOrEqualTo: trailing, - constant: -padding.right) + trailingAnchor.constraint( + lessThanOrEqualTo: trailing, + constant: -padding.right + ) } if size.width != 0 { @@ -93,12 +112,14 @@ extension UIView { anchoredConstraints.height = heightAnchor.constraint(equalToConstant: size.height) } - [anchoredConstraints.top, - anchoredConstraints.leading, - anchoredConstraints.bottom, - anchoredConstraints.trailing, - anchoredConstraints.width, - anchoredConstraints.height].forEach { $0?.isActive = true } + [ + anchoredConstraints.top, + anchoredConstraints.leading, + anchoredConstraints.bottom, + anchoredConstraints.trailing, + anchoredConstraints.width, + anchoredConstraints.height, + ].forEach { $0?.isActive = true } return anchoredConstraints } diff --git a/station/Extensions/UIViewController+Alert.swift b/station/Extensions/UIViewController+Alert.swift index 45af1a46f..5c3d7b34f 100644 --- a/station/Extensions/UIViewController+Alert.swift +++ b/station/Extensions/UIViewController+Alert.swift @@ -2,9 +2,10 @@ import RuuviLocalization import UIKit extension UIViewController { - func showAlert(title: String? = nil, - message: String? = nil) - { + func showAlert( + title: String? = nil, + message: String? = nil + ) { let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) diff --git a/station/Extensions/UnitSettingsType.swift b/station/Extensions/UnitSettingsType.swift index e5eb15889..c1ec02179 100644 --- a/station/Extensions/UnitSettingsType.swift +++ b/station/Extensions/UnitSettingsType.swift @@ -9,10 +9,8 @@ enum UnitSettingsType { extension UnitSettingsType: SelectionItemProtocol { var title: (String) -> String { switch self { - case .unit: - { _ in RuuviLocalization.Settings.Measurement.Unit.title } - case .accuracy: - { _ in RuuviLocalization.Settings.Measurement.Resolution.title } + case .unit: { _ in RuuviLocalization.Settings.Measurement.Unit.title } + case .accuracy: { _ in RuuviLocalization.Settings.Measurement.Resolution.title } } } } diff --git a/stationTests/MockLocalNotificationsManager.swift b/stationTests/MockLocalNotificationsManager.swift index 021e2492b..5529438b4 100644 --- a/stationTests/MockLocalNotificationsManager.swift +++ b/stationTests/MockLocalNotificationsManager.swift @@ -5,8 +5,10 @@ class MockLocalNotificationsManager: LocalNotificationsManager { var reason: LowHighNotificationReason? var type: LowHighNotificationType? var uuid: String? - func application(_: UIApplication, - didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) {} + func application( + _: UIApplication, + didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? + ) {} func showDidConnect(uuid _: String) {} diff --git a/stationTests/Services/Alert/AlertServiceSpec.swift b/stationTests/Services/Alert/AlertServiceSpec.swift index 2c8176736..e2deec658 100644 --- a/stationTests/Services/Alert/AlertServiceSpec.swift +++ b/stationTests/Services/Alert/AlertServiceSpec.swift @@ -689,14 +689,16 @@ class AlertServiceSpec: QuickSpec { func equalName(_ expectedName: Notification.Name, for uuid: String) -> Predicate<[Notification]> { Predicate.define("equal <\(stringify(expectedName))>") { actualExpression, msg in - guard let actualValue = try actualExpression.evaluate() else { + guard let actualValue = try actualExpression.evaluate() + else { return PredicateResult(status: .fail, message: msg) } let actualNames = actualValue .filter { $0.name == expectedName } .filter { notification in - guard let userInfo = notification.userInfo else { + guard let userInfo = notification.userInfo + else { return false } return userInfo[RuuviServiceAlertDidChangeKey.uuid] as? String == uuid diff --git a/stationTests/Services/MeasurementsService/MeasurementsServiceEnSpec.swift b/stationTests/Services/MeasurementsService/MeasurementsServiceEnSpec.swift index dbcf3ffaf..0b666af32 100644 --- a/stationTests/Services/MeasurementsService/MeasurementsServiceEnSpec.swift +++ b/stationTests/Services/MeasurementsService/MeasurementsServiceEnSpec.swift @@ -44,17 +44,21 @@ class MeasurementsServiceEnSpec: QuickSpec { } it("string without sign kelvin") { let temp = Temperature(value: 250.10, unit: .kelvin) - service.units = MeasurementsServiceSettigsUnit(temperatureUnit: .kelvin, - humidityUnit: settings.humidityUnit, - pressureUnit: settings.pressureUnit) + service.units = MeasurementsServiceSettigsUnit( + temperatureUnit: .kelvin, + humidityUnit: settings.humidityUnit, + pressureUnit: settings.pressureUnit + ) expect(service.stringWithoutSign(for: temp)) .to(equal("250.10")) } it("string without sign fahrenheit") { let temp = Temperature(value: 73.10, unit: .fahrenheit) - service.units = MeasurementsServiceSettigsUnit(temperatureUnit: .fahrenheit, - humidityUnit: settings.humidityUnit, - pressureUnit: settings.pressureUnit) + service.units = MeasurementsServiceSettigsUnit( + temperatureUnit: .fahrenheit, + humidityUnit: settings.humidityUnit, + pressureUnit: settings.pressureUnit + ) settings.temperatureUnit = .fahrenheit expect(service.stringWithoutSign(for: temp)) .to(equal("73.10")) diff --git a/stationTests/Services/MeasurementsService/MeasurementsServiceFiSpec.swift b/stationTests/Services/MeasurementsService/MeasurementsServiceFiSpec.swift index b6fe94ca6..808af29e9 100644 --- a/stationTests/Services/MeasurementsService/MeasurementsServiceFiSpec.swift +++ b/stationTests/Services/MeasurementsService/MeasurementsServiceFiSpec.swift @@ -44,17 +44,21 @@ class MeasurementsServiceFiSpec: QuickSpec { } it("string without sign kelvin") { let temp = Temperature(value: 250.10, unit: .kelvin) - service.units = MeasurementsServiceSettigsUnit(temperatureUnit: .kelvin, - humidityUnit: settings.humidityUnit, - pressureUnit: settings.pressureUnit) + service.units = MeasurementsServiceSettigsUnit( + temperatureUnit: .kelvin, + humidityUnit: settings.humidityUnit, + pressureUnit: settings.pressureUnit + ) expect(service.stringWithoutSign(for: temp)) .to(equal("250,10")) } it("string without sign fahrenheit") { let temp = Temperature(value: 73.10, unit: .fahrenheit) - service.units = MeasurementsServiceSettigsUnit(temperatureUnit: .fahrenheit, - humidityUnit: settings.humidityUnit, - pressureUnit: settings.pressureUnit) + service.units = MeasurementsServiceSettigsUnit( + temperatureUnit: .fahrenheit, + humidityUnit: settings.humidityUnit, + pressureUnit: settings.pressureUnit + ) settings.temperatureUnit = .fahrenheit expect(service.stringWithoutSign(for: temp)) .to(equal("73,10")) diff --git a/stationTests/Services/MeasurementsService/MeasurementsServiceRuSpec.swift b/stationTests/Services/MeasurementsService/MeasurementsServiceRuSpec.swift index a1495d9bc..12a68a06e 100644 --- a/stationTests/Services/MeasurementsService/MeasurementsServiceRuSpec.swift +++ b/stationTests/Services/MeasurementsService/MeasurementsServiceRuSpec.swift @@ -44,17 +44,21 @@ class MeasurementsServiceRuSpec: QuickSpec { } it("string without sign kelvin") { let temp = Temperature(value: 250.10, unit: .kelvin) - service.units = MeasurementsServiceSettigsUnit(temperatureUnit: .kelvin, - humidityUnit: settings.humidityUnit, - pressureUnit: settings.pressureUnit) + service.units = MeasurementsServiceSettigsUnit( + temperatureUnit: .kelvin, + humidityUnit: settings.humidityUnit, + pressureUnit: settings.pressureUnit + ) expect(service.stringWithoutSign(for: temp)) .to(equal("250,10")) } it("string without sign fahrenheit") { let temp = Temperature(value: 73.10, unit: .fahrenheit) - service.units = MeasurementsServiceSettigsUnit(temperatureUnit: .fahrenheit, - humidityUnit: settings.humidityUnit, - pressureUnit: settings.pressureUnit) + service.units = MeasurementsServiceSettigsUnit( + temperatureUnit: .fahrenheit, + humidityUnit: settings.humidityUnit, + pressureUnit: settings.pressureUnit + ) settings.temperatureUnit = .fahrenheit expect(service.stringWithoutSign(for: temp)) .to(equal("73,10")) diff --git a/stationTests/Services/MeasurementsService/MeasurementsServiceSvSpec.swift b/stationTests/Services/MeasurementsService/MeasurementsServiceSvSpec.swift index 13ff35b38..a95f89ce9 100644 --- a/stationTests/Services/MeasurementsService/MeasurementsServiceSvSpec.swift +++ b/stationTests/Services/MeasurementsService/MeasurementsServiceSvSpec.swift @@ -44,17 +44,21 @@ class MeasurementsServiceSvSpec: QuickSpec { } it("string without sign kelvin") { let temp = Temperature(value: 250.10, unit: .kelvin) - service.units = MeasurementsServiceSettigsUnit(temperatureUnit: .kelvin, - humidityUnit: settings.humidityUnit, - pressureUnit: settings.pressureUnit) + service.units = MeasurementsServiceSettigsUnit( + temperatureUnit: .kelvin, + humidityUnit: settings.humidityUnit, + pressureUnit: settings.pressureUnit + ) expect(service.stringWithoutSign(for: temp)) .to(equal("250,10")) } it("string without sign fahrenheit") { let temp = Temperature(value: 73.10, unit: .fahrenheit) - service.units = MeasurementsServiceSettigsUnit(temperatureUnit: .fahrenheit, - humidityUnit: settings.humidityUnit, - pressureUnit: settings.pressureUnit) + service.units = MeasurementsServiceSettigsUnit( + temperatureUnit: .fahrenheit, + humidityUnit: settings.humidityUnit, + pressureUnit: settings.pressureUnit + ) settings.temperatureUnit = .fahrenheit expect(service.stringWithoutSign(for: temp)) .to(equal("73,10")) diff --git a/stationTests/StationTests.swift b/stationTests/StationTests.swift index 8ca8bd1fe..9b1da2184 100644 --- a/stationTests/StationTests.swift +++ b/stationTests/StationTests.swift @@ -5,13 +5,17 @@ class StationTests: XCTestCase { func testWebTagDaemonCrash() { NotificationCenter .default - .post(name: .isWebTagDaemonOnDidChange, - object: self, - userInfo: nil) + .post( + name: .isWebTagDaemonOnDidChange, + object: self, + userInfo: nil + ) NotificationCenter .default - .post(name: .WebTagDaemonIntervalDidChange, - object: self, - userInfo: nil) + .post( + name: .WebTagDaemonIntervalDidChange, + object: self, + userInfo: nil + ) } } diff --git a/stationUITests/StationUITests.swift b/stationUITests/StationUITests.swift index d5025188c..5734f1de0 100644 --- a/stationUITests/StationUITests.swift +++ b/stationUITests/StationUITests.swift @@ -6,8 +6,4 @@ class StationUITests: XCTestCase { continueAfterFailure = false XCUIApplication().launch() } - - override func tearDown() { - super.tearDown() - } } From d40a2b4f66980b284fe33e2a36b4738bba829c57 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sun, 10 Dec 2023 01:05:44 +0200 Subject: [PATCH 33/84] Eliminate warnings and fix localization (#1762) * Eliminate warnings and fix localization Fixes localization issues related to %0.f * suppress OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries * suppress OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries in widgets --- .../Resources/de.lproj/Localizable.strings | 10 +- .../Resources/en.lproj/Localizable.strings | 10 +- .../Resources/fi.lproj/Localizable.strings | 10 +- .../Resources/fr.lproj/Localizable.strings | 10 +- .../Resources/ru.lproj/Localizable.strings | 10 +- .../Resources/sv.lproj/Localizable.strings | 10 +- .../RuuviLocalization/RuuviLocalization.swift | 30 +++-- .../Templates/Localizable_de.strings.stencil | 4 +- .../Templates/Localizable_en.strings.stencil | 2 +- .../Templates/Localizable_fi.strings.stencil | 4 +- .../Templates/Localizable_fr.strings.stencil | 4 +- .../Templates/Localizable_ru.strings.stencil | 4 +- .../Templates/Localizable_sv.strings.stencil | 4 +- .../VMP/Presenter/DiscoverPresenter.swift | 20 ++- .../View/Table/DiscoverTableHeaderView.swift | 8 +- .../Table/DiscoverTableViewController.swift | 1 + .../Sources/RuuviOnboard/Pages/Helpers.swift | 6 +- .../Pages/RuuviOnboardViewController.swift | 2 - .../RuuviAnalyticsImpl.swift | 1 - .../Sources/RuuviCloudApi/RuuviCloudApi.swift | 1 - ...uuviCloudApiSensorImageUploadRequest.swift | 1 - .../Request/Upload/UserApiUploadRequest.swift | 1 - .../Response/RuuviCloudApiBaseResponse.swift | 1 - .../URLSession/RuuviCloudApiURLSession.swift | 1 - .../RuuviCloudFactoryPure.swift | 4 - .../RuuviCloudPure/RuuviCloudPure.swift | 4 - .../RealmContextFactoryImpl.swift | 2 - .../RuuviContextRealm/RealmContextImpl.swift | 1 - .../SQLiteContextFactoryGRDB.swift | 1 - .../SQLiteContextGRDB.swift | 1 - .../RuuviCoreImage/RuuviCoreImageImpl.swift | 3 +- .../RuuviCoreLocationImpl.swift | 14 +-- .../Sources/RuuviCorePN/RuuviCorePNImpl.swift | 1 - .../RuuviCorePermissionImpl.swift | 1 - .../Sources/RuuviDFUImpl/DfuFlasher.swift | 1 - .../Sources/RuuviDFUImpl/DfuScanner.swift | 1 - .../Sources/RuuviDFUImpl/RuuviDFUImpl.swift | 1 - .../BackgroundProcessServiceiOS13.swift | 4 - .../RuuviDaemonCloudSyncWorker.swift | 1 - .../RuuviDaemonFactoryCloudSync.swift | 1 - .../Data/DataPruningOperationsManager.swift | 1 - .../RuuviTagAdvertisementDaemonBTKit.swift | 1 - .../RuuviTagHeartbeatDaemonBTKit.swift | 1 - .../RuuviTagPropertiesDaemonBTKit.swift | 3 +- .../Documents/ImagePersistenceDocuments.swift | 1 - .../Background/Image/ImagePersistence.swift | 1 - .../RuuviLocalImagesUserDefaults.swift | 3 +- .../RuuviLocalConnectionsUserDefaults.swift | 1 - .../RuuviLocalFactoryUserDefaults.swift | 1 - .../RuuviLocalIDsUserDefaults.swift | 1 - .../RuuviLocalSettingsUserDefaults.swift | 1 - .../RuuviLocalSyncStateUserDefaults.swift | 1 - .../MigrationManagerAlertService.swift | 1 - .../RuuviMigrationFactoryImpl.swift | 1 - .../MigrationManagerSensorSettings.swift | 1 - .../RuuviMigrationFixRHAlerts.swift | 1 - .../MigrationManagerToChartDuration240.swift | 1 - .../MigrationManagerToNetworkPull60.swift | 1 - .../MigrationManagerToPrune240.swift | 1 - .../toRH/MigrationManagerToRH.swift | 1 - .../toSQLite/MigrationManagerToSQLite.swift | 1 - .../MigrationManagerToTimeouts.swift | 1 - .../toVIPER/MigrationManagerToVIPER.swift | 1 - .../RuuviNotificationLocalImpl.swift | 18 +-- .../RuuviNotifierImpl+Process.swift | 3 +- .../RuuviNotifierImpl/RuuviNotifierImpl.swift | 1 - .../RuuviTagDataRealm+Extension.swift | 1 - ...uviTagDataRealm+RuuviTagSensorRecord.swift | 1 - .../RuuviTagDataRealm.swift | 1 - .../RuuviTagLatestDataRealm+Extension.swift | 1 - ...LatestDataRealm+RuuviTagSensorRecord.swift | 1 - .../RuuviTagLatestDataRealm.swift | 1 - .../RuuviTagRealm+RuuviTagSensor.swift | 1 - .../RuuviOntologyRealm/RuuviTagRealm.swift | 1 - .../RuuviTagRealmProtocol.swift | 1 - .../SensorSettingsRealm.swift | 1 - .../RuuviCloudQueuedRequestSQLite.swift | 1 - .../RuuviTagDataSQLite.swift | 1 - .../RuuviTagLatestDataSQLite.swift | 1 - .../RuuviOntologySQLite/RuuviTagSQLite.swift | 1 - ...viTagSensorRecord+RuuviTagDataSQLite.swift | 1 - .../SensorSettingsSQLite.swift | 1 - .../RuuviPersistenceRealm.swift | 1 - .../RuuviPersistenceSQLite.swift | 1 - .../RuuviPoolCoordinator.swift | 1 - .../RuuviPoolFactoryCoordinator.swift | 1 - .../RuuviReactorFactoryImpl.swift | 1 - .../RuuviReactorImpl/RuuviReactorImpl.swift | 1 - .../RuuviRepositoryCoordinator.swift | 1 - .../RuuviRepositoryFactoryCoordinator.swift | 1 - .../AlertPersistenceUserDefaults.swift | 14 +-- .../UserDefaults/KeyedArchiver.swift | 14 +-- .../RuuviServiceAlertImpl.swift | 3 +- .../RuuviServiceAppSettingsImpl.swift | 1 - .../RuuviServiceAuthImpl.swift | 1 - .../RuuviServiceCloudNotificationImpl.swift | 1 - .../RuuviServiceCloudSyncImpl.swift | 3 +- ...uuviServiceCloudSyncRecordsOperation.swift | 1 - .../RuuviServiceExportImpl.swift | 7 +- .../RuuviServiceFactory.swift | 1 - .../RuuviTagReadLogsOperation.swift | 1 - .../Queue/GATTServiceQueue.swift | 1 - .../RuuviServiceMeasurementImpl.swift | 1 - ...RuuviServiceAppOffsetCalibrationImpl.swift | 1 - .../RuuviServiceOwnershipImpl.swift | 1 - .../RuuviServiceSensorPropertiesImpl.swift | 1 - .../RuuviServiceSensorRecordsImpl.swift | 1 - .../RuuviStorageCoordinator.swift | 1 - .../RuuviStorageFactoryCoordinator.swift | 1 - .../RuuviUserCoordinator.swift | 1 - .../RuuviUserFactoryCoordinator.swift | 3 - intents_frameworks.yml | 1 + pnservice.yml | 1 + project_frameworks.yml | 10 ++ .../About/View/AboutViewController.swift | 1 + .../BackgroundSelectionViewController.swift | 1 + .../Cards/Presenter/CardsPresenter.swift | 4 +- .../Cards/View/UI/CardsViewController.swift | 1 + .../Presenter/TagChartsViewPresenter.swift | 6 +- .../Charts/View/UI/TagChartsView.swift | 1 + .../View/UI/TagChartsViewController.swift | 5 +- .../Home/Presenter/DashboardPresenter.swift | 4 +- .../Home/View/DashboardViewController.swift | 1 + .../MenuTableEmbededViewController.swift | 5 + .../View/MyRuuviAccountViewController.swift | 1 + .../Table/SettingsTableViewController.swift | 1 + .../UI/ASSelectionTableViewController.swift | 1 + ...ppearanceSettingsTableViewController.swift | 1 + .../View/DefaultsViewController.swift | 1 + .../Table/DefaultsTableViewController.swift | 7 +- .../View/UI/DevicesTableViewController.swift | 1 + .../View/HeartbeatViewController.swift | 1 + .../Table/HeartbeatTableViewController.swift | 1 + ...ertSoundSelectionTableViewController.swift | 1 + ...ficationsSettingsTableViewController.swift | 1 + .../UI/RuuviCloudTableViewController.swift | 1 + .../Table/SelectionTableViewController.swift | 1 + .../UnitSettingsTableViewController.swift | 1 + .../ViewController/ShareViewController.swift | 1 + .../View/SignInBenefitsViewController.swift | 1 + .../SignIn/View/UI/SignInViewController.swift | 1 + .../UI/SensorForceClaimViewController.swift | 1 + .../OffsetCorrectionAppleViewController.swift | 2 +- .../Owner/View/OwnerViewController.swift | 1 + .../View/UI/SensorRemovalViewController.swift | 1 + .../View/UI/TagSettingsViewController.swift | 117 ++++-------------- .../Alert/Impl/AlertPresenterImpl.swift | 16 +-- widget_frameworks.yml | 1 + 148 files changed, 195 insertions(+), 336 deletions(-) diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/de.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/de.lproj/Localizable.strings index 7b56f5ec0..3be9a37ef 100644 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/de.lproj/Localizable.strings +++ b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/de.lproj/Localizable.strings @@ -240,7 +240,7 @@ "LocalNotificationsManager.HighTemperature.title" = "Temperatur ist zu hoch!"; "LocalNotificationsManager.LowTemperature.title" = "Temperatur zu niedrig!"; "TagSettings.Alerts.Off" = "Aus"; -"TagSettings.Alerts.Temperature.description" = "Warnung bei weniger als %0.f oder mehr als %0.f"; +"TagSettings.Alerts.Temperature.description" = "Warnung bei weniger als %.0f oder mehr als %.0f"; "TagSettings.Label.alerts.text" = "Warnungen"; "TagSettings.backgroundImageLabel.text" = "Hintergrund bild"; "TagSettings.batteryVoltageTitleLabel.text" = "Batteriespannung"; @@ -558,8 +558,8 @@ Ihr RuuviTag-Sensor ist einsatzbereit!"; "TagSettings.Alert.SetHumidity.title" = "Feuchtigkeitsalarm einstellen"; "TagSettings.Alert.SetPressure.title" = "Druckalarm einstellen"; "TagSettings.Alert.SetRSSI.title" = "Signalstärkealarm einstellen"; -"TagSettings.AlertSettings.Dialog.Min" = "Min (%0.f)"; -"TagSettings.AlertSettings.Dialog.Max" = "Max (%0.f)"; +"TagSettings.AlertSettings.Dialog.Min" = "Min (%.0f)"; +"TagSettings.AlertSettings.Dialog.Max" = "Max (%.0f)"; "export_history" = "Verlauf exportieren (csv)"; "clear_view" = "Klare verlaufsansicht"; "day_1" = "1 Tag"; @@ -572,12 +572,12 @@ Ihr RuuviTag-Sensor ist einsatzbereit!"; "day_8" = "8 Tage"; "day_9" = "9 Tage"; "day_10" = "10 Tage"; -"day_x" = "%0.f Tage"; +"day_x" = "%.0f Tage"; "more" = "Mehr..."; "all" = "Alle"; "longer_history_title" = "Längere Geschichte"; "longer_history_message" = "Die Ruuvi Station Mobile App unterstützt maximal 10 Tage Historie. Ruuvi-Cloud-Abonnenten können mit der Web-App unter ruuvi.com/station (erfordert Ruuvi-Gateway-Router) bis zu 2 Jahre historische Daten anzeigen."; -"reading_history_x" = "Bluetooth-Sync: %0.f"; +"reading_history_x" = "Bluetooth-Sync: %.0f"; "rssi_alert_description" = "Die Verwendung dieses Alarms setzt voraus, dass Sie in der App angemeldet sind und dass Sie den Sensor für sich beansprucht haben und dass er sich in der Reichweite des Ruuvi Gateway Routers befindet. iOS-Geräte können keine Informationen zur Signalstärke der vom Ruuvi-Sensor gesendeten Daten anzeigen, wenn der Sensor gekoppelt ist und Messungen im Hintergrund empfangen werden. Die Echtzeit-Bluetooth-Signalstärke wird in der App angezeigt, hat aber keinen Einfluss auf diesen Alarm."; "bluetooth_download" = "Bluetooth-Download"; "bluetooth_download_description" = "Lokale Sensordaten können heruntergeladen werden, wenn Sie sich in Bluetooth-Reichweite befinden."; diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings index f815def81..df8b7ce15 100644 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings +++ b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings @@ -241,7 +241,7 @@ If you cannot see the Language option in the settings, make sure that you have a "LocalNotificationsManager.HighTemperature.title" = "Temperature is too high!"; "LocalNotificationsManager.LowTemperature.title" = "Temperature is too low!"; "TagSettings.Alerts.Off" = "Off"; -"TagSettings.Alerts.Temperature.description" = "Alert when less than %0.f or more than %0.f"; +"TagSettings.Alerts.Temperature.description" = "Alert when less than %.0f or more than %.0f"; "TagSettings.Label.alerts.text" = "Alerts"; "TagSettings.backgroundImageLabel.text" = "Background image"; "TagSettings.batteryVoltageTitleLabel.text" = "Battery Voltage"; @@ -559,8 +559,8 @@ Your RuuviTag sensor is ready for use!"; "TagSettings.Alert.SetHumidity.title" = "Set humidity alert"; "TagSettings.Alert.SetPressure.title" = "Set pressure alert"; "TagSettings.Alert.SetRSSI.title" = "Set signal strength alert"; -"TagSettings.AlertSettings.Dialog.Min" = "Min (%0.f)"; -"TagSettings.AlertSettings.Dialog.Max" = "Max (%0.f)"; +"TagSettings.AlertSettings.Dialog.Min" = "Min (%.0f)"; +"TagSettings.AlertSettings.Dialog.Max" = "Max (%.0f)"; "export_history" = "Export history (csv)"; "clear_view" = "Clear history view"; "day_1" = "1 day"; @@ -573,12 +573,12 @@ Your RuuviTag sensor is ready for use!"; "day_8" = "8 days"; "day_9" = "9 days"; "day_10" = "10 days"; -"day_x" = "%0.f days"; +"day_x" = "%.0f days"; "more" = "More..."; "all" = "All"; "longer_history_title" = "Longer history"; "longer_history_message" = "Ruuvi Station mobile app supports maximum 10 days of history. Ruuvi Cloud subscribers are able to view up to 2 years of historical data using web app at ruuvi.com/station (requires Ruuvi Gateway router)."; -"reading_history_x" = "Reading Bluetooth: %0.f"; +"reading_history_x" = "Reading Bluetooth: %.0f"; "rssi_alert_description" = "Using this alert requires you to be signed in to the app, and that you have claimed the ownership of this sensor and it's in the range of Ruuvi Gateway router. iOS devices are unable to indicate signal strength information of received data sent by Ruuvi sensor when sensor is paired and measurements are being received in the background. Realtime Bluetooth signal strength is shown in the app but doesn't affect this alert."; "bluetooth_download" = "Bluetooth download"; "bluetooth_download_description" = "Local sensor data can be downloaded, when you're within its Bluetooth range."; diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fi.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fi.lproj/Localizable.strings index be1cbb293..50b4daa2e 100644 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fi.lproj/Localizable.strings +++ b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fi.lproj/Localizable.strings @@ -241,7 +241,7 @@ Mikäli et näe Kieli-valintaa asetuksissa, varmista, että sinulla on vähintä "LocalNotificationsManager.HighTemperature.title" = "Lämpötila liian korkea!"; "LocalNotificationsManager.LowTemperature.title" = "Lämpötila liian alhainen!"; "TagSettings.Alerts.Off" = "Pois käytöstä"; -"TagSettings.Alerts.Temperature.description" = "Hälytä, mikäli alle %0.f tai yli %0.f"; +"TagSettings.Alerts.Temperature.description" = "Hälytä, mikäli alle %.0f tai yli %.0f"; "TagSettings.Label.alerts.text" = "Hälytykset"; "TagSettings.backgroundImageLabel.text" = "Taustakuva"; "TagSettings.batteryVoltageTitleLabel.text" = "Paristojännite"; @@ -559,8 +559,8 @@ RuuviTag on valmis käyttöön!"; "TagSettings.Alert.SetHumidity.title" = "Aseta kosteushälytys"; "TagSettings.Alert.SetPressure.title" = "Aseta painehälytys"; "TagSettings.Alert.SetRSSI.title" = "Aseta signaalinvoimakkuushälytys"; -"TagSettings.AlertSettings.Dialog.Min" = "Min (%0.f)"; -"TagSettings.AlertSettings.Dialog.Max" = "Max (%0.f)"; +"TagSettings.AlertSettings.Dialog.Min" = "Min (%.0f)"; +"TagSettings.AlertSettings.Dialog.Max" = "Max (%.0f)"; "export_history" = "Lataa historia (csv)"; "clear_view" = "Tyhjennä kaavionäkymä"; "day_1" = "1 päivä"; @@ -573,12 +573,12 @@ RuuviTag on valmis käyttöön!"; "day_8" = "8 päivää"; "day_9" = "9 päivää"; "day_10" = "10 päivää"; -"day_x" = "%0.f päivää"; +"day_x" = "%.0f päivää"; "more" = "Lisää..."; "all" = "Kaikki"; "longer_history_title" = "Pidempi historia"; "longer_history_message" = "Ruuvi Station -mobiilisovellus tukee maksimissaan 10 päivän historiaa. Ruuvi Cloud -tilaajat voivat tarkastella historiatietoja jopa 2 vuoden ajalta web-sovelluksessa osoitteessa ruuvi.com/fi/station (vaatii Ruuvi Gateway -reitittimen)."; -"reading_history_x" = "Bluetooth-lataus: %0.f"; +"reading_history_x" = "Bluetooth-lataus: %.0f"; "rssi_alert_description" = "Tämän hälytyksen käyttö vaatii, että olet sisäänkirjautunut sovellukseen, sinut on merkitty anturin omistajaksi ja anturi on Ruuvi Gateway -reitittimen kuuluvuusalueella. iOS-päätelaitteet eivät pysty näyttämään Ruuvin anturien lähettämien viestien signaalinvoimakkuustietoja anturin ollessa paritettuna ja kun mittauksia luetaan taustalla. Reaaliaikainen Bluetooth-signaalinvoimakkuus näytetään sovelluksessa, mutta sitä ei käytetä tässä hälytyksessä."; "bluetooth_download" = "Bluetooth-lataus"; "bluetooth_download_description" = "Voit ladata anturin sisäisen historian ollessasi Bluetooth-kantaman sisällä."; diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fr.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fr.lproj/Localizable.strings index 34b04170f..10f7618e3 100644 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fr.lproj/Localizable.strings +++ b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fr.lproj/Localizable.strings @@ -240,7 +240,7 @@ "LocalNotificationsManager.HighTemperature.title" = "Température trop haute !"; "LocalNotificationsManager.LowTemperature.title" = "Température trop basse !"; "TagSettings.Alerts.Off" = "Désactivé"; -"TagSettings.Alerts.Temperature.description" = "Notifier si la valeur est inférieure à %0.f ou supérieure à %0.f"; +"TagSettings.Alerts.Temperature.description" = "Notifier si la valeur est inférieure à %.0f ou supérieure à %.0f"; "TagSettings.Label.alerts.text" = "Notifications"; "TagSettings.backgroundImageLabel.text" = "Fond d'écran"; "TagSettings.batteryVoltageTitleLabel.text" = "Tension de la pile"; @@ -558,8 +558,8 @@ RuuviTag est prêt à être utilisé !"; "TagSettings.Alert.SetHumidity.title" = "Réglage de l'alerte d'humidité"; "TagSettings.Alert.SetPressure.title" = "Régler l'alerte de pression"; "TagSettings.Alert.SetRSSI.title" = "Définir une alerte sur la puissance du signal"; -"TagSettings.AlertSettings.Dialog.Min" = "Min (%0.f)"; -"TagSettings.AlertSettings.Dialog.Max" = "Max (%0.f)"; +"TagSettings.AlertSettings.Dialog.Min" = "Min (%.0f)"; +"TagSettings.AlertSettings.Dialog.Max" = "Max (%.0f)"; "export_history" = "Exportation de l'historique (csv)"; "clear_view" = "Vue historique vide"; "day_1" = "1 jour"; @@ -572,12 +572,12 @@ RuuviTag est prêt à être utilisé !"; "day_8" = "8 jours"; "day_9" = "9 jours"; "day_10" = "10 jours"; -"day_x" = "%0.f jours"; +"day_x" = "%.0f jours"; "more" = "Plus..."; "all" = "Tout"; "longer_history_title" = "Une histoire plus longue"; "longer_history_message" = "L'application mobile Ruuvi Station prend en charge un maximum de 10 jours d'historique. Les abonnés à Ruuvi Cloud peuvent consulter jusqu'à 2 ans d'historique en utilisant l'application web à ruuvi.com/station (nécessite le routeur Ruuvi Gateway)."; -"reading_history_x" = "Bluetooth sync: %0.f"; +"reading_history_x" = "Bluetooth sync: %.0f"; "rssi_alert_description" = "L'utilisation de cette alerte nécessite que vous soyez connecté à l'application, que vous ayez revendiqué la propriété de ce capteur et qu'il se trouve dans le rayon d'action du routeur de la passerelle Ruuvi. Les appareils iOS sont incapables d'indiquer l'intensité du signal des données reçues envoyées par le capteur Ruuvi lorsque le capteur est apparié et que des mesures sont reçues en arrière-plan. La puissance du signal Bluetooth en temps réel est affichée dans l'application mais n'affecte pas cette alerte."; "bluetooth_download" = "Téléchargement Bluetooth"; "bluetooth_download_description" = "Les données du capteur local peuvent être téléchargées lorsque vous êtes dans sa portée Bluetooth."; diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/ru.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/ru.lproj/Localizable.strings index 5f8df82b7..77faef121 100644 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/ru.lproj/Localizable.strings +++ b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/ru.lproj/Localizable.strings @@ -241,7 +241,7 @@ If you cannot see the Language option in the settings, make sure that you have a "LocalNotificationsManager.HighTemperature.title" = "Высокая температура!"; "LocalNotificationsManager.LowTemperature.title" = "Низкая температура!"; "TagSettings.Alerts.Off" = "Отключено"; -"TagSettings.Alerts.Temperature.description" = "Уведомление если меньше %0.f или больше %0.f"; +"TagSettings.Alerts.Temperature.description" = "Уведомление если меньше %.0f или больше %.0f"; "TagSettings.Label.alerts.text" = "Уведомления"; "TagSettings.backgroundImageLabel.text" = "Фоновое изображение"; "TagSettings.batteryVoltageTitleLabel.text" = "Напряжение Батареи"; @@ -559,8 +559,8 @@ If you cannot see the Language option in the settings, make sure that you have a "TagSettings.Alert.SetHumidity.title" = "Set humidity alert"; "TagSettings.Alert.SetPressure.title" = "Set pressure alert"; "TagSettings.Alert.SetRSSI.title" = "Set signal strength alert"; -"TagSettings.AlertSettings.Dialog.Min" = "Min (%0.f)"; -"TagSettings.AlertSettings.Dialog.Max" = "Max (%0.f)"; +"TagSettings.AlertSettings.Dialog.Min" = "Min (%.0f)"; +"TagSettings.AlertSettings.Dialog.Max" = "Max (%.0f)"; "export_history" = "Выгрузить историю (csv)"; "clear_view" = "Clear history view"; "day_1" = "1 день"; @@ -573,12 +573,12 @@ If you cannot see the Language option in the settings, make sure that you have a "day_8" = "8 дней"; "day_9" = "9 дней"; "day_10" = "10 дней"; -"day_x" = "%0.f days"; +"day_x" = "%.0f days"; "more" = "Больше..."; "all" = "All"; "longer_history_title" = "Longer history"; "longer_history_message" = "Ruuvi Station mobile app supports maximum 10 days of history. Ruuvi Cloud subscribers are able to view up to 2 years of historical data using web app at ruuvi.com/station (requires Ruuvi Gateway router)."; -"reading_history_x" = "Bluetooth sync: %0.f"; +"reading_history_x" = "Bluetooth sync: %.0f"; "rssi_alert_description" = "Using this alert requires you to be signed in to the app, and that you have claimed the ownership of this sensor and it's in the range of Ruuvi Gateway router. iOS devices are unable to indicate signal strength information of received data sent by Ruuvi sensor when sensor is paired and measurements are being received in the background. Realtime Bluetooth signal strength is shown in the app but doesn't affect this alert."; "bluetooth_download" = "Bluetooth download"; "bluetooth_download_description" = "Local sensor data can be downloaded, when you're within its Bluetooth range."; diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/sv.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/sv.lproj/Localizable.strings index b9779e4e8..a6979e528 100644 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/sv.lproj/Localizable.strings +++ b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/sv.lproj/Localizable.strings @@ -241,7 +241,7 @@ Om du inte kan se språkalternativet i inställningarna, se till att du har lagt "LocalNotificationsManager.HighTemperature.title" = "För hög temperatur!"; "LocalNotificationsManager.LowTemperature.title" = "För låg temperatur!"; "TagSettings.Alerts.Off" = "Av"; -"TagSettings.Alerts.Temperature.description" = "Alarmera när mindre än %0.f eller mer än %0.f"; +"TagSettings.Alerts.Temperature.description" = "Alarmera när mindre än %.0f eller mer än %.0f"; "TagSettings.Label.alerts.text" = "Alarm"; "TagSettings.backgroundImageLabel.text" = "Bakgrundsbild"; "TagSettings.batteryVoltageTitleLabel.text" = "Batterispänning"; @@ -559,8 +559,8 @@ RuuviTag-sensorn är redo att användas!"; "TagSettings.Alert.SetHumidity.title" = "Ställ in fuktighetsalarm"; "TagSettings.Alert.SetPressure.title" = "Ställ in lufttryckssalarm"; "TagSettings.Alert.SetRSSI.title" = "Ställ in signalstyrkealarm"; -"TagSettings.AlertSettings.Dialog.Min" = "Min (%0.f)"; -"TagSettings.AlertSettings.Dialog.Max" = "Max (%0.f)"; +"TagSettings.AlertSettings.Dialog.Min" = "Min (%.0f)"; +"TagSettings.AlertSettings.Dialog.Max" = "Max (%.0f)"; "export_history" = "Exportera historik (csv)"; "clear_view" = "Töm historikvy"; "day_1" = "1 dag"; @@ -573,12 +573,12 @@ RuuviTag-sensorn är redo att användas!"; "day_8" = "8 dagar"; "day_9" = "9 dagar"; "day_10" = "10 dagar"; -"day_x" = "%0.f dagar"; +"day_x" = "%.0f dagar"; "more" = "Mer..."; "all" = "Allt"; "longer_history_title" = "Längre historik"; "longer_history_message" = "Ruuvi Station mobilapp stöder högst 10 dagars historik. Ruuvi Cloud-prenumeranter kan se upp till 2 års historisk data med hjälp av webbappen på ruuvi.com/station (kräver Ruuvi Gateway-router)."; -"reading_history_x" = "Läser Bluetooth: %0.f"; +"reading_history_x" = "Läser Bluetooth: %.0f"; "rssi_alert_description" = "För att använda denna avisering måste du vara inloggad i appen, att du har tagit ägandeskap av den här sensorn och att den är inom räckhåll för Ruuvi Gateway-routern. IOS-enheter kan inte visa signalstyrka för mottagna data som skickas av Ruuvi-sensorn när sensorn är parat och mätningar mottas i bakgrunden. Realtids Bluetooth-signalstyrka visas i appen men påverkar inte denna avisering."; "bluetooth_download" = "Bluetooth-nedladdning"; "bluetooth_download_description" = "Lokal sensordata kan laddas ner när du är inom Bluetooth-räckvidd."; diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift b/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift index b8a4daaad..343dbe3ee 100644 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift +++ b/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift @@ -180,8 +180,10 @@ public enum RuuviLocalization { public static let day8 = RuuviLocalization.tr("Localizable", "day_8", fallback: "8 days") /// 9 days public static let day9 = RuuviLocalization.tr("Localizable", "day_9", fallback: "9 days") - /// %0.f days - public static let dayX = RuuviLocalization.tr("Localizable", "day_x", fallback: "%0.f days") + /// %.0f days + public static func dayX(_ p1: Float) -> String { + return RuuviLocalization.tr("Localizable", "day_x", p1, fallback: "%.0f days") + } /// dBm public static let dBm = RuuviLocalization.tr("Localizable", "dBm", fallback: "dBm") /// Are you sure? @@ -349,8 +351,10 @@ public enum RuuviLocalization { public static let openSensorView = RuuviLocalization.tr("Localizable", "open_sensor_view", fallback: "Open sensor view") /// Owner's Ruuvi Plan public static let ownersPlan = RuuviLocalization.tr("Localizable", "owners_plan", fallback: "Owner's Ruuvi Plan") - /// Reading Bluetooth: %0.f - public static let readingHistoryX = RuuviLocalization.tr("Localizable", "reading_history_x", fallback: "Reading Bluetooth: %0.f") + /// Reading Bluetooth: %.0f + public static func readingHistoryX(_ p1: Float) -> String { + return RuuviLocalization.tr("Localizable", "reading_history_x", p1, fallback: "Reading Bluetooth: %.0f") + } /// Remove public static let remove = RuuviLocalization.tr("Localizable", "Remove", fallback: "Remove") /// By removing the sensor, your sensor ownership status will be revoked and sensor settings, such as name, background image, calibration settings and alert settings will be removed. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner. @@ -1920,10 +1924,14 @@ public enum RuuviLocalization { } public enum AlertSettings { public enum Dialog { - /// Max (%0.f) - public static let max = RuuviLocalization.tr("Localizable", "TagSettings.AlertSettings.Dialog.Max", fallback: "Max (%0.f)") - /// Min (%0.f) - public static let min = RuuviLocalization.tr("Localizable", "TagSettings.AlertSettings.Dialog.Min", fallback: "Min (%0.f)") + /// Max (%.0f) + public static func max(_ p1: Float) -> String { + return RuuviLocalization.tr("Localizable", "TagSettings.AlertSettings.Dialog.Max", p1, fallback: "Max (%.0f)") + } + /// Min (%.0f) + public static func min(_ p1: Float) -> String { + return RuuviLocalization.tr("Localizable", "TagSettings.AlertSettings.Dialog.Min", p1, fallback: "Min (%.0f)") + } } } public enum Alerts { @@ -1956,8 +1964,10 @@ public enum RuuviLocalization { } } public enum Temperature { - /// Alert when less than %0.f or more than %0.f - public static let description = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Temperature.description", fallback: "Alert when less than %0.f or more than %0.f") + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + return RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Temperature.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } } } public enum AlertsAreDisabled { diff --git a/Common/RuuviLocalization/Templates/Localizable_de.strings.stencil b/Common/RuuviLocalization/Templates/Localizable_de.strings.stencil index b40417834..0355527d6 100644 --- a/Common/RuuviLocalization/Templates/Localizable_de.strings.stencil +++ b/Common/RuuviLocalization/Templates/Localizable_de.strings.stencil @@ -11,8 +11,8 @@ {% for item in document.data["translations"] %} {% if item["ident_ios"] != "" %} {% set localizeKey %}{{item["ident_ios"]}}{% endset %} - {% set defaultLocalizeValue %}{{item["en"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%0.f" | replace:"{%.0f^%2$s}","%0.f"}}{% endset %} - {% set localizeValue %}{{item["de"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%0.f" | replace:"{%.0f^%2$s}","%0.f"}}{% endset %} + {% set defaultLocalizeValue %}{{item["en"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%.0f" | replace:"{%.0f^%2$s}","%.0f"}}{% endset %} + {% set localizeValue %}{{item["de"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%.0f" | replace:"{%.0f^%2$s}","%.0f"}}{% endset %} {% if not localizeValue %} "{{localizeKey}}" = "{{defaultLocalizeValue}}"; {% else %} diff --git a/Common/RuuviLocalization/Templates/Localizable_en.strings.stencil b/Common/RuuviLocalization/Templates/Localizable_en.strings.stencil index e51ae7a95..c8407cc8d 100644 --- a/Common/RuuviLocalization/Templates/Localizable_en.strings.stencil +++ b/Common/RuuviLocalization/Templates/Localizable_en.strings.stencil @@ -11,7 +11,7 @@ {% for item in document.data["translations"] %} {% if item["ident_ios"] != "" %} {% set localizeKey %}{{item["ident_ios"]}}{% endset %} - {% set localizeValue %}{{item["en"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%0.f" | replace:"{%.0f^%2$s}","%0.f"}}{% endset %} + {% set localizeValue %}{{item["en"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%.0f" | replace:"{%.0f^%2$s}","%.0f"}}{% endset %} "{{localizeKey}}" = "{{localizeValue}}"; {% endif %} {% endfor %} diff --git a/Common/RuuviLocalization/Templates/Localizable_fi.strings.stencil b/Common/RuuviLocalization/Templates/Localizable_fi.strings.stencil index 4104c602b..da8a19f1f 100644 --- a/Common/RuuviLocalization/Templates/Localizable_fi.strings.stencil +++ b/Common/RuuviLocalization/Templates/Localizable_fi.strings.stencil @@ -11,8 +11,8 @@ {% for item in document.data["translations"] %} {% if item["ident_ios"] != "" %} {% set localizeKey %}{{item["ident_ios"]}}{% endset %} - {% set defaultLocalizeValue %}{{item["en"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%0.f" | replace:"{%.0f^%2$s}","%0.f"}}{% endset %} - {% set localizeValue %}{{item["fi"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%0.f" | replace:"{%.0f^%2$s}","%0.f"}}{% endset %} + {% set defaultLocalizeValue %}{{item["en"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%.0f" | replace:"{%.0f^%2$s}","%.0f"}}{% endset %} + {% set localizeValue %}{{item["fi"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%.0f" | replace:"{%.0f^%2$s}","%.0f"}}{% endset %} {% if not localizeValue %} "{{localizeKey}}" = "{{defaultLocalizeValue}}"; {% else %} diff --git a/Common/RuuviLocalization/Templates/Localizable_fr.strings.stencil b/Common/RuuviLocalization/Templates/Localizable_fr.strings.stencil index 4f96a692b..6a67d79e4 100644 --- a/Common/RuuviLocalization/Templates/Localizable_fr.strings.stencil +++ b/Common/RuuviLocalization/Templates/Localizable_fr.strings.stencil @@ -11,8 +11,8 @@ {% for item in document.data["translations"] %} {% if item["ident_ios"] != "" %} {% set localizeKey %}{{item["ident_ios"]}}{% endset %} - {% set defaultLocalizeValue %}{{item["en"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%0.f" | replace:"{%.0f^%2$s}","%0.f"}}{% endset %} - {% set localizeValue %}{{item["fr"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%0.f" | replace:"{%.0f^%2$s}","%0.f"}}{% endset %} + {% set defaultLocalizeValue %}{{item["en"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%.0f" | replace:"{%.0f^%2$s}","%.0f"}}{% endset %} + {% set localizeValue %}{{item["fr"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%.0f" | replace:"{%.0f^%2$s}","%.0f"}}{% endset %} {% if not localizeValue %} "{{localizeKey}}" = "{{defaultLocalizeValue}}"; {% else %} diff --git a/Common/RuuviLocalization/Templates/Localizable_ru.strings.stencil b/Common/RuuviLocalization/Templates/Localizable_ru.strings.stencil index e855d4d69..2f4e3d530 100644 --- a/Common/RuuviLocalization/Templates/Localizable_ru.strings.stencil +++ b/Common/RuuviLocalization/Templates/Localizable_ru.strings.stencil @@ -11,8 +11,8 @@ {% for item in document.data["translations"] %} {% if item["ident_ios"] != "" %} {% set localizeKey %}{{item["ident_ios"]}}{% endset %} - {% set defaultLocalizeValue %}{{item["en"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%0.f" | replace:"{%.0f^%2$s}","%0.f"}}{% endset %} - {% set localizeValue %}{{item["ru"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%0.f" | replace:"{%.0f^%2$s}","%0.f"}}{% endset %} + {% set defaultLocalizeValue %}{{item["en"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%.0f" | replace:"{%.0f^%2$s}","%.0f"}}{% endset %} + {% set localizeValue %}{{item["ru"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%.0f" | replace:"{%.0f^%2$s}","%.0f"}}{% endset %} {% if not localizeValue %} "{{localizeKey}}" = "{{defaultLocalizeValue}}"; {% else %} diff --git a/Common/RuuviLocalization/Templates/Localizable_sv.strings.stencil b/Common/RuuviLocalization/Templates/Localizable_sv.strings.stencil index 19a0e8584..c09184dc1 100644 --- a/Common/RuuviLocalization/Templates/Localizable_sv.strings.stencil +++ b/Common/RuuviLocalization/Templates/Localizable_sv.strings.stencil @@ -11,8 +11,8 @@ {% for item in document.data["translations"] %} {% if item["ident_ios"] != "" %} {% set localizeKey %}{{item["ident_ios"]}}{% endset %} - {% set defaultLocalizeValue %}{{item["en"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%0.f" | replace:"{%.0f^%2$s}","%0.f"}}{% endset %} - {% set localizeValue %}{{item["sv"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%0.f" | replace:"{%.0f^%2$s}","%0.f"}}{% endset %} + {% set defaultLocalizeValue %}{{item["en"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%.0f" | replace:"{%.0f^%2$s}","%.0f"}}{% endset %} + {% set localizeValue %}{{item["sv"]|replace:"{%@^%1$s}","%@"|replace:"{%.0f^%1$,d}","%.0f"|replace:"{%d^%1$,d}","%d"|replace:"{%d^%2$,d}","%d"|replace:"{%.0f^%2$,d}","%.0f"|replace:"{%.0f^%1$s}","%.0f" | replace:"{%.0f^%2$s}","%.0f"}}{% endset %} {% if not localizeValue %} "{{localizeKey}}" = "{{defaultLocalizeValue}}"; {% else %} diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift index d91669c98..bc0989ce2 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift @@ -84,13 +84,7 @@ class DiscoverPresenter: NSObject, RuuviDiscover { private var persistedReactorToken: RuuviReactorToken? private lazy var ruuviLogoImage = UIImage.named("ruuvi_logo", for: Self.self) private var isBluetoothPermissionGranted: Bool { - if #available(iOS 13.1, *) { - return CBCentralManager.authorization == .allowedAlways - } else if #available(iOS 13.0, *) { - return CBCentralManager().authorization == .allowedAlways - } - // Before iOS 13, Bluetooth permissions are not required - return true + CBCentralManager.authorization == .allowedAlways } deinit { @@ -201,9 +195,9 @@ extension DiscoverPresenter: DiscoverViewOutput { } // If tag is not added get the name from the mac and show other info. - if let addableTag = ruuviTags.first(where: { ruuviTag in + if ruuviTags.first(where: { ruuviTag in ruuviTag.mac == nfcSensor?.macId - }) { + }) != nil { guard let message = self.message( for: nfcSensor, displayName: displayName(for: nfcSensor) @@ -289,14 +283,14 @@ extension DiscoverPresenter: RuuviFirmwareOutput { extension DiscoverPresenter { private func startObservingPersistedRuuviSensors() { persistedReactorToken = ruuviReactor.observe { [weak self] change in + guard let self else { return } switch change { case let .initial(sensors): - guard let sSelf = self else { return } - self?.persistedSensors = sensors + persistedSensors = sensors case let .insert(sensor): - self?.persistedSensors.append(sensor) + persistedSensors.append(sensor) case let .delete(sensor): - self?.persistedSensors.removeAll(where: { $0.any == sensor }) + persistedSensors.removeAll(where: { $0.any == sensor }) default: return } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift index 48f757007..771e1956d 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift @@ -15,13 +15,7 @@ class DiscoverTableHeaderView: UIView { } private var isBluetoothPermissionGranted: Bool { - if #available(iOS 13.1, *) { - return CBCentralManager.authorization == .allowedAlways - } else if #available(iOS 13.0, *) { - return CBCentralManager().authorization == .allowedAlways - } - // Before iOS 13, Bluetooth permissions are not required - return true + CBCentralManager.authorization == .allowedAlways } private let addSensorDescriptionKey: String = "add_sensor_description" diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift index fea137aae..eb2e1900d 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift @@ -196,6 +196,7 @@ extension DiscoverTableViewController: DiscoverTableHeaderViewDelegate { extension DiscoverTableViewController { override func viewDidLoad() { super.viewDidLoad() + localize() configureViews() updateUI() output.viewDidLoad() diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Helpers.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Helpers.swift index 6da970867..69e15295a 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Helpers.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Helpers.swift @@ -5,8 +5,10 @@ import UIKit public extension UIAlertController { func setMessageAlignment(_ alignment: NSTextAlignment) { - let paragraphStyle = NSParagraphStyle.default.mutableCopy() as? NSMutableParagraphStyle - paragraphStyle?.alignment = alignment + guard let paragraphStyle = NSParagraphStyle.default.mutableCopy() as? NSMutableParagraphStyle else { + return + } + paragraphStyle.alignment = alignment let messageText = NSMutableAttributedString( string: message ?? "", diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift index d9b5e9dea..4db785010 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift @@ -263,8 +263,6 @@ extension RuuviOnboardViewController { cell?.delegate = self cell?.configure(with: viewModel) return cell - default: - return UICollectionViewCell() } } } diff --git a/Packages/RuuviAnalytics/Sources/RuuviAnalyticsImpl/RuuviAnalyticsImpl.swift b/Packages/RuuviAnalytics/Sources/RuuviAnalyticsImpl/RuuviAnalyticsImpl.swift index 13c765245..adf98a0d2 100644 --- a/Packages/RuuviAnalytics/Sources/RuuviAnalyticsImpl/RuuviAnalyticsImpl.swift +++ b/Packages/RuuviAnalytics/Sources/RuuviAnalyticsImpl/RuuviAnalyticsImpl.swift @@ -2,7 +2,6 @@ import Foundation #if canImport(FirebaseAnalytics) import FirebaseAnalytics #endif -import RuuviAnalytics import RuuviLocal import RuuviOntology import RuuviService diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/RuuviCloudApi.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/RuuviCloudApi.swift index 17eb27ef1..aa7000bca 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/RuuviCloudApi.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/RuuviCloudApi.swift @@ -1,7 +1,6 @@ import BTKit import Foundation import Future -import RuuviCloud import RuuviOntology /// https://docs.ruuvi.com/communication/ruuvi-network/backends/serverless/user-api diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/Upload/RuuviCloudApiSensorImageUploadRequest.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/Upload/RuuviCloudApiSensorImageUploadRequest.swift index af4aa7563..1648e36ac 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/Upload/RuuviCloudApiSensorImageUploadRequest.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/Upload/RuuviCloudApiSensorImageUploadRequest.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviCloud public struct RuuviCloudApiSensorImageUploadRequest: UserApiUploadRequest { public let sensor: String diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/Upload/UserApiUploadRequest.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/Upload/UserApiUploadRequest.swift index 49c46acac..8db984399 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/Upload/UserApiUploadRequest.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/Upload/UserApiUploadRequest.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviCloud public protocol UserApiUploadRequest: Codable { var sensor: String { get } diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiBaseResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiBaseResponse.swift index 3f2529581..79895942a 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiBaseResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiBaseResponse.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviCloud public struct RuuviCloudApiBaseResponse: Decodable where T: Decodable { enum Status: String, Decodable { diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiURLSession.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiURLSession.swift index b730de909..9855cf539 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiURLSession.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiURLSession.swift @@ -1,6 +1,5 @@ import Foundation import Future -import RuuviCloud // swiftlint:disable file_length diff --git a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift index 51b63009d..9166136d9 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudFactoryPure.swift @@ -1,10 +1,6 @@ import Foundation -import RuuviCloud import RuuviPool import RuuviUser -#if canImport(RuuviCloudApi) - import RuuviCloudApi -#endif public final class RuuviCloudFactoryPure: RuuviCloudFactory { public init() {} diff --git a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift index 11c94485f..7f289dc5c 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift @@ -2,13 +2,9 @@ import BTKit // swiftlint:disable file_length import Foundation import Future -import RuuviCloud import RuuviOntology import RuuviPool import RuuviUser -#if canImport(RuuviCloudApi) - import RuuviCloudApi -#endif // swiftlint:disable:next type_body_length public final class RuuviCloudPure: RuuviCloud { diff --git a/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextFactoryImpl.swift b/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextFactoryImpl.swift index 68f7bfa62..6dd330878 100644 --- a/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextFactoryImpl.swift +++ b/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextFactoryImpl.swift @@ -1,5 +1,3 @@ -import RuuviContext - public final class RealmContextFactoryImpl: RealmContextFactory { public init() {} diff --git a/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextImpl.swift b/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextImpl.swift index 6f99a116c..4dfa6f5c3 100644 --- a/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextImpl.swift +++ b/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextImpl.swift @@ -1,5 +1,4 @@ import RealmSwift -import RuuviContext class RealmContextImpl: RealmContext { var main: Realm = try! Realm() diff --git a/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextFactoryGRDB.swift b/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextFactoryGRDB.swift index 23adfad49..0506e7336 100644 --- a/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextFactoryGRDB.swift +++ b/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextFactoryGRDB.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviContext public final class SQLiteContextFactoryGRDB: SQLiteContextFactory { public init() {} diff --git a/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextGRDB.swift b/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextGRDB.swift index 864faed91..7fc1254c1 100644 --- a/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextGRDB.swift +++ b/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextGRDB.swift @@ -1,6 +1,5 @@ import Foundation import GRDB -import RuuviContext import RuuviOntology #if canImport(RuuviOntologySQLite) import RuuviOntologySQLite diff --git a/Packages/RuuviCore/Sources/RuuviCoreImage/RuuviCoreImageImpl.swift b/Packages/RuuviCore/Sources/RuuviCoreImage/RuuviCoreImageImpl.swift index 5bdb723c7..90f4efd13 100644 --- a/Packages/RuuviCore/Sources/RuuviCoreImage/RuuviCoreImageImpl.swift +++ b/Packages/RuuviCore/Sources/RuuviCoreImage/RuuviCoreImageImpl.swift @@ -1,7 +1,6 @@ import AVFoundation import CoreGraphics import Foundation -import RuuviCore import UIKit public final class RuuviCoreImageImpl: RuuviCoreImage { @@ -25,7 +24,7 @@ extension UIImage { let imageAspectRatio = self.size.width / self.size.height let canvasAspectRatio = size.width / size.height - var resizeFactor: CGFloat = if imageAspectRatio > canvasAspectRatio { + let resizeFactor: CGFloat = if imageAspectRatio > canvasAspectRatio { size.width / self.size.width } else { size.height / self.size.height diff --git a/Packages/RuuviCore/Sources/RuuviCoreLocation/RuuviCoreLocationImpl.swift b/Packages/RuuviCore/Sources/RuuviCoreLocation/RuuviCoreLocationImpl.swift index fe021f5e5..95ad4b49b 100644 --- a/Packages/RuuviCore/Sources/RuuviCoreLocation/RuuviCoreLocationImpl.swift +++ b/Packages/RuuviCore/Sources/RuuviCoreLocation/RuuviCoreLocationImpl.swift @@ -1,34 +1,32 @@ import CoreLocation import Foundation import Future -import RuuviCore public final class RuuviCoreLocationImpl: NSObject, RuuviCoreLocation { public var isLocationPermissionGranted: Bool { CLLocationManager.locationServicesEnabled() - && (CLLocationManager.authorizationStatus() == .authorizedWhenInUse - || CLLocationManager.authorizationStatus() == .authorizedAlways) + && (locationManager.authorizationStatus == .authorizedWhenInUse + || locationManager.authorizationStatus == .authorizedAlways) } public var locationAuthorizationStatus: CLAuthorizationStatus { - CLLocationManager.authorizationStatus() + locationManager.authorizationStatus } var isLocationPermissionDenied: Bool { !CLLocationManager.locationServicesEnabled() - || CLLocationManager.authorizationStatus() == .denied || CLLocationManager.authorizationStatus() == .denied + || locationManager.authorizationStatus == .denied || locationManager.authorizationStatus == .denied } var isLocationPermissionNotDetermined: Bool { - CLLocationManager.authorizationStatus() == .notDetermined + locationManager.authorizationStatus == .notDetermined } - private var locationManager: CLLocationManager + private let locationManager = CLLocationManager() private var requestLocationPermissionCallback: ((Bool) -> Void)? private var getCurrentLocationPromise: Promise? override public init() { - locationManager = CLLocationManager() super.init() locationManager.delegate = self locationManager.distanceFilter = 100 diff --git a/Packages/RuuviCore/Sources/RuuviCorePN/RuuviCorePNImpl.swift b/Packages/RuuviCore/Sources/RuuviCorePN/RuuviCorePNImpl.swift index 29ee43e9b..53b9b5197 100644 --- a/Packages/RuuviCore/Sources/RuuviCorePN/RuuviCorePNImpl.swift +++ b/Packages/RuuviCore/Sources/RuuviCorePN/RuuviCorePNImpl.swift @@ -1,4 +1,3 @@ -import RuuviCore import UIKit import UserNotifications diff --git a/Packages/RuuviCore/Sources/RuuviCorePermission/RuuviCorePermissionImpl.swift b/Packages/RuuviCore/Sources/RuuviCorePermission/RuuviCorePermissionImpl.swift index b22f45b5d..934ce2173 100644 --- a/Packages/RuuviCore/Sources/RuuviCorePermission/RuuviCorePermissionImpl.swift +++ b/Packages/RuuviCore/Sources/RuuviCorePermission/RuuviCorePermissionImpl.swift @@ -1,6 +1,5 @@ import Foundation import Photos -import RuuviCore public final class RuuviCorePermissionImpl: RuuviCorePermission { private let locationManager: RuuviCoreLocation diff --git a/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift b/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift index d2c5c9c11..04ac983ef 100644 --- a/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift +++ b/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift @@ -1,6 +1,5 @@ import Combine import Foundation -import RuuviDFU #if canImport(NordicDFU) import NordicDFU #endif diff --git a/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuScanner.swift b/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuScanner.swift index c8a722e7e..35a26636e 100644 --- a/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuScanner.swift +++ b/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuScanner.swift @@ -1,6 +1,5 @@ import CoreBluetooth import Foundation -import RuuviDFU import UIKit class DfuScanner: NSObject { diff --git a/Packages/RuuviDFU/Sources/RuuviDFUImpl/RuuviDFUImpl.swift b/Packages/RuuviDFU/Sources/RuuviDFUImpl/RuuviDFUImpl.swift index 27649a9eb..e7b62797b 100644 --- a/Packages/RuuviDFU/Sources/RuuviDFUImpl/RuuviDFUImpl.swift +++ b/Packages/RuuviDFU/Sources/RuuviDFUImpl/RuuviDFUImpl.swift @@ -1,6 +1,5 @@ import Combine import Foundation -import RuuviDFU #if canImport(NordicDFU) import NordicDFU #endif diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift index ab2a7b609..53bcfd410 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonBackground/BackgroundProcessServiceiOS13.swift @@ -1,10 +1,6 @@ import BackgroundTasks import Foundation import Future -import RuuviDaemon -#if canImport(RuuviDaemonOperation) - import RuuviDaemonOperation -#endif @available(iOS 13, *) public final class BackgroundProcessServiceiOS13: BackgroundProcessService { diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift index 72df85cfa..5f886f962 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonCloudSyncWorker.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviDaemon import RuuviLocal import RuuviService diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonFactoryCloudSync.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonFactoryCloudSync.swift index 3f2284c93..1bf992c24 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonFactoryCloudSync.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonCloudSync/RuuviDaemonFactoryCloudSync.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviDaemon import RuuviLocal import RuuviService diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/DataPruningOperationsManager.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/DataPruningOperationsManager.swift index 831c9657f..5f269a038 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/DataPruningOperationsManager.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonOperation/Data/DataPruningOperationsManager.swift @@ -1,6 +1,5 @@ import Foundation import Future -import RuuviDaemon import RuuviLocal import RuuviPool import RuuviStorage diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Advertisement/RuuviTagAdvertisementDaemonBTKit.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Advertisement/RuuviTagAdvertisementDaemonBTKit.swift index 5dc3f022d..b86567b16 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Advertisement/RuuviTagAdvertisementDaemonBTKit.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Advertisement/RuuviTagAdvertisementDaemonBTKit.swift @@ -1,6 +1,5 @@ import BTKit import Foundation -import RuuviDaemon import RuuviLocal import RuuviOntology import RuuviPersistence diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Heartbeat/RuuviTagHeartbeatDaemonBTKit.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Heartbeat/RuuviTagHeartbeatDaemonBTKit.swift index 8286fcfd9..e428e110a 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Heartbeat/RuuviTagHeartbeatDaemonBTKit.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Heartbeat/RuuviTagHeartbeatDaemonBTKit.swift @@ -1,6 +1,5 @@ import BTKit import Foundation -import RuuviDaemon import RuuviLocal import RuuviNotification import RuuviNotifier diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift index f9cc9e9cc..616cf6c35 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift @@ -1,6 +1,5 @@ import BTKit import Foundation -import RuuviDaemon import RuuviLocal import RuuviOntology import RuuviPersistence @@ -166,7 +165,7 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro .with(isOwner: true) ).on(success: { [weak self] _ in self?.realmPersistence.readAll(pair.device.uuid).on(success: { realmRecords in - var records = realmRecords.map { $0.with(macId: mac.mac) } + let records = realmRecords.map { $0.with(macId: mac.mac) } self?.sqiltePersistence.create(records).on(success: { _ in self?.realmPersistence.deleteAllRecords(pair.device.uuid).on(success: { _ in self?.idPersistence.set(mac: mac.mac, for: pair.device.uuid.luid) diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/Documents/ImagePersistenceDocuments.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/Documents/ImagePersistenceDocuments.swift index c663ac74b..685cc249c 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/Documents/ImagePersistenceDocuments.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/Documents/ImagePersistenceDocuments.swift @@ -1,5 +1,4 @@ import Future -import RuuviLocal import RuuviOntology import UIKit diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/ImagePersistence.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/ImagePersistence.swift index 905a38ced..883716398 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/ImagePersistence.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/Image/ImagePersistence.swift @@ -1,5 +1,4 @@ import Future -import RuuviLocal import RuuviOntology import UIKit diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/RuuviLocalImagesUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/RuuviLocalImagesUserDefaults.swift index eee3aa941..a22e1f794 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/RuuviLocalImagesUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/Background/RuuviLocalImagesUserDefaults.swift @@ -1,5 +1,4 @@ import Future -import RuuviLocal import RuuviOntology import UIKit @@ -65,7 +64,7 @@ final class RuuviLocalImagesUserDefaults: RuuviLocalImages { } func getOrGenerateBackground(for identifier: Identifier) -> UIImage? { - var id = backgroundId(for: identifier) + let id = backgroundId(for: identifier) if id >= bgMinIndex, id <= bgMaxIndex { return UIImage(named: "bg\(id)") } else { diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalConnectionsUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalConnectionsUserDefaults.swift index 4d065bb44..0edce2a06 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalConnectionsUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalConnectionsUserDefaults.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviLocal import RuuviOntology final class RuuviLocalConnectionsUserDefaults: RuuviLocalConnections { diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalFactoryUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalFactoryUserDefaults.swift index 44d87be76..20dd10d40 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalFactoryUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalFactoryUserDefaults.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviLocal public final class RuuviLocalFactoryUserDefaults: RuuviLocalFactory { public init() {} diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalIDsUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalIDsUserDefaults.swift index 80def07c8..3d593962c 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalIDsUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalIDsUserDefaults.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviLocal import RuuviOntology class RuuviLocalIDsUserDefaults: RuuviLocalIDs { diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift index 7b5e05aa3..920029844 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviLocal import RuuviOntology // swiftlint:disable type_body_length file_length diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSyncStateUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSyncStateUserDefaults.swift index 66eafaf15..c9587c207 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSyncStateUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSyncStateUserDefaults.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviLocal import RuuviOntology final class RuuviLocalSyncStateUserDefaults: RuuviLocalSyncState { diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/AlertService/MigrationManagerAlertService.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/AlertService/MigrationManagerAlertService.swift index 2f673895c..3e25ee94b 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/AlertService/MigrationManagerAlertService.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/AlertService/MigrationManagerAlertService.swift @@ -1,7 +1,6 @@ import AVKit import Foundation import RuuviContext -import RuuviMigration import RuuviOntology import RuuviService import RuuviStorage diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift index 613175356..56c22b539 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift @@ -1,6 +1,5 @@ import RuuviContext import RuuviLocal -import RuuviMigration import RuuviPool import RuuviService import RuuviStorage diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/SensorSettings/MigrationManagerSensorSettings.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/SensorSettings/MigrationManagerSensorSettings.swift index 13b49201e..916352c5c 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/SensorSettings/MigrationManagerSensorSettings.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/SensorSettings/MigrationManagerSensorSettings.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviMigration import RuuviService import RuuviStorage diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/fixRHAlerts/RuuviMigrationFixRHAlerts.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/fixRHAlerts/RuuviMigrationFixRHAlerts.swift index bd551d126..6f638c841 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/fixRHAlerts/RuuviMigrationFixRHAlerts.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/fixRHAlerts/RuuviMigrationFixRHAlerts.swift @@ -1,7 +1,6 @@ import Foundation import RuuviContext import RuuviLocal -import RuuviMigration import RuuviPool import RuuviService import RuuviStorage diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toChartDuration240/MigrationManagerToChartDuration240.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toChartDuration240/MigrationManagerToChartDuration240.swift index f449bc3ed..37391aba4 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toChartDuration240/MigrationManagerToChartDuration240.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toChartDuration240/MigrationManagerToChartDuration240.swift @@ -1,6 +1,5 @@ import Foundation import RuuviLocal -import RuuviMigration final class MigrationManagerToChartDuration240: RuuviMigration { private var settings: RuuviLocalSettings diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toNetworkPull60/MigrationManagerToNetworkPull60.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toNetworkPull60/MigrationManagerToNetworkPull60.swift index d7b156f9f..579cdb2e7 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toNetworkPull60/MigrationManagerToNetworkPull60.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toNetworkPull60/MigrationManagerToNetworkPull60.swift @@ -1,6 +1,5 @@ import Foundation import RuuviLocal -import RuuviMigration final class MigrationManagerToNetworkPull60: RuuviMigration { private var settings: RuuviLocalSettings diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toPrune240/MigrationManagerToPrune240.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toPrune240/MigrationManagerToPrune240.swift index a14495c33..08b6a61a4 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toPrune240/MigrationManagerToPrune240.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toPrune240/MigrationManagerToPrune240.swift @@ -1,6 +1,5 @@ import Foundation import RuuviLocal -import RuuviMigration final class MigrationManagerToPrune240: RuuviMigration { private var settings: RuuviLocalSettings diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toRH/MigrationManagerToRH.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toRH/MigrationManagerToRH.swift index 98e12af1a..67755eaa2 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toRH/MigrationManagerToRH.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toRH/MigrationManagerToRH.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviMigration import RuuviOntology import RuuviService import RuuviStorage diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift index d1b544ed3..0633be772 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift @@ -2,7 +2,6 @@ import Foundation import RealmSwift import RuuviContext import RuuviLocal -import RuuviMigration import RuuviOntology import RuuviPool #if canImport(RuuviOntologyRealm) diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toTimeouts/MigrationManagerToTimeouts.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toTimeouts/MigrationManagerToTimeouts.swift index 01bc26e7d..2be9edbb6 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toTimeouts/MigrationManagerToTimeouts.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toTimeouts/MigrationManagerToTimeouts.swift @@ -1,6 +1,5 @@ import Foundation import RuuviLocal -import RuuviMigration final class MigrationManagerToTimeouts: RuuviMigration { private var settings: RuuviLocalSettings diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift index ce94e097a..b386decfa 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift @@ -1,7 +1,6 @@ import Foundation import RealmSwift import RuuviLocal -import RuuviMigration import RuuviOntology #if canImport(RuuviOntologyRealm) import RuuviOntologyRealm diff --git a/Packages/RuuviNotification/Sources/RuuviNotificationLocal/RuuviNotificationLocalImpl.swift b/Packages/RuuviNotification/Sources/RuuviNotificationLocal/RuuviNotificationLocalImpl.swift index 6ba15a039..812af9a56 100644 --- a/Packages/RuuviNotification/Sources/RuuviNotificationLocal/RuuviNotificationLocalImpl.swift +++ b/Packages/RuuviNotification/Sources/RuuviNotificationLocal/RuuviNotificationLocalImpl.swift @@ -1,6 +1,5 @@ import Foundation import RuuviLocal -import RuuviNotification import RuuviOntology import RuuviService import RuuviStorage @@ -87,17 +86,12 @@ public final class RuuviNotificationLocalImpl: NSObject, RuuviNotificationLocal } private func id(for uuid: String) -> String { - var id: String = if let macId = idPersistence.mac(for: uuid.luid) { - macId.value - } else { - uuid - } - return id + idPersistence.mac(for: uuid.luid)?.value ?? uuid } public func showDidConnect(uuid: String, title: String) { var needsToShow: Bool - var cache: [String: Date] = connectAlerts + let cache: [String: Date] = connectAlerts if let shownDate = cache[uuid] { var intervalPassed = true @@ -145,7 +139,7 @@ public final class RuuviNotificationLocalImpl: NSObject, RuuviNotificationLocal public func showDidDisconnect(uuid: String, title: String) { var needsToShow: Bool - var cache: [String: Date] = disconnectAlerts + let cache: [String: Date] = disconnectAlerts if let shownDate = cache[uuid] { var intervalPassed = true @@ -193,7 +187,7 @@ public final class RuuviNotificationLocalImpl: NSObject, RuuviNotificationLocal public func notifyDidMove(for uuid: String, counter _: Int, title: String) { var needsToShow: Bool - var cache: [String: Date] = movementAlerts + let cache: [String: Date] = movementAlerts if let shownDate = cache[uuid] { var intervalPassed = true @@ -252,7 +246,7 @@ public extension RuuviNotificationLocalImpl { title: String ) { var needsToShow: Bool - var cache: [String: Date] = switch reason { + let cache: [String: Date] = switch reason { case .low: switch type { case .temperature: @@ -512,7 +506,7 @@ extension RuuviNotificationLocalImpl: UNUserNotificationCenterDelegate { willPresent _: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void ) { - completionHandler([.alert, .badge, .sound]) + completionHandler([.banner, .list, .badge, .sound]) } // swiftlint:disable:next function_body_length diff --git a/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl+Process.swift b/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl+Process.swift index 517a18726..d51b48d19 100644 --- a/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl+Process.swift +++ b/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl+Process.swift @@ -1,13 +1,12 @@ // swiftlint:disable file_length import Foundation -import RuuviNotifier import RuuviOntology // MARK: - Process Physical Sensors public extension RuuviNotifierImpl { // swiftlint:disable:next function_body_length - func process(record record: RuuviTagSensorRecord, trigger: Bool) { + func process(record: RuuviTagSensorRecord, trigger: Bool) { guard let luid = record.luid, ruuviAlertService.hasRegistrations(for: record) else { diff --git a/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl.swift b/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl.swift index 39ca726eb..4db8a67eb 100644 --- a/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl.swift +++ b/Packages/RuuviNotifier/Sources/RuuviNotifierImpl/RuuviNotifierImpl.swift @@ -1,7 +1,6 @@ import Foundation import RuuviLocal import RuuviNotification -import RuuviNotifier import RuuviOntology import RuuviService diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+Extension.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+Extension.swift index 5b10e20ed..d229c82ef 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+Extension.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+Extension.swift @@ -1,7 +1,6 @@ import Foundation import Humidity import RealmSwift -import RuuviOntology public extension RuuviTagDataRealm { var unitTemperature: Temperature? { diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+RuuviTagSensorRecord.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+RuuviTagSensorRecord.swift index 26b124928..ac97c2c9d 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+RuuviTagSensorRecord.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+RuuviTagSensorRecord.swift @@ -1,6 +1,5 @@ import Foundation import RealmSwift -import RuuviOntology public extension RuuviTagDataRealm { var any: AnyRuuviTagSensorRecord? { diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm.swift index 2d28b0027..a40a1e6d0 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm.swift @@ -1,7 +1,6 @@ import BTKit import Foundation import RealmSwift -import RuuviOntology public final class RuuviTagDataRealm: Object { @objc public dynamic var ruuviTag: RuuviTagRealm? diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+Extension.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+Extension.swift index b60d3354b..02e38a3d6 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+Extension.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+Extension.swift @@ -1,7 +1,6 @@ import Foundation import Humidity import RealmSwift -import RuuviOntology public extension RuuviTagLatestDataRealm { var unitTemperature: Temperature? { diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+RuuviTagSensorRecord.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+RuuviTagSensorRecord.swift index 8696a7b79..0ef08ad04 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+RuuviTagSensorRecord.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+RuuviTagSensorRecord.swift @@ -1,6 +1,5 @@ import Foundation import RealmSwift -import RuuviOntology public extension RuuviTagLatestDataRealm { var any: AnyRuuviTagSensorRecord? { diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm.swift index 032471c19..6df825b7b 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm.swift @@ -1,7 +1,6 @@ import BTKit import Foundation import RealmSwift -import RuuviOntology public final class RuuviTagLatestDataRealm: Object { @objc public dynamic var uuid: String = "" diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm+RuuviTagSensor.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm+RuuviTagSensor.swift index 6625335f1..114fdade2 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm+RuuviTagSensor.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm+RuuviTagSensor.swift @@ -1,6 +1,5 @@ import Foundation import RealmSwift -import RuuviOntology extension RuuviTagRealm: RuuviTagSensor { public var luid: LocalIdentifier? { diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm.swift index b5d959f0a..be4652124 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm.swift @@ -1,7 +1,6 @@ import BTKit import Foundation import RealmSwift -import RuuviOntology public final class RuuviTagRealm: Object, RuuviTagRealmProtocol { @objc public dynamic var uuid: String = "" diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealmProtocol.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealmProtocol.swift index 85c9db4ee..6656954ff 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealmProtocol.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealmProtocol.swift @@ -1,6 +1,5 @@ import Foundation import RealmSwift -import RuuviOntology public protocol RuuviTagRealmProtocol: Object { var uuid: String { get set } diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/SensorSettingsRealm.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/SensorSettingsRealm.swift index d288ce9fc..090afd652 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/SensorSettingsRealm.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/SensorSettingsRealm.swift @@ -1,6 +1,5 @@ import Foundation import RealmSwift -import RuuviOntology public class SensorSettingsRealm: Object { @objc public dynamic var luid: String? diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviCloudQueuedRequestSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviCloudQueuedRequestSQLite.swift index c70b8fc07..cef188ac3 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviCloudQueuedRequestSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviCloudQueuedRequestSQLite.swift @@ -1,6 +1,5 @@ import Foundation import GRDB -import RuuviOntology public struct RuuviCloudQueuedRequestSQLite: RuuviCloudQueuedRequest { public var id: Int64? diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagDataSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagDataSQLite.swift index 5dabf2e64..b7c4c181a 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagDataSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagDataSQLite.swift @@ -1,7 +1,6 @@ import Foundation import GRDB import Humidity -import RuuviOntology public struct RuuviTagDataSQLite: RuuviTagSensorRecord { public var luid: LocalIdentifier? diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagLatestDataSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagLatestDataSQLite.swift index 9ab62c1f9..6e5b89f42 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagLatestDataSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagLatestDataSQLite.swift @@ -1,7 +1,6 @@ import Foundation import GRDB import Humidity -import RuuviOntology public struct RuuviTagLatestDataSQLite: RuuviTagSensorRecord { public var id: String diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSQLite.swift index 053f727e8..0bba62ac2 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSQLite.swift @@ -1,6 +1,5 @@ import Foundation import GRDB -import RuuviOntology public struct RuuviTagSQLite: RuuviTagSensor { public var id: String diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSensorRecord+RuuviTagDataSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSensorRecord+RuuviTagDataSQLite.swift index 101b32791..17ca93aaa 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSensorRecord+RuuviTagDataSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSensorRecord+RuuviTagDataSQLite.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviOntology public extension RuuviTagSensorRecord { var sqlite: RuuviTagDataSQLite { diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/SensorSettingsSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/SensorSettingsSQLite.swift index d6c099b8e..1043b905c 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/SensorSettingsSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/SensorSettingsSQLite.swift @@ -1,6 +1,5 @@ import Foundation import GRDB -import RuuviOntology public struct SensorSettingsSQLite: SensorSettings { public var luid: LocalIdentifier? diff --git a/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift b/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift index cfec0c094..1f49b26b7 100644 --- a/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift +++ b/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift @@ -5,7 +5,6 @@ import Future import RealmSwift import RuuviContext import RuuviOntology -import RuuviPersistence #if canImport(FirebaseCrashlytics) // TODO: @rinat eliminate import FirebaseCrashlytics #endif diff --git a/Packages/RuuviPersistence/Sources/RuuviPersistenceSQLite/RuuviPersistenceSQLite.swift b/Packages/RuuviPersistence/Sources/RuuviPersistenceSQLite/RuuviPersistenceSQLite.swift index 6da3727f2..6aad4eaac 100644 --- a/Packages/RuuviPersistence/Sources/RuuviPersistenceSQLite/RuuviPersistenceSQLite.swift +++ b/Packages/RuuviPersistence/Sources/RuuviPersistenceSQLite/RuuviPersistenceSQLite.swift @@ -5,7 +5,6 @@ import Future import GRDB import RuuviContext import RuuviOntology -import RuuviPersistence #if canImport(FirebaseCrashlytics) import FirebaseCrashlytics #endif diff --git a/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolCoordinator.swift b/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolCoordinator.swift index f30a8a47d..ed66fc45d 100644 --- a/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolCoordinator.swift +++ b/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolCoordinator.swift @@ -3,7 +3,6 @@ import Future import RuuviLocal import RuuviOntology import RuuviPersistence -import RuuviPool // swiftlint:disable:next type_body_length final class RuuviPoolCoordinator: RuuviPool { diff --git a/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolFactoryCoordinator.swift b/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolFactoryCoordinator.swift index 6d627bca5..61e316c53 100644 --- a/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolFactoryCoordinator.swift +++ b/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolFactoryCoordinator.swift @@ -1,7 +1,6 @@ import Foundation import RuuviLocal import RuuviPersistence -import RuuviPool public final class RuuviPoolFactoryCoordinator: RuuviPoolFactory { public init() {} diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorFactoryImpl.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorFactoryImpl.swift index 3887ce40e..cfa55b8f2 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorFactoryImpl.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorFactoryImpl.swift @@ -1,7 +1,6 @@ import Foundation import RuuviContext import RuuviPersistence -import RuuviReactor public final class RuuviReactorFactoryImpl: RuuviReactorFactory { public init() {} diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift index 693cd7f0b..0df62d43a 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift @@ -4,7 +4,6 @@ import GRDB import RuuviContext import RuuviOntology import RuuviPersistence -import RuuviReactor #if canImport(RuuviOntologyRealm) import RuuviOntologyRealm #endif diff --git a/Packages/RuuviRepository/Sources/RuuviRepositoryCoordinator/RuuviRepositoryCoordinator.swift b/Packages/RuuviRepository/Sources/RuuviRepositoryCoordinator/RuuviRepositoryCoordinator.swift index 4111e0b94..5c4e67238 100644 --- a/Packages/RuuviRepository/Sources/RuuviRepositoryCoordinator/RuuviRepositoryCoordinator.swift +++ b/Packages/RuuviRepository/Sources/RuuviRepositoryCoordinator/RuuviRepositoryCoordinator.swift @@ -2,7 +2,6 @@ import Foundation import Future import RuuviOntology import RuuviPool -import RuuviRepository import RuuviStorage final class RuuviRepositoryCoordinator: RuuviRepository { diff --git a/Packages/RuuviRepository/Sources/RuuviRepositoryCoordinator/RuuviRepositoryFactoryCoordinator.swift b/Packages/RuuviRepository/Sources/RuuviRepositoryCoordinator/RuuviRepositoryFactoryCoordinator.swift index ae7382e58..bb5808d76 100644 --- a/Packages/RuuviRepository/Sources/RuuviRepositoryCoordinator/RuuviRepositoryFactoryCoordinator.swift +++ b/Packages/RuuviRepository/Sources/RuuviRepositoryCoordinator/RuuviRepositoryFactoryCoordinator.swift @@ -1,6 +1,5 @@ import Foundation import RuuviPool -import RuuviRepository import RuuviStorage public final class RuuviRepositoryFactoryCoordinator: RuuviRepositoryFactory { diff --git a/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/AlertPersistenceUserDefaults.swift b/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/AlertPersistenceUserDefaults.swift index 91ab2c1d7..4cb0a114f 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/AlertPersistenceUserDefaults.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/AlertPersistenceUserDefaults.swift @@ -273,31 +273,31 @@ class AlertPersistenceUserDefaults: AlertPersistence { func remove(type: AlertType, for uuid: String) { switch type { - case let .temperature(lower, upper): + case .temperature: prefs.removeObject(forKey: temperatureAlertIsOnUDKeyPrefix + uuid) prefs.removeObject(forKey: temperatureLowerBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: temperatureUpperBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: temperatureAlertIsTriggeredUDKeyPrefix + uuid) prefs.removeObject(forKey: temperatureAlertTriggeredAtUDKeyPrefix + uuid) - case let .relativeHumidity(lower, upper): + case .relativeHumidity: prefs.removeObject(forKey: relativeHumidityAlertIsOnUDKeyPrefix + uuid) prefs.removeObject(forKey: relativeHumidityLowerBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: relativeHumidityUpperBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: relativeHumidityAlertIsTriggeredUDKeyPrefix + uuid) prefs.removeObject(forKey: relativeHumidityAlertTriggeredAtUDKeyPrefix + uuid) - case let .humidity(lower, upper): + case .humidity: prefs.removeObject(forKey: humidityAlertIsOnUDKeyPrefix + uuid) prefs.removeObject(forKey: humidityLowerBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: humidityUpperBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: humidityAlertIsTriggeredUDKeyPrefix + uuid) prefs.removeObject(forKey: humidityAlertTriggeredAtUDKeyPrefix + uuid) - case let .pressure(lower, upper): + case .pressure: prefs.removeObject(forKey: pressureAlertIsOnUDKeyPrefix + uuid) prefs.removeObject(forKey: pressureLowerBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: pressureUpperBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: pressureAlertIsTriggeredUDKeyPrefix + uuid) prefs.removeObject(forKey: pressureAlertTriggeredAtUDKeyPrefix + uuid) - case let .signal(lower, upper): + case .signal: prefs.removeObject(forKey: signalAlertIsOnUDKeyPrefix + uuid) prefs.removeObject(forKey: signalLowerBoundUDKeyPrefix + uuid) prefs.removeObject(forKey: signalUpperBoundUDKeyPrefix + uuid) @@ -305,12 +305,12 @@ class AlertPersistenceUserDefaults: AlertPersistence { prefs.removeObject(forKey: signalAlertTriggeredAtUDKeyPrefix + uuid) case .connection: prefs.removeObject(forKey: connectionAlertIsOnUDKeyPrefix + uuid) - case let .cloudConnection(unseenDuration): + case .cloudConnection: prefs.removeObject(forKey: cloudConnectionAlertIsOnUDKeyPrefix + uuid) prefs.removeObject(forKey: cloudConnectionAlertUnseenDurationUDPrefix + uuid) prefs.removeObject(forKey: cloudConnectionAlertIsTriggeredUDKeyPrefix + uuid) prefs.removeObject(forKey: cloudConnectionAlertTriggeredAtUDKeyPrefix + uuid) - case let .movement(last): + case .movement: prefs.removeObject(forKey: movementAlertIsOnUDKeyPrefix + uuid) prefs.removeObject(forKey: movementAlertCounterUDPrefix + uuid) prefs.removeObject(forKey: movementAlertIsTriggeredUDKeyPrefix + uuid) diff --git a/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/KeyedArchiver.swift b/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/KeyedArchiver.swift index 0706b7031..0f068ad20 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/KeyedArchiver.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAlert/AlertPersistence/UserDefaults/KeyedArchiver.swift @@ -2,18 +2,12 @@ import Foundation enum KeyedArchiver { static func archive(object: Any) -> Data? { - if #available(iOS 12.0, *) { - try? NSKeyedArchiver.archivedData(withRootObject: object, requiringSecureCoding: false) - } else { - NSKeyedArchiver.archivedData(withRootObject: object) - } + try? NSKeyedArchiver.archivedData(withRootObject: object, requiringSecureCoding: false) } static func unarchive(_ data: Data, with _: T.Type) -> T? { - if #available(iOS 12.0, *) { - return try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? T - } else { - return NSKeyedUnarchiver.unarchiveObject(with: data) as? T - } + let unarchiver = try? NSKeyedUnarchiver(forReadingFrom: data) + unarchiver?.requiresSecureCoding = false + return unarchiver?.decodeObject(forKey: NSKeyedArchiveRootObjectKey) as? T } } diff --git a/Packages/RuuviService/Sources/RuuviServiceAlert/RuuviServiceAlertImpl.swift b/Packages/RuuviService/Sources/RuuviServiceAlert/RuuviServiceAlertImpl.swift index 27816b780..bb9f40101 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAlert/RuuviServiceAlertImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAlert/RuuviServiceAlertImpl.swift @@ -4,7 +4,6 @@ import Future import RuuviCloud import RuuviLocal import RuuviOntology -import RuuviService // MARK: - RuuviTag @@ -1285,7 +1284,7 @@ public extension RuuviServiceAlertImpl { } func signalDescription(for uuid: String) -> String? { - signalDescription(for: uuid) + alertPersistence.signalDescription(for: uuid) } } diff --git a/Packages/RuuviService/Sources/RuuviServiceAppSettings/RuuviServiceAppSettingsImpl.swift b/Packages/RuuviService/Sources/RuuviServiceAppSettings/RuuviServiceAppSettingsImpl.swift index e339fa5c6..cb99c0ce4 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAppSettings/RuuviServiceAppSettingsImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAppSettings/RuuviServiceAppSettingsImpl.swift @@ -3,7 +3,6 @@ import Future import RuuviCloud import RuuviLocal import RuuviOntology -import RuuviService public final class RuuviServiceAppSettingsImpl: RuuviServiceAppSettings { private let cloud: RuuviCloud diff --git a/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift b/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift index a39e2d810..5725beb93 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift @@ -3,7 +3,6 @@ import Future import RuuviLocal import RuuviOntology import RuuviPool -import RuuviService import RuuviStorage import RuuviUser diff --git a/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift b/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift index 64f7498cf..8aa448d15 100644 --- a/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift @@ -5,7 +5,6 @@ import RuuviCore import RuuviLocal import RuuviOntology import RuuviPool -import RuuviService import RuuviStorage import RuuviUser #if canImport(RuuviCloudApi) diff --git a/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift b/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift index 56e3db61f..43660f93b 100644 --- a/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift @@ -5,7 +5,6 @@ import RuuviLocal import RuuviOntology import RuuviPool import RuuviRepository -import RuuviService import RuuviStorage import UIKit // swiftlint:disable file_length @@ -216,7 +215,7 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { switch error { case let .ruuviCloud(cloudError): switch cloudError { - case let .api(.unauthorized): + case .api(.unauthorized): self?.postNotification() default: break } diff --git a/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncRecordsOperation.swift b/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncRecordsOperation.swift index 8c38942eb..612bba4ed 100644 --- a/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncRecordsOperation.swift +++ b/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncRecordsOperation.swift @@ -3,7 +3,6 @@ import RuuviCloud import RuuviLocal import RuuviOntology import RuuviRepository -import RuuviService final class RuuviServiceCloudSyncRecordsOperation: AsyncOperation { var sensor: RuuviTagSensor diff --git a/Packages/RuuviService/Sources/RuuviServiceExport/RuuviServiceExportImpl.swift b/Packages/RuuviService/Sources/RuuviServiceExport/RuuviServiceExportImpl.swift index 1c38d94e8..ef23add29 100644 --- a/Packages/RuuviService/Sources/RuuviServiceExport/RuuviServiceExportImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceExport/RuuviServiceExportImpl.swift @@ -3,7 +3,6 @@ import Future import Humidity import RuuviLocal import RuuviOntology -import RuuviService import RuuviStorage public final class RuuviServiceExportImpl: RuuviServiceExport { @@ -113,7 +112,7 @@ extension RuuviServiceExportImpl { pressure = toString(p, format: "%.2f") } - var rssi: String = if let rssiValue = log.rssi { + let rssi: String = if let rssiValue = log.rssi { "\(rssiValue)" } else { self.emptyValueString @@ -131,13 +130,13 @@ extension RuuviServiceExportImpl { self.emptyValueString } - var measurementSequenceNumber: String = if let msn = log.measurementSequenceNumber { + let measurementSequenceNumber: String = if let msn = log.measurementSequenceNumber { "\(msn)" } else { self.emptyValueString } - var txPower: String = if let tx = log.txPower { + let txPower: String = if let tx = log.txPower { "\(tx)" } else { self.emptyValueString diff --git a/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift b/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift index 122e273d8..fb77e0d8d 100644 --- a/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift +++ b/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift @@ -4,7 +4,6 @@ import RuuviCore import RuuviLocal import RuuviPool import RuuviRepository -import RuuviService import RuuviStorage import RuuviUser #if canImport(RuuviServiceCloudSync) diff --git a/Packages/RuuviService/Sources/RuuviServiceGATT/Operations/RuuviTagReadLogsOperation.swift b/Packages/RuuviService/Sources/RuuviServiceGATT/Operations/RuuviTagReadLogsOperation.swift index 690819818..b75b039da 100644 --- a/Packages/RuuviService/Sources/RuuviServiceGATT/Operations/RuuviTagReadLogsOperation.swift +++ b/Packages/RuuviService/Sources/RuuviServiceGATT/Operations/RuuviTagReadLogsOperation.swift @@ -2,7 +2,6 @@ import BTKit import Foundation import RuuviOntology import RuuviPool -import RuuviService final class RuuviTagReadLogsOperation: AsyncOperation { var uuid: String diff --git a/Packages/RuuviService/Sources/RuuviServiceGATT/Queue/GATTServiceQueue.swift b/Packages/RuuviService/Sources/RuuviServiceGATT/Queue/GATTServiceQueue.swift index 7f7613e91..f3ebe4918 100644 --- a/Packages/RuuviService/Sources/RuuviServiceGATT/Queue/GATTServiceQueue.swift +++ b/Packages/RuuviService/Sources/RuuviServiceGATT/Queue/GATTServiceQueue.swift @@ -3,7 +3,6 @@ import Foundation import Future import RuuviOntology import RuuviPool -import RuuviService public final class GATTServiceQueue: GATTService { private let ruuviPool: RuuviPool diff --git a/Packages/RuuviService/Sources/RuuviServiceMeasurement/RuuviServiceMeasurementImpl.swift b/Packages/RuuviService/Sources/RuuviServiceMeasurement/RuuviServiceMeasurementImpl.swift index f3ca5f90f..7a7ef3b92 100644 --- a/Packages/RuuviService/Sources/RuuviServiceMeasurement/RuuviServiceMeasurementImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceMeasurement/RuuviServiceMeasurementImpl.swift @@ -3,7 +3,6 @@ import Foundation import Humidity import RuuviLocal import RuuviOntology -import RuuviService // TODO: - @priyonto - Improve the number formatter instances. public final class RuuviServiceMeasurementImpl: NSObject { var settings: RuuviLocalSettings { diff --git a/Packages/RuuviService/Sources/RuuviServiceOffsetCalibration/RuuviServiceAppOffsetCalibrationImpl.swift b/Packages/RuuviService/Sources/RuuviServiceOffsetCalibration/RuuviServiceAppOffsetCalibrationImpl.swift index e69151f42..20a5d2455 100644 --- a/Packages/RuuviService/Sources/RuuviServiceOffsetCalibration/RuuviServiceAppOffsetCalibrationImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceOffsetCalibration/RuuviServiceAppOffsetCalibrationImpl.swift @@ -3,7 +3,6 @@ import Future import RuuviCloud import RuuviOntology import RuuviPool -import RuuviService public final class RuuviServiceAppOffsetCalibrationImpl: RuuviServiceOffsetCalibration { private let cloud: RuuviCloud diff --git a/Packages/RuuviService/Sources/RuuviServiceOwnership/RuuviServiceOwnershipImpl.swift b/Packages/RuuviService/Sources/RuuviServiceOwnership/RuuviServiceOwnershipImpl.swift index d8f4c1af7..5f9df21a0 100644 --- a/Packages/RuuviService/Sources/RuuviServiceOwnership/RuuviServiceOwnershipImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceOwnership/RuuviServiceOwnershipImpl.swift @@ -4,7 +4,6 @@ import RuuviCloud import RuuviLocal import RuuviOntology import RuuviPool -import RuuviService import RuuviStorage import RuuviUser diff --git a/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift b/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift index 6d81ebb6f..cd0d8d615 100644 --- a/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift @@ -5,7 +5,6 @@ import RuuviCore import RuuviLocal import RuuviOntology import RuuviPool -import RuuviService import UIKit public final class RuuviServiceSensorPropertiesImpl: RuuviServiceSensorProperties { diff --git a/Packages/RuuviService/Sources/RuuviServiceSensorRecords/RuuviServiceSensorRecordsImpl.swift b/Packages/RuuviService/Sources/RuuviServiceSensorRecords/RuuviServiceSensorRecordsImpl.swift index 046c3ec41..e02ddc6e7 100644 --- a/Packages/RuuviService/Sources/RuuviServiceSensorRecords/RuuviServiceSensorRecordsImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceSensorRecords/RuuviServiceSensorRecordsImpl.swift @@ -3,7 +3,6 @@ import Future import RuuviLocal import RuuviOntology import RuuviPool -import RuuviService public final class RuuviServiceSensorRecordsImpl: RuuviServiceSensorRecords { private let pool: RuuviPool diff --git a/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageCoordinator.swift b/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageCoordinator.swift index c70c22645..62a9d441e 100644 --- a/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageCoordinator.swift +++ b/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageCoordinator.swift @@ -2,7 +2,6 @@ import Foundation import Future import RuuviOntology import RuuviPersistence -import RuuviStorage final class RuuviStorageCoordinator: RuuviStorage { private let sqlite: RuuviPersistence diff --git a/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageFactoryCoordinator.swift b/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageFactoryCoordinator.swift index 467af6a59..c141fcb6e 100644 --- a/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageFactoryCoordinator.swift +++ b/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageFactoryCoordinator.swift @@ -1,6 +1,5 @@ import Foundation import RuuviPersistence -import RuuviStorage public final class RuuviStorageFactoryCoordinator: RuuviStorageFactory { public init() {} diff --git a/Packages/RuuviUser/Sources/RuuviUserCoordinator/RuuviUserCoordinator.swift b/Packages/RuuviUser/Sources/RuuviUserCoordinator/RuuviUserCoordinator.swift index 4f1801831..5c2a71ded 100644 --- a/Packages/RuuviUser/Sources/RuuviUserCoordinator/RuuviUserCoordinator.swift +++ b/Packages/RuuviUser/Sources/RuuviUserCoordinator/RuuviUserCoordinator.swift @@ -1,5 +1,4 @@ import Foundation -import RuuviUser import WidgetKit final class RuuviUserCoordinator: RuuviUser { diff --git a/Packages/RuuviUser/Sources/RuuviUserCoordinator/RuuviUserFactoryCoordinator.swift b/Packages/RuuviUser/Sources/RuuviUserCoordinator/RuuviUserFactoryCoordinator.swift index 086a7d6b5..fc7b26792 100644 --- a/Packages/RuuviUser/Sources/RuuviUserCoordinator/RuuviUserFactoryCoordinator.swift +++ b/Packages/RuuviUser/Sources/RuuviUserCoordinator/RuuviUserFactoryCoordinator.swift @@ -1,6 +1,3 @@ -import Foundation -import RuuviUser - public final class RuuviUserFactoryCoordinator: RuuviUserFactory { public init() {} diff --git a/intents_frameworks.yml b/intents_frameworks.yml index 158d18292..070846e13 100644 --- a/intents_frameworks.yml +++ b/intents_frameworks.yml @@ -26,6 +26,7 @@ targets: PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.intents" Debug: CODE_SIGN_STYLE: Automatic + OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries Release: EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" CODE_SIGN_IDENTITY: "iPhone Distribution" diff --git a/pnservice.yml b/pnservice.yml index d6db014fc..cac393f9b 100644 --- a/pnservice.yml +++ b/pnservice.yml @@ -22,6 +22,7 @@ targets: PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.pnservice" Debug: CODE_SIGN_STYLE: Automatic + OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries Release: EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" CODE_SIGN_IDENTITY: "iPhone Distribution" diff --git a/project_frameworks.yml b/project_frameworks.yml index 98ba56094..ce06fe8e3 100644 --- a/project_frameworks.yml +++ b/project_frameworks.yml @@ -55,6 +55,9 @@ targetTemplates: CFBundleShortVersionString: "$(MARKETING_VERSION)" CFBundleVersion: $(CURRENT_PROJECT_VERSION) MERGEABLE_LIBRARY: true + configs: + Debug: + OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries Module: name: "${target_name}" type: framework @@ -88,6 +91,9 @@ targetTemplates: CFBundleShortVersionString: "$(MARKETING_VERSION)" CFBundleVersion: $(CURRENT_PROJECT_VERSION) MERGEABLE_LIBRARY: true + configs: + Debug: + OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries CommonFramework: name: "${target_name}" type: framework @@ -121,6 +127,9 @@ targetTemplates: CFBundleShortVersionString: "$(MARKETING_VERSION)" CFBundleVersion: $(CURRENT_PROJECT_VERSION) MERGEABLE_LIBRARY: true + configs: + Debug: + OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries packages: BTKit: @@ -296,6 +305,7 @@ targets: PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station" Debug: CODE_SIGN_STYLE: Automatic + OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries Release: EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" CODE_SIGN_IDENTITY: "iPhone Distribution" diff --git a/station/Classes/Presentation/Modules/About/View/AboutViewController.swift b/station/Classes/Presentation/Modules/About/View/AboutViewController.swift index fb3155b27..303ce0a26 100644 --- a/station/Classes/Presentation/Modules/About/View/AboutViewController.swift +++ b/station/Classes/Presentation/Modules/About/View/AboutViewController.swift @@ -41,6 +41,7 @@ extension AboutViewController { super.viewDidLoad() configureViews() setUpChangelogTapGesture() + localize() output.viewDidLoad() } diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift index 43907f7f4..0252a1d75 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift @@ -55,6 +55,7 @@ extension BackgroundSelectionViewController { super.viewDidLoad() setUpUI() bindViewModel() + localize() output.viewDidLoad() } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift index 6b8f85731..06211dc1a 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift @@ -1305,7 +1305,7 @@ extension CardsPresenter { for uuid: String, viewModel: CardsViewModel ) { - var observable: Observable = switch type { + let observable: Observable = switch type { case .temperature: viewModel.temperatureAlertMutedTill case .relativeHumidity: @@ -1334,7 +1334,7 @@ extension CardsPresenter { for uuid: String, viewModel: CardsViewModel ) { - var observable: Observable = switch type { + let observable: Observable = switch type { case .temperature: viewModel.isTemperatureAlertOn case .relativeHumidity: diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift index 621143818..9143b34d5 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift @@ -210,6 +210,7 @@ extension CardsViewController { super.viewDidLoad() setUpUI() configureGestureViews() + localize() output.viewDidLoad() } diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift index b790267c2..a5c5c06d0 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift @@ -846,7 +846,7 @@ extension TagChartsViewPresenter { var value: Double? switch type { case .temperature: - var temp: Temperature? + let temp: Temperature? // Backword compatibility for the users who used earlier versions than 0.7.7 // 1: If local record has temperature offset added, calculate and get original temp data // 2: Apply current sensor settings @@ -859,7 +859,7 @@ extension TagChartsViewPresenter { } value = measurementService.double(for: temp) ?? 0 case .humidity: - var humidity: Humidity? + let humidity: Humidity? // Backword compatibility for the users who used earlier versions than 0.7.7 // 1: If local record has humidity offset added, calculate and get original humidity data // 2: Apply current sensor settings @@ -876,7 +876,7 @@ extension TagChartsViewPresenter { isDecimal: false ) case .pressure: - var pressure: Pressure? + let pressure: Pressure? // Backword compatibility for the users who used earlier versions than 0.7.7 // 1: If local record has pressure offset added, calculate and get original pressure data // 2: Apply current sensor settings diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift index dfcb29db0..7c5be0f38 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift @@ -44,6 +44,7 @@ class TagChartsView: LineChartView { delegate = self addSubviews() configure() + localize() } @available(*, unavailable) diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift index 9d21ccd2c..b67a3bac8 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift @@ -194,6 +194,7 @@ class TagChartsViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() setUpUI() + localize() output.viewDidLoad() } @@ -797,7 +798,7 @@ extension TagChartsViewController: TagChartsViewInput { syncStatusLabel.text = RuuviLocalization.TagCharts.Status.serving case let .reading(points): let format = RuuviLocalization.readingHistoryX - syncStatusLabel.text = String(format: format, Float(points)) + syncStatusLabel.text = format(Float(points)) case .disconnecting: syncStatusLabel.text = RuuviLocalization.TagCharts.Status.disconnecting case .success: @@ -1240,7 +1241,7 @@ private extension Int { case 10: RuuviLocalization.day10 default: - String(format: RuuviLocalization.dayX, self) + RuuviLocalization.dayX(Float(self)) // TOOD: @rinat check } } } diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift index 1ae69ce52..417c29cf7 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift @@ -1746,7 +1746,7 @@ extension DashboardPresenter { for uuid: String, viewModel: CardsViewModel ) { - var observable: Observable = switch type { + let observable: Observable = switch type { case .temperature: viewModel.temperatureAlertMutedTill case .relativeHumidity: @@ -1776,7 +1776,7 @@ extension DashboardPresenter { for uuid: String, viewModel: CardsViewModel ) { - var observable: Observable = switch type { + let observable: Observable = switch type { case .temperature: viewModel.isTemperatureAlertOn case .relativeHumidity: diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift index 54b170355..a920b3106 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift @@ -169,6 +169,7 @@ extension DashboardViewController { super.viewDidLoad() setUpUI() configureRestartAnimationsOnAppDidBecomeActive() + localize() output.viewDidLoad() } diff --git a/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift b/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift index 8e6fcec53..1a8763fdb 100644 --- a/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift +++ b/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift @@ -36,6 +36,11 @@ extension MenuTableEmbededViewController { // MARK: - View lifecycle extension MenuTableEmbededViewController { + override func viewDidLoad() { + super.viewDidLoad() + localize() + } + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) output.viewWillAppear() diff --git a/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift b/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift index 6af673f20..9dd7a466d 100644 --- a/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift +++ b/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift @@ -20,6 +20,7 @@ class MyRuuviAccountViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() configureViews() + localize() output.viewDidLoad() } diff --git a/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift index ed372aa76..42187f16b 100644 --- a/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift @@ -124,6 +124,7 @@ extension SettingsTableViewController { super.viewDidLoad() updateNavBarTitleFont() updateUI() + localize() output.viewDidLoad() becomeFirstResponder() } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift index b7d0df9dd..c53442d60 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift @@ -28,6 +28,7 @@ extension ASSelectionTableViewController { override func viewDidLoad() { super.viewDidLoad() setUpUI() + localize() output.viewDidLoad() } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift index 5428b946a..3c7882c9a 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift @@ -28,6 +28,7 @@ extension AppearanceSettingsTableViewController { override func viewDidLoad() { super.viewDidLoad() setUpUI() + localize() output.viewDidLoad() } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift index c87c73e10..d9926f2b8 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift @@ -53,6 +53,7 @@ extension DefaultsViewController { override func viewDidLoad() { super.viewDidLoad() configureViews() + localize() } override func shouldPerformSegue(withIdentifier identifier: String, sender _: Any?) -> Bool { diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift index 68f217505..310337645 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift @@ -29,7 +29,12 @@ extension DefaultsTableViewController: DefaultsViewInput { // MARK: - View lifecycle -extension DefaultsTableViewController {} +extension DefaultsTableViewController { + override func viewDidLoad() { + super.viewDidLoad() + localize() + } +} // MARK: - UITableViewDataSource diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift index 45be1de76..67c160e24 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift @@ -27,6 +27,7 @@ extension DevicesTableViewController { override func viewDidLoad() { super.viewDidLoad() setUpTableView() + localize() output.viewDidLoad() } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift index b13649bb9..7d4fa1dad 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift @@ -41,6 +41,7 @@ extension HeartbeatViewController { override func viewDidLoad() { super.viewDidLoad() configureViews() + localize() } override func shouldPerformSegue(withIdentifier identifier: String, sender _: Any?) -> Bool { diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift index 842b78e95..4aad330ad 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift @@ -52,6 +52,7 @@ extension HeartbeatTableViewController { super.viewDidLoad() bindViewModel() updateUIComponent() + localize() } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift index 76f5a24e8..b7ada4f69 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift @@ -38,6 +38,7 @@ extension PushAlertSoundSelectionTableViewController { override func viewDidLoad() { super.viewDidLoad() setUpUI() + localize() output.viewDidLoad() } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift index dac9c4d8d..300c701e3 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift @@ -30,6 +30,7 @@ extension NotificationsSettingsTableViewController { override func viewDidLoad() { super.viewDidLoad() setUpUI() + localize() output?.viewDidLoad() } } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift index 912edbcd0..99188f8c1 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift @@ -28,6 +28,7 @@ extension RuuviCloudTableViewController { override func viewDidLoad() { super.viewDidLoad() setUpUI() + localize() output.viewDidLoad() } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift index 45c4cb226..3e7bcbd6b 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift @@ -48,6 +48,7 @@ extension SelectionTableViewController: SelectionViewInput { extension SelectionTableViewController { override func viewDidLoad() { super.viewDidLoad() + localize() output.viewDidLoad() updateUI() } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift index 6c5d8b809..ece0c480b 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift @@ -67,6 +67,7 @@ extension UnitSettingsTableViewController: UnitSettingsViewInput { extension UnitSettingsTableViewController { override func viewDidLoad() { super.viewDidLoad() + localize() output.viewDidLoad() updateUI() } diff --git a/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift b/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift index 066df855c..ee90bde01 100644 --- a/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift +++ b/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift @@ -52,6 +52,7 @@ class ShareViewController: UITableViewController { super.viewDidLoad() configureTableView() setupCustomBackButton() + localize() output.viewDidLoad() } diff --git a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift b/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift index 73be92e39..14911f47f 100644 --- a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift +++ b/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift @@ -109,6 +109,7 @@ extension SignInBenefitsViewController { override func viewDidLoad() { super.viewDidLoad() setUpUI() + localize() } override func viewWillAppear(_ animated: Bool) { diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift b/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift index 1c968c348..776b8f150 100644 --- a/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift +++ b/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift @@ -74,6 +74,7 @@ extension SignInViewController { override func viewDidLoad() { super.viewDidLoad() setUpUI() + localize() output.viewDidLoad() } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift index 7c936fca1..44d9d3b19 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift @@ -120,6 +120,7 @@ extension SensorForceClaimViewController { override func viewDidLoad() { super.viewDidLoad() setUpUI() + localize() output?.viewDidLoad() } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift index 7034efe01..e52e2a165 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift @@ -49,7 +49,7 @@ class OffsetCorrectionAppleViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - + localize() timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { [weak self] _ in if let updateAt = self?.updatedAt { self?.originalValueUpdateTimeLabel.text = "(\(updateAt.ruuviAgo()))" diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift index 73b2d24ae..a9009d4d8 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift @@ -59,6 +59,7 @@ final class OwnerViewController: UIViewController { super.viewDidLoad() setUpCustomBackButton() setUpCloudHistoryContentView() + localize() output.viewDidTriggerFirmwareUpdateDialog() } } diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift index 309441752..12514a7c4 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift @@ -80,6 +80,7 @@ extension SensorRemovalViewController { override func viewDidLoad() { super.viewDidLoad() setUpUI() + localize() output?.viewDidLoad() } } diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift index 3495f9b38..c836927c9 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift @@ -396,6 +396,7 @@ class TagSettingsViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() setUpUI() + localize() output.viewDidLoad() } @@ -1865,42 +1866,15 @@ extension TagSettingsViewController { max: CGFloat? = nil ) -> NSMutableAttributedString? { guard isViewLoaded else { return nil } - var format = RuuviLocalization.TagSettings.Alerts.Temperature.description + let format = RuuviLocalization.TagSettings.Alerts.Temperature.description if let min, let max { - return attributedString(from: String( - format: format, - locale: Locale.autoupdatingCurrent, - min, - max - )) + return attributedString(from: format(Float(min), Float(max))) } if let tu = viewModel?.temperatureUnit.value?.unitTemperature, let l = viewModel?.temperatureLowerBound.value?.converted(to: tu), let u = viewModel?.temperatureUpperBound.value?.converted(to: tu) { - if l.value.decimalPoint > 0 { - let decimalPointToConsider = l.value.decimalPoint > 2 ? 2 : l.value.decimalPoint - format = format.replacingFirstOccurrence( - of: "%0.f", - with: "%0.\(decimalPointToConsider)f" - ) - } - - if u.value.decimalPoint > 0 { - let decimalPointToConsider = u.value.decimalPoint > 2 ? 2 : u.value.decimalPoint - format = format.replacingLastOccurrence( - of: "%0.f", - with: "%0.\(decimalPointToConsider)f" - ) - } - - let message = String( - format: format, - locale: Locale.autoupdatingCurrent, - l.value.round(to: 2), - u.value.round(to: 2) - ) - return attributedString(from: message) + return attributedString(from: format(Float(l.value.round(to: 2)), Float(u.value.round(to: 2)))) } else { return nil } @@ -1948,31 +1922,15 @@ extension TagSettingsViewController { max: CGFloat? = nil ) -> NSMutableAttributedString? { guard isViewLoaded else { return nil } - var format = RuuviLocalization.TagSettings.Alerts.Temperature.description + let format = RuuviLocalization.TagSettings.Alerts.Temperature.description if let min, let max { - return attributedString(from: String( - format: format, - locale: Locale.autoupdatingCurrent, - min, - max - )) + return attributedString(from: format(Float(min), Float(max))) } if let l = viewModel?.relativeHumidityLowerBound.value, let u = viewModel?.relativeHumidityUpperBound.value { - if l.decimalPoint > 0 { - let decimalPointToConsider = l.decimalPoint > 2 ? 2 : l.decimalPoint - format = format.replacingFirstOccurrence(of: "%0.f", with: "%0.\(decimalPointToConsider)f") - } - - if u.decimalPoint > 0 { - let decimalPointToConsider = u.decimalPoint > 2 ? 2 : u.decimalPoint - format = format.replacingLastOccurrence(of: "%0.f", with: "%0.\(decimalPointToConsider)f") - } - let message = String( - format: format, - locale: Locale.autoupdatingCurrent, - l.round(to: 2), - u.round(to: 2) + let message = format( + Float(l.round(to: 2)), + Float(u.round(to: 2)) ) return attributedString(from: message) } else { @@ -2014,15 +1972,12 @@ extension TagSettingsViewController { maxValue: CGFloat? = nil ) -> NSMutableAttributedString? { guard isViewLoaded else { return nil } - var format = RuuviLocalization.TagSettings.Alerts.Temperature.description + let format = RuuviLocalization.TagSettings.Alerts.Temperature.description if let minValue, let maxValue { - return attributedString(from: String( - format: format, - locale: Locale.autoupdatingCurrent, - minValue, - maxValue - )) + return attributedString( + from: format(Float(minValue), Float(maxValue)) + ) } if let pu = viewModel?.pressureUnit.value, @@ -2036,20 +1991,9 @@ extension TagSettingsViewController { min(upper, pu.alertRange.upperBound), pu.alertRange.lowerBound ) - if l.decimalPoint > 0 { - let decimalPointToConsider = l.decimalPoint > 2 ? 2 : l.decimalPoint - format = format.replacingFirstOccurrence(of: "%0.f", with: "%0.\(decimalPointToConsider)f") - } - - if u.decimalPoint > 0 { - let decimalPointToConsider = u.decimalPoint > 2 ? 2 : u.decimalPoint - format = format.replacingLastOccurrence(of: "%0.f", with: "%0.\(decimalPointToConsider)f") - } - let message = String( - format: format, - locale: Locale.autoupdatingCurrent, - l.round(to: 2), - u.round(to: 2) + let message = format( + Float(l.round(to: 2)), + Float(u.round(to: 2)) ) return attributedString(from: message) } else { @@ -2110,21 +2054,16 @@ extension TagSettingsViewController { let format = RuuviLocalization.TagSettings.Alerts.Temperature.description if let min, let max { - return attributedString(from: String( - format: format, - locale: Locale.autoupdatingCurrent, - min, - max - )) + return attributedString( + from: format(Float(min), Float(max)) + ) } if let lower = viewModel?.signalLowerBound.value, let upper = viewModel?.signalUpperBound.value { - let message = String( - format: format, - locale: Locale.autoupdatingCurrent, - lower, - upper + let message = format( + Float(lower), + Float(upper) ) return attributedString(from: message) } else { @@ -3788,10 +3727,8 @@ extension TagSettingsViewController { guard let self else { return } alertTextField.delegate = self let format = RuuviLocalization.TagSettings.AlertSettings.Dialog.min - alertTextField.placeholder = String( - format: format, - locale: Locale.autoupdatingCurrent, - minimumBound + alertTextField.placeholder = format( + Float(minimumBound) ) alertTextField.keyboardType = .decimalPad alertMinRangeTextField = alertTextField @@ -3807,10 +3744,8 @@ extension TagSettingsViewController { guard let self else { return } alertTextField.delegate = self let format = RuuviLocalization.TagSettings.AlertSettings.Dialog.max - alertTextField.placeholder = String( - format: format, - locale: Locale.autoupdatingCurrent, - maximumBound + alertTextField.placeholder = format( + Float(maximumBound) ) alertTextField.keyboardType = .decimalPad alertMaxRangeTextField = alertTextField diff --git a/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift b/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift index 72fb9272e..0bac89215 100644 --- a/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift +++ b/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift @@ -9,19 +9,11 @@ class AlertPresenterImpl: AlertPresenter { preferredStyle: viewModel.style ) viewModel.actions.forEach { alert.addAction($0) } - let group = DispatchGroup() DispatchQueue.main.async { - group.enter() - let topViewController = UIApplication.shared.topViewController() - group.leave() - group.notify(queue: .main) { - DispatchQueue.main.async { - let feedback = UINotificationFeedbackGenerator() - feedback.notificationOccurred(.error) - feedback.prepare() - UIApplication.shared.topViewController()?.present(alert, animated: true) - } - } + let feedback = UINotificationFeedbackGenerator() + feedback.notificationOccurred(.error) + feedback.prepare() + UIApplication.shared.topViewController()?.present(alert, animated: true) } } } diff --git a/widget_frameworks.yml b/widget_frameworks.yml index fd1f025cd..90f9a2a4b 100644 --- a/widget_frameworks.yml +++ b/widget_frameworks.yml @@ -22,6 +22,7 @@ targets: PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.widgets" Debug: CODE_SIGN_STYLE: Automatic + OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries Release: CODE_SIGN_IDENTITY: "iPhone Distribution" PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.widgets" From 568caad31ab4c594b5f40d109e8c331375e7b25f Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Sun, 10 Dec 2023 20:54:32 +0100 Subject: [PATCH 34/84] fix: Update localised string identifiers #1714 --- ruuvi-widgets/RuuviWidgets.swift | 3 ++- ruuvi-widgets/View/EmptyWidgetView.swift | 11 ++++++----- ruuvi-widgets/View/UnauthorizedView.swift | 7 ++++--- widget_frameworks.yml | 2 ++ widget_spm.yml | 3 ++- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/ruuvi-widgets/RuuviWidgets.swift b/ruuvi-widgets/RuuviWidgets.swift index d6e788670..03637ff32 100644 --- a/ruuvi-widgets/RuuviWidgets.swift +++ b/ruuvi-widgets/RuuviWidgets.swift @@ -1,6 +1,7 @@ import Intents import SwiftUI import WidgetKit +import RuuviLocalization struct RuuviWidgetEntryView: View { @Environment(\.widgetFamily) private var family @@ -59,7 +60,7 @@ struct RuuviWidgets: Widget { RuuviWidgetEntryView(entry: entry) .environment(\.locale, viewModel.locale()) }.configurationDisplayName(Constants.simpleWidgetDisplayName.rawValue) - .description(LocalizedStringKey("Widgets.Description.message")) + .description(RuuviLocalization.Widgets.Description.message) .supportedFamilies(supportedFamilies) .contentMarginsDisabledIfAvailable() } diff --git a/ruuvi-widgets/View/EmptyWidgetView.swift b/ruuvi-widgets/View/EmptyWidgetView.swift index b743ba514..8cadd6e4f 100644 --- a/ruuvi-widgets/View/EmptyWidgetView.swift +++ b/ruuvi-widgets/View/EmptyWidgetView.swift @@ -1,13 +1,14 @@ import SwiftUI +import RuuviLocalization struct EmptyWidgetView: View { @Environment(\.widgetFamily) private var family struct Texts { - let messageSimple = "Widgets.Unconfigured.Simple.message" - let messageRectangular = "Widgets.Unconfigured.Rectangular.message" - let messageCircular = "Widgets.Unconfigured.Circular.message" - let messageInline = "Widgets.Unconfigured.Inline.message" - let loading = "Widgets.Loading.message" + let messageSimple = RuuviLocalization.Widgets.Unconfigured.Simple.message + let messageRectangular = RuuviLocalization.Widgets.Unconfigured.Rectangular.message + let messageCircular = RuuviLocalization.Widgets.Unconfigured.Circular.message + let messageInline = RuuviLocalization.Widgets.Unconfigured.Inline.message + let loading = RuuviLocalization.Widgets.Loading.message } private let texts = Texts() diff --git a/ruuvi-widgets/View/UnauthorizedView.swift b/ruuvi-widgets/View/UnauthorizedView.swift index 22efcdb89..39196d661 100644 --- a/ruuvi-widgets/View/UnauthorizedView.swift +++ b/ruuvi-widgets/View/UnauthorizedView.swift @@ -1,11 +1,12 @@ import SwiftUI +import RuuviLocalization struct UnauthorizedView: View { @Environment(\.widgetFamily) private var family struct Texts { - let unauthorizedRegular = "Widgets.Unauthorized.Regular.message" - let unauthorizedSmall = "SignIn.Title.text" - let unauthorizedInline = "Widgets.Unauthorized.Inline.message" + let unauthorizedRegular = RuuviLocalization.Widgets.Unauthorized.Regular.message + let unauthorizedSmall = RuuviLocalization.SignIn.Title.text + let unauthorizedInline = RuuviLocalization.Widgets.Unauthorized.Inline.message } private let texts = Texts() diff --git a/widget_frameworks.yml b/widget_frameworks.yml index 90f9a2a4b..86c6f773d 100644 --- a/widget_frameworks.yml +++ b/widget_frameworks.yml @@ -54,4 +54,6 @@ targets: - target: RuuviPersistence embed: true - target: RuuviContext + embed: true + - target: RuuviLocalization embed: true \ No newline at end of file diff --git a/widget_spm.yml b/widget_spm.yml index e0ce7d15a..ea6235e2e 100644 --- a/widget_spm.yml +++ b/widget_spm.yml @@ -52,4 +52,5 @@ targets: - package: RuuviPool - package: RuuviLocal - package: RuuviPersistence - - package: RuuviContext \ No newline at end of file + - package: RuuviContext + - package: RuuviLocalization \ No newline at end of file From 4cd7399e6ae1bbbd076370d1a23d644553d018f4 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sun, 10 Dec 2023 23:30:56 +0200 Subject: [PATCH 35/84] Implements SwiftLint as post compile step (#1764) * Install swiftlint to .tools subdirectory from Make command Implements installing swiftlint from make command * fix swiftlint warnings * fix last warmning flatMap * newline at the end * return in localization --- .swiftformat | 1 - .swiftlint.yml | 3 + .../RuuviLocalization/RuuviLocalization.swift | 5623 +++++++++-------- .../Templates/structured-swift5.stencil | 104 + .../Util/RuuviBundleUtils.swift | 8 +- Makefile | 13 +- .../RuuviDiscover/Util/RuuviBundleUtils.swift | 8 +- .../VMP/View/DiscoverViewInput.swift | 1 + .../Table/DiscoverTableViewController.swift | 4 + .../RuuviFirmware/FirmwareInteractor.swift | 4 +- .../RuuviFirmware/SwiftUI/FirmwareView.swift | 12 +- .../SwiftUI/FirmwareViewModel.swift | 4 + .../RuuviFirmware/Util/RuuviBundleUtils.swift | 8 +- .../Pages/RuuviOnboardViewController.swift | 2 - .../Pages/Util/RuuviBundleUtils.swift | 8 +- .../URLSession/RuuviCloudApiURLSession.swift | 11 +- .../ThirdParty/URLQueryItemEncoder.swift | 20 +- .../RuuviTagAdvertisementDaemonBTKit.swift | 2 +- .../RuuviTagPropertiesDaemonBTKit.swift | 1 + .../RuuviLocalConnectionsUserDefaults.swift | 1 + .../RuuviLocalSettingsUserDefaults.swift | 3 - .../toVIPER/MigrationManagerToVIPER.swift | 1 + .../RuuviServiceCloudSyncImpl.swift | 2 +- pnservice/NotificationService.swift | 3 - project_frameworks.yml | 5 + scripts/build/lint.sh | 7 + scripts/install/install_swiftlint.sh | 42 + .../BackgroundSelectionViewController.swift | 1 + .../Cards/Presenter/CardsPresenter.swift | 8 +- .../Presenter/TagChartsViewPresenter.swift | 1 + .../Home/Presenter/DashboardPresenter.swift | 11 +- .../Home/View/DashboardImageCell.swift | 4 +- .../ChartSettingsStepperTableViewCell.swift | 4 +- .../Presenter/DefaultsPresenter.swift | 6 +- .../UnitSettingsTableViewController.swift | 2 +- .../Share/Presenter/SharePresenter.swift | 3 - .../SignIn/View/UI/SignInViewController.swift | 6 +- .../Submodules/DFU/View/DFUViewModel.swift | 3 +- .../View/UI/TagSettingsAlertConfigCell.swift | 3 + .../View/UI/TagSettingsViewController.swift | 10 +- .../Services/Alert/AlertServiceSpec.swift | 52 +- .../MeasurementsServiceEnSpec.swift | 2 + .../MeasurementsServiceFiSpec.swift | 2 + .../MeasurementsServiceRuSpec.swift | 2 + .../MeasurementsServiceSvSpec.swift | 2 + swiftgen.yml | 16 +- 46 files changed, 3353 insertions(+), 2686 deletions(-) create mode 100644 Common/RuuviLocalization/Templates/structured-swift5.stencil create mode 100644 scripts/build/lint.sh create mode 100755 scripts/install/install_swiftlint.sh diff --git a/.swiftformat b/.swiftformat index 0b95d9516..a845437d0 100644 --- a/.swiftformat +++ b/.swiftformat @@ -1,5 +1,4 @@ --swiftversion 5.9 ---exclude ./Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift --disable wrapMultilineStatementBraces,trailingCommas --xcodeindentation enabled --wraparguments before-first \ No newline at end of file diff --git a/.swiftlint.yml b/.swiftlint.yml index af0e8101b..f5b353ed2 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -9,3 +9,6 @@ excluded: - Pods disabled_rules: - closure_parameter_position + - identifier_name + - force_try + - todo diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift b/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift index 343dbe3ee..ed5342077 100644 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift +++ b/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift @@ -10,2649 +10,3032 @@ import Foundation // swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length // swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces public enum RuuviLocalization { - /// Operation failed. - public static let activityFailedGeneric = RuuviLocalization.tr("Localizable", "activity_failed_generic", fallback: "Operation failed.") - /// Please wait... - public static let activityOngoingGeneric = RuuviLocalization.tr("Localizable", "activity_ongoing_generic", fallback: "Please wait...") - /// Couldn't save changes to cloud. - public static let activitySavingFail = RuuviLocalization.tr("Localizable", "activity_saving_fail", fallback: "Couldn't save changes to cloud.") - /// Saved successfully. - public static let activitySavingSuccess = RuuviLocalization.tr("Localizable", "activity_saving_success", fallback: "Saved successfully.") - /// Saving to cloud...please wait. - public static let activitySavingToCloud = RuuviLocalization.tr("Localizable", "activity_saving_to_cloud", fallback: "Saving to cloud...please wait.") - /// Operation successful. - public static let activitySuccessGeneric = RuuviLocalization.tr("Localizable", "activity_success_generic", fallback: "Operation successful.") - /// Add a Sensor - public static let addASensor = RuuviLocalization.tr("Localizable", "add_a_sensor", fallback: "Add a Sensor") - /// Add Sensor - public static let addSensor = RuuviLocalization.tr("Localizable", "add_sensor", fallback: "Add Sensor") - /// This page shows nearby Ruuvi sensors not yet added to the app. Tap a sensor to add it. - public static let addSensorDescription = RuuviLocalization.tr("Localizable", "add_sensor_description", fallback: "This page shows nearby Ruuvi sensors not yet added to the app. Tap a sensor to add it.") - /// This sensor cannot be added with NFC due to old firmware. Please add the sensor with Bluetooth and update firmware. - public static let addSensorNfcDf3Error = RuuviLocalization.tr("Localizable", "add_sensor_nfc_df3_error", fallback: "This sensor cannot be added with NFC due to old firmware. Please add the sensor with Bluetooth and update firmware.") - /// Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone. - public static let addSensorViaNfc = RuuviLocalization.tr("Localizable", "add_sensor_via_nfc", fallback: "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone.") - /// Add with NFC - public static let addWithNfc = RuuviLocalization.tr("Localizable", "add_with_nfc", fallback: "Add with NFC") - /// ago - public static let ago = RuuviLocalization.tr("Localizable", "ago", fallback: "ago") - /// Alert if sensor data hasn't been updated to the cloud for longer than %d minutes. - public static func alertCloudConnectionDescription(_ p1: Int) -> String { - return RuuviLocalization.tr("Localizable", "alert_cloud_connection_description", p1, fallback: "Alert if sensor data hasn't been updated to the cloud for longer than %d minutes.") - } - /// Enter the desired delay to be used in minutes before alert is triggered. Minimum value is 2 minutes. - public static let alertCloudConnectionDialogDescription = RuuviLocalization.tr("Localizable", "alert_cloud_connection_dialog_description", fallback: "Enter the desired delay to be used in minutes before alert is triggered. Minimum value is 2 minutes.") - /// Set cloud connection alert - public static let alertCloudConnectionDialogTitle = RuuviLocalization.tr("Localizable", "alert_cloud_connection_dialog_title", fallback: "Set cloud connection alert") - /// Cloud Connection - public static let alertCloudConnectionTitle = RuuviLocalization.tr("Localizable", "alert_cloud_connection_title", fallback: "Cloud Connection") - /// Air Humidity is above %@ - public static func alertNotificationHumidityHighThreshold(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "alert_notification_humidity_high_threshold", String(describing: p1), fallback: "Air Humidity is above %@") - } - /// Air Humidity is below %@ - public static func alertNotificationHumidityLowThreshold(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "alert_notification_humidity_low_threshold", String(describing: p1), fallback: "Air Humidity is below %@") - } - /// Air Pressure is above %@ - public static func alertNotificationPressureHighThreshold(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "alert_notification_pressure_high_threshold", String(describing: p1), fallback: "Air Pressure is above %@") - } - /// Air Pressure is below %@ - public static func alertNotificationPressureLowThreshold(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "alert_notification_pressure_low_threshold", String(describing: p1), fallback: "Air Pressure is below %@") - } - /// Signal strength is above %@ - public static func alertNotificationRssiHighThreshold(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "alert_notification_rssi_high_threshold", String(describing: p1), fallback: "Signal strength is above %@") - } - /// Signal strength is below %@ - public static func alertNotificationRssiLowThreshold(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "alert_notification_rssi_low_threshold", String(describing: p1), fallback: "Signal strength is below %@") - } - /// Temperature is above %@ - public static func alertNotificationTemperatureHighThreshold(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "alert_notification_temperature_high_threshold", String(describing: p1), fallback: "Temperature is above %@") - } - /// Temperature is below %@ - public static func alertNotificationTemperatureLowThreshold(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "alert_notification_temperature_low_threshold", String(describing: p1), fallback: "Temperature is below %@") - } - /// All - public static let all = RuuviLocalization.tr("Localizable", "all", fallback: "All") - /// App Theme - public static let appTheme = RuuviLocalization.tr("Localizable", "app_theme", fallback: "App Theme") - /// Read more about Ruuvi account benefits or sign in later - public static let benefitsSignIn = RuuviLocalization.tr("Localizable", "benefits_sign_in", fallback: "Read more about Ruuvi account benefits or sign in later") - /// Bluetooth download - public static let bluetoothDownload = RuuviLocalization.tr("Localizable", "bluetooth_download", fallback: "Bluetooth download") - /// Local sensor data can be downloaded, when you're within its Bluetooth range. - public static let bluetoothDownloadDescription = RuuviLocalization.tr("Localizable", "bluetooth_download_description", fallback: "Local sensor data can be downloaded, when you're within its Bluetooth range.") - /// Cancel - public static let cancel = RuuviLocalization.tr("Localizable", "Cancel", fallback: "Cancel") - /// Card action - public static let cardAction = RuuviLocalization.tr("Localizable", "card_action", fallback: "Card action") - /// Card type - public static let cardType = RuuviLocalization.tr("Localizable", "card_type", fallback: "Card type") - /// Change background - public static let changeBackground = RuuviLocalization.tr("Localizable", "change_background", fallback: "Change background") - /// Change background image - public static let changeBackgroundImage = RuuviLocalization.tr("Localizable", "change_background_image", fallback: "Change background image") - /// Select background image. If you're not signed in, you'll lose the image in case of app reinstall. - public static let changeBackgroundMessage = RuuviLocalization.tr("Localizable", "change_background_message", fallback: "Select background image. If you're not signed in, you'll lose the image in case of app reinstall.") - /// (changelog) - public static let changelog = RuuviLocalization.tr("Localizable", "changelog", fallback: "(changelog)") - /// https://f.ruuvi.com/t/3192 - public static let changelogIosUrl = RuuviLocalization.tr("Localizable", "changelog_ios_url", fallback: "https://f.ruuvi.com/t/3192") - /// Average - public static let chartStatAvg = RuuviLocalization.tr("Localizable", "chart_stat_avg", fallback: "Average") - /// Hide min/max/avg - public static let chartStatHide = RuuviLocalization.tr("Localizable", "chart_stat_hide", fallback: "Hide min/max/avg") - /// Max - public static let chartStatMax = RuuviLocalization.tr("Localizable", "chart_stat_max", fallback: "Max") - /// Min - public static let chartStatMin = RuuviLocalization.tr("Localizable", "chart_stat_min", fallback: "Min") - /// Show min/max/avg - public static let chartStatShow = RuuviLocalization.tr("Localizable", "chart_stat_show", fallback: "Show min/max/avg") - /// Checking claim state - public static let checkClaimState = RuuviLocalization.tr("Localizable", "check_claim_state", fallback: "Checking claim state") - /// Claiming in progress - public static let claimInProgress = RuuviLocalization.tr("Localizable", "claim_in_progress", fallback: "Claiming in progress") - /// Claim sensor ownership - public static let claimSensorOwnership = RuuviLocalization.tr("Localizable", "claim_sensor_ownership", fallback: "Claim sensor ownership") - /// Secure the ownership information of your sensors by claiming their ownerships in the app. - public static let claimWarning = RuuviLocalization.tr("Localizable", "claim_warning", fallback: "Secure the ownership information of your sensors by claiming their ownerships in the app.") - /// You are scanning different RuuviTag - public static let claimWrongSensorScanned = RuuviLocalization.tr("Localizable", "claim_wrong_sensor_scanned", fallback: "You are scanning different RuuviTag") - /// Clear local history - public static let clearLocalHistory = RuuviLocalization.tr("Localizable", "clear_local_history", fallback: "Clear local history") - /// Do you want to clear locally stored history data from the app? This won't clear internally stored history from the sensor or history data stored on the Ruuvi Cloud service. - public static let clearLocalHistoryDescription = RuuviLocalization.tr("Localizable", "clear_local_history_description", fallback: "Do you want to clear locally stored history data from the app? This won't clear internally stored history from the sensor or history data stored on the Ruuvi Cloud service.") - /// Clear history view - public static let clearView = RuuviLocalization.tr("Localizable", "clear_view", fallback: "Clear history view") - /// Close - public static let close = RuuviLocalization.tr("Localizable", "Close", fallback: "Close") - /// ● Background images - public static let cloudStoredAlerts = RuuviLocalization.tr("Localizable", "cloud_stored_alerts", fallback: "● Background images") - /// ● Alert settings - public static let cloudStoredBackgrounds = RuuviLocalization.tr("Localizable", "cloud_stored_backgrounds", fallback: "● Alert settings") - /// ● Calibration settings - public static let cloudStoredCalibration = RuuviLocalization.tr("Localizable", "cloud_stored_calibration", fallback: "● Calibration settings") - /// ● Custom names - public static let cloudStoredNames = RuuviLocalization.tr("Localizable", "cloud_stored_names", fallback: "● Custom names") - /// ● Sensor ownerships - public static let cloudStoredOwnerships = RuuviLocalization.tr("Localizable", "cloud_stored_ownerships", fallback: "● Sensor ownerships") - /// ● App settings - public static let cloudStoredSharing = RuuviLocalization.tr("Localizable", "cloud_stored_sharing", fallback: "● App settings") - /// Confirm - public static let confirm = RuuviLocalization.tr("Localizable", "Confirm", fallback: "Confirm") - /// Copy - public static let copy = RuuviLocalization.tr("Localizable", "Copy", fallback: "Copy") - /// Copy MAC Address - public static let copyMacAddress = RuuviLocalization.tr("Localizable", "copy_mac_address", fallback: "Copy MAC Address") - /// Copy Unique ID - public static let copyUniqueId = RuuviLocalization.tr("Localizable", "copy_unique_id", fallback: "Copy Unique ID") - /// Dark theme - public static let darkTheme = RuuviLocalization.tr("Localizable", "dark_theme", fallback: "Dark theme") - /// Seems that you don't have any Ruuvi sensors added yet. - public static let dashboardNoSensorsMessage = RuuviLocalization.tr("Localizable", "dashboard_no_sensors_message", fallback: "Seems that you don't have any Ruuvi sensors added yet.") - /// You are not signed in. - /// - /// If you have an account and have already added Ruuvi sensors to it, they will automatically synchronise with Ruuvi Station mobile app when you sign in. - public static let dashboardNoSensorsMessageSignedOut = RuuviLocalization.tr("Localizable", "dashboard_no_sensors_message_signed_out", fallback: "You are not signed in.\n\nIf you have an account and have already added Ruuvi sensors to it, they will automatically synchronise with Ruuvi Station mobile app when you sign in.") - /// 1 day - public static let day1 = RuuviLocalization.tr("Localizable", "day_1", fallback: "1 day") - /// 10 days - public static let day10 = RuuviLocalization.tr("Localizable", "day_10", fallback: "10 days") - /// 2 days - public static let day2 = RuuviLocalization.tr("Localizable", "day_2", fallback: "2 days") - /// 3 days - public static let day3 = RuuviLocalization.tr("Localizable", "day_3", fallback: "3 days") - /// 4 days - public static let day4 = RuuviLocalization.tr("Localizable", "day_4", fallback: "4 days") - /// 5 days - public static let day5 = RuuviLocalization.tr("Localizable", "day_5", fallback: "5 days") - /// 6 days - public static let day6 = RuuviLocalization.tr("Localizable", "day_6", fallback: "6 days") - /// 7 days - public static let day7 = RuuviLocalization.tr("Localizable", "day_7", fallback: "7 days") - /// 8 days - public static let day8 = RuuviLocalization.tr("Localizable", "day_8", fallback: "8 days") - /// 9 days - public static let day9 = RuuviLocalization.tr("Localizable", "day_9", fallback: "9 days") - /// %.0f days - public static func dayX(_ p1: Float) -> String { - return RuuviLocalization.tr("Localizable", "day_x", p1, fallback: "%.0f days") - } - /// dBm - public static let dBm = RuuviLocalization.tr("Localizable", "dBm", fallback: "dBm") - /// Are you sure? - public static let dialogAreYouSure = RuuviLocalization.tr("Localizable", "dialog_are_you_sure", fallback: "Are you sure?") - /// This operation cannot be undone. - public static let dialogOperationUndone = RuuviLocalization.tr("Localizable", "dialog_operation_undone", fallback: "This operation cannot be undone.") - /// Don't show this again - public static let doNotShowAgain = RuuviLocalization.tr("Localizable", "do_not_show_again", fallback: "Don't show this again") - /// Do you own this sensor? - public static let doYouOwnSensor = RuuviLocalization.tr("Localizable", "do_you_own_sensor", fallback: "Do you own this sensor?") - /// Done - public static let done = RuuviLocalization.tr("Localizable", "Done", fallback: "Done") - /// Download - public static let download = RuuviLocalization.tr("Localizable", "download", fallback: "Download") - /// No data available - /// in the selected history window. - public static let emptyChartMessage = RuuviLocalization.tr("Localizable", "empty_chart_message", fallback: "No data available \nin the selected history window.") - /// Enter Code - public static let enterCode = RuuviLocalization.tr("Localizable", "enter_code", fallback: "Enter Code") - /// You can export a sensor's history from its history graph page. Tap the three dots menu icon in the top right corner, and then select "Export history (csv)". - public static let exportCsvFeatureLocation = RuuviLocalization.tr("Localizable", "export_csv_feature_location", fallback: "You can export a sensor's history from its history graph page. Tap the three dots menu icon in the top right corner, and then select \"Export history (csv)\".") - /// Export history (csv) - public static let exportHistory = RuuviLocalization.tr("Localizable", "export_history", fallback: "Export history (csv)") - /// Firmware Version: - public static let firmwareVersion = RuuviLocalization.tr("Localizable", "firmware_version", fallback: "Firmware Version:") - /// System theme - public static let followSystemTheme = RuuviLocalization.tr("Localizable", "follow_system_theme", fallback: "System theme") - /// Force Claim - public static let forceClaim = RuuviLocalization.tr("Localizable", "force_claim", fallback: "Force Claim") - /// Force Claim Sensor - public static let forceClaimSensor = RuuviLocalization.tr("Localizable", "force_claim_sensor", fallback: "Force Claim Sensor") - /// This sensor has been claimed by another user. You can force the ownership to your account if you have physical access to this sensor. Each Ruuvi sensor can have only one owner. - public static let forceClaimSensorDescription1 = RuuviLocalization.tr("Localizable", "force_claim_sensor_description1", fallback: "This sensor has been claimed by another user. You can force the ownership to your account if you have physical access to this sensor. Each Ruuvi sensor can have only one owner.") - /// Force Claim is done by using Near-Field Communication (NFC). Make sure NFC is enabled on your mobile device. - /// - /// 1. Touch your Ruuvi sensor with your mobile device to start the claiming process. - /// - /// 2. When successfully claimed, you will be sent back to Sensor Settings. - /// - /// If claiming was unsuccessful or NFC is not available on your device: - /// - /// 1. Open the cover of your Ruuvi sensor. - /// - /// 2. Locate the round black button (or button "B" in case your sensor has 2 buttons) on the white circuit board and press it briefly, then tap on Use BT button to start the claiming process. - /// - /// 3. When successfully claimed you will be sent back to Sensor Settings. - public static let forceClaimSensorDescription2 = RuuviLocalization.tr("Localizable", "force_claim_sensor_description2", fallback: "Force Claim is done by using Near-Field Communication (NFC). Make sure NFC is enabled on your mobile device.\n\n\t1. Touch your Ruuvi sensor with your mobile device to start the claiming process.\n\n\t2. When successfully claimed, you will be sent back to Sensor Settings.\n\nIf claiming was unsuccessful or NFC is not available on your device:\n\n\t1. Open the cover of your Ruuvi sensor.\n\n\t2. Locate the round black button (or button \"B\" in case your sensor has 2 buttons) on the white circuit board and press it briefly, then tap on Use BT button to start the claiming process.\n\n\t3. When successfully claimed you will be sent back to Sensor Settings.") - /// Full image view - public static let fullImageView = RuuviLocalization.tr("Localizable", "full_image_view", fallback: "Full image view") - /// g - public static let g = RuuviLocalization.tr("Localizable", "g", fallback: "g") - /// g/m³ - public static let gm³ = RuuviLocalization.tr("Localizable", "g/m³", fallback: "g/m³") - /// Ruuvi Station downloads the internal history of the sensor for the last 10 days if the measurement history is available. - /// - /// The history is downloaded using a Bluetooth connection. Make sure you are near the sensor. - public static let gattSyncDescription = RuuviLocalization.tr("Localizable", "gatt_sync_description", fallback: "Ruuvi Station downloads the internal history of the sensor for the last 10 days if the measurement history is available.\n\nThe history is downloaded using a Bluetooth connection. Make sure you are near the sensor.") - /// Go to sensor card - public static let goToSensor = RuuviLocalization.tr("Localizable", "go_to_sensor", fallback: "Go to sensor card") - /// h - public static let h = RuuviLocalization.tr("Localizable", "h", fallback: "h") - /// History view - public static let historyView = RuuviLocalization.tr("Localizable", "history_view", fallback: "History view") - /// Hour - public static let hour = RuuviLocalization.tr("Localizable", "hour", fallback: "Hour") - /// Hours - public static let hours = RuuviLocalization.tr("Localizable", "hours", fallback: "Hours") - /// hPa - public static let hPa = RuuviLocalization.tr("Localizable", "hPa", fallback: "hPa") - /// Image cards - public static let imageCards = RuuviLocalization.tr("Localizable", "image_cards", fallback: "Image cards") - /// Internet connection problem - public static let internetConnectionProblem = RuuviLocalization.tr("Localizable", "internet_connection_problem", fallback: "Internet connection problem") - /// Let's Sign In - public static let letsDoIt = RuuviLocalization.tr("Localizable", "lets_do_it", fallback: "Let's Sign In") - /// Light theme - public static let lightTheme = RuuviLocalization.tr("Localizable", "light_theme", fallback: "Light theme") - /// Ruuvi Station mobile app supports maximum 10 days of history. Ruuvi Cloud subscribers are able to view up to 2 years of historical data using web app at ruuvi.com/station (requires Ruuvi Gateway router). - public static let longerHistoryMessage = RuuviLocalization.tr("Localizable", "longer_history_message", fallback: "Ruuvi Station mobile app supports maximum 10 days of history. Ruuvi Cloud subscribers are able to view up to 2 years of historical data using web app at ruuvi.com/station (requires Ruuvi Gateway router).") - /// Longer history - public static let longerHistoryTitle = RuuviLocalization.tr("Localizable", "longer_history_title", fallback: "Longer history") - /// Low battery - public static let lowBattery = RuuviLocalization.tr("Localizable", "low_battery", fallback: "Low battery") - /// Mac Address: - public static let macAddress = RuuviLocalization.tr("Localizable", "mac_address", fallback: "Mac Address:") - /// min - public static let min = RuuviLocalization.tr("Localizable", "min", fallback: "min") - /// Minutes - public static let minutes = RuuviLocalization.tr("Localizable", "minutes", fallback: "Minutes") - /// More... - public static let more = RuuviLocalization.tr("Localizable", "more", fallback: "More...") - /// - - public static let na = RuuviLocalization.tr("Localizable", "N/A", fallback: "-") - /// Name: - public static let name = RuuviLocalization.tr("Localizable", "name", fallback: "Name:") - /// Only sensors within range of your Ruuvi Gateway can be shared. - public static let networkSharingDisabled = RuuviLocalization.tr("Localizable", "network_sharing_disabled", fallback: "Only sensors within range of your Ruuvi Gateway can be shared.") - /// No - public static let no = RuuviLocalization.tr("Localizable", "No", fallback: "No") - /// A free account will be created for this email if you don't already have one. Only email address is required. We keep your information safe. - public static let noPasswordNeeded = RuuviLocalization.tr("Localizable", "no_password_needed", fallback: "A free account will be created for this email if you don't already have one. Only email address is required. We keep your information safe.") - /// Note! - public static let note = RuuviLocalization.tr("Localizable", "note", fallback: "Note!") - /// Off - public static let off = RuuviLocalization.tr("Localizable", "Off", fallback: "Off") - /// OK - public static let ok = RuuviLocalization.tr("Localizable", "OK", fallback: "OK") - /// On - public static let on = RuuviLocalization.tr("Localizable", "On", fallback: "On") - /// Bring your favorite sensors to your Home Screen and Lock Screen as - public static let onboardingAccessWidgets = RuuviLocalization.tr("Localizable", "onboarding_access_widgets", fallback: "Bring your favorite sensors to your Home Screen and Lock Screen as") - /// Alerts - public static let onboardingAlerts = RuuviLocalization.tr("Localizable", "onboarding_alerts", fallback: "Alerts") - /// Next - public static let onboardingContinue = RuuviLocalization.tr("Localizable", "onboarding_continue", fallback: "Next") - /// Dashboard - public static let onboardingDashboard = RuuviLocalization.tr("Localizable", "onboarding_dashboard", fallback: "Dashboard") - /// Explore your measurement - public static let onboardingExploreDetailed = RuuviLocalization.tr("Localizable", "onboarding_explore_detailed", fallback: "Explore your measurement") - /// View all sensors at a glance on your - public static let onboardingFollowMeasurement = RuuviLocalization.tr("Localizable", "onboarding_follow_measurement", fallback: "View all sensors at a glance on your") - /// A Ruuvi Gateway router is required. - public static let onboardingGatewayRequired = RuuviLocalization.tr("Localizable", "onboarding_gateway_required", fallback: "A Ruuvi Gateway router is required.") - /// Ruuvi experience is better when you're signed in. Do it now or continue without cloud features. - public static let onboardingGoToSignIn = RuuviLocalization.tr("Localizable", "onboarding_go_to_sign_in", fallback: "Ruuvi experience is better when you're signed in. Do it now or continue without cloud features.") - /// Let's start measuring! - public static let onboardingGoToSignInAlreadySignedIn = RuuviLocalization.tr("Localizable", "onboarding_go_to_sign_in_already_signed_in", fallback: "Let's start measuring!") - /// Widgets - public static let onboardingHandyWidgets = RuuviLocalization.tr("Localizable", "onboarding_handy_widgets", fallback: "Widgets") - /// History - public static let onboardingHistory = RuuviLocalization.tr("Localizable", "onboarding_history", fallback: "History") - /// Measure Your World - public static let onboardingMeasureYourWorld = RuuviLocalization.tr("Localizable", "onboarding_measure_your_world", fallback: "Measure Your World") - /// Personalise - public static let onboardingPersonalise = RuuviLocalization.tr("Localizable", "onboarding_personalise", fallback: "Personalise") - /// Read Your Ruuvi Sensors - public static let onboardingReadSensorsData = RuuviLocalization.tr("Localizable", "onboarding_read_sensors_data", fallback: "Read Your Ruuvi Sensors") - /// Set and customise your - public static let onboardingSetCustom = RuuviLocalization.tr("Localizable", "onboarding_set_custom", fallback: "Set and customise your") - /// to measure together with your friends and family. - public static let onboardingShareYourSensors = RuuviLocalization.tr("Localizable", "onboarding_share_your_sensors", fallback: "to measure together with your friends and family.") - /// Share Sensors - public static let onboardingShareesCanUse = RuuviLocalization.tr("Localizable", "onboarding_sharees_can_use", fallback: "Share Sensors") - /// Skip - public static let onboardingSkip = RuuviLocalization.tr("Localizable", "onboarding_skip", fallback: "Skip") - /// Ruuvi Web App - public static let onboardingStationWeb = RuuviLocalization.tr("Localizable", "onboarding_station_web", fallback: "Ruuvi Web App") - /// Swipe to continue → - public static let onboardingSwipeToContinue = RuuviLocalization.tr("Localizable", "onboarding_swipe_to_continue", fallback: "Swipe to continue →") - /// Almost there! - public static let onboardingThatsIt = RuuviLocalization.tr("Localizable", "onboarding_thats_it", fallback: "Almost there!") - /// Let's get started! - public static let onboardingThatsItAlreadySignedIn = RuuviLocalization.tr("Localizable", "onboarding_thats_it_already_signed_in", fallback: "Let's get started!") - /// using Bluetooth or Ruuvi Cloud - public static let onboardingViaBluetoothOrCloud = RuuviLocalization.tr("Localizable", "onboarding_via_bluetooth_or_cloud", fallback: "using Bluetooth or Ruuvi Cloud") - /// Large dashboard, multi-year history, email alerts and more on - public static let onboardingWebPros = RuuviLocalization.tr("Localizable", "onboarding_web_pros", fallback: "Large dashboard, multi-year history, email alerts and more on") - /// Let's get to know your Ruuvi Station app. - public static let onboardingWithRuuviSensors = RuuviLocalization.tr("Localizable", "onboarding_with_ruuvi_sensors", fallback: "Let's get to know your Ruuvi Station app.") - /// your app with custom names and backgrounds. - public static let onboardingYourSensors = RuuviLocalization.tr("Localizable", "onboarding_your_sensors", fallback: "your app with custom names and backgrounds.") - /// Open history view - public static let openHistoryView = RuuviLocalization.tr("Localizable", "open_history_view", fallback: "Open history view") - /// Open sensor view - public static let openSensorView = RuuviLocalization.tr("Localizable", "open_sensor_view", fallback: "Open sensor view") - /// Owner's Ruuvi Plan - public static let ownersPlan = RuuviLocalization.tr("Localizable", "owners_plan", fallback: "Owner's Ruuvi Plan") - /// Reading Bluetooth: %.0f - public static func readingHistoryX(_ p1: Float) -> String { - return RuuviLocalization.tr("Localizable", "reading_history_x", p1, fallback: "Reading Bluetooth: %.0f") - } - /// Remove - public static let remove = RuuviLocalization.tr("Localizable", "Remove", fallback: "Remove") - /// By removing the sensor, your sensor ownership status will be revoked and sensor settings, such as name, background image, calibration settings and alert settings will be removed. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner. - public static let removeClaimedSensorDescription = RuuviLocalization.tr("Localizable", "remove_claimed_sensor_description", fallback: "By removing the sensor, your sensor ownership status will be revoked and sensor settings, such as name, background image, calibration settings and alert settings will be removed. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner.") - /// I also want to remove sensor history data from Ruuvi Cloud. - public static let removeCloudHistoryDescription = RuuviLocalization.tr("Localizable", "remove_cloud_history_description", fallback: "I also want to remove sensor history data from Ruuvi Cloud.") - /// Remove cloud history - public static let removeCloudHistoryTitle = RuuviLocalization.tr("Localizable", "remove_cloud_history_title", fallback: "Remove cloud history") - /// If you choose to remove this sensor, it will result in the deletion of your locally stored measurement history, along with the removal of any related sensor settings like name, background image, calibration, and alert configurations. - /// - /// You can add this sensor later again, if needed. - public static let removeLocalSensorDescription = RuuviLocalization.tr("Localizable", "remove_local_sensor_description", fallback: "If you choose to remove this sensor, it will result in the deletion of your locally stored measurement history, along with the removal of any related sensor settings like name, background image, calibration, and alert configurations.\n\nYou can add this sensor later again, if needed.") - /// If you choose to remove this shared sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore. - /// - /// You will also lose any related sensor settings like name, background image and alert configurations. - public static let removeSharedSensorDescription = RuuviLocalization.tr("Localizable", "remove_shared_sensor_description", fallback: "If you choose to remove this shared sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore.\n\nYou will also lose any related sensor settings like name, background image and alert configurations.") - /// Rename - public static let rename = RuuviLocalization.tr("Localizable", "rename", fallback: "Rename") - /// Request Code - public static let requestCode = RuuviLocalization.tr("Localizable", "request_code", fallback: "Request Code") - /// Using this alert requires you to be signed in to the app, and that you have claimed the ownership of this sensor and it's in the range of Ruuvi Gateway router. iOS devices are unable to indicate signal strength information of received data sent by Ruuvi sensor when sensor is paired and measurements are being received in the background. Realtime Bluetooth signal strength is shown in the app but doesn't affect this alert. - public static let rssiAlertDescription = RuuviLocalization.tr("Localizable", "rssi_alert_description", fallback: "Using this alert requires you to be signed in to the app, and that you have claimed the ownership of this sensor and it's in the range of Ruuvi Gateway router. iOS devices are unable to indicate signal strength information of received data sent by Ruuvi sensor when sensor is paired and measurements are being received in the background. Realtime Bluetooth signal strength is shown in the app but doesn't affect this alert.") - /// Ruuvi Cloud - public static let ruuviCloud = RuuviLocalization.tr("Localizable", "ruuvi_cloud", fallback: "Ruuvi Cloud") - /// s - public static let s = RuuviLocalization.tr("Localizable", "s", fallback: "s") - /// Select from default images - public static let selectDefaultImage = RuuviLocalization.tr("Localizable", "select_default_image", fallback: "Select from default images") - /// Select from phone gallery - public static let selectFromGallery = RuuviLocalization.tr("Localizable", "select_from_gallery", fallback: "Select from phone gallery") - /// Sensor Details - public static let sensorDetails = RuuviLocalization.tr("Localizable", "sensor_details", fallback: "Sensor Details") - /// Sensor not found. Try again. - public static let sensorNotFoundError = RuuviLocalization.tr("Localizable", "sensor_not_found_error", fallback: "Sensor not found. Try again.") - /// Signing in to the app has many advantages. Settings will be safely stored to your account: - public static let sensorsOwnershipAndSettingsStoredInCloud = RuuviLocalization.tr("Localizable", "sensors_ownership_and_settings_stored_in_cloud", fallback: "Signing in to the app has many advantages. Settings will be safely stored to your account:") - /// Limit alert notifications - public static let settingsAlertLimitNotification = RuuviLocalization.tr("Localizable", "settings_alert_limit_notification", fallback: "Limit alert notifications") - /// Trigger Bluetooth alert notification only once per hour even if alert was retriggered. - public static let settingsAlertLimitNotificationDescription = RuuviLocalization.tr("Localizable", "settings_alert_limit_notification_description", fallback: "Trigger Bluetooth alert notification only once per hour even if alert was retriggered.") - /// Alert Notifications - public static let settingsAlertNotifications = RuuviLocalization.tr("Localizable", "settings_alert_notifications", fallback: "Alert Notifications") - /// Alert Sound - public static let settingsAlertSound = RuuviLocalization.tr("Localizable", "settings_alert_sound", fallback: "Alert Sound") - /// System Default - public static let settingsAlertSoundDefault = RuuviLocalization.tr("Localizable", "settings_alert_sound_default", fallback: "System Default") - /// Select push notification alert sound. - public static let settingsAlertSoundDescription = RuuviLocalization.tr("Localizable", "settings_alert_sound_description", fallback: "Select push notification alert sound.") - /// Ruuvi Alert - public static let settingsAlertSoundRuuviSpeak = RuuviLocalization.tr("Localizable", "settings_alert_sound_ruuvi_speak", fallback: "Ruuvi Alert") - /// You can also adjust Notification settings under iOS Settings -> Notifications - public static let settingsAlertsFooterDescription = RuuviLocalization.tr("Localizable", "settings_alerts_footer_description", fallback: "You can also adjust Notification settings under iOS Settings -> Notifications") - /// iOS Settings -> Notifications - public static let settingsAlertsFooterDescriptionLinkMask = RuuviLocalization.tr("Localizable", "settings_alerts_footer_description_link_mask", fallback: "iOS Settings -> Notifications") - /// Settings & alerts - public static let settingsAndAlerts = RuuviLocalization.tr("Localizable", "settings_and_alerts", fallback: "Settings & alerts") - /// Appearance - public static let settingsAppearance = RuuviLocalization.tr("Localizable", "settings_appearance", fallback: "Appearance") - /// Email Alerts - public static let settingsEmailAlerts = RuuviLocalization.tr("Localizable", "settings_email_alerts", fallback: "Email Alerts") - /// If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive email alerts by enabling this. - public static let settingsEmailAlertsDescription = RuuviLocalization.tr("Localizable", "settings_email_alerts_description", fallback: "If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive email alerts by enabling this.") - /// Push Alerts - public static let settingsPushAlerts = RuuviLocalization.tr("Localizable", "settings_push_alerts", fallback: "Push Alerts") - /// If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive push alerts by enabling this. - public static let settingsPushAlertsDescription = RuuviLocalization.tr("Localizable", "settings_push_alerts_description", fallback: "If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive push alerts by enabling this.") - /// Share pending - public static let sharePending = RuuviLocalization.tr("Localizable", "share_pending", fallback: "Share pending") - /// Shared successfully! This email address isn't linked to a Ruuvi account yet. An invite to create a free account has been sent. Once created, you'll see it in the sharee listing. - public static let sharePendingMessage = RuuviLocalization.tr("Localizable", "share_pending_message", fallback: "Shared successfully! This email address isn't linked to a Ruuvi account yet. An invite to create a free account has been sent. Once created, you'll see it in the sharee listing.") - /// Shared to %d/%d - public static func sharedToX(_ p1: Int, _ p2: Int) -> String { - return RuuviLocalization.tr("Localizable", "shared_to_x", p1, p2, fallback: "Shared to %d/%d") - } - /// Continue - public static let signInContinue = RuuviLocalization.tr("Localizable", "sign_in_continue", fallback: "Continue") - /// Sign in or create a free Ruuvi account - public static let signInOrCreateFreeAccount = RuuviLocalization.tr("Localizable", "sign_in_or_create_free_account", fallback: "Sign in or create a free Ruuvi account") - /// Signal Strength (dBm) - public static let signalStrengthDbm = RuuviLocalization.tr("Localizable", "signal_strength_dbm", fallback: "Signal Strength (dBm)") - /// (Signing in is optional) - public static let signingInIsOptional = RuuviLocalization.tr("Localizable", "signing_in_is_optional", fallback: "(Signing in is optional)") - /// Simple cards - public static let simpleCards = RuuviLocalization.tr("Localizable", "simple_cards", fallback: "Simple cards") - /// Support - public static let support = RuuviLocalization.tr("Localizable", "support", fallback: "Support") - /// Synchronisation - public static let synchronisation = RuuviLocalization.tr("Localizable", "synchronisation", fallback: "Synchronisation") - /// Synchronised - public static let synchronized = RuuviLocalization.tr("Localizable", "Synchronized", fallback: "Synchronised") - /// Loading history from the cloud... - public static let syncing = RuuviLocalization.tr("Localizable", "Syncing...", fallback: "Loading history from the cloud...") - /// Take a photo - public static let takePhoto = RuuviLocalization.tr("Localizable", "take_photo", fallback: "Take a photo") - /// No password needed. - public static let toUseAllAppFeatures = RuuviLocalization.tr("Localizable", "to_use_all_app_features", fallback: "No password needed.") - /// Type your email.. - public static let typeYourEmail = RuuviLocalization.tr("Localizable", "type_your_email", fallback: "Type your email..") - /// Unclaim - public static let unclaim = RuuviLocalization.tr("Localizable", "unclaim", fallback: "Unclaim") - /// Unclaim sensor - public static let unclaimSensor = RuuviLocalization.tr("Localizable", "unclaim_sensor", fallback: "Unclaim sensor") - /// Ownership of this sensor has been claimed to your Ruuvi account. Press Unclaim to remove this sensor's settings and related data from your Ruuvi account. - public static let unclaimSensorDescription = RuuviLocalization.tr("Localizable", "unclaim_sensor_description", fallback: "Ownership of this sensor has been claimed to your Ruuvi account. Press Unclaim to remove this sensor's settings and related data from your Ruuvi account.") - /// Unique ID: - public static let uniqueId = RuuviLocalization.tr("Localizable", "unique_id", fallback: "Unique ID:") - /// Updated - public static let updated = RuuviLocalization.tr("Localizable", "Updated", fallback: "Updated") - /// Uploading: %.0f - public static func uploadingProgress(_ p1: Float) -> String { - return RuuviLocalization.tr("Localizable", "uploading_progress", p1, fallback: "Uploading: %.0f") - } - /// Use BT - public static let useBluetooth = RuuviLocalization.tr("Localizable", "use_bluetooth", fallback: "Use BT") - /// Use NFC - public static let useNfc = RuuviLocalization.tr("Localizable", "use_nfc", fallback: "Use NFC") - /// No thanks, skip - public static let useWithoutAccount = RuuviLocalization.tr("Localizable", "use_without_account", fallback: "No thanks, skip") - /// V - public static let v = RuuviLocalization.tr("Localizable", "V", fallback: "V") - /// View - public static let view = RuuviLocalization.tr("Localizable", "view", fallback: "View") - /// Benefits - public static let whyShouldSignIn = RuuviLocalization.tr("Localizable", "why_should_sign_in", fallback: "Benefits") - /// Yes - public static let yes = RuuviLocalization.tr("Localizable", "Yes", fallback: "Yes") - /// °C - public static let ºC = RuuviLocalization.tr("Localizable", "ºC", fallback: "°C") - /// °F - public static let ºF = RuuviLocalization.tr("Localizable", "ºF", fallback: "°F") - public enum About { - public enum AboutHelp { - /// Ruuvi Station is an easy-to-use application that allows you to monitor the measurement data of Ruuvi sensors. - public static let contents = RuuviLocalization.tr("Localizable", "About.AboutHelp.contents", fallback: "Ruuvi Station is an easy-to-use application that allows you to monitor the measurement data of Ruuvi sensors.") - /// About / Help - public static let header = RuuviLocalization.tr("Localizable", "About.AboutHelp.header", fallback: "About / Help") - } - public enum DatabaseSize { - /// Database size: %@ - public static func text(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "About.DatabaseSize.text", String(describing: p1), fallback: "Database size: %@") - } - } - public enum MeasurementsCount { - /// Number of locally stored measurements: %d - public static func text(_ p1: Int) -> String { - return RuuviLocalization.tr("Localizable", "About.MeasurementsCount.text", p1, fallback: "Number of locally stored measurements: %d") - } - } - public enum More { - /// Ruuvi's website: ruuvi.com - /// Ruuvi Forum: f.ruuvi.com - /// Ruuvi Blog: ruuvi.com/blog - /// Ruuvi on Twitter: twitter.com/ruuvicom - public static let contents = RuuviLocalization.tr("Localizable", "About.More.contents", fallback: "Ruuvi's website: ruuvi.com\nRuuvi Forum: f.ruuvi.com\nRuuvi Blog: ruuvi.com/blog\nRuuvi on Twitter: twitter.com/ruuvicom") - /// More to read - public static let header = RuuviLocalization.tr("Localizable", "About.More.header", fallback: "More to read") - } - public enum OpenSource { - /// Just like Ruuvi sensors, Ruuvi Station apps are open source. Follow the development and contribute at: github.com/ruuvi - public static let contents = RuuviLocalization.tr("Localizable", "About.OpenSource.contents", fallback: "Just like Ruuvi sensors, Ruuvi Station apps are open source. Follow the development and contribute at: github.com/ruuvi") - /// Open-source - public static let header = RuuviLocalization.tr("Localizable", "About.OpenSource.header", fallback: "Open-source") - } - public enum OperationsManual { - /// Get started using the Ruuvi Station mobile application with our online guides: ruuvi.com/support/station-mobile - public static let contents = RuuviLocalization.tr("Localizable", "About.OperationsManual.contents", fallback: "Get started using the Ruuvi Station mobile application with our online guides: ruuvi.com/support/station-mobile") - /// Operations manual - public static let header = RuuviLocalization.tr("Localizable", "About.OperationsManual.header", fallback: "Operations manual") - } - public enum Privacy { - /// By using the application, you accept Ruuvi's standard terms and conditions: ruuvi.com/terms - public static let contents = RuuviLocalization.tr("Localizable", "About.Privacy.contents", fallback: "By using the application, you accept Ruuvi's standard terms and conditions: ruuvi.com/terms") - /// Privacy policy - public static let header = RuuviLocalization.tr("Localizable", "About.Privacy.header", fallback: "Privacy policy") - } - public enum TagsCount { - /// Added sensors: %d - public static func text(_ p1: Int) -> String { - return RuuviLocalization.tr("Localizable", "About.TagsCount.text", p1, fallback: "Added sensors: %d") - } - } - public enum Troubleshooting { - /// Find help using the Ruuvi Station apps, Ruuvi products and Ruuvi Cloud service from our support center: ruuvi.com/support - public static let contents = RuuviLocalization.tr("Localizable", "About.Troubleshooting.contents", fallback: "Find help using the Ruuvi Station apps, Ruuvi products and Ruuvi Cloud service from our support center: ruuvi.com/support") - /// Troubleshooting - public static let header = RuuviLocalization.tr("Localizable", "About.Troubleshooting.header", fallback: "Troubleshooting") - } - public enum Version { - /// Version - public static let text = RuuviLocalization.tr("Localizable", "About.Version.text", fallback: "Version") - } - } - public enum Background { - public enum Interval { - public enum Every { - /// every - public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Every.string", fallback: "every") - } - public enum Min { - /// min - public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Min.string", fallback: "min") - } - public enum Sec { - /// sec - public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Sec.string", fallback: "sec") - } - } - public enum KeepConnection { - /// Keep the Connection - public static let title = RuuviLocalization.tr("Localizable", "Background.KeepConnection.title", fallback: "Keep the Connection") - } - public enum PresentNotifications { - /// Show Notifications - public static let title = RuuviLocalization.tr("Localizable", "Background.PresentNotifications.title", fallback: "Show Notifications") - } - public enum ReadRSSITitle { - /// Read RSSI - public static let title = RuuviLocalization.tr("Localizable", "Background.readRSSITitle.title", fallback: "Read RSSI") - } - } - public enum BluetoothError { - /// Disconnected - public static let disconnected = RuuviLocalization.tr("Localizable", "BluetoothError.disconnected", fallback: "Disconnected") - } - public enum Cards { - public enum Alert { - public enum AlreadyLoggedIn { - /// User %@ is already signed in. If you'd like to use a different account, please sign out first and then try again. - public static func message(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "Cards.Alert.AlreadyLoggedIn.message", String(describing: p1), fallback: "User %@ is already signed in. If you'd like to use a different account, please sign out first and then try again.") - } - } - } - public enum BluetoothDisabledAlert { - /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. - public static let message = RuuviLocalization.tr("Localizable", "Cards.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") - /// Bluetooth is not enabled - public static let title = RuuviLocalization.tr("Localizable", "Cards.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") - } - public enum Connected { - /// Connected - public static let title = RuuviLocalization.tr("Localizable", "Cards.Connected.title", fallback: "Connected") - } - public enum Error { - public enum ReverseGeocodingFailed { - /// Failed to load data for Virtual Sensor. Reverse geocode operation limit exceeded. - public static let message = RuuviLocalization.tr("Localizable", "Cards.Error.ReverseGeocodingFailed.message", fallback: "Failed to load data for Virtual Sensor. Reverse geocode operation limit exceeded.") - } - } - public enum KeepConnectionDialog { - /// Seems like you are running a connectable firmware on your Ruuvi device. Would you like to keep the connection open to this Ruuvi device in the background? This will allow histograms and alerts to work even when the application is minimised. - public static let message = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.message", fallback: "Seems like you are running a connectable firmware on your Ruuvi device. Would you like to keep the connection open to this Ruuvi device in the background? This will allow histograms and alerts to work even when the application is minimised.") - public enum Dismiss { - /// Cancel - public static let title = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.Dismiss.title", fallback: "Cancel") - } - public enum KeepConnection { - /// Keep the Connection - public static let title = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.KeepConnection.title", fallback: "Keep the Connection") - } - } - public enum LegacyFirmwareUpdateDialog { - /// Looks like your sensor is using an old firmware software version. To access new features such as history graphs, alerts and cloud services, updating is mandatory. - public static let message = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.message", fallback: "Looks like your sensor is using an old firmware software version. To access new features such as history graphs, alerts and cloud services, updating is mandatory.") - public enum CancelConfirmation { - /// Are you sure? Without updating, you won't be able to claim ownership of the sensor, download history graphs and set alerts. The update also includes bug fixes. If you cancel now, you can start the update process again from the sensor's settings page. - public static let message = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message", fallback: "Are you sure? Without updating, you won't be able to claim ownership of the sensor, download history graphs and set alerts. The update also includes bug fixes. If you cancel now, you can start the update process again from the sensor's settings page.") - } - public enum CheckForUpdate { - /// Check for update - public static let title = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title", fallback: "Check for update") - } - } - public enum Movements { - /// movements - public static let title = RuuviLocalization.tr("Localizable", "Cards.Movements.title", fallback: "movements") - } - public enum NoSensors { - /// No sensors added - /// Press here to add sensors - public static let title = RuuviLocalization.tr("Localizable", "Cards.NoSensors.title", fallback: "No sensors added\nPress here to add sensors") - } - public enum UpdatedLabel { - public enum NoData { - /// No data during the last 10 days - public static let message = RuuviLocalization.tr("Localizable", "Cards.UpdatedLabel.NoData.message", fallback: "No data during the last 10 days") - } - } - public enum WebTagAPILimitExcededError { - public enum Alert { - /// Please try again in 5 minutes - public static let message = RuuviLocalization.tr("Localizable", "Cards.WebTagAPILimitExcededError.Alert.message", fallback: "Please try again in 5 minutes") - /// Too many requests - public static let title = RuuviLocalization.tr("Localizable", "Cards.WebTagAPILimitExcededError.Alert.title", fallback: "Too many requests") - } - } - } - public enum ChartSettings { - public enum AllPoints { - /// Charts may be updated slowly when enabled. - public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.AllPoints.description", fallback: "Charts may be updated slowly when enabled.") - /// Show all measurements - public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.AllPoints.title", fallback: "Show all measurements") - } - public enum DrawDots { - /// Small dots will help to understand when measurements were collected. - public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.DrawDots.description", fallback: "Small dots will help to understand when measurements were collected.") - /// Show datapoints - public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.DrawDots.title", fallback: "Show datapoints") - } - public enum Duration { - /// Configure the period of history to be shown on chart from 1 to 10 days. - public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.Duration.description", fallback: "Configure the period of history to be shown on chart from 1 to 10 days.") - /// Chart History View Period - public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.Duration.title", fallback: "Chart History View Period") - } - } - public enum CoreError { - /// Failed to get current location - public static let failedToGetCurrentLocation = RuuviLocalization.tr("Localizable", "CoreError.failedToGetCurrentLocation", fallback: "Failed to get current location") - /// Failed to get data from response - public static let failedToGetDataFromResponse = RuuviLocalization.tr("Localizable", "CoreError.failedToGetDataFromResponse", fallback: "Failed to get data from response") - /// Failed to get background directory - public static let failedToGetDocumentsDirectory = RuuviLocalization.tr("Localizable", "CoreError.failedToGetDocumentsDirectory", fallback: "Failed to get background directory") - /// Failed to get PNG representation - public static let failedToGetPngRepresentation = RuuviLocalization.tr("Localizable", "CoreError.failedToGetPngRepresentation", fallback: "Failed to get PNG representation") - /// Missing permission for Location Services - public static let locationPermissionDenied = RuuviLocalization.tr("Localizable", "CoreError.locationPermissionDenied", fallback: "Missing permission for Location Services") - /// Location permission authorisation status is not determined - public static let locationPermissionNotDetermined = RuuviLocalization.tr("Localizable", "CoreError.locationPermissionNotDetermined", fallback: "Location permission authorisation status is not determined") - /// Object invalidated - public static let objectInvalidated = RuuviLocalization.tr("Localizable", "CoreError.objectInvalidated", fallback: "Object invalidated") - /// Object not found - public static let objectNotFound = RuuviLocalization.tr("Localizable", "CoreError.objectNotFound", fallback: "Object not found") - /// Unable to send email - public static let unableToSendEmail = RuuviLocalization.tr("Localizable", "CoreError.unableToSendEmail", fallback: "Unable to send email") - } - public enum DFUUIView { - /// You are running the latest firmware version, no need to update - public static let alreadyOnLatest = RuuviLocalization.tr("Localizable", "DFUUIView.alreadyOnLatest", fallback: "You are running the latest firmware version, no need to update") - /// Current version: - public static let currentTitle = RuuviLocalization.tr("Localizable", "DFUUIView.currentTitle", fallback: "Current version:") - /// Do not close the app or power off the sensor during the update. - public static let doNotCloseTitle = RuuviLocalization.tr("Localizable", "DFUUIView.doNotCloseTitle", fallback: "Do not close the app or power off the sensor during the update.") - /// Downloading the latest firmware to be updated... - public static let downloadingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.downloadingTitle", fallback: "Downloading the latest firmware to be updated...") - /// Latest available Ruuvi Firmware version: - public static let latestTitle = RuuviLocalization.tr("Localizable", "DFUUIView.latestTitle", fallback: "Latest available Ruuvi Firmware version:") - /// 2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label. - public static let locateBootButtonTitle = RuuviLocalization.tr("Localizable", "DFUUIView.locateBootButtonTitle", fallback: "2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label.") - /// Firmware Update - public static let navigationTitle = RuuviLocalization.tr("Localizable", "DFUUIView.navigationTitle", fallback: "Firmware Update") - /// Your sensor doesn't report its current firmware version. Either you're not in its Bluetooth range, it's connected to another phone, or it's running a very old firmware version. - public static let notReportingDescription = RuuviLocalization.tr("Localizable", "DFUUIView.notReportingDescription", fallback: "Your sensor doesn't report its current firmware version. Either you're not in its Bluetooth range, it's connected to another phone, or it's running a very old firmware version.") - /// 1. Open the cover of your Ruuvi sensor - public static let openCoverTitle = RuuviLocalization.tr("Localizable", "DFUUIView.openCoverTitle", fallback: "1. Open the cover of your Ruuvi sensor") - /// Prepare your sensor - public static let prepareTitle = RuuviLocalization.tr("Localizable", "DFUUIView.prepareTitle", fallback: "Prepare your sensor") - /// Searching for a sensor - public static let searchingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.searchingTitle", fallback: "Searching for a sensor") - /// 3. Set the sensor to updating mode: - public static let setUpdatingModeTitle = RuuviLocalization.tr("Localizable", "DFUUIView.setUpdatingModeTitle", fallback: "3. Set the sensor to updating mode:") - /// Start the update - public static let startTitle = RuuviLocalization.tr("Localizable", "DFUUIView.startTitle", fallback: "Start the update") - /// Start update process - public static let startUpdateProcess = RuuviLocalization.tr("Localizable", "DFUUIView.startUpdateProcess", fallback: "Start update process") - /// Update successful - public static let successfulTitle = RuuviLocalization.tr("Localizable", "DFUUIView.successfulTitle", fallback: "Update successful") - /// 3.2. If your sensor has a single button: keep the button pressed for 10 seconds. - public static let toBootModeOneButtonDescription = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeOneButtonDescription", fallback: "3.2. If your sensor has a single button: keep the button pressed for 10 seconds.") - /// 4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”. - public static let toBootModeSuccessTitle = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeSuccessTitle", fallback: "4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”.") - /// 3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”. - public static let toBootModeTwoButtonsDescription = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeTwoButtonsDescription", fallback: "3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”.") - /// Updating... - public static let updatingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.updatingTitle", fallback: "Updating...") - public enum DBMigration { - public enum Error { - /// The update was successful, but an unexpected database migration error occurred. To continue using this sensor, please remove it from the app and then add it again. - public static let message = RuuviLocalization.tr("Localizable", "DFUUIView.DBMigration.Error.message", fallback: "The update was successful, but an unexpected database migration error occurred. To continue using this sensor, please remove it from the app and then add it again.") - } - } - public enum LowBattery { - public enum Warning { - /// Sensor's battery voltage seems to be low and the firmware update process may fail. We recommend to replace the battery before updating. - public static let message = RuuviLocalization.tr("Localizable", "DFUUIView.lowBattery.warning.message", fallback: "Sensor's battery voltage seems to be low and the firmware update process may fail. We recommend to replace the battery before updating.") - } - } - } - public enum Defaults { - public enum AlertsMuteInterval { - /// Alerts Mute Interval - public static let title = RuuviLocalization.tr("Localizable", "Defaults.AlertsMuteInterval.title", fallback: "Alerts Mute Interval") - } - public enum AlertsRepeatInterval { - /// Alerts Interval - public static let title = RuuviLocalization.tr("Localizable", "Defaults.AlertsRepeatInterval.title", fallback: "Alerts Interval") - } - public enum AppLaunchRequiredForReview { - public enum Count { - /// App launch count to ask for review for the first time - public static let title = RuuviLocalization.tr("Localizable", "Defaults.AppLaunchRequiredForReview.Count.title", fallback: "App launch count to ask for review for the first time") - } - } - public enum AskReviewIfLaunchDivisibleBy { - public enum Count { - /// Ask review if app launch divisible by - public static let title = RuuviLocalization.tr("Localizable", "Defaults.AskReviewIfLaunchDivisibleBy.Count.title", fallback: "Ask review if app launch divisible by") - } - } - public enum CardsSwipeHint { - /// Cards Swipe Hint Was Shown - public static let title = RuuviLocalization.tr("Localizable", "Defaults.CardsSwipeHint.title", fallback: "Cards Swipe Hint Was Shown") - } - public enum ChartDurationHours { - /// Chart Duration - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartDurationHours.title", fallback: "Chart Duration") - } - public enum ChartIntervalSeconds { - /// Chart Interval - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartIntervalSeconds.title", fallback: "Chart Interval") - } - public enum ChartsSwipeInstructionWasShown { - /// Charts Swipe Hint Was Shown - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartsSwipeInstructionWasShown.title", fallback: "Charts Swipe Hint Was Shown") - } - public enum ConnectionTimeout { - /// Connection Timeout - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ConnectionTimeout.title", fallback: "Connection Timeout") - } - public enum DashboardTapActionChart { - /// Show Chart on Dashboard Card Tap - public static let title = RuuviLocalization.tr("Localizable", "Defaults.DashboardTapActionChart.title", fallback: "Show Chart on Dashboard Card Tap") - } - public enum DevServer { - /// Changing Ruuvi Cloud endpoint requires signing out from current session and restart the app. Are you sure? - public static let message = RuuviLocalization.tr("Localizable", "Defaults.DevServer.message", fallback: "Changing Ruuvi Cloud endpoint requires signing out from current session and restart the app. Are you sure?") - /// Use Dev Server - public static let title = RuuviLocalization.tr("Localizable", "Defaults.DevServer.title", fallback: "Use Dev Server") - } - public enum HideNFC { - /// Hide NFC Option for sensor contest - public static let title = RuuviLocalization.tr("Localizable", "Defaults.HideNFC.title", fallback: "Hide NFC Option for sensor contest") + /// Operation failed. + public static let activityFailedGeneric = RuuviLocalization.tr("Localizable", "activity_failed_generic", fallback: "Operation failed.") + /// Please wait... + public static let activityOngoingGeneric = RuuviLocalization.tr("Localizable", "activity_ongoing_generic", fallback: "Please wait...") + /// Couldn't save changes to cloud. + public static let activitySavingFail = RuuviLocalization.tr("Localizable", "activity_saving_fail", fallback: "Couldn't save changes to cloud.") + /// Saved successfully. + public static let activitySavingSuccess = RuuviLocalization.tr("Localizable", "activity_saving_success", fallback: "Saved successfully.") + /// Saving to cloud...please wait. + public static let activitySavingToCloud = RuuviLocalization.tr("Localizable", "activity_saving_to_cloud", fallback: "Saving to cloud...please wait.") + /// Operation successful. + public static let activitySuccessGeneric = RuuviLocalization.tr("Localizable", "activity_success_generic", fallback: "Operation successful.") + /// Add a Sensor + public static let addASensor = RuuviLocalization.tr("Localizable", "add_a_sensor", fallback: "Add a Sensor") + /// Add Sensor + public static let addSensor = RuuviLocalization.tr("Localizable", "add_sensor", fallback: "Add Sensor") + /// This page shows nearby Ruuvi sensors not yet added to the app. Tap a sensor to add it. + public static let addSensorDescription = RuuviLocalization.tr("Localizable", "add_sensor_description", fallback: "This page shows nearby Ruuvi sensors not yet added to the app. Tap a sensor to add it.") + /// This sensor cannot be added with NFC due to old firmware. Please add the sensor with Bluetooth and update firmware. + public static let addSensorNfcDf3Error = RuuviLocalization.tr("Localizable", "add_sensor_nfc_df3_error", fallback: "This sensor cannot be added with NFC due to old firmware. Please add the sensor with Bluetooth and update firmware.") + /// Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone. + public static let addSensorViaNfc = RuuviLocalization.tr("Localizable", "add_sensor_via_nfc", fallback: "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone.") + /// Add with NFC + public static let addWithNfc = RuuviLocalization.tr("Localizable", "add_with_nfc", fallback: "Add with NFC") + /// ago + public static let ago = RuuviLocalization.tr("Localizable", "ago", fallback: "ago") + /// Alert if sensor data hasn't been updated to the cloud for longer than %d minutes. + public static func alertCloudConnectionDescription(_ p1: Int) -> String { + RuuviLocalization.tr("Localizable", "alert_cloud_connection_description", p1, fallback: "Alert if sensor data hasn't been updated to the cloud for longer than %d minutes.") } - public enum Interval { - public enum Hour { - /// h - public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Hour.string", fallback: "h") - } - public enum Min { - /// min - public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Min.string", fallback: "min") - } - public enum Sec { - /// sec - public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Sec.string", fallback: "sec") - } - } - public enum PruningOffsetHours { - /// Pruning Offset Hours - public static let title = RuuviLocalization.tr("Localizable", "Defaults.PruningOffsetHours.title", fallback: "Pruning Offset Hours") - } - public enum ServiceTimeout { - /// Service Timeout - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ServiceTimeout.title", fallback: "Service Timeout") - } - public enum ShowEmailAlertsSettings { - /// Show email alerts settings - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ShowEmailAlertsSettings.title", fallback: "Show email alerts settings") - } - public enum ShowPushAlertsSettings { - /// Show push alerts settings - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ShowPushAlertsSettings.title", fallback: "Show push alerts settings") - } - public enum UserAuthorized { - /// User Authorized - public static let title = RuuviLocalization.tr("Localizable", "Defaults.UserAuthorized.title", fallback: "User Authorized") - } - public enum WebPullInterval { - /// Web Alerts Interval - public static let title = RuuviLocalization.tr("Localizable", "Defaults.WebPullInterval.title", fallback: "Web Alerts Interval") - } - public enum WelcomeShown { - /// Welcome Displayed - public static let title = RuuviLocalization.tr("Localizable", "Defaults.WelcomeShown.title", fallback: "Welcome Displayed") - } - public enum NavigationItem { - /// Defaults - public static let title = RuuviLocalization.tr("Localizable", "Defaults.navigationItem.title", fallback: "Defaults") - } - } - public enum Devices { - /// Token Id - public static let tokenId = RuuviLocalization.tr("Localizable", "Devices.tokenId", fallback: "Token Id") - } - public enum DfuDevicesScanner { - public enum BluetoothDisabled { - /// (Bluetooth is disabled) - public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabled.text", fallback: "(Bluetooth is disabled)") - } - public enum BluetoothDisabledAlert { - /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. - public static let message = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") - /// Bluetooth is not enabled - public static let title = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") - } - public enum Description { - /// Find and select sensor "RuuviBoot". - public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.Description.text", fallback: "Find and select sensor \"RuuviBoot\".") - } - public enum NoDevice { - /// (No sensors in Bluetooth range) - public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.NoDevice.text", fallback: "(No sensors in Bluetooth range)") - } - public enum Title { - /// Devices - public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.Title.text", fallback: "Devices") - } - } - public enum DfuFlash { - public enum Cancel { - /// CANCEL - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Cancel.text", fallback: "CANCEL") - } - public enum CancelAlert { - /// Are you sure you want to cancel the firmware update process? - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.CancelAlert.text", fallback: "Are you sure you want to cancel the firmware update process?") - } - public enum Finish { - /// FINISH - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Finish.text", fallback: "FINISH") - } - public enum FinishGuide { - /// Firmware update process has been completed successfully. - /// Your RuuviTag sensor is ready for use! - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.FinishGuide.text", fallback: "Firmware update process has been completed successfully.\nYour RuuviTag sensor is ready for use!") - } - public enum Firmware { - public enum BootloaderSize { - /// Bootloader size - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.BootloaderSize.text", fallback: "Bootloader size") - } - public enum FileName { - /// File name - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.FileName.text", fallback: "File name") - } - public enum Parts { - /// Parts - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.Parts.text", fallback: "Parts") - } - public enum Size { - /// Size - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.Size.text", fallback: "Size") - } - public enum SoftDeviceSize { - /// Soft Device size - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.SoftDeviceSize.text", fallback: "Soft Device size") - } - } - public enum FirmwareSelectionGuide { - /// Locate the previously downloaded ZIP file on your mobile device. - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.FirmwareSelectionGuide.text", fallback: "Locate the previously downloaded ZIP file on your mobile device.") - } - public enum OpenDocumentPicker { - /// OPEN DOCUMENT PICKER - public static let title = RuuviLocalization.tr("Localizable", "DfuFlash.OpenDocumentPicker.title", fallback: "OPEN DOCUMENT PICKER") - } - public enum Progress { - /// Progress - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Progress.text", fallback: "Progress") - } - public enum Start { - /// Start - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Start.text", fallback: "Start") - } - public enum Step { - /// Step - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Step.text", fallback: "Step") - } - public enum Steps { - public enum Completed { - /// Completed - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.Completed.text", fallback: "Completed") - } - public enum PackageSelection { - /// Package selection - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.PackageSelection.text", fallback: "Package selection") - } - public enum ReadyForUpload { - /// Ready For upload - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.ReadyForUpload.text", fallback: "Ready For upload") - } - public enum Uploading { - /// Uploading - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.Uploading.text", fallback: "Uploading") - } - } - public enum Title { - /// DFU Flash - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Title.text", fallback: "DFU Flash") - } - } - public enum DiscoverTable { - public enum BluetoothDisabledAlert { - /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. - public static let message = RuuviLocalization.tr("Localizable", "DiscoverTable.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") - /// Bluetooth is not enabled - public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") - } - public enum GetMoreSensors { - public enum Button { - /// Buy Ruuvi Sensors - public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.GetMoreSensors.button.title", fallback: "Buy Ruuvi Sensors") - } - } - public enum NavigationItem { - /// Add a New Sensor - public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.NavigationItem.title", fallback: "Add a New Sensor") - } - public enum NoDevicesSection { - public enum BluetoothDisabled { - /// (Bluetooth is disabled) - public static let text = RuuviLocalization.tr("Localizable", "DiscoverTable.NoDevicesSection.BluetoothDisabled.text", fallback: "(Bluetooth is disabled)") - } - public enum NotFound { - /// (No sensors in Bluetooth range) - public static let text = RuuviLocalization.tr("Localizable", "DiscoverTable.NoDevicesSection.NotFound.text", fallback: "(No sensors in Bluetooth range)") - } - } - public enum RuuviDevice { - /// Ruuvi - public static let `prefix` = RuuviLocalization.tr("Localizable", "DiscoverTable.RuuviDevice.prefix", fallback: "Ruuvi") - } - public enum SectionTitle { - /// Nearby Ruuvi sensors - public static let devices = RuuviLocalization.tr("Localizable", "DiscoverTable.SectionTitle.Devices", fallback: "Nearby Ruuvi sensors") - /// Virtual sensors - public static let webTags = RuuviLocalization.tr("Localizable", "DiscoverTable.SectionTitle.WebTags", fallback: "Virtual sensors") - } - public enum WebTagsInfoDialog { - /// Virtual Sensors show public weather data provided by local weather stations. - public static let message = RuuviLocalization.tr("Localizable", "DiscoverTable.WebTagsInfoDialog.message", fallback: "Virtual Sensors show public weather data provided by local weather stations.") - } - } - public enum ErrorPresenterAlert { - /// Error - public static let error = RuuviLocalization.tr("Localizable", "ErrorPresenterAlert.Error", fallback: "Error") + + /// Enter the desired delay to be used in minutes before alert is triggered. Minimum value is 2 minutes. + public static let alertCloudConnectionDialogDescription = RuuviLocalization.tr("Localizable", "alert_cloud_connection_dialog_description", fallback: "Enter the desired delay to be used in minutes before alert is triggered. Minimum value is 2 minutes.") + /// Set cloud connection alert + public static let alertCloudConnectionDialogTitle = RuuviLocalization.tr("Localizable", "alert_cloud_connection_dialog_title", fallback: "Set cloud connection alert") + /// Cloud Connection + public static let alertCloudConnectionTitle = RuuviLocalization.tr("Localizable", "alert_cloud_connection_title", fallback: "Cloud Connection") + /// Air Humidity is above %@ + public static func alertNotificationHumidityHighThreshold(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "alert_notification_humidity_high_threshold", String(describing: p1), fallback: "Air Humidity is above %@") + } + + /// Air Humidity is below %@ + public static func alertNotificationHumidityLowThreshold(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "alert_notification_humidity_low_threshold", String(describing: p1), fallback: "Air Humidity is below %@") + } + + /// Air Pressure is above %@ + public static func alertNotificationPressureHighThreshold(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "alert_notification_pressure_high_threshold", String(describing: p1), fallback: "Air Pressure is above %@") + } + + /// Air Pressure is below %@ + public static func alertNotificationPressureLowThreshold(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "alert_notification_pressure_low_threshold", String(describing: p1), fallback: "Air Pressure is below %@") + } + + /// Signal strength is above %@ + public static func alertNotificationRssiHighThreshold(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "alert_notification_rssi_high_threshold", String(describing: p1), fallback: "Signal strength is above %@") + } + + /// Signal strength is below %@ + public static func alertNotificationRssiLowThreshold(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "alert_notification_rssi_low_threshold", String(describing: p1), fallback: "Signal strength is below %@") + } + + /// Temperature is above %@ + public static func alertNotificationTemperatureHighThreshold(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "alert_notification_temperature_high_threshold", String(describing: p1), fallback: "Temperature is above %@") + } + + /// Temperature is below %@ + public static func alertNotificationTemperatureLowThreshold(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "alert_notification_temperature_low_threshold", String(describing: p1), fallback: "Temperature is below %@") + } + + /// All + public static let all = RuuviLocalization.tr("Localizable", "all", fallback: "All") + /// App Theme + public static let appTheme = RuuviLocalization.tr("Localizable", "app_theme", fallback: "App Theme") + /// Read more about Ruuvi account benefits or sign in later + public static let benefitsSignIn = RuuviLocalization.tr("Localizable", "benefits_sign_in", fallback: "Read more about Ruuvi account benefits or sign in later") + /// Bluetooth download + public static let bluetoothDownload = RuuviLocalization.tr("Localizable", "bluetooth_download", fallback: "Bluetooth download") + /// Local sensor data can be downloaded, when you're within its Bluetooth range. + public static let bluetoothDownloadDescription = RuuviLocalization.tr("Localizable", "bluetooth_download_description", fallback: "Local sensor data can be downloaded, when you're within its Bluetooth range.") + /// Cancel + public static let cancel = RuuviLocalization.tr("Localizable", "Cancel", fallback: "Cancel") + /// Card action + public static let cardAction = RuuviLocalization.tr("Localizable", "card_action", fallback: "Card action") + /// Card type + public static let cardType = RuuviLocalization.tr("Localizable", "card_type", fallback: "Card type") + /// Change background + public static let changeBackground = RuuviLocalization.tr("Localizable", "change_background", fallback: "Change background") + /// Change background image + public static let changeBackgroundImage = RuuviLocalization.tr("Localizable", "change_background_image", fallback: "Change background image") + /// Select background image. If you're not signed in, you'll lose the image in case of app reinstall. + public static let changeBackgroundMessage = RuuviLocalization.tr("Localizable", "change_background_message", fallback: "Select background image. If you're not signed in, you'll lose the image in case of app reinstall.") + /// (changelog) + public static let changelog = RuuviLocalization.tr("Localizable", "changelog", fallback: "(changelog)") + /// https://f.ruuvi.com/t/3192 + public static let changelogIosUrl = RuuviLocalization.tr("Localizable", "changelog_ios_url", fallback: "https://f.ruuvi.com/t/3192") + /// Average + public static let chartStatAvg = RuuviLocalization.tr("Localizable", "chart_stat_avg", fallback: "Average") + /// Hide min/max/avg + public static let chartStatHide = RuuviLocalization.tr("Localizable", "chart_stat_hide", fallback: "Hide min/max/avg") + /// Max + public static let chartStatMax = RuuviLocalization.tr("Localizable", "chart_stat_max", fallback: "Max") + /// Min + public static let chartStatMin = RuuviLocalization.tr("Localizable", "chart_stat_min", fallback: "Min") + /// Show min/max/avg + public static let chartStatShow = RuuviLocalization.tr("Localizable", "chart_stat_show", fallback: "Show min/max/avg") + /// Checking claim state + public static let checkClaimState = RuuviLocalization.tr("Localizable", "check_claim_state", fallback: "Checking claim state") + /// Claiming in progress + public static let claimInProgress = RuuviLocalization.tr("Localizable", "claim_in_progress", fallback: "Claiming in progress") + /// Claim sensor ownership + public static let claimSensorOwnership = RuuviLocalization.tr("Localizable", "claim_sensor_ownership", fallback: "Claim sensor ownership") + /// Secure the ownership information of your sensors by claiming their ownerships in the app. + public static let claimWarning = RuuviLocalization.tr("Localizable", "claim_warning", fallback: "Secure the ownership information of your sensors by claiming their ownerships in the app.") + /// You are scanning different RuuviTag + public static let claimWrongSensorScanned = RuuviLocalization.tr("Localizable", "claim_wrong_sensor_scanned", fallback: "You are scanning different RuuviTag") + /// Clear local history + public static let clearLocalHistory = RuuviLocalization.tr("Localizable", "clear_local_history", fallback: "Clear local history") + /// Do you want to clear locally stored history data from the app? This won't clear internally stored history from the sensor or history data stored on the Ruuvi Cloud service. + public static let clearLocalHistoryDescription = RuuviLocalization.tr("Localizable", "clear_local_history_description", fallback: "Do you want to clear locally stored history data from the app? This won't clear internally stored history from the sensor or history data stored on the Ruuvi Cloud service.") + /// Clear history view + public static let clearView = RuuviLocalization.tr("Localizable", "clear_view", fallback: "Clear history view") + /// Close + public static let close = RuuviLocalization.tr("Localizable", "Close", fallback: "Close") + /// ● Background images + public static let cloudStoredAlerts = RuuviLocalization.tr("Localizable", "cloud_stored_alerts", fallback: "● Background images") + /// ● Alert settings + public static let cloudStoredBackgrounds = RuuviLocalization.tr("Localizable", "cloud_stored_backgrounds", fallback: "● Alert settings") + /// ● Calibration settings + public static let cloudStoredCalibration = RuuviLocalization.tr("Localizable", "cloud_stored_calibration", fallback: "● Calibration settings") + /// ● Custom names + public static let cloudStoredNames = RuuviLocalization.tr("Localizable", "cloud_stored_names", fallback: "● Custom names") + /// ● Sensor ownerships + public static let cloudStoredOwnerships = RuuviLocalization.tr("Localizable", "cloud_stored_ownerships", fallback: "● Sensor ownerships") + /// ● App settings + public static let cloudStoredSharing = RuuviLocalization.tr("Localizable", "cloud_stored_sharing", fallback: "● App settings") + /// Confirm + public static let confirm = RuuviLocalization.tr("Localizable", "Confirm", fallback: "Confirm") + /// Copy + public static let copy = RuuviLocalization.tr("Localizable", "Copy", fallback: "Copy") + /// Copy MAC Address + public static let copyMacAddress = RuuviLocalization.tr("Localizable", "copy_mac_address", fallback: "Copy MAC Address") + /// Copy Unique ID + public static let copyUniqueId = RuuviLocalization.tr("Localizable", "copy_unique_id", fallback: "Copy Unique ID") + /// Dark theme + public static let darkTheme = RuuviLocalization.tr("Localizable", "dark_theme", fallback: "Dark theme") + /// Seems that you don't have any Ruuvi sensors added yet. + public static let dashboardNoSensorsMessage = RuuviLocalization.tr("Localizable", "dashboard_no_sensors_message", fallback: "Seems that you don't have any Ruuvi sensors added yet.") + /// You are not signed in. + /// + /// If you have an account and have already added Ruuvi sensors to it, they will automatically synchronise with Ruuvi Station mobile app when you sign in. + public static let dashboardNoSensorsMessageSignedOut = RuuviLocalization.tr("Localizable", "dashboard_no_sensors_message_signed_out", fallback: "You are not signed in.\n\nIf you have an account and have already added Ruuvi sensors to it, they will automatically synchronise with Ruuvi Station mobile app when you sign in.") + /// 1 day + public static let day1 = RuuviLocalization.tr("Localizable", "day_1", fallback: "1 day") + /// 10 days + public static let day10 = RuuviLocalization.tr("Localizable", "day_10", fallback: "10 days") + /// 2 days + public static let day2 = RuuviLocalization.tr("Localizable", "day_2", fallback: "2 days") + /// 3 days + public static let day3 = RuuviLocalization.tr("Localizable", "day_3", fallback: "3 days") + /// 4 days + public static let day4 = RuuviLocalization.tr("Localizable", "day_4", fallback: "4 days") + /// 5 days + public static let day5 = RuuviLocalization.tr("Localizable", "day_5", fallback: "5 days") + /// 6 days + public static let day6 = RuuviLocalization.tr("Localizable", "day_6", fallback: "6 days") + /// 7 days + public static let day7 = RuuviLocalization.tr("Localizable", "day_7", fallback: "7 days") + /// 8 days + public static let day8 = RuuviLocalization.tr("Localizable", "day_8", fallback: "8 days") + /// 9 days + public static let day9 = RuuviLocalization.tr("Localizable", "day_9", fallback: "9 days") + /// %.0f days + public static func dayX(_ p1: Float) -> String { + RuuviLocalization.tr("Localizable", "day_x", p1, fallback: "%.0f days") + } + + /// dBm + public static let dBm = RuuviLocalization.tr("Localizable", "dBm", fallback: "dBm") + /// Are you sure? + public static let dialogAreYouSure = RuuviLocalization.tr("Localizable", "dialog_are_you_sure", fallback: "Are you sure?") + /// This operation cannot be undone. + public static let dialogOperationUndone = RuuviLocalization.tr("Localizable", "dialog_operation_undone", fallback: "This operation cannot be undone.") + /// Don't show this again + public static let doNotShowAgain = RuuviLocalization.tr("Localizable", "do_not_show_again", fallback: "Don't show this again") + /// Do you own this sensor? + public static let doYouOwnSensor = RuuviLocalization.tr("Localizable", "do_you_own_sensor", fallback: "Do you own this sensor?") + /// Done + public static let done = RuuviLocalization.tr("Localizable", "Done", fallback: "Done") + /// Download + public static let download = RuuviLocalization.tr("Localizable", "download", fallback: "Download") + /// No data available + /// in the selected history window. + public static let emptyChartMessage = RuuviLocalization.tr("Localizable", "empty_chart_message", fallback: "No data available \nin the selected history window.") + /// Enter Code + public static let enterCode = RuuviLocalization.tr("Localizable", "enter_code", fallback: "Enter Code") + /// You can export a sensor's history from its history graph page. Tap the three dots menu icon in the top right corner, and then select "Export history (csv)". + public static let exportCsvFeatureLocation = RuuviLocalization.tr("Localizable", "export_csv_feature_location", fallback: "You can export a sensor's history from its history graph page. Tap the three dots menu icon in the top right corner, and then select \"Export history (csv)\".") + /// Export history (csv) + public static let exportHistory = RuuviLocalization.tr("Localizable", "export_history", fallback: "Export history (csv)") + /// Firmware Version: + public static let firmwareVersion = RuuviLocalization.tr("Localizable", "firmware_version", fallback: "Firmware Version:") + /// System theme + public static let followSystemTheme = RuuviLocalization.tr("Localizable", "follow_system_theme", fallback: "System theme") + /// Force Claim + public static let forceClaim = RuuviLocalization.tr("Localizable", "force_claim", fallback: "Force Claim") + /// Force Claim Sensor + public static let forceClaimSensor = RuuviLocalization.tr("Localizable", "force_claim_sensor", fallback: "Force Claim Sensor") + /// This sensor has been claimed by another user. You can force the ownership to your account if you have physical access to this sensor. Each Ruuvi sensor can have only one owner. + public static let forceClaimSensorDescription1 = RuuviLocalization.tr("Localizable", "force_claim_sensor_description1", fallback: "This sensor has been claimed by another user. You can force the ownership to your account if you have physical access to this sensor. Each Ruuvi sensor can have only one owner.") + /// Force Claim is done by using Near-Field Communication (NFC). Make sure NFC is enabled on your mobile device. + /// + /// 1. Touch your Ruuvi sensor with your mobile device to start the claiming process. + /// + /// 2. When successfully claimed, you will be sent back to Sensor Settings. + /// + /// If claiming was unsuccessful or NFC is not available on your device: + /// + /// 1. Open the cover of your Ruuvi sensor. + /// + /// 2. Locate the round black button (or button "B" in case your sensor has 2 buttons) on the white circuit board and press it briefly, then tap on Use BT button to start the claiming process. + /// + /// 3. When successfully claimed you will be sent back to Sensor Settings. + public static let forceClaimSensorDescription2 = RuuviLocalization.tr("Localizable", "force_claim_sensor_description2", fallback: "Force Claim is done by using Near-Field Communication (NFC). Make sure NFC is enabled on your mobile device.\n\n\t1. Touch your Ruuvi sensor with your mobile device to start the claiming process.\n\n\t2. When successfully claimed, you will be sent back to Sensor Settings.\n\nIf claiming was unsuccessful or NFC is not available on your device:\n\n\t1. Open the cover of your Ruuvi sensor.\n\n\t2. Locate the round black button (or button \"B\" in case your sensor has 2 buttons) on the white circuit board and press it briefly, then tap on Use BT button to start the claiming process.\n\n\t3. When successfully claimed you will be sent back to Sensor Settings.") + /// Full image view + public static let fullImageView = RuuviLocalization.tr("Localizable", "full_image_view", fallback: "Full image view") + /// g + public static let g = RuuviLocalization.tr("Localizable", "g", fallback: "g") + /// g/m³ + public static let gm³ = RuuviLocalization.tr("Localizable", "g/m³", fallback: "g/m³") + /// Ruuvi Station downloads the internal history of the sensor for the last 10 days if the measurement history is available. + /// + /// The history is downloaded using a Bluetooth connection. Make sure you are near the sensor. + public static let gattSyncDescription = RuuviLocalization.tr("Localizable", "gatt_sync_description", fallback: "Ruuvi Station downloads the internal history of the sensor for the last 10 days if the measurement history is available.\n\nThe history is downloaded using a Bluetooth connection. Make sure you are near the sensor.") + /// Go to sensor card + public static let goToSensor = RuuviLocalization.tr("Localizable", "go_to_sensor", fallback: "Go to sensor card") + /// h + public static let h = RuuviLocalization.tr("Localizable", "h", fallback: "h") + /// History view + public static let historyView = RuuviLocalization.tr("Localizable", "history_view", fallback: "History view") + /// Hour + public static let hour = RuuviLocalization.tr("Localizable", "hour", fallback: "Hour") + /// Hours + public static let hours = RuuviLocalization.tr("Localizable", "hours", fallback: "Hours") + /// hPa + public static let hPa = RuuviLocalization.tr("Localizable", "hPa", fallback: "hPa") + /// Image cards + public static let imageCards = RuuviLocalization.tr("Localizable", "image_cards", fallback: "Image cards") + /// Internet connection problem + public static let internetConnectionProblem = RuuviLocalization.tr("Localizable", "internet_connection_problem", fallback: "Internet connection problem") + /// Let's Sign In + public static let letsDoIt = RuuviLocalization.tr("Localizable", "lets_do_it", fallback: "Let's Sign In") + /// Light theme + public static let lightTheme = RuuviLocalization.tr("Localizable", "light_theme", fallback: "Light theme") + /// Ruuvi Station mobile app supports maximum 10 days of history. Ruuvi Cloud subscribers are able to view up to 2 years of historical data using web app at ruuvi.com/station (requires Ruuvi Gateway router). + public static let longerHistoryMessage = RuuviLocalization.tr("Localizable", "longer_history_message", fallback: "Ruuvi Station mobile app supports maximum 10 days of history. Ruuvi Cloud subscribers are able to view up to 2 years of historical data using web app at ruuvi.com/station (requires Ruuvi Gateway router).") + /// Longer history + public static let longerHistoryTitle = RuuviLocalization.tr("Localizable", "longer_history_title", fallback: "Longer history") + /// Low battery + public static let lowBattery = RuuviLocalization.tr("Localizable", "low_battery", fallback: "Low battery") + /// Mac Address: + public static let macAddress = RuuviLocalization.tr("Localizable", "mac_address", fallback: "Mac Address:") + /// min + public static let min = RuuviLocalization.tr("Localizable", "min", fallback: "min") + /// Minutes + public static let minutes = RuuviLocalization.tr("Localizable", "minutes", fallback: "Minutes") + /// More... + public static let more = RuuviLocalization.tr("Localizable", "more", fallback: "More...") + /// - + public static let na = RuuviLocalization.tr("Localizable", "N/A", fallback: "-") + /// Name: + public static let name = RuuviLocalization.tr("Localizable", "name", fallback: "Name:") + /// Only sensors within range of your Ruuvi Gateway can be shared. + public static let networkSharingDisabled = RuuviLocalization.tr("Localizable", "network_sharing_disabled", fallback: "Only sensors within range of your Ruuvi Gateway can be shared.") + /// No + public static let no = RuuviLocalization.tr("Localizable", "No", fallback: "No") + /// A free account will be created for this email if you don't already have one. Only email address is required. We keep your information safe. + public static let noPasswordNeeded = RuuviLocalization.tr("Localizable", "no_password_needed", fallback: "A free account will be created for this email if you don't already have one. Only email address is required. We keep your information safe.") + /// Note! + public static let note = RuuviLocalization.tr("Localizable", "note", fallback: "Note!") + /// Off + public static let off = RuuviLocalization.tr("Localizable", "Off", fallback: "Off") /// OK - public static let ok = RuuviLocalization.tr("Localizable", "ErrorPresenterAlert.OK", fallback: "OK") - } - public enum ExpectedError { - /// Unable to remove a connected device that is not reachable. Please check your Bluetooth connection. - public static let failedToDeleteTag = RuuviLocalization.tr("Localizable", "ExpectedError.failedToDeleteTag", fallback: "Unable to remove a connected device that is not reachable. Please check your Bluetooth connection.") - /// App is already in the process of syncing logs with this sensor - public static let isAlreadySyncingLogsWithThisTag = RuuviLocalization.tr("Localizable", "ExpectedError.isAlreadySyncingLogsWithThisTag", fallback: "App is already in the process of syncing logs with this sensor") - /// Missing OpenWeatherMap API Key. Please get one from openweathermap.org website and enter it in the station/Classes/Networking/Assembly/Networking.plist file - public static let missingOpenWeatherMapAPIKey = RuuviLocalization.tr("Localizable", "ExpectedError.missingOpenWeatherMapAPIKey", fallback: "Missing OpenWeatherMap API Key. Please get one from openweathermap.org website and enter it in the station/Classes/Networking/Assembly/Networking.plist file") - } - public enum ExportService { - /// Acceleration X - public static let accelerationX = RuuviLocalization.tr("Localizable", "ExportService.AccelerationX", fallback: "Acceleration X") - /// Acceleration Y - public static let accelerationY = RuuviLocalization.tr("Localizable", "ExportService.AccelerationY", fallback: "Acceleration Y") - /// Acceleration Z - public static let accelerationZ = RuuviLocalization.tr("Localizable", "ExportService.AccelerationZ", fallback: "Acceleration Z") - /// Date - public static let date = RuuviLocalization.tr("Localizable", "ExportService.Date", fallback: "Date") - /// Dew point (%@) - public static func dewPoint(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "ExportService.DewPoint", String(describing: p1), fallback: "Dew point (%@)") - } - /// Humidity (%@) - public static func humidity(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "ExportService.Humidity", String(describing: p1), fallback: "Humidity (%@)") - } - /// ISO8601 - public static let iso8601 = RuuviLocalization.tr("Localizable", "ExportService.ISO8601", fallback: "ISO8601") - /// Measurement Sequence Number - public static let measurementSequenceNumber = RuuviLocalization.tr("Localizable", "ExportService.MeasurementSequenceNumber", fallback: "Measurement Sequence Number") - /// Movement Counter - public static let movementCounter = RuuviLocalization.tr("Localizable", "ExportService.MovementCounter", fallback: "Movement Counter") - /// Pressure (%@) - public static func pressure(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "ExportService.Pressure", String(describing: p1), fallback: "Pressure (%@)") - } - /// Temperature (%@) - public static func temperature(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "ExportService.Temperature", String(describing: p1), fallback: "Temperature (%@)") - } - /// TX Power - public static let txPower = RuuviLocalization.tr("Localizable", "ExportService.TXPower", fallback: "TX Power") - /// Voltage (V) - public static let voltage = RuuviLocalization.tr("Localizable", "ExportService.Voltage", fallback: "Voltage (V)") - } - public enum Foreground { - public enum Interval { - public enum All { - /// All - public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.All.string", fallback: "All") - } - public enum Every { - /// Every - public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.Every.string", fallback: "Every") - } - public enum Min { - /// min - public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.Min.string", fallback: "min") - } - } - public enum NavigationItem { - /// Foreground - public static let title = RuuviLocalization.tr("Localizable", "Foreground.navigationItem.title", fallback: "Foreground") - } - } - public enum ForegroundRow { - public enum Advertisement { - /// ADVERTISEMENTS - public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.advertisement.section", fallback: "ADVERTISEMENTS") - /// Save advertisements - public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.advertisement.title", fallback: "Save advertisements") - } - public enum Connection { - /// LOGS - public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.connection.section", fallback: "LOGS") - /// Connect and sync logs - public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.connection.title", fallback: "Connect and sync logs") - } - public enum WebTags { - /// VIRTUAL SENSORS - public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.webTags.section", fallback: "VIRTUAL SENSORS") - /// Load and save from web - public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.webTags.title", fallback: "Load and save from web") - } - } - public enum Heartbeat { + public static let ok = RuuviLocalization.tr("Localizable", "OK", fallback: "OK") + /// On + public static let on = RuuviLocalization.tr("Localizable", "On", fallback: "On") + /// Bring your favorite sensors to your Home Screen and Lock Screen as + public static let onboardingAccessWidgets = RuuviLocalization.tr("Localizable", "onboarding_access_widgets", fallback: "Bring your favorite sensors to your Home Screen and Lock Screen as") + /// Alerts + public static let onboardingAlerts = RuuviLocalization.tr("Localizable", "onboarding_alerts", fallback: "Alerts") + /// Next + public static let onboardingContinue = RuuviLocalization.tr("Localizable", "onboarding_continue", fallback: "Next") + /// Dashboard + public static let onboardingDashboard = RuuviLocalization.tr("Localizable", "onboarding_dashboard", fallback: "Dashboard") + /// Explore your measurement + public static let onboardingExploreDetailed = RuuviLocalization.tr("Localizable", "onboarding_explore_detailed", fallback: "Explore your measurement") + /// View all sensors at a glance on your + public static let onboardingFollowMeasurement = RuuviLocalization.tr("Localizable", "onboarding_follow_measurement", fallback: "View all sensors at a glance on your") + /// A Ruuvi Gateway router is required. + public static let onboardingGatewayRequired = RuuviLocalization.tr("Localizable", "onboarding_gateway_required", fallback: "A Ruuvi Gateway router is required.") + /// Ruuvi experience is better when you're signed in. Do it now or continue without cloud features. + public static let onboardingGoToSignIn = RuuviLocalization.tr("Localizable", "onboarding_go_to_sign_in", fallback: "Ruuvi experience is better when you're signed in. Do it now or continue without cloud features.") + /// Let's start measuring! + public static let onboardingGoToSignInAlreadySignedIn = RuuviLocalization.tr("Localizable", "onboarding_go_to_sign_in_already_signed_in", fallback: "Let's start measuring!") + /// Widgets + public static let onboardingHandyWidgets = RuuviLocalization.tr("Localizable", "onboarding_handy_widgets", fallback: "Widgets") + /// History + public static let onboardingHistory = RuuviLocalization.tr("Localizable", "onboarding_history", fallback: "History") + /// Measure Your World + public static let onboardingMeasureYourWorld = RuuviLocalization.tr("Localizable", "onboarding_measure_your_world", fallback: "Measure Your World") + /// Personalise + public static let onboardingPersonalise = RuuviLocalization.tr("Localizable", "onboarding_personalise", fallback: "Personalise") + /// Read Your Ruuvi Sensors + public static let onboardingReadSensorsData = RuuviLocalization.tr("Localizable", "onboarding_read_sensors_data", fallback: "Read Your Ruuvi Sensors") + /// Set and customise your + public static let onboardingSetCustom = RuuviLocalization.tr("Localizable", "onboarding_set_custom", fallback: "Set and customise your") + /// to measure together with your friends and family. + public static let onboardingShareYourSensors = RuuviLocalization.tr("Localizable", "onboarding_share_your_sensors", fallback: "to measure together with your friends and family.") + /// Share Sensors + public static let onboardingShareesCanUse = RuuviLocalization.tr("Localizable", "onboarding_sharees_can_use", fallback: "Share Sensors") + /// Skip + public static let onboardingSkip = RuuviLocalization.tr("Localizable", "onboarding_skip", fallback: "Skip") + /// Ruuvi Web App + public static let onboardingStationWeb = RuuviLocalization.tr("Localizable", "onboarding_station_web", fallback: "Ruuvi Web App") + /// Swipe to continue → + public static let onboardingSwipeToContinue = RuuviLocalization.tr("Localizable", "onboarding_swipe_to_continue", fallback: "Swipe to continue →") + /// Almost there! + public static let onboardingThatsIt = RuuviLocalization.tr("Localizable", "onboarding_thats_it", fallback: "Almost there!") + /// Let's get started! + public static let onboardingThatsItAlreadySignedIn = RuuviLocalization.tr("Localizable", "onboarding_thats_it_already_signed_in", fallback: "Let's get started!") + /// using Bluetooth or Ruuvi Cloud + public static let onboardingViaBluetoothOrCloud = RuuviLocalization.tr("Localizable", "onboarding_via_bluetooth_or_cloud", fallback: "using Bluetooth or Ruuvi Cloud") + /// Large dashboard, multi-year history, email alerts and more on + public static let onboardingWebPros = RuuviLocalization.tr("Localizable", "onboarding_web_pros", fallback: "Large dashboard, multi-year history, email alerts and more on") + /// Let's get to know your Ruuvi Station app. + public static let onboardingWithRuuviSensors = RuuviLocalization.tr("Localizable", "onboarding_with_ruuvi_sensors", fallback: "Let's get to know your Ruuvi Station app.") + /// your app with custom names and backgrounds. + public static let onboardingYourSensors = RuuviLocalization.tr("Localizable", "onboarding_your_sensors", fallback: "your app with custom names and backgrounds.") + /// Open history view + public static let openHistoryView = RuuviLocalization.tr("Localizable", "open_history_view", fallback: "Open history view") + /// Open sensor view + public static let openSensorView = RuuviLocalization.tr("Localizable", "open_sensor_view", fallback: "Open sensor view") + /// Owner's Ruuvi Plan + public static let ownersPlan = RuuviLocalization.tr("Localizable", "owners_plan", fallback: "Owner's Ruuvi Plan") + /// Reading Bluetooth: %.0f + public static func readingHistoryX(_ p1: Float) -> String { + RuuviLocalization.tr("Localizable", "reading_history_x", p1, fallback: "Reading Bluetooth: %.0f") + } + + /// Remove + public static let remove = RuuviLocalization.tr("Localizable", "Remove", fallback: "Remove") + /// By removing the sensor, your sensor ownership status will be revoked and sensor settings, such as name, background image, calibration settings and alert settings will be removed. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner. + public static let removeClaimedSensorDescription = RuuviLocalization.tr("Localizable", "remove_claimed_sensor_description", fallback: "By removing the sensor, your sensor ownership status will be revoked and sensor settings, such as name, background image, calibration settings and alert settings will be removed. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner.") + /// I also want to remove sensor history data from Ruuvi Cloud. + public static let removeCloudHistoryDescription = RuuviLocalization.tr("Localizable", "remove_cloud_history_description", fallback: "I also want to remove sensor history data from Ruuvi Cloud.") + /// Remove cloud history + public static let removeCloudHistoryTitle = RuuviLocalization.tr("Localizable", "remove_cloud_history_title", fallback: "Remove cloud history") + /// If you choose to remove this sensor, it will result in the deletion of your locally stored measurement history, along with the removal of any related sensor settings like name, background image, calibration, and alert configurations. + /// + /// You can add this sensor later again, if needed. + public static let removeLocalSensorDescription = RuuviLocalization.tr("Localizable", "remove_local_sensor_description", fallback: "If you choose to remove this sensor, it will result in the deletion of your locally stored measurement history, along with the removal of any related sensor settings like name, background image, calibration, and alert configurations.\n\nYou can add this sensor later again, if needed.") + /// If you choose to remove this shared sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore. + /// + /// You will also lose any related sensor settings like name, background image and alert configurations. + public static let removeSharedSensorDescription = RuuviLocalization.tr("Localizable", "remove_shared_sensor_description", fallback: "If you choose to remove this shared sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore.\n\nYou will also lose any related sensor settings like name, background image and alert configurations.") + /// Rename + public static let rename = RuuviLocalization.tr("Localizable", "rename", fallback: "Rename") + /// Request Code + public static let requestCode = RuuviLocalization.tr("Localizable", "request_code", fallback: "Request Code") + /// Using this alert requires you to be signed in to the app, and that you have claimed the ownership of this sensor and it's in the range of Ruuvi Gateway router. iOS devices are unable to indicate signal strength information of received data sent by Ruuvi sensor when sensor is paired and measurements are being received in the background. Realtime Bluetooth signal strength is shown in the app but doesn't affect this alert. + public static let rssiAlertDescription = RuuviLocalization.tr("Localizable", "rssi_alert_description", fallback: "Using this alert requires you to be signed in to the app, and that you have claimed the ownership of this sensor and it's in the range of Ruuvi Gateway router. iOS devices are unable to indicate signal strength information of received data sent by Ruuvi sensor when sensor is paired and measurements are being received in the background. Realtime Bluetooth signal strength is shown in the app but doesn't affect this alert.") + /// Ruuvi Cloud + public static let ruuviCloud = RuuviLocalization.tr("Localizable", "ruuvi_cloud", fallback: "Ruuvi Cloud") + /// s + public static let s = RuuviLocalization.tr("Localizable", "s", fallback: "s") + /// Select from default images + public static let selectDefaultImage = RuuviLocalization.tr("Localizable", "select_default_image", fallback: "Select from default images") + /// Select from phone gallery + public static let selectFromGallery = RuuviLocalization.tr("Localizable", "select_from_gallery", fallback: "Select from phone gallery") + /// Sensor Details + public static let sensorDetails = RuuviLocalization.tr("Localizable", "sensor_details", fallback: "Sensor Details") + /// Sensor not found. Try again. + public static let sensorNotFoundError = RuuviLocalization.tr("Localizable", "sensor_not_found_error", fallback: "Sensor not found. Try again.") + /// Signing in to the app has many advantages. Settings will be safely stored to your account: + public static let sensorsOwnershipAndSettingsStoredInCloud = RuuviLocalization.tr("Localizable", "sensors_ownership_and_settings_stored_in_cloud", fallback: "Signing in to the app has many advantages. Settings will be safely stored to your account:") + /// Limit alert notifications + public static let settingsAlertLimitNotification = RuuviLocalization.tr("Localizable", "settings_alert_limit_notification", fallback: "Limit alert notifications") + /// Trigger Bluetooth alert notification only once per hour even if alert was retriggered. + public static let settingsAlertLimitNotificationDescription = RuuviLocalization.tr("Localizable", "settings_alert_limit_notification_description", fallback: "Trigger Bluetooth alert notification only once per hour even if alert was retriggered.") + /// Alert Notifications + public static let settingsAlertNotifications = RuuviLocalization.tr("Localizable", "settings_alert_notifications", fallback: "Alert Notifications") + /// Alert Sound + public static let settingsAlertSound = RuuviLocalization.tr("Localizable", "settings_alert_sound", fallback: "Alert Sound") + /// System Default + public static let settingsAlertSoundDefault = RuuviLocalization.tr("Localizable", "settings_alert_sound_default", fallback: "System Default") + /// Select push notification alert sound. + public static let settingsAlertSoundDescription = RuuviLocalization.tr("Localizable", "settings_alert_sound_description", fallback: "Select push notification alert sound.") + /// Ruuvi Alert + public static let settingsAlertSoundRuuviSpeak = RuuviLocalization.tr("Localizable", "settings_alert_sound_ruuvi_speak", fallback: "Ruuvi Alert") + /// You can also adjust Notification settings under iOS Settings -> Notifications + public static let settingsAlertsFooterDescription = RuuviLocalization.tr("Localizable", "settings_alerts_footer_description", fallback: "You can also adjust Notification settings under iOS Settings -> Notifications") + /// iOS Settings -> Notifications + public static let settingsAlertsFooterDescriptionLinkMask = RuuviLocalization.tr("Localizable", "settings_alerts_footer_description_link_mask", fallback: "iOS Settings -> Notifications") + /// Settings & alerts + public static let settingsAndAlerts = RuuviLocalization.tr("Localizable", "settings_and_alerts", fallback: "Settings & alerts") + /// Appearance + public static let settingsAppearance = RuuviLocalization.tr("Localizable", "settings_appearance", fallback: "Appearance") + /// Email Alerts + public static let settingsEmailAlerts = RuuviLocalization.tr("Localizable", "settings_email_alerts", fallback: "Email Alerts") + /// If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive email alerts by enabling this. + public static let settingsEmailAlertsDescription = RuuviLocalization.tr("Localizable", "settings_email_alerts_description", fallback: "If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive email alerts by enabling this.") + /// Push Alerts + public static let settingsPushAlerts = RuuviLocalization.tr("Localizable", "settings_push_alerts", fallback: "Push Alerts") + /// If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive push alerts by enabling this. + public static let settingsPushAlertsDescription = RuuviLocalization.tr("Localizable", "settings_push_alerts_description", fallback: "If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive push alerts by enabling this.") + /// Share pending + public static let sharePending = RuuviLocalization.tr("Localizable", "share_pending", fallback: "Share pending") + /// Shared successfully! This email address isn't linked to a Ruuvi account yet. An invite to create a free account has been sent. Once created, you'll see it in the sharee listing. + public static let sharePendingMessage = RuuviLocalization.tr("Localizable", "share_pending_message", fallback: "Shared successfully! This email address isn't linked to a Ruuvi account yet. An invite to create a free account has been sent. Once created, you'll see it in the sharee listing.") + /// Shared to %d/%d + public static func sharedToX(_ p1: Int, _ p2: Int) -> String { + RuuviLocalization.tr("Localizable", "shared_to_x", p1, p2, fallback: "Shared to %d/%d") + } + + /// Continue + public static let signInContinue = RuuviLocalization.tr("Localizable", "sign_in_continue", fallback: "Continue") + /// Sign in or create a free Ruuvi account + public static let signInOrCreateFreeAccount = RuuviLocalization.tr("Localizable", "sign_in_or_create_free_account", fallback: "Sign in or create a free Ruuvi account") + /// Signal Strength (dBm) + public static let signalStrengthDbm = RuuviLocalization.tr("Localizable", "signal_strength_dbm", fallback: "Signal Strength (dBm)") + /// (Signing in is optional) + public static let signingInIsOptional = RuuviLocalization.tr("Localizable", "signing_in_is_optional", fallback: "(Signing in is optional)") + /// Simple cards + public static let simpleCards = RuuviLocalization.tr("Localizable", "simple_cards", fallback: "Simple cards") + /// Support + public static let support = RuuviLocalization.tr("Localizable", "support", fallback: "Support") + /// Synchronisation + public static let synchronisation = RuuviLocalization.tr("Localizable", "synchronisation", fallback: "Synchronisation") + /// Synchronised + public static let synchronized = RuuviLocalization.tr("Localizable", "Synchronized", fallback: "Synchronised") + /// Loading history from the cloud... + public static let syncing = RuuviLocalization.tr("Localizable", "Syncing...", fallback: "Loading history from the cloud...") + /// Take a photo + public static let takePhoto = RuuviLocalization.tr("Localizable", "take_photo", fallback: "Take a photo") + /// No password needed. + public static let toUseAllAppFeatures = RuuviLocalization.tr("Localizable", "to_use_all_app_features", fallback: "No password needed.") + /// Type your email.. + public static let typeYourEmail = RuuviLocalization.tr("Localizable", "type_your_email", fallback: "Type your email..") + /// Unclaim + public static let unclaim = RuuviLocalization.tr("Localizable", "unclaim", fallback: "Unclaim") + /// Unclaim sensor + public static let unclaimSensor = RuuviLocalization.tr("Localizable", "unclaim_sensor", fallback: "Unclaim sensor") + /// Ownership of this sensor has been claimed to your Ruuvi account. Press Unclaim to remove this sensor's settings and related data from your Ruuvi account. + public static let unclaimSensorDescription = RuuviLocalization.tr("Localizable", "unclaim_sensor_description", fallback: "Ownership of this sensor has been claimed to your Ruuvi account. Press Unclaim to remove this sensor's settings and related data from your Ruuvi account.") + /// Unique ID: + public static let uniqueId = RuuviLocalization.tr("Localizable", "unique_id", fallback: "Unique ID:") + /// Updated + public static let updated = RuuviLocalization.tr("Localizable", "Updated", fallback: "Updated") + /// Uploading: %.0f + public static func uploadingProgress(_ p1: Float) -> String { + RuuviLocalization.tr("Localizable", "uploading_progress", p1, fallback: "Uploading: %.0f") + } + + /// Use BT + public static let useBluetooth = RuuviLocalization.tr("Localizable", "use_bluetooth", fallback: "Use BT") + /// Use NFC + public static let useNfc = RuuviLocalization.tr("Localizable", "use_nfc", fallback: "Use NFC") + /// No thanks, skip + public static let useWithoutAccount = RuuviLocalization.tr("Localizable", "use_without_account", fallback: "No thanks, skip") + /// V + public static let v = RuuviLocalization.tr("Localizable", "V", fallback: "V") + /// View + public static let view = RuuviLocalization.tr("Localizable", "view", fallback: "View") + /// Benefits + public static let whyShouldSignIn = RuuviLocalization.tr("Localizable", "why_should_sign_in", fallback: "Benefits") + /// Yes + public static let yes = RuuviLocalization.tr("Localizable", "Yes", fallback: "Yes") + /// °C + public static let ºC = RuuviLocalization.tr("Localizable", "ºC", fallback: "°C") + /// °F + public static let ºF = RuuviLocalization.tr("Localizable", "ºF", fallback: "°F") + public enum About { + public enum AboutHelp { + /// Ruuvi Station is an easy-to-use application that allows you to monitor the measurement data of Ruuvi sensors. + public static let contents = RuuviLocalization.tr("Localizable", "About.AboutHelp.contents", fallback: "Ruuvi Station is an easy-to-use application that allows you to monitor the measurement data of Ruuvi sensors.") + /// About / Help + public static let header = RuuviLocalization.tr("Localizable", "About.AboutHelp.header", fallback: "About / Help") + } + + public enum DatabaseSize { + /// Database size: %@ + public static func text(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "About.DatabaseSize.text", String(describing: p1), fallback: "Database size: %@") + } + } + + public enum MeasurementsCount { + /// Number of locally stored measurements: %d + public static func text(_ p1: Int) -> String { + RuuviLocalization.tr("Localizable", "About.MeasurementsCount.text", p1, fallback: "Number of locally stored measurements: %d") + } + } + + public enum More { + /// Ruuvi's website: ruuvi.com + /// Ruuvi Forum: f.ruuvi.com + /// Ruuvi Blog: ruuvi.com/blog + /// Ruuvi on Twitter: twitter.com/ruuvicom + public static let contents = RuuviLocalization.tr("Localizable", "About.More.contents", fallback: "Ruuvi's website: ruuvi.com\nRuuvi Forum: f.ruuvi.com\nRuuvi Blog: ruuvi.com/blog\nRuuvi on Twitter: twitter.com/ruuvicom") + /// More to read + public static let header = RuuviLocalization.tr("Localizable", "About.More.header", fallback: "More to read") + } + + public enum OpenSource { + /// Just like Ruuvi sensors, Ruuvi Station apps are open source. Follow the development and contribute at: github.com/ruuvi + public static let contents = RuuviLocalization.tr("Localizable", "About.OpenSource.contents", fallback: "Just like Ruuvi sensors, Ruuvi Station apps are open source. Follow the development and contribute at: github.com/ruuvi") + /// Open-source + public static let header = RuuviLocalization.tr("Localizable", "About.OpenSource.header", fallback: "Open-source") + } + + public enum OperationsManual { + /// Get started using the Ruuvi Station mobile application with our online guides: ruuvi.com/support/station-mobile + public static let contents = RuuviLocalization.tr("Localizable", "About.OperationsManual.contents", fallback: "Get started using the Ruuvi Station mobile application with our online guides: ruuvi.com/support/station-mobile") + /// Operations manual + public static let header = RuuviLocalization.tr("Localizable", "About.OperationsManual.header", fallback: "Operations manual") + } + + public enum Privacy { + /// By using the application, you accept Ruuvi's standard terms and conditions: ruuvi.com/terms + public static let contents = RuuviLocalization.tr("Localizable", "About.Privacy.contents", fallback: "By using the application, you accept Ruuvi's standard terms and conditions: ruuvi.com/terms") + /// Privacy policy + public static let header = RuuviLocalization.tr("Localizable", "About.Privacy.header", fallback: "Privacy policy") + } + + public enum TagsCount { + /// Added sensors: %d + public static func text(_ p1: Int) -> String { + RuuviLocalization.tr("Localizable", "About.TagsCount.text", p1, fallback: "Added sensors: %d") + } + } + + public enum Troubleshooting { + /// Find help using the Ruuvi Station apps, Ruuvi products and Ruuvi Cloud service from our support center: ruuvi.com/support + public static let contents = RuuviLocalization.tr("Localizable", "About.Troubleshooting.contents", fallback: "Find help using the Ruuvi Station apps, Ruuvi products and Ruuvi Cloud service from our support center: ruuvi.com/support") + /// Troubleshooting + public static let header = RuuviLocalization.tr("Localizable", "About.Troubleshooting.header", fallback: "Troubleshooting") + } + + public enum Version { + /// Version + public static let text = RuuviLocalization.tr("Localizable", "About.Version.text", fallback: "Version") + } + } + + public enum Background { + public enum Interval { + public enum Every { + /// every + public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Every.string", fallback: "every") + } + + public enum Min { + /// min + public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Min.string", fallback: "min") + } + + public enum Sec { + /// sec + public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Sec.string", fallback: "sec") + } + } + + public enum KeepConnection { + /// Keep the Connection + public static let title = RuuviLocalization.tr("Localizable", "Background.KeepConnection.title", fallback: "Keep the Connection") + } + + public enum PresentNotifications { + /// Show Notifications + public static let title = RuuviLocalization.tr("Localizable", "Background.PresentNotifications.title", fallback: "Show Notifications") + } + + public enum ReadRSSITitle { + /// Read RSSI + public static let title = RuuviLocalization.tr("Localizable", "Background.readRSSITitle.title", fallback: "Read RSSI") + } + } + + public enum BluetoothError { + /// Disconnected + public static let disconnected = RuuviLocalization.tr("Localizable", "BluetoothError.disconnected", fallback: "Disconnected") + } + + public enum Cards { + public enum Alert { + public enum AlreadyLoggedIn { + /// User %@ is already signed in. If you'd like to use a different account, please sign out first and then try again. + public static func message(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "Cards.Alert.AlreadyLoggedIn.message", String(describing: p1), fallback: "User %@ is already signed in. If you'd like to use a different account, please sign out first and then try again.") + } + } + } + + public enum BluetoothDisabledAlert { + /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. + public static let message = RuuviLocalization.tr("Localizable", "Cards.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") + /// Bluetooth is not enabled + public static let title = RuuviLocalization.tr("Localizable", "Cards.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") + } + + public enum Connected { + /// Connected + public static let title = RuuviLocalization.tr("Localizable", "Cards.Connected.title", fallback: "Connected") + } + + public enum Error { + public enum ReverseGeocodingFailed { + /// Failed to load data for Virtual Sensor. Reverse geocode operation limit exceeded. + public static let message = RuuviLocalization.tr("Localizable", "Cards.Error.ReverseGeocodingFailed.message", fallback: "Failed to load data for Virtual Sensor. Reverse geocode operation limit exceeded.") + } + } + + public enum KeepConnectionDialog { + /// Seems like you are running a connectable firmware on your Ruuvi device. Would you like to keep the connection open to this Ruuvi device in the background? This will allow histograms and alerts to work even when the application is minimised. + public static let message = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.message", fallback: "Seems like you are running a connectable firmware on your Ruuvi device. Would you like to keep the connection open to this Ruuvi device in the background? This will allow histograms and alerts to work even when the application is minimised.") + public enum Dismiss { + /// Cancel + public static let title = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.Dismiss.title", fallback: "Cancel") + } + + public enum KeepConnection { + /// Keep the Connection + public static let title = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.KeepConnection.title", fallback: "Keep the Connection") + } + } + + public enum LegacyFirmwareUpdateDialog { + /// Looks like your sensor is using an old firmware software version. To access new features such as history graphs, alerts and cloud services, updating is mandatory. + public static let message = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.message", fallback: "Looks like your sensor is using an old firmware software version. To access new features such as history graphs, alerts and cloud services, updating is mandatory.") + public enum CancelConfirmation { + /// Are you sure? Without updating, you won't be able to claim ownership of the sensor, download history graphs and set alerts. The update also includes bug fixes. If you cancel now, you can start the update process again from the sensor's settings page. + public static let message = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message", fallback: "Are you sure? Without updating, you won't be able to claim ownership of the sensor, download history graphs and set alerts. The update also includes bug fixes. If you cancel now, you can start the update process again from the sensor's settings page.") + } + + public enum CheckForUpdate { + /// Check for update + public static let title = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title", fallback: "Check for update") + } + } + + public enum Movements { + /// movements + public static let title = RuuviLocalization.tr("Localizable", "Cards.Movements.title", fallback: "movements") + } + + public enum NoSensors { + /// No sensors added + /// Press here to add sensors + public static let title = RuuviLocalization.tr("Localizable", "Cards.NoSensors.title", fallback: "No sensors added\nPress here to add sensors") + } + + public enum UpdatedLabel { + public enum NoData { + /// No data during the last 10 days + public static let message = RuuviLocalization.tr("Localizable", "Cards.UpdatedLabel.NoData.message", fallback: "No data during the last 10 days") + } + } + + public enum WebTagAPILimitExcededError { + public enum Alert { + /// Please try again in 5 minutes + public static let message = RuuviLocalization.tr("Localizable", "Cards.WebTagAPILimitExcededError.Alert.message", fallback: "Please try again in 5 minutes") + /// Too many requests + public static let title = RuuviLocalization.tr("Localizable", "Cards.WebTagAPILimitExcededError.Alert.title", fallback: "Too many requests") + } + } + } + + public enum ChartSettings { + public enum AllPoints { + /// Charts may be updated slowly when enabled. + public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.AllPoints.description", fallback: "Charts may be updated slowly when enabled.") + /// Show all measurements + public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.AllPoints.title", fallback: "Show all measurements") + } + + public enum DrawDots { + /// Small dots will help to understand when measurements were collected. + public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.DrawDots.description", fallback: "Small dots will help to understand when measurements were collected.") + /// Show datapoints + public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.DrawDots.title", fallback: "Show datapoints") + } + + public enum Duration { + /// Configure the period of history to be shown on chart from 1 to 10 days. + public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.Duration.description", fallback: "Configure the period of history to be shown on chart from 1 to 10 days.") + /// Chart History View Period + public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.Duration.title", fallback: "Chart History View Period") + } + } + + public enum CoreError { + /// Failed to get current location + public static let failedToGetCurrentLocation = RuuviLocalization.tr("Localizable", "CoreError.failedToGetCurrentLocation", fallback: "Failed to get current location") + /// Failed to get data from response + public static let failedToGetDataFromResponse = RuuviLocalization.tr("Localizable", "CoreError.failedToGetDataFromResponse", fallback: "Failed to get data from response") + /// Failed to get background directory + public static let failedToGetDocumentsDirectory = RuuviLocalization.tr("Localizable", "CoreError.failedToGetDocumentsDirectory", fallback: "Failed to get background directory") + /// Failed to get PNG representation + public static let failedToGetPngRepresentation = RuuviLocalization.tr("Localizable", "CoreError.failedToGetPngRepresentation", fallback: "Failed to get PNG representation") + /// Missing permission for Location Services + public static let locationPermissionDenied = RuuviLocalization.tr("Localizable", "CoreError.locationPermissionDenied", fallback: "Missing permission for Location Services") + /// Location permission authorisation status is not determined + public static let locationPermissionNotDetermined = RuuviLocalization.tr("Localizable", "CoreError.locationPermissionNotDetermined", fallback: "Location permission authorisation status is not determined") + /// Object invalidated + public static let objectInvalidated = RuuviLocalization.tr("Localizable", "CoreError.objectInvalidated", fallback: "Object invalidated") + /// Object not found + public static let objectNotFound = RuuviLocalization.tr("Localizable", "CoreError.objectNotFound", fallback: "Object not found") + /// Unable to send email + public static let unableToSendEmail = RuuviLocalization.tr("Localizable", "CoreError.unableToSendEmail", fallback: "Unable to send email") + } + + public enum DFUUIView { + /// You are running the latest firmware version, no need to update + public static let alreadyOnLatest = RuuviLocalization.tr("Localizable", "DFUUIView.alreadyOnLatest", fallback: "You are running the latest firmware version, no need to update") + /// Current version: + public static let currentTitle = RuuviLocalization.tr("Localizable", "DFUUIView.currentTitle", fallback: "Current version:") + /// Do not close the app or power off the sensor during the update. + public static let doNotCloseTitle = RuuviLocalization.tr("Localizable", "DFUUIView.doNotCloseTitle", fallback: "Do not close the app or power off the sensor during the update.") + /// Downloading the latest firmware to be updated... + public static let downloadingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.downloadingTitle", fallback: "Downloading the latest firmware to be updated...") + /// Latest available Ruuvi Firmware version: + public static let latestTitle = RuuviLocalization.tr("Localizable", "DFUUIView.latestTitle", fallback: "Latest available Ruuvi Firmware version:") + /// 2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label. + public static let locateBootButtonTitle = RuuviLocalization.tr("Localizable", "DFUUIView.locateBootButtonTitle", fallback: "2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label.") + /// Firmware Update + public static let navigationTitle = RuuviLocalization.tr("Localizable", "DFUUIView.navigationTitle", fallback: "Firmware Update") + /// Your sensor doesn't report its current firmware version. Either you're not in its Bluetooth range, it's connected to another phone, or it's running a very old firmware version. + public static let notReportingDescription = RuuviLocalization.tr("Localizable", "DFUUIView.notReportingDescription", fallback: "Your sensor doesn't report its current firmware version. Either you're not in its Bluetooth range, it's connected to another phone, or it's running a very old firmware version.") + /// 1. Open the cover of your Ruuvi sensor + public static let openCoverTitle = RuuviLocalization.tr("Localizable", "DFUUIView.openCoverTitle", fallback: "1. Open the cover of your Ruuvi sensor") + /// Prepare your sensor + public static let prepareTitle = RuuviLocalization.tr("Localizable", "DFUUIView.prepareTitle", fallback: "Prepare your sensor") + /// Searching for a sensor + public static let searchingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.searchingTitle", fallback: "Searching for a sensor") + /// 3. Set the sensor to updating mode: + public static let setUpdatingModeTitle = RuuviLocalization.tr("Localizable", "DFUUIView.setUpdatingModeTitle", fallback: "3. Set the sensor to updating mode:") + /// Start the update + public static let startTitle = RuuviLocalization.tr("Localizable", "DFUUIView.startTitle", fallback: "Start the update") + /// Start update process + public static let startUpdateProcess = RuuviLocalization.tr("Localizable", "DFUUIView.startUpdateProcess", fallback: "Start update process") + /// Update successful + public static let successfulTitle = RuuviLocalization.tr("Localizable", "DFUUIView.successfulTitle", fallback: "Update successful") + /// 3.2. If your sensor has a single button: keep the button pressed for 10 seconds. + public static let toBootModeOneButtonDescription = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeOneButtonDescription", fallback: "3.2. If your sensor has a single button: keep the button pressed for 10 seconds.") + /// 4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”. + public static let toBootModeSuccessTitle = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeSuccessTitle", fallback: "4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”.") + /// 3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”. + public static let toBootModeTwoButtonsDescription = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeTwoButtonsDescription", fallback: "3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”.") + /// Updating... + public static let updatingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.updatingTitle", fallback: "Updating...") + public enum DBMigration { + public enum Error { + /// The update was successful, but an unexpected database migration error occurred. To continue using this sensor, please remove it from the app and then add it again. + public static let message = RuuviLocalization.tr("Localizable", "DFUUIView.DBMigration.Error.message", fallback: "The update was successful, but an unexpected database migration error occurred. To continue using this sensor, please remove it from the app and then add it again.") + } + } + + public enum LowBattery { + public enum Warning { + /// Sensor's battery voltage seems to be low and the firmware update process may fail. We recommend to replace the battery before updating. + public static let message = RuuviLocalization.tr("Localizable", "DFUUIView.lowBattery.warning.message", fallback: "Sensor's battery voltage seems to be low and the firmware update process may fail. We recommend to replace the battery before updating.") + } + } + } + + public enum Defaults { + public enum AlertsMuteInterval { + /// Alerts Mute Interval + public static let title = RuuviLocalization.tr("Localizable", "Defaults.AlertsMuteInterval.title", fallback: "Alerts Mute Interval") + } + + public enum AlertsRepeatInterval { + /// Alerts Interval + public static let title = RuuviLocalization.tr("Localizable", "Defaults.AlertsRepeatInterval.title", fallback: "Alerts Interval") + } + + public enum AppLaunchRequiredForReview { + public enum Count { + /// App launch count to ask for review for the first time + public static let title = RuuviLocalization.tr("Localizable", "Defaults.AppLaunchRequiredForReview.Count.title", fallback: "App launch count to ask for review for the first time") + } + } + + public enum AskReviewIfLaunchDivisibleBy { + public enum Count { + /// Ask review if app launch divisible by + public static let title = RuuviLocalization.tr("Localizable", "Defaults.AskReviewIfLaunchDivisibleBy.Count.title", fallback: "Ask review if app launch divisible by") + } + } + + public enum CardsSwipeHint { + /// Cards Swipe Hint Was Shown + public static let title = RuuviLocalization.tr("Localizable", "Defaults.CardsSwipeHint.title", fallback: "Cards Swipe Hint Was Shown") + } + + public enum ChartDurationHours { + /// Chart Duration + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartDurationHours.title", fallback: "Chart Duration") + } + + public enum ChartIntervalSeconds { + /// Chart Interval + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartIntervalSeconds.title", fallback: "Chart Interval") + } + + public enum ChartsSwipeInstructionWasShown { + /// Charts Swipe Hint Was Shown + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartsSwipeInstructionWasShown.title", fallback: "Charts Swipe Hint Was Shown") + } + + public enum ConnectionTimeout { + /// Connection Timeout + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ConnectionTimeout.title", fallback: "Connection Timeout") + } + + public enum DashboardTapActionChart { + /// Show Chart on Dashboard Card Tap + public static let title = RuuviLocalization.tr("Localizable", "Defaults.DashboardTapActionChart.title", fallback: "Show Chart on Dashboard Card Tap") + } + + public enum DevServer { + /// Changing Ruuvi Cloud endpoint requires signing out from current session and restart the app. Are you sure? + public static let message = RuuviLocalization.tr("Localizable", "Defaults.DevServer.message", fallback: "Changing Ruuvi Cloud endpoint requires signing out from current session and restart the app. Are you sure?") + /// Use Dev Server + public static let title = RuuviLocalization.tr("Localizable", "Defaults.DevServer.title", fallback: "Use Dev Server") + } + + public enum HideNFC { + /// Hide NFC Option for sensor contest + public static let title = RuuviLocalization.tr("Localizable", "Defaults.HideNFC.title", fallback: "Hide NFC Option for sensor contest") + } + + public enum Interval { + public enum Hour { + /// h + public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Hour.string", fallback: "h") + } + + public enum Min { + /// min + public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Min.string", fallback: "min") + } + + public enum Sec { + /// sec + public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Sec.string", fallback: "sec") + } + } + + public enum PruningOffsetHours { + /// Pruning Offset Hours + public static let title = RuuviLocalization.tr("Localizable", "Defaults.PruningOffsetHours.title", fallback: "Pruning Offset Hours") + } + + public enum ServiceTimeout { + /// Service Timeout + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ServiceTimeout.title", fallback: "Service Timeout") + } + + public enum ShowEmailAlertsSettings { + /// Show email alerts settings + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ShowEmailAlertsSettings.title", fallback: "Show email alerts settings") + } + + public enum ShowPushAlertsSettings { + /// Show push alerts settings + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ShowPushAlertsSettings.title", fallback: "Show push alerts settings") + } + + public enum UserAuthorized { + /// User Authorized + public static let title = RuuviLocalization.tr("Localizable", "Defaults.UserAuthorized.title", fallback: "User Authorized") + } + + public enum WebPullInterval { + /// Web Alerts Interval + public static let title = RuuviLocalization.tr("Localizable", "Defaults.WebPullInterval.title", fallback: "Web Alerts Interval") + } + + public enum WelcomeShown { + /// Welcome Displayed + public static let title = RuuviLocalization.tr("Localizable", "Defaults.WelcomeShown.title", fallback: "Welcome Displayed") + } + + public enum NavigationItem { + /// Defaults + public static let title = RuuviLocalization.tr("Localizable", "Defaults.navigationItem.title", fallback: "Defaults") + } + } + + public enum Devices { + /// Token Id + public static let tokenId = RuuviLocalization.tr("Localizable", "Devices.tokenId", fallback: "Token Id") + } + + public enum DfuDevicesScanner { + public enum BluetoothDisabled { + /// (Bluetooth is disabled) + public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabled.text", fallback: "(Bluetooth is disabled)") + } + + public enum BluetoothDisabledAlert { + /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. + public static let message = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") + /// Bluetooth is not enabled + public static let title = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") + } + + public enum Description { + /// Find and select sensor "RuuviBoot". + public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.Description.text", fallback: "Find and select sensor \"RuuviBoot\".") + } + + public enum NoDevice { + /// (No sensors in Bluetooth range) + public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.NoDevice.text", fallback: "(No sensors in Bluetooth range)") + } + + public enum Title { + /// Devices + public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.Title.text", fallback: "Devices") + } + } + + public enum DfuFlash { + public enum Cancel { + /// CANCEL + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Cancel.text", fallback: "CANCEL") + } + + public enum CancelAlert { + /// Are you sure you want to cancel the firmware update process? + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.CancelAlert.text", fallback: "Are you sure you want to cancel the firmware update process?") + } + + public enum Finish { + /// FINISH + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Finish.text", fallback: "FINISH") + } + + public enum FinishGuide { + /// Firmware update process has been completed successfully. + /// Your RuuviTag sensor is ready for use! + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.FinishGuide.text", fallback: "Firmware update process has been completed successfully.\nYour RuuviTag sensor is ready for use!") + } + + public enum Firmware { + public enum BootloaderSize { + /// Bootloader size + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.BootloaderSize.text", fallback: "Bootloader size") + } + + public enum FileName { + /// File name + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.FileName.text", fallback: "File name") + } + + public enum Parts { + /// Parts + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.Parts.text", fallback: "Parts") + } + + public enum Size { + /// Size + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.Size.text", fallback: "Size") + } + + public enum SoftDeviceSize { + /// Soft Device size + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.SoftDeviceSize.text", fallback: "Soft Device size") + } + } + + public enum FirmwareSelectionGuide { + /// Locate the previously downloaded ZIP file on your mobile device. + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.FirmwareSelectionGuide.text", fallback: "Locate the previously downloaded ZIP file on your mobile device.") + } + + public enum OpenDocumentPicker { + /// OPEN DOCUMENT PICKER + public static let title = RuuviLocalization.tr("Localizable", "DfuFlash.OpenDocumentPicker.title", fallback: "OPEN DOCUMENT PICKER") + } + + public enum Progress { + /// Progress + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Progress.text", fallback: "Progress") + } + + public enum Start { + /// Start + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Start.text", fallback: "Start") + } + + public enum Step { + /// Step + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Step.text", fallback: "Step") + } + + public enum Steps { + public enum Completed { + /// Completed + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.Completed.text", fallback: "Completed") + } + + public enum PackageSelection { + /// Package selection + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.PackageSelection.text", fallback: "Package selection") + } + + public enum ReadyForUpload { + /// Ready For upload + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.ReadyForUpload.text", fallback: "Ready For upload") + } + + public enum Uploading { + /// Uploading + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.Uploading.text", fallback: "Uploading") + } + } + + public enum Title { + /// DFU Flash + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Title.text", fallback: "DFU Flash") + } + } + + public enum DiscoverTable { + public enum BluetoothDisabledAlert { + /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. + public static let message = RuuviLocalization.tr("Localizable", "DiscoverTable.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") + /// Bluetooth is not enabled + public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") + } + + public enum GetMoreSensors { + public enum Button { + /// Buy Ruuvi Sensors + public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.GetMoreSensors.button.title", fallback: "Buy Ruuvi Sensors") + } + } + + public enum NavigationItem { + /// Add a New Sensor + public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.NavigationItem.title", fallback: "Add a New Sensor") + } + + public enum NoDevicesSection { + public enum BluetoothDisabled { + /// (Bluetooth is disabled) + public static let text = RuuviLocalization.tr("Localizable", "DiscoverTable.NoDevicesSection.BluetoothDisabled.text", fallback: "(Bluetooth is disabled)") + } + + public enum NotFound { + /// (No sensors in Bluetooth range) + public static let text = RuuviLocalization.tr("Localizable", "DiscoverTable.NoDevicesSection.NotFound.text", fallback: "(No sensors in Bluetooth range)") + } + } + + public enum RuuviDevice { + /// Ruuvi + public static let prefix = RuuviLocalization.tr("Localizable", "DiscoverTable.RuuviDevice.prefix", fallback: "Ruuvi") + } + + public enum SectionTitle { + /// Nearby Ruuvi sensors + public static let devices = RuuviLocalization.tr("Localizable", "DiscoverTable.SectionTitle.Devices", fallback: "Nearby Ruuvi sensors") + /// Virtual sensors + public static let webTags = RuuviLocalization.tr("Localizable", "DiscoverTable.SectionTitle.WebTags", fallback: "Virtual sensors") + } + + public enum WebTagsInfoDialog { + /// Virtual Sensors show public weather data provided by local weather stations. + public static let message = RuuviLocalization.tr("Localizable", "DiscoverTable.WebTagsInfoDialog.message", fallback: "Virtual Sensors show public weather data provided by local weather stations.") + } + } + + public enum ErrorPresenterAlert { + /// Error + public static let error = RuuviLocalization.tr("Localizable", "ErrorPresenterAlert.Error", fallback: "Error") + /// OK + public static let ok = RuuviLocalization.tr("Localizable", "ErrorPresenterAlert.OK", fallback: "OK") + } + + public enum ExpectedError { + /// Unable to remove a connected device that is not reachable. Please check your Bluetooth connection. + public static let failedToDeleteTag = RuuviLocalization.tr("Localizable", "ExpectedError.failedToDeleteTag", fallback: "Unable to remove a connected device that is not reachable. Please check your Bluetooth connection.") + /// App is already in the process of syncing logs with this sensor + public static let isAlreadySyncingLogsWithThisTag = RuuviLocalization.tr("Localizable", "ExpectedError.isAlreadySyncingLogsWithThisTag", fallback: "App is already in the process of syncing logs with this sensor") + /// Missing OpenWeatherMap API Key. Please get one from openweathermap.org website and enter it in the station/Classes/Networking/Assembly/Networking.plist file + public static let missingOpenWeatherMapAPIKey = RuuviLocalization.tr("Localizable", "ExpectedError.missingOpenWeatherMapAPIKey", fallback: "Missing OpenWeatherMap API Key. Please get one from openweathermap.org website and enter it in the station/Classes/Networking/Assembly/Networking.plist file") + } + + public enum ExportService { + /// Acceleration X + public static let accelerationX = RuuviLocalization.tr("Localizable", "ExportService.AccelerationX", fallback: "Acceleration X") + /// Acceleration Y + public static let accelerationY = RuuviLocalization.tr("Localizable", "ExportService.AccelerationY", fallback: "Acceleration Y") + /// Acceleration Z + public static let accelerationZ = RuuviLocalization.tr("Localizable", "ExportService.AccelerationZ", fallback: "Acceleration Z") + /// Date + public static let date = RuuviLocalization.tr("Localizable", "ExportService.Date", fallback: "Date") + /// Dew point (%@) + public static func dewPoint(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "ExportService.DewPoint", String(describing: p1), fallback: "Dew point (%@)") + } + + /// Humidity (%@) + public static func humidity(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "ExportService.Humidity", String(describing: p1), fallback: "Humidity (%@)") + } + + /// ISO8601 + public static let iso8601 = RuuviLocalization.tr("Localizable", "ExportService.ISO8601", fallback: "ISO8601") + /// Measurement Sequence Number + public static let measurementSequenceNumber = RuuviLocalization.tr("Localizable", "ExportService.MeasurementSequenceNumber", fallback: "Measurement Sequence Number") + /// Movement Counter + public static let movementCounter = RuuviLocalization.tr("Localizable", "ExportService.MovementCounter", fallback: "Movement Counter") + /// Pressure (%@) + public static func pressure(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "ExportService.Pressure", String(describing: p1), fallback: "Pressure (%@)") + } + + /// Temperature (%@) + public static func temperature(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "ExportService.Temperature", String(describing: p1), fallback: "Temperature (%@)") + } + + /// TX Power + public static let txPower = RuuviLocalization.tr("Localizable", "ExportService.TXPower", fallback: "TX Power") + /// Voltage (V) + public static let voltage = RuuviLocalization.tr("Localizable", "ExportService.Voltage", fallback: "Voltage (V)") + } + + public enum Foreground { + public enum Interval { + public enum All { + /// All + public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.All.string", fallback: "All") + } + + public enum Every { + /// Every + public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.Every.string", fallback: "Every") + } + + public enum Min { + /// min + public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.Min.string", fallback: "min") + } + } + + public enum NavigationItem { + /// Foreground + public static let title = RuuviLocalization.tr("Localizable", "Foreground.navigationItem.title", fallback: "Foreground") + } + } + + public enum ForegroundRow { + public enum Advertisement { + /// ADVERTISEMENTS + public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.advertisement.section", fallback: "ADVERTISEMENTS") + /// Save advertisements + public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.advertisement.title", fallback: "Save advertisements") + } + + public enum Connection { + /// LOGS + public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.connection.section", fallback: "LOGS") + /// Connect and sync logs + public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.connection.title", fallback: "Connect and sync logs") + } + + public enum WebTags { + /// VIRTUAL SENSORS + public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.webTags.section", fallback: "VIRTUAL SENSORS") + /// Load and save from web + public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.webTags.title", fallback: "Load and save from web") + } + } + + public enum Heartbeat { + public enum Interval { + public enum All { + /// All + public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.All.string", fallback: "All") + } + + public enum Every { + /// every + public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Every.string", fallback: "every") + } + + public enum Min { + /// min + public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Min.string", fallback: "min") + } + + public enum Sec { + /// sec + public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Sec.string", fallback: "sec") + } + } + + public enum ReadRSSITitle { + /// Read RSSI + public static let title = RuuviLocalization.tr("Localizable", "Heartbeat.readRSSITitle.title", fallback: "Read RSSI") + } + } + + public enum HumidityCalibration { + public enum Button { + public enum Calibrate { + /// Calibrate + public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Calibrate.title", fallback: "Calibrate") + } + + public enum Clear { + /// Clear + public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Clear.title", fallback: "Clear") + } + + public enum Close { + /// Close + public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Close.title", fallback: "Close") + } + } + + public enum CalibrationConfirmationAlert { + /// You are going to calibrate humidity offset. Tap "Confirm" to continue + public static let message = RuuviLocalization.tr("Localizable", "HumidityCalibration.CalibrationConfirmationAlert.message", fallback: "You are going to calibrate humidity offset. Tap \"Confirm\" to continue") + /// Are you sure? + public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.CalibrationConfirmationAlert.title", fallback: "Are you sure?") + } + + public enum ClearCalibrationConfirmationAlert { + /// You are going to clear humidity offset. This can't be undone. Tap "Confirm" to continue. + public static let message = RuuviLocalization.tr("Localizable", "HumidityCalibration.ClearCalibrationConfirmationAlert.message", fallback: "You are going to clear humidity offset. This can't be undone. Tap \"Confirm\" to continue.") + /// Are you sure? + public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.ClearCalibrationConfirmationAlert.title", fallback: "Are you sure?") + } + + public enum Description { + /// In order to measure relative humidity as accurately as possible, a sodium chloride (salt) calibration is recommended. See video tutorials on how to easily do this at home. + public static let text = RuuviLocalization.tr("Localizable", "HumidityCalibration.Description.text", fallback: "In order to measure relative humidity as accurately as possible, a sodium chloride (salt) calibration is recommended. See video tutorials on how to easily do this at home.") + } + + public enum Label { + public enum Note { + /// Note that calibration data will be stored locally in your mobile device. After Ruuvi Station uninstall and install, you may need to recalibrate. + public static let text = RuuviLocalization.tr("Localizable", "HumidityCalibration.Label.note.text", fallback: "Note that calibration data will be stored locally in your mobile device. After Ruuvi Station uninstall and install, you may need to recalibrate.") + } + } + + public enum VideoTutorials { + /// video tutorials + public static let link = RuuviLocalization.tr("Localizable", "HumidityCalibration.VideoTutorials.link", fallback: "video tutorials") + } + + public enum LastCalibrationDate { + /// Calibrated: %@ + public static func format(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "HumidityCalibration.lastCalibrationDate.format", String(describing: p1), fallback: "Calibrated: %@") + } + } + } + + public enum HumidityUnit { + public enum Dew { + /// Dew point (%@) + public static func title(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "HumidityUnit.Dew.title", String(describing: p1), fallback: "Dew point (%@)") + } + } + + public enum Percent { + /// Relative (%) + public static let title = RuuviLocalization.tr("Localizable", "HumidityUnit.Percent.title", fallback: "Relative (%)") + } + + public enum Gm3 { + /// Absolute (g/m³) + public static let title = RuuviLocalization.tr("Localizable", "HumidityUnit.gm3.title", fallback: "Absolute (g/m³)") + } + } + public enum Interval { - public enum All { - /// All - public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.All.string", fallback: "All") - } - public enum Every { - /// every - public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Every.string", fallback: "every") - } - public enum Min { - /// min - public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Min.string", fallback: "min") - } - public enum Sec { - /// sec - public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Sec.string", fallback: "sec") - } - } - public enum ReadRSSITitle { - /// Read RSSI - public static let title = RuuviLocalization.tr("Localizable", "Heartbeat.readRSSITitle.title", fallback: "Read RSSI") - } - } - public enum HumidityCalibration { - public enum Button { - public enum Calibrate { - /// Calibrate - public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Calibrate.title", fallback: "Calibrate") - } - public enum Clear { - /// Clear - public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Clear.title", fallback: "Clear") - } - public enum Close { - /// Close - public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Close.title", fallback: "Close") - } - } - public enum CalibrationConfirmationAlert { - /// You are going to calibrate humidity offset. Tap "Confirm" to continue - public static let message = RuuviLocalization.tr("Localizable", "HumidityCalibration.CalibrationConfirmationAlert.message", fallback: "You are going to calibrate humidity offset. Tap \"Confirm\" to continue") - /// Are you sure? - public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.CalibrationConfirmationAlert.title", fallback: "Are you sure?") - } - public enum ClearCalibrationConfirmationAlert { - /// You are going to clear humidity offset. This can't be undone. Tap "Confirm" to continue. - public static let message = RuuviLocalization.tr("Localizable", "HumidityCalibration.ClearCalibrationConfirmationAlert.message", fallback: "You are going to clear humidity offset. This can't be undone. Tap \"Confirm\" to continue.") - /// Are you sure? - public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.ClearCalibrationConfirmationAlert.title", fallback: "Are you sure?") - } - public enum Description { - /// In order to measure relative humidity as accurately as possible, a sodium chloride (salt) calibration is recommended. See video tutorials on how to easily do this at home. - public static let text = RuuviLocalization.tr("Localizable", "HumidityCalibration.Description.text", fallback: "In order to measure relative humidity as accurately as possible, a sodium chloride (salt) calibration is recommended. See video tutorials on how to easily do this at home.") - } - public enum Label { - public enum Note { - /// Note that calibration data will be stored locally in your mobile device. After Ruuvi Station uninstall and install, you may need to recalibrate. - public static let text = RuuviLocalization.tr("Localizable", "HumidityCalibration.Label.note.text", fallback: "Note that calibration data will be stored locally in your mobile device. After Ruuvi Station uninstall and install, you may need to recalibrate.") - } - } - public enum VideoTutorials { - /// video tutorials - public static let link = RuuviLocalization.tr("Localizable", "HumidityCalibration.VideoTutorials.link", fallback: "video tutorials") - } - public enum LastCalibrationDate { - /// Calibrated: %@ - public static func format(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "HumidityCalibration.lastCalibrationDate.format", String(describing: p1), fallback: "Calibrated: %@") - } - } - } - public enum HumidityUnit { - public enum Dew { - /// Dew point (%@) - public static func title(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "HumidityUnit.Dew.title", String(describing: p1), fallback: "Dew point (%@)") - } - } - public enum Percent { - /// Relative (%) - public static let title = RuuviLocalization.tr("Localizable", "HumidityUnit.Percent.title", fallback: "Relative (%)") - } - public enum Gm3 { - /// Absolute (g/m³) - public static let title = RuuviLocalization.tr("Localizable", "HumidityUnit.gm3.title", fallback: "Absolute (g/m³)") - } - } - public enum Interval { - public enum Day { - /// Day - public static let string = RuuviLocalization.tr("Localizable", "Interval.Day.string", fallback: "Day") - } - public enum Days { - /// Days - public static let string = RuuviLocalization.tr("Localizable", "Interval.Days.string", fallback: "Days") - } - } - public enum Language { - /// English - public static let english = RuuviLocalization.tr("Localizable", "Language.English", fallback: "English") - /// Suomi - public static let finnish = RuuviLocalization.tr("Localizable", "Language.Finnish", fallback: "Suomi") - /// Français - public static let french = RuuviLocalization.tr("Localizable", "Language.French", fallback: "Français") - /// Deutsch - public static let german = RuuviLocalization.tr("Localizable", "Language.German", fallback: "Deutsch") - /// Русский - public static let russian = RuuviLocalization.tr("Localizable", "Language.Russian", fallback: "Русский") - /// Svenska - public static let swedish = RuuviLocalization.tr("Localizable", "Language.Swedish", fallback: "Svenska") - } - public enum LocalNotificationsManager { - public enum DidConnect { - /// Connected - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidConnect.title", fallback: "Connected") - } - public enum DidDisconnect { - /// Disconnected - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidDisconnect.title", fallback: "Disconnected") - } - public enum DidMove { - /// Movement detected! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidMove.title", fallback: "Movement detected!") - } - public enum Disable { - /// Turn off - public static let button = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.Disable.button", fallback: "Turn off") - } - public enum HighDewPoint { - /// Dew Point is too high! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighDewPoint.title", fallback: "Dew Point is too high!") - } - public enum HighHumidity { - /// Air Humidity is too high! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighHumidity.title", fallback: "Air Humidity is too high!") - } - public enum HighPressure { - /// Air Pressure is too high! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighPressure.title", fallback: "Air Pressure is too high!") - } - public enum HighSignal { - /// Signal strength is too high! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighSignal.title", fallback: "Signal strength is too high!") - } - public enum HighTemperature { - /// Temperature is too high! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighTemperature.title", fallback: "Temperature is too high!") - } - public enum LowDewPoint { - /// Dew Point is too low! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowDewPoint.title", fallback: "Dew Point is too low!") - } - public enum LowHumidity { - /// Air Humidity is too low! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowHumidity.title", fallback: "Air Humidity is too low!") - } - public enum LowPressure { - /// Air Pressure is too low! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowPressure.title", fallback: "Air Pressure is too low!") - } - public enum LowSignal { - /// Signal strength is too low! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowSignal.title", fallback: "Signal strength is too low!") - } - public enum LowTemperature { - /// Temperature is too low! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowTemperature.title", fallback: "Temperature is too low!") - } - public enum Mute { - /// Mute for an hour - public static let button = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.Mute.button", fallback: "Mute for an hour") - } - } - public enum Menu { - public enum BuyGateway { - public enum Url { - /// https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios - public static let ios = RuuviLocalization.tr("Localizable", "Menu.BuyGateway.URL.IOS", fallback: "https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") - } - } - public enum Label { - public enum AboutHelp { - /// About / Help - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AboutHelp.text", fallback: "About / Help") - } - public enum AddAnNewSensor { - /// Add a New Sensor - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AddAnNewSensor.text", fallback: "Add a New Sensor") - } - public enum AppSettings { - /// App Settings - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AppSettings.text", fallback: "App Settings") - } - public enum BuyRuuviGateway { - /// Buy Ruuvi Gateway - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.BuyRuuviGateway.text", fallback: "Buy Ruuvi Gateway") - } - public enum Feedback { - /// Send Feedback - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.Feedback.text", fallback: "Send Feedback") - } - public enum GetMoreSensors { - /// Buy Ruuvi Sensors - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.GetMoreSensors.text", fallback: "Buy Ruuvi Sensors") - } - public enum MyRuuviAccount { - /// My Ruuvi Account - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.MyRuuviAccount.text", fallback: "My Ruuvi Account") - } - public enum WhatToMeasure { - /// What to measure with Ruuvi? - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.WhatToMeasure.text", fallback: "What to measure with Ruuvi?") - } - } - public enum LoggedIn { - /// Signed in: - public static let title = RuuviLocalization.tr("Localizable", "Menu.LoggedIn.title", fallback: "Signed in:") - } - public enum Measure { - public enum Url { - /// https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios - public static let ios = RuuviLocalization.tr("Localizable", "Menu.Measure.URL.IOS", fallback: "https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") - } - } - public enum RuuviNetworkStatus { - /// Ruuvi Cloud status - public static let text = RuuviLocalization.tr("Localizable", "Menu.RuuviNetworkStatus.text", fallback: "Ruuvi Cloud status") - } - public enum SignOut { - /// Sign out - public static let text = RuuviLocalization.tr("Localizable", "Menu.SignOut.text", fallback: "Sign out") - } - } - public enum MenuTableViewController { - /// none - public static let `none` = RuuviLocalization.tr("Localizable", "MenuTableViewController.None", fallback: "none") - /// User: %@ - public static func user(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "MenuTableViewController.User", String(describing: p1), fallback: "User: %@") - } - } - public enum MyRuuvi { + public enum Day { + /// Day + public static let string = RuuviLocalization.tr("Localizable", "Interval.Day.string", fallback: "Day") + } + + public enum Days { + /// Days + public static let string = RuuviLocalization.tr("Localizable", "Interval.Days.string", fallback: "Days") + } + } + + public enum Language { + /// English + public static let english = RuuviLocalization.tr("Localizable", "Language.English", fallback: "English") + /// Suomi + public static let finnish = RuuviLocalization.tr("Localizable", "Language.Finnish", fallback: "Suomi") + /// Français + public static let french = RuuviLocalization.tr("Localizable", "Language.French", fallback: "Français") + /// Deutsch + public static let german = RuuviLocalization.tr("Localizable", "Language.German", fallback: "Deutsch") + /// Русский + public static let russian = RuuviLocalization.tr("Localizable", "Language.Russian", fallback: "Русский") + /// Svenska + public static let swedish = RuuviLocalization.tr("Localizable", "Language.Swedish", fallback: "Svenska") + } + + public enum LocalNotificationsManager { + public enum DidConnect { + /// Connected + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidConnect.title", fallback: "Connected") + } + + public enum DidDisconnect { + /// Disconnected + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidDisconnect.title", fallback: "Disconnected") + } + + public enum DidMove { + /// Movement detected! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidMove.title", fallback: "Movement detected!") + } + + public enum Disable { + /// Turn off + public static let button = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.Disable.button", fallback: "Turn off") + } + + public enum HighDewPoint { + /// Dew Point is too high! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighDewPoint.title", fallback: "Dew Point is too high!") + } + + public enum HighHumidity { + /// Air Humidity is too high! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighHumidity.title", fallback: "Air Humidity is too high!") + } + + public enum HighPressure { + /// Air Pressure is too high! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighPressure.title", fallback: "Air Pressure is too high!") + } + + public enum HighSignal { + /// Signal strength is too high! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighSignal.title", fallback: "Signal strength is too high!") + } + + public enum HighTemperature { + /// Temperature is too high! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighTemperature.title", fallback: "Temperature is too high!") + } + + public enum LowDewPoint { + /// Dew Point is too low! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowDewPoint.title", fallback: "Dew Point is too low!") + } + + public enum LowHumidity { + /// Air Humidity is too low! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowHumidity.title", fallback: "Air Humidity is too low!") + } + + public enum LowPressure { + /// Air Pressure is too low! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowPressure.title", fallback: "Air Pressure is too low!") + } + + public enum LowSignal { + /// Signal strength is too low! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowSignal.title", fallback: "Signal strength is too low!") + } + + public enum LowTemperature { + /// Temperature is too low! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowTemperature.title", fallback: "Temperature is too low!") + } + + public enum Mute { + /// Mute for an hour + public static let button = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.Mute.button", fallback: "Mute for an hour") + } + } + + public enum Menu { + public enum BuyGateway { + public enum Url { + /// https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios + public static let ios = RuuviLocalization.tr("Localizable", "Menu.BuyGateway.URL.IOS", fallback: "https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") + } + } + + public enum Label { + public enum AboutHelp { + /// About / Help + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AboutHelp.text", fallback: "About / Help") + } + + public enum AddAnNewSensor { + /// Add a New Sensor + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AddAnNewSensor.text", fallback: "Add a New Sensor") + } + + public enum AppSettings { + /// App Settings + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AppSettings.text", fallback: "App Settings") + } + + public enum BuyRuuviGateway { + /// Buy Ruuvi Gateway + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.BuyRuuviGateway.text", fallback: "Buy Ruuvi Gateway") + } + + public enum Feedback { + /// Send Feedback + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.Feedback.text", fallback: "Send Feedback") + } + + public enum GetMoreSensors { + /// Buy Ruuvi Sensors + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.GetMoreSensors.text", fallback: "Buy Ruuvi Sensors") + } + + public enum MyRuuviAccount { + /// My Ruuvi Account + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.MyRuuviAccount.text", fallback: "My Ruuvi Account") + } + + public enum WhatToMeasure { + /// What to measure with Ruuvi? + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.WhatToMeasure.text", fallback: "What to measure with Ruuvi?") + } + } + + public enum LoggedIn { + /// Signed in: + public static let title = RuuviLocalization.tr("Localizable", "Menu.LoggedIn.title", fallback: "Signed in:") + } + + public enum Measure { + public enum Url { + /// https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios + public static let ios = RuuviLocalization.tr("Localizable", "Menu.Measure.URL.IOS", fallback: "https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") + } + } + + public enum RuuviNetworkStatus { + /// Ruuvi Cloud status + public static let text = RuuviLocalization.tr("Localizable", "Menu.RuuviNetworkStatus.text", fallback: "Ruuvi Cloud status") + } + + public enum SignOut { + /// Sign out + public static let text = RuuviLocalization.tr("Localizable", "Menu.SignOut.text", fallback: "Sign out") + } + } + + public enum MenuTableViewController { + /// none + public static let none = RuuviLocalization.tr("Localizable", "MenuTableViewController.None", fallback: "none") + /// User: %@ + public static func user(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "MenuTableViewController.User", String(describing: p1), fallback: "User: %@") + } + } + + public enum MyRuuvi { + public enum Settings { + public enum DeleteAccount { + /// Delete Account + public static let title = RuuviLocalization.tr("Localizable", "MyRuuvi.Settings.DeleteAccount.title", fallback: "Delete Account") + public enum Confirmation { + /// A confirmation has been sent to your email. To proceed with the deletion, please check your inbox and follow the instructions. + public static let message = RuuviLocalization.tr("Localizable", "MyRuuvi.Settings.DeleteAccount.Confirmation.message", fallback: "A confirmation has been sent to your email. To proceed with the deletion, please check your inbox and follow the instructions.") + } + } + } + } + + public enum OWMError { + /// API limit exceeded + public static let apiLimitExceeded = RuuviLocalization.tr("Localizable", "OWMError.apiLimitExceeded", fallback: "API limit exceeded") + /// Failed to parse Open Weather Map response + public static let failedToParseOpenWeatherMapResponse = RuuviLocalization.tr("Localizable", "OWMError.failedToParseOpenWeatherMapResponse", fallback: "Failed to parse Open Weather Map response") + /// Invalid API Key + public static let invalidApiKey = RuuviLocalization.tr("Localizable", "OWMError.invalidApiKey", fallback: "Invalid API Key") + /// Not an HTTP response + public static let notAHttpResponse = RuuviLocalization.tr("Localizable", "OWMError.notAHttpResponse", fallback: "Not an HTTP response") + } + + public enum OffsetCorrection { + public enum Calibrate { + /// Offset correction + public static let button = RuuviLocalization.tr("Localizable", "OffsetCorrection.Calibrate.button", fallback: "Offset correction") + } + + public enum CalibrationDescription { + /// In normal use, it's not necessary to adjust the offset. + /// + /// If you're an advanced user and you'd like to manually configure the factory calibrated sensors, it's possible to do so. + /// + /// Calibration tips are available on ruuvi.com/support + public static let text = RuuviLocalization.tr("Localizable", "OffsetCorrection.CalibrationDescription.text", fallback: "In normal use, it's not necessary to adjust the offset.\n\nIf you're an advanced user and you'd like to manually configure the factory calibrated sensors, it's possible to do so.\n\nCalibration tips are available on ruuvi.com/support") + } + + public enum CorrectedValue { + /// Corrected value + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.CorrectedValue.title", fallback: "Corrected value") + } + + public enum Dialog { + public enum Calibration { + /// Clear calibration settings? + public static let clearConfirm = RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.ClearConfirm", fallback: "Clear calibration settings?") + /// Enter the expected humidity value from sensor under current conditions (%@): + public static func enterHumidity(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterHumidity", String(describing: p1), fallback: "Enter the expected humidity value from sensor under current conditions (%@): ") + } + + /// Enter the expected pressure value from sensor under current conditions (%@): + public static func enterPressure(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterPressure", String(describing: p1), fallback: "Enter the expected pressure value from sensor under current conditions (%@): ") + } + + /// Enter the expected temperature value from sensor under current conditions (%@): + public static func enterTemperature(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterTemperature", String(describing: p1), fallback: "Enter the expected temperature value from sensor under current conditions (%@): ") + } + + /// Calibration setup + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.Title", fallback: "Calibration setup") + } + } + + public enum Humidity { + /// Humidity offset + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Humidity.Title", fallback: "Humidity offset") + } + + public enum OriginalValue { + /// Original measured value + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.OriginalValue.title", fallback: "Original measured value") + } + + public enum Pressure { + /// Pressure offset + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Pressure.Title", fallback: "Pressure offset") + } + + public enum Temperature { + /// Temperature offset + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Temperature.Title", fallback: "Temperature offset") + } + } + + public enum Owner { + /// Claim sensor + public static let title = RuuviLocalization.tr("Localizable", "Owner.title", fallback: "Claim sensor") + public enum Claim { + /// Do you own this sensor? If yes, please claim ownership of the sensor and it'll be added to your Ruuvi account. Each Ruuvi sensor can have only one owner. To claim ownership, you need to be signed in. + /// + /// Benefits: + /// + /// ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud + /// + /// ● Access sensors remotely over the Internet (requires a Ruuvi Gateway) + /// + /// ● Share sensors with friends and family (requires a Ruuvi Gateway) + /// + /// ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway) + public static let description = RuuviLocalization.tr("Localizable", "Owner.Claim.description", fallback: "Do you own this sensor? If yes, please claim ownership of the sensor and it'll be added to your Ruuvi account. Each Ruuvi sensor can have only one owner. To claim ownership, you need to be signed in.\n\nBenefits:\n\n ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud\n\n ● Access sensors remotely over the Internet (requires a Ruuvi Gateway)\n\n ● Share sensors with friends and family (requires a Ruuvi Gateway)\n\n ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway)") + } + + public enum ClaimOwnership { + /// Claim ownership + public static let button = RuuviLocalization.tr("Localizable", "Owner.ClaimOwnership.button", fallback: "Claim ownership") + } + } + + public enum PermissionPresenter { + /// Settings + public static let settings = RuuviLocalization.tr("Localizable", "PermissionPresenter.settings", fallback: "Settings") + public enum NoCameraAccess { + /// Ruuvi Station needs to access your camera to enable this feature. + public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoCameraAccess.message", fallback: "Ruuvi Station needs to access your camera to enable this feature.") + } + + public enum NoLocationAccess { + /// Ruuvi Station needs to access your location to enable this feature. + public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoLocationAccess.message", fallback: "Ruuvi Station needs to access your location to enable this feature.") + } + + public enum NoPhotoLibraryAccess { + /// Ruuvi Station needs to access your camera library to enable this feature. + public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoPhotoLibraryAccess.message", fallback: "Ruuvi Station needs to access your camera library to enable this feature.") + } + + public enum NoPushNotificationsPermission { + /// Ruuvi Station needs push notifications permission to enable this feature + public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoPushNotificationsPermission.message", fallback: "Ruuvi Station needs push notifications permission to enable this feature") + } + } + + public enum PhotoPicker { + public enum Sheet { + /// Take photo + public static let camera = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.camera", fallback: "Take photo") + /// Choose from files + public static let files = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.files", fallback: "Choose from files") + /// Choose from the library + public static let library = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.library", fallback: "Choose from the library") + /// Pick a photo + public static let message = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.message", fallback: "Pick a photo") + } + } + + public enum Ruuvi { + public enum BuySensors { + public enum Menu { + public enum Url { + /// https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios + public static let ios = RuuviLocalization.tr("Localizable", "Ruuvi.BuySensors.Menu.URL.IOS", fallback: "https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios") + } + } + + public enum Url { + /// https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios + public static let ios = RuuviLocalization.tr("Localizable", "Ruuvi.BuySensors.URL.IOS", fallback: "https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") + } + } + } + + public enum RuuviCloudApiError { + /// Empty response + public static let emptyResponse = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.emptyResponse", fallback: "Empty response") + /// Failed to get data from response + public static let failedToGetDataFromResponse = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.failedToGetDataFromResponse", fallback: "Failed to get data from response") + /// Unexpected HTTP status code + public static let unexpectedHTTPStatusCode = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.unexpectedHTTPStatusCode", fallback: "Unexpected HTTP status code") + } + + public enum RuuviCloudError { + /// Not authorised + public static let notAuthorized = RuuviLocalization.tr("Localizable", "RuuviCloudError.NotAuthorized", fallback: "Not authorised") + } + + public enum RuuviDfuError { + /// Failed to construct UUID + public static let failedToConstructUUID = RuuviLocalization.tr("Localizable", "RuuviDfuError.failedToConstructUUID", fallback: "Failed to construct UUID") + /// Invalid firmware file + public static let invalidFirmwareFile = RuuviLocalization.tr("Localizable", "RuuviDfuError.invalidFirmwareFile", fallback: "Invalid firmware file") + } + + public enum RuuviLocalError { + /// Failed to get background directory + public static let failedToGetDocumentsDirectory = RuuviLocalization.tr("Localizable", "RuuviLocalError.failedToGetDocumentsDirectory", fallback: "Failed to get background directory") + /// Failed to get JPG representation + public static let failedToGetJpegRepresentation = RuuviLocalization.tr("Localizable", "RuuviLocalError.failedToGetJpegRepresentation", fallback: "Failed to get JPG representation") + } + + public enum RuuviOnboard { + public enum Access { + /// Access data for each linked sensor in real time and explore history graphs. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Access.title", fallback: "Access data for each linked sensor in real time and explore history graphs.") + } + + public enum Alerts { + /// Set alerts and get notified whenever your limits are hit. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Alerts.title", fallback: "Set alerts and get notified whenever your limits are hit.") + } + + public enum Cloud { + /// Claim ownership of your sensors with a free Ruuvi Cloud account. + public static let subtitle = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.subtitle", fallback: "Claim ownership of your sensors with a free Ruuvi Cloud account.") + /// Sign in to use the full potential of the app. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.title", fallback: "Sign in to use the full potential of the app.") + public enum Benefits { + /// Benefits: + /// + /// ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud + /// + /// ● Access sensors remotely over the Internet (requires a Ruuvi Gateway) + /// + /// ● Share sensors with friends and family (requires a Ruuvi Gateway) + /// + /// ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway) + public static let message = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Benefits.message", fallback: "Benefits:\n\n ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud\n\n ● Access sensors remotely over the Internet (requires a Ruuvi Gateway)\n\n ● Share sensors with friends and family (requires a Ruuvi Gateway)\n\n ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway)") + } + + public enum Details { + /// Details + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Details.title", fallback: "Details") + } + + public enum Skip { + /// Are you sure you want to skip sign in? + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.title", fallback: "Are you sure you want to skip sign in?") + public enum GoBack { + /// Go back + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.GoBack.title", fallback: "Go back") + } + + public enum Yes { + /// Yes, skip + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.Yes.title", fallback: "Yes, skip") + } + } + + public enum Subtitle { + /// Great! You already signed in! + public static let signed = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.subtitle.signed", fallback: "Great! You already signed in!") + } + } + + public enum Measure { + /// Measure environmental data: temperature, relative humidity and air pressure. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Measure.title", fallback: "Measure environmental data: temperature, relative humidity and air pressure.") + } + + public enum Start { + /// Press SCAN to find and add nearby sensors to your Ruuvi Station. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Start.title", fallback: "Press SCAN to find and add nearby sensors to your Ruuvi Station.") + } + + public enum Welcome { + /// Swipe to see what Ruuvi Station can do for you. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Welcome.title", fallback: "Swipe to see what Ruuvi Station can do for you.") + } + } + + public enum RuuviPersistenceError { + /// Failed to find sensor + public static let failedToFindRuuviTag = RuuviLocalization.tr("Localizable", "RuuviPersistenceError.failedToFindRuuviTag", fallback: "Failed to find sensor") + } + + public enum RuuviServiceError { + /// Both local and MAC identifiers are nil + public static let bothLuidAndMacAreNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.bothLuidAndMacAreNil", fallback: "Both local and MAC identifiers are nil") + /// Failed to find or generate background image + public static let failedToFindOrGenerateBackgroundImage = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToFindOrGenerateBackgroundImage", fallback: "Failed to find or generate background image") + /// Failed to get JPG representation + public static let failedToGetJpegRepresentation = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToGetJpegRepresentation", fallback: "Failed to get JPG representation") + /// Failed to parse response. + public static let failedToParseNetworkResponse = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToParseNetworkResponse", fallback: "Failed to parse response.") + /// MAC identifier is nil + public static let macIdIsNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.macIdIsNil", fallback: "MAC identifier is nil") + /// Photo URL is nil + public static let pictureUrlIsNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.pictureUrlIsNil", fallback: "Photo URL is nil") + } + public enum Settings { - public enum DeleteAccount { - /// Delete Account - public static let title = RuuviLocalization.tr("Localizable", "MyRuuvi.Settings.DeleteAccount.title", fallback: "Delete Account") - public enum Confirmation { - /// A confirmation has been sent to your email. To proceed with the deletion, please check your inbox and follow the instructions. - public static let message = RuuviLocalization.tr("Localizable", "MyRuuvi.Settings.DeleteAccount.Confirmation.message", fallback: "A confirmation has been sent to your email. To proceed with the deletion, please check your inbox and follow the instructions.") - } - } - } - } - public enum OWMError { - /// API limit exceeded - public static let apiLimitExceeded = RuuviLocalization.tr("Localizable", "OWMError.apiLimitExceeded", fallback: "API limit exceeded") - /// Failed to parse Open Weather Map response - public static let failedToParseOpenWeatherMapResponse = RuuviLocalization.tr("Localizable", "OWMError.failedToParseOpenWeatherMapResponse", fallback: "Failed to parse Open Weather Map response") - /// Invalid API Key - public static let invalidApiKey = RuuviLocalization.tr("Localizable", "OWMError.invalidApiKey", fallback: "Invalid API Key") - /// Not an HTTP response - public static let notAHttpResponse = RuuviLocalization.tr("Localizable", "OWMError.notAHttpResponse", fallback: "Not an HTTP response") - } - public enum OffsetCorrection { - public enum Calibrate { - /// Offset correction - public static let button = RuuviLocalization.tr("Localizable", "OffsetCorrection.Calibrate.button", fallback: "Offset correction") - } - public enum CalibrationDescription { - /// In normal use, it's not necessary to adjust the offset. - /// - /// If you're an advanced user and you'd like to manually configure the factory calibrated sensors, it's possible to do so. - /// - /// Calibration tips are available on ruuvi.com/support - public static let text = RuuviLocalization.tr("Localizable", "OffsetCorrection.CalibrationDescription.text", fallback: "In normal use, it's not necessary to adjust the offset.\n\nIf you're an advanced user and you'd like to manually configure the factory calibrated sensors, it's possible to do so.\n\nCalibration tips are available on ruuvi.com/support") - } - public enum CorrectedValue { - /// Corrected value - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.CorrectedValue.title", fallback: "Corrected value") - } - public enum Dialog { - public enum Calibration { - /// Clear calibration settings? - public static let clearConfirm = RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.ClearConfirm", fallback: "Clear calibration settings?") - /// Enter the expected humidity value from sensor under current conditions (%@): - public static func enterHumidity(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterHumidity", String(describing: p1), fallback: "Enter the expected humidity value from sensor under current conditions (%@): ") - } - /// Enter the expected pressure value from sensor under current conditions (%@): - public static func enterPressure(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterPressure", String(describing: p1), fallback: "Enter the expected pressure value from sensor under current conditions (%@): ") - } - /// Enter the expected temperature value from sensor under current conditions (%@): - public static func enterTemperature(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterTemperature", String(describing: p1), fallback: "Enter the expected temperature value from sensor under current conditions (%@): ") - } - /// Calibration setup - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.Title", fallback: "Calibration setup") - } - } - public enum Humidity { - /// Humidity offset - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Humidity.Title", fallback: "Humidity offset") - } - public enum OriginalValue { - /// Original measured value - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.OriginalValue.title", fallback: "Original measured value") - } - public enum Pressure { - /// Pressure offset - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Pressure.Title", fallback: "Pressure offset") - } - public enum Temperature { - /// Temperature offset - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Temperature.Title", fallback: "Temperature offset") - } - } - public enum Owner { - /// Claim sensor - public static let title = RuuviLocalization.tr("Localizable", "Owner.title", fallback: "Claim sensor") - public enum Claim { - /// Do you own this sensor? If yes, please claim ownership of the sensor and it'll be added to your Ruuvi account. Each Ruuvi sensor can have only one owner. To claim ownership, you need to be signed in. - /// - /// Benefits: - /// - /// ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud - /// - /// ● Access sensors remotely over the Internet (requires a Ruuvi Gateway) - /// - /// ● Share sensors with friends and family (requires a Ruuvi Gateway) - /// - /// ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway) - public static let description = RuuviLocalization.tr("Localizable", "Owner.Claim.description", fallback: "Do you own this sensor? If yes, please claim ownership of the sensor and it'll be added to your Ruuvi account. Each Ruuvi sensor can have only one owner. To claim ownership, you need to be signed in.\n\nBenefits:\n\n ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud\n\n ● Access sensors remotely over the Internet (requires a Ruuvi Gateway)\n\n ● Share sensors with friends and family (requires a Ruuvi Gateway)\n\n ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway)") - } - public enum ClaimOwnership { - /// Claim ownership - public static let button = RuuviLocalization.tr("Localizable", "Owner.ClaimOwnership.button", fallback: "Claim ownership") - } - } - public enum PermissionPresenter { - /// Settings - public static let settings = RuuviLocalization.tr("Localizable", "PermissionPresenter.settings", fallback: "Settings") - public enum NoCameraAccess { - /// Ruuvi Station needs to access your camera to enable this feature. - public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoCameraAccess.message", fallback: "Ruuvi Station needs to access your camera to enable this feature.") - } - public enum NoLocationAccess { - /// Ruuvi Station needs to access your location to enable this feature. - public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoLocationAccess.message", fallback: "Ruuvi Station needs to access your location to enable this feature.") - } - public enum NoPhotoLibraryAccess { - /// Ruuvi Station needs to access your camera library to enable this feature. - public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoPhotoLibraryAccess.message", fallback: "Ruuvi Station needs to access your camera library to enable this feature.") - } - public enum NoPushNotificationsPermission { - /// Ruuvi Station needs push notifications permission to enable this feature - public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoPushNotificationsPermission.message", fallback: "Ruuvi Station needs push notifications permission to enable this feature") - } - } - public enum PhotoPicker { - public enum Sheet { - /// Take photo - public static let camera = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.camera", fallback: "Take photo") - /// Choose from files - public static let files = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.files", fallback: "Choose from files") - /// Choose from the library - public static let library = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.library", fallback: "Choose from the library") - /// Pick a photo - public static let message = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.message", fallback: "Pick a photo") - } - } - public enum Ruuvi { - public enum BuySensors { - public enum Menu { - public enum Url { - /// https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios - public static let ios = RuuviLocalization.tr("Localizable", "Ruuvi.BuySensors.Menu.URL.IOS", fallback: "https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios") - } - } - public enum Url { - /// https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios - public static let ios = RuuviLocalization.tr("Localizable", "Ruuvi.BuySensors.URL.IOS", fallback: "https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") - } - } - } - public enum RuuviCloudApiError { - /// Empty response - public static let emptyResponse = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.emptyResponse", fallback: "Empty response") - /// Failed to get data from response - public static let failedToGetDataFromResponse = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.failedToGetDataFromResponse", fallback: "Failed to get data from response") - /// Unexpected HTTP status code - public static let unexpectedHTTPStatusCode = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.unexpectedHTTPStatusCode", fallback: "Unexpected HTTP status code") - } - public enum RuuviCloudError { - /// Not authorised - public static let notAuthorized = RuuviLocalization.tr("Localizable", "RuuviCloudError.NotAuthorized", fallback: "Not authorised") - } - public enum RuuviDfuError { - /// Failed to construct UUID - public static let failedToConstructUUID = RuuviLocalization.tr("Localizable", "RuuviDfuError.failedToConstructUUID", fallback: "Failed to construct UUID") - /// Invalid firmware file - public static let invalidFirmwareFile = RuuviLocalization.tr("Localizable", "RuuviDfuError.invalidFirmwareFile", fallback: "Invalid firmware file") - } - public enum RuuviLocalError { - /// Failed to get background directory - public static let failedToGetDocumentsDirectory = RuuviLocalization.tr("Localizable", "RuuviLocalError.failedToGetDocumentsDirectory", fallback: "Failed to get background directory") - /// Failed to get JPG representation - public static let failedToGetJpegRepresentation = RuuviLocalization.tr("Localizable", "RuuviLocalError.failedToGetJpegRepresentation", fallback: "Failed to get JPG representation") - } - public enum RuuviOnboard { - public enum Access { - /// Access data for each linked sensor in real time and explore history graphs. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Access.title", fallback: "Access data for each linked sensor in real time and explore history graphs.") - } - public enum Alerts { - /// Set alerts and get notified whenever your limits are hit. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Alerts.title", fallback: "Set alerts and get notified whenever your limits are hit.") - } - public enum Cloud { - /// Claim ownership of your sensors with a free Ruuvi Cloud account. - public static let subtitle = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.subtitle", fallback: "Claim ownership of your sensors with a free Ruuvi Cloud account.") - /// Sign in to use the full potential of the app. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.title", fallback: "Sign in to use the full potential of the app.") - public enum Benefits { - /// Benefits: - /// - /// ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud - /// - /// ● Access sensors remotely over the Internet (requires a Ruuvi Gateway) - /// - /// ● Share sensors with friends and family (requires a Ruuvi Gateway) - /// - /// ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway) - public static let message = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Benefits.message", fallback: "Benefits:\n\n ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud\n\n ● Access sensors remotely over the Internet (requires a Ruuvi Gateway)\n\n ● Share sensors with friends and family (requires a Ruuvi Gateway)\n\n ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway)") - } - public enum Details { - /// Details - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Details.title", fallback: "Details") - } - public enum Skip { - /// Are you sure you want to skip sign in? - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.title", fallback: "Are you sure you want to skip sign in?") - public enum GoBack { - /// Go back - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.GoBack.title", fallback: "Go back") - } - public enum Yes { - /// Yes, skip - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.Yes.title", fallback: "Yes, skip") - } - } - public enum Subtitle { - /// Great! You already signed in! - public static let signed = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.subtitle.signed", fallback: "Great! You already signed in!") - } - } - public enum Measure { - /// Measure environmental data: temperature, relative humidity and air pressure. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Measure.title", fallback: "Measure environmental data: temperature, relative humidity and air pressure.") - } - public enum Start { - /// Press SCAN to find and add nearby sensors to your Ruuvi Station. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Start.title", fallback: "Press SCAN to find and add nearby sensors to your Ruuvi Station.") + public enum BackgroundScanning { + /// Data logging interval + public static let interval = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.interval", fallback: "Data logging interval") + /// Background Scanning + public static let title = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.title", fallback: "Background Scanning") + public enum Footer { + /// Important note: Bluetooth background history logging and Bluetooth alerts work only when background scanning is enabled. If you disable the background scanning, all paired Ruuvi sensors will be automatically unpaired and you need to pair them again from their settings pages. + public static let message = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.Footer.message", fallback: "Important note: Bluetooth background history logging and Bluetooth alerts work only when background scanning is enabled. If you disable the background scanning, all paired Ruuvi sensors will be automatically unpaired and you need to pair them again from their settings pages.") + } + } + + public enum ChooseHumidityUnit { + /// Choose the humidity unit you want to be displayed. + public static let text = RuuviLocalization.tr("Localizable", "Settings.ChooseHumidityUnit.text", fallback: "Choose the humidity unit you want to be displayed.") + } + + public enum ChoosePressureUnit { + /// Choose the pressure unit you want to be displayed. + public static let text = RuuviLocalization.tr("Localizable", "Settings.ChoosePressureUnit.text", fallback: "Choose the pressure unit you want to be displayed.") + } + + public enum ChooseTemperatureUnit { + /// Choose the temperature unit you want to be displayed. + public static let text = RuuviLocalization.tr("Localizable", "Settings.ChooseTemperatureUnit.text", fallback: "Choose the temperature unit you want to be displayed.") + } + + public enum Humidity { + public enum Resolution { + /// Humidity Resolution + public static let title = RuuviLocalization.tr("Localizable", "Settings.Humidity.Resolution.title", fallback: "Humidity Resolution") + } + } + + public enum Label { + /// Chart Settings + public static let chart = RuuviLocalization.tr("Localizable", "Settings.Label.Chart", fallback: "Chart Settings") + /// Cloud mode + public static let cloudMode = RuuviLocalization.tr("Localizable", "Settings.Label.CloudMode", fallback: "Cloud mode") + /// Defaults + public static let defaults = RuuviLocalization.tr("Localizable", "Settings.Label.Defaults", fallback: "Defaults") + /// Foreground + public static let foreground = RuuviLocalization.tr("Localizable", "Settings.Label.Foreground", fallback: "Foreground") + /// Humidity + public static let humidity = RuuviLocalization.tr("Localizable", "Settings.Label.Humidity", fallback: "Humidity") + /// Pressure + public static let pressure = RuuviLocalization.tr("Localizable", "Settings.Label.Pressure", fallback: "Pressure") + /// Temperature + public static let temperature = RuuviLocalization.tr("Localizable", "Settings.Label.Temperature", fallback: "Temperature") + public enum CloudMode { + /// Refresh nearby cloud sensors only from the cloud by ignoring their Bluetooth messages and receiving alerts only by email. Requires a Ruuvi Gateway router. + public static let description = RuuviLocalization.tr("Localizable", "Settings.Label.CloudMode.description", fallback: "Refresh nearby cloud sensors only from the cloud by ignoring their Bluetooth messages and receiving alerts only by email. Requires a Ruuvi Gateway router.") + } + + public enum HumidityUnit { + /// Humidity Unit + public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.HumidityUnit.text", fallback: "Humidity Unit") + } + + public enum Language { + /// Language + public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.Language.text", fallback: "Language") + } + + public enum PressureUnit { + /// Pressure Unit + public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.PressureUnit.text", fallback: "Pressure Unit") + } + + public enum TemperatureUnit { + /// Temperature Unit + public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.TemperatureUnit.text", fallback: "Temperature Unit") + } + } + + public enum Language { + public enum Dialog { + /// Open settings and tap Language to change language of the app. + /// If you cannot see the Language option in the settings, make sure that you have at least one preferred language added in system settings: Settings -> General -> Language & Region. + public static let message = RuuviLocalization.tr("Localizable", "Settings.Language.Dialog.message", fallback: "Open settings and tap Language to change language of the app.\nIf you cannot see the Language option in the settings, make sure that you have at least one preferred language added in system settings: Settings -> General -> Language & Region.") + /// Select Language + public static let title = RuuviLocalization.tr("Localizable", "Settings.Language.Dialog.title", fallback: "Select Language") + } + } + + public enum Measurement { + public enum Resolution { + /// Select how accurately you'd like to see the sensors' live measurement values in the app. This setting doesn't affect history charts or alerts. + public static let description = RuuviLocalization.tr("Localizable", "Settings.Measurement.Resolution.description", fallback: "Select how accurately you'd like to see the sensors' live measurement values in the app. This setting doesn't affect history charts or alerts.") + /// Resolution + public static let title = RuuviLocalization.tr("Localizable", "Settings.Measurement.Resolution.title", fallback: "Resolution") + } + + public enum Unit { + /// Unit + public static let title = RuuviLocalization.tr("Localizable", "Settings.Measurement.Unit.title", fallback: "Unit") + } + } + + public enum Pressure { + public enum Resolution { + /// Pressure Resolution + public static let title = RuuviLocalization.tr("Localizable", "Settings.Pressure.Resolution.title", fallback: "Pressure Resolution") + } + } + + public enum SectionHeader { + public enum Application { + /// APPLICATION + public static let title = RuuviLocalization.tr("Localizable", "Settings.SectionHeader.Application.title", fallback: "APPLICATION") + } + + public enum General { + /// GENERAL + public static let title = RuuviLocalization.tr("Localizable", "Settings.SectionHeader.General.title", fallback: "GENERAL") + } + } + + public enum SegmentedControl { + public enum Humidity { + public enum Absolute { + /// Abs + public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.Absolute.title", fallback: "Abs") + } + + public enum DewPoint { + /// Dew + public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.DewPoint.title", fallback: "Dew") + } + + public enum Relative { + /// Rel + public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.Relative.title", fallback: "Rel") + } + } + } + + public enum Temperature { + public enum Resolution { + /// Temperature Resolution + public static let title = RuuviLocalization.tr("Localizable", "Settings.Temperature.Resolution.title", fallback: "Temperature Resolution") + } + } + + public enum NavigationItem { + /// Settings + public static let title = RuuviLocalization.tr("Localizable", "Settings.navigationItem.title", fallback: "Settings") + } + } + + public enum Share { + public enum Send { + /// Send + public static let button = RuuviLocalization.tr("Localizable", "Share.Send.button", fallback: "Send") + } + + public enum Success { + /// Successfully shared sensor + public static let message = RuuviLocalization.tr("Localizable", "Share.Success.message", fallback: "Successfully shared sensor") + } + } + + public enum SharePresenter { + public enum UnshareSensor { + /// Do you want to unshare sensor for %@? + public static func message(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "SharePresenter.UnshareSensor.Message", String(describing: p1), fallback: "Do you want to unshare sensor for %@?") + } + } + } + + public enum ShareViewController { + /// You can share the sensor with friends and family if it's in range of a Ruuvi Gateway. + /// + /// Receiver will be notified by email. If the receiver doesn't have a Ruuvi account, a free Ruuvi account will automatically be created at first log in. + /// + /// Note that the sensor's custom name and background image will be shared. The name and image sync is one time only, and after this, they can be privately customised by the receiver. Offset values (if any) set by the owner, will be automatically synced, and the receiver will always see the final corrected values. + public static let description = RuuviLocalization.tr("Localizable", "ShareViewController.Description", fallback: "You can share the sensor with friends and family if it's in range of a Ruuvi Gateway.\n\nReceiver will be notified by email. If the receiver doesn't have a Ruuvi account, a free Ruuvi account will automatically be created at first log in.\n\nNote that the sensor's custom name and background image will be shared. The name and image sync is one time only, and after this, they can be privately customised by the receiver. Offset values (if any) set by the owner, will be automatically synced, and the receiver will always see the final corrected values.") + /// Share sensor + public static let title = RuuviLocalization.tr("Localizable", "ShareViewController.Title", fallback: "Share sensor") + public enum AddFriend { + /// Add friend + public static let title = RuuviLocalization.tr("Localizable", "ShareViewController.addFriend.Title", fallback: "Add friend") + } + + public enum EmailTextField { + /// Type email + public static let placeholder = RuuviLocalization.tr("Localizable", "ShareViewController.emailTextField.placeholder", fallback: "Type email") + } + + public enum SharedEmails { + /// You have used %d/%d of maximum shares of this sensor. The sensor has been shared to following users: + public static func title(_ p1: Int, _ p2: Int) -> String { + RuuviLocalization.tr("Localizable", "ShareViewController.sharedEmails.Title", p1, p2, fallback: "You have used %d/%d of maximum shares of this sensor. The sensor has been shared to following users:") + } + } + } + + public enum SignIn { + /// We've sent a one-time password to your email %@. Sign in by entering it here: + public static func checkMailbox(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "SignIn.CheckMailbox", String(describing: p1), fallback: "We've sent a one-time password to your email %@. Sign in by entering it here:") + } + + /// Code + public static let codeHint = RuuviLocalization.tr("Localizable", "SignIn.CodeHint", fallback: "Code") + /// Email + public static let emailPlaceholder = RuuviLocalization.tr("Localizable", "SignIn.EmailPlaceholder", fallback: "Email") + /// Email sent + public static let emailSent = RuuviLocalization.tr("Localizable", "SignIn.EmailSent", fallback: "Email sent") + /// Please enter verification code + public static let enterVerificationCode = RuuviLocalization.tr("Localizable", "SignIn.EnterVerificationCode", fallback: "Please enter verification code") + /// Request a code + public static let requestCode = RuuviLocalization.tr("Localizable", "SignIn.RequestCode", fallback: "Request a code") + /// Submit + public static let submitCode = RuuviLocalization.tr("Localizable", "SignIn.SubmitCode", fallback: "Submit") + /// verification code in format: CJSM + public static let verificationCodePlaceholder = RuuviLocalization.tr("Localizable", "SignIn.VerificationCodePlaceholder", fallback: "verification code in format: CJSM") + public enum EmailMismatch { + public enum Alert { + /// Oops, you've requested the code for %@, but used the code for %@. Please double check that you are using the code for %@ + public static func message(_ p1: Any, _ p2: Any, _ p3: Any) -> String { + RuuviLocalization.tr("Localizable", "SignIn.EmailMismatch.Alert.message", String(describing: p1), String(describing: p2), String(describing: p3), fallback: "Oops, you've requested the code for %@, but used the code for %@. Please double check that you are using the code for %@") + } + } + } + + public enum EmailMissing { + public enum Alert { + /// Oops, the email you've used to get the code was not saved. Please try to sign in again. + public static let message = RuuviLocalization.tr("Localizable", "SignIn.EmailMissing.Alert.message", fallback: "Oops, the email you've used to get the code was not saved. Please try to sign in again.") + } + } + + public enum SubtitleLabel { + /// To enjoy all the features, create a free account or sign in to your existing Ruuvi account by entering your email address. + public static let text = RuuviLocalization.tr("Localizable", "SignIn.SubtitleLabel.text", fallback: "To enjoy all the features, create a free account or sign in to your existing Ruuvi account by entering your email address.") + } + + public enum Sync { + /// Downloading content from the cloud. Please wait. + public static let message = RuuviLocalization.tr("Localizable", "SignIn.Sync.message", fallback: "Downloading content from the cloud. Please wait.") + } + + public enum Title { + /// Sign in + public static let text = RuuviLocalization.tr("Localizable", "SignIn.Title.text", fallback: "Sign in") + } + + public enum TitleLabel { + /// Sign in to + /// Ruuvi + /// Station + public static let text = RuuviLocalization.tr("Localizable", "SignIn.TitleLabel.text", fallback: "Sign in to\nRuuvi\nStation") + } } - public enum Welcome { - /// Swipe to see what Ruuvi Station can do for you. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Welcome.title", fallback: "Swipe to see what Ruuvi Station can do for you.") - } - } - public enum RuuviPersistenceError { - /// Failed to find sensor - public static let failedToFindRuuviTag = RuuviLocalization.tr("Localizable", "RuuviPersistenceError.failedToFindRuuviTag", fallback: "Failed to find sensor") - } - public enum RuuviServiceError { - /// Both local and MAC identifiers are nil - public static let bothLuidAndMacAreNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.bothLuidAndMacAreNil", fallback: "Both local and MAC identifiers are nil") - /// Failed to find or generate background image - public static let failedToFindOrGenerateBackgroundImage = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToFindOrGenerateBackgroundImage", fallback: "Failed to find or generate background image") - /// Failed to get JPG representation - public static let failedToGetJpegRepresentation = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToGetJpegRepresentation", fallback: "Failed to get JPG representation") - /// Failed to parse response. - public static let failedToParseNetworkResponse = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToParseNetworkResponse", fallback: "Failed to parse response.") - /// MAC identifier is nil - public static let macIdIsNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.macIdIsNil", fallback: "MAC identifier is nil") - /// Photo URL is nil - public static let pictureUrlIsNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.pictureUrlIsNil", fallback: "Photo URL is nil") - } - public enum Settings { - public enum BackgroundScanning { - /// Data logging interval - public static let interval = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.interval", fallback: "Data logging interval") - /// Background Scanning - public static let title = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.title", fallback: "Background Scanning") - public enum Footer { - /// Important note: Bluetooth background history logging and Bluetooth alerts work only when background scanning is enabled. If you disable the background scanning, all paired Ruuvi sensors will be automatically unpaired and you need to pair them again from their settings pages. - public static let message = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.Footer.message", fallback: "Important note: Bluetooth background history logging and Bluetooth alerts work only when background scanning is enabled. If you disable the background scanning, all paired Ruuvi sensors will be automatically unpaired and you need to pair them again from their settings pages.") - } - } - public enum ChooseHumidityUnit { - /// Choose the humidity unit you want to be displayed. - public static let text = RuuviLocalization.tr("Localizable", "Settings.ChooseHumidityUnit.text", fallback: "Choose the humidity unit you want to be displayed.") - } - public enum ChoosePressureUnit { - /// Choose the pressure unit you want to be displayed. - public static let text = RuuviLocalization.tr("Localizable", "Settings.ChoosePressureUnit.text", fallback: "Choose the pressure unit you want to be displayed.") - } - public enum ChooseTemperatureUnit { - /// Choose the temperature unit you want to be displayed. - public static let text = RuuviLocalization.tr("Localizable", "Settings.ChooseTemperatureUnit.text", fallback: "Choose the temperature unit you want to be displayed.") - } - public enum Humidity { - public enum Resolution { - /// Humidity Resolution - public static let title = RuuviLocalization.tr("Localizable", "Settings.Humidity.Resolution.title", fallback: "Humidity Resolution") - } - } - public enum Label { - /// Chart Settings - public static let chart = RuuviLocalization.tr("Localizable", "Settings.Label.Chart", fallback: "Chart Settings") - /// Cloud mode - public static let cloudMode = RuuviLocalization.tr("Localizable", "Settings.Label.CloudMode", fallback: "Cloud mode") - /// Defaults - public static let defaults = RuuviLocalization.tr("Localizable", "Settings.Label.Defaults", fallback: "Defaults") - /// Foreground - public static let foreground = RuuviLocalization.tr("Localizable", "Settings.Label.Foreground", fallback: "Foreground") - /// Humidity - public static let humidity = RuuviLocalization.tr("Localizable", "Settings.Label.Humidity", fallback: "Humidity") - /// Pressure - public static let pressure = RuuviLocalization.tr("Localizable", "Settings.Label.Pressure", fallback: "Pressure") - /// Temperature - public static let temperature = RuuviLocalization.tr("Localizable", "Settings.Label.Temperature", fallback: "Temperature") - public enum CloudMode { - /// Refresh nearby cloud sensors only from the cloud by ignoring their Bluetooth messages and receiving alerts only by email. Requires a Ruuvi Gateway router. - public static let description = RuuviLocalization.tr("Localizable", "Settings.Label.CloudMode.description", fallback: "Refresh nearby cloud sensors only from the cloud by ignoring their Bluetooth messages and receiving alerts only by email. Requires a Ruuvi Gateway router.") - } - public enum HumidityUnit { - /// Humidity Unit - public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.HumidityUnit.text", fallback: "Humidity Unit") - } - public enum Language { - /// Language - public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.Language.text", fallback: "Language") - } - public enum PressureUnit { - /// Pressure Unit - public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.PressureUnit.text", fallback: "Pressure Unit") - } - public enum TemperatureUnit { - /// Temperature Unit - public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.TemperatureUnit.text", fallback: "Temperature Unit") - } + + public enum TagCharts { + public enum AbortSync { + public enum Alert { + /// Sometimes the history download is slow due to the Bluetooth connectivity. Please wait a moment. + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.AbortSync.Alert.message", fallback: "Sometimes the history download is slow due to the Bluetooth connectivity. Please wait a moment.") + } + + public enum Button { + /// Abort download + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.AbortSync.Button.title", fallback: "Abort download") + } + } + + public enum BluetoothDisabledAlert { + /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") + /// Bluetooth is not enabled + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") + } + + public enum Clear { + /// Clear + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Clear.title", fallback: "Clear") + } + + public enum DeleteHistoryConfirmationDialog { + /// Clear the local history data from the app? + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.message", fallback: "Clear the local history data from the app?") + /// Are you sure? + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.title", fallback: "Are you sure?") + public enum Button { + public enum Delete { + /// Delete + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.button.delete.title", fallback: "Delete") + } + } + } + + public enum Dismiss { + public enum Alert { + /// The history download via Bluetooth connection is in progress. Please wait. + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.Dismiss.Alert.message", fallback: "The history download via Bluetooth connection is in progress. Please wait.") + } + } + + public enum Export { + /// EXPORT + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Export.title", fallback: "EXPORT") + } + + public enum FailedToSyncDialog { + /// Bluetooth history download failed. Check that you're within Bluetooth range, your sensor has firmware that supports downloading and that the sensor is not simultaneously connected to another iOS device. Sensor connection is reserved for Ruuvi Station when using connected mode in iOS. + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.FailedToSyncDialog.message", fallback: "Bluetooth history download failed. Check that you're within Bluetooth range, your sensor has firmware that supports downloading and that the sensor is not simultaneously connected to another iOS device. Sensor connection is reserved for Ruuvi Station when using connected mode in iOS.") + /// Download failed + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.FailedToSyncDialog.title", fallback: "Download failed") + } + + public enum NoChartData { + /// No chart data available + public static let text = RuuviLocalization.tr("Localizable", "TagCharts.NoChartData.text", fallback: "No chart data available") + } + + public enum Status { + /// Connecting... + public static let connecting = RuuviLocalization.tr("Localizable", "TagCharts.Status.Connecting", fallback: "Connecting...") + /// Disconnecting... + public static let disconnecting = RuuviLocalization.tr("Localizable", "TagCharts.Status.Disconnecting", fallback: "Disconnecting...") + /// Error + public static let error = RuuviLocalization.tr("Localizable", "TagCharts.Status.Error", fallback: "Error") + /// Reading history + public static let readingHistory = RuuviLocalization.tr("Localizable", "TagCharts.Status.ReadingHistory", fallback: "Reading history") + /// Synchronising... + public static let serving = RuuviLocalization.tr("Localizable", "TagCharts.Status.Serving", fallback: "Synchronising...") + /// Success + public static let success = RuuviLocalization.tr("Localizable", "TagCharts.Status.Success", fallback: "Success") + } + + public enum Sync { + /// Sync + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Sync.title", fallback: "Sync") + } + + public enum SyncConfirmationDialog { + /// Download history data from the sensor? + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.SyncConfirmationDialog.message", fallback: "Download history data from the sensor?") + /// Are you sure? + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.SyncConfirmationDialog.title", fallback: "Are you sure?") + } + + public enum TryAgain { + /// Try again + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.TryAgain.title", fallback: "Try again") + } } - public enum Language { - public enum Dialog { - /// Open settings and tap Language to change language of the app. - /// If you cannot see the Language option in the settings, make sure that you have at least one preferred language added in system settings: Settings -> General -> Language & Region. - public static let message = RuuviLocalization.tr("Localizable", "Settings.Language.Dialog.message", fallback: "Open settings and tap Language to change language of the app.\nIf you cannot see the Language option in the settings, make sure that you have at least one preferred language added in system settings: Settings -> General -> Language & Region.") - /// Select Language - public static let title = RuuviLocalization.tr("Localizable", "Settings.Language.Dialog.title", fallback: "Select Language") - } - } - public enum Measurement { - public enum Resolution { - /// Select how accurately you'd like to see the sensors' live measurement values in the app. This setting doesn't affect history charts or alerts. - public static let description = RuuviLocalization.tr("Localizable", "Settings.Measurement.Resolution.description", fallback: "Select how accurately you'd like to see the sensors' live measurement values in the app. This setting doesn't affect history charts or alerts.") - /// Resolution - public static let title = RuuviLocalization.tr("Localizable", "Settings.Measurement.Resolution.title", fallback: "Resolution") - } - public enum Unit { - /// Unit - public static let title = RuuviLocalization.tr("Localizable", "Settings.Measurement.Unit.title", fallback: "Unit") - } - } - public enum Pressure { - public enum Resolution { - /// Pressure Resolution - public static let title = RuuviLocalization.tr("Localizable", "Settings.Pressure.Resolution.title", fallback: "Pressure Resolution") - } - } - public enum SectionHeader { - public enum Application { - /// APPLICATION - public static let title = RuuviLocalization.tr("Localizable", "Settings.SectionHeader.Application.title", fallback: "APPLICATION") - } - public enum General { - /// GENERAL - public static let title = RuuviLocalization.tr("Localizable", "Settings.SectionHeader.General.title", fallback: "GENERAL") - } - } - public enum SegmentedControl { - public enum Humidity { - public enum Absolute { - /// Abs - public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.Absolute.title", fallback: "Abs") - } - public enum DewPoint { - /// Dew - public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.DewPoint.title", fallback: "Dew") - } - public enum Relative { - /// Rel - public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.Relative.title", fallback: "Rel") - } - } - } - public enum Temperature { - public enum Resolution { - /// Temperature Resolution - public static let title = RuuviLocalization.tr("Localizable", "Settings.Temperature.Resolution.title", fallback: "Temperature Resolution") - } - } - public enum NavigationItem { - /// Settings - public static let title = RuuviLocalization.tr("Localizable", "Settings.navigationItem.title", fallback: "Settings") - } - } - public enum Share { - public enum Send { - /// Send - public static let button = RuuviLocalization.tr("Localizable", "Share.Send.button", fallback: "Send") - } - public enum Success { - /// Successfully shared sensor - public static let message = RuuviLocalization.tr("Localizable", "Share.Success.message", fallback: "Successfully shared sensor") - } - } - public enum SharePresenter { - public enum UnshareSensor { - /// Do you want to unshare sensor for %@? - public static func message(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "SharePresenter.UnshareSensor.Message", String(describing: p1), fallback: "Do you want to unshare sensor for %@?") - } - } - } - public enum ShareViewController { - /// You can share the sensor with friends and family if it's in range of a Ruuvi Gateway. - /// - /// Receiver will be notified by email. If the receiver doesn't have a Ruuvi account, a free Ruuvi account will automatically be created at first log in. - /// - /// Note that the sensor's custom name and background image will be shared. The name and image sync is one time only, and after this, they can be privately customised by the receiver. Offset values (if any) set by the owner, will be automatically synced, and the receiver will always see the final corrected values. - public static let description = RuuviLocalization.tr("Localizable", "ShareViewController.Description", fallback: "You can share the sensor with friends and family if it's in range of a Ruuvi Gateway.\n\nReceiver will be notified by email. If the receiver doesn't have a Ruuvi account, a free Ruuvi account will automatically be created at first log in.\n\nNote that the sensor's custom name and background image will be shared. The name and image sync is one time only, and after this, they can be privately customised by the receiver. Offset values (if any) set by the owner, will be automatically synced, and the receiver will always see the final corrected values.") - /// Share sensor - public static let title = RuuviLocalization.tr("Localizable", "ShareViewController.Title", fallback: "Share sensor") - public enum AddFriend { - /// Add friend - public static let title = RuuviLocalization.tr("Localizable", "ShareViewController.addFriend.Title", fallback: "Add friend") - } - public enum EmailTextField { - /// Type email - public static let placeholder = RuuviLocalization.tr("Localizable", "ShareViewController.emailTextField.placeholder", fallback: "Type email") - } - public enum SharedEmails { - /// You have used %d/%d of maximum shares of this sensor. The sensor has been shared to following users: - public static func title(_ p1: Int, _ p2: Int) -> String { - return RuuviLocalization.tr("Localizable", "ShareViewController.sharedEmails.Title", p1, p2, fallback: "You have used %d/%d of maximum shares of this sensor. The sensor has been shared to following users:") - } - } - } - public enum SignIn { - /// We've sent a one-time password to your email %@. Sign in by entering it here: - public static func checkMailbox(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "SignIn.CheckMailbox", String(describing: p1), fallback: "We've sent a one-time password to your email %@. Sign in by entering it here:") - } - /// Code - public static let codeHint = RuuviLocalization.tr("Localizable", "SignIn.CodeHint", fallback: "Code") - /// Email - public static let emailPlaceholder = RuuviLocalization.tr("Localizable", "SignIn.EmailPlaceholder", fallback: "Email") - /// Email sent - public static let emailSent = RuuviLocalization.tr("Localizable", "SignIn.EmailSent", fallback: "Email sent") - /// Please enter verification code - public static let enterVerificationCode = RuuviLocalization.tr("Localizable", "SignIn.EnterVerificationCode", fallback: "Please enter verification code") - /// Request a code - public static let requestCode = RuuviLocalization.tr("Localizable", "SignIn.RequestCode", fallback: "Request a code") - /// Submit - public static let submitCode = RuuviLocalization.tr("Localizable", "SignIn.SubmitCode", fallback: "Submit") - /// verification code in format: CJSM - public static let verificationCodePlaceholder = RuuviLocalization.tr("Localizable", "SignIn.VerificationCodePlaceholder", fallback: "verification code in format: CJSM") - public enum EmailMismatch { - public enum Alert { - /// Oops, you've requested the code for %@, but used the code for %@. Please double check that you are using the code for %@ - public static func message(_ p1: Any, _ p2: Any, _ p3: Any) -> String { - return RuuviLocalization.tr("Localizable", "SignIn.EmailMismatch.Alert.message", String(describing: p1), String(describing: p2), String(describing: p3), fallback: "Oops, you've requested the code for %@, but used the code for %@. Please double check that you are using the code for %@") - } - } - } - public enum EmailMissing { - public enum Alert { - /// Oops, the email you've used to get the code was not saved. Please try to sign in again. - public static let message = RuuviLocalization.tr("Localizable", "SignIn.EmailMissing.Alert.message", fallback: "Oops, the email you've used to get the code was not saved. Please try to sign in again.") - } - } - public enum SubtitleLabel { - /// To enjoy all the features, create a free account or sign in to your existing Ruuvi account by entering your email address. - public static let text = RuuviLocalization.tr("Localizable", "SignIn.SubtitleLabel.text", fallback: "To enjoy all the features, create a free account or sign in to your existing Ruuvi account by entering your email address.") - } - public enum Sync { - /// Downloading content from the cloud. Please wait. - public static let message = RuuviLocalization.tr("Localizable", "SignIn.Sync.message", fallback: "Downloading content from the cloud. Please wait.") - } - public enum Title { - /// Sign in - public static let text = RuuviLocalization.tr("Localizable", "SignIn.Title.text", fallback: "Sign in") - } - public enum TitleLabel { - /// Sign in to - /// Ruuvi - /// Station - public static let text = RuuviLocalization.tr("Localizable", "SignIn.TitleLabel.text", fallback: "Sign in to\nRuuvi\nStation") - } - } - public enum TagCharts { - public enum AbortSync { - public enum Alert { - /// Sometimes the history download is slow due to the Bluetooth connectivity. Please wait a moment. - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.AbortSync.Alert.message", fallback: "Sometimes the history download is slow due to the Bluetooth connectivity. Please wait a moment.") - } - public enum Button { - /// Abort download - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.AbortSync.Button.title", fallback: "Abort download") - } - } - public enum BluetoothDisabledAlert { - /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") - /// Bluetooth is not enabled - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") - } - public enum Clear { - /// Clear - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Clear.title", fallback: "Clear") - } - public enum DeleteHistoryConfirmationDialog { - /// Clear the local history data from the app? - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.message", fallback: "Clear the local history data from the app?") - /// Are you sure? - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.title", fallback: "Are you sure?") - public enum Button { - public enum Delete { - /// Delete - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.button.delete.title", fallback: "Delete") - } - } - } - public enum Dismiss { - public enum Alert { - /// The history download via Bluetooth connection is in progress. Please wait. - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.Dismiss.Alert.message", fallback: "The history download via Bluetooth connection is in progress. Please wait.") - } - } - public enum Export { - /// EXPORT - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Export.title", fallback: "EXPORT") - } - public enum FailedToSyncDialog { - /// Bluetooth history download failed. Check that you're within Bluetooth range, your sensor has firmware that supports downloading and that the sensor is not simultaneously connected to another iOS device. Sensor connection is reserved for Ruuvi Station when using connected mode in iOS. - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.FailedToSyncDialog.message", fallback: "Bluetooth history download failed. Check that you're within Bluetooth range, your sensor has firmware that supports downloading and that the sensor is not simultaneously connected to another iOS device. Sensor connection is reserved for Ruuvi Station when using connected mode in iOS.") - /// Download failed - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.FailedToSyncDialog.title", fallback: "Download failed") - } - public enum NoChartData { - /// No chart data available - public static let text = RuuviLocalization.tr("Localizable", "TagCharts.NoChartData.text", fallback: "No chart data available") - } - public enum Status { - /// Connecting... - public static let connecting = RuuviLocalization.tr("Localizable", "TagCharts.Status.Connecting", fallback: "Connecting...") - /// Disconnecting... - public static let disconnecting = RuuviLocalization.tr("Localizable", "TagCharts.Status.Disconnecting", fallback: "Disconnecting...") - /// Error - public static let error = RuuviLocalization.tr("Localizable", "TagCharts.Status.Error", fallback: "Error") - /// Reading history - public static let readingHistory = RuuviLocalization.tr("Localizable", "TagCharts.Status.ReadingHistory", fallback: "Reading history") - /// Synchronising... - public static let serving = RuuviLocalization.tr("Localizable", "TagCharts.Status.Serving", fallback: "Synchronising...") - /// Success - public static let success = RuuviLocalization.tr("Localizable", "TagCharts.Status.Success", fallback: "Success") - } - public enum Sync { - /// Sync - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Sync.title", fallback: "Sync") - } - public enum SyncConfirmationDialog { - /// Download history data from the sensor? - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.SyncConfirmationDialog.message", fallback: "Download history data from the sensor?") - /// Are you sure? - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.SyncConfirmationDialog.title", fallback: "Are you sure?") - } - public enum TryAgain { - /// Try again - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.TryAgain.title", fallback: "Try again") - } - } - public enum TagChartsPresenter { - /// Synchronised: %@ - public static func numberOfPointsSynchronizedOverNetwork(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "TagChartsPresenter.NumberOfPointsSynchronizedOverNetwork", String(describing: p1), fallback: "Synchronised: %@") - } - } - public enum TagSettings { - /// Share - public static let shareButton = RuuviLocalization.tr("Localizable", "TagSettings.ShareButton", fallback: "Share") - public enum AirHumidityAlert { - /// Air Humidity (%@) - public static func title(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "TagSettings.AirHumidityAlert.title", String(describing: p1), fallback: "Air Humidity (%@)") - } - } - public enum Alert { - public enum CustomDescription { - /// Set custom description... - public static let placeholder = RuuviLocalization.tr("Localizable", "TagSettings.Alert.CustomDescription.placeholder", fallback: "Set custom description...") - /// Alert custom description - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.CustomDescription.title", fallback: "Alert custom description") - } - public enum SetHumidity { - /// Set humidity alert - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetHumidity.title", fallback: "Set humidity alert") - } - public enum SetPressure { - /// Set pressure alert - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetPressure.title", fallback: "Set pressure alert") - } - public enum SetRSSI { - /// Set signal strength alert - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetRSSI.title", fallback: "Set signal strength alert") - } - public enum SetTemperature { - /// Set temperature alert - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetTemperature.title", fallback: "Set temperature alert") - } - } - public enum AlertSettings { - public enum Dialog { - /// Max (%.0f) - public static func max(_ p1: Float) -> String { - return RuuviLocalization.tr("Localizable", "TagSettings.AlertSettings.Dialog.Max", p1, fallback: "Max (%.0f)") - } - /// Min (%.0f) - public static func min(_ p1: Float) -> String { - return RuuviLocalization.tr("Localizable", "TagSettings.AlertSettings.Dialog.Min", p1, fallback: "Min (%.0f)") - } - } - } - public enum Alerts { - /// Off - public static let off = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Off", fallback: "Off") - public enum Connection { - /// Alert when connected/disconnected - public static let description = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Connection.description", fallback: "Alert when connected/disconnected") - } - public enum DewPoint { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - return RuuviLocalization.tr("Localizable", "TagSettings.Alerts.DewPoint.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - public enum Humidity { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - return RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Humidity.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - public enum Movement { - /// Alert when sensor is moved - public static let description = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Movement.description", fallback: "Alert when sensor is moved") - } - public enum Pressure { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - return RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Pressure.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - public enum Temperature { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - return RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Temperature.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - } - public enum AlertsAreDisabled { - public enum Dialog { - public enum BothNotConnectedAndNoPNPermission { - /// Alerts are disabled because the device is not connected and missing push notification permission. Please connect to the device first. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.BothNotConnectedAndNoPNPermission.message", fallback: "Alerts are disabled because the device is not connected and missing push notification permission. Please connect to the device first.") - } - public enum Connect { - /// Connect - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.Connect.title", fallback: "Connect") - } - public enum NotConnected { - /// Alerts are disabled because you are not connected to the device. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.NotConnected.message", fallback: "Alerts are disabled because you are not connected to the device.") - } - } - } - public enum BatteryStatusLabel { - public enum Ok { - /// Battery OK - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.BatteryStatusLabel.Ok.message", fallback: "Battery OK") - } - public enum Replace { - /// Low battery - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.BatteryStatusLabel.Replace.message", fallback: "Low battery") - } - } - public enum ClaimTagButton { - /// Claim ownership - public static let claim = RuuviLocalization.tr("Localizable", "TagSettings.ClaimTagButton.Claim", fallback: "Claim ownership") - } - public enum ConnectStatus { - /// Disconnected - public static let disconnected = RuuviLocalization.tr("Localizable", "TagSettings.ConnectStatus.Disconnected", fallback: "Disconnected") - } - public enum ConnectionAlert { - /// Connection - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.ConnectionAlert.title", fallback: "Connection") - } - public enum DataSource { - public enum Advertisement { - /// Advertisement - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Advertisement.title", fallback: "Advertisement") - } - public enum Heartbeat { - /// Heartbeat - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Heartbeat.title", fallback: "Heartbeat") - } - public enum Network { - /// Cloud - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Network.title", fallback: "Cloud") - } - } - public enum EmptyValue { - /// - - public static let sign = RuuviLocalization.tr("Localizable", "TagSettings.EmptyValue.sign", fallback: "-") - } - public enum Firmware { - /// Current version - public static let currentVersion = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.CurrentVersion", fallback: "Current version") - /// Update - public static let updateFirmware = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.UpdateFirmware", fallback: "Update") - public enum CurrentVersion { - /// Very old - public static let veryOld = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.CurrentVersion.VeryOld", fallback: "Very old") - } - } - public enum General { - public enum Owner { - /// No owner - public static let `none` = RuuviLocalization.tr("Localizable", "TagSettings.General.Owner.none", fallback: "No owner") - } - } - public enum HumidityIsClipped { - public enum Alert { - /// Humidity value is greater than 100% after calibration. This value doesn't make sense, so the value has been adjusted to 100%. - public static func message(_ p1: Float) -> String { - return RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.message", p1, fallback: "Humidity value is greater than 100% after calibration. This value doesn't make sense, so the value has been adjusted to 100%.") - } - /// Humidity is adjusted - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.title", fallback: "Humidity is adjusted") - public enum Fix { - /// Fix - public static let button = RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.Fix.button", fallback: "Fix") - } - } - } - public enum Label { - public enum Alerts { - /// Alerts - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.alerts.text", fallback: "Alerts") - } - public enum Disabled { - /// DISABLED? - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.disabled.text", fallback: "DISABLED?") - } - public enum MoreInfo { - /// More info - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.moreInfo.text", fallback: "More info") - } - public enum NoValues { - /// NO VALUES? - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.noValues.text", fallback: "NO VALUES?") - } - } - public enum Mac { - public enum Alert { - /// MAC Address - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Mac.Alert.title", fallback: "MAC Address") - } - } - public enum MovementAlert { - /// Movement - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.MovementAlert.title", fallback: "Movement") - } - public enum NetworkInfo { - /// Owner - public static let owner = RuuviLocalization.tr("Localizable", "TagSettings.NetworkInfo.Owner", fallback: "Owner") - } - public enum NotShared { - /// Not shared - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.NotShared.title", fallback: "Not shared") + + public enum TagChartsPresenter { + /// Synchronised: %@ + public static func numberOfPointsSynchronizedOverNetwork(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "TagChartsPresenter.NumberOfPointsSynchronizedOverNetwork", String(describing: p1), fallback: "Synchronised: %@") + } } - public enum OffsetCorrection { - /// Humidity - public static let humidity = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Humidity", fallback: "Humidity") - /// Pressure - public static let pressure = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Pressure", fallback: "Pressure") - /// Temperature - public static let temperature = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Temperature", fallback: "Temperature") - } - public enum PairAndBackgroundScan { - /// Alerts are not available over Bluetooth connection if background scanning is not enabled. Only one iOS device can be paired to a Ruuvi sensor at a time. - public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.description", fallback: "Alerts are not available over Bluetooth connection if background scanning is not enabled. Only one iOS device can be paired to a Ruuvi sensor at a time.") - public enum Paired { - /// Paired and background scan is on - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Paired.title", fallback: "Paired and background scan is on") - } - public enum Pairing { - /// Connecting to the sensor - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Pairing.title", fallback: "Connecting to the sensor") - } - public enum Unpaired { - /// Pair and use background scan - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Unpaired.title", fallback: "Pair and use background scan") - } - } - public enum PairError { - public enum CloudMode { - /// The sensor cannot be connected to via Bluetooth when the cloud mode is active. You can re-enable the Bluetooth connection for the cloud sensors by disabling cloud mode in the app settings. - public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairError.CloudMode.description", fallback: "The sensor cannot be connected to via Bluetooth when the cloud mode is active. You can re-enable the Bluetooth connection for the cloud sensors by disabling cloud mode in the app settings.") - } - public enum Timeout { - /// Connection timed out. Pairing was unsuccessful. Please try again. - public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairError.Timeout.description", fallback: "Connection timed out. Pairing was unsuccessful. Please try again.") - } - } - public enum PressureAlert { - /// Air Pressure (%@) - public static func title(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "TagSettings.PressureAlert.title", String(describing: p1), fallback: "Air Pressure (%@)") - } - } - public enum RemoveThisSensor { - /// Remove this sensor - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.RemoveThisSensor.title", fallback: "Remove this sensor") - } - public enum SectionHeader { - public enum BTConnection { - /// BLUETOOTH CONNECTION - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.BTConnection.title", fallback: "BLUETOOTH CONNECTION") - } - public enum Calibration { - /// CALIBRATION - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Calibration.title", fallback: "CALIBRATION") - } - public enum Firmware { - /// Firmware - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Firmware.title", fallback: "Firmware") - } - public enum General { - /// General - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.General.title", fallback: "General") - } - public enum Name { - /// NAME - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Name.title", fallback: "NAME") - } - public enum NetworkInfo { - /// NETWORK INFO - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.NetworkInfo.title", fallback: "NETWORK INFO") - } - public enum OffsetCorrection { - /// OFFSET CORRECTION - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.OffsetCorrection.Title", fallback: "OFFSET CORRECTION") - } - public enum Remove { - /// REMOVE - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Remove.title", fallback: "REMOVE") - } + + public enum TagSettings { + /// Share + public static let shareButton = RuuviLocalization.tr("Localizable", "TagSettings.ShareButton", fallback: "Share") + public enum AirHumidityAlert { + /// Air Humidity (%@) + public static func title(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.AirHumidityAlert.title", String(describing: p1), fallback: "Air Humidity (%@)") + } + } + + public enum Alert { + public enum CustomDescription { + /// Set custom description... + public static let placeholder = RuuviLocalization.tr("Localizable", "TagSettings.Alert.CustomDescription.placeholder", fallback: "Set custom description...") + /// Alert custom description + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.CustomDescription.title", fallback: "Alert custom description") + } + + public enum SetHumidity { + /// Set humidity alert + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetHumidity.title", fallback: "Set humidity alert") + } + + public enum SetPressure { + /// Set pressure alert + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetPressure.title", fallback: "Set pressure alert") + } + + public enum SetRSSI { + /// Set signal strength alert + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetRSSI.title", fallback: "Set signal strength alert") + } + + public enum SetTemperature { + /// Set temperature alert + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetTemperature.title", fallback: "Set temperature alert") + } + } + + public enum AlertSettings { + public enum Dialog { + /// Max (%.0f) + public static func max(_ p1: Float) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.AlertSettings.Dialog.Max", p1, fallback: "Max (%.0f)") + } + + /// Min (%.0f) + public static func min(_ p1: Float) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.AlertSettings.Dialog.Min", p1, fallback: "Min (%.0f)") + } + } + } + + public enum Alerts { + /// Off + public static let off = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Off", fallback: "Off") + public enum Connection { + /// Alert when connected/disconnected + public static let description = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Connection.description", fallback: "Alert when connected/disconnected") + } + + public enum DewPoint { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.Alerts.DewPoint.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } + } + + public enum Humidity { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Humidity.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } + } + + public enum Movement { + /// Alert when sensor is moved + public static let description = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Movement.description", fallback: "Alert when sensor is moved") + } + + public enum Pressure { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Pressure.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } + } + + public enum Temperature { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Temperature.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } + } + } + + public enum AlertsAreDisabled { + public enum Dialog { + public enum BothNotConnectedAndNoPNPermission { + /// Alerts are disabled because the device is not connected and missing push notification permission. Please connect to the device first. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.BothNotConnectedAndNoPNPermission.message", fallback: "Alerts are disabled because the device is not connected and missing push notification permission. Please connect to the device first.") + } + + public enum Connect { + /// Connect + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.Connect.title", fallback: "Connect") + } + + public enum NotConnected { + /// Alerts are disabled because you are not connected to the device. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.NotConnected.message", fallback: "Alerts are disabled because you are not connected to the device.") + } + } + } + + public enum BatteryStatusLabel { + public enum Ok { + /// Battery OK + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.BatteryStatusLabel.Ok.message", fallback: "Battery OK") + } + + public enum Replace { + /// Low battery + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.BatteryStatusLabel.Replace.message", fallback: "Low battery") + } + } + + public enum ClaimTagButton { + /// Claim ownership + public static let claim = RuuviLocalization.tr("Localizable", "TagSettings.ClaimTagButton.Claim", fallback: "Claim ownership") + } + + public enum ConnectStatus { + /// Disconnected + public static let disconnected = RuuviLocalization.tr("Localizable", "TagSettings.ConnectStatus.Disconnected", fallback: "Disconnected") + } + + public enum ConnectionAlert { + /// Connection + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.ConnectionAlert.title", fallback: "Connection") + } + + public enum DataSource { + public enum Advertisement { + /// Advertisement + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Advertisement.title", fallback: "Advertisement") + } + + public enum Heartbeat { + /// Heartbeat + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Heartbeat.title", fallback: "Heartbeat") + } + + public enum Network { + /// Cloud + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Network.title", fallback: "Cloud") + } + } + + public enum EmptyValue { + /// - + public static let sign = RuuviLocalization.tr("Localizable", "TagSettings.EmptyValue.sign", fallback: "-") + } + + public enum Firmware { + /// Current version + public static let currentVersion = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.CurrentVersion", fallback: "Current version") + /// Update + public static let updateFirmware = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.UpdateFirmware", fallback: "Update") + public enum CurrentVersion { + /// Very old + public static let veryOld = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.CurrentVersion.VeryOld", fallback: "Very old") + } + } + + public enum General { + public enum Owner { + /// No owner + public static let none = RuuviLocalization.tr("Localizable", "TagSettings.General.Owner.none", fallback: "No owner") + } + } + + public enum HumidityIsClipped { + public enum Alert { + /// Humidity value is greater than 100% after calibration. This value doesn't make sense, so the value has been adjusted to 100%. + public static func message(_ p1: Float) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.message", p1, fallback: "Humidity value is greater than 100% after calibration. This value doesn't make sense, so the value has been adjusted to 100%.") + } + + /// Humidity is adjusted + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.title", fallback: "Humidity is adjusted") + public enum Fix { + /// Fix + public static let button = RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.Fix.button", fallback: "Fix") + } + } + } + + public enum Label { + public enum Alerts { + /// Alerts + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.alerts.text", fallback: "Alerts") + } + + public enum Disabled { + /// DISABLED? + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.disabled.text", fallback: "DISABLED?") + } + + public enum MoreInfo { + /// More info + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.moreInfo.text", fallback: "More info") + } + + public enum NoValues { + /// NO VALUES? + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.noValues.text", fallback: "NO VALUES?") + } + } + + public enum Mac { + public enum Alert { + /// MAC Address + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Mac.Alert.title", fallback: "MAC Address") + } + } + + public enum MovementAlert { + /// Movement + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.MovementAlert.title", fallback: "Movement") + } + + public enum NetworkInfo { + /// Owner + public static let owner = RuuviLocalization.tr("Localizable", "TagSettings.NetworkInfo.Owner", fallback: "Owner") + } + + public enum NotShared { + /// Not shared + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.NotShared.title", fallback: "Not shared") + } + + public enum OffsetCorrection { + /// Humidity + public static let humidity = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Humidity", fallback: "Humidity") + /// Pressure + public static let pressure = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Pressure", fallback: "Pressure") + /// Temperature + public static let temperature = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Temperature", fallback: "Temperature") + } + + public enum PairAndBackgroundScan { + /// Alerts are not available over Bluetooth connection if background scanning is not enabled. Only one iOS device can be paired to a Ruuvi sensor at a time. + public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.description", fallback: "Alerts are not available over Bluetooth connection if background scanning is not enabled. Only one iOS device can be paired to a Ruuvi sensor at a time.") + public enum Paired { + /// Paired and background scan is on + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Paired.title", fallback: "Paired and background scan is on") + } + + public enum Pairing { + /// Connecting to the sensor + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Pairing.title", fallback: "Connecting to the sensor") + } + + public enum Unpaired { + /// Pair and use background scan + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Unpaired.title", fallback: "Pair and use background scan") + } + } + + public enum PairError { + public enum CloudMode { + /// The sensor cannot be connected to via Bluetooth when the cloud mode is active. You can re-enable the Bluetooth connection for the cloud sensors by disabling cloud mode in the app settings. + public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairError.CloudMode.description", fallback: "The sensor cannot be connected to via Bluetooth when the cloud mode is active. You can re-enable the Bluetooth connection for the cloud sensors by disabling cloud mode in the app settings.") + } + + public enum Timeout { + /// Connection timed out. Pairing was unsuccessful. Please try again. + public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairError.Timeout.description", fallback: "Connection timed out. Pairing was unsuccessful. Please try again.") + } + } + + public enum PressureAlert { + /// Air Pressure (%@) + public static func title(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.PressureAlert.title", String(describing: p1), fallback: "Air Pressure (%@)") + } + } + + public enum RemoveThisSensor { + /// Remove this sensor + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.RemoveThisSensor.title", fallback: "Remove this sensor") + } + + public enum SectionHeader { + public enum BTConnection { + /// BLUETOOTH CONNECTION + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.BTConnection.title", fallback: "BLUETOOTH CONNECTION") + } + + public enum Calibration { + /// CALIBRATION + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Calibration.title", fallback: "CALIBRATION") + } + + public enum Firmware { + /// Firmware + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Firmware.title", fallback: "Firmware") + } + + public enum General { + /// General + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.General.title", fallback: "General") + } + + public enum Name { + /// NAME + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Name.title", fallback: "NAME") + } + + public enum NetworkInfo { + /// NETWORK INFO + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.NetworkInfo.title", fallback: "NETWORK INFO") + } + + public enum OffsetCorrection { + /// OFFSET CORRECTION + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.OffsetCorrection.Title", fallback: "OFFSET CORRECTION") + } + + public enum Remove { + /// REMOVE + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Remove.title", fallback: "REMOVE") + } + } + + public enum Share { + /// Share + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Share.title", fallback: "Share") + } + + public enum Shared { + /// Shared + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Shared.title", fallback: "Shared") + } + + public enum Uuid { + public enum Alert { + /// UUID + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UUID.Alert.title", fallback: "UUID") + } + } + + public enum UpdateFirmware { + public enum Alert { + /// In order to see missing values: + /// If you are using the latest firmware, set RAWv2 mode by pressing "B" on a sensor. + /// Or update your sensor with the latest firmware. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.message", fallback: "In order to see missing values:\nIf you are using the latest firmware, set RAWv2 mode by pressing \"B\" on a sensor.\nOr update your sensor with the latest firmware.") + /// RAWv2 mode is required + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.title", fallback: "RAWv2 mode is required") + public enum Buttons { + public enum LearnMore { + /// Learn more + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.Buttons.LearnMore.title", fallback: "Learn more") + } + } + } + } + + public enum AccelerationXTitleLabel { + /// Acceleration X + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationXTitleLabel.text", fallback: "Acceleration X") + } + + public enum AccelerationYTitleLabel { + /// Acceleration Y + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationYTitleLabel.text", fallback: "Acceleration Y") + } + + public enum AccelerationZTitleLabel { + /// Acceleration Z + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationZTitleLabel.text", fallback: "Acceleration Z") + } + + public enum BackgroundImageLabel { + /// Background image + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.backgroundImageLabel.text", fallback: "Background image") + } + + public enum BatteryVoltageTitleLabel { + /// Battery Voltage + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.batteryVoltageTitleLabel.text", fallback: "Battery Voltage") + } + + public enum ConfirmSharedTagRemovalDialog { + /// If you remove the sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmSharedTagRemovalDialog.message", fallback: "If you remove the sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore.") + } + + public enum ConfirmTagRemovalDialog { + /// Do you want to remove the sensor? You can add it again later, if needed. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagRemovalDialog.message", fallback: "Do you want to remove the sensor? You can add it again later, if needed.") + /// Remove sensor + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagRemovalDialog.title", fallback: "Remove sensor") + } + + public enum ConfirmTagUnclaimAndRemoveDialog { + /// By removing the sensor, your sensor ownership status will be revoked. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagUnclaimAndRemoveDialog.message", fallback: "By removing the sensor, your sensor ownership status will be revoked. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner.") + } + + public enum DataFormatTitleLabel { + /// Data Format + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dataFormatTitleLabel.text", fallback: "Data Format") + } + + public enum DataSourceTitleLabel { + /// Data Received Via + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dataSourceTitleLabel.text", fallback: "Data Received Via") + } + + public enum DewPointAlertTitleLabel { + /// Dew Point + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dewPointAlertTitleLabel.text", fallback: "Dew Point") + } + + public enum HumidityTitleLabel { + /// Humidity + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.humidityTitleLabel.text", fallback: "Humidity") + } + + public enum MacAddressTitleLabel { + /// MAC Address + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.macAddressTitleLabel.text", fallback: "MAC Address") + } + + public enum McTitleLabel { + /// Movement Counter + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.mcTitleLabel.text", fallback: "Movement Counter") + } + + public enum MsnTitleLabel { + /// Measurement Sequence Number + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.msnTitleLabel.text", fallback: "Measurement Sequence Number") + } + + public enum NavigationItem { + /// Sensor Settings + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.navigationItem.title", fallback: "Sensor Settings") + } + + public enum RssiTitleLabel { + /// Signal Strength (RSSI) + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.rssiTitleLabel.text", fallback: "Signal Strength (RSSI)") + } + + public enum TagNameTitleLabel { + /// Name + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.tagNameTitleLabel.text", fallback: "Name") + public enum Rename { + /// Your sensors are displayed in alphabetical order. + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.tagNameTitleLabel.rename.text", fallback: "Your sensors are displayed in alphabetical order.") + } + } + + public enum TemperatureAlertTitleLabel { + /// Temperature (%@) + public static func text(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.temperatureAlertTitleLabel.text", String(describing: p1), fallback: "Temperature (%@)") + } + } + + public enum TxPowerTitleLabel { + /// Tx Power + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.txPowerTitleLabel.text", fallback: "Tx Power") + } + + public enum UuidTitleLabel { + /// UUID + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.uuidTitleLabel.text", fallback: "UUID") + } } - public enum Share { - /// Share - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Share.title", fallback: "Share") + + public enum TagsManagerPresenter { + public enum SignOutConfirmAlert { + /// When you sign out, sensors the ownerships of which you've claimed on the sensor Settings page will be automatically removed from the app. When you sign in again using the same email address, the sensors will be returned from the cloud. + /// + /// Do you want to sign out? + public static let message = RuuviLocalization.tr("Localizable", "TagsManagerPresenter.SignOutConfirmAlert.Message", fallback: "When you sign out, sensors the ownerships of which you've claimed on the sensor Settings page will be automatically removed from the app. When you sign in again using the same email address, the sensors will be returned from the cloud.\n\nDo you want to sign out?") + } + } + + public enum TemperatureUnit { + public enum Celsius { + /// Celsius (℃) + public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Celsius.title", fallback: "Celsius (℃)") + } + + public enum Fahrenheit { + /// Fahrenheit (℉) + public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Fahrenheit.title", fallback: "Fahrenheit (℉)") + } + + public enum Kelvin { + /// Kelvin (K) + public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Kelvin.title", fallback: "Kelvin (K)") + } } - public enum Shared { - /// Shared - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Shared.title", fallback: "Shared") + + public enum UnexpectedError { + /// Attempt to read data from Realm without LUID + public static let attemptToReadDataFromRealmWithoutLUID = RuuviLocalization.tr("Localizable", "UnexpectedError.attemptToReadDataFromRealmWithoutLUID", fallback: "Attempt to read data from Realm without LUID") + /// Both local and MAC identifiers are nil + public static let bothLuidAndMacAreNil = RuuviLocalization.tr("Localizable", "UnexpectedError.bothLuidAndMacAreNil", fallback: "Both local and MAC identifiers are nil") + /// Both callback result and error are nil + public static let callbackErrorAndResultAreNil = RuuviLocalization.tr("Localizable", "UnexpectedError.callbackErrorAndResultAreNil", fallback: "Both callback result and error are nil") + /// Caller was deallocated during operation + public static let callerDeinitedDuringOperation = RuuviLocalization.tr("Localizable", "UnexpectedError.callerDeinitedDuringOperation", fallback: "Caller was deallocated during operation") + /// Failed to find logs for the sensor + public static let failedToFindLogsForTheTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindLogsForTheTag", fallback: "Failed to find logs for the sensor") + /// Failed to find or generate background image + public static let failedToFindOrGenerateBackgroundImage = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindOrGenerateBackgroundImage", fallback: "Failed to find or generate background image") + /// Failed to find sensor + public static let failedToFindRuuviTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindRuuviTag", fallback: "Failed to find sensor") + /// Failed to find virtual sensor + public static let failedToFindVirtualTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindVirtualTag", fallback: "Failed to find virtual sensor") + /// Failed to reverse geocode location + public static let failedToReverseGeocodeCoordinate = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToReverseGeocodeCoordinate", fallback: "Failed to reverse geocode location") + /// View Model UUID is nil + public static let viewModelUUIDIsNil = RuuviLocalization.tr("Localizable", "UnexpectedError.viewModelUUIDIsNil", fallback: "View Model UUID is nil") } - public enum Uuid { - public enum Alert { - /// UUID - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UUID.Alert.title", fallback: "UUID") - } + + public enum UnitPressure { + public enum Hectopascal { + /// Hectopascal (hPa) + public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.hectopascal.title", fallback: "Hectopascal (hPa)") + } + + public enum InchOfMercury { + /// Inch of mercury (inHg) + public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.inchOfMercury.title", fallback: "Inch of mercury (inHg)") + } + + public enum MillimetreOfMercury { + /// Millimetre of mercury (mmHg) + public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.millimetreOfMercury.title", fallback: "Millimetre of mercury (mmHg)") + } } + public enum UpdateFirmware { - public enum Alert { - /// In order to see missing values: - /// If you are using the latest firmware, set RAWv2 mode by pressing "B" on a sensor. - /// Or update your sensor with the latest firmware. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.message", fallback: "In order to see missing values:\nIf you are using the latest firmware, set RAWv2 mode by pressing \"B\" on a sensor.\nOr update your sensor with the latest firmware.") - /// RAWv2 mode is required - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.title", fallback: "RAWv2 mode is required") - public enum Buttons { - public enum LearnMore { - /// Learn more - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.Buttons.LearnMore.title", fallback: "Learn more") - } - } - } - } - public enum AccelerationXTitleLabel { - /// Acceleration X - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationXTitleLabel.text", fallback: "Acceleration X") - } - public enum AccelerationYTitleLabel { - /// Acceleration Y - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationYTitleLabel.text", fallback: "Acceleration Y") - } - public enum AccelerationZTitleLabel { - /// Acceleration Z - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationZTitleLabel.text", fallback: "Acceleration Z") - } - public enum BackgroundImageLabel { - /// Background image - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.backgroundImageLabel.text", fallback: "Background image") - } - public enum BatteryVoltageTitleLabel { - /// Battery Voltage - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.batteryVoltageTitleLabel.text", fallback: "Battery Voltage") - } - public enum ConfirmSharedTagRemovalDialog { - /// If you remove the sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmSharedTagRemovalDialog.message", fallback: "If you remove the sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore.") - } - public enum ConfirmTagRemovalDialog { - /// Do you want to remove the sensor? You can add it again later, if needed. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagRemovalDialog.message", fallback: "Do you want to remove the sensor? You can add it again later, if needed.") - /// Remove sensor - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagRemovalDialog.title", fallback: "Remove sensor") - } - public enum ConfirmTagUnclaimAndRemoveDialog { - /// By removing the sensor, your sensor ownership status will be revoked. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagUnclaimAndRemoveDialog.message", fallback: "By removing the sensor, your sensor ownership status will be revoked. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner.") - } - public enum DataFormatTitleLabel { - /// Data Format - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dataFormatTitleLabel.text", fallback: "Data Format") - } - public enum DataSourceTitleLabel { - /// Data Received Via - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dataSourceTitleLabel.text", fallback: "Data Received Via") - } - public enum DewPointAlertTitleLabel { - /// Dew Point - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dewPointAlertTitleLabel.text", fallback: "Dew Point") - } - public enum HumidityTitleLabel { - /// Humidity - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.humidityTitleLabel.text", fallback: "Humidity") - } - public enum MacAddressTitleLabel { - /// MAC Address - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.macAddressTitleLabel.text", fallback: "MAC Address") - } - public enum McTitleLabel { - /// Movement Counter - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.mcTitleLabel.text", fallback: "Movement Counter") - } - public enum MsnTitleLabel { - /// Measurement Sequence Number - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.msnTitleLabel.text", fallback: "Measurement Sequence Number") - } - public enum NavigationItem { - /// Sensor Settings - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.navigationItem.title", fallback: "Sensor Settings") - } - public enum RssiTitleLabel { - /// Signal Strength (RSSI) - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.rssiTitleLabel.text", fallback: "Signal Strength (RSSI)") - } - public enum TagNameTitleLabel { - /// Name - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.tagNameTitleLabel.text", fallback: "Name") - public enum Rename { - /// Your sensors are displayed in alphabetical order. - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.tagNameTitleLabel.rename.text", fallback: "Your sensors are displayed in alphabetical order.") - } - } - public enum TemperatureAlertTitleLabel { - /// Temperature (%@) - public static func text(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "TagSettings.temperatureAlertTitleLabel.text", String(describing: p1), fallback: "Temperature (%@)") - } - } - public enum TxPowerTitleLabel { - /// Tx Power - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.txPowerTitleLabel.text", fallback: "Tx Power") - } - public enum UuidTitleLabel { - /// UUID - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.uuidTitleLabel.text", fallback: "UUID") - } - } - public enum TagsManagerPresenter { - public enum SignOutConfirmAlert { - /// When you sign out, sensors the ownerships of which you've claimed on the sensor Settings page will be automatically removed from the app. When you sign in again using the same email address, the sensors will be returned from the cloud. - /// - /// Do you want to sign out? - public static let message = RuuviLocalization.tr("Localizable", "TagsManagerPresenter.SignOutConfirmAlert.Message", fallback: "When you sign out, sensors the ownerships of which you've claimed on the sensor Settings page will be automatically removed from the app. When you sign in again using the same email address, the sensors will be returned from the cloud.\n\nDo you want to sign out?") - } - } - public enum TemperatureUnit { - public enum Celsius { - /// Celsius (℃) - public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Celsius.title", fallback: "Celsius (℃)") - } - public enum Fahrenheit { - /// Fahrenheit (℉) - public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Fahrenheit.title", fallback: "Fahrenheit (℉)") - } - public enum Kelvin { - /// Kelvin (K) - public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Kelvin.title", fallback: "Kelvin (K)") - } - } - public enum UnexpectedError { - /// Attempt to read data from Realm without LUID - public static let attemptToReadDataFromRealmWithoutLUID = RuuviLocalization.tr("Localizable", "UnexpectedError.attemptToReadDataFromRealmWithoutLUID", fallback: "Attempt to read data from Realm without LUID") - /// Both local and MAC identifiers are nil - public static let bothLuidAndMacAreNil = RuuviLocalization.tr("Localizable", "UnexpectedError.bothLuidAndMacAreNil", fallback: "Both local and MAC identifiers are nil") - /// Both callback result and error are nil - public static let callbackErrorAndResultAreNil = RuuviLocalization.tr("Localizable", "UnexpectedError.callbackErrorAndResultAreNil", fallback: "Both callback result and error are nil") - /// Caller was deallocated during operation - public static let callerDeinitedDuringOperation = RuuviLocalization.tr("Localizable", "UnexpectedError.callerDeinitedDuringOperation", fallback: "Caller was deallocated during operation") - /// Failed to find logs for the sensor - public static let failedToFindLogsForTheTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindLogsForTheTag", fallback: "Failed to find logs for the sensor") - /// Failed to find or generate background image - public static let failedToFindOrGenerateBackgroundImage = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindOrGenerateBackgroundImage", fallback: "Failed to find or generate background image") - /// Failed to find sensor - public static let failedToFindRuuviTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindRuuviTag", fallback: "Failed to find sensor") - /// Failed to find virtual sensor - public static let failedToFindVirtualTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindVirtualTag", fallback: "Failed to find virtual sensor") - /// Failed to reverse geocode location - public static let failedToReverseGeocodeCoordinate = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToReverseGeocodeCoordinate", fallback: "Failed to reverse geocode location") - /// View Model UUID is nil - public static let viewModelUUIDIsNil = RuuviLocalization.tr("Localizable", "UnexpectedError.viewModelUUIDIsNil", fallback: "View Model UUID is nil") - } - public enum UnitPressure { - public enum Hectopascal { - /// Hectopascal (hPa) - public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.hectopascal.title", fallback: "Hectopascal (hPa)") - } - public enum InchOfMercury { - /// Inch of mercury (inHg) - public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.inchOfMercury.title", fallback: "Inch of mercury (inHg)") - } - public enum MillimetreOfMercury { - /// Millimetre of mercury (mmHg) - public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.millimetreOfMercury.title", fallback: "Millimetre of mercury (mmHg)") - } - } - public enum UpdateFirmware { - public enum Download { - /// To start with the update process, first download the latest software package on the device you're going to use for updates. Latest version is available on ruuvi.com/software-update - public static let content = RuuviLocalization.tr("Localizable", "UpdateFirmware.Download.content", fallback: "To start with the update process, first download the latest software package on the device you're going to use for updates. Latest version is available on ruuvi.com/software-update") - /// DOWNLOAD LATEST FIRMWARE - public static let header = RuuviLocalization.tr("Localizable", "UpdateFirmware.Download.header", fallback: "DOWNLOAD LATEST FIRMWARE") - } - public enum NextButton { - /// NEXT - public static let title = RuuviLocalization.tr("Localizable", "UpdateFirmware.NextButton.title", fallback: "NEXT") - } - public enum SetDfu { - /// Open the RuuviTag's enclosure by pulling it open with your fingers or gently with a flat head screw driver. - /// - /// Set RuuviTag to bootloader mode by holding down button B and pressing reset button R. Red indicator LED light will light up and stay on. If your device has only 1 button, keep it pressed 10 seconds to enter the bootloader. - public static let content = RuuviLocalization.tr("Localizable", "UpdateFirmware.SetDfu.content", fallback: "Open the RuuviTag's enclosure by pulling it open with your fingers or gently with a flat head screw driver.\n\nSet RuuviTag to bootloader mode by holding down button B and pressing reset button R. Red indicator LED light will light up and stay on. If your device has only 1 button, keep it pressed 10 seconds to enter the bootloader.") - /// SET RUUVI TAG TO DFU MODE - public static let header = RuuviLocalization.tr("Localizable", "UpdateFirmware.SetDfu.header", fallback: "SET RUUVI TAG TO DFU MODE") - } - public enum Title { - /// Update Firmware - public static let text = RuuviLocalization.tr("Localizable", "UpdateFirmware.Title.text", fallback: "Update Firmware") - } - } - public enum UserApiError { - /// Maximum claim count for the user reached - public static let erClaimCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_CLAIM_COUNT_REACHED", fallback: "Maximum claim count for the user reached") - /// Data already exists, cannot update - public static let erConflict = RuuviLocalization.tr("Localizable", "UserApiError.ER_CONFLICT", fallback: "Data already exists, cannot update") - /// Forbidden - public static let erForbidden = RuuviLocalization.tr("Localizable", "UserApiError.ER_FORBIDDEN", fallback: "Forbidden") - /// Gateway already whitelisted - public static let erGatewayAlreadyWhitelisted = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_ALREADY_WHITELISTED", fallback: "Gateway already whitelisted") - /// Gateway not found - public static let erGatewayNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_NOT_FOUND", fallback: "Gateway not found") - /// Gateway status report failed - public static let erGatewayStatusReportFailed = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED", fallback: "Gateway status report failed") - /// Internal error - public static let erInternal = RuuviLocalization.tr("Localizable", "UserApiError.ER_INTERNAL", fallback: "Internal error") - /// Invalid density mode - public static let erInvalidDensityMode = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_DENSITY_MODE", fallback: "Invalid density mode") - /// Invalid email address - public static let erInvalidEmailAddress = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_EMAIL_ADDRESS", fallback: "Invalid email address") - /// Invalid ENUM value given - public static let erInvalidEnumValue = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_ENUM_VALUE", fallback: "Invalid ENUM value given") - /// Invalid request format - public static let erInvalidFormat = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_FORMAT", fallback: "Invalid request format") - /// Invalid MAC-address - public static let erInvalidMacAddress = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_MAC_ADDRESS", fallback: "Invalid MAC-address") - /// Invalid sort mode - public static let erInvalidSortMode = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_SORT_MODE", fallback: "Invalid sort mode") - /// Invalid time range - public static let erInvalidTimeRange = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_TIME_RANGE", fallback: "Invalid time range") - /// Missing argument - public static let erMissingArgument = RuuviLocalization.tr("Localizable", "UserApiError.ER_MISSING_ARGUMENT", fallback: "Missing argument") - /// In order to share a sensor, it must have data - public static let erNoDataToShare = RuuviLocalization.tr("Localizable", "UserApiError.ER_NO_DATA_TO_SHARE", fallback: "In order to share a sensor, it must have data") - /// Newer data already exists, cannot update - public static let erOldEntry = RuuviLocalization.tr("Localizable", "UserApiError.ER_OLD_ENTRY", fallback: "Newer data already exists, cannot update") - /// Sensor already claimed by %@ - public static func erSensorAlreadyClaimed(_ p1: Any) -> String { - return RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_CLAIMED", String(describing: p1), fallback: "Sensor already claimed by %@") - } - /// Sensor already claimed - public static let erSensorAlreadyClaimedNoEmail = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_CLAIMED_NO_EMAIL", fallback: "Sensor already claimed") - /// The sensor has already been registered - public static let erSensorAlreadyRegistered = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_REGISTERED", fallback: "The sensor has already been registered") - /// This sensor is already shared - public static let erSensorAlreadyShared = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_SHARED", fallback: "This sensor is already shared") - /// Sensor not found - public static let erSensorNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_NOT_FOUND", fallback: "Sensor not found") - /// Maximum share count for the sensor reached - public static let erSensorShareCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_SHARE_COUNT_REACHED", fallback: "Maximum share count for the sensor reached") - /// The share limit is reached - public static let erShareCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_SHARE_COUNT_REACHED", fallback: "The share limit is reached") - /// Data storage error - public static let erSubDataStorageError = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUB_DATA_STORAGE_ERROR", fallback: "Data storage error") - /// No user - public static let erSubNoUser = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUB_NO_USER", fallback: "No user") - /// Tried to add duplicate subscription to a code - public static let erSubscriptionCodeExists = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_CODE_EXISTS", fallback: "Tried to add duplicate subscription to a code") - /// Tried to claim already used code - public static let erSubscriptionCodeUsed = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_CODE_USED", fallback: "Tried to claim already used code") - /// Subscription is not found - public static let erSubscriptionNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_NOT_FOUND", fallback: "Subscription is not found") - /// Too many requests - public static let erThrottled = RuuviLocalization.tr("Localizable", "UserApiError.ER_THROTTLED", fallback: "Too many requests") - /// Token is expired - public static let erTokenExpired = RuuviLocalization.tr("Localizable", "UserApiError.ER_TOKEN_EXPIRED", fallback: "Token is expired") - /// Unable to send email - public static let erUnableToSendEmail = RuuviLocalization.tr("Localizable", "UserApiError.ER_UNABLE_TO_SEND_EMAIL", fallback: "Unable to send email") - /// Unauthorised - public static let erUnauthorized = RuuviLocalization.tr("Localizable", "UserApiError.ER_UNAUTHORIZED", fallback: "Unauthorised") - /// User not found - public static let erUserNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_USER_NOT_FOUND", fallback: "User not found") - /// Operation was successful - public static let ok = RuuviLocalization.tr("Localizable", "UserApiError.OK", fallback: "Operation was successful") - } - public enum WebTagLocationSource { - /// Your location - public static let current = RuuviLocalization.tr("Localizable", "WebTagLocationSource.current", fallback: "Your location") - /// Pick from the map - public static let manual = RuuviLocalization.tr("Localizable", "WebTagLocationSource.manual", fallback: "Pick from the map") - } - public enum WebTagSettings { - public enum AirHumidityAlert { - /// Air Humidity - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.AirHumidityAlert.title", fallback: "Air Humidity") - } - public enum Alerts { - /// Off - public static let off = RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Off", fallback: "Off") - public enum DewPoint { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - return RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.DewPoint.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - public enum Humidity { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - return RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Humidity.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - public enum Pressure { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - return RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Pressure.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - public enum Temperature { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - return RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Temperature.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - } - public enum AlertsAreDisabled { - public enum Dialog { - public enum BothNoPNPermissionAndNoLocationPermission { - /// In order to enable virtual sensor alerts please always grant location and notification permissions in Settings. - public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.AlertsAreDisabled.Dialog.BothNoPNPermissionAndNoLocationPermission.message", fallback: "In order to enable virtual sensor alerts please always grant location and notification permissions in Settings.") + public enum Download { + /// To start with the update process, first download the latest software package on the device you're going to use for updates. Latest version is available on ruuvi.com/software-update + public static let content = RuuviLocalization.tr("Localizable", "UpdateFirmware.Download.content", fallback: "To start with the update process, first download the latest software package on the device you're going to use for updates. Latest version is available on ruuvi.com/software-update") + /// DOWNLOAD LATEST FIRMWARE + public static let header = RuuviLocalization.tr("Localizable", "UpdateFirmware.Download.header", fallback: "DOWNLOAD LATEST FIRMWARE") } - public enum Settings { - /// Settings - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.AlertsAreDisabled.Dialog.Settings.title", fallback: "Settings") - } - } - } - public enum Button { - public enum Remove { - /// REMOVE THIS VIRTUAL SENSOR - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.Button.Remove.title", fallback: "REMOVE THIS VIRTUAL SENSOR") - } - } - public enum Label { - public enum BackgroundImage { - /// BACKGROUND - /// IMAGE - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.BackgroundImage.text", fallback: "BACKGROUND\nIMAGE") - } - public enum Location { - /// Location - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.Location.text", fallback: "Location") - } - public enum TagName { - /// Sensor Name - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.TagName.text", fallback: "Sensor Name") - } - public enum Alerts { - /// ALERTS - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.alerts.text", fallback: "ALERTS") - } - public enum Disabled { - /// DISABLED? - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.disabled.text", fallback: "DISABLED?") - } - } - public enum Location { - /// Your location - public static let current = RuuviLocalization.tr("Localizable", "WebTagSettings.Location.Current", fallback: "Your location") - } - public enum PressureAlert { - /// Air Pressure - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.PressureAlert.title", fallback: "Air Pressure") - } - public enum SectionHeader { - public enum MoreInfo { - /// MORE INFO - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.SectionHeader.MoreInfo.title", fallback: "MORE INFO") - } - public enum Name { - /// NAME - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.SectionHeader.Name.title", fallback: "NAME") - } - } - public enum ConfirmClearLocationDialog { - /// Are you sure you want to clear location for this virtual sensor? Current location will be used instead. - public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmClearLocationDialog.message", fallback: "Are you sure you want to clear location for this virtual sensor? Current location will be used instead.") - /// Clear Location - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmClearLocationDialog.title", fallback: "Clear Location") - } - public enum ConfirmTagRemovalDialog { - /// Are you sure you want to remove this virtual sensor? - public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmTagRemovalDialog.message", fallback: "Are you sure you want to remove this virtual sensor?") - /// Remove virtual sensor - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmTagRemovalDialog.title", fallback: "Remove virtual sensor") - } - public enum DewPointAlertTitleLabel { - /// Dew Point - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.dewPointAlertTitleLabel.text", fallback: "Dew Point") - } - public enum NavigationItem { - /// Virtual Sensor Settings - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.navigationItem.title", fallback: "Virtual Sensor Settings") - } - public enum TemperatureAlertTitleLabel { - /// Temperature - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.temperatureAlertTitleLabel.text", fallback: "Temperature") - } - } - public enum Welcome { - public enum Description { - /// To find nearby sensors and receive live sensor data, press 'scan'. - public static let text = RuuviLocalization.tr("Localizable", "Welcome.description.text", fallback: "To find nearby sensors and receive live sensor data, press 'scan'.") - } - public enum Scan { - /// SCAN - public static let title = RuuviLocalization.tr("Localizable", "Welcome.scan.title", fallback: "SCAN") - } - } - public enum Widgets { - public enum Description { - /// Create widgets of your favourite Ruuvi sensors. Widgets update from the Ruuvi Cloud. A Ruuvi Gateway router is required. - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Description.message", fallback: "Create widgets of your favourite Ruuvi sensors. Widgets update from the Ruuvi Cloud. A Ruuvi Gateway router is required.") - } - public enum Loading { - /// loading... - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Loading.message", fallback: "loading...") - } - public enum Select { - public enum Sensor { - /// Selected Ruuvi sensor - public static let title = RuuviLocalization.tr("Localizable", "Widgets.Select.Sensor.title", fallback: "Selected Ruuvi sensor") - } - } - public enum Sensor { - public enum `Type` { - /// Selected sensor type - public static let title = RuuviLocalization.tr("Localizable", "Widgets.Sensor.Type.title", fallback: "Selected sensor type") - } - } - public enum Unauthorized { - public enum Inline { - /// Sign in to Ruuvi Station - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unauthorized.Inline.message", fallback: "Sign in to Ruuvi Station") - } - public enum Regular { - /// Sign in to use the widget. - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unauthorized.Regular.message", fallback: "Sign in to use the widget.") - } - } - public enum Unconfigured { - public enum Circular { - /// +Add - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Circular.message", fallback: "+Add") - } - public enum Inline { - /// Add sensor to use Ruuvi Widget - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Inline.message", fallback: "Add sensor to use Ruuvi Widget") - } - public enum Rectangular { - /// Add sensor to use Ruuvi Widget - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Rectangular.message", fallback: "Add sensor to use Ruuvi Widget") - } - public enum Simple { - /// Force tap to edit the widget. - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Simple.message", fallback: "Force tap to edit the widget.") - } - } - } + + public enum NextButton { + /// NEXT + public static let title = RuuviLocalization.tr("Localizable", "UpdateFirmware.NextButton.title", fallback: "NEXT") + } + + public enum SetDfu { + /// Open the RuuviTag's enclosure by pulling it open with your fingers or gently with a flat head screw driver. + /// + /// Set RuuviTag to bootloader mode by holding down button B and pressing reset button R. Red indicator LED light will light up and stay on. If your device has only 1 button, keep it pressed 10 seconds to enter the bootloader. + public static let content = RuuviLocalization.tr("Localizable", "UpdateFirmware.SetDfu.content", fallback: "Open the RuuviTag's enclosure by pulling it open with your fingers or gently with a flat head screw driver.\n\nSet RuuviTag to bootloader mode by holding down button B and pressing reset button R. Red indicator LED light will light up and stay on. If your device has only 1 button, keep it pressed 10 seconds to enter the bootloader.") + /// SET RUUVI TAG TO DFU MODE + public static let header = RuuviLocalization.tr("Localizable", "UpdateFirmware.SetDfu.header", fallback: "SET RUUVI TAG TO DFU MODE") + } + + public enum Title { + /// Update Firmware + public static let text = RuuviLocalization.tr("Localizable", "UpdateFirmware.Title.text", fallback: "Update Firmware") + } + } + + public enum UserApiError { + /// Maximum claim count for the user reached + public static let erClaimCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_CLAIM_COUNT_REACHED", fallback: "Maximum claim count for the user reached") + /// Data already exists, cannot update + public static let erConflict = RuuviLocalization.tr("Localizable", "UserApiError.ER_CONFLICT", fallback: "Data already exists, cannot update") + /// Forbidden + public static let erForbidden = RuuviLocalization.tr("Localizable", "UserApiError.ER_FORBIDDEN", fallback: "Forbidden") + /// Gateway already whitelisted + public static let erGatewayAlreadyWhitelisted = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_ALREADY_WHITELISTED", fallback: "Gateway already whitelisted") + /// Gateway not found + public static let erGatewayNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_NOT_FOUND", fallback: "Gateway not found") + /// Gateway status report failed + public static let erGatewayStatusReportFailed = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED", fallback: "Gateway status report failed") + /// Internal error + public static let erInternal = RuuviLocalization.tr("Localizable", "UserApiError.ER_INTERNAL", fallback: "Internal error") + /// Invalid density mode + public static let erInvalidDensityMode = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_DENSITY_MODE", fallback: "Invalid density mode") + /// Invalid email address + public static let erInvalidEmailAddress = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_EMAIL_ADDRESS", fallback: "Invalid email address") + /// Invalid ENUM value given + public static let erInvalidEnumValue = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_ENUM_VALUE", fallback: "Invalid ENUM value given") + /// Invalid request format + public static let erInvalidFormat = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_FORMAT", fallback: "Invalid request format") + /// Invalid MAC-address + public static let erInvalidMacAddress = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_MAC_ADDRESS", fallback: "Invalid MAC-address") + /// Invalid sort mode + public static let erInvalidSortMode = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_SORT_MODE", fallback: "Invalid sort mode") + /// Invalid time range + public static let erInvalidTimeRange = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_TIME_RANGE", fallback: "Invalid time range") + /// Missing argument + public static let erMissingArgument = RuuviLocalization.tr("Localizable", "UserApiError.ER_MISSING_ARGUMENT", fallback: "Missing argument") + /// In order to share a sensor, it must have data + public static let erNoDataToShare = RuuviLocalization.tr("Localizable", "UserApiError.ER_NO_DATA_TO_SHARE", fallback: "In order to share a sensor, it must have data") + /// Newer data already exists, cannot update + public static let erOldEntry = RuuviLocalization.tr("Localizable", "UserApiError.ER_OLD_ENTRY", fallback: "Newer data already exists, cannot update") + /// Sensor already claimed by %@ + public static func erSensorAlreadyClaimed(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_CLAIMED", String(describing: p1), fallback: "Sensor already claimed by %@") + } + + /// Sensor already claimed + public static let erSensorAlreadyClaimedNoEmail = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_CLAIMED_NO_EMAIL", fallback: "Sensor already claimed") + /// The sensor has already been registered + public static let erSensorAlreadyRegistered = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_REGISTERED", fallback: "The sensor has already been registered") + /// This sensor is already shared + public static let erSensorAlreadyShared = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_SHARED", fallback: "This sensor is already shared") + /// Sensor not found + public static let erSensorNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_NOT_FOUND", fallback: "Sensor not found") + /// Maximum share count for the sensor reached + public static let erSensorShareCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_SHARE_COUNT_REACHED", fallback: "Maximum share count for the sensor reached") + /// The share limit is reached + public static let erShareCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_SHARE_COUNT_REACHED", fallback: "The share limit is reached") + /// Data storage error + public static let erSubDataStorageError = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUB_DATA_STORAGE_ERROR", fallback: "Data storage error") + /// No user + public static let erSubNoUser = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUB_NO_USER", fallback: "No user") + /// Tried to add duplicate subscription to a code + public static let erSubscriptionCodeExists = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_CODE_EXISTS", fallback: "Tried to add duplicate subscription to a code") + /// Tried to claim already used code + public static let erSubscriptionCodeUsed = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_CODE_USED", fallback: "Tried to claim already used code") + /// Subscription is not found + public static let erSubscriptionNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_NOT_FOUND", fallback: "Subscription is not found") + /// Too many requests + public static let erThrottled = RuuviLocalization.tr("Localizable", "UserApiError.ER_THROTTLED", fallback: "Too many requests") + /// Token is expired + public static let erTokenExpired = RuuviLocalization.tr("Localizable", "UserApiError.ER_TOKEN_EXPIRED", fallback: "Token is expired") + /// Unable to send email + public static let erUnableToSendEmail = RuuviLocalization.tr("Localizable", "UserApiError.ER_UNABLE_TO_SEND_EMAIL", fallback: "Unable to send email") + /// Unauthorised + public static let erUnauthorized = RuuviLocalization.tr("Localizable", "UserApiError.ER_UNAUTHORIZED", fallback: "Unauthorised") + /// User not found + public static let erUserNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_USER_NOT_FOUND", fallback: "User not found") + /// Operation was successful + public static let ok = RuuviLocalization.tr("Localizable", "UserApiError.OK", fallback: "Operation was successful") + } + + public enum WebTagLocationSource { + /// Your location + public static let current = RuuviLocalization.tr("Localizable", "WebTagLocationSource.current", fallback: "Your location") + /// Pick from the map + public static let manual = RuuviLocalization.tr("Localizable", "WebTagLocationSource.manual", fallback: "Pick from the map") + } + + public enum WebTagSettings { + public enum AirHumidityAlert { + /// Air Humidity + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.AirHumidityAlert.title", fallback: "Air Humidity") + } + + public enum Alerts { + /// Off + public static let off = RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Off", fallback: "Off") + public enum DewPoint { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.DewPoint.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } + } + + public enum Humidity { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Humidity.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } + } + + public enum Pressure { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Pressure.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } + } + + public enum Temperature { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Temperature.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } + } + } + + public enum AlertsAreDisabled { + public enum Dialog { + public enum BothNoPNPermissionAndNoLocationPermission { + /// In order to enable virtual sensor alerts please always grant location and notification permissions in Settings. + public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.AlertsAreDisabled.Dialog.BothNoPNPermissionAndNoLocationPermission.message", fallback: "In order to enable virtual sensor alerts please always grant location and notification permissions in Settings.") + } + + public enum Settings { + /// Settings + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.AlertsAreDisabled.Dialog.Settings.title", fallback: "Settings") + } + } + } + + public enum Button { + public enum Remove { + /// REMOVE THIS VIRTUAL SENSOR + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.Button.Remove.title", fallback: "REMOVE THIS VIRTUAL SENSOR") + } + } + + public enum Label { + public enum BackgroundImage { + /// BACKGROUND + /// IMAGE + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.BackgroundImage.text", fallback: "BACKGROUND\nIMAGE") + } + + public enum Location { + /// Location + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.Location.text", fallback: "Location") + } + + public enum TagName { + /// Sensor Name + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.TagName.text", fallback: "Sensor Name") + } + + public enum Alerts { + /// ALERTS + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.alerts.text", fallback: "ALERTS") + } + + public enum Disabled { + /// DISABLED? + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.disabled.text", fallback: "DISABLED?") + } + } + + public enum Location { + /// Your location + public static let current = RuuviLocalization.tr("Localizable", "WebTagSettings.Location.Current", fallback: "Your location") + } + + public enum PressureAlert { + /// Air Pressure + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.PressureAlert.title", fallback: "Air Pressure") + } + + public enum SectionHeader { + public enum MoreInfo { + /// MORE INFO + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.SectionHeader.MoreInfo.title", fallback: "MORE INFO") + } + + public enum Name { + /// NAME + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.SectionHeader.Name.title", fallback: "NAME") + } + } + + public enum ConfirmClearLocationDialog { + /// Are you sure you want to clear location for this virtual sensor? Current location will be used instead. + public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmClearLocationDialog.message", fallback: "Are you sure you want to clear location for this virtual sensor? Current location will be used instead.") + /// Clear Location + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmClearLocationDialog.title", fallback: "Clear Location") + } + + public enum ConfirmTagRemovalDialog { + /// Are you sure you want to remove this virtual sensor? + public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmTagRemovalDialog.message", fallback: "Are you sure you want to remove this virtual sensor?") + /// Remove virtual sensor + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmTagRemovalDialog.title", fallback: "Remove virtual sensor") + } + + public enum DewPointAlertTitleLabel { + /// Dew Point + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.dewPointAlertTitleLabel.text", fallback: "Dew Point") + } + + public enum NavigationItem { + /// Virtual Sensor Settings + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.navigationItem.title", fallback: "Virtual Sensor Settings") + } + + public enum TemperatureAlertTitleLabel { + /// Temperature + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.temperatureAlertTitleLabel.text", fallback: "Temperature") + } + } + + public enum Welcome { + public enum Description { + /// To find nearby sensors and receive live sensor data, press 'scan'. + public static let text = RuuviLocalization.tr("Localizable", "Welcome.description.text", fallback: "To find nearby sensors and receive live sensor data, press 'scan'.") + } + + public enum Scan { + /// SCAN + public static let title = RuuviLocalization.tr("Localizable", "Welcome.scan.title", fallback: "SCAN") + } + } + + public enum Widgets { + public enum Description { + /// Create widgets of your favourite Ruuvi sensors. Widgets update from the Ruuvi Cloud. A Ruuvi Gateway router is required. + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Description.message", fallback: "Create widgets of your favourite Ruuvi sensors. Widgets update from the Ruuvi Cloud. A Ruuvi Gateway router is required.") + } + + public enum Loading { + /// loading... + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Loading.message", fallback: "loading...") + } + + public enum Select { + public enum Sensor { + /// Selected Ruuvi sensor + public static let title = RuuviLocalization.tr("Localizable", "Widgets.Select.Sensor.title", fallback: "Selected Ruuvi sensor") + } + } + + public enum Sensor { + public enum `Type` { + /// Selected sensor type + public static let title = RuuviLocalization.tr("Localizable", "Widgets.Sensor.Type.title", fallback: "Selected sensor type") + } + } + + public enum Unauthorized { + public enum Inline { + /// Sign in to Ruuvi Station + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unauthorized.Inline.message", fallback: "Sign in to Ruuvi Station") + } + + public enum Regular { + /// Sign in to use the widget. + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unauthorized.Regular.message", fallback: "Sign in to use the widget.") + } + } + + public enum Unconfigured { + public enum Circular { + /// +Add + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Circular.message", fallback: "+Add") + } + + public enum Inline { + /// Add sensor to use Ruuvi Widget + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Inline.message", fallback: "Add sensor to use Ruuvi Widget") + } + + public enum Rectangular { + /// Add sensor to use Ruuvi Widget + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Rectangular.message", fallback: "Add sensor to use Ruuvi Widget") + } + + public enum Simple { + /// Force tap to edit the widget. + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Simple.message", fallback: "Force tap to edit the widget.") + } + } + } } + // swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length // swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces // MARK: - Implementation Details extension RuuviLocalization { - private static func tr(_ table: String, _ key: String, _ args: CVarArg..., fallback value: String) -> String { - let format = BundleToken.bundle.localizedString(forKey: key, value: value, table: table) - return String(format: format, locale: Locale.current, arguments: args) - } + private static func tr(_ table: String, _ key: String, _ args: CVarArg..., fallback value: String) -> String { + let format = BundleToken.bundle.localizedString(forKey: key, value: value, table: table) + return String(format: format, locale: Locale.current, arguments: args) + } } // swiftlint:disable convenience_type private final class BundleToken { - static let bundle: Bundle = { - #if SWIFT_PACKAGE - return Bundle.module - #else - return Bundle(for: BundleToken.self) - #endif - }() + static let bundle: Bundle = { + #if SWIFT_PACKAGE + return Bundle.module + #else + return Bundle(for: BundleToken.self) + #endif + }() } + // swiftlint:enable convenience_type +// swiftlint:enable all diff --git a/Common/RuuviLocalization/Templates/structured-swift5.stencil b/Common/RuuviLocalization/Templates/structured-swift5.stencil new file mode 100644 index 000000000..14f387f37 --- /dev/null +++ b/Common/RuuviLocalization/Templates/structured-swift5.stencil @@ -0,0 +1,104 @@ +// swiftlint:disable all +// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen + +{% if tables.count > 0 %} +{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %} +import Foundation + +// swiftlint:disable superfluous_disable_command file_length implicit_return prefer_self_in_static_references + +// MARK: - Strings + +{% macro parametersBlock types %} + {%- for type in types -%} + {%- if type == "String" -%} + _ p{{forloop.counter}}: Any + {%- else -%} + _ p{{forloop.counter}}: {{type}} + {%- endif -%} + {{ ", " if not forloop.last }} + {%- endfor -%} +{% endmacro %} +{% macro argumentsBlock types %} + {%- for type in types -%} + {%- if type == "String" -%} + String(describing: p{{forloop.counter}}) + {%- elif type == "UnsafeRawPointer" -%} + Int(bitPattern: p{{forloop.counter}}) + {%- else -%} + p{{forloop.counter}} + {%- endif -%} + {{ ", " if not forloop.last }} + {%- endfor -%} +{% endmacro %} +{% macro recursiveBlock table item %} + {% for string in item.strings %} + {% if not param.noComments %} + {% for line in string.comment|default:string.translation|split:"\n" %} + /// {{line}} + {% endfor %} + {% endif %} + {% set translation string.translation|replace:'"','\"'|replace:' ','\t' %} + {% if string.types %} + {{accessModifier}} static func {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}({% call parametersBlock string.types %}) -> String { + {{enumName}}.tr("{{table}}", "{{string.key}}", {%+ call argumentsBlock string.types %}, fallback: "{{translation}}") + } + {% elif param.lookupFunction %} + {{accessModifier}} static var {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}: String { return {{enumName}}.tr("{{table}}", "{{string.key}}", fallback: "{{translation}}") } + {% else %} + {{accessModifier}} static let {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{enumName}}.tr("{{table}}", "{{string.key}}", fallback: "{{translation}}") + {% endif %} + {% endfor %} + {% for child in item.children %} + {{accessModifier}} enum {{child.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} { + {% filter indent:2," ",true %}{% call recursiveBlock table child %}{% endfilter %} + } + {% endfor %} +{% endmacro %} +// swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length +// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces +{% set enumName %}{{param.enumName|default:"L10n"}}{% endset %} +{{accessModifier}} enum {{enumName}} { + {% if tables.count > 1 or param.forceFileNameEnum %} + {% for table in tables %} + {{accessModifier}} enum {{table.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} { + {% filter indent:2," ",true %}{% call recursiveBlock table.name table.levels %}{% endfilter %} + } + {% endfor %} + {% else %} + {% call recursiveBlock tables.first.name tables.first.levels %} + {% endif %} +} +// swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length +// swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces + +// MARK: - Implementation Details + +extension {{enumName}} { + private static func tr(_ table: String, _ key: String, _ args: CVarArg..., fallback value: String) -> String { + {% if param.lookupFunction %} + let format = {{ param.lookupFunction }}(key, table, value) + {% else %} + let format = {{param.bundle|default:"BundleToken.bundle"}}.localizedString(forKey: key, value: value, table: table) + {% endif %} + return String(format: format, locale: Locale.current, arguments: args) + } +} +{% if not param.bundle and not param.lookupFunction %} + +// swiftlint:disable convenience_type +private final class BundleToken { + static let bundle: Bundle = { + #if SWIFT_PACKAGE + return Bundle.module + #else + return Bundle(for: BundleToken.self) + #endif + }() +} +// swiftlint:enable convenience_type +{% endif %} +{% else %} +// No string found +{% endif %} +// swiftlint:enable all diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift index 6d2204801..19876bf35 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift @@ -4,7 +4,13 @@ import UIKit public extension Bundle { static func pod(_ clazz: AnyClass) -> Bundle { if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { - if let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), let bundle = Bundle(url: bundleURL) { + if let bundleURL = Bundle( + for: clazz + ).resourceURL?.appendingPathComponent( + "\(module).bundle" + ), let bundle = Bundle( + url: bundleURL + ) { return bundle } else if let bundleURL = Bundle(for: clazz).resourceURL, let bundle = Bundle(url: bundleURL) { return bundle diff --git a/Makefile b/Makefile index 0e75f75ff..b0ea02ca2 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ -.PHONY: installed_xcodegen installed_swiftgen installed_firebase +.PHONY: installed_xcodegen installed_swiftgen installed_swiftlint installed_firebase # generates xcodeproj for frameworks build configuration -xcodeproj_with_frameworks: installed_xcodegen installed_swiftgen +xcodeproj_with_frameworks: installed_xcodegen installed_swiftgen installed_swiftlint .tools/xcodegen/bin/xcodegen -s project_frameworks.yml # install firebase @@ -11,6 +11,13 @@ installed_firebase: .tools/firebase/firebase scripts/install/install_firebase.sh touch $@ +# install swiftgen +installed_swiftlint: .tools/swiftlint/swiftlint + +.tools/swiftlint/swiftlint: scripts/install/install_swiftlint.sh + scripts/install/install_swiftlint.sh + touch $@ + # install swiftgen installed_swiftgen: .tools/swiftgen/bin/swiftgen @@ -27,7 +34,7 @@ installed_xcodegen: .tools/xcodegen/bin/xcodegen touch $@ # generates xcodeproj for swift package manager build configuration -xcodeproj_with_spm: installed_xcodegen installed_swiftgen +xcodeproj_with_spm: installed_xcodegen installed_swiftgen installed_swiftlint .tools/xcodegen/bin/xcodegen -s project_spm.yml # builds station target with frameworks build configuration for iOS diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift index 6d2204801..19876bf35 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift @@ -4,7 +4,13 @@ import UIKit public extension Bundle { static func pod(_ clazz: AnyClass) -> Bundle { if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { - if let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), let bundle = Bundle(url: bundleURL) { + if let bundleURL = Bundle( + for: clazz + ).resourceURL?.appendingPathComponent( + "\(module).bundle" + ), let bundle = Bundle( + url: bundleURL + ) { return bundle } else if let bundleURL = Bundle(for: clazz).resourceURL, let bundle = Bundle(url: bundleURL) { return bundle diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift index d7c4eb5bf..b2e79c480 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift @@ -11,6 +11,7 @@ protocol DiscoverViewInput: UIViewController { func showBluetoothDisabled(userDeclined: Bool) func startNFCSession() func stopNFCSession() + // swiftlint:disable:next function_parameter_count func showSensorDetailsDialog( for tag: NFCSensor?, message: String, diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift index eb2e1900d..8bf10300e 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift @@ -1,3 +1,4 @@ +// swiftlint:disable file_length import BTKit import CoreNFC import RuuviLocalization @@ -86,6 +87,7 @@ extension DiscoverTableViewController: DiscoverViewInput { session = nil } + // swiftlint:disable:next function_parameter_count function_body_length func showSensorDetailsDialog( for tag: NFCSensor?, message: String, @@ -402,3 +404,5 @@ extension DiscoverTableViewController: NFCNDEFReaderSessionDelegate { } } } + +// swiftlint:enable file_length diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift index 00bd99755..81a29a664 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift @@ -184,7 +184,9 @@ final class FirmwareInteractor { guard let firmware = ruuviDFU.firmwareFromUrl(url: firmwareUrl) else { - return Fail(error: FirmwareError.failedToConstructFirmwareFromFile).eraseToAnyPublisher() + return Fail( + error: FirmwareError.failedToConstructFirmwareFromFile + ).eraseToAnyPublisher() } return ruuviDFU.flashFirmware(uuid: uuid, with: firmware).eraseToAnyPublisher() } diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift index cbecc9212..8b5bfeba8 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift @@ -1,5 +1,7 @@ +// swiftlint:disable file_length import SwiftUI +// swiftlint:disable:next type_body_length struct FirmwareView: View { @ObservedObject var viewModel: FirmwareViewModel @@ -17,8 +19,12 @@ struct FirmwareView: View { let openCoverTitle = "DFUUIView.openCoverTitle".localized(for: FirmwareViewModel.self) let localBootButtonTitle = "DFUUIView.locateBootButtonTitle".localized(for: FirmwareViewModel.self) let setUpdatingModeTitle = "DFUUIView.setUpdatingModeTitle".localized(for: FirmwareViewModel.self) - let toBootModeTwoButtonsDescription = "DFUUIView.toBootModeTwoButtonsDescription".localized(for: FirmwareViewModel.self) - let toBootModeOneButtonDescription = "DFUUIView.toBootModeOneButtonDescription".localized(for: FirmwareViewModel.self) + let toBootModeTwoButtonsDescription = "DFUUIView.toBootModeTwoButtonsDescription".localized( + for: FirmwareViewModel.self + ) + let toBootModeOneButtonDescription = "DFUUIView.toBootModeOneButtonDescription".localized( + for: FirmwareViewModel.self + ) let toBootModeSuccessTitle = "DFUUIView.toBootModeSuccessTitle".localized(for: FirmwareViewModel.self) let updatingTitle = "DFUUIView.updatingTitle".localized(for: FirmwareViewModel.self) let searchingTitle = "DFUUIView.searchingTitle".localized(for: FirmwareViewModel.self) @@ -435,3 +441,5 @@ private extension CGFloat { UIDevice.current.userInterfaceIdiom == .pad ? self + 4 : self } } + +// swiftlint:enable file_length diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift index 6293a7b95..743063220 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift @@ -1,3 +1,4 @@ +// swiftlint:disable file_length import Combine import Foundation @@ -305,6 +306,7 @@ extension FirmwareViewModel { } extension FirmwareViewModel { + // swiftlint:disable:next cyclomatic_complexity function_body_length static func reduce(_ state: State, _ event: Event) -> State { switch state { case .idle: @@ -416,3 +418,5 @@ extension FirmwareViewModel { return !currentRelease.version.contains(latestRelease.version) } } + +// swiftlint:enable file_length diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift index 6d2204801..19876bf35 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift @@ -4,7 +4,13 @@ import UIKit public extension Bundle { static func pod(_ clazz: AnyClass) -> Bundle { if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { - if let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), let bundle = Bundle(url: bundleURL) { + if let bundleURL = Bundle( + for: clazz + ).resourceURL?.appendingPathComponent( + "\(module).bundle" + ), let bundle = Bundle( + url: bundleURL + ) { return bundle } else if let bundleURL = Bundle(for: clazz).resourceURL, let bundle = Bundle(url: bundleURL) { return bundle diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift index 4db785010..da863fb5e 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift @@ -30,10 +30,8 @@ struct OnboardViewModel { var pageType: OnboardPageType var title: String var subtitle: String - // swiftlint:disable redundant_optional_initialization var sub_subtitle: String? var image: String? - // swiftlint:enable redundant_optional_initialization } class RuuviOnboardViewController: UIViewController { diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift index 6d2204801..19876bf35 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift @@ -4,7 +4,13 @@ import UIKit public extension Bundle { static func pod(_ clazz: AnyClass) -> Bundle { if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { - if let bundleURL = Bundle(for: clazz).resourceURL?.appendingPathComponent("\(module).bundle"), let bundle = Bundle(url: bundleURL) { + if let bundleURL = Bundle( + for: clazz + ).resourceURL?.appendingPathComponent( + "\(module).bundle" + ), let bundle = Bundle( + url: bundleURL + ) { return bundle } else if let bundleURL = Bundle(for: clazz).resourceURL, let bundle = Bundle(url: bundleURL) { return bundle diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiURLSession.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiURLSession.swift index 9855cf539..8766bb1a9 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiURLSession.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/RuuviCloudApiURLSession.swift @@ -28,6 +28,7 @@ extension RuuviCloudApiURLSession { } } +// swiftlint:disable:next type_body_length public final class RuuviCloudApiURLSession: NSObject, RuuviCloudApi { private lazy var uploadSession: URLSession = { let config = URLSessionConfiguration.default @@ -396,14 +397,20 @@ extension RuuviCloudApiURLSession { config.waitsForConnectivity = true config.timeoutIntervalForResource = 30 } - let task = URLSession(configuration: config).dataTask(with: request) { data, _, error in + let task = URLSession(configuration: config).dataTask(with: request) { + data, + _, + error in if let error { promise.fail(error: .networking(error)) } else { if let data { #if DEBUG if let object = try? JSONSerialization.jsonObject(with: data, options: []), - let jsonData = try? JSONSerialization.data(withJSONObject: object, options: [.prettyPrinted]), + let jsonData = try? JSONSerialization.data( + withJSONObject: object, + options: [.prettyPrinted] + ), let prettyPrintedString = NSString(data: jsonData, encoding: String.Encoding.utf8.rawValue) { debugPrint("📬 Response of request", dump(request), prettyPrintedString) } diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/ThirdParty/URLQueryItemEncoder.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/ThirdParty/URLQueryItemEncoder.swift index f83f68ec9..f5e7253d6 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/ThirdParty/URLQueryItemEncoder.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/ThirdParty/URLQueryItemEncoder.swift @@ -357,7 +357,10 @@ private extension URLQueryItemEncoder { keyedBy _: NestedKey.Type ) -> KeyedEncodingContainer where NestedKey: CodingKey { codingPath.append( - URLQueryItemArrayElementKey(index: encodedItemsCount, encodingStrategy: encoder.arrayIndexEncodingStrategy) + URLQueryItemArrayElementKey( + index: encodedItemsCount, + encodingStrategy: encoder.arrayIndexEncodingStrategy + ) ) defer { codingPath.removeLast() } return KeyedEncodingContainer(KeyedContainer(encoder: encoder, codingPath: codingPath)) @@ -365,7 +368,10 @@ private extension URLQueryItemEncoder { func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { codingPath.append( - URLQueryItemArrayElementKey(index: encodedItemsCount, encodingStrategy: encoder.arrayIndexEncodingStrategy) + URLQueryItemArrayElementKey( + index: encodedItemsCount, + encodingStrategy: encoder.arrayIndexEncodingStrategy + ) ) defer { codingPath.removeLast() } return self @@ -384,7 +390,10 @@ private extension URLQueryItemEncoder { func encodeNil() throws { codingPath.append( - URLQueryItemArrayElementKey(index: encodedItemsCount, encodingStrategy: encoder.arrayIndexEncodingStrategy) + URLQueryItemArrayElementKey( + index: encodedItemsCount, + encodingStrategy: encoder.arrayIndexEncodingStrategy + ) ) defer { codingPath.removeLast() } try encoder.pushNil(forKey: codingPath) @@ -393,7 +402,10 @@ private extension URLQueryItemEncoder { func encode(_ value: some Encodable) throws { codingPath.append( - URLQueryItemArrayElementKey(index: encodedItemsCount, encodingStrategy: encoder.arrayIndexEncodingStrategy) + URLQueryItemArrayElementKey( + index: encodedItemsCount, + encodingStrategy: encoder.arrayIndexEncodingStrategy + ) ) defer { codingPath.removeLast() } try encoder.push(value, forKey: codingPath) diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Advertisement/RuuviTagAdvertisementDaemonBTKit.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Advertisement/RuuviTagAdvertisementDaemonBTKit.swift index b86567b16..51ba40c38 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Advertisement/RuuviTagAdvertisementDaemonBTKit.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Advertisement/RuuviTagAdvertisementDaemonBTKit.swift @@ -169,7 +169,7 @@ public final class RuuviTagAdvertisementDaemonBTKit: RuuviDaemonWorker, RuuviTag } } - // swiftlint:disable:next cyclomatic_complexity + // swiftlint:disable:next cyclomatic_complexity function_body_length private func restartObserving() { observeTokens.forEach { $0.invalidate() } observeTokens.removeAll() diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift index 616cf6c35..085918b73 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift @@ -6,6 +6,7 @@ import RuuviPersistence import RuuviPool import RuuviReactor +// swiftlint:disable:next type_body_length public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPropertiesDaemon { private let ruuviPool: RuuviPool private let ruuviReactor: RuuviReactor diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalConnectionsUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalConnectionsUserDefaults.swift index 0edce2a06..b5963c280 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalConnectionsUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalConnectionsUserDefaults.swift @@ -32,6 +32,7 @@ final class RuuviLocalConnectionsUserDefaults: RuuviLocalConnections { } } + // swiftlint:disable:next function_body_length func setKeepConnection( _ value: Bool, for luid: LocalIdentifier diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift index 920029844..9a151eefe 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift @@ -510,7 +510,6 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { } } - // swiftlint:disable switch_case_alignment var dashboardTapActionType: DashboardTapActionType { get { switch dashboardTapActionTypeId { @@ -539,8 +538,6 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { } } - // swiftlint:enable switch_case_alignment - private let ruuviThemeIdKey = "SettingsUserDefaults.ruuviThemeIdKey" private var ruuviThemeId: Int { get { diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift index b386decfa..d257a81e2 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift @@ -70,6 +70,7 @@ public final class MigrationManagerToVIPER: RuuviMigration { } } + // swiftlint:disable:next function_body_length private func from1to2(_ migration: Migration) { migration.enumerateObjects(ofType: "RuuviTag") { oldObject, _ in if let uuid = oldObject?["uuid"] as? String, diff --git a/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift b/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift index 43660f93b..b34df7b89 100644 --- a/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift @@ -235,7 +235,7 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { return promise.succeed(value: true) } - let queuedRequests = requests.flatMap { request in + let queuedRequests = requests.compactMap { request in self?.syncQueuedRequest(request: request) } diff --git a/pnservice/NotificationService.swift b/pnservice/NotificationService.swift index bbce08154..537d14b17 100644 --- a/pnservice/NotificationService.swift +++ b/pnservice/NotificationService.swift @@ -1,7 +1,6 @@ import UserNotifications class NotificationService: UNNotificationServiceExtension { - // swiftlint:disable redundant_string_enum_value private enum AlertType: String { case temperature case humidity @@ -16,8 +15,6 @@ class NotificationService: UNNotificationServiceExtension { case over } - // swiftlint:enable redundant_string_enum_value - private let notificationServiceAppGroup = UserDefaults(suiteName: "group.com.ruuvi.station.pnservice") var contentHandler: ((UNNotificationContent) -> Void)? diff --git a/project_frameworks.yml b/project_frameworks.yml index ce06fe8e3..6ea423bcf 100644 --- a/project_frameworks.yml +++ b/project_frameworks.yml @@ -322,6 +322,11 @@ targets: - $(SRCROOT)/station/Resources/Strings/fi.lproj/Localizable.strings - $(SRCROOT)/station/Resources/Strings/fr.lproj/Localizable.strings - $(SRCROOT)/station/Resources/Strings/de.lproj/Localizable.strings + postCompileScripts: + - path: scripts/build/lint.sh + name: Lint + BASED_ON_DEPENDENCY_ANALYSIS: false + ENABLE_USER_SCRIPT_SANDBOXING: false postBuildScripts: - path: scripts/build/load_keystore.sh name: Load Keystore diff --git a/scripts/build/lint.sh b/scripts/build/lint.sh new file mode 100644 index 000000000..a7e900929 --- /dev/null +++ b/scripts/build/lint.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +if which ./.tools/swiftlint/swiftlint > /dev/null; then + ./.tools/swiftlint/swiftlint +else + echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint" +fi \ No newline at end of file diff --git a/scripts/install/install_swiftlint.sh b/scripts/install/install_swiftlint.sh new file mode 100755 index 000000000..7650b350d --- /dev/null +++ b/scripts/install/install_swiftlint.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +set -e + +OUTPUT_DIR=".tools/swiftlint" + + +EXPECTED_SWIFTLINT_HASH="1511431b2ca803ecb921cfa119b70bb1" + +# check if swiftlint is already installed by hashing all files in the output directory +if [ -d "$OUTPUT_DIR" ] && [ "$(find "$OUTPUT_DIR" -type f -exec md5 {} \; | md5)" = $EXPECTED_SWIFTLINT_HASH ]; then + echo "swiftlint is already installed" + exit 0 +fi + +# remove the output directory if it exists +if [ -d "$OUTPUT_DIR" ]; then + rm -rf "$OUTPUT_DIR" +fi + +# create the output directory +mkdir -p "$OUTPUT_DIR" + +# download the latest release of swiftlint +curl -L "https://github.com/realm/SwiftLint/releases/download/0.54.0/portable_swiftlint.zip" -o ".tools/swiftlint.zip" + +# unzip the downloaded file +unzip ".tools/swiftlint.zip" -d ".tools/swiftlint" + +# remove the downloaded file +rm ".tools/swiftlint.zip" + +# if the hash of downloaded swiftlint is not the expected value, exit with an error +INSTALLED_SWIFTLINT_HASH="$(find "$OUTPUT_DIR" -type f -exec md5 {} \; | md5)" +if [ "$INSTALLED_SWIFTLINT_HASH" != "$EXPECTED_SWIFTLINT_HASH" ]; then + echo "swiftlint failed to install" + echo "Expected hash: $EXPECTED_SWIFTLINT_HASH" + echo "Actual hash: $INSTALLED_SWIFTLINT_HASH" + exit 1 +else + echo "No swiftlint install needed" +fi \ No newline at end of file diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift index 0252a1d75..6ec8d7cdf 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift @@ -142,6 +142,7 @@ private extension BackgroundSelectionViewController { uploadProgressView.isHidden = true } + // swiftlint:disable:next function_body_length func createLayout() -> UICollectionViewLayout { let sectionProvider = { [weak self] ( _: Int, diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift index 06211dc1a..c334ae532 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift @@ -1,6 +1,6 @@ +// swiftlint:disable file_length import BTKit import CoreBluetooth -// swiftlint:disable file_length trailing_whitespace import Foundation import RuuviCore import RuuviDaemon @@ -295,7 +295,6 @@ extension CardsPresenter { } } - // swiftlint:disable:next function_body_length private func startObservingAlertChanges() { alertDidChangeToken?.invalidate() alertDidChangeToken = NotificationCenter @@ -538,7 +537,7 @@ extension CardsPresenter { } } - // swiftlint:disable:next cyclomatic_complexity function_body_length + // swiftlint:disable:next function_body_length func startObservingDaemonsErrors() { ruuviTagAdvertisementDaemonFailureToken?.invalidate() ruuviTagAdvertisementDaemonFailureToken = NotificationCenter @@ -659,7 +658,6 @@ extension CardsPresenter { } // ACTIONS - // swiftlint:disable:next function_body_length private func syncViewModels() { let ruuviViewModels = ruuviTags.compactMap { ruuviTag -> CardsViewModel in let viewModel = CardsViewModel(ruuviTag) @@ -1383,4 +1381,4 @@ extension CardsPresenter { } } -// swiftlint:enable file_length trailing_whitespace +// swiftlint:enable file_length diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift index a5c5c06d0..279f2857b 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift @@ -747,6 +747,7 @@ extension TagChartsViewPresenter { view?.updateLatestRecordStatus(with: record) } + // swiftlint:disable:next function_body_length private func createChartData() { guard view != nil else { return } datasource.removeAll() diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift b/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift index 417c29cf7..43a7a2b1c 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift @@ -1,6 +1,5 @@ import BTKit import CoreBluetooth -// swiftlint:disable file_length trailing_whitespace import Foundation import Future import Humidity @@ -19,6 +18,7 @@ import RuuviUser import UIKit import WidgetKit +// swiftlint:disable file_length class DashboardPresenter: DashboardModuleInput { weak var view: DashboardViewInput? var router: DashboardRouterInput! @@ -227,7 +227,6 @@ extension DashboardPresenter: DashboardViewOutput { openCardView(viewModel: viewModel, showCharts: false) } - // swiftlint:disable switch_case_alignment func viewDidTriggerDashboardCard(for viewModel: CardsViewModel) { switch settings.dashboardTapActionType { case .card: @@ -237,8 +236,6 @@ extension DashboardPresenter: DashboardViewOutput { } } - // swiftlint:enable switch_case_alignment - func viewDidTriggerChangeBackground(for viewModel: CardsViewModel) { if viewModel.type == .ruuvi { if let ruuviTagSensor = ruuviTags.first(where: { $0.id == viewModel.id.value }) { @@ -556,7 +553,6 @@ extension DashboardPresenter: TagSettingsModuleOutput { // MARK: - Private extension DashboardPresenter { - // swiftlint:disable:next function_body_length private func syncViewModels() { view?.userSignedInOnce = settings.signedInAtleastOnce view?.dashboardType = settings.dashboardType @@ -1058,7 +1054,7 @@ extension DashboardPresenter { } } - // swiftlint:disable:next cyclomatic_complexity function_body_length + // swiftlint:disable:next function_body_length func startObservingDaemonsErrors() { ruuviTagAdvertisementDaemonFailureToken?.invalidate() ruuviTagAdvertisementDaemonFailureToken = NotificationCenter @@ -1190,7 +1186,6 @@ extension DashboardPresenter { ) } - // swiftlint:disable:next function_body_length private func startObservingAlertChanges() { alertDidChangeToken?.invalidate() alertDidChangeToken = NotificationCenter @@ -1879,4 +1874,4 @@ extension DashboardPresenter { } } -// swiftlint:enable file_length trailing_whitespace +// swiftlint:enable file_length diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift index a3a896ae0..f17a92cc7 100644 --- a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift +++ b/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift @@ -2,9 +2,11 @@ import RuuviLocal import RuuviLocalization import RuuviOntology import RuuviService -// swiftlint:disable file_length + import UIKit +// swiftlint:disable file_length +// swiftlint:disable:next type_body_length class DashboardImageCell: UICollectionViewCell { private lazy var cardBackgroundView = CardsBackgroundView() diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift index e3ba42572..549a11a01 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift @@ -21,7 +21,9 @@ class ChartSettingsStepperTableViewCell: UITableViewCell { @IBAction func stepperValueChanged(_: Any) { let result = Int(stepper.value) - let unitString: String = result > 1 ? RuuviLocalization.Interval.Days.string : RuuviLocalization.Interval.Day.string + let unitString: String = result > 1 + ? RuuviLocalization.Interval.Days.string + : RuuviLocalization.Interval.Day.string titleLabel.text = prefix + " " + "(" + "\(result)" + " " + unitString + ")" delegate?.chartSettingsStepper(cell: self, didChange: result) } diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift index 7e52b11d7..f27e2d33f 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift @@ -73,8 +73,10 @@ extension DefaultsPresenter { private func buildChartsSwipeInstruction() -> DefaultsViewModel { let tagChartsLandscapeSwipeInstructionWasShown = DefaultsViewModel() - tagChartsLandscapeSwipeInstructionWasShown.title = RuuviLocalization.Defaults.ChartsSwipeInstructionWasShown.title - tagChartsLandscapeSwipeInstructionWasShown.boolean.value = settings.tagChartsLandscapeSwipeInstructionWasShown + tagChartsLandscapeSwipeInstructionWasShown.title + = RuuviLocalization.Defaults.ChartsSwipeInstructionWasShown.title + tagChartsLandscapeSwipeInstructionWasShown.boolean.value + = settings.tagChartsLandscapeSwipeInstructionWasShown tagChartsLandscapeSwipeInstructionWasShown.type.value = .switcher bind(tagChartsLandscapeSwipeInstructionWasShown.boolean, fire: false) { diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift index ece0c480b..10ee6ddd4 100644 --- a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift +++ b/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift @@ -80,7 +80,7 @@ extension UnitSettingsTableViewController { 2 } - // swiftlint:disable:next cyclomatic_complexity + // swiftlint:disable:next cyclomatic_complexity function_body_length override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell( withIdentifier: unitSettingsCellReuseIdentifier, diff --git a/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift b/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift index 9498d5256..c7705bf4a 100644 --- a/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift +++ b/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift @@ -134,7 +134,6 @@ extension SharePresenter: ShareModuleInput { // MARK: - Private extension SharePresenter { - // swiftlint:disable switch_case_alignment private func startObservingRuuviTag() { ruuviTagToken?.invalidate() ruuviTagToken = ruuviReactor.observe { [weak self] change in @@ -210,5 +209,3 @@ extension SharePresenter { return emailPred.evaluate(with: email) } } - -// swiftlint:enable switch_case_alignment diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift b/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift index 776b8f150..f352547b1 100644 --- a/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift +++ b/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift @@ -129,7 +129,11 @@ extension SignInViewController: SignInViewInput { } func showEmailsAreDifferent(requestedEmail: String, validatedEmail: String) { - let message = RuuviLocalization.SignIn.EmailMismatch.Alert.message(requestedEmail, validatedEmail, requestedEmail) + let message = RuuviLocalization.SignIn.EmailMismatch.Alert.message( + requestedEmail, + validatedEmail, + requestedEmail + ) let alertVC = UIAlertController(title: nil, message: message, preferredStyle: .alert) alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift index 650ba3fea..6b0fecf59 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift @@ -1,6 +1,6 @@ +// swiftlint:disable file_length import BTKit import Combine -// swiftlint:disable file_length import Foundation import RuuviDaemon import RuuviFirmware @@ -11,6 +11,7 @@ import RuuviPool import RuuviPresenters import RuuviStorage +// swiftlint:disable:next type_body_length final class DFUViewModel: ObservableObject { @Published private(set) var state: State = .idle @Published var downloadProgress: Double = 0 diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift index bb5d2070e..1991de466 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift @@ -1,3 +1,4 @@ +// swiftlint:disable file_length import RangeSeekSlider import RuuviLocalization import UIKit @@ -432,3 +433,5 @@ extension TagSettingsAlertConfigCell: RangeSeekSliderDelegate { ) } } + +// swiftlint:enable file_length diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift index c836927c9..8c4e3b12f 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift @@ -65,7 +65,6 @@ class TagSettingsSection { } struct TagSettingsItem { - // swiftlint:disable:next redundant_optional_initialization var identifier: TagSettingsItemCellIdentifier? var createdCell: () -> UITableViewCell var action: ((TagSettingsItem) -> Swift.Void)? @@ -215,7 +214,10 @@ class TagSettingsViewController: UIViewController { return section }() - private lazy var humidityAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell(style: .value1, reuseIdentifier: Self.ReuseIdentifier) + private lazy var humidityAlertCell: TagSettingsAlertConfigCell? = TagSettingsAlertConfigCell( + style: .value1, + reuseIdentifier: Self.ReuseIdentifier + ) // Pressure private lazy var pressureAlertSectionHeaderView: @@ -3518,6 +3520,7 @@ extension TagSettingsViewController: TagSettingsExpandableSectionHeaderDelegate } private extension TagSettingsViewController { + // swiftlint:disable:next function_body_length func setUpUI() { title = RuuviLocalization.TagSettings.NavigationItem.title @@ -3635,7 +3638,6 @@ extension TagSettingsViewController { // MARK: - Sensor alert custom description dialog extension TagSettingsViewController { - // swiftlint:disable:next function_body_length private func showSensorCustomAlertDescriptionDialog( description: String?, sender: TagSettingsAlertConfigCell @@ -3709,7 +3711,7 @@ extension TagSettingsViewController { // MARK: - Sensor alert range settings extension TagSettingsViewController { - // swiftlint:disable:next function_parameter_count function_body_length cyclomatic_complexity + // swiftlint:disable:next function_parameter_count function_body_length private func showSensorCustomAlertRangeDialog( title: String?, minimumBound: Double, diff --git a/stationTests/Services/Alert/AlertServiceSpec.swift b/stationTests/Services/Alert/AlertServiceSpec.swift index e2deec658..972388da2 100644 --- a/stationTests/Services/Alert/AlertServiceSpec.swift +++ b/stationTests/Services/Alert/AlertServiceSpec.swift @@ -3,9 +3,12 @@ import Nimble import Quick import XCTest +// swiftlint:disable file_length @testable import station +// swiftlint:disable:next type_body_length class AlertServiceSpec: QuickSpec { let notificationWaitTimeout: DispatchTimeInterval = .milliseconds(200) + // swiftlint:disable:next function_body_length override func spec() { let alertService = AlertServiceImpl() alertService.alertPersistence = AlertPersistenceUserDefaults() @@ -81,6 +84,7 @@ class AlertServiceSpec: QuickSpec { alertService.setLower(celsius: randomDouble, for: uuid) expect(alertService.lowerCelsius(for: uuid)).to(equal(randomDouble)) } + // swiftlint:disable:next line_length it("if set upper temp is set must send notification AlertServiceAlertDidChange with type .temperature(lower: l, upper: u)") { alertService.alertPersistence.setUpper(celsius: randomDouble, for: uuid) expect { @@ -96,6 +100,7 @@ class AlertServiceSpec: QuickSpec { alertService.setUpper(celsius: randomDouble, for: uuid) expect(alertService.upperCelsius(for: uuid)).to(equal(randomDouble)) } + // swiftlint:disable:next line_length it("if lower temp is set must send notification AlertServiceAlertDidChange with type .temperature(lower: l, upper: u)") { alertService.alertPersistence.setLower(celsius: randomDouble, for: uuid) expect { @@ -111,6 +116,7 @@ class AlertServiceSpec: QuickSpec { alertService.setTemperature(description: uuid, for: uuid) expect(alertService.temperatureDescription(for: uuid)).to(equal(uuid)) } + // swiftlint:disable:next line_length it("if upper and lower temp is set, must send notification AlertServiceAlertDidChange with type .temperature(lower: l, upper: u)") { alertService.alertPersistence.setUpper(celsius: randomDouble, for: uuid) alertService.alertPersistence.setLower(celsius: randomDouble, for: uuid) @@ -132,6 +138,7 @@ class AlertServiceSpec: QuickSpec { alertService.setLower(humidity: Humidity(randomDouble), for: uuid) expect(alertService.lowerHumidity(for: uuid)?.value.isEqual(to: randomDouble)) } + // swiftlint:disable:next line_length it("if upper is set must send notification AlertServiceAlertDidChange with type .relativeHumidity(lower: l, upper: u)") { alertService.alertPersistence.setUpper(relativeHumidity: randomDouble, for: uuid) expect { @@ -147,6 +154,7 @@ class AlertServiceSpec: QuickSpec { alertService.setUpper(relativeHumidity: randomDouble, for: uuid) expect(alertService.upperRelativeHumidity(for: uuid)).to(equal(randomDouble)) } + // swiftlint:disable:next line_length it("if lower is set must send notification AlertServiceAlertDidChange with type .relativeHumidity(lower: l, upper: u)") { alertService.alertPersistence.setLower(relativeHumidity: randomDouble, for: uuid) expect { @@ -162,6 +170,7 @@ class AlertServiceSpec: QuickSpec { alertService.setRelativeHumidity(description: uuid, for: uuid) expect(alertService.relativeHumidityDescription(for: uuid)).to(equal(uuid)) } + // swiftlint:disable:next line_length it("if upper and lower relative humidity is set, must send notification AlertServiceAlertDidChange with type .relativeHumidity(lower: l, upper: u)") { alertService.alertPersistence.setUpper(relativeHumidity: randomDouble, for: uuid) alertService.alertPersistence.setLower(relativeHumidity: randomDouble, for: uuid) @@ -183,6 +192,7 @@ class AlertServiceSpec: QuickSpec { alertService.setLower(absoluteHumidity: randomDouble, for: uuid) expect(alertService.lowerAbsoluteHumidity(for: uuid)).to(equal(randomDouble)) } + // swiftlint:disable:next line_length it("if upper is set must send notification AlertServiceAlertDidChange with type .absoluteHumidity(lower: l, upper: u)") { alertService.alertPersistence.setUpper(absoluteHumidity: randomDouble, for: uuid) expect { @@ -198,6 +208,7 @@ class AlertServiceSpec: QuickSpec { alertService.setUpper(absoluteHumidity: randomDouble, for: uuid) expect(alertService.upperAbsoluteHumidity(for: uuid)).to(equal(randomDouble)) } + // swiftlint:disable:next line_length it("if lower is set must send notification AlertServiceAlertDidChange with type .absoluteHumidity(lower: l, upper: u)") { alertService.alertPersistence.setLower(absoluteHumidity: randomDouble, for: uuid) expect { @@ -213,6 +224,7 @@ class AlertServiceSpec: QuickSpec { alertService.setAbsoluteHumidity(description: uuid, for: uuid) expect(alertService.absoluteHumidityDescription(for: uuid)).to(equal(uuid)) } + // swiftlint:disable:next line_length it("if upper and lower absolute humidity is set, must send notification AlertServiceAlertDidChange with type .absoluteHumidity(lower: l, upper: u)") { alertService.alertPersistence.setUpper(absoluteHumidity: randomDouble, for: uuid) alertService.alertPersistence.setLower(absoluteHumidity: randomDouble, for: uuid) @@ -234,6 +246,7 @@ class AlertServiceSpec: QuickSpec { alertService.setLowerDewPoint(celsius: randomDouble, for: uuid) expect(alertService.lowerDewPointCelsius(for: uuid)).to(equal(randomDouble)) } + // swiftlint:disable:next line_length it("if upper is set must send notification AlertServiceAlertDidChange with type .absoluteHumidity(lower: l, upper: u)") { alertService.alertPersistence.setUpperDewPoint(celsius: randomDouble, for: uuid) expect { @@ -249,6 +262,7 @@ class AlertServiceSpec: QuickSpec { alertService.setUpperDewPoint(celsius: randomDouble, for: uuid) expect(alertService.upperDewPointCelsius(for: uuid)).to(equal(randomDouble)) } + // swiftlint:disable:next line_length it("if lower is set must send notification AlertServiceAlertDidChange with type .absoluteHumidity(lower: l, upper: u)") { alertService.alertPersistence.setLowerDewPoint(celsius: randomDouble, for: uuid) expect { @@ -264,6 +278,7 @@ class AlertServiceSpec: QuickSpec { alertService.setDewPoint(description: uuid, for: uuid) expect(alertService.dewPointDescription(for: uuid)).to(equal(uuid)) } + // swiftlint:disable:next line_length it("if upper and lower is set, must send notification AlertServiceAlertDidChange with type .dewPoint(lower: l, upper: u)") { alertService.alertPersistence.setUpperDewPoint(celsius: randomDouble, for: uuid) alertService.alertPersistence.setLowerDewPoint(celsius: randomDouble, for: uuid) @@ -285,6 +300,7 @@ class AlertServiceSpec: QuickSpec { alertService.setLower(pressure: randomDouble, for: uuid) expect(alertService.lowerPressure(for: uuid)).to(equal(randomDouble)) } + // swiftlint:disable:next line_length it("if upper is set must send notification AlertServiceAlertDidChange with type .pressure(lower: l, upper: u)") { alertService.alertPersistence.setUpper(pressure: randomDouble, for: uuid) expect { @@ -300,6 +316,7 @@ class AlertServiceSpec: QuickSpec { alertService.setUpper(pressure: randomDouble, for: uuid) expect(alertService.upperPressure(for: uuid)).to(equal(randomDouble)) } + // swiftlint:disable:next line_length it("if lower is set must send notification AlertServiceAlertDidChange with type .pressure(lower: l, upper: u)") { alertService.alertPersistence.setLower(pressure: randomDouble, for: uuid) expect { @@ -315,6 +332,7 @@ class AlertServiceSpec: QuickSpec { alertService.setPressure(description: uuid, for: uuid) expect(alertService.pressureDescription(for: uuid)).to(equal(uuid)) } + // swiftlint:disable:next line_length it("if upper and lower pressure is set, must send notification AlertServiceAlertDidChange with type .pressure(lower: l, upper: u)") { alertService.alertPersistence.setLower(pressure: randomDouble, for: uuid) alertService.alertPersistence.setUpper(pressure: randomDouble, for: uuid) @@ -404,7 +422,13 @@ class AlertServiceSpec: QuickSpec { } context("relativeHumidity trigger") { it("if less") { - alertService.register(type: .relativeHumidity(lower: randomPercentDouble, upper: randomPercentDouble + 10), for: uuid) + alertService.register( + type: .relativeHumidity( + lower: randomPercentDouble, + upper: randomPercentDouble + 10 + ), + for: uuid + ) let fakeDelegate = MockAlertServiceObserver() alertService.subscribe(fakeDelegate, to: uuid) @@ -417,7 +441,13 @@ class AlertServiceSpec: QuickSpec { expect(localNotificationManager.type).toEventually(equal(LowHighNotificationType.relativeHumidity)) } it("if greather") { - alertService.register(type: .relativeHumidity(lower: randomPercentDouble - 10, upper: randomPercentDouble), for: uuid) + alertService.register( + type: .relativeHumidity( + lower: randomPercentDouble - 10, + upper: randomPercentDouble + ), + for: uuid + ) let fakeDelegate = MockAlertServiceObserver() alertService.subscribe(fakeDelegate, to: uuid) @@ -562,7 +592,13 @@ class AlertServiceSpec: QuickSpec { } context("relativeHumidity trigger") { it("if less") { - alertService.register(type: .relativeHumidity(lower: randomPercentDouble, upper: randomPercentDouble + 10), for: uuid) + alertService.register( + type: .relativeHumidity( + lower: randomPercentDouble, + upper: randomPercentDouble + 10 + ), + for: uuid + ) let fakeDelegate = MockAlertServiceObserver() alertService.subscribe(fakeDelegate, to: uuid) @@ -575,7 +611,13 @@ class AlertServiceSpec: QuickSpec { expect(localNotificationManager.type).toEventually(equal(LowHighNotificationType.relativeHumidity)) } it("if greather") { - alertService.register(type: .relativeHumidity(lower: randomPercentDouble - 10, upper: randomPercentDouble), for: uuid) + alertService.register( + type: .relativeHumidity( + lower: randomPercentDouble - 10, + upper: randomPercentDouble + ), + for: uuid + ) let fakeDelegate = MockAlertServiceObserver() alertService.subscribe(fakeDelegate, to: uuid) @@ -709,3 +751,5 @@ class AlertServiceSpec: QuickSpec { } } } + +// swiftlint:enable file_length diff --git a/stationTests/Services/MeasurementsService/MeasurementsServiceEnSpec.swift b/stationTests/Services/MeasurementsService/MeasurementsServiceEnSpec.swift index 0b666af32..e8b9d4f04 100644 --- a/stationTests/Services/MeasurementsService/MeasurementsServiceEnSpec.swift +++ b/stationTests/Services/MeasurementsService/MeasurementsServiceEnSpec.swift @@ -5,7 +5,9 @@ import XCTest @testable import station +// swiftlint:disable:next type_body_length class MeasurementsServiceEnSpec: QuickSpec { + // swiftlint:disable:next function_body_length override func spec() { let r = AppAssembly.shared.assembler.resolver var service: MeasurementsService! = r.resolve(MeasurementsService.self) diff --git a/stationTests/Services/MeasurementsService/MeasurementsServiceFiSpec.swift b/stationTests/Services/MeasurementsService/MeasurementsServiceFiSpec.swift index 808af29e9..7b5192633 100644 --- a/stationTests/Services/MeasurementsService/MeasurementsServiceFiSpec.swift +++ b/stationTests/Services/MeasurementsService/MeasurementsServiceFiSpec.swift @@ -5,7 +5,9 @@ import XCTest @testable import station +// swiftlint:disable:next type_body_length class MeasurementsServiceFiSpec: QuickSpec { + // swiftlint:disable:next function_body_length override func spec() { let r = AppAssembly.shared.assembler.resolver var service: MeasurementsService! = r.resolve(MeasurementsService.self) diff --git a/stationTests/Services/MeasurementsService/MeasurementsServiceRuSpec.swift b/stationTests/Services/MeasurementsService/MeasurementsServiceRuSpec.swift index 12a68a06e..c25fb58da 100644 --- a/stationTests/Services/MeasurementsService/MeasurementsServiceRuSpec.swift +++ b/stationTests/Services/MeasurementsService/MeasurementsServiceRuSpec.swift @@ -5,7 +5,9 @@ import XCTest @testable import station +// swiftlint:disable:next type_body_length class MeasurementsServiceRuSpec: QuickSpec { + // swiftlint:disable:next function_body_length override func spec() { let r = AppAssembly.shared.assembler.resolver var service: MeasurementsService! = r.resolve(MeasurementsService.self) diff --git a/stationTests/Services/MeasurementsService/MeasurementsServiceSvSpec.swift b/stationTests/Services/MeasurementsService/MeasurementsServiceSvSpec.swift index a95f89ce9..52d136525 100644 --- a/stationTests/Services/MeasurementsService/MeasurementsServiceSvSpec.swift +++ b/stationTests/Services/MeasurementsService/MeasurementsServiceSvSpec.swift @@ -5,7 +5,9 @@ import XCTest @testable import station +// swiftlint:disable:next type_body_length class MeasurementsServiceSvSpec: QuickSpec { + // swiftlint:disable:next function_body_length override func spec() { let r = AppAssembly.shared.assembler.resolver var service: MeasurementsService! = r.resolve(MeasurementsService.self) diff --git a/swiftgen.yml b/swiftgen.yml index 0752caad9..826a8779c 100644 --- a/swiftgen.yml +++ b/swiftgen.yml @@ -24,11 +24,11 @@ json: - templatePath: ./Common/RuuviLocalization/Templates/Localizable_de.strings.stencil output: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/de.lproj/Localizable.strings strings: - inputs: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings - outputs: - templateName: structured-swift5 - params: - forceProvidesNamespaces: true - publicAccess: true - enumName: RuuviLocalization - output: ./Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift \ No newline at end of file + - inputs: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings + outputs: + - templatePath: ./Common/RuuviLocalization/Templates/structured-swift5.stencil + output: ./Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift + params: + forceProvidesNamespaces: true + publicAccess: true + enumName: RuuviLocalization \ No newline at end of file From 37679904084c67c0b91c89b7bd1da4de50011a1a Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sun, 10 Dec 2023 23:37:34 +0200 Subject: [PATCH 36/84] Disable Lint script dependency analysis (#1765) to fix warning --- project_frameworks.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/project_frameworks.yml b/project_frameworks.yml index 6ea423bcf..1a0d5613b 100644 --- a/project_frameworks.yml +++ b/project_frameworks.yml @@ -325,8 +325,7 @@ targets: postCompileScripts: - path: scripts/build/lint.sh name: Lint - BASED_ON_DEPENDENCY_ANALYSIS: false - ENABLE_USER_SCRIPT_SANDBOXING: false + basedOnDependencyAnalysis: false postBuildScripts: - path: scripts/build/load_keystore.sh name: Load Keystore From ace2482d84e55ab523e0b9c1e159b597d93e83fe Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Mon, 11 Dec 2023 22:14:37 +0200 Subject: [PATCH 37/84] Add pr_checks GitHub Actions workflow (#1766) * Add pr_checks GitHub Actions workflow Implements linter checks on the PR. * lint whole project * fix swiftlint artificial violation --- .github/workflows/pr_checks.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/workflows/pr_checks.yml diff --git a/.github/workflows/pr_checks.yml b/.github/workflows/pr_checks.yml new file mode 100644 index 000000000..4d553ce67 --- /dev/null +++ b/.github/workflows/pr_checks.yml @@ -0,0 +1,16 @@ +name: Checks for opened PR + +on: + pull_request: + types: [opened, synchronize] + +jobs: + swiftlint: + runs-on: ubuntu-latest + name: SwiftLint + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Lint + uses: norio-nomura/action-swiftlint@3.2.1 From 95cc3797f133d02e83f2b7287c37274a363b5cdb Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Tue, 12 Dec 2023 18:46:13 +0100 Subject: [PATCH 38/84] fix: Show cloud connection alert for only users with pro+ plans #1750 --- .../Modules/TagSettings/Presenter/TagSettingsPresenter.swift | 5 +++++ .../Modules/TagSettings/View/TagSettingsViewModel.swift | 1 + .../TagSettings/View/UI/TagSettingsViewController.swift | 4 ++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift index ef789a61f..c04c5432f 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift @@ -559,6 +559,11 @@ extension TagSettingsPresenter { ruuviTag.ownersPlan?.lowercased() != "basic" && ruuviTag.ownersPlan?.lowercased() != "free" + viewModel.isCloudConnectionAlertsAvailable.value = + ruuviUser.isAuthorized && + ruuviTag.isCloud && + viewModel.isOwnersPlanProPlus.value ?? false + if ruuviTag.name == ruuviTag.luid?.value || ruuviTag.name == ruuviTag.macId?.value, !ruuviTag.isCloud { diff --git a/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift b/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift index 5ea259b62..46783e276 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift @@ -94,6 +94,7 @@ struct TagSettingsViewModel { let isAlertsEnabled: Observable = .init(false) let isPNAlertsAvailiable: Observable = .init(false) let isCloudAlertsAvailable: Observable = .init(false) + let isCloudConnectionAlertsAvailable: Observable = .init(false) var source: Observable = .init() diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift index 8c4e3b12f..763ce9153 100644 --- a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift +++ b/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift @@ -1375,7 +1375,7 @@ extension TagSettingsViewController { } // Cloud Connection - tableView.bind(viewModel.isOwnersPlanProPlus) { + tableView.bind(viewModel.isCloudConnectionAlertsAvailable) { [weak self] _, _ in self?.reloadSection(identifier: .alertCloudConnection) } @@ -2122,7 +2122,7 @@ extension TagSettingsViewController { // Cloud Connection private func cloudConnectionAlertVisible() -> Bool { - viewModel?.isOwnersPlanProPlus.value ?? false + viewModel?.isCloudConnectionAlertsAvailable.value ?? false } private func cloudConnectionAlertRangeDescription( From 471917947a77a30c1509a129e6f1a7831f08e55c Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Tue, 12 Dec 2023 21:13:24 +0200 Subject: [PATCH 39/84] Remove Pods and SPM projects (#1768) Removes Pods xcodeworkspace and SPM yml files. Motivation: not used --- .github/workflows/firebase_frameworks.yml | 4 +- Gemfile | 3 - Gemfile.lock | 131 +- Makefile | 26 +- Podfile | 190 - Podfile.lock | 796 -- fastlane/Fastfile | 12 - intents_frameworks.yml => intents.yml | 0 intents_spm.yml | 60 - project_frameworks.yml => project.yml | 4 +- project_spm.yml | 293 - station.xcodeproj/project.pbxproj | 6911 ----------------- .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - station.xcworkspace/contents.xcworkspacedata | 44 - .../xcshareddata/IDETemplateMacros.plist | 14 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/WorkspaceSettings.xcsettings | 10 - .../xcshareddata/xcschemes/station.xcscheme | 108 - .../xcschemes/station_dev.xcscheme | 84 - .../xcschemes/station_intents.xcscheme | 97 - .../xcschemes/station_widgets.xcscheme | 124 - widget_frameworks.yml => widget.yml | 0 widget_spm.yml | 56 - 24 files changed, 40 insertions(+), 8950 deletions(-) delete mode 100644 Podfile delete mode 100644 Podfile.lock rename intents_frameworks.yml => intents.yml (100%) delete mode 100644 intents_spm.yml rename project_frameworks.yml => project.yml (99%) delete mode 100644 project_spm.yml delete mode 100644 station.xcodeproj/project.pbxproj delete mode 100755 station.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100755 station.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 station.xcworkspace/contents.xcworkspacedata delete mode 100644 station.xcworkspace/xcshareddata/IDETemplateMacros.plist delete mode 100644 station.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 station.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings delete mode 100644 station.xcworkspace/xcshareddata/xcschemes/station.xcscheme delete mode 100644 station.xcworkspace/xcshareddata/xcschemes/station_dev.xcscheme delete mode 100644 station.xcworkspace/xcshareddata/xcschemes/station_intents.xcscheme delete mode 100644 station.xcworkspace/xcshareddata/xcschemes/station_widgets.xcscheme rename widget_frameworks.yml => widget.yml (100%) delete mode 100644 widget_spm.yml diff --git a/.github/workflows/firebase_frameworks.yml b/.github/workflows/firebase_frameworks.yml index d5e3013f7..cebbc12c2 100644 --- a/.github/workflows/firebase_frameworks.yml +++ b/.github/workflows/firebase_frameworks.yml @@ -56,7 +56,7 @@ jobs: - name: Increment build number run: | - make set_build_number_frameworks + make set_build_number - name: Tools cache uses: actions/cache@v2 @@ -68,7 +68,7 @@ jobs: - name: Make xcodeproj run: | - make xcodeproj_with_frameworks + make xcodeproj - name: SPM Cache uses: actions/cache@v2 diff --git a/Gemfile b/Gemfile index b14d63467..cdd3a6b34 100644 --- a/Gemfile +++ b/Gemfile @@ -1,9 +1,6 @@ source "https://rubygems.org" gem "fastlane" -gem "cocoapods", '1.12.1' plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') eval_gemfile(plugins_path) if File.exist?(plugins_path) - -gem "i18n", "~> 1.8" diff --git a/Gemfile.lock b/Gemfile.lock index 666875c0f..03a3425b8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,89 +3,39 @@ GEM specs: CFPropertyList (3.0.6) rexml - activesupport (7.0.8) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 1.6, < 2) - minitest (>= 5.1) - tzinfo (~> 2.0) - addressable (2.8.5) + addressable (2.8.6) public_suffix (>= 2.0.2, < 6.0) - algoliasearch (1.27.5) - httpclient (~> 2.8, >= 2.8.3) - json (>= 1.5.1) artifactory (3.0.15) atomos (0.1.3) - aws-eventstream (1.2.0) - aws-partitions (1.826.0) - aws-sdk-core (3.183.0) - aws-eventstream (~> 1, >= 1.0.2) + aws-eventstream (1.3.0) + aws-partitions (1.864.0) + aws-sdk-core (3.190.0) + aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) - aws-sigv4 (~> 1.5) + aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.71.0) - aws-sdk-core (~> 3, >= 3.177.0) + aws-sdk-kms (1.74.0) + aws-sdk-core (~> 3, >= 3.188.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.135.0) - aws-sdk-core (~> 3, >= 3.181.0) + aws-sdk-s3 (1.141.0) + aws-sdk-core (~> 3, >= 3.189.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.6) - aws-sigv4 (1.6.0) + aws-sigv4 (~> 1.8) + aws-sigv4 (1.8.0) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) claide (1.1.0) - cocoapods (1.12.1) - addressable (~> 2.8) - claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.12.1) - cocoapods-deintegrate (>= 1.0.3, < 2.0) - cocoapods-downloader (>= 1.6.0, < 2.0) - cocoapods-plugins (>= 1.0.0, < 2.0) - cocoapods-search (>= 1.0.0, < 2.0) - cocoapods-trunk (>= 1.6.0, < 2.0) - cocoapods-try (>= 1.1.0, < 2.0) - colored2 (~> 3.1) - escape (~> 0.0.4) - fourflusher (>= 2.3.0, < 3.0) - gh_inspector (~> 1.0) - molinillo (~> 0.8.0) - nap (~> 1.0) - ruby-macho (>= 2.3.0, < 3.0) - xcodeproj (>= 1.21.0, < 2.0) - cocoapods-core (1.12.1) - activesupport (>= 5.0, < 8) - addressable (~> 2.8) - algoliasearch (~> 1.0) - concurrent-ruby (~> 1.1) - fuzzy_match (~> 2.0.4) - nap (~> 1.0) - netrc (~> 0.11) - public_suffix (~> 4.0) - typhoeus (~> 1.0) - cocoapods-deintegrate (1.0.5) - cocoapods-downloader (1.6.3) - cocoapods-plugins (1.0.0) - nap - cocoapods-search (1.0.1) - cocoapods-trunk (1.6.0) - nap (>= 0.8, < 2.0) - netrc (~> 0.11) - cocoapods-try (1.2.0) colored (1.2) colored2 (3.1.2) commander (4.6.0) highline (~> 2.0.0) - concurrent-ruby (1.2.2) declarative (0.0.20) digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) - domain_name (0.5.20190701) - unf (>= 0.0.5, < 1.0.0) + domain_name (0.6.20231109) dotenv (2.8.1) emoji_regex (3.2.3) - escape (0.0.4) - ethon (0.16.0) - ffi (>= 1.15.0) - excon (0.103.0) + excon (0.105.0) faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -115,7 +65,7 @@ GEM faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.2.7) - fastlane (2.216.0) + fastlane (2.217.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -155,15 +105,12 @@ GEM xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) - fastlane-plugin-firebase_app_distribution (0.7.3) + fastlane-plugin-firebase_app_distribution (0.7.4) google-apis-firebaseappdistribution_v1 (~> 0.3.0) - ffi (1.15.5) - fourflusher (2.3.1) - fuzzy_match (2.0.4) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.49.0) + google-apis-androidpublisher_v3 (0.53.0) google-apis-core (>= 0.11.0, < 2.a) - google-apis-core (0.11.1) + google-apis-core (0.11.2) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -178,19 +125,19 @@ GEM google-apis-core (>= 0.11.0, < 2.a) google-apis-playcustomapp_v1 (0.13.0) google-apis-core (>= 0.11.0, < 2.a) - google-apis-storage_v1 (0.19.0) - google-apis-core (>= 0.9.0, < 2.a) - google-cloud-core (1.6.0) - google-cloud-env (~> 1.0) + google-apis-storage_v1 (0.29.0) + google-apis-core (>= 0.11.0, < 2.a) + google-cloud-core (1.6.1) + google-cloud-env (>= 1.0, < 3.a) google-cloud-errors (~> 1.0) - google-cloud-env (1.6.0) - faraday (>= 0.17.3, < 3.0) + google-cloud-env (2.1.0) + faraday (>= 1.0, < 3.a) google-cloud-errors (1.3.1) - google-cloud-storage (1.44.0) + google-cloud-storage (1.45.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.19.0) + google-apis-storage_v1 (~> 0.29.0) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) @@ -204,26 +151,20 @@ GEM http-cookie (1.0.5) domain_name (~> 0.5) httpclient (2.8.3) - i18n (1.14.1) - concurrent-ruby (~> 1.0) jmespath (1.6.2) - json (2.6.3) + json (2.7.1) jwt (2.7.1) mini_magick (4.12.0) mini_mime (1.1.5) - minitest (5.20.0) - molinillo (0.8.0) multi_json (1.15.0) multipart-post (2.3.0) nanaimo (0.3.0) - nap (1.1.0) naturally (2.2.1) - netrc (0.11.0) optparse (0.1.1) os (1.1.4) plist (3.7.0) - public_suffix (4.0.7) - rake (13.0.6) + public_suffix (5.0.4) + rake (13.1.0) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) @@ -231,7 +172,6 @@ GEM retriable (3.1.2) rexml (3.2.6) rouge (2.0.7) - ruby-macho (2.5.1) ruby2_keywords (0.0.5) rubyzip (2.3.2) security (0.1.3) @@ -251,18 +191,11 @@ GEM tty-screen (0.8.1) tty-spinner (0.9.3) tty-cursor (~> 0.7) - typhoeus (1.4.0) - ethon (>= 0.9.0) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) uber (0.1.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.8.2) - unicode-display_width (2.4.2) + unicode-display_width (2.5.0) webrick (1.8.1) word_wrap (1.0.0) - xcodeproj (1.22.0) + xcodeproj (1.23.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) @@ -278,10 +211,8 @@ PLATFORMS ruby DEPENDENCIES - cocoapods (= 1.12.1) fastlane fastlane-plugin-firebase_app_distribution - i18n (~> 1.8) BUNDLED WITH 2.4.13 diff --git a/Makefile b/Makefile index b0ea02ca2..d1f3cfaea 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ .PHONY: installed_xcodegen installed_swiftgen installed_swiftlint installed_firebase # generates xcodeproj for frameworks build configuration -xcodeproj_with_frameworks: installed_xcodegen installed_swiftgen installed_swiftlint - .tools/xcodegen/bin/xcodegen -s project_frameworks.yml +xcodeproj: installed_xcodegen installed_swiftgen installed_swiftlint + .tools/xcodegen/bin/xcodegen -s project.yml # install firebase installed_firebase: .tools/firebase/firebase @@ -33,28 +33,12 @@ installed_xcodegen: .tools/xcodegen/bin/xcodegen scripts/install/install_xcodegen.sh touch $@ -# generates xcodeproj for swift package manager build configuration -xcodeproj_with_spm: installed_xcodegen installed_swiftgen installed_swiftlint - .tools/xcodegen/bin/xcodegen -s project_spm.yml - # builds station target with frameworks build configuration for iOS -build_with_frameworks: +build: d=$$(date +%s)\ ; xcodebuild -project frameworks.xcodeproj -scheme station -configuration Release -sdk iphoneos17.0 build\ && echo "Build took $$(($$(date +%s)-d)) seconds" -# builds station target with swift package manager build configuration for iOS -build_with_spm: - d=$$(date +%s)\ - ; xcodebuild -project spm.xcodeproj -scheme station -configuration Release -sdk iphoneos17.0 build\ - && echo "Build took $$(($$(date +%s)-d)) seconds" - -# builds station target with development pods build configuration for iOS -build_with_pods: - d=$$(date +%s)\ - ; xcodebuild -workspace station.xcworkspace -scheme station -configuration Release -sdk iphoneos17.0 build\ - && echo "Build took $$(($$(date +%s)-d)) seconds" - # sets the build number to current datetime -set_build_number_frameworks: - scripts/build/set_build_number.sh project_frameworks.yml \ No newline at end of file +set_build_number: + scripts/build/set_build_number.sh project.yml \ No newline at end of file diff --git a/Podfile b/Podfile deleted file mode 100644 index 1b94e8bec..000000000 --- a/Podfile +++ /dev/null @@ -1,190 +0,0 @@ -platform :ios, '13.0' -project 'station.xcodeproj' -use_frameworks! -inhibit_all_warnings! - -install! 'cocoapods', :disable_input_output_paths => true - -def ruuvi_ontology - pod 'RuuviOntology', :path => 'Packages/RuuviOntology/RuuviOntology.podspec' - pod 'RuuviOntology/Contract', :path => 'Packages/RuuviOntology/RuuviOntology.podspec' - pod 'RuuviOntology/SQLite', :path => 'Packages/RuuviOntology/RuuviOntology.podspec' - pod 'RuuviOntology/Realm', :path => 'Packages/RuuviOntology/RuuviOntology.podspec' -end - -def shared_pods - pod 'BTKit', :git => 'https://github.com/ruuvi/BTKit.git' - pod 'Firebase' - pod 'Firebase/Messaging' - pod 'Firebase/Analytics' - pod 'Firebase/Crashlytics' - pod 'Firebase/RemoteConfig' - pod 'Firebase/InAppMessaging' - pod 'FutureX' - pod 'GestureInstructions' - pod 'GRDB.swift', '~> 4.14.0' - pod 'Humidity', :git => 'https://github.com/rinat-enikeev/Humidity.git' - pod 'LightRoute', :git => 'https://github.com/rinat-enikeev/LightRoute.git' - pod 'Nantes' - pod 'RangeSeekSlider', :git => 'https://github.com/rinat-enikeev/RangeSeekSlider' - pod 'Realm' - pod 'RealmSwift', '~> 10.33.0' - # common - pod 'RuuviPresenters', :path => 'Common/RuuviPresenters/RuuviPresenters.podspec', :testspecs => ['Tests'] - pod 'RuuviLocalization', :path => 'Common/RuuviLocalization/RuuviLocalization.podspec', :testspecs => ['Tests'] - # modules - pod 'RuuviDiscover', :path => 'Modules/RuuviDiscover/RuuviDiscover.podspec', :testspecs => ['Tests'] - pod 'RuuviOnboard', :path => 'Modules/RuuviOnboard/RuuviOnboard.podspec', :testspecs => ['Tests'] - # packages - pod 'RuuviAnalytics', :path => 'Packages/RuuviAnalytics/RuuviAnalytics.podspec', :testspecs => ['Tests'] - pod 'RuuviAnalytics/Impl', :path => 'Packages/RuuviAnalytics/RuuviAnalytics.podspec' - pod 'RuuviContext', :path => 'Packages/RuuviContext/RuuviContext.podspec' - pod 'RuuviCore', :path => 'Packages/RuuviCore/RuuviCore.podspec', :testspecs => ['Tests'] - pod 'RuuviCore/Image', :path => 'Packages/RuuviCore/RuuviCore.podspec' - pod 'RuuviCore/Location', :path => 'Packages/RuuviCore/RuuviCore.podspec' - pod 'RuuviCore/Diff', :path => 'Packages/RuuviCore/RuuviCore.podspec' - pod 'RuuviCore/PN', :path => 'Packages/RuuviCore/RuuviCore.podspec' - pod 'RuuviCore/Permission', :path => 'Packages/RuuviCore/RuuviCore.podspec' - pod 'RuuviCloud', :path => 'Packages/RuuviCloud/RuuviCloud.podspec', :testspecs => ['Tests'] - pod 'RuuviCloud/Pure', :path => 'Packages/RuuviCloud/RuuviCloud.podspec' - pod 'RuuviCloud/Api', :path => 'Packages/RuuviCloud/RuuviCloud.podspec' - pod 'RuuviDFU', :path => 'Packages/RuuviDFU/RuuviDFU.podspec', :testspecs => ['Tests'] - pod 'RuuviDFU/Impl', :path => 'Packages/RuuviDFU/RuuviDFU.podspec' - pod 'RuuviDaemon', :path => 'Packages/RuuviDaemon/RuuviDaemon.podspec', :testspecs => ['Tests'] - pod 'RuuviDaemon/CloudSync', :path => 'Packages/RuuviDaemon/RuuviDaemon.podspec' - pod 'RuuviDaemon/Operation', :path => 'Packages/RuuviDaemon/RuuviDaemon.podspec' - pod 'RuuviDaemon/RuuviTag', :path => 'Packages/RuuviDaemon/RuuviDaemon.podspec' - pod 'RuuviDaemon/VirtualTag', :path => 'Packages/RuuviDaemon/RuuviDaemon.podspec' - pod 'RuuviDaemon/Background', :path => 'Packages/RuuviDaemon/RuuviDaemon.podspec' - pod 'RuuviLocal/UserDefaults', :path => 'Packages/RuuviLocal/RuuviLocal.podspec' - pod 'RuuviNotification', :path => 'Packages/RuuviNotification/RuuviNotification.podspec', :testspecs => ['Tests'] - pod 'RuuviNotification/Local', :path => 'Packages/RuuviNotification/RuuviNotification.podspec' - pod 'RuuviNotifier', :path => 'Packages/RuuviNotifier/RuuviNotifier.podspec', :testspecs => ['Tests'] - pod 'RuuviNotifier/Impl', :path => 'Packages/RuuviNotifier/RuuviNotifier.podspec' - pod 'RuuviMigration', :path => 'Packages/RuuviMigration/RuuviMigration.podspec', :testspecs => ['Tests'] - pod 'RuuviMigration/Impl', :path => 'Packages/RuuviMigration/RuuviMigration.podspec' - pod 'RuuviPersistence', :path => 'Packages/RuuviPersistence/RuuviPersistence.podspec', :testspecs => ['Tests'] - pod 'RuuviReactor', :path => 'Packages/RuuviReactor/RuuviReactor.podspec', :testspecs => ['Tests'] - pod 'RuuviReactor/Impl', :path => 'Packages/RuuviReactor/RuuviReactor.podspec' - pod 'RuuviStorage', :path => 'Packages/RuuviStorage/RuuviStorage.podspec', :testspecs => ['Tests'] - pod 'RuuviStorage/Coordinator', :path => 'Packages/RuuviStorage/RuuviStorage.podspec' - pod 'RuuviService', :path => 'Packages/RuuviService/RuuviService.podspec', :testspecs => ['Tests'] - pod 'RuuviService/Factory', :path => 'Packages/RuuviService/RuuviService.podspec' - pod 'RuuviService/Auth', :path => 'Packages/RuuviService/RuuviService.podspec' - pod 'RuuviService/CloudSync', :path => 'Packages/RuuviService/RuuviService.podspec' - pod 'RuuviService/Ownership', :path => 'Packages/RuuviService/RuuviService.podspec' - pod 'RuuviService/SensorProperties', :path => 'Packages/RuuviService/RuuviService.podspec' - pod 'RuuviService/SensorRecords', :path => 'Packages/RuuviService/RuuviService.podspec' - pod 'RuuviService/AppSettings', :path => 'Packages/RuuviService/RuuviService.podspec' - pod 'RuuviService/OffsetCalibration', :path => 'Packages/RuuviService/RuuviService.podspec' - pod 'RuuviService/Alert', :path => 'Packages/RuuviService/RuuviService.podspec' - pod 'RuuviService/Measurement', :path => 'Packages/RuuviService/RuuviService.podspec' - pod 'RuuviService/Export', :path => 'Packages/RuuviService/RuuviService.podspec' - pod 'RuuviService/GATT', :path => 'Packages/RuuviService/RuuviService.podspec' - pod 'RuuviService/CloudNotification', :path => 'Packages/RuuviService/RuuviService.podspec' - pod 'RuuviPool', :path => 'Packages/RuuviPool/RuuviPool.podspec', :testspecs => ['Tests'] - pod 'RuuviPool/Coordinator', :path => 'Packages/RuuviPool/RuuviPool.podspec' - pod 'RuuviRepository', :path => 'Packages/RuuviRepository/RuuviRepository.podspec', :testspecs => ['Tests'] - pod 'RuuviRepository/Coordinator', :path => 'Packages/RuuviRepository/RuuviRepository.podspec' - pod 'RuuviUser', :path => 'Packages/RuuviUser/RuuviUser.podspec', :testspecs => ['Tests'] - pod 'RuuviUser/Coordinator', :path => 'Packages/RuuviUser/RuuviUser.podspec' - pod 'Swinject' - pod 'SwiftGen', '~> 6.0' - pod 'KeychainAccess' - pod 'iOSDFULibrary' -end - -def widget_pods - pod 'Swinject' - pod 'BTKit', :git => 'https://github.com/ruuvi/BTKit.git' - pod 'FutureX' - pod 'GRDB.swift', '~> 4.14.0' - pod 'Humidity', :git => 'https://github.com/rinat-enikeev/Humidity.git' - pod 'Realm' - pod 'RealmSwift', '~> 10.33.0' - pod 'RuuviUser', :path => 'Packages/RuuviUser/RuuviUser.podspec', :testspecs => ['Tests'] - pod 'RuuviUser/Coordinator', :path => 'Packages/RuuviUser/RuuviUser.podspec' - pod 'RuuviCloud', :path => 'Packages/RuuviCloud/RuuviCloud.podspec', :testspecs => ['Tests'] - pod 'RuuviCloud/Pure', :path => 'Packages/RuuviCloud/RuuviCloud.podspec' - pod 'KeychainAccess' - pod 'RuuviPool', :path => 'Packages/RuuviPool/RuuviPool.podspec', :testspecs => ['Tests'] - pod 'RuuviPool/Coordinator', :path => 'Packages/RuuviPool/RuuviPool.podspec' - pod 'RuuviLocal/UserDefaults', :path => 'Packages/RuuviLocal/RuuviLocal.podspec' - pod 'RuuviPersistence', :path => 'Packages/RuuviPersistence/RuuviPersistence.podspec', :testspecs => ['Tests'] - pod 'RuuviContext', :path => 'Packages/RuuviContext/RuuviContext.podspec' -end - -target 'station' do - ruuvi_ontology - shared_pods -end - -target 'station_dev' do - ruuvi_ontology - shared_pods - pod 'FLEX', :configurations => ['Debug'] -end - -target 'station_widgets' do - ruuvi_ontology - widget_pods -end - -target 'station_intents' do - ruuvi_ontology - widget_pods -end - -target 'stationTests' do - ruuvi_ontology - shared_pods - pod 'Nimble' - pod 'Quick' -end - -# Fix Xcode 14 warnings like: -# warning: Run script build phase '[CP] Copy XCFrameworks' will be run during every build because it does not specify any outputs. To address this warning, either add output dependencies to the script phase, or configure it to run in every build by unchecking "Based on dependency analysis" in the script phase. (in target 'ATargetNameHere' from project 'YourProjectName') -# Ref.: https://github.com/CocoaPods/CocoaPods/issues/11444 -def set_run_script_to_always_run_when_no_input_or_output_files_exist(project:) - project.targets.each do |target| - run_script_build_phases = target.build_phases.filter { |phase| phase.is_a?(Xcodeproj::Project::Object::PBXShellScriptBuildPhase) } - cocoapods_run_script_build_phases = run_script_build_phases.filter { |phase| phase.name.start_with?("[CP") } - cocoapods_run_script_build_phases.each do |run_script| - next unless (run_script.input_paths || []).empty? && (run_script.output_paths || []).empty? - run_script.always_out_of_date = "1" - end - end - project.save -end - -post_install do |installer| - installer.pods_project.targets.each do |target| - target.build_configurations.each do |config| - if config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'].to_f < 13.0 - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0' - config.build_settings['GCC_WARN_INHIBIT_ALL_WARNINGS'] = "YES" - config.build_settings['SWIFT_SUPPRESS_WARNINGS'] = "YES" - config.build_settings["DEVELOPMENT_TEAM"] = "4MUYJ4YYH4" - # Need these for Xcode 16 Beta 6 - xcconfig_path = config.base_configuration_reference.real_path - xcconfig = File.read(xcconfig_path) - xcconfig_mod = xcconfig.gsub(/DT_TOOLCHAIN_DIR/, "TOOLCHAIN_DIR") - File.open(xcconfig_path, "w") { |file| file << xcconfig_mod } - # End patch for Xcode 15 Beta 6 - end - end - # This is specifically for Realm - if target.name == 'Realm' - create_symlink_phase = target.shell_script_build_phases.find { |x| x.name == 'Create Symlinks to Header Folders' } - create_symlink_phase.always_out_of_date = "1" - end - # End Realm patch - end - set_run_script_to_always_run_when_no_input_or_output_files_exist(project: installer.pods_project) -end - -post_integrate do |installer| - main_project = installer.aggregate_targets[0].user_project - set_run_script_to_always_run_when_no_input_or_output_files_exist(project: main_project) -end - diff --git a/Podfile.lock b/Podfile.lock deleted file mode 100644 index c55c2f9cc..000000000 --- a/Podfile.lock +++ /dev/null @@ -1,796 +0,0 @@ -PODS: - - BTKit (0.4.4) - - Firebase (10.7.0): - - Firebase/Core (= 10.7.0) - - Firebase/Analytics (10.7.0): - - Firebase/Core - - Firebase/Core (10.7.0): - - Firebase/CoreOnly - - FirebaseAnalytics (~> 10.7.0) - - Firebase/CoreOnly (10.7.0): - - FirebaseCore (= 10.7.0) - - Firebase/Crashlytics (10.7.0): - - Firebase/CoreOnly - - FirebaseCrashlytics (~> 10.7.0) - - Firebase/InAppMessaging (10.7.0): - - Firebase/CoreOnly - - FirebaseInAppMessaging (~> 10.7.0-beta) - - Firebase/Messaging (10.7.0): - - Firebase/CoreOnly - - FirebaseMessaging (~> 10.7.0) - - Firebase/RemoteConfig (10.7.0): - - Firebase/CoreOnly - - FirebaseRemoteConfig (~> 10.7.0) - - FirebaseABTesting (10.7.0): - - FirebaseCore (~> 10.0) - - FirebaseAnalytics (10.7.0): - - FirebaseAnalytics/AdIdSupport (= 10.7.0) - - FirebaseCore (~> 10.0) - - FirebaseInstallations (~> 10.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.8) - - GoogleUtilities/MethodSwizzler (~> 7.8) - - GoogleUtilities/Network (~> 7.8) - - "GoogleUtilities/NSData+zlib (~> 7.8)" - - nanopb (< 2.30910.0, >= 2.30908.0) - - FirebaseAnalytics/AdIdSupport (10.7.0): - - FirebaseCore (~> 10.0) - - FirebaseInstallations (~> 10.0) - - GoogleAppMeasurement (= 10.7.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.8) - - GoogleUtilities/MethodSwizzler (~> 7.8) - - GoogleUtilities/Network (~> 7.8) - - "GoogleUtilities/NSData+zlib (~> 7.8)" - - nanopb (< 2.30910.0, >= 2.30908.0) - - FirebaseCore (10.7.0): - - FirebaseCoreInternal (~> 10.0) - - GoogleUtilities/Environment (~> 7.8) - - GoogleUtilities/Logger (~> 7.8) - - FirebaseCoreExtension (10.7.0): - - FirebaseCore (~> 10.0) - - FirebaseCoreInternal (10.7.0): - - "GoogleUtilities/NSData+zlib (~> 7.8)" - - FirebaseCrashlytics (10.7.0): - - FirebaseCore (~> 10.5) - - FirebaseInstallations (~> 10.0) - - FirebaseSessions (~> 10.5) - - GoogleDataTransport (~> 9.2) - - GoogleUtilities/Environment (~> 7.8) - - nanopb (< 2.30910.0, >= 2.30908.0) - - PromisesObjC (~> 2.1) - - FirebaseInAppMessaging (10.7.0-beta): - - FirebaseABTesting (~> 10.0) - - FirebaseCore (~> 10.0) - - FirebaseInstallations (~> 10.0) - - GoogleUtilities/Environment (~> 7.8) - - nanopb (< 2.30910.0, >= 2.30908.0) - - FirebaseInstallations (10.7.0): - - FirebaseCore (~> 10.0) - - GoogleUtilities/Environment (~> 7.8) - - GoogleUtilities/UserDefaults (~> 7.8) - - PromisesObjC (~> 2.1) - - FirebaseMessaging (10.7.0): - - FirebaseCore (~> 10.0) - - FirebaseInstallations (~> 10.0) - - GoogleDataTransport (~> 9.2) - - GoogleUtilities/AppDelegateSwizzler (~> 7.8) - - GoogleUtilities/Environment (~> 7.8) - - GoogleUtilities/Reachability (~> 7.8) - - GoogleUtilities/UserDefaults (~> 7.8) - - nanopb (< 2.30910.0, >= 2.30908.0) - - FirebaseRemoteConfig (10.7.0): - - FirebaseABTesting (~> 10.0) - - FirebaseCore (~> 10.0) - - FirebaseInstallations (~> 10.0) - - GoogleUtilities/Environment (~> 7.8) - - "GoogleUtilities/NSData+zlib (~> 7.8)" - - FirebaseSessions (10.7.0): - - FirebaseCore (~> 10.5) - - FirebaseCoreExtension (~> 10.0) - - FirebaseInstallations (~> 10.0) - - GoogleDataTransport (~> 9.2) - - GoogleUtilities/Environment (~> 7.10) - - nanopb (< 2.30910.0, >= 2.30908.0) - - PromisesSwift (~> 2.1) - - FLEX (5.22.10) - - FutureX (1.1.1) - - GestureInstructions (0.0.2) - - GoogleAppMeasurement (10.7.0): - - GoogleAppMeasurement/AdIdSupport (= 10.7.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.8) - - GoogleUtilities/MethodSwizzler (~> 7.8) - - GoogleUtilities/Network (~> 7.8) - - "GoogleUtilities/NSData+zlib (~> 7.8)" - - nanopb (< 2.30910.0, >= 2.30908.0) - - GoogleAppMeasurement/AdIdSupport (10.7.0): - - GoogleAppMeasurement/WithoutAdIdSupport (= 10.7.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.8) - - GoogleUtilities/MethodSwizzler (~> 7.8) - - GoogleUtilities/Network (~> 7.8) - - "GoogleUtilities/NSData+zlib (~> 7.8)" - - nanopb (< 2.30910.0, >= 2.30908.0) - - GoogleAppMeasurement/WithoutAdIdSupport (10.7.0): - - GoogleUtilities/AppDelegateSwizzler (~> 7.8) - - GoogleUtilities/MethodSwizzler (~> 7.8) - - GoogleUtilities/Network (~> 7.8) - - "GoogleUtilities/NSData+zlib (~> 7.8)" - - nanopb (< 2.30910.0, >= 2.30908.0) - - GoogleDataTransport (9.2.2): - - GoogleUtilities/Environment (~> 7.7) - - nanopb (< 2.30910.0, >= 2.30908.0) - - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/AppDelegateSwizzler (7.11.1): - - GoogleUtilities/Environment - - GoogleUtilities/Logger - - GoogleUtilities/Network - - GoogleUtilities/Environment (7.11.1): - - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/Logger (7.11.1): - - GoogleUtilities/Environment - - GoogleUtilities/MethodSwizzler (7.11.1): - - GoogleUtilities/Logger - - GoogleUtilities/Network (7.11.1): - - GoogleUtilities/Logger - - "GoogleUtilities/NSData+zlib" - - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (7.11.1)" - - GoogleUtilities/Reachability (7.11.1): - - GoogleUtilities/Logger - - GoogleUtilities/UserDefaults (7.11.1): - - GoogleUtilities/Logger - - GRDB.swift (4.14.0): - - GRDB.swift/standard (= 4.14.0) - - GRDB.swift/standard (4.14.0) - - Humidity (0.1.5) - - iOSDFULibrary (4.13.0): - - ZIPFoundation (= 0.9.11) - - KeychainAccess (4.2.2) - - LightRoute (2.2.2) - - nanopb (2.30909.0): - - nanopb/decode (= 2.30909.0) - - nanopb/encode (= 2.30909.0) - - nanopb/decode (2.30909.0) - - nanopb/encode (2.30909.0) - - Nantes (0.1.2) - - Nimble (11.2.2) - - PromisesObjC (2.2.0) - - PromisesSwift (2.2.0): - - PromisesObjC (= 2.2.0) - - Quick (6.1.0) - - RangeSeekSlider (1.8.2) - - Realm (10.33.0): - - Realm/Headers (= 10.33.0) - - Realm/Headers (10.33.0) - - RealmSwift (10.33.0): - - Realm (= 10.33.0) - - RuuviAnalytics (0.0.3): - - RuuviAnalytics/Contract (= 0.0.3) - - RuuviAnalytics/Contract (0.0.3) - - RuuviAnalytics/Impl (0.0.3): - - Firebase - - RuuviAnalytics/Contract - - RuuviLocal - - RuuviService/Alert - - RuuviStorage - - RuuviUser - - RuuviAnalytics/Tests (0.0.3) - - RuuviCloud (0.1.0): - - RuuviCloud/Contract (= 0.1.0) - - RuuviCloud/Api (0.1.0): - - BTKit - - FutureX - - RuuviCloud/Contract - - RuuviOntology - - RuuviOntology/Mappers - - RuuviPersistence - - RuuviPool - - RuuviCloud/Contract (0.1.0): - - FutureX - - RuuviOntology - - RuuviPersistence - - RuuviPool - - RuuviUser - - RuuviCloud/Pure (0.1.0): - - FutureX - - RuuviCloud/Api - - RuuviCloud/Contract - - RuuviOntology - - RuuviPersistence - - RuuviPool - - RuuviUser - - RuuviCloud/Tests (0.1.0) - - RuuviContext (0.0.1): - - RuuviContext/SQLite (= 0.0.1) - - RuuviContext/Contract (0.0.1) - - RuuviContext/Realm (0.0.1): - - Realm - - RealmSwift - - RuuviContext/Contract - - RuuviContext/SQLite (0.0.1): - - GRDB.swift - - RuuviContext/Contract - - RuuviOntology/SQLite - - RuuviCore (0.0.1): - - RuuviCore/Contract (= 0.0.1) - - RuuviCore/Contract (0.0.1): - - FutureX - - RuuviCore/Diff (0.0.1) - - RuuviCore/Image (0.0.1): - - FutureX - - RuuviCore/Contract - - RuuviCore/Location (0.0.1): - - RuuviCore/Contract - - RuuviCore/Permission (0.0.1): - - RuuviCore/Contract - - RuuviCore/PN (0.0.1): - - RuuviCore/Contract - - RuuviCore/Tests (0.0.1) - - RuuviDaemon (0.0.1): - - RuuviDaemon/Contract (= 0.0.1) - - RuuviDaemon/Background (0.0.1): - - RuuviDaemon/Contract - - RuuviDaemon/Operation - - RuuviDaemon/CloudSync (0.0.1): - - RuuviDaemon/Contract - - RuuviDaemon/Worker - - RuuviLocal - - RuuviService - - RuuviDaemon/Contract (0.0.1) - - RuuviDaemon/Operation (0.0.1): - - FutureX - - RuuviDaemon/Contract - - RuuviLocal - - RuuviNotifier - - RuuviOntology - - RuuviPool - - RuuviStorage - - RuuviDaemon/RuuviTag (0.0.1): - - BTKit - - RuuviDaemon/Contract - - RuuviLocal - - RuuviNotification - - RuuviNotifier - - RuuviOntology - - RuuviPersistence - - RuuviPool - - RuuviReactor - - RuuviService - - RuuviStorage - - RuuviDaemon/Tests (0.0.1) - - RuuviDaemon/VirtualTag (0.0.1): - - BTKit - - RuuviDaemon/Contract - - RuuviLocal - - RuuviNotifier - - RuuviOntology - - RuuviDaemon/Worker (0.0.1) - - RuuviDFU (0.0.1): - - RuuviDFU/Contract (= 0.0.1) - - RuuviDFU/Contract (0.0.1) - - RuuviDFU/Impl (0.0.1): - - iOSDFULibrary - - RuuviDFU/Tests (0.0.1) - - RuuviDiscover (0.0.2): - - RuuviDiscover/RuuviDiscover (= 0.0.2) - - RuuviDiscover/RuuviDiscover (0.0.2): - - BTKit - - RuuviContext - - RuuviCore - - RuuviLocal - - RuuviLocalization - - RuuviPresenters - - RuuviReactor - - RuuviService - - RuuviDiscover/Tests (0.0.2) - - RuuviLocal (0.0.3): - - RuuviLocal/Contract (= 0.0.3) - - RuuviLocal/Contract (0.0.3): - - FutureX - - RuuviOntology - - RuuviLocal/UserDefaults (0.0.3): - - FutureX - - RuuviLocal/Contract - - RuuviOntology - - RuuviLocalization (0.0.1): - - RuuviLocalization/RuuviLocalization (= 0.0.1) - - RuuviLocalization/RuuviLocalization (0.0.1) - - RuuviLocalization/Tests (0.0.1) - - RuuviMigration (0.0.1): - - RuuviMigration/Contract (= 0.0.1) - - RuuviMigration/Contract (0.0.1) - - RuuviMigration/Impl (0.0.1): - - RuuviContext - - RuuviLocal - - RuuviOntology - - RuuviService - - RuuviStorage - - RuuviMigration/Tests (0.0.1) - - RuuviNotification (0.0.2): - - RuuviNotification/Contract (= 0.0.2) - - RuuviNotification/Contract (0.0.2) - - RuuviNotification/Local (0.0.2): - - RuuviLocal - - RuuviNotification/Contract - - RuuviOntology - - RuuviService - - RuuviStorage - - RuuviNotification/Tests (0.0.2) - - RuuviNotifier (0.0.1): - - RuuviNotifier/Contract (= 0.0.1) - - RuuviNotifier/Contract (0.0.1) - - RuuviNotifier/Impl (0.0.1): - - RuuviNotification - - RuuviNotifier/Contract - - RuuviOntology - - RuuviNotifier/Tests (0.0.1) - - RuuviOnboard (0.0.4): - - RuuviOnboard/RuuviOnboard (= 0.0.4) - - RuuviOnboard/RuuviOnboard (0.0.4): - - RuuviUser - - RuuviOnboard/Tests (0.0.4) - - RuuviOntology (0.0.6): - - RuuviOntology/Contract (= 0.0.6) - - RuuviOntology/Contract (0.0.6): - - Humidity - - RuuviOntology/Mappers (0.0.6): - - BTKit - - Humidity - - RuuviOntology/Contract - - RuuviOntology/Realm (0.0.6): - - Humidity - - Realm - - RealmSwift (~> 10.33.0) - - RuuviOntology/Contract - - RuuviOntology/SQLite (0.0.6): - - GRDB.swift - - Humidity - - RuuviOntology/Contract - - RuuviPersistence (0.0.2): - - RuuviPersistence/Contract (= 0.0.2) - - RuuviPersistence/Contract (0.0.2): - - FutureX - - RuuviOntology - - RuuviPersistence/Realm (0.0.2): - - FutureX - - Realm - - RealmSwift (~> 10.33.0) - - RuuviContext/Realm - - RuuviOntology - - RuuviOntology/Realm - - RuuviPersistence/Contract - - RuuviPersistence/SQLite (0.0.2): - - FutureX - - GRDB.swift - - RuuviContext/SQLite - - RuuviOntology - - RuuviOntology/SQLite - - RuuviPersistence/Contract - - RuuviPersistence/Tests (0.0.2) - - RuuviPool (0.0.1): - - RuuviPool/Contract (= 0.0.1) - - RuuviPool/Contract (0.0.1): - - FutureX - - RuuviLocal - - RuuviOntology - - RuuviPersistence - - RuuviPool/Coordinator (0.0.1): - - FutureX - - RuuviLocal - - RuuviOntology - - RuuviPersistence - - RuuviPersistence/Realm - - RuuviPersistence/SQLite - - RuuviPool/Contract - - RuuviPool/Tests (0.0.1) - - RuuviPresenters (0.0.1): - - RuuviPresenters/RuuviPresenters (= 0.0.1) - - RuuviPresenters/RuuviPresenters (0.0.1) - - RuuviPresenters/Tests (0.0.1) - - RuuviReactor (0.0.1): - - RuuviReactor/Contract (= 0.0.1) - - RuuviReactor/Contract (0.0.1): - - RuuviOntology - - RuuviPersistence - - RuuviReactor/Impl (0.0.1): - - FutureX - - GRDB.swift - - RealmSwift - - RuuviContext - - RuuviOntology - - RuuviReactor/Tests (0.0.1) - - RuuviRepository (0.0.1): - - RuuviRepository/Contract (= 0.0.1) - - RuuviRepository/Contract (0.0.1): - - FutureX - - RuuviOntology - - RuuviRepository/Coordinator (0.0.1): - - FutureX - - RuuviOntology - - RuuviPool - - RuuviRepository/Contract - - RuuviStorage - - RuuviRepository/Tests (0.0.1) - - RuuviService (0.0.4): - - RuuviService/Contract (= 0.0.4) - - RuuviService/Alert (0.0.4): - - FutureX - - RuuviCloud - - RuuviOntology - - RuuviService/Contract - - RuuviService/AppSettings (0.0.4): - - FutureX - - RuuviCloud - - RuuviLocal - - RuuviOntology - - RuuviService/Contract - - RuuviService/Auth (0.0.4): - - FutureX - - RuuviService/Contract - - RuuviUser - - RuuviService/CloudNotification (0.0.4): - - FutureX - - RuuviCloud - - RuuviOntology - - RuuviPool - - RuuviService/Contract - - RuuviStorage - - RuuviUser - - RuuviService/CloudSync (0.0.4): - - FutureX - - RuuviCloud - - RuuviLocal - - RuuviOntology - - RuuviPool - - RuuviRepository - - RuuviService/Contract - - RuuviStorage - - RuuviService/Contract (0.0.4): - - FutureX - - RuuviOntology - - RuuviService/Export (0.0.4): - - FutureX - - Humidity - - RuuviOntology - - RuuviService/Contract - - RuuviStorage - - RuuviService/Factory (0.0.4): - - FutureX - - RuuviOntology - - RuuviService/Alert - - RuuviService/AppSettings - - RuuviService/CloudSync - - RuuviService/OffsetCalibration - - RuuviService/Ownership - - RuuviService/SensorProperties - - RuuviService/SensorRecords - - RuuviService/GATT (0.0.4): - - BTKit - - FutureX - - RuuviOntology - - RuuviPool - - RuuviService/Contract - - RuuviService/Measurement (0.0.4): - - RuuviLocal - - RuuviOntology - - RuuviService/Contract - - RuuviService/OffsetCalibration (0.0.4): - - FutureX - - RuuviCloud - - RuuviOntology - - RuuviPool - - RuuviService/Contract - - RuuviService/Ownership (0.0.4): - - FutureX - - RuuviCloud - - RuuviOntology - - RuuviPool - - RuuviService/Contract - - RuuviStorage - - RuuviUser - - RuuviService/SensorProperties (0.0.4): - - FutureX - - RuuviCloud - - RuuviCore - - RuuviOntology - - RuuviPool - - RuuviService/Contract - - RuuviStorage - - RuuviService/SensorRecords (0.0.4): - - FutureX - - RuuviLocal - - RuuviOntology - - RuuviPool - - RuuviService/Contract - - RuuviService/Tests (0.0.4) - - RuuviStorage (0.0.1): - - RuuviStorage/Contract (= 0.0.1) - - RuuviStorage/Contract (0.0.1): - - FutureX - - RuuviOntology - - RuuviStorage/Coordinator (0.0.1): - - FutureX - - RuuviOntology - - RuuviPersistence/Realm - - RuuviPersistence/SQLite - - RuuviStorage/Contract - - RuuviStorage/Tests (0.0.1) - - RuuviUser (0.0.1): - - RuuviUser/Contract (= 0.0.1) - - RuuviUser/Contract (0.0.1) - - RuuviUser/Coordinator (0.0.1): - - KeychainAccess - - RuuviUser/Contract - - RuuviUser/Tests (0.0.1) - - SwiftGen (6.6.2) - - Swinject (2.8.3) - - ZIPFoundation (0.9.11) - -DEPENDENCIES: - - BTKit (from `https://github.com/ruuvi/BTKit.git`) - - Firebase - - Firebase/Analytics - - Firebase/Crashlytics - - Firebase/InAppMessaging - - Firebase/Messaging - - Firebase/RemoteConfig - - FLEX - - FutureX - - GestureInstructions - - GRDB.swift (~> 4.14.0) - - Humidity (from `https://github.com/rinat-enikeev/Humidity.git`) - - iOSDFULibrary - - KeychainAccess - - LightRoute (from `https://github.com/rinat-enikeev/LightRoute.git`) - - Nantes - - Nimble - - Quick - - RangeSeekSlider (from `https://github.com/rinat-enikeev/RangeSeekSlider`) - - Realm - - RealmSwift (~> 10.33.0) - - RuuviAnalytics (from `Packages/RuuviAnalytics/RuuviAnalytics.podspec`) - - RuuviAnalytics/Impl (from `Packages/RuuviAnalytics/RuuviAnalytics.podspec`) - - RuuviAnalytics/Tests (from `Packages/RuuviAnalytics/RuuviAnalytics.podspec`) - - RuuviCloud (from `Packages/RuuviCloud/RuuviCloud.podspec`) - - RuuviCloud/Api (from `Packages/RuuviCloud/RuuviCloud.podspec`) - - RuuviCloud/Pure (from `Packages/RuuviCloud/RuuviCloud.podspec`) - - RuuviCloud/Tests (from `Packages/RuuviCloud/RuuviCloud.podspec`) - - RuuviContext (from `Packages/RuuviContext/RuuviContext.podspec`) - - RuuviCore (from `Packages/RuuviCore/RuuviCore.podspec`) - - RuuviCore/Diff (from `Packages/RuuviCore/RuuviCore.podspec`) - - RuuviCore/Image (from `Packages/RuuviCore/RuuviCore.podspec`) - - RuuviCore/Location (from `Packages/RuuviCore/RuuviCore.podspec`) - - RuuviCore/Permission (from `Packages/RuuviCore/RuuviCore.podspec`) - - RuuviCore/PN (from `Packages/RuuviCore/RuuviCore.podspec`) - - RuuviCore/Tests (from `Packages/RuuviCore/RuuviCore.podspec`) - - RuuviDaemon (from `Packages/RuuviDaemon/RuuviDaemon.podspec`) - - RuuviDaemon/Background (from `Packages/RuuviDaemon/RuuviDaemon.podspec`) - - RuuviDaemon/CloudSync (from `Packages/RuuviDaemon/RuuviDaemon.podspec`) - - RuuviDaemon/Operation (from `Packages/RuuviDaemon/RuuviDaemon.podspec`) - - RuuviDaemon/RuuviTag (from `Packages/RuuviDaemon/RuuviDaemon.podspec`) - - RuuviDaemon/Tests (from `Packages/RuuviDaemon/RuuviDaemon.podspec`) - - RuuviDaemon/VirtualTag (from `Packages/RuuviDaemon/RuuviDaemon.podspec`) - - RuuviDFU (from `Packages/RuuviDFU/RuuviDFU.podspec`) - - RuuviDFU/Impl (from `Packages/RuuviDFU/RuuviDFU.podspec`) - - RuuviDFU/Tests (from `Packages/RuuviDFU/RuuviDFU.podspec`) - - RuuviDiscover (from `Modules/RuuviDiscover/RuuviDiscover.podspec`) - - RuuviDiscover/Tests (from `Modules/RuuviDiscover/RuuviDiscover.podspec`) - - RuuviLocal/UserDefaults (from `Packages/RuuviLocal/RuuviLocal.podspec`) - - RuuviLocalization (from `Common/RuuviLocalization/RuuviLocalization.podspec`) - - RuuviLocalization/Tests (from `Common/RuuviLocalization/RuuviLocalization.podspec`) - - RuuviMigration (from `Packages/RuuviMigration/RuuviMigration.podspec`) - - RuuviMigration/Impl (from `Packages/RuuviMigration/RuuviMigration.podspec`) - - RuuviMigration/Tests (from `Packages/RuuviMigration/RuuviMigration.podspec`) - - RuuviNotification (from `Packages/RuuviNotification/RuuviNotification.podspec`) - - RuuviNotification/Local (from `Packages/RuuviNotification/RuuviNotification.podspec`) - - RuuviNotification/Tests (from `Packages/RuuviNotification/RuuviNotification.podspec`) - - RuuviNotifier (from `Packages/RuuviNotifier/RuuviNotifier.podspec`) - - RuuviNotifier/Impl (from `Packages/RuuviNotifier/RuuviNotifier.podspec`) - - RuuviNotifier/Tests (from `Packages/RuuviNotifier/RuuviNotifier.podspec`) - - RuuviOnboard (from `Modules/RuuviOnboard/RuuviOnboard.podspec`) - - RuuviOnboard/Tests (from `Modules/RuuviOnboard/RuuviOnboard.podspec`) - - RuuviOntology (from `Packages/RuuviOntology/RuuviOntology.podspec`) - - RuuviOntology/Contract (from `Packages/RuuviOntology/RuuviOntology.podspec`) - - RuuviOntology/Realm (from `Packages/RuuviOntology/RuuviOntology.podspec`) - - RuuviOntology/SQLite (from `Packages/RuuviOntology/RuuviOntology.podspec`) - - RuuviPersistence (from `Packages/RuuviPersistence/RuuviPersistence.podspec`) - - RuuviPersistence/Tests (from `Packages/RuuviPersistence/RuuviPersistence.podspec`) - - RuuviPool (from `Packages/RuuviPool/RuuviPool.podspec`) - - RuuviPool/Coordinator (from `Packages/RuuviPool/RuuviPool.podspec`) - - RuuviPool/Tests (from `Packages/RuuviPool/RuuviPool.podspec`) - - RuuviPresenters (from `Common/RuuviPresenters/RuuviPresenters.podspec`) - - RuuviPresenters/Tests (from `Common/RuuviPresenters/RuuviPresenters.podspec`) - - RuuviReactor (from `Packages/RuuviReactor/RuuviReactor.podspec`) - - RuuviReactor/Impl (from `Packages/RuuviReactor/RuuviReactor.podspec`) - - RuuviReactor/Tests (from `Packages/RuuviReactor/RuuviReactor.podspec`) - - RuuviRepository (from `Packages/RuuviRepository/RuuviRepository.podspec`) - - RuuviRepository/Coordinator (from `Packages/RuuviRepository/RuuviRepository.podspec`) - - RuuviRepository/Tests (from `Packages/RuuviRepository/RuuviRepository.podspec`) - - RuuviService (from `Packages/RuuviService/RuuviService.podspec`) - - RuuviService/Alert (from `Packages/RuuviService/RuuviService.podspec`) - - RuuviService/AppSettings (from `Packages/RuuviService/RuuviService.podspec`) - - RuuviService/Auth (from `Packages/RuuviService/RuuviService.podspec`) - - RuuviService/CloudNotification (from `Packages/RuuviService/RuuviService.podspec`) - - RuuviService/CloudSync (from `Packages/RuuviService/RuuviService.podspec`) - - RuuviService/Export (from `Packages/RuuviService/RuuviService.podspec`) - - RuuviService/Factory (from `Packages/RuuviService/RuuviService.podspec`) - - RuuviService/GATT (from `Packages/RuuviService/RuuviService.podspec`) - - RuuviService/Measurement (from `Packages/RuuviService/RuuviService.podspec`) - - RuuviService/OffsetCalibration (from `Packages/RuuviService/RuuviService.podspec`) - - RuuviService/Ownership (from `Packages/RuuviService/RuuviService.podspec`) - - RuuviService/SensorProperties (from `Packages/RuuviService/RuuviService.podspec`) - - RuuviService/SensorRecords (from `Packages/RuuviService/RuuviService.podspec`) - - RuuviService/Tests (from `Packages/RuuviService/RuuviService.podspec`) - - RuuviStorage (from `Packages/RuuviStorage/RuuviStorage.podspec`) - - RuuviStorage/Coordinator (from `Packages/RuuviStorage/RuuviStorage.podspec`) - - RuuviStorage/Tests (from `Packages/RuuviStorage/RuuviStorage.podspec`) - - RuuviUser (from `Packages/RuuviUser/RuuviUser.podspec`) - - RuuviUser/Coordinator (from `Packages/RuuviUser/RuuviUser.podspec`) - - RuuviUser/Tests (from `Packages/RuuviUser/RuuviUser.podspec`) - - SwiftGen (~> 6.0) - - Swinject - -SPEC REPOS: - trunk: - - Firebase - - FirebaseABTesting - - FirebaseAnalytics - - FirebaseCore - - FirebaseCoreExtension - - FirebaseCoreInternal - - FirebaseCrashlytics - - FirebaseInAppMessaging - - FirebaseInstallations - - FirebaseMessaging - - FirebaseRemoteConfig - - FirebaseSessions - - FLEX - - FutureX - - GestureInstructions - - GoogleAppMeasurement - - GoogleDataTransport - - GoogleUtilities - - GRDB.swift - - iOSDFULibrary - - KeychainAccess - - nanopb - - Nantes - - Nimble - - PromisesObjC - - PromisesSwift - - Quick - - Realm - - RealmSwift - - SwiftGen - - Swinject - - ZIPFoundation - -EXTERNAL SOURCES: - BTKit: - :git: https://github.com/ruuvi/BTKit.git - Humidity: - :git: https://github.com/rinat-enikeev/Humidity.git - LightRoute: - :git: https://github.com/rinat-enikeev/LightRoute.git - RangeSeekSlider: - :git: https://github.com/rinat-enikeev/RangeSeekSlider - RuuviAnalytics: - :path: Packages/RuuviAnalytics/RuuviAnalytics.podspec - RuuviCloud: - :path: Packages/RuuviCloud/RuuviCloud.podspec - RuuviContext: - :path: Packages/RuuviContext/RuuviContext.podspec - RuuviCore: - :path: Packages/RuuviCore/RuuviCore.podspec - RuuviDaemon: - :path: Packages/RuuviDaemon/RuuviDaemon.podspec - RuuviDFU: - :path: Packages/RuuviDFU/RuuviDFU.podspec - RuuviDiscover: - :path: Modules/RuuviDiscover/RuuviDiscover.podspec - RuuviLocal: - :path: Packages/RuuviLocal/RuuviLocal.podspec - RuuviLocalization: - :path: Common/RuuviLocalization/RuuviLocalization.podspec - RuuviMigration: - :path: Packages/RuuviMigration/RuuviMigration.podspec - RuuviNotification: - :path: Packages/RuuviNotification/RuuviNotification.podspec - RuuviNotifier: - :path: Packages/RuuviNotifier/RuuviNotifier.podspec - RuuviOnboard: - :path: Modules/RuuviOnboard/RuuviOnboard.podspec - RuuviOntology: - :path: Packages/RuuviOntology/RuuviOntology.podspec - RuuviPersistence: - :path: Packages/RuuviPersistence/RuuviPersistence.podspec - RuuviPool: - :path: Packages/RuuviPool/RuuviPool.podspec - RuuviPresenters: - :path: Common/RuuviPresenters/RuuviPresenters.podspec - RuuviReactor: - :path: Packages/RuuviReactor/RuuviReactor.podspec - RuuviRepository: - :path: Packages/RuuviRepository/RuuviRepository.podspec - RuuviService: - :path: Packages/RuuviService/RuuviService.podspec - RuuviStorage: - :path: Packages/RuuviStorage/RuuviStorage.podspec - RuuviUser: - :path: Packages/RuuviUser/RuuviUser.podspec - -CHECKOUT OPTIONS: - BTKit: - :commit: 3f8d3742fe7fb1721627853fa14827ca0e7b36f1 - :git: https://github.com/ruuvi/BTKit.git - Humidity: - :commit: fb909b332a1f17a6453587dbeaebcfe7c6712a72 - :git: https://github.com/rinat-enikeev/Humidity.git - LightRoute: - :commit: fcea1b3808b75be92d983316742bf186e21981ec - :git: https://github.com/rinat-enikeev/LightRoute.git - RangeSeekSlider: - :commit: 35712fc13229f527e0a356f3de34deccbcfd6b59 - :git: https://github.com/rinat-enikeev/RangeSeekSlider - -SPEC CHECKSUMS: - BTKit: f4e41362078035f6f91b3fb4f3e106881fa501ee - Firebase: 0219acf760880eeec8ce479895bd7767466d9f81 - FirebaseABTesting: 76c8297fd026074e0366dc941d265d1be80a56d5 - FirebaseAnalytics: f8133442ee6f8512e28ff19e62ce15398bfaeace - FirebaseCore: e317665b9d744727a97e623edbbed009320afdd7 - FirebaseCoreExtension: f17247ba8c61e4d3c8d136b5e2de3cb4ac6a85b6 - FirebaseCoreInternal: 8845798510aae74703467480f71ac613788d0696 - FirebaseCrashlytics: 35fdd1a433b31e28adcf5c8933f4c526691a1e0b - FirebaseInAppMessaging: d04732fe9c37c3d026d66435abba60120087a7f5 - FirebaseInstallations: 59c0e4c7a816a0f76710d83f77e5369b3e45eb96 - FirebaseMessaging: ac9062bcc35ed56e15a0241d8fd317022499baf8 - FirebaseRemoteConfig: d5de62211e2eaa2152d8ee85a23c301b70887a74 - FirebaseSessions: 34e5c084da010ef3802cbc062b822e513c9e6318 - FLEX: f21ee4f498eed3f8a1eded66b21939fd3b7a22ce - FutureX: 85faeccb370f5a4286ae8540849095adb0bd7b2d - GestureInstructions: acbd12854a5c7658365a11eaae2652dcbe623038 - GoogleAppMeasurement: fe17c92a32207dd5cdd4e8d742767f2da74857f6 - GoogleDataTransport: 8378d1fa8ac49753ea6ce70d65a7cb70ce5f66e6 - GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749 - GRDB.swift: 8cc3ab7c8b8b4ac1761deb8dca4b51c1c9d429f8 - Humidity: fb16fe2430b7a8aa979821ede5b5164519fca6d1 - iOSDFULibrary: 3b9de67ed4bfb901b5f09c2fea843f65e152612d - KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51 - LightRoute: 771c97d6f2b160f9f345465804c0399f9580723d - nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 - Nantes: 0396442578e32242223fed46050dea1850236184 - Nimble: 01a944d4d07eab73617dfd4b32ac9f7152ac34de - PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef - PromisesSwift: cf9eb58666a43bbe007302226e510b16c1e10959 - Quick: 6676ffb409bf04abba2ff23902af2407bfc6ac90 - RangeSeekSlider: 0c26866bb2f59eea808d486ec3b990bcfae1b938 - Realm: d4f810e161fa2c2c589b9860b6eb09238deacd73 - RealmSwift: cef9946f09f2333a8f2ac8bac4f8de52fb9f5ac3 - RuuviAnalytics: 57b1793c6d12cce0f0232179625962e7ee5d8eb3 - RuuviCloud: f488ad2791dea1cee92b648e96e3eca20f5465b6 - RuuviContext: 3c3a03e1791189e57d35252cac2448b30cb5c8c4 - RuuviCore: c42d46fd24adec33663aa61a7b73430b448a56e4 - RuuviDaemon: 49929276bac8f6d1a73c31326bdebbf29ac513ac - RuuviDFU: f032417ccbb62cbaa35d62918cdb51b420010c78 - RuuviDiscover: b5c4f470541f50ad68e785542f7839ba067c5614 - RuuviLocal: 5d711ed6933bbea2c958bd805186bbde012bc4e3 - RuuviLocalization: 04e829bac8113cc8edb49c22a243da88b8383210 - RuuviMigration: 9db6edb260c58fedfc816bb8561d3f070113bdba - RuuviNotification: 9985612f76fd661cf26473518e503c3ac224c928 - RuuviNotifier: c417691a212ca07ab4fae7095cb9e0bc25e19084 - RuuviOnboard: c9c5556007c56b4491df3ad8e1ef9c3c57ebbd34 - RuuviOntology: 174c688dc2083e7afe1d98d941c9db0fd6c7a063 - RuuviPersistence: 0be00598293866c79a94636247e9365b2a2e3da5 - RuuviPool: 663c3b125b2f865b0e5174abcd88c148c4c7ed6b - RuuviPresenters: b883212d32138c00dd61680547ce33dcac922b37 - RuuviReactor: 5fd4dcff29ba553c36e26b0a0334dc5007d26fcd - RuuviRepository: 2a98401ff527bc19ec488281e5bbe5a820c405ca - RuuviService: 87d15c3b9758850079b91a7823f4de41e7b90cac - RuuviStorage: b7f0d9e11fdc0bb73317b70464cc04e8b5b5d6d7 - RuuviUser: 7222200bae9f4a7d1309f0b77013890d764b3c28 - SwiftGen: 1366a7f71aeef49954ca5a63ba4bef6b0f24138c - Swinject: 893c9a543000ac2f10ee4cbaf0933c6992c935d5 - ZIPFoundation: b1f0de4eed33e74a676f76e12559ab6b75990197 - -PODFILE CHECKSUM: b310e01f364c17dd00c1de3d944fa2a1ad2776b8 - -COCOAPODS: 1.12.1 diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 51399460e..02199b2a7 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -23,15 +23,7 @@ def remove_artifacts end platform :ios do - def install_pods - cocoapods( - podfile: "Podfile", - try_repo_update_on_error: true - ) - end - lane :test do - install_pods() scan( scheme: "stationTests", workspace: "station.xcworkspace", @@ -42,10 +34,6 @@ platform :ios do desc "Register devices" lane :reg do - register_devices(devices: { - "Marko 6" => "2cc93059fe0e9cc7cd815128e032cdbecdde33cb", - "Marko 5s" => "ad7a30c543977fb7d88ade9b60c34acbc10fd707" - }) match(type: "development", force_for_new_devices: true) match(type: "adhoc", force_for_new_devices: true) end diff --git a/intents_frameworks.yml b/intents.yml similarity index 100% rename from intents_frameworks.yml rename to intents.yml diff --git a/intents_spm.yml b/intents_spm.yml deleted file mode 100644 index 76f3f7a88..000000000 --- a/intents_spm.yml +++ /dev/null @@ -1,60 +0,0 @@ -targets: - station.intents: - type: app-extension - platform: iOS - info: - path: intents/Info.plist - properties: - NSExtension: - NSExtensionAttributes: - IntentsRestrictedWhileLocked: [] - IntentsRestrictedWhileProtectedDataUnavailable: [] - IntentsSupported: [RuuviTagSelectionIntent] - NSExtensionPointIdentifier: com.apple.intents-service - NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).IntentHandler - CFBundleDisplayName: Ruuvi Station - CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString: $(MARKETING_VERSION) - CFBundleVersion: $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright: Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. - settings: - base: - CODE_SIGN_ENTITLEMENTS: station_intents.entitlements - configs: - Alpha: - CODE_SIGN_IDENTITY: "iPhone Distribution" - PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.intents" - Debug: - CODE_SIGN_STYLE: Automatic - Release: - EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" - CODE_SIGN_IDENTITY: "iPhone Distribution" - PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.intents" - sources: - - path: intents - - path: ruuvi-widgets - excludes: - - Info.plist - dependencies: - - package: Swinject - - package: BTKit - - package: Future - - package: GRDB - - package: Humidity - - package: Realm - - package: KeychainAccess - - package: Realm - product: RealmSwift - - package: RuuviUser - - package: RuuviUser - product: RuuviUserCoordinator - - package: RuuviCloud - - package: RuuviCloud - product: RuuviCloudPure - - package: RuuviCloud - product: RuuviCloudApi - - package: RuuviOntology - - package: RuuviPool - - package: RuuviLocal - - package: RuuviPersistence - - package: RuuviContext \ No newline at end of file diff --git a/project_frameworks.yml b/project.yml similarity index 99% rename from project_frameworks.yml rename to project.yml index 1a0d5613b..0f223a674 100644 --- a/project_frameworks.yml +++ b/project.yml @@ -199,9 +199,9 @@ include: - Modules/RuuviDiscover/target.yml - Modules/RuuviOnboard/target.yml - Modules/RuuviFirmware/target.yml -- widget_frameworks.yml +- widget.yml - pnservice.yml -- intents_frameworks.yml +- intents.yml configs: Alpha: debug diff --git a/project_spm.yml b/project_spm.yml deleted file mode 100644 index 40feb95d8..000000000 --- a/project_spm.yml +++ /dev/null @@ -1,293 +0,0 @@ -APP_NAME: &APP_NAME spm -DEVELOPMENT_TEAM: &DEVELOPMENT_TEAM 4MUYJ4YYH4 -BUNDLE_ID_PREFIX: &BUNDLE_ID_PREFIX com.ruuvi - -attributes: - ORGANIZATIONNAME: Ruuvi Innovations Oy - -settings: - base: - CURRENT_PROJECT_VERSION: 1 - MARKETING_VERSION: "2.5.2" - DEVELOPMENT_TEAM: *DEVELOPMENT_TEAM - -name: *APP_NAME - -options: - bundleIdPrefix: *BUNDLE_ID_PREFIX - developmentLanguage: en - deploymentTarget: - iOS: 14.0 - -packages: - BTKit: - url: https://github.com/ruuvi/BTKit - from: 0.4.3 - Charts: - url: https://github.com/danielgindi/Charts - from: 4.1.0 - LightRoute: - url: https://github.com/rinat-enikeev/LightRoute - from: 2.2.2 - Swinject: - url: https://github.com/Swinject/Swinject - from: 2.8.3 - Firebase: - url: https://github.com/firebase/firebase-ios-sdk - from: 10.7.0 - RangeSeekSlider: - url: https://github.com/rinat-enikeev/RangeSeekSlider - from: 1.8.2 - GestureInstructions: - url: https://github.com/rinat-enikeev/GestureInstructions - from: 0.0.2 - KeychainAccess: - url: https://github.com/kishikawakatsumi/KeychainAccess - from: 4.2.1 - Realm: - url: https://github.com/realm/realm-cocoa - from: 10.8.0 - GRDB: - url: https://github.com/groue/GRDB.swift - from: 4.14.0 - Humidity: - url: https://github.com/rinat-enikeev/Humidity - from: 0.1.5 - Future: - url: https://github.com/kean/Future - from: 1.3.0 - NordicDFU: - url: https://github.com/NordicSemiconductor/IOS-Pods-DFU-Library - from: 4.10.3 - FLEX: - url: https://github.com/FLEXTool/FLEX.git - from: 5.22.10 - RuuviAnalytics: - path: Packages/RuuviAnalytics - RuuviCloud: - path: Packages/RuuviCloud - RuuviContext: - path: Packages/RuuviContext - RuuviCore: - path: Packages/RuuviCore - RuuviDaemon: - path: Packages/RuuviDaemon - RuuviDFU: - path: Packages/RuuviDFU - RuuviLocal: - path: Packages/RuuviLocal - RuuviMigration: - path: Packages/RuuviMigration - RuuviNotification: - path: Packages/RuuviNotification - RuuviNotifier: - path: Packages/RuuviNotifier - RuuviOntology: - path: Packages/RuuviOntology - RuuviPersistence: - path: Packages/RuuviPersistence - RuuviPool: - path: Packages/RuuviPool - RuuviReactor: - path: Packages/RuuviReactor - RuuviRepository: - path: Packages/RuuviRepository - RuuviService: - path: Packages/RuuviService - RuuviStorage: - path: Packages/RuuviStorage - RuuviUser: - path: Packages/RuuviUser - RuuviPresenters: - path: Common/RuuviPresenters - RuuviDiscover: - path: Modules/RuuviDiscover - RuuviOnboard: - path: Modules/RuuviOnboard - -include: -- widget_spm.yml -- pnservice.yml -- intents_spm.yml - -configs: - Alpha: debug - Debug: debug - Release: release - -targets: - station: - type: application - platform: iOS - sources: - - path: station - - path: ruuvi_widgets.entitlements - - path: station_intents.entitlements - - path: pnservice.entitlements - dependencies: - - target: "station.widgets" - - target: "station.intents" - - target: "station.pnservice" - - package: BTKit - - package: Charts - - package: LightRoute - - package: Swinject - - package: RangeSeekSlider - - package: GestureInstructions - - package: Firebase - product: FirebaseMessaging - - package: Firebase - product: FirebaseRemoteConfig - - package: KeychainAccess - - package: Realm - - package: Realm - product: RealmSwift - - package: NordicDFU - - package: FLEX - - package: RuuviAnalytics - - package: RuuviAnalytics - product: RuuviAnalyticsImpl - - package: RuuviCloud - - package: RuuviCloud - product: RuuviCloudPure - - package: RuuviContext - - package: RuuviContext - product: RuuviContextRealm - - package: RuuviContext - product: RuuviContextSQLite - - package: RuuviCore - - package: RuuviCore - product: RuuviCoreImage - - package: RuuviCore - product: RuuviCorePN - - package: RuuviCore - product: RuuviCorePermission - - package: RuuviCore - product: RuuviCoreLocation - - package: RuuviDaemon - - package: RuuviDaemon - product: RuuviDaemonBackground - - package: RuuviDaemon - product: RuuviDaemonRuuviTag - - package: RuuviDaemon - product: RuuviDaemonCloudSync - - package: RuuviDFU - - package: RuuviDFU - product: RuuviDFUImpl - - package: RuuviLocal - - package: RuuviLocal - product: RuuviLocalUserDefaults - - package: RuuviMigration - - package: RuuviMigration - product: RuuviMigrationImpl - - package: RuuviNotification - - package: RuuviNotification - product: RuuviNotificationLocal - - package: RuuviNotifier - - package: RuuviNotifier - product: RuuviNotifierImpl - - package: RuuviOntology - - package: RuuviPersistence - - package: RuuviPersistence - product: RuuviPersistenceRealm - - package: RuuviPersistence - product: RuuviPersistenceSQLite - - package: RuuviPool - - package: RuuviPool - product: RuuviPoolCoordinator - - package: RuuviReactor - - package: RuuviReactor - product: RuuviReactorImpl - - package: RuuviRepository - - package: RuuviRepository - product: RuuviRepositoryCoordinator - - package: RuuviService - - package: RuuviService - product: RuuviServiceFactory - - package: RuuviService - product: RuuviServiceMeasurement - - package: RuuviService - product: RuuviServiceOwnership - - package: RuuviService - product: RuuviServiceExport - - package: RuuviService - product: RuuviServiceGATT - - package: RuuviStorage - - package: RuuviStorage - product: RuuviStorageCoordinator - - package: RuuviUser - - package: RuuviUser - product: RuuviUserCoordinator - - package: RuuviPresenters - - package: RuuviDiscover - - package: RuuviOnboard - info: - path: station/Resources/Plists/Info.plist - properties: - CFBundleDisplayName: Ruuvi Station - CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString: "$(MARKETING_VERSION)" - CFBundleVersion: $(CURRENT_PROJECT_VERSION) - UISupportedInterfaceOrientations: [UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight, UIInterfaceOrientationPortrait] - UILaunchStoryboardName: LaunchScreen - BGTaskSchedulerPermittedIdentifiers: [com.ruuvi.station.BackgroundProcessServiceiOS13.dataPruning] - FirebaseMessagingAutoInitEnabled: false - LSApplicationQueriesSchemes: [https, http, mailto] - LSRequiresIPhoneOS: true - NFCReaderUsageDescription: Allows user to claim a RuuviTag using NFC when the user has physical access to the sensor - NSBluetoothAlwaysUsageDescription: The app uses Bluetooth LE to read data from Ruuvi Sensors - NSBluetoothPeripheralUsageDescription: The app uses Bluetooth LE to read data from RuuviTag sensors. - NSCameraUsageDescription: Ruuvi Station needs to access your camera in order to be able to capture photos and use them as sensor background. - NSLocationAlwaysAndWhenInUseUsageDescription: Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. - NSLocationAlwaysUsageDescription: Ruuvi Station needs to access your location while being in background in order to pull data for Virtual Sensors for your current location and display alerts. - NSLocationUsageDescription: Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. - NSLocationWhenInUseUsageDescription: Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. - NSPhotoLibraryUsageDescription: Ruuvi Station needs to access your camera roll to enable selecting the background for the sensor. - NSUserActivityTypes: [RuuviTagSelectionIntent] - UIAppFonts: [Oswald-Bold.ttf,Oswald-ExtraLight.ttf,Muli-Regular.ttf,Muli-Bold.ttf,Muli-SemiBoldItalic.ttf,Muli-ExtraBold.ttf,Montserrat-Bold.ttf,Montserrat-Regular.ttf,Montserrat-ExtraBold.ttf] - UIBackgroundModes: [bluetooth-central, processing, remote-notification] - UIRequiredDeviceCapabilities: [armv7] - UIRequiresFullScreen: true - UIStatusBarStyle: UIStatusBarStyleLightContent - UISupportedInterfaceOrientations~ipad: [UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight,UIInterfaceOrientationPortrait, UIInterfaceOrientationPortraitUpsideDown] - UIViewControllerBasedStatusBarAppearance: true - settings: - base: - TARGETED_DEVICE_FAMILY: 1,2 - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true - CODE_SIGN_ENTITLEMENTS: station/station.entitlements - configs: - Alpha: - CODE_SIGN_IDENTITY: "iPhone Distribution" - PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station" - Debug: - CODE_SIGN_STYLE: Automatic - Release: - EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" - CODE_SIGN_IDENTITY: "iPhone Distribution" - PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station" - preBuildScripts: - - path: scripts/build/generate_l10n.sh - name: Generate L10N - inputFiles: - - $(SRCROOT)/station.localization/station.localization.json - outputFiles: - - $(SRCROOT)/station/Resources/Strings/en.lproj/Localizable.strings - - $(SRCROOT)/station/Resources/Strings/sv.lproj/Localizable.strings - - $(SRCROOT)/station/Resources/Strings/ru.lproj/Localizable.strings - - $(SRCROOT)/station/Resources/Strings/fi.lproj/Localizable.strings - - $(SRCROOT)/station/Resources/Strings/fr.lproj/Localizable.strings - - $(SRCROOT)/station/Resources/Strings/de.lproj/Localizable.strings - postBuildScripts: - - path: scripts/build/load_keystore.sh - name: Load Keystore - inputFiles: - - $(SRCROOT)/station/Classes/Networking/Assembly/Networking.plist - - $(SRCROOT)/station/Resources/Plists/GoogleService-Info.plist - runOnlyWhenInstalling: true - basedOnDependencyAnalysis: false -schemes: - station: - build: - targets: - station: all \ No newline at end of file diff --git a/station.xcodeproj/project.pbxproj b/station.xcodeproj/project.pbxproj deleted file mode 100644 index eedb1295b..000000000 --- a/station.xcodeproj/project.pbxproj +++ /dev/null @@ -1,6911 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXBuildFile section */ - 08E830207D43DAF06076D647 /* SignInModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87EFB230083D471777FBE5D0 /* SignInModuleInput.swift */; }; - 0E00C4F12684D97B009B3C24 /* ExportHeadersProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E00C4F02684D97B009B3C24 /* ExportHeadersProvider.swift */; }; - 0E00C4F22684D97B009B3C24 /* ExportHeadersProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E00C4F02684D97B009B3C24 /* ExportHeadersProvider.swift */; }; - 0E00C5082685D82B009B3C24 /* RuuviDaemonError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E00C5072685D82B009B3C24 /* RuuviDaemonError+LocalizedError.swift */; }; - 0E00C5092685D82B009B3C24 /* RuuviDaemonError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E00C5072685D82B009B3C24 /* RuuviDaemonError+LocalizedError.swift */; }; - 0E02ABBA237598C600ED4629 /* RURangeSeekSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E02ABB9237598C600ED4629 /* RURangeSeekSlider.swift */; }; - 0E02ABCB2379483A00ED4629 /* Double+Temperature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E02ABCA2379483A00ED4629 /* Double+Temperature.swift */; }; - 0E0501212685E895007060C4 /* HeartbeatDaemonTitles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0501202685E895007060C4 /* HeartbeatDaemonTitles.swift */; }; - 0E0501222685E895007060C4 /* HeartbeatDaemonTitles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0501202685E895007060C4 /* HeartbeatDaemonTitles.swift */; }; - 0E09672522AE897000E85F48 /* CALayer+IB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E09672422AE897000E85F48 /* CALayer+IB.swift */; }; - 0E0A381923616AC3003A0364 /* UserDefaults+Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0A381823616AC3003A0364 /* UserDefaults+Optional.swift */; }; - 0E197C6623C4A47A0074015B /* MailComposerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C6523C4A47A0074015B /* MailComposerPresenter.swift */; }; - 0E197C6723C4A47A0074015B /* MailComposerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C6523C4A47A0074015B /* MailComposerPresenter.swift */; }; - 0E197C6B23C4A52A0074015B /* MailComposerPresenterMessageUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C6A23C4A52A0074015B /* MailComposerPresenterMessageUI.swift */; }; - 0E197C6C23C4A52A0074015B /* MailComposerPresenterMessageUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C6A23C4A52A0074015B /* MailComposerPresenterMessageUI.swift */; }; - 0E197C6F23C4A7D00074015B /* Presentation.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0E197C6E23C4A7D00074015B /* Presentation.plist */; }; - 0E197C7023C4A7D00074015B /* Presentation.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0E197C6E23C4A7D00074015B /* Presentation.plist */; }; - 0E197C7423C5C7A20074015B /* InfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C7323C5C7A20074015B /* InfoProvider.swift */; }; - 0E197C7523C5C7A20074015B /* InfoProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C7323C5C7A20074015B /* InfoProvider.swift */; }; - 0E197C7923C5CCBC0074015B /* InfoProviderImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C7823C5CCBB0074015B /* InfoProviderImpl.swift */; }; - 0E197C7A23C5CCBC0074015B /* InfoProviderImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C7823C5CCBB0074015B /* InfoProviderImpl.swift */; }; - 0E197C7D23C5CD7C0074015B /* UIDevice+ReadableModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C7C23C5CD7C0074015B /* UIDevice+ReadableModel.swift */; }; - 0E197C7E23C5CD7C0074015B /* UIDevice+ReadableModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E197C7C23C5CD7C0074015B /* UIDevice+ReadableModel.swift */; }; - 0E197C8123C5CDBE0074015B /* iOSDeviceModelMapping.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0E197C8023C5CDBE0074015B /* iOSDeviceModelMapping.plist */; }; - 0E197C8223C5CDBE0074015B /* iOSDeviceModelMapping.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0E197C8023C5CDBE0074015B /* iOSDeviceModelMapping.plist */; }; - 0E1C1DA022B36C100032F6CA /* RUError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1D9F22B36C100032F6CA /* RUError.swift */; }; - 0E1C1DA822B387A00032F6CA /* AppAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DA722B387A00032F6CA /* AppAssembly.swift */; }; - 0E1C1DBB22B3919F0032F6CA /* UIApplication+ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DBA22B3919F0032F6CA /* UIApplication+ViewController.swift */; }; - 0E1C1DBE22B3921E0032F6CA /* PresentationAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DBD22B3921E0032F6CA /* PresentationAssembly.swift */; }; - 0E1C1DD322B3BF180032F6CA /* CardsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DD222B3BF180032F6CA /* CardsViewInput.swift */; }; - 0E1C1DD522B3BF3A0032F6CA /* CardsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DD422B3BF3A0032F6CA /* CardsViewOutput.swift */; }; - 0E1C1DDD22B3C2160032F6CA /* CardsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DDC22B3C2160032F6CA /* CardsModuleInput.swift */; }; - 0E1C1DE222B3C25F0032F6CA /* CardsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE122B3C25F0032F6CA /* CardsRouterInput.swift */; }; - 0E1C1DE422B3C2710032F6CA /* CardsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE322B3C2710032F6CA /* CardsRouter.swift */; }; - 0E1C1DF122B3FDE30032F6CA /* Menu.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF022B3FDE30032F6CA /* Menu.storyboard */; }; - 0E1C1DF322B3FEFF0032F6CA /* MenuViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF222B3FEFF0032F6CA /* MenuViewInput.swift */; }; - 0E1C1DF522B3FF1D0032F6CA /* MenuViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF422B3FF1D0032F6CA /* MenuViewOutput.swift */; }; - 0E1C1DF822B3FF480032F6CA /* MenuTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF722B3FF480032F6CA /* MenuTableViewController.swift */; }; - 0E1C1DFA22B3FFBF0032F6CA /* MenuRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF922B3FFBF0032F6CA /* MenuRouterInput.swift */; }; - 0E1C1DFC22B3FFD90032F6CA /* MenuRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFB22B3FFD90032F6CA /* MenuRouter.swift */; }; - 0E1C1DFE22B3FFFC0032F6CA /* MenuModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFD22B3FFFC0032F6CA /* MenuModuleInput.swift */; }; - 0E1C1E0022B400130032F6CA /* MenuPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFF22B400130032F6CA /* MenuPresenter.swift */; }; - 0E1C1E0322B400590032F6CA /* MenuTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0222B400590032F6CA /* MenuTableInitializer.swift */; }; - 0E1C1E0522B400890032F6CA /* MenuTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0422B400890032F6CA /* MenuTableConfigurator.swift */; }; - 0E1C1E0922B4024E0032F6CA /* MenuTableTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0822B4024E0032F6CA /* MenuTableTransitioningDelegate.swift */; }; - 0E1C1E0B22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0A22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift */; }; - 0E1C1E0D22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0C22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift */; }; - 0E1C1E0F22B4049F0032F6CA /* MenuTablePresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0E22B4049E0032F6CA /* MenuTablePresentationController.swift */; }; - 0E211C2A234C5FE900FC37B0 /* CardsRouterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E211C29234C5FE900FC37B0 /* CardsRouterDelegate.swift */; }; - 0E25135F2684AEAD004A522A /* RuuviNotifierTitlesImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E25135E2684AEAD004A522A /* RuuviNotifierTitlesImpl.swift */; }; - 0E2513602684AEAD004A522A /* RuuviNotifierTitlesImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E25135E2684AEAD004A522A /* RuuviNotifierTitlesImpl.swift */; }; - 0E290A852660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E290A842660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift */; }; - 0E290A862660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E290A842660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift */; }; - 0E2AFFA0266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2AFF9F266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift */; }; - 0E2AFFA1266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2AFF9F266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift */; }; - 0E2B339B26A2BC3F00366B01 /* AppRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2B339A26A2BC3F00366B01 /* AppRouter.swift */; }; - 0E2B339C26A2BC3F00366B01 /* AppRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2B339A26A2BC3F00366B01 /* AppRouter.swift */; }; - 0E2B339E26A2BCBE00366B01 /* OnboardRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2B339D26A2BCBE00366B01 /* OnboardRouter.swift */; }; - 0E2B339F26A2BCBE00366B01 /* OnboardRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E2B339D26A2BCBE00366B01 /* OnboardRouter.swift */; }; - 0E3CA70C267365B1000D9B25 /* Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3CA70B267365B1000D9B25 /* Debouncer.swift */; }; - 0E3CA70D267365B1000D9B25 /* Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E3CA70B267365B1000D9B25 /* Debouncer.swift */; }; - 0E502FBA22B27D4800E8A6CC /* TemperatureUnit+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E502FB922B27D4800E8A6CC /* TemperatureUnit+Localization.swift */; }; - 0E53A3F1232DFC6200ACED49 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0E53A3F3232DFC6200ACED49 /* InfoPlist.strings */; }; - 0E53DA6022CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA5F22CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift */; }; - 0E53DA6222CC93EB00BC6D64 /* SwipeDownToDismissTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6122CC93EB00BC6D64 /* SwipeDownToDismissTransitionAnimation.swift */; }; - 0E53DA6422CC943900BC6D64 /* SwipeDownToDismissInteractiveTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6322CC943900BC6D64 /* SwipeDownToDismissInteractiveTransition.swift */; }; - 0E53DA6722CC964200BC6D64 /* SwipeDownToDismissNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6622CC964200BC6D64 /* SwipeDownToDismissNavigationController.swift */; }; - 0E5C300B22CF629100B52E39 /* PhotoPickerPresenterSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C300A22CF629100B52E39 /* PhotoPickerPresenterSheet.swift */; }; - 0E5C302522D0B19600B52E39 /* AppStateService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C302422D0B19600B52E39 /* AppStateService.swift */; }; - 0E5C302822D0B1C600B52E39 /* AppStateServiceImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C302722D0B1C600B52E39 /* AppStateServiceImpl.swift */; }; - 0E62299526AAA0570041DCDD /* DiscoverRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E62299426AAA0570041DCDD /* DiscoverRouter.swift */; }; - 0E62299626AAA0570041DCDD /* DiscoverRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E62299426AAA0570041DCDD /* DiscoverRouter.swift */; }; - 0E6C471723D305960016B46E /* StationUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E6C471623D305960016B46E /* StationUITests.swift */; }; - 0E70A46022AF9567006CB87C /* ViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A45F22AF9567006CB87C /* ViewInput.swift */; }; - 0E70A46322AF959E006CB87C /* Localizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A46222AF959E006CB87C /* Localizable.swift */; }; - 0E84BF552397F29800A37E1A /* Heartbeat.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E84BF542397F29800A37E1A /* Heartbeat.storyboard */; }; - 0E84BF572397F33E00A37E1A /* HeartbeatViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF562397F33E00A37E1A /* HeartbeatViewInput.swift */; }; - 0E84BF592397F3C600A37E1A /* HeartbeatViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF582397F3C600A37E1A /* HeartbeatViewModel.swift */; }; - 0E84BF5B2397F3DF00A37E1A /* HeartbeatViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF5A2397F3DF00A37E1A /* HeartbeatViewOutput.swift */; }; - 0E84BF5F2397F6BE00A37E1A /* HeartbeatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF5E2397F6BE00A37E1A /* HeartbeatViewController.swift */; }; - 0E84BF612397F73100A37E1A /* HeartbeatEnvironmentObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF602397F73100A37E1A /* HeartbeatEnvironmentObject.swift */; }; - 0E84BF632397F76A00A37E1A /* HeartbeatList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF622397F76A00A37E1A /* HeartbeatList.swift */; }; - 0E84BF652397F9DC00A37E1A /* HeartbeatTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF642397F9DC00A37E1A /* HeartbeatTableViewController.swift */; }; - 0E84BF67239801AF00A37E1A /* HeartbeatRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF66239801AF00A37E1A /* HeartbeatRouterInput.swift */; }; - 0E84BF69239801C100A37E1A /* HeartbeatRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF68239801C100A37E1A /* HeartbeatRouter.swift */; }; - 0E84BF6B239802A400A37E1A /* HeartbeatModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF6A239802A400A37E1A /* HeartbeatModuleInput.swift */; }; - 0E84BF6D239802CA00A37E1A /* HeartbeatPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF6C239802CA00A37E1A /* HeartbeatPresenter.swift */; }; - 0E84BF6F2398031B00A37E1A /* HeartbeatInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF6E2398031B00A37E1A /* HeartbeatInitializer.swift */; }; - 0E84BF712398035C00A37E1A /* HeartbeatConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF702398035C00A37E1A /* HeartbeatConfigurator.swift */; }; - 0E8A100223845E5100A9CBA6 /* Defaults.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E8A100123845E5100A9CBA6 /* Defaults.storyboard */; }; - 0E8A100A23845F3900A9CBA6 /* DefaultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100923845F3900A9CBA6 /* DefaultsViewController.swift */; }; - 0E8A100C23845F7100A9CBA6 /* DefaultsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100B23845F7100A9CBA6 /* DefaultsViewInput.swift */; }; - 0E8A100E23845F8C00A9CBA6 /* DefaultsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100D23845F8C00A9CBA6 /* DefaultsViewOutput.swift */; }; - 0E8A101023845FAE00A9CBA6 /* DefaultsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100F23845FAE00A9CBA6 /* DefaultsViewModel.swift */; }; - 0E8A10122384605A00A9CBA6 /* DefaultsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10112384605A00A9CBA6 /* DefaultsTableViewController.swift */; }; - 0E8A10142384610400A9CBA6 /* DefaultsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10132384610400A9CBA6 /* DefaultsRouter.swift */; }; - 0E8A10162384612300A9CBA6 /* DefaultsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10152384612300A9CBA6 /* DefaultsRouterInput.swift */; }; - 0E8A10182384613E00A9CBA6 /* DefaultsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10172384613E00A9CBA6 /* DefaultsModuleInput.swift */; }; - 0E8A101A2384615400A9CBA6 /* DefaultsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10192384615400A9CBA6 /* DefaultsPresenter.swift */; }; - 0E8A101C2384618700A9CBA6 /* DefaultsInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A101B2384618700A9CBA6 /* DefaultsInitializer.swift */; }; - 0E8A101E238461D400A9CBA6 /* DefaultsConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A101D238461D400A9CBA6 /* DefaultsConfigurator.swift */; }; - 0E8A10202384633200A9CBA6 /* DefaultsEnvironmentObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A101F2384633200A9CBA6 /* DefaultsEnvironmentObject.swift */; }; - 0E8A10222384637F00A9CBA6 /* DefaultsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10212384637F00A9CBA6 /* DefaultsList.swift */; }; - 0E8A102523846CEB00A9CBA6 /* DefaultsSwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A102423846CEB00A9CBA6 /* DefaultsSwitchTableViewCell.swift */; }; - 0E8BD2AB23851CF2008B31EF /* DefaultsStepperTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8BD2AA23851CF2008B31EF /* DefaultsStepperTableViewCell.swift */; }; - 0E8BD2B3238566AB008B31EF /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5522CCE46D00172EEB /* Optional.swift */; }; - 0E8BD2B8238566AB008B31EF /* CALayer+IB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E09672422AE897000E85F48 /* CALayer+IB.swift */; }; - 0E8BD2BA238566AB008B31EF /* MenuTablePresentationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0E22B4049E0032F6CA /* MenuTablePresentationController.swift */; }; - 0E8BD2BD238566AB008B31EF /* TagSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863022CBB00D0026C7A5 /* TagSettingsViewInput.swift */; }; - 0E8BD2BE238566AB008B31EF /* DefaultsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100D23845F8C00A9CBA6 /* DefaultsViewOutput.swift */; }; - 0E8BD2BF238566AB008B31EF /* MenuPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFF22B400130032F6CA /* MenuPresenter.swift */; }; - 0E8BD2C1238566AB008B31EF /* MenuTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF722B3FF480032F6CA /* MenuTableViewController.swift */; }; - 0E8BD2C2238566AB008B31EF /* AboutRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F822B7D28C0015F9E0 /* AboutRouterInput.swift */; }; - 0E8BD2C6238566AB008B31EF /* AboutViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F422B7D1A40015F9E0 /* AboutViewOutput.swift */; }; - 0E8BD2CE238566AB008B31EF /* Language+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF064232002A00025A191 /* Language+Localization.swift */; }; - 0E8BD2D1238566AB008B31EF /* DefaultsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10192384615400A9CBA6 /* DefaultsPresenter.swift */; }; - 0E8BD2D4238566AB008B31EF /* SettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E222B7C8C10015F9E0 /* SettingsPresenter.swift */; }; - 0E8BD2D6238566AB008B31EF /* MenuTablePresentTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0A22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift */; }; - 0E8BD2DA238566AB008B31EF /* MenuModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20CC22B7BD6C0015F9E0 /* MenuModuleOutput.swift */; }; - 0E8BD2DD238566AB008B31EF /* Localizable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A46222AF959E006CB87C /* Localizable.swift */; }; - 0E8BD2E0238566AB008B31EF /* DefaultsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10212384637F00A9CBA6 /* DefaultsList.swift */; }; - 0E8BD2E4238566AB008B31EF /* CardsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DD422B3BF3A0032F6CA /* CardsViewOutput.swift */; }; - 0E8BD2E5238566AB008B31EF /* DefaultsSwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A102423846CEB00A9CBA6 /* DefaultsSwitchTableViewCell.swift */; }; - 0E8BD2E6238566AB008B31EF /* DefaultsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100B23845F7100A9CBA6 /* DefaultsViewInput.swift */; }; - 0E8BD2E9238566AB008B31EF /* MenuTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0422B400890032F6CA /* MenuTableConfigurator.swift */; }; - 0E8BD2ED238566AB008B31EF /* DefaultsStepperTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8BD2AA23851CF2008B31EF /* DefaultsStepperTableViewCell.swift */; }; - 0E8BD2F0238566AB008B31EF /* SettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20DE22B7C8790015F9E0 /* SettingsRouter.swift */; }; - 0E8BD2F3238566AB008B31EF /* SwipeDownToDismissNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6622CC964200BC6D64 /* SwipeDownToDismissNavigationController.swift */; }; - 0E8BD2F4238566AB008B31EF /* DefaultsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10152384612300A9CBA6 /* DefaultsRouterInput.swift */; }; - 0E8BD2F5238566AB008B31EF /* AboutPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FE22B7D2DD0015F9E0 /* AboutPresenter.swift */; }; - 0E8BD2FC238566AB008B31EF /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F4F22CCB92000172EEB /* Observable.swift */; }; - 0E8BD300238566AB008B31EF /* TagSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863222CBB0250026C7A5 /* TagSettingsViewOutput.swift */; }; - 0E8BD302238566AB008B31EF /* CardsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20C522B7915C0015F9E0 /* CardsViewModel.swift */; }; - 0E8BD303238566AB008B31EF /* UIApplication+ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DBA22B3919F0032F6CA /* UIApplication+ViewController.swift */; }; - 0E8BD30F238566AB008B31EF /* PhotoPickerPresenterSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C300A22CF629100B52E39 /* PhotoPickerPresenterSheet.swift */; }; - 0E8BD310238566AB008B31EF /* AboutConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB210222B7D3210015F9E0 /* AboutConfigurator.swift */; }; - 0E8BD311238566AB008B31EF /* AboutViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F222B7D1900015F9E0 /* AboutViewInput.swift */; }; - 0E8BD314238566AB008B31EF /* DefaultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100923845F3900A9CBA6 /* DefaultsViewController.swift */; }; - 0E8BD316238566AB008B31EF /* DefaultsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A100F23845FAE00A9CBA6 /* DefaultsViewModel.swift */; }; - 0E8BD318238566AB008B31EF /* TemperatureUnit+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E502FB922B27D4800E8A6CC /* TemperatureUnit+Localization.swift */; }; - 0E8BD31A238566AB008B31EF /* DefaultsConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A101D238461D400A9CBA6 /* DefaultsConfigurator.swift */; }; - 0E8BD31B238566AB008B31EF /* MenuRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFB22B3FFD90032F6CA /* MenuRouter.swift */; }; - 0E8BD320238566AB008B31EF /* DefaultsInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A101B2384618700A9CBA6 /* DefaultsInitializer.swift */; }; - 0E8BD326238566AB008B31EF /* MenuTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0222B400590032F6CA /* MenuTableInitializer.swift */; }; - 0E8BD330238566AB008B31EF /* AboutInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB210022B7D2F50015F9E0 /* AboutInitializer.swift */; }; - 0E8BD332238566AB008B31EF /* MenuTableEmbededViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20CA22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift */; }; - 0E8BD335238566AB008B31EF /* Date+Ruuvi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF5B72A22D62CD900D9D14A /* Date+Ruuvi.swift */; }; - 0E8BD343238566AB008B31EF /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D222B7C7AC0015F9E0 /* SettingsTableViewController.swift */; }; - 0E8BD345238566AB008B31EF /* SwipeDownToDismissTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6122CC93EB00BC6D64 /* SwipeDownToDismissTransitionAnimation.swift */; }; - 0E8BD348238566AB008B31EF /* SettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20DC22B7C8650015F9E0 /* SettingsRouterInput.swift */; }; - 0E8BD34A238566AB008B31EF /* MenuTableTransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215922BA28860015F9E0 /* MenuTableTransitionManager.swift */; }; - 0E8BD34C238566AB008B31EF /* DefaultsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10132384610400A9CBA6 /* DefaultsRouter.swift */; }; - 0E8BD353238566AB008B31EF /* LocalizationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9D0AB0231EBEFD00C6BDA7 /* LocalizationService.swift */; }; - 0E8BD354238566AB008B31EF /* RURangeSeekSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E02ABB9237598C600ED4629 /* RURangeSeekSlider.swift */; }; - 0E8BD355238566AB008B31EF /* CardsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DDC22B3C2160032F6CA /* CardsModuleInput.swift */; }; - 0E8BD35B238566AB008B31EF /* PresentationAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DBD22B3921E0032F6CA /* PresentationAssembly.swift */; }; - 0E8BD35D238566AB008B31EF /* AboutModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FC22B7D2C90015F9E0 /* AboutModuleInput.swift */; }; - 0E8BD364238566AB008B31EF /* MenuRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF922B3FFBF0032F6CA /* MenuRouterInput.swift */; }; - 0E8BD368238566AB008B31EF /* Double+Temperature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E02ABCA2379483A00ED4629 /* Double+Temperature.swift */; }; - 0E8BD36B238566AB008B31EF /* AppStateServiceImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C302722D0B1C600B52E39 /* AppStateServiceImpl.swift */; }; - 0E8BD36D238566AB008B31EF /* MenuViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF422B3FF1D0032F6CA /* MenuViewOutput.swift */; }; - 0E8BD372238566AB008B31EF /* SwipeDownToDismissTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA5F22CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift */; }; - 0E8BD373238566AB008B31EF /* MenuViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF222B3FEFF0032F6CA /* MenuViewInput.swift */; }; - 0E8BD377238566AB008B31EF /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F622B7D2090015F9E0 /* AboutViewController.swift */; }; - 0E8BD37A238566AB008B31EF /* DefaultsEnvironmentObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A101F2384633200A9CBA6 /* DefaultsEnvironmentObject.swift */; }; - 0E8BD37C238566AB008B31EF /* ViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E70A45F22AF9567006CB87C /* ViewInput.swift */; }; - 0E8BD37D238566AB008B31EF /* UserDefaults+Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0A381823616AC3003A0364 /* UserDefaults+Optional.swift */; }; - 0E8BD37F238566AB008B31EF /* CardsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DD222B3BF180032F6CA /* CardsViewInput.swift */; }; - 0E8BD382238566AB008B31EF /* AboutRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FA22B7D2990015F9E0 /* AboutRouter.swift */; }; - 0E8BD389238566AB008B31EF /* PhotoPickerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5822CF621000172EEB /* PhotoPickerPresenter.swift */; }; - 0E8BD38D238566AB008B31EF /* DefaultsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10172384613E00A9CBA6 /* DefaultsModuleInput.swift */; }; - 0E8BD392238566AB008B31EF /* HumidityUnit+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF5B75322DE153A00D9D14A /* HumidityUnit+Localization.swift */; }; - 0E8BD393238566AB008B31EF /* SwipeDownToDismissInteractiveTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E53DA6322CC943900BC6D64 /* SwipeDownToDismissInteractiveTransition.swift */; }; - 0E8BD395238566AB008B31EF /* NSObject+Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5322CCBBE800172EEB /* NSObject+Observable.swift */; }; - 0E8BD399238566AB008B31EF /* AppAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DA722B387A00032F6CA /* AppAssembly.swift */; }; - 0E8BD39A238566AB008B31EF /* AppStateService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E5C302422D0B19600B52E39 /* AppStateService.swift */; }; - 0E8BD39B238566AB008B31EF /* MenuTableDismissTransitionAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0C22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift */; }; - 0E8BD39E238566AB008B31EF /* SettingsTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E722B7C92C0015F9E0 /* SettingsTableConfigurator.swift */; }; - 0E8BD3A5238566AB008B31EF /* SettingsTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E522B7C8F20015F9E0 /* SettingsTableInitializer.swift */; }; - 0E8BD3AA238566AB008B31EF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64333D2820B0C45900CDF4B6 /* AppDelegate.swift */; }; - 0E8BD3AD238566AB008B31EF /* RUError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1D9F22B36C100032F6CA /* RUError.swift */; }; - 0E8BD3B4238566AB008B31EF /* MenuModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DFD22B3FFFC0032F6CA /* MenuModuleInput.swift */; }; - 0E8BD3B7238566AB008B31EF /* DefaultsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E8A10112384605A00A9CBA6 /* DefaultsTableViewController.swift */; }; - 0E8BD3BA238566AB008B31EF /* MenuTableTransitioningDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1E0822B4024E0032F6CA /* MenuTableTransitioningDelegate.swift */; }; - 0E8BD3C2238566AB008B31EF /* SettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D722B7C8060015F9E0 /* SettingsViewOutput.swift */; }; - 0E8BD3C5238566AB008B31EF /* SettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E022B7C8A90015F9E0 /* SettingsModuleInput.swift */; }; - 0E8BD3CA238566AB008B31EF /* CardsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE322B3C2710032F6CA /* CardsRouter.swift */; }; - 0E8BD3CC238566AB008B31EF /* CardsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E1C1DE122B3C25F0032F6CA /* CardsRouterInput.swift */; }; - 0E8BD3CF238566AB008B31EF /* SettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D522B7C7E70015F9E0 /* SettingsViewInput.swift */; }; - 0E8BD3D2238566AB008B31EF /* CardsRouterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E211C29234C5FE900FC37B0 /* CardsRouterDelegate.swift */; }; - 0E8BD3DF238566AB008B31EF /* Montserrat-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6486971120E0439200CCD7C1 /* Montserrat-Regular.ttf */; }; - 0E8BD3E0238566AB008B31EF /* About.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20EE22B7D1580015F9E0 /* About.storyboard */; }; - 0E8BD3E1238566AB008B31EF /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0ECDF1B42313D65500A09ACA /* GoogleService-Info.plist */; }; - 0E8BD3E3238566AB008B31EF /* Networking.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0E9F97B422EC44930015ADE2 /* Networking.plist */; }; - 0E8BD3E6238566AB008B31EF /* Defaults.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E8A100123845E5100A9CBA6 /* Defaults.storyboard */; }; - 0E8BD3E8238566AB008B31EF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 64333D3120B0C45A00CDF4B6 /* LaunchScreen.storyboard */; }; - 0E8BD3EA238566AB008B31EF /* Oswald-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6486970F20E042E000CCD7C1 /* Oswald-Bold.ttf */; }; - 0E8BD3EB238566AB008B31EF /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20C922B7A7200015F9E0 /* Localizable.strings */; }; - 0E8BD3EF238566AB008B31EF /* Muli-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6467818F225CFB170072856A /* Muli-Regular.ttf */; }; - 0E8BD3F0238566AB008B31EF /* Oswald-ExtraLight.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 643EEC2A2266435100D4E837 /* Oswald-ExtraLight.ttf */; }; - 0E8BD3F3238566AB008B31EF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0E53A3F3232DFC6200ACED49 /* InfoPlist.strings */; }; - 0E8BD3F5238566AB008B31EF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 64333D2F20B0C45A00CDF4B6 /* Assets.xcassets */; }; - 0E8BD3F8238566AB008B31EF /* Menu.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C1DF022B3FDE30032F6CA /* Menu.storyboard */; }; - 0E8BD3FA238566AB008B31EF /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20D022B7C6F30015F9E0 /* Settings.storyboard */; }; - 0E8BD3FB238566AB008B31EF /* Muli-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 64678190225D02CE0072856A /* Muli-Bold.ttf */; }; - 0E8BD3FD238566AB008B31EF /* Montserrat-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 643C651E21C38F490037BE5B /* Montserrat-Bold.ttf */; }; - 0E97D79B268C881300FE9D5B /* DFUModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E97D79A268C881300FE9D5B /* DFUModuleInput.swift */; }; - 0E97D79C268C881300FE9D5B /* DFUModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E97D79A268C881300FE9D5B /* DFUModuleInput.swift */; }; - 0E97D79E268C884500FE9D5B /* DFUPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E97D79D268C884500FE9D5B /* DFUPresenter.swift */; }; - 0E97D79F268C884500FE9D5B /* DFUPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E97D79D268C884500FE9D5B /* DFUPresenter.swift */; }; - 0E97D7A8268C922C00FE9D5B /* DFUInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E97D7A7268C922C00FE9D5B /* DFUInteractor.swift */; }; - 0E97D7A9268C922C00FE9D5B /* DFUInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E97D7A7268C922C00FE9D5B /* DFUInteractor.swift */; }; - 0E9D0AB1231EBEFD00C6BDA7 /* LocalizationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9D0AB0231EBEFD00C6BDA7 /* LocalizationService.swift */; }; - 0E9E775A238CCE5F006D7013 /* String+Replace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9E7759238CCE5F006D7013 /* String+Replace.swift */; }; - 0E9E775B238CCE5F006D7013 /* String+Replace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9E7759238CCE5F006D7013 /* String+Replace.swift */; }; - 0E9F97B522EC44930015ADE2 /* Networking.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0E9F97B422EC44930015ADE2 /* Networking.plist */; }; - 0EA511B8261F3C2C00EE5D5E /* LocalFeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA511B7261F3C2C00EE5D5E /* LocalFeatureToggleProvider.swift */; }; - 0EA511B9261F3C2C00EE5D5E /* LocalFeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA511B7261F3C2C00EE5D5E /* LocalFeatureToggleProvider.swift */; }; - 0EA796712664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796702664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift */; }; - 0EA796722664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796702664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift */; }; - 0EA796752664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796742664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift */; }; - 0EA796762664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796742664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift */; }; - 0EA796792664B37F002BA25D /* RuuviLocalError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796782664B37F002BA25D /* RuuviLocalError+LocalizedError.swift */; }; - 0EA7967A2664B37F002BA25D /* RuuviLocalError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796782664B37F002BA25D /* RuuviLocalError+LocalizedError.swift */; }; - 0EA7967D2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA7967C2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift */; }; - 0EA7967E2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA7967C2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift */; }; - 0EA796812664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796802664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift */; }; - 0EA796822664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796802664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift */; }; - 0EA796852664B84D002BA25D /* RuuviReactorError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796842664B84D002BA25D /* RuuviReactorError+LocalizedError.swift */; }; - 0EA796862664B84D002BA25D /* RuuviReactorError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796842664B84D002BA25D /* RuuviReactorError+LocalizedError.swift */; }; - 0EA796892664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796882664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift */; }; - 0EA7968A2664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA796882664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift */; }; - 0EA7968D2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA7968C2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift */; }; - 0EA7968E2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA7968C2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift */; }; - 0EA7AB7A2680A68200C137AD /* RuuviCoreError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA7AB792680A68200C137AD /* RuuviCoreError+LocalizedError.swift */; }; - 0EA7AB7B2680A68200C137AD /* RuuviCoreError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA7AB792680A68200C137AD /* RuuviCoreError+LocalizedError.swift */; }; - 0EAD33D72399273D00EC5BAA /* Heartbeat.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E84BF542397F29800A37E1A /* Heartbeat.storyboard */; }; - 0EAD33D82399273D00EC5BAA /* HeartbeatInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF6E2398031B00A37E1A /* HeartbeatInitializer.swift */; }; - 0EAD33D92399273D00EC5BAA /* HeartbeatConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF702398035C00A37E1A /* HeartbeatConfigurator.swift */; }; - 0EAD33DA2399273D00EC5BAA /* HeartbeatModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF6A239802A400A37E1A /* HeartbeatModuleInput.swift */; }; - 0EAD33DB2399273D00EC5BAA /* HeartbeatPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF6C239802CA00A37E1A /* HeartbeatPresenter.swift */; }; - 0EAD33DC2399273D00EC5BAA /* HeartbeatRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF66239801AF00A37E1A /* HeartbeatRouterInput.swift */; }; - 0EAD33DD2399273D00EC5BAA /* HeartbeatRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF68239801C100A37E1A /* HeartbeatRouter.swift */; }; - 0EAD33DE2399273D00EC5BAA /* HeartbeatList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF622397F76A00A37E1A /* HeartbeatList.swift */; }; - 0EAD33DF2399273D00EC5BAA /* HeartbeatEnvironmentObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF602397F73100A37E1A /* HeartbeatEnvironmentObject.swift */; }; - 0EAD33E02399273D00EC5BAA /* HeartbeatTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF642397F9DC00A37E1A /* HeartbeatTableViewController.swift */; }; - 0EAD33E12399273D00EC5BAA /* HeartbeatViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF562397F33E00A37E1A /* HeartbeatViewInput.swift */; }; - 0EAD33E22399273D00EC5BAA /* HeartbeatViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF582397F3C600A37E1A /* HeartbeatViewModel.swift */; }; - 0EAD33E32399273D00EC5BAA /* HeartbeatViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF5A2397F3DF00A37E1A /* HeartbeatViewOutput.swift */; }; - 0EAD33E42399273D00EC5BAA /* HeartbeatViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E84BF5E2397F6BE00A37E1A /* HeartbeatViewController.swift */; }; - 0EB48D6F2619D50A008E0D2D /* FeatureToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB48D6E2619D50A008E0D2D /* FeatureToggle.swift */; }; - 0EB48D702619D50A008E0D2D /* FeatureToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB48D6E2619D50A008E0D2D /* FeatureToggle.swift */; }; - 0EB48D8B2619D5AC008E0D2D /* FeatureToggleService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB48D8A2619D5AC008E0D2D /* FeatureToggleService.swift */; }; - 0EB48D8C2619D5AC008E0D2D /* FeatureToggleService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB48D8A2619D5AC008E0D2D /* FeatureToggleService.swift */; }; - 0EB48D952619D5E5008E0D2D /* FeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB48D942619D5E5008E0D2D /* FeatureToggleProvider.swift */; }; - 0EB48D962619D5E5008E0D2D /* FeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB48D942619D5E5008E0D2D /* FeatureToggleProvider.swift */; }; - 0EB48DA32619D7EE008E0D2D /* FirebaseFeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB48DA22619D7EE008E0D2D /* FirebaseFeatureToggleProvider.swift */; }; - 0EB48DA42619D7EE008E0D2D /* FirebaseFeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB48DA22619D7EE008E0D2D /* FirebaseFeatureToggleProvider.swift */; }; - 0EB48DDC2619E306008E0D2D /* FallbackFeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB48DDB2619E306008E0D2D /* FallbackFeatureToggleProvider.swift */; }; - 0EB48DDD2619E306008E0D2D /* FallbackFeatureToggleProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB48DDB2619E306008E0D2D /* FallbackFeatureToggleProvider.swift */; }; - 0EB48DE6261A1816008E0D2D /* FeatureToggles.json in Resources */ = {isa = PBXBuildFile; fileRef = 0EB48DE5261A1816008E0D2D /* FeatureToggles.json */; }; - 0EB48DE7261A1816008E0D2D /* FeatureToggles.json in Resources */ = {isa = PBXBuildFile; fileRef = 0EB48DE5261A1816008E0D2D /* FeatureToggles.json */; }; - 0EB48DFC261B105D008E0D2D /* RemoteConfigService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB48DFB261B105D008E0D2D /* RemoteConfigService.swift */; }; - 0EB48DFD261B105D008E0D2D /* RemoteConfigService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB48DFB261B105D008E0D2D /* RemoteConfigService.swift */; }; - 0EB48E06261B1095008E0D2D /* FirebaseRemoteConfigService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB48E05261B1095008E0D2D /* FirebaseRemoteConfigService.swift */; }; - 0EB48E07261B1095008E0D2D /* FirebaseRemoteConfigService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB48E05261B1095008E0D2D /* FirebaseRemoteConfigService.swift */; }; - 0EB8ED1A268EF36200C6B0FA /* DFUViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED19268EF36200C6B0FA /* DFUViewModel.swift */; }; - 0EB8ED1B268EF36200C6B0FA /* DFUViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED19268EF36200C6B0FA /* DFUViewModel.swift */; }; - 0EB8ED1E268EFF4200C6B0FA /* Publishers+System.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED1D268EFF4200C6B0FA /* Publishers+System.swift */; }; - 0EB8ED1F268EFF4200C6B0FA /* Publishers+System.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED1D268EFF4200C6B0FA /* Publishers+System.swift */; }; - 0EB8ED21268EFF6400C6B0FA /* Feedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED20268EFF6400C6B0FA /* Feedback.swift */; }; - 0EB8ED22268EFF6400C6B0FA /* Feedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED20268EFF6400C6B0FA /* Feedback.swift */; }; - 0EB8ED25268F083700C6B0FA /* DFUUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED24268F083700C6B0FA /* DFUUIView.swift */; }; - 0EB8ED26268F083700C6B0FA /* DFUUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED24268F083700C6B0FA /* DFUUIView.swift */; }; - 0EB8ED29268F10E900C6B0FA /* Spinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED28268F10E900C6B0FA /* Spinner.swift */; }; - 0EB8ED2A268F10E900C6B0FA /* Spinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED28268F10E900C6B0FA /* Spinner.swift */; }; - 0EB8ED2C268F111B00C6B0FA /* View+Any.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED2B268F111B00C6B0FA /* View+Any.swift */; }; - 0EB8ED2D268F111B00C6B0FA /* View+Any.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED2B268F111B00C6B0FA /* View+Any.swift */; }; - 0EB8ED2F268F12FA00C6B0FA /* DFUModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED2E268F12FA00C6B0FA /* DFUModuleFactory.swift */; }; - 0EB8ED30268F12FA00C6B0FA /* DFUModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED2E268F12FA00C6B0FA /* DFUModuleFactory.swift */; }; - 0EB8ED36268F685500C6B0FA /* URLSession+downloadTaskPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED35268F685500C6B0FA /* URLSession+downloadTaskPublisher.swift */; }; - 0EB8ED37268F685500C6B0FA /* URLSession+downloadTaskPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED35268F685500C6B0FA /* URLSession+downloadTaskPublisher.swift */; }; - 0EB8ED39268F6A6900C6B0FA /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED38268F6A6900C6B0FA /* ProgressBar.swift */; }; - 0EB8ED3A268F6A6900C6B0FA /* ProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED38268F6A6900C6B0FA /* ProgressBar.swift */; }; - 0EB8ED3C268F8CD900C6B0FA /* FirmwareRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED3B268F8CD900C6B0FA /* FirmwareRepository.swift */; }; - 0EB8ED3D268F8CD900C6B0FA /* FirmwareRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED3B268F8CD900C6B0FA /* FirmwareRepository.swift */; }; - 0EB8ED3F26916D1700C6B0FA /* LargeButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED3E26916D1700C6B0FA /* LargeButtonStyle.swift */; }; - 0EB8ED4026916D1700C6B0FA /* LargeButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED3E26916D1700C6B0FA /* LargeButtonStyle.swift */; }; - 0EB8ED432692005900C6B0FA /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0EB8ED422692005900C6B0FA /* Colors.xcassets */; }; - 0EB8ED442692005900C6B0FA /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0EB8ED422692005900C6B0FA /* Colors.xcassets */; }; - 0EB8ED472692018000C6B0FA /* RuuviColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED462692018000C6B0FA /* RuuviColor.swift */; }; - 0EB8ED482692018000C6B0FA /* RuuviColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB8ED462692018000C6B0FA /* RuuviColor.swift */; }; - 0EBAF065232002A00025A191 /* Language+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EBAF064232002A00025A191 /* Language+Localization.swift */; }; - 0EC50F5022CCB92000172EEB /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F4F22CCB92000172EEB /* Observable.swift */; }; - 0EC50F5422CCBBE800172EEB /* NSObject+Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5322CCBBE800172EEB /* NSObject+Observable.swift */; }; - 0EC50F5622CCE46D00172EEB /* Optional.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5522CCE46D00172EEB /* Optional.swift */; }; - 0EC50F5922CF621000172EEB /* PhotoPickerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EC50F5822CF621000172EEB /* PhotoPickerPresenter.swift */; }; - 0ECA196A2B138C3A00BEE4DB /* FeatureTogglesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECA19692B138C3A00BEE4DB /* FeatureTogglesViewController.swift */; }; - 0ECA196B2B138C3A00BEE4DB /* FeatureTogglesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ECA19692B138C3A00BEE4DB /* FeatureTogglesViewController.swift */; }; - 0ECDF1B52313D65500A09ACA /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 0ECDF1B42313D65500A09ACA /* GoogleService-Info.plist */; }; - 0EE36E3F26957E010021B746 /* DFUInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E3E26957E000021B746 /* DFUInteractorInput.swift */; }; - 0EE36E4026957E010021B746 /* DFUInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E3E26957E000021B746 /* DFUInteractorInput.swift */; }; - 0EE36E4226957E200021B746 /* LatestRelease.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E4126957E200021B746 /* LatestRelease.swift */; }; - 0EE36E4326957E200021B746 /* LatestRelease.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE36E4126957E200021B746 /* LatestRelease.swift */; }; - 0EE36EAF269DC70E0021B746 /* Algorithms in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE36EAE269DC70E0021B746 /* Algorithms */; }; - 0EE36EB1269DC71B0021B746 /* Algorithms in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE36EB0269DC71B0021B746 /* Algorithms */; }; - 0EE36EB4269DC7D90021B746 /* Charts in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE36EB3269DC7D90021B746 /* Charts */; }; - 0EE36EB6269DC7E40021B746 /* Charts in Frameworks */ = {isa = PBXBuildFile; productRef = 0EE36EB5269DC7E40021B746 /* Charts */; }; - 0EEB20C622B7915C0015F9E0 /* CardsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20C522B7915C0015F9E0 /* CardsViewModel.swift */; }; - 0EEB20C722B7A7200015F9E0 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20C922B7A7200015F9E0 /* Localizable.strings */; }; - 0EEB20CB22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20CA22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift */; }; - 0EEB20CD22B7BD6C0015F9E0 /* MenuModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20CC22B7BD6C0015F9E0 /* MenuModuleOutput.swift */; }; - 0EEB20D122B7C6F30015F9E0 /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20D022B7C6F30015F9E0 /* Settings.storyboard */; }; - 0EEB20D322B7C7AC0015F9E0 /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D222B7C7AC0015F9E0 /* SettingsTableViewController.swift */; }; - 0EEB20D622B7C7E70015F9E0 /* SettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D522B7C7E70015F9E0 /* SettingsViewInput.swift */; }; - 0EEB20D822B7C8060015F9E0 /* SettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20D722B7C8060015F9E0 /* SettingsViewOutput.swift */; }; - 0EEB20DD22B7C8650015F9E0 /* SettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20DC22B7C8650015F9E0 /* SettingsRouterInput.swift */; }; - 0EEB20DF22B7C8790015F9E0 /* SettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20DE22B7C8790015F9E0 /* SettingsRouter.swift */; }; - 0EEB20E122B7C8A90015F9E0 /* SettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E022B7C8A90015F9E0 /* SettingsModuleInput.swift */; }; - 0EEB20E322B7C8C10015F9E0 /* SettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E222B7C8C10015F9E0 /* SettingsPresenter.swift */; }; - 0EEB20E622B7C8F20015F9E0 /* SettingsTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E522B7C8F20015F9E0 /* SettingsTableInitializer.swift */; }; - 0EEB20E822B7C92C0015F9E0 /* SettingsTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20E722B7C92C0015F9E0 /* SettingsTableConfigurator.swift */; }; - 0EEB20EF22B7D1580015F9E0 /* About.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20EE22B7D1580015F9E0 /* About.storyboard */; }; - 0EEB20F322B7D1900015F9E0 /* AboutViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F222B7D1900015F9E0 /* AboutViewInput.swift */; }; - 0EEB20F522B7D1A40015F9E0 /* AboutViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F422B7D1A40015F9E0 /* AboutViewOutput.swift */; }; - 0EEB20F722B7D2090015F9E0 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F622B7D2090015F9E0 /* AboutViewController.swift */; }; - 0EEB20F922B7D28C0015F9E0 /* AboutRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20F822B7D28C0015F9E0 /* AboutRouterInput.swift */; }; - 0EEB20FB22B7D2990015F9E0 /* AboutRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FA22B7D2990015F9E0 /* AboutRouter.swift */; }; - 0EEB20FD22B7D2C90015F9E0 /* AboutModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FC22B7D2C90015F9E0 /* AboutModuleInput.swift */; }; - 0EEB20FF22B7D2DD0015F9E0 /* AboutPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB20FE22B7D2DD0015F9E0 /* AboutPresenter.swift */; }; - 0EEB210122B7D2F50015F9E0 /* AboutInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB210022B7D2F50015F9E0 /* AboutInitializer.swift */; }; - 0EEB210322B7D3220015F9E0 /* AboutConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB210222B7D3210015F9E0 /* AboutConfigurator.swift */; }; - 0EEB215A22BA28860015F9E0 /* MenuTableTransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EEB215922BA28860015F9E0 /* MenuTableTransitionManager.swift */; }; - 0EF2863122CBB00D0026C7A5 /* TagSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863022CBB00D0026C7A5 /* TagSettingsViewInput.swift */; }; - 0EF2863322CBB0250026C7A5 /* TagSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF2863222CBB0250026C7A5 /* TagSettingsViewOutput.swift */; }; - 0EF4E33D26824ABD00D83CC7 /* RuuviDFUError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF4E33C26824ABD00D83CC7 /* RuuviDFUError+LocalizedError.swift */; }; - 0EF4E33E26824ABD00D83CC7 /* RuuviDFUError+LocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF4E33C26824ABD00D83CC7 /* RuuviDFUError+LocalizedError.swift */; }; - 0EF4E34026824EF500D83CC7 /* DfuFirmware+Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF4E33F26824EF500D83CC7 /* DfuFirmware+Log.swift */; }; - 0EF4E34126824EF500D83CC7 /* DfuFirmware+Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF4E33F26824EF500D83CC7 /* DfuFirmware+Log.swift */; }; - 0EF5B72B22D62CD900D9D14A /* Date+Ruuvi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF5B72A22D62CD900D9D14A /* Date+Ruuvi.swift */; }; - 0EF5B75422DE153A00D9D14A /* HumidityUnit+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EF5B75322DE153A00D9D14A /* HumidityUnit+Localization.swift */; }; - 248444E4B7F8C3D6454D4D1B /* ShareModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5710E4EF18D419D01D60405E /* ShareModuleOutput.swift */; }; - 26BA929FDA200CCAC9964651 /* SharePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC1D67615D6DBA9E2FC5B402 /* SharePresenter.swift */; }; - 2BB81E4733D8EC40BECC68EF /* ShareViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 354B5B6F50E98F55D6A672BA /* ShareViewModel.swift */; }; - 340BE37227B54E25006D6C34 /* PresentationConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE37127B54E25006D6C34 /* PresentationConstants.swift */; }; - 340BE37327B54E26006D6C34 /* PresentationConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE37127B54E25006D6C34 /* PresentationConstants.swift */; }; - 340BE37527B54EE2006D6C34 /* AppAssemblyConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE37427B54EE2006D6C34 /* AppAssemblyConstants.swift */; }; - 340BE37627B54EE2006D6C34 /* AppAssemblyConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE37427B54EE2006D6C34 /* AppAssemblyConstants.swift */; }; - 340BE38627B54F37006D6C34 /* Owner.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 340BE37827B54F37006D6C34 /* Owner.storyboard */; }; - 340BE38727B54F37006D6C34 /* Owner.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 340BE37827B54F37006D6C34 /* Owner.storyboard */; }; - 340BE38827B54F37006D6C34 /* OwnerInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE37A27B54F37006D6C34 /* OwnerInitializer.swift */; }; - 340BE38927B54F37006D6C34 /* OwnerInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE37A27B54F37006D6C34 /* OwnerInitializer.swift */; }; - 340BE38A27B54F37006D6C34 /* OwnerConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE37B27B54F37006D6C34 /* OwnerConfigurator.swift */; }; - 340BE38B27B54F37006D6C34 /* OwnerConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE37B27B54F37006D6C34 /* OwnerConfigurator.swift */; }; - 340BE38C27B54F37006D6C34 /* OwnerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE37D27B54F37006D6C34 /* OwnerPresenter.swift */; }; - 340BE38D27B54F37006D6C34 /* OwnerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE37D27B54F37006D6C34 /* OwnerPresenter.swift */; }; - 340BE38E27B54F37006D6C34 /* OwnerModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE37E27B54F37006D6C34 /* OwnerModuleInput.swift */; }; - 340BE38F27B54F37006D6C34 /* OwnerModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE37E27B54F37006D6C34 /* OwnerModuleInput.swift */; }; - 340BE39027B54F37006D6C34 /* OwnerViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE38027B54F37006D6C34 /* OwnerViewInput.swift */; }; - 340BE39127B54F37006D6C34 /* OwnerViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE38027B54F37006D6C34 /* OwnerViewInput.swift */; }; - 340BE39227B54F37006D6C34 /* OwnerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE38127B54F37006D6C34 /* OwnerViewController.swift */; }; - 340BE39327B54F37006D6C34 /* OwnerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE38127B54F37006D6C34 /* OwnerViewController.swift */; }; - 340BE39427B54F37006D6C34 /* OwnerViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE38227B54F37006D6C34 /* OwnerViewOutput.swift */; }; - 340BE39527B54F38006D6C34 /* OwnerViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE38227B54F37006D6C34 /* OwnerViewOutput.swift */; }; - 340BE39627B54F38006D6C34 /* OwnerRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE38427B54F37006D6C34 /* OwnerRouter.swift */; }; - 340BE39727B54F38006D6C34 /* OwnerRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE38427B54F37006D6C34 /* OwnerRouter.swift */; }; - 340BE39827B54F38006D6C34 /* OwnerRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE38527B54F37006D6C34 /* OwnerRouterInput.swift */; }; - 340BE39927B54F38006D6C34 /* OwnerRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE38527B54F37006D6C34 /* OwnerRouterInput.swift */; }; - 340BE39B27B54FEC006D6C34 /* String+Email.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE39A27B54FEB006D6C34 /* String+Email.swift */; }; - 340BE39C27B54FEC006D6C34 /* String+Email.swift in Sources */ = {isa = PBXBuildFile; fileRef = 340BE39A27B54FEB006D6C34 /* String+Email.swift */; }; - 340BE39E27B56129006D6C34 /* ruuvi_logo_splash.png in Resources */ = {isa = PBXBuildFile; fileRef = 340BE39D27B56128006D6C34 /* ruuvi_logo_splash.png */; }; - 340BE39F27B56129006D6C34 /* ruuvi_logo_splash.png in Resources */ = {isa = PBXBuildFile; fileRef = 340BE39D27B56128006D6C34 /* ruuvi_logo_splash.png */; }; - 341401EC282D03C8003DE721 /* MeasurementService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341401EB282D03C8003DE721 /* MeasurementService.swift */; }; - 3414BFC82806D19C00C63BE9 /* RuuviCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3414BFC72806D19C00C63BE9 /* RuuviCodeView.swift */; }; - 3414BFC92806D19C00C63BE9 /* RuuviCodeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3414BFC72806D19C00C63BE9 /* RuuviCodeView.swift */; }; - 3414BFCB2806D1B300C63BE9 /* RuuviCodeTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3414BFCA2806D1B300C63BE9 /* RuuviCodeTextField.swift */; }; - 3414BFCC2806D1B300C63BE9 /* RuuviCodeTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3414BFCA2806D1B300C63BE9 /* RuuviCodeTextField.swift */; }; - 34238B2C062103E10D2BC65D /* SignInViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BD498E7491E278B4EF4919C /* SignInViewOutput.swift */; }; - 3490A4C327D9F2C80032BBAB /* UINavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3490A4C227D9F2C70032BBAB /* UINavigationController.swift */; }; - 3490A4C427D9F2C80032BBAB /* UINavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3490A4C227D9F2C70032BBAB /* UINavigationController.swift */; }; - 3493385B282FAB0D009060E8 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20C922B7A7200015F9E0 /* Localizable.strings */; }; - 3493385D28300396009060E8 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3493385C28300396009060E8 /* NetworkManager.swift */; }; - 3493385E28300679009060E8 /* MeasurementService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 341401EB282D03C8003DE721 /* MeasurementService.swift */; }; - 3493385F283006CB009060E8 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A8D4A1281ED018008A8698 /* Extensions.swift */; }; - 34933860283006F4009060E8 /* WidgetEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A8D4C5281EEC19008A8698 /* WidgetEntry.swift */; }; - 3493386328300A73009060E8 /* SimpleWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3493386228300A73009060E8 /* SimpleWidgetView.swift */; }; - 3493386528300ACC009060E8 /* UnauthorizedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3493386428300ACC009060E8 /* UnauthorizedView.swift */; }; - 3493386728300B06009060E8 /* EmptyWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3493386628300B05009060E8 /* EmptyWidgetView.swift */; }; - 3493386C28300C49009060E8 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3493386B28300C49009060E8 /* Constants.swift */; }; - 3493386D28300DC3009060E8 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3493386B28300C49009060E8 /* Constants.swift */; }; - 3493386F283014A0009060E8 /* Model+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3493386E283014A0009060E8 /* Model+Extension.swift */; }; - 34933870283014A0009060E8 /* Model+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3493386E283014A0009060E8 /* Model+Extension.swift */; }; - 34933873283014F6009060E8 /* WidgetSensorEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34933872283014F6009060E8 /* WidgetSensorEnum.swift */; }; - 34933874283014F6009060E8 /* WidgetSensorEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34933872283014F6009060E8 /* WidgetSensorEnum.swift */; }; - 34A8D48B281EBFD9008A8698 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34A8D48A281EBFD9008A8698 /* WidgetKit.framework */; }; - 34A8D48D281EBFD9008A8698 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34A8D48C281EBFD9008A8698 /* SwiftUI.framework */; }; - 34A8D490281EBFD9008A8698 /* RuuviWidgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A8D48F281EBFD9008A8698 /* RuuviWidgets.swift */; }; - 34A8D493281EBFDB008A8698 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 34A8D492281EBFDB008A8698 /* Assets.xcassets */; }; - 34A8D499281EBFDB008A8698 /* station_widgets.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 34A8D489281EBFD9008A8698 /* station_widgets.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 34A8D4A2281ED018008A8698 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A8D4A1281ED018008A8698 /* Extensions.swift */; }; - 34A8D4AA281ED046008A8698 /* Montserrat-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 34A8D4A4281ED046008A8698 /* Montserrat-Regular.ttf */; }; - 34A8D4AB281ED046008A8698 /* Montserrat-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 34A8D4A5281ED046008A8698 /* Montserrat-Bold.ttf */; }; - 34A8D4AC281ED046008A8698 /* Muli-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 34A8D4A6281ED046008A8698 /* Muli-Regular.ttf */; }; - 34A8D4AD281ED046008A8698 /* Oswald-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 34A8D4A7281ED046008A8698 /* Oswald-Bold.ttf */; }; - 34A8D4AE281ED046008A8698 /* Oswald-ExtraLight.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 34A8D4A8281ED046008A8698 /* Oswald-ExtraLight.ttf */; }; - 34A8D4AF281ED046008A8698 /* Muli-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 34A8D4A9281ED046008A8698 /* Muli-Bold.ttf */; }; - 34A8D4B7281EE5AE008A8698 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34A8D4B6281EE5AE008A8698 /* Intents.framework */; }; - 34A8D4BA281EE5AE008A8698 /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A8D4B9281EE5AE008A8698 /* IntentHandler.swift */; }; - 34A8D4BE281EE5AE008A8698 /* station_intents.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 34A8D4B5281EE5AE008A8698 /* station_intents.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 34A8D4C4281EEBF8008A8698 /* WidgetProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A8D4C3281EEBF8008A8698 /* WidgetProvider.swift */; }; - 34A8D4C6281EEC19008A8698 /* WidgetEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A8D4C5281EEC19008A8698 /* WidgetEntry.swift */; }; - 34D458E028216B2200EA9F93 /* WidgetAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D458DF28216B2200EA9F93 /* WidgetAssembly.swift */; }; - 34D458E228216C6900EA9F93 /* WidgetViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D458E128216C6900EA9F93 /* WidgetViewModel.swift */; }; - 34D458E328217BF600EA9F93 /* WidgetViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D458E128216C6900EA9F93 /* WidgetViewModel.swift */; }; - 34D458E428217C5900EA9F93 /* WidgetAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D458DF28216B2200EA9F93 /* WidgetAssembly.swift */; }; - 34D458E52821A06E00EA9F93 /* station_intents.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 34A8D4B5281EE5AE008A8698 /* station_intents.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 34D458E92821A07600EA9F93 /* station_widgets.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 34A8D489281EBFD9008A8698 /* station_widgets.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 34F266A52832489900AE79D9 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20C922B7A7200015F9E0 /* Localizable.strings */; }; - 3BA1E7A8054CF95D80BAE3F9 /* ShareViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE5C4AD5C54EF024669EAF47 /* ShareViewOutput.swift */; }; - 4F8FB6FCCB69D64B47FF440B /* ShareConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB681E62A66E5924A87859B1 /* ShareConfigurator.swift */; }; - 61E02A45E5B5666DBF1972A6 /* Pods_station_intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B004B50BE06AD9034B2EFCB4 /* Pods_station_intents.framework */; }; - 6204554EB76ED0EFDE0DC290 /* ShareRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD7AE39C23B8C52BB202BB5E /* ShareRouter.swift */; }; - 64333D2920B0C45900CDF4B6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64333D2820B0C45900CDF4B6 /* AppDelegate.swift */; }; - 64333D3020B0C45A00CDF4B6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 64333D2F20B0C45A00CDF4B6 /* Assets.xcassets */; }; - 64333D3320B0C45A00CDF4B6 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 64333D3120B0C45A00CDF4B6 /* LaunchScreen.storyboard */; }; - 64333D3E20B0C45A00CDF4B6 /* StationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64333D3D20B0C45A00CDF4B6 /* StationTests.swift */; }; - 643C651F21C38F490037BE5B /* Montserrat-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 643C651E21C38F490037BE5B /* Montserrat-Bold.ttf */; }; - 643EEC2B2266435100D4E837 /* Oswald-ExtraLight.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 643EEC2A2266435100D4E837 /* Oswald-ExtraLight.ttf */; }; - 64678191225D03300072856A /* Muli-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 64678190225D02CE0072856A /* Muli-Bold.ttf */; }; - 64678192225D03330072856A /* Muli-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6467818F225CFB170072856A /* Muli-Regular.ttf */; }; - 6486971020E0436A00CCD7C1 /* Oswald-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6486970F20E042E000CCD7C1 /* Oswald-Bold.ttf */; }; - 6486971220E0439200CCD7C1 /* Montserrat-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6486971120E0439200CCD7C1 /* Montserrat-Regular.ttf */; }; - 660EB29C266928E6000FD22B /* UIViewController+Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB29B266928E6000FD22B /* UIViewController+Alert.swift */; }; - 660EB29D266928E6000FD22B /* UIViewController+Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 660EB29B266928E6000FD22B /* UIViewController+Alert.swift */; }; - 66718A6C266BD0E800A380F8 /* Color+Ruuvi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A6B266BD0E800A380F8 /* Color+Ruuvi.swift */; }; - 66718A6D266BD0E800A380F8 /* Color+Ruuvi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66718A6B266BD0E800A380F8 /* Color+Ruuvi.swift */; }; - 66BC44952657AED400A03253 /* OffsetCorrection.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 66BC44832657AED400A03253 /* OffsetCorrection.storyboard */; }; - 66BC44962657AED400A03253 /* OffsetCorrection.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 66BC44832657AED400A03253 /* OffsetCorrection.storyboard */; }; - 66BC44982657AED400A03253 /* OffsetCorrectionAppleInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44862657AED400A03253 /* OffsetCorrectionAppleInitializer.swift */; }; - 66BC44992657AED400A03253 /* OffsetCorrectionAppleInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44862657AED400A03253 /* OffsetCorrectionAppleInitializer.swift */; }; - 66BC449B2657AED400A03253 /* OffsetCorrectionConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44872657AED400A03253 /* OffsetCorrectionConfigurator.swift */; }; - 66BC449C2657AED400A03253 /* OffsetCorrectionConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44872657AED400A03253 /* OffsetCorrectionConfigurator.swift */; }; - 66BC449E2657AED400A03253 /* OffsetCorrectionModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44892657AED400A03253 /* OffsetCorrectionModuleOutput.swift */; }; - 66BC449F2657AED400A03253 /* OffsetCorrectionModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44892657AED400A03253 /* OffsetCorrectionModuleOutput.swift */; }; - 66BC44A12657AED400A03253 /* OffsetCorrectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448A2657AED400A03253 /* OffsetCorrectionPresenter.swift */; }; - 66BC44A22657AED400A03253 /* OffsetCorrectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448A2657AED400A03253 /* OffsetCorrectionPresenter.swift */; }; - 66BC44A42657AED400A03253 /* OffsetCorrectionModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448B2657AED400A03253 /* OffsetCorrectionModuleInput.swift */; }; - 66BC44A52657AED400A03253 /* OffsetCorrectionModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448B2657AED400A03253 /* OffsetCorrectionModuleInput.swift */; }; - 66BC44A72657AED400A03253 /* OffsetCorrectionAppleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448E2657AED400A03253 /* OffsetCorrectionAppleViewController.swift */; }; - 66BC44A82657AED400A03253 /* OffsetCorrectionAppleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448E2657AED400A03253 /* OffsetCorrectionAppleViewController.swift */; }; - 66BC44AA2657AED400A03253 /* OffsetCorrectionViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448F2657AED400A03253 /* OffsetCorrectionViewInput.swift */; }; - 66BC44AB2657AED400A03253 /* OffsetCorrectionViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC448F2657AED400A03253 /* OffsetCorrectionViewInput.swift */; }; - 66BC44AD2657AED400A03253 /* OffsetCorrectionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44902657AED400A03253 /* OffsetCorrectionViewModel.swift */; }; - 66BC44AE2657AED400A03253 /* OffsetCorrectionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44902657AED400A03253 /* OffsetCorrectionViewModel.swift */; }; - 66BC44B02657AED400A03253 /* OffsetCorrectionViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44912657AED400A03253 /* OffsetCorrectionViewOutput.swift */; }; - 66BC44B12657AED400A03253 /* OffsetCorrectionViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44912657AED400A03253 /* OffsetCorrectionViewOutput.swift */; }; - 66BC44B32657AED400A03253 /* OffsetCorrectionRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44932657AED400A03253 /* OffsetCorrectionRouter.swift */; }; - 66BC44B42657AED400A03253 /* OffsetCorrectionRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44932657AED400A03253 /* OffsetCorrectionRouter.swift */; }; - 66BC44B62657AED400A03253 /* OffsetCorrectionRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44942657AED400A03253 /* OffsetCorrectionRouterInput.swift */; }; - 66BC44B72657AED400A03253 /* OffsetCorrectionRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66BC44942657AED400A03253 /* OffsetCorrectionRouterInput.swift */; }; - 706E22795B6DE254AF39BB12 /* Pods_stationTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9174E0B0C8F457647FEE639C /* Pods_stationTests.framework */; }; - 73949279A33A1BF08159FE0E /* Pods_station_dev.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7097B76856D5F01896F963EC /* Pods_station_dev.framework */; }; - 74E67721EFA7BF9397D52B1F /* SignInViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC59D3B5AD8926DBDD79AA1C /* SignInViewModel.swift */; }; - 898D45D0BF0ABBCB2E68FBE9 /* ShareInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 392F0E992BEAA3382C2CF709 /* ShareInitializer.swift */; }; - 8A37F49EA3B84BB415491B03 /* SignInModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B3006A5FB2173EC6AA2728D /* SignInModuleOutput.swift */; }; - A907BB1124AE620A009DA3DB /* UIWindow+Orientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A907BB1024AE620A009DA3DB /* UIWindow+Orientation.swift */; }; - A907BB1224AE620D009DA3DB /* UIWindow+Orientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A907BB1024AE620A009DA3DB /* UIWindow+Orientation.swift */; }; - A91D02EE2511207200694733 /* SelectionTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02DD2511207200694733 /* SelectionTableConfigurator.swift */; }; - A91D02EF2511207200694733 /* SelectionTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02DD2511207200694733 /* SelectionTableConfigurator.swift */; }; - A91D02F12511207200694733 /* SelectionTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02DE2511207200694733 /* SelectionTableInitializer.swift */; }; - A91D02F22511207200694733 /* SelectionTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02DE2511207200694733 /* SelectionTableInitializer.swift */; }; - A91D02F42511207300694733 /* SelectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E02511207200694733 /* SelectionPresenter.swift */; }; - A91D02F52511207300694733 /* SelectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E02511207200694733 /* SelectionPresenter.swift */; }; - A91D02F72511207300694733 /* SelectionModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E12511207200694733 /* SelectionModuleInput.swift */; }; - A91D02F82511207300694733 /* SelectionModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E12511207200694733 /* SelectionModuleInput.swift */; }; - A91D02FA2511207300694733 /* SelectionViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E32511207200694733 /* SelectionViewInput.swift */; }; - A91D02FB2511207300694733 /* SelectionViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E32511207200694733 /* SelectionViewInput.swift */; }; - A91D02FD2511207300694733 /* SelectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E52511207200694733 /* SelectionTableViewCell.swift */; }; - A91D02FE2511207300694733 /* SelectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E52511207200694733 /* SelectionTableViewCell.swift */; }; - A91D03002511207300694733 /* SelectionTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E62511207200694733 /* SelectionTableViewController.swift */; }; - A91D03012511207300694733 /* SelectionTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E62511207200694733 /* SelectionTableViewController.swift */; }; - A91D03032511207300694733 /* SelectionViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E72511207200694733 /* SelectionViewOutput.swift */; }; - A91D03042511207300694733 /* SelectionViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E72511207200694733 /* SelectionViewOutput.swift */; }; - A91D03062511207300694733 /* SelectionRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E92511207200694733 /* SelectionRouter.swift */; }; - A91D03072511207300694733 /* SelectionRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02E92511207200694733 /* SelectionRouter.swift */; }; - A91D03092511207300694733 /* SelectionRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02EA2511207200694733 /* SelectionRouterInput.swift */; }; - A91D030A2511207300694733 /* SelectionRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D02EA2511207200694733 /* SelectionRouterInput.swift */; }; - A91D030D251121C800694733 /* Selection.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A91D030C251121C800694733 /* Selection.storyboard */; }; - A91D030E251121C800694733 /* Selection.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A91D030C251121C800694733 /* Selection.storyboard */; }; - A91D0311251123B400694733 /* SelectionModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D0310251123B400694733 /* SelectionModuleOutput.swift */; }; - A91D0312251123B400694733 /* SelectionModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D0310251123B400694733 /* SelectionModuleOutput.swift */; }; - A91D0316251124F900694733 /* SelectionItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D0315251124F900694733 /* SelectionItem.swift */; }; - A91D0317251124F900694733 /* SelectionItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D0315251124F900694733 /* SelectionItem.swift */; }; - A91D031A25113EAA00694733 /* UnitPressure+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D031925113EAA00694733 /* UnitPressure+Extension.swift */; }; - A91D031B25113EAA00694733 /* UnitPressure+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A91D031925113EAA00694733 /* UnitPressure+Extension.swift */; }; - A92A66BD2450C640002918E7 /* UITableViewCell+ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92A66BC2450C640002918E7 /* UITableViewCell+ReusableView.swift */; }; - A92A66BE2450C64A002918E7 /* UITableViewCell+ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92A66BC2450C640002918E7 /* UITableViewCell+ReusableView.swift */; }; - A92E3C4C24261CF900D981D5 /* MeasurementType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92E3C4B24261CF900D981D5 /* MeasurementType.swift */; }; - A92E3C6C2426767E00D981D5 /* MeasurementType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92E3C4B24261CF900D981D5 /* MeasurementType.swift */; }; - A935E47625A49E8F009538C4 /* MeasurementsServiceFiSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = A935E47525A49E8F009538C4 /* MeasurementsServiceFiSpec.swift */; }; - A935E47D25A49E9E009538C4 /* MeasurementsServiceRuSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = A935E47C25A49E9E009538C4 /* MeasurementsServiceRuSpec.swift */; }; - A93CDCCF25659BA600018C6C /* AlertPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93CDCCE25659BA600018C6C /* AlertPresenter.swift */; }; - A93CDCD025659BA600018C6C /* AlertPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93CDCCE25659BA600018C6C /* AlertPresenter.swift */; }; - A93CDCDE25659BF600018C6C /* AlertPresenterImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93CDCDD25659BF600018C6C /* AlertPresenterImpl.swift */; }; - A93CDCDF25659BF600018C6C /* AlertPresenterImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93CDCDD25659BF600018C6C /* AlertPresenterImpl.swift */; }; - A949A83B24707FD0006B7F4F /* LocalizedCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949A83A24707FD0006B7F4F /* LocalizedCache.swift */; }; - A949A83C24707FDD006B7F4F /* LocalizedCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = A949A83A24707FD0006B7F4F /* LocalizedCache.swift */; }; - A94FFD48241C34EA00888017 /* MockAlertPersistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9100D82241AD1E4004007FD /* MockAlertPersistence.swift */; }; - A94FFD4A241D45C600888017 /* MockRuuviTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = A94FFD49241D45C600888017 /* MockRuuviTag.swift */; }; - A94FFD4C241D512900888017 /* MockLocalNotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A94FFD4B241D512900888017 /* MockLocalNotificationsManager.swift */; }; - A94FFD4E241D57E700888017 /* MockCalibrationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = A94FFD4D241D57E700888017 /* MockCalibrationService.swift */; }; - A94FFD50241D6BA300888017 /* MockAlertServiceObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = A94FFD4F241D6BA300888017 /* MockAlertServiceObserver.swift */; }; - A9646466247BAE6B0001D55D /* ChartSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646454247BAE6A0001D55D /* ChartSettingsViewInput.swift */; }; - A9646467247BAE6B0001D55D /* ChartSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646454247BAE6A0001D55D /* ChartSettingsViewInput.swift */; }; - A964646C247BAE6B0001D55D /* ChartSettingsStepperTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646458247BAE6A0001D55D /* ChartSettingsStepperTableViewCell.swift */; }; - A964646D247BAE6B0001D55D /* ChartSettingsStepperTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646458247BAE6A0001D55D /* ChartSettingsStepperTableViewCell.swift */; }; - A964646F247BAE6B0001D55D /* ChartSettingsSwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646459247BAE6A0001D55D /* ChartSettingsSwitchTableViewCell.swift */; }; - A9646470247BAE6B0001D55D /* ChartSettingsSwitchTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646459247BAE6A0001D55D /* ChartSettingsSwitchTableViewCell.swift */; }; - A9646472247BAE6B0001D55D /* ChartSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645A247BAE6A0001D55D /* ChartSettingsTableViewController.swift */; }; - A9646473247BAE6B0001D55D /* ChartSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645A247BAE6A0001D55D /* ChartSettingsTableViewController.swift */; }; - A9646475247BAE6B0001D55D /* ChartSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645B247BAE6A0001D55D /* ChartSettingsViewOutput.swift */; }; - A9646476247BAE6B0001D55D /* ChartSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645B247BAE6A0001D55D /* ChartSettingsViewOutput.swift */; }; - A9646478247BAE6B0001D55D /* ChartSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645C247BAE6A0001D55D /* ChartSettingsViewModel.swift */; }; - A9646479247BAE6B0001D55D /* ChartSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645C247BAE6A0001D55D /* ChartSettingsViewModel.swift */; }; - A964647B247BAE6B0001D55D /* ChartSettingsConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645E247BAE6A0001D55D /* ChartSettingsConfigurator.swift */; }; - A964647C247BAE6B0001D55D /* ChartSettingsConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645E247BAE6A0001D55D /* ChartSettingsConfigurator.swift */; }; - A964647E247BAE6B0001D55D /* ChartSettingsInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645F247BAE6A0001D55D /* ChartSettingsInitializer.swift */; }; - A964647F247BAE6B0001D55D /* ChartSettingsInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A964645F247BAE6A0001D55D /* ChartSettingsInitializer.swift */; }; - A9646481247BAE6B0001D55D /* ChartModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646461247BAE6A0001D55D /* ChartModuleInput.swift */; }; - A9646482247BAE6B0001D55D /* ChartModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646461247BAE6A0001D55D /* ChartModuleInput.swift */; }; - A9646484247BAE6B0001D55D /* ChartSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646462247BAE6A0001D55D /* ChartSettingsPresenter.swift */; }; - A9646485247BAE6B0001D55D /* ChartSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646462247BAE6A0001D55D /* ChartSettingsPresenter.swift */; }; - A9646487247BAE6B0001D55D /* ChartSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646464247BAE6A0001D55D /* ChartSettingsRouterInput.swift */; }; - A9646488247BAE6B0001D55D /* ChartSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646464247BAE6A0001D55D /* ChartSettingsRouterInput.swift */; }; - A964648A247BAE6B0001D55D /* ChartSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646465247BAE6A0001D55D /* ChartSettingsRouter.swift */; }; - A964648B247BAE6B0001D55D /* ChartSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9646465247BAE6A0001D55D /* ChartSettingsRouter.swift */; }; - A964648E247BAEBA0001D55D /* ChartSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A964648D247BAEBA0001D55D /* ChartSettings.storyboard */; }; - A964648F247BAEBA0001D55D /* ChartSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A964648D247BAEBA0001D55D /* ChartSettings.storyboard */; }; - A971B0DC24215334008EF50D /* XCTest+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = A971B0DB24215334008EF50D /* XCTest+Extension.swift */; }; - A976CA7E24A928C20099BDC1 /* ChartSettingsDisclosureTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A976CA7D24A928C20099BDC1 /* ChartSettingsDisclosureTableViewCell.swift */; }; - A976CA7F24A928C20099BDC1 /* ChartSettingsDisclosureTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A976CA7D24A928C20099BDC1 /* ChartSettingsDisclosureTableViewCell.swift */; }; - A980573825807118000D03AB /* AboutViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A980573725807118000D03AB /* AboutViewModel.swift */; }; - A980573925807118000D03AB /* AboutViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A980573725807118000D03AB /* AboutViewModel.swift */; }; - A98CCBB3BAF61A33CE4A2D1B /* Pods_station.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8018B7836CF8C748718825DD /* Pods_station.framework */; }; - A98D3F06256CBD410066588B /* ShareModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AE2284D927021C0BEA560B0 /* ShareModuleInput.swift */; }; - A98D3F0C256CBD600066588B /* ShareConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB681E62A66E5924A87859B1 /* ShareConfigurator.swift */; }; - A98D3F0D256CBD600066588B /* ShareInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 392F0E992BEAA3382C2CF709 /* ShareInitializer.swift */; }; - A98D3F0E256CBD600066588B /* ShareRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9546F1EFEE8F8CFC22377BB4 /* ShareRouterInput.swift */; }; - A98D3F0F256CBD600066588B /* ShareViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 167F75FD2FDAD002C10686FA /* ShareViewInput.swift */; }; - A98D3F10256CBD600066588B /* ShareViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 354B5B6F50E98F55D6A672BA /* ShareViewModel.swift */; }; - A98D3F11256CBD600066588B /* ShareRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD7AE39C23B8C52BB202BB5E /* ShareRouter.swift */; }; - A98D3F12256CBD600066588B /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC417B8977A47FFAE71585F0 /* ShareViewController.swift */; }; - A98D3F13256CBD600066588B /* SharePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC1D67615D6DBA9E2FC5B402 /* SharePresenter.swift */; }; - A98D3F14256CBD600066588B /* ShareModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5710E4EF18D419D01D60405E /* ShareModuleOutput.swift */; }; - A98D3F15256CBD600066588B /* ShareViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE5C4AD5C54EF024669EAF47 /* ShareViewOutput.swift */; }; - A9A48A5D244CD9EB0004FD50 /* UIWindow+Shake.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9A48A5B244CD9E70004FD50 /* UIWindow+Shake.swift */; }; - A9A67BFA24C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9A67BF924C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift */; }; - A9A67BFB24C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9A67BF924C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift */; }; - A9B57441253B994700DB7353 /* SignInRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E816312622E83E3B42001DC /* SignInRouterInput.swift */; }; - A9B57442253B994700DB7353 /* SignInRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F0552F1D17F403B7DE508B5 /* SignInRouter.swift */; }; - A9B57443253B994700DB7353 /* SignInViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A7D6325DFC865D2D11BD1D1 /* SignInViewInput.swift */; }; - A9B57446253B994700DB7353 /* SignInModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 87EFB230083D471777FBE5D0 /* SignInModuleInput.swift */; }; - A9B57447253B994700DB7353 /* SignInModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B3006A5FB2173EC6AA2728D /* SignInModuleOutput.swift */; }; - A9B57448253B994700DB7353 /* SignInViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC59D3B5AD8926DBDD79AA1C /* SignInViewModel.swift */; }; - A9B5744A253B994700DB7353 /* SignInViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BD498E7491E278B4EF4919C /* SignInViewOutput.swift */; }; - A9BB94CC2540AB610042B190 /* AlertViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BB94CB2540AB610042B190 /* AlertViewModel.swift */; }; - A9BB94CD2540AB610042B190 /* AlertViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BB94CB2540AB610042B190 /* AlertViewModel.swift */; }; - A9BD38BA24F6108300904BBE /* Humidity+Offset.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BD38B924F6108300904BBE /* Humidity+Offset.swift */; }; - A9BD38BB24F6108300904BBE /* Humidity+Offset.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9BD38B924F6108300904BBE /* Humidity+Offset.swift */; }; - A9E5994025572CF700F9E5CC /* Share.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A9E5993F25572CF700F9E5CC /* Share.storyboard */; }; - A9E5994125572CF700F9E5CC /* Share.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A9E5993F25572CF700F9E5CC /* Share.storyboard */; }; - A9E5994A2557341F00F9E5CC /* ShareDescriptionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E599492557341F00F9E5CC /* ShareDescriptionTableViewCell.swift */; }; - A9E5994B2557341F00F9E5CC /* ShareDescriptionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E599492557341F00F9E5CC /* ShareDescriptionTableViewCell.swift */; }; - A9E599582557345200F9E5CC /* ShareEmailInputTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E599572557345200F9E5CC /* ShareEmailInputTableViewCell.swift */; }; - A9E599592557345200F9E5CC /* ShareEmailInputTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E599572557345200F9E5CC /* ShareEmailInputTableViewCell.swift */; }; - A9E599612557346600F9E5CC /* ShareSendButtonTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E599602557346600F9E5CC /* ShareSendButtonTableViewCell.swift */; }; - A9E599622557346600F9E5CC /* ShareSendButtonTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E599602557346600F9E5CC /* ShareSendButtonTableViewCell.swift */; }; - A9E5996A255734A000F9E5CC /* ShareEmailTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E59969255734A000F9E5CC /* ShareEmailTableViewCell.swift */; }; - A9E5996B255734A000F9E5CC /* ShareEmailTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E59969255734A000F9E5CC /* ShareEmailTableViewCell.swift */; }; - A9E6774825A33081000B75A3 /* String+Characters.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E6774725A33081000B75A3 /* String+Characters.swift */; }; - A9E6774925A33081000B75A3 /* String+Characters.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E6774725A33081000B75A3 /* String+Characters.swift */; }; - A9E6774B25A33081000B75A3 /* String+Characters.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E6774725A33081000B75A3 /* String+Characters.swift */; }; - A9E6775125A331D6000B75A3 /* MeasurementsServiceEnSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E6770D25A30D0A000B75A3 /* MeasurementsServiceEnSpec.swift */; }; - A9E6775C25A331E1000B75A3 /* MeasurementsServiceSvSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E6771925A31556000B75A3 /* MeasurementsServiceSvSpec.swift */; }; - A9FC78E92579671B00F94604 /* UniversalLinkCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FC78E82579671B00F94604 /* UniversalLinkCoordinator.swift */; }; - A9FC78EA2579671B00F94604 /* UniversalLinkCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FC78E82579671B00F94604 /* UniversalLinkCoordinator.swift */; }; - A9FC78FF2579675100F94604 /* UniversalLinkRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FC78FE2579675100F94604 /* UniversalLinkRouter.swift */; }; - A9FC79002579675100F94604 /* UniversalLinkRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FC78FE2579675100F94604 /* UniversalLinkRouter.swift */; }; - A9FC790E2579676E00F94604 /* UniversalLinkRouterImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FC790D2579676E00F94604 /* UniversalLinkRouterImpl.swift */; }; - A9FC790F2579676E00F94604 /* UniversalLinkRouterImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FC790D2579676E00F94604 /* UniversalLinkRouterImpl.swift */; }; - A9FC79172579678D00F94604 /* UniversalLinkCoordinatormpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FC79162579678D00F94604 /* UniversalLinkCoordinatormpl.swift */; }; - A9FC79182579678D00F94604 /* UniversalLinkCoordinatormpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9FC79162579678D00F94604 /* UniversalLinkCoordinatormpl.swift */; }; - ABCA915676F9A8C975D9F2A3 /* SignInViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A7D6325DFC865D2D11BD1D1 /* SignInViewInput.swift */; }; - B198F488C89E6DFFD1EECAF3 /* ShareRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9546F1EFEE8F8CFC22377BB4 /* ShareRouterInput.swift */; }; - B2A3FB2578B246F6CBBF0CA9 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC417B8977A47FFAE71585F0 /* ShareViewController.swift */; }; - B6FA27492FB1F63393783EFC /* ShareViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 167F75FD2FDAD002C10686FA /* ShareViewInput.swift */; }; - C9D6ACA6CB9694F6C33414CE /* ShareModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6AE2284D927021C0BEA560B0 /* ShareModuleInput.swift */; }; - D037B55274A07756F884696B /* SignInRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6F0552F1D17F403B7DE508B5 /* SignInRouter.swift */; }; - D54F2103EF7E3360E7D09BC4 /* Pods_station_widgets.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D63A307EB55306A1D598FDAE /* Pods_station_widgets.framework */; }; - E1072687291C49E500247625 /* SimpleWidgetViewInline.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1072686291C49E500247625 /* SimpleWidgetViewInline.swift */; }; - E10E18722978AF3D002C78C3 /* TagSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18712978AF3D002C78C3 /* TagSettingsViewModel.swift */; }; - E10E18732978AF3D002C78C3 /* TagSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18712978AF3D002C78C3 /* TagSettingsViewModel.swift */; }; - E10E18AB297D6664002C78C3 /* RuuviCloudModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18AA297D6664002C78C3 /* RuuviCloudModuleFactory.swift */; }; - E10E18AC297D6664002C78C3 /* RuuviCloudModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18AA297D6664002C78C3 /* RuuviCloudModuleFactory.swift */; }; - E10E18AE297D6672002C78C3 /* RuuviCloudPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18AD297D6672002C78C3 /* RuuviCloudPresenter.swift */; }; - E10E18AF297D6672002C78C3 /* RuuviCloudPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18AD297D6672002C78C3 /* RuuviCloudPresenter.swift */; }; - E10E18B1297D6690002C78C3 /* RuuviCloudTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18B0297D6690002C78C3 /* RuuviCloudTableViewController.swift */; }; - E10E18B2297D6690002C78C3 /* RuuviCloudTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18B0297D6690002C78C3 /* RuuviCloudTableViewController.swift */; }; - E10E18B4297D67B8002C78C3 /* RuuviCloudViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18B3297D67B8002C78C3 /* RuuviCloudViewModel.swift */; }; - E10E18B5297D67B8002C78C3 /* RuuviCloudViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18B3297D67B8002C78C3 /* RuuviCloudViewModel.swift */; }; - E10E18B7297D67E8002C78C3 /* RuuviCloudViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18B6297D67E8002C78C3 /* RuuviCloudViewInput.swift */; }; - E10E18B8297D67E8002C78C3 /* RuuviCloudViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18B6297D67E8002C78C3 /* RuuviCloudViewInput.swift */; }; - E10E18BA297D67FC002C78C3 /* RuuviCloudViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18B9297D67FC002C78C3 /* RuuviCloudViewOutput.swift */; }; - E10E18BB297D67FC002C78C3 /* RuuviCloudViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18B9297D67FC002C78C3 /* RuuviCloudViewOutput.swift */; }; - E10E18BD297D68EB002C78C3 /* RuuviCloudModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18BC297D68EB002C78C3 /* RuuviCloudModuleInput.swift */; }; - E10E18BE297D68EB002C78C3 /* RuuviCloudModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18BC297D68EB002C78C3 /* RuuviCloudModuleInput.swift */; }; - E10E18C1297DD0CA002C78C3 /* RuuviCloudTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18C0297DD0CA002C78C3 /* RuuviCloudTableViewCell.swift */; }; - E10E18C2297DD0CA002C78C3 /* RuuviCloudTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18C0297DD0CA002C78C3 /* RuuviCloudTableViewCell.swift */; }; - E10E18C4297DE3AF002C78C3 /* TagChartsMarkerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18C3297DE3AF002C78C3 /* TagChartsMarkerView.swift */; }; - E10E18C5297DE3AF002C78C3 /* TagChartsMarkerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E10E18C3297DE3AF002C78C3 /* TagChartsMarkerView.swift */; }; - E1117008291C34A700ACCD72 /* SimpleWidgetViewRectangle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1117007291C34A700ACCD72 /* SimpleWidgetViewRectangle.swift */; }; - E116706F29620AD4002DF7BF /* BackgroundSelectionButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E116706E29620AD4002DF7BF /* BackgroundSelectionButtonView.swift */; }; - E116707029620AD4002DF7BF /* BackgroundSelectionButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E116706E29620AD4002DF7BF /* BackgroundSelectionButtonView.swift */; }; - E116707629634332002DF7BF /* BackgroundSelectionViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E116707529634332002DF7BF /* BackgroundSelectionViewInput.swift */; }; - E116707729634332002DF7BF /* BackgroundSelectionViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E116707529634332002DF7BF /* BackgroundSelectionViewInput.swift */; }; - E116707929634363002DF7BF /* BackgroundSelectionViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E116707829634363002DF7BF /* BackgroundSelectionViewOutput.swift */; }; - E116707A29634363002DF7BF /* BackgroundSelectionViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E116707829634363002DF7BF /* BackgroundSelectionViewOutput.swift */; }; - E1167082296346D5002DF7BF /* BackgroundSelectionModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1167081296346D5002DF7BF /* BackgroundSelectionModuleInput.swift */; }; - E1167083296346D5002DF7BF /* BackgroundSelectionModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1167081296346D5002DF7BF /* BackgroundSelectionModuleInput.swift */; }; - E116708529634708002DF7BF /* BackgroundSelectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E116708429634708002DF7BF /* BackgroundSelectionPresenter.swift */; }; - E116708629634708002DF7BF /* BackgroundSelectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E116708429634708002DF7BF /* BackgroundSelectionPresenter.swift */; }; - E116708829634815002DF7BF /* BackgroundSelectionModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E116708729634815002DF7BF /* BackgroundSelectionModuleFactory.swift */; }; - E116708929634815002DF7BF /* BackgroundSelectionModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E116708729634815002DF7BF /* BackgroundSelectionModuleFactory.swift */; }; - E116708C29634D91002DF7BF /* BackgroundSelectionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E116708B29634D91002DF7BF /* BackgroundSelectionViewModel.swift */; }; - E116708D29634D91002DF7BF /* BackgroundSelectionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E116708B29634D91002DF7BF /* BackgroundSelectionViewModel.swift */; }; - E116708F29635B53002DF7BF /* BackgroundSelectionUploadProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E116708E29635B53002DF7BF /* BackgroundSelectionUploadProgressView.swift */; }; - E116709029635B53002DF7BF /* BackgroundSelectionUploadProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E116708E29635B53002DF7BF /* BackgroundSelectionUploadProgressView.swift */; }; - E116AED22A059578003EF65A /* ruuvi_speak.caf in Resources */ = {isa = PBXBuildFile; fileRef = E116AED12A059578003EF65A /* ruuvi_speak.caf */; }; - E116AED32A059578003EF65A /* ruuvi_speak.caf in Resources */ = {isa = PBXBuildFile; fileRef = E116AED12A059578003EF65A /* ruuvi_speak.caf */; }; - E116AED42A059578003EF65A /* ruuvi_speak.caf in Resources */ = {isa = PBXBuildFile; fileRef = E116AED12A059578003EF65A /* ruuvi_speak.caf */; }; - E11989F529B7A46E002245CF /* UIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11989F429B7A46E002245CF /* UIView+Extension.swift */; }; - E11989F629B7A46E002245CF /* UIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11989F429B7A46E002245CF /* UIView+Extension.swift */; }; - E11989FF29BA60CE002245CF /* AppearanceSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11989FE29BA60CE002245CF /* AppearanceSettingsTableViewController.swift */; }; - E1198A0029BA60CE002245CF /* AppearanceSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11989FE29BA60CE002245CF /* AppearanceSettingsTableViewController.swift */; }; - E1198A0229BA6193002245CF /* AppearanceSettingsTableViewBasicCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A0129BA6193002245CF /* AppearanceSettingsTableViewBasicCell.swift */; }; - E1198A0329BA6193002245CF /* AppearanceSettingsTableViewBasicCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A0129BA6193002245CF /* AppearanceSettingsTableViewBasicCell.swift */; }; - E1198A0829BA68B6002245CF /* AppearanceSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A0729BA68B6002245CF /* AppearanceSettingsRouterInput.swift */; }; - E1198A0929BA68B6002245CF /* AppearanceSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A0729BA68B6002245CF /* AppearanceSettingsRouterInput.swift */; }; - E1198A0B29BA68BE002245CF /* AppearanceSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A0A29BA68BE002245CF /* AppearanceSettingsRouter.swift */; }; - E1198A0C29BA68BE002245CF /* AppearanceSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A0A29BA68BE002245CF /* AppearanceSettingsRouter.swift */; }; - E1198A0E29BA68FD002245CF /* AppearanceSettingsModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A0D29BA68FD002245CF /* AppearanceSettingsModuleFactory.swift */; }; - E1198A0F29BA68FD002245CF /* AppearanceSettingsModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A0D29BA68FD002245CF /* AppearanceSettingsModuleFactory.swift */; }; - E1198A1129BA6910002245CF /* AppearanceSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A1029BA6910002245CF /* AppearanceSettingsPresenter.swift */; }; - E1198A1229BA6910002245CF /* AppearanceSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A1029BA6910002245CF /* AppearanceSettingsPresenter.swift */; }; - E1198A1529BA6A06002245CF /* AppearanceSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A1429BA6A06002245CF /* AppearanceSettingsViewOutput.swift */; }; - E1198A1629BA6A06002245CF /* AppearanceSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A1429BA6A06002245CF /* AppearanceSettingsViewOutput.swift */; }; - E1198A1829BA6A61002245CF /* AppearanceSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A1729BA6A61002245CF /* AppearanceSettingsViewInput.swift */; }; - E1198A1929BA6A61002245CF /* AppearanceSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A1729BA6A61002245CF /* AppearanceSettingsViewInput.swift */; }; - E1198A1B29BA6A79002245CF /* AppearanceSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A1A29BA6A79002245CF /* AppearanceSettingsViewModel.swift */; }; - E1198A1C29BA6A79002245CF /* AppearanceSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A1A29BA6A79002245CF /* AppearanceSettingsViewModel.swift */; }; - E1198A1E29BA6B7E002245CF /* AppearanceSettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A1D29BA6B7E002245CF /* AppearanceSettingsModuleInput.swift */; }; - E1198A1F29BA6B7E002245CF /* AppearanceSettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A1D29BA6B7E002245CF /* AppearanceSettingsModuleInput.swift */; }; - E1198A2129BA6EC6002245CF /* RuuviTheme+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A2029BA6EC6002245CF /* RuuviTheme+Extension.swift */; }; - E1198A2229BA6EC6002245CF /* RuuviTheme+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A2029BA6EC6002245CF /* RuuviTheme+Extension.swift */; }; - E1198A2629BA763F002245CF /* ASSelectionModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A2529BA763F002245CF /* ASSelectionModuleFactory.swift */; }; - E1198A2729BA763F002245CF /* ASSelectionModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A2529BA763F002245CF /* ASSelectionModuleFactory.swift */; }; - E1198A2C29BA769A002245CF /* ASSelectionTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A2B29BA769A002245CF /* ASSelectionTableViewController.swift */; }; - E1198A2D29BA769A002245CF /* ASSelectionTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A2B29BA769A002245CF /* ASSelectionTableViewController.swift */; }; - E1198A2F29BA76A8002245CF /* ASSelectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A2E29BA76A8002245CF /* ASSelectionTableViewCell.swift */; }; - E1198A3029BA76A8002245CF /* ASSelectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A2E29BA76A8002245CF /* ASSelectionTableViewCell.swift */; }; - E1198A3229BA76C1002245CF /* ASSelectionViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A3129BA76C1002245CF /* ASSelectionViewOutput.swift */; }; - E1198A3329BA76C1002245CF /* ASSelectionViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A3129BA76C1002245CF /* ASSelectionViewOutput.swift */; }; - E1198A3529BA76CB002245CF /* ASSelectionViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A3429BA76CB002245CF /* ASSelectionViewInput.swift */; }; - E1198A3629BA76CB002245CF /* ASSelectionViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A3429BA76CB002245CF /* ASSelectionViewInput.swift */; }; - E1198A3829BA76DD002245CF /* ASSelectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A3729BA76DD002245CF /* ASSelectionPresenter.swift */; }; - E1198A3929BA76DD002245CF /* ASSelectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A3729BA76DD002245CF /* ASSelectionPresenter.swift */; }; - E1198A3B29BA76F1002245CF /* ASSelectionModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A3A29BA76F1002245CF /* ASSelectionModuleInput.swift */; }; - E1198A3C29BA76F1002245CF /* ASSelectionModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1198A3A29BA76F1002245CF /* ASSelectionModuleInput.swift */; }; - E11FDA6A29A1757C003ADA7B /* splash_bg_layer_dark.jpg in Resources */ = {isa = PBXBuildFile; fileRef = E11FDA6929A1757C003ADA7B /* splash_bg_layer_dark.jpg */; }; - E11FDA6B29A1757C003ADA7B /* splash_bg_layer_dark.jpg in Resources */ = {isa = PBXBuildFile; fileRef = E11FDA6929A1757C003ADA7B /* splash_bg_layer_dark.jpg */; }; - E11FDA6D29A2A3C2003ADA7B /* DefaultsPlainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11FDA6C29A2A3C2003ADA7B /* DefaultsPlainTableViewCell.swift */; }; - E11FDA6E29A2A3C6003ADA7B /* DefaultsPlainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11FDA6C29A2A3C2003ADA7B /* DefaultsPlainTableViewCell.swift */; }; - E11FDA7029A3F78D003ADA7B /* RuuviSimpleViewCompositionalLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11FDA6F29A3F78D003ADA7B /* RuuviSimpleViewCompositionalLayout.swift */; }; - E11FDA7129A3F78D003ADA7B /* RuuviSimpleViewCompositionalLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11FDA6F29A3F78D003ADA7B /* RuuviSimpleViewCompositionalLayout.swift */; }; - E128160B292ABCFA008E9282 /* SimpleWidgetViewCircular.swift in Sources */ = {isa = PBXBuildFile; fileRef = E128160A292ABCFA008E9282 /* SimpleWidgetViewCircular.swift */; }; - E1395BEA294F6C2A00C403C6 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1395BE9294F6C2A00C403C6 /* String+Localization.swift */; }; - E1395BEB294F6C2A00C403C6 /* String+Localization.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1395BE9294F6C2A00C403C6 /* String+Localization.swift */; }; - E1395BF1294F793000C403C6 /* AppDateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1395BF0294F793000C403C6 /* AppDateFormatter.swift */; }; - E1395BF2294F793000C403C6 /* AppDateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1395BF0294F793000C403C6 /* AppDateFormatter.swift */; }; - E1395BF92954DAA200C403C6 /* CardsInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1395BF82954DAA200C403C6 /* CardsInteractorInput.swift */; }; - E1395BFA2954DAA200C403C6 /* CardsInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1395BF82954DAA200C403C6 /* CardsInteractorInput.swift */; }; - E1395BFC2954DAAD00C403C6 /* CardsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1395BFB2954DAAD00C403C6 /* CardsInteractor.swift */; }; - E1395BFD2954DAAD00C403C6 /* CardsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1395BFB2954DAAD00C403C6 /* CardsInteractor.swift */; }; - E1395C002957944E00C403C6 /* CardsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1395BFF2957944E00C403C6 /* CardsViewController.swift */; }; - E1395C012957944E00C403C6 /* CardsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1395BFF2957944E00C403C6 /* CardsViewController.swift */; }; - E1395C032958A2A900C403C6 /* CardsIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1395C022958A2A900C403C6 /* CardsIndicatorView.swift */; }; - E1395C042958A2A900C403C6 /* CardsIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1395C022958A2A900C403C6 /* CardsIndicatorView.swift */; }; - E1395C062958A33400C403C6 /* CardsBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1395C052958A33400C403C6 /* CardsBackgroundView.swift */; }; - E1395C072958A33400C403C6 /* CardsBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1395C052958A33400C403C6 /* CardsBackgroundView.swift */; }; - E1597A2D295B6E6B00DFB70B /* UIFont+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A2C295B6E6B00DFB70B /* UIFont+Extension.swift */; }; - E1597A2E295B6E6B00DFB70B /* UIFont+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A2C295B6E6B00DFB70B /* UIFont+Extension.swift */; }; - E1597A30295B909B00DFB70B /* DashboardPlainCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A2F295B909B00DFB70B /* DashboardPlainCell.swift */; }; - E1597A31295B909B00DFB70B /* DashboardPlainCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A2F295B909B00DFB70B /* DashboardPlainCell.swift */; }; - E1597A33295CC4F900DFB70B /* LowBatteryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A32295CC4F900DFB70B /* LowBatteryView.swift */; }; - E1597A34295CC4F900DFB70B /* LowBatteryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A32295CC4F900DFB70B /* LowBatteryView.swift */; }; - E1597A3D295CD52A00DFB70B /* DashboardRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A3C295CD52A00DFB70B /* DashboardRouterInput.swift */; }; - E1597A3E295CD52A00DFB70B /* DashboardRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A3C295CD52A00DFB70B /* DashboardRouterInput.swift */; }; - E1597A40295CD55300DFB70B /* DashboardRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A3F295CD55300DFB70B /* DashboardRouter.swift */; }; - E1597A41295CD55300DFB70B /* DashboardRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A3F295CD55300DFB70B /* DashboardRouter.swift */; }; - E1597A43295CD58600DFB70B /* DashboardRouterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A42295CD58600DFB70B /* DashboardRouterDelegate.swift */; }; - E1597A44295CD58600DFB70B /* DashboardRouterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A42295CD58600DFB70B /* DashboardRouterDelegate.swift */; }; - E1597A46295CD5E400DFB70B /* DashboardModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A45295CD5E400DFB70B /* DashboardModuleInput.swift */; }; - E1597A47295CD5E400DFB70B /* DashboardModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A45295CD5E400DFB70B /* DashboardModuleInput.swift */; }; - E1597A49295CD5F800DFB70B /* DashboardPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A48295CD5F800DFB70B /* DashboardPresenter.swift */; }; - E1597A4A295CD5F800DFB70B /* DashboardPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A48295CD5F800DFB70B /* DashboardPresenter.swift */; }; - E1597A4C295CD66500DFB70B /* DashboardInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A4B295CD66500DFB70B /* DashboardInteractorInput.swift */; }; - E1597A4D295CD66500DFB70B /* DashboardInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A4B295CD66500DFB70B /* DashboardInteractorInput.swift */; }; - E1597A4F295CD67900DFB70B /* DashboardInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A4E295CD67900DFB70B /* DashboardInteractor.swift */; }; - E1597A50295CD67900DFB70B /* DashboardInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A4E295CD67900DFB70B /* DashboardInteractor.swift */; }; - E1597A52295CD6BB00DFB70B /* DashboardViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A51295CD6BB00DFB70B /* DashboardViewInput.swift */; }; - E1597A53295CD6BB00DFB70B /* DashboardViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A51295CD6BB00DFB70B /* DashboardViewInput.swift */; }; - E1597A55295CD6E300DFB70B /* DashboardViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A54295CD6E300DFB70B /* DashboardViewOutput.swift */; }; - E1597A56295CD6E300DFB70B /* DashboardViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A54295CD6E300DFB70B /* DashboardViewOutput.swift */; }; - E1597A5C295E24D400DFB70B /* RuuviAssets.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A5B295E24D400DFB70B /* RuuviAssets.swift */; }; - E1597A5D295E24D400DFB70B /* RuuviAssets.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A5B295E24D400DFB70B /* RuuviAssets.swift */; }; - E1597A5F295F803400DFB70B /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A5E295F803400DFB70B /* UIColor+Extension.swift */; }; - E1597A60295F803400DFB70B /* UIColor+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A5E295F803400DFB70B /* UIColor+Extension.swift */; }; - E1597A6529608CF300DFB70B /* GlobalHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A6429608CF300DFB70B /* GlobalHelpers.swift */; }; - E1597A6629608CF300DFB70B /* GlobalHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A6429608CF300DFB70B /* GlobalHelpers.swift */; }; - E1597A682960944600DFB70B /* DashboardCellDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A672960944600DFB70B /* DashboardCellDelegate.swift */; }; - E1597A692960944600DFB70B /* DashboardCellDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A672960944600DFB70B /* DashboardCellDelegate.swift */; }; - E1597A6F2961FEB800DFB70B /* BackgroundSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A6E2961FEB800DFB70B /* BackgroundSelectionViewController.swift */; }; - E1597A702961FEB900DFB70B /* BackgroundSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A6E2961FEB800DFB70B /* BackgroundSelectionViewController.swift */; }; - E1597A722962000B00DFB70B /* BackgroundSelectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A712962000B00DFB70B /* BackgroundSelectionViewCell.swift */; }; - E1597A732962000B00DFB70B /* BackgroundSelectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A712962000B00DFB70B /* BackgroundSelectionViewCell.swift */; }; - E1597A752962046500DFB70B /* BackgroundSelectionViewHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A742962046500DFB70B /* BackgroundSelectionViewHeader.swift */; }; - E1597A762962046500DFB70B /* BackgroundSelectionViewHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1597A742962046500DFB70B /* BackgroundSelectionViewHeader.swift */; }; - E16051E6285A15A1003FCA70 /* RuuviTagBatteryStatusProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16051E5285A15A1003FCA70 /* RuuviTagBatteryStatusProvider.swift */; }; - E16051E7285A15A1003FCA70 /* RuuviTagBatteryStatusProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16051E5285A15A1003FCA70 /* RuuviTagBatteryStatusProvider.swift */; }; - E16051E9285CB384003FCA70 /* AppStoreReviewHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16051E8285CB384003FCA70 /* AppStoreReviewHelper.swift */; }; - E16051EA285CB384003FCA70 /* AppStoreReviewHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16051E8285CB384003FCA70 /* AppStoreReviewHelper.swift */; }; - E16051EC285CBA57003FCA70 /* FileManager+Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16051EB285CBA57003FCA70 /* FileManager+Date.swift */; }; - E16051ED285CBA57003FCA70 /* FileManager+Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16051EB285CBA57003FCA70 /* FileManager+Date.swift */; }; - E168B4AB2885C28000D6B5C6 /* MeasurementAccuracyTitles.swift in Sources */ = {isa = PBXBuildFile; fileRef = E168B4AA2885C28000D6B5C6 /* MeasurementAccuracyTitles.swift */; }; - E168B4AC2885C28000D6B5C6 /* MeasurementAccuracyTitles.swift in Sources */ = {isa = PBXBuildFile; fileRef = E168B4AA2885C28000D6B5C6 /* MeasurementAccuracyTitles.swift */; }; - E168B4AE2886AE4E00D6B5C6 /* MeasurementAccuracyType+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E168B4AD2886AE4E00D6B5C6 /* MeasurementAccuracyType+Extension.swift */; }; - E168B4AF2886AE4E00D6B5C6 /* MeasurementAccuracyType+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E168B4AD2886AE4E00D6B5C6 /* MeasurementAccuracyType+Extension.swift */; }; - E168B4B62886AF1200D6B5C6 /* UnitSettingsType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E168B4B52886AF1200D6B5C6 /* UnitSettingsType.swift */; }; - E168B4B72886AF1200D6B5C6 /* UnitSettingsType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E168B4B52886AF1200D6B5C6 /* UnitSettingsType.swift */; }; - E16B8F3C28D109DD0025B92D /* MyRuuvi.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E16B8F3B28D109DD0025B92D /* MyRuuvi.storyboard */; }; - E16B8F3D28D109DD0025B92D /* MyRuuvi.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E16B8F3B28D109DD0025B92D /* MyRuuvi.storyboard */; }; - E16B8F3F28D10CF50025B92D /* MyRuuviAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F3E28D10CF50025B92D /* MyRuuviAccountViewController.swift */; }; - E16B8F4028D10CF50025B92D /* MyRuuviAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F3E28D10CF50025B92D /* MyRuuviAccountViewController.swift */; }; - E16B8F4228D10DF90025B92D /* MyRuuviAccountViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F4128D10DF90025B92D /* MyRuuviAccountViewInput.swift */; }; - E16B8F4328D10DF90025B92D /* MyRuuviAccountViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F4128D10DF90025B92D /* MyRuuviAccountViewInput.swift */; }; - E16B8F4528D10E2C0025B92D /* MyRuuviAccountViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F4428D10E2C0025B92D /* MyRuuviAccountViewOutput.swift */; }; - E16B8F4628D10E2C0025B92D /* MyRuuviAccountViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F4428D10E2C0025B92D /* MyRuuviAccountViewOutput.swift */; }; - E16B8F4828D10E7A0025B92D /* MyRuuviAccountViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F4728D10E7A0025B92D /* MyRuuviAccountViewModel.swift */; }; - E16B8F4928D10E7A0025B92D /* MyRuuviAccountViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F4728D10E7A0025B92D /* MyRuuviAccountViewModel.swift */; }; - E16B8F4B28D1114F0025B92D /* MyRuuviAccountModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F4A28D1114F0025B92D /* MyRuuviAccountModuleInput.swift */; }; - E16B8F4C28D1114F0025B92D /* MyRuuviAccountModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F4A28D1114F0025B92D /* MyRuuviAccountModuleInput.swift */; }; - E16B8F4E28D113230025B92D /* MyRuuviAccountInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F4D28D113230025B92D /* MyRuuviAccountInitializer.swift */; }; - E16B8F4F28D113230025B92D /* MyRuuviAccountInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F4D28D113230025B92D /* MyRuuviAccountInitializer.swift */; }; - E16B8F5128D113440025B92D /* MyRuuviAccountConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F5028D113440025B92D /* MyRuuviAccountConfigurator.swift */; }; - E16B8F5228D113440025B92D /* MyRuuviAccountConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F5028D113440025B92D /* MyRuuviAccountConfigurator.swift */; }; - E16B8F5428D113750025B92D /* MyRuuviAccountPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F5328D113750025B92D /* MyRuuviAccountPresenter.swift */; }; - E16B8F5528D113750025B92D /* MyRuuviAccountPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F5328D113750025B92D /* MyRuuviAccountPresenter.swift */; }; - E16B8F5728D113CB0025B92D /* MyRuuviAccountRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F5628D113CB0025B92D /* MyRuuviAccountRouterInput.swift */; }; - E16B8F5828D113CB0025B92D /* MyRuuviAccountRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F5628D113CB0025B92D /* MyRuuviAccountRouterInput.swift */; }; - E16B8F5A28D113EA0025B92D /* MyRuuviAccountRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F5928D113EA0025B92D /* MyRuuviAccountRouter.swift */; }; - E16B8F5B28D113EA0025B92D /* MyRuuviAccountRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E16B8F5928D113EA0025B92D /* MyRuuviAccountRouter.swift */; }; - E17C469C29956732008CFDD7 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E17C469B29956732008CFDD7 /* NotificationService.swift */; }; - E17C46A029956732008CFDD7 /* pnservice.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = E17C469929956732008CFDD7 /* pnservice.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - E17C46A429957763008CFDD7 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0EEB20C922B7A7200015F9E0 /* Localizable.strings */; }; - E186AB2B2844A273004926FC /* RuuviWidgetsConfiguration.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = E186AB302844A273004926FC /* RuuviWidgetsConfiguration.intentdefinition */; }; - E186AB2C2844A273004926FC /* RuuviWidgetsConfiguration.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = E186AB302844A273004926FC /* RuuviWidgetsConfiguration.intentdefinition */; }; - E186AB2D2844A273004926FC /* RuuviWidgetsConfiguration.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = E186AB302844A273004926FC /* RuuviWidgetsConfiguration.intentdefinition */; }; - E186AB2E2844A273004926FC /* RuuviWidgetsConfiguration.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = E186AB302844A273004926FC /* RuuviWidgetsConfiguration.intentdefinition */; }; - E18D04A128E879EE008EF5EC /* UIView+Init.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04A028E879EE008EF5EC /* UIView+Init.swift */; }; - E18D04A228E879EE008EF5EC /* UIView+Init.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04A028E879EE008EF5EC /* UIView+Init.swift */; }; - E18D04A528E8A5A3008EF5EC /* TagChartsViewConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04A428E8A5A3008EF5EC /* TagChartsViewConfigurator.swift */; }; - E18D04A628E8A5A3008EF5EC /* TagChartsViewConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04A428E8A5A3008EF5EC /* TagChartsViewConfigurator.swift */; }; - E18D04A928E8A6C0008EF5EC /* TagChartsViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04A828E8A6C0008EF5EC /* TagChartsViewPresenter.swift */; }; - E18D04AA28E8A6C0008EF5EC /* TagChartsViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04A828E8A6C0008EF5EC /* TagChartsViewPresenter.swift */; }; - E18D04AC28E8A737008EF5EC /* TagChartsViewModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04AB28E8A737008EF5EC /* TagChartsViewModuleInput.swift */; }; - E18D04AD28E8A737008EF5EC /* TagChartsViewModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04AB28E8A737008EF5EC /* TagChartsViewModuleInput.swift */; }; - E18D04AF28E8A747008EF5EC /* TagChartsViewModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04AE28E8A747008EF5EC /* TagChartsViewModuleOutput.swift */; }; - E18D04B028E8A747008EF5EC /* TagChartsViewModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04AE28E8A747008EF5EC /* TagChartsViewModuleOutput.swift */; }; - E18D04BA28E8B34F008EF5EC /* TagChartsViewInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04B928E8B34F008EF5EC /* TagChartsViewInteractor.swift */; }; - E18D04BB28E8B34F008EF5EC /* TagChartsViewInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04B928E8B34F008EF5EC /* TagChartsViewInteractor.swift */; }; - E18D04BD28E8B397008EF5EC /* TagChartsViewInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04BC28E8B397008EF5EC /* TagChartsViewInteractorInput.swift */; }; - E18D04BE28E8B397008EF5EC /* TagChartsViewInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04BC28E8B397008EF5EC /* TagChartsViewInteractorInput.swift */; }; - E18D04C028E8B3B0008EF5EC /* TagChartsViewInteractorOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04BF28E8B3B0008EF5EC /* TagChartsViewInteractorOutput.swift */; }; - E18D04C128E8B3B0008EF5EC /* TagChartsViewInteractorOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04BF28E8B3B0008EF5EC /* TagChartsViewInteractorOutput.swift */; }; - E18D04C428E9DF77008EF5EC /* TagChartsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04C328E9DF77008EF5EC /* TagChartsView.swift */; }; - E18D04C528E9DF77008EF5EC /* TagChartsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04C328E9DF77008EF5EC /* TagChartsView.swift */; }; - E18D04D128F1D027008EF5EC /* TagChartsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04D028F1D027008EF5EC /* TagChartsViewInput.swift */; }; - E18D04D228F1D027008EF5EC /* TagChartsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04D028F1D027008EF5EC /* TagChartsViewInput.swift */; }; - E18D04D428F1D52A008EF5EC /* TagChartsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04D328F1D52A008EF5EC /* TagChartsViewOutput.swift */; }; - E18D04D528F1D52A008EF5EC /* TagChartsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18D04D328F1D52A008EF5EC /* TagChartsViewOutput.swift */; }; - E18FD50A28DF7B7900289359 /* TagChartsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18FD50928DF7B7900289359 /* TagChartsViewController.swift */; }; - E18FD50B28DF7B7900289359 /* TagChartsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18FD50928DF7B7900289359 /* TagChartsViewController.swift */; }; - E18FD50D28DF7E7100289359 /* UIView+Layout.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18FD50C28DF7E7100289359 /* UIView+Layout.swift */; }; - E18FD50E28DF7E7100289359 /* UIView+Layout.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18FD50C28DF7E7100289359 /* UIView+Layout.swift */; }; - E191F1E92968B6B100F1FEA6 /* TagSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F1E82968B6B100F1FEA6 /* TagSettingsViewController.swift */; }; - E191F1EA2968B6B100F1FEA6 /* TagSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F1E82968B6B100F1FEA6 /* TagSettingsViewController.swift */; }; - E191F1EC2968BCF300F1FEA6 /* TagSettingsBasicCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F1EB2968BCF300F1FEA6 /* TagSettingsBasicCell.swift */; }; - E191F1ED2968BCF300F1FEA6 /* TagSettingsBasicCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F1EB2968BCF300F1FEA6 /* TagSettingsBasicCell.swift */; }; - E191F1F22968C2C900F1FEA6 /* TagSettingsAlertConfigCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F1F12968C2C900F1FEA6 /* TagSettingsAlertConfigCell.swift */; }; - E191F1F32968C2C900F1FEA6 /* TagSettingsAlertConfigCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F1F12968C2C900F1FEA6 /* TagSettingsAlertConfigCell.swift */; }; - E191F1F52968D32000F1FEA6 /* TagSettingsExpandableSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F1F42968D32000F1FEA6 /* TagSettingsExpandableSectionHeader.swift */; }; - E191F1F62968D32000F1FEA6 /* TagSettingsExpandableSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F1F42968D32000F1FEA6 /* TagSettingsExpandableSectionHeader.swift */; }; - E191F1F82968D33800F1FEA6 /* TagSettingsSimpleSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F1F72968D33800F1FEA6 /* TagSettingsSimpleSectionHeader.swift */; }; - E191F1F92968D33800F1FEA6 /* TagSettingsSimpleSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F1F72968D33800F1FEA6 /* TagSettingsSimpleSectionHeader.swift */; }; - E191F1FB2969CD0100F1FEA6 /* TagSettingsBackgroundSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F1FA2969CD0100F1FEA6 /* TagSettingsBackgroundSelectionView.swift */; }; - E191F1FC2969CD0100F1FEA6 /* TagSettingsBackgroundSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F1FA2969CD0100F1FEA6 /* TagSettingsBackgroundSelectionView.swift */; }; - E191F1FE2969D6C900F1FEA6 /* TagSettingsPlainCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F1FD2969D6C900F1FEA6 /* TagSettingsPlainCell.swift */; }; - E191F1FF2969D6C900F1FEA6 /* TagSettingsPlainCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F1FD2969D6C900F1FEA6 /* TagSettingsPlainCell.swift */; }; - E191F2092969E11F00F1FEA6 /* TagSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F2082969E11F00F1FEA6 /* TagSettingsRouterInput.swift */; }; - E191F20A2969E11F00F1FEA6 /* TagSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F2082969E11F00F1FEA6 /* TagSettingsRouterInput.swift */; }; - E191F20C2969E14600F1FEA6 /* TagSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F20B2969E14600F1FEA6 /* TagSettingsRouter.swift */; }; - E191F20D2969E14600F1FEA6 /* TagSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F20B2969E14600F1FEA6 /* TagSettingsRouter.swift */; }; - E191F20F2969E1C300F1FEA6 /* TagSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F20E2969E1C300F1FEA6 /* TagSettingsPresenter.swift */; }; - E191F2102969E1C300F1FEA6 /* TagSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F20E2969E1C300F1FEA6 /* TagSettingsPresenter.swift */; }; - E191F21B2969EF7B00F1FEA6 /* TagSettingsModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F21A2969EF7B00F1FEA6 /* TagSettingsModuleFactory.swift */; }; - E191F21C2969EF7B00F1FEA6 /* TagSettingsModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F21A2969EF7B00F1FEA6 /* TagSettingsModuleFactory.swift */; }; - E191F21E2969FF6900F1FEA6 /* TagSettingsSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F21D2969FF6900F1FEA6 /* TagSettingsSwitchCell.swift */; }; - E191F21F2969FF6900F1FEA6 /* TagSettingsSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F21D2969FF6900F1FEA6 /* TagSettingsSwitchCell.swift */; }; - E191F221296A00CE00F1FEA6 /* TagSettingsFooterCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F220296A00CE00F1FEA6 /* TagSettingsFooterCell.swift */; }; - E191F222296A00CE00F1FEA6 /* TagSettingsFooterCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E191F220296A00CE00F1FEA6 /* TagSettingsFooterCell.swift */; }; - E19691502A06DCA400DC360E /* NotificationsSettingsModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E196914F2A06DCA400DC360E /* NotificationsSettingsModuleFactory.swift */; }; - E19691512A06DCA400DC360E /* NotificationsSettingsModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E196914F2A06DCA400DC360E /* NotificationsSettingsModuleFactory.swift */; }; - E19691542A06DCBB00DC360E /* NotificationsSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691522A06DCBB00DC360E /* NotificationsSettingsRouterInput.swift */; }; - E19691552A06DCBB00DC360E /* NotificationsSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691522A06DCBB00DC360E /* NotificationsSettingsRouterInput.swift */; }; - E19691562A06DCBB00DC360E /* NotificationsSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691532A06DCBB00DC360E /* NotificationsSettingsRouter.swift */; }; - E19691572A06DCBB00DC360E /* NotificationsSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691532A06DCBB00DC360E /* NotificationsSettingsRouter.swift */; }; - E196915B2A06DCD500DC360E /* NotificationsSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691582A06DCD400DC360E /* NotificationsSettingsTableViewController.swift */; }; - E196915C2A06DCD500DC360E /* NotificationsSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691582A06DCD400DC360E /* NotificationsSettingsTableViewController.swift */; }; - E196915D2A06DCD500DC360E /* NotificationsSettingsTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691592A06DCD500DC360E /* NotificationsSettingsTextCell.swift */; }; - E196915E2A06DCD500DC360E /* NotificationsSettingsTextCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691592A06DCD500DC360E /* NotificationsSettingsTextCell.swift */; }; - E196915F2A06DCD500DC360E /* NotificationsSettingsSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E196915A2A06DCD500DC360E /* NotificationsSettingsSwitchCell.swift */; }; - E19691602A06DCD500DC360E /* NotificationsSettingsSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E196915A2A06DCD500DC360E /* NotificationsSettingsSwitchCell.swift */; }; - E19691642A06DCE500DC360E /* NotificationsSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691612A06DCE500DC360E /* NotificationsSettingsViewInput.swift */; }; - E19691652A06DCE500DC360E /* NotificationsSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691612A06DCE500DC360E /* NotificationsSettingsViewInput.swift */; }; - E19691662A06DCE500DC360E /* NotificationsSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691622A06DCE500DC360E /* NotificationsSettingsViewModel.swift */; }; - E19691672A06DCE500DC360E /* NotificationsSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691622A06DCE500DC360E /* NotificationsSettingsViewModel.swift */; }; - E19691682A06DCE500DC360E /* NotificationsSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691632A06DCE500DC360E /* NotificationsSettingsViewOutput.swift */; }; - E19691692A06DCE500DC360E /* NotificationsSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691632A06DCE500DC360E /* NotificationsSettingsViewOutput.swift */; }; - E196916C2A06DCEF00DC360E /* NotificationsSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E196916A2A06DCEF00DC360E /* NotificationsSettingsPresenter.swift */; }; - E196916D2A06DCEF00DC360E /* NotificationsSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E196916A2A06DCEF00DC360E /* NotificationsSettingsPresenter.swift */; }; - E196916E2A06DCEF00DC360E /* NotificationsSettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E196916B2A06DCEF00DC360E /* NotificationsSettingsModuleInput.swift */; }; - E196916F2A06DCEF00DC360E /* NotificationsSettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E196916B2A06DCEF00DC360E /* NotificationsSettingsModuleInput.swift */; }; - E196917C2A06E03300DC360E /* PushAlertSoundSelectionModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691722A06E03300DC360E /* PushAlertSoundSelectionModuleFactory.swift */; }; - E196917D2A06E03300DC360E /* PushAlertSoundSelectionModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691722A06E03300DC360E /* PushAlertSoundSelectionModuleFactory.swift */; }; - E196917E2A06E03300DC360E /* PushAlertSoundSelectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691742A06E03300DC360E /* PushAlertSoundSelectionPresenter.swift */; }; - E196917F2A06E03300DC360E /* PushAlertSoundSelectionPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691742A06E03300DC360E /* PushAlertSoundSelectionPresenter.swift */; }; - E19691802A06E03300DC360E /* PushAlertSoundSelectionModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691752A06E03300DC360E /* PushAlertSoundSelectionModuleInput.swift */; }; - E19691812A06E03300DC360E /* PushAlertSoundSelectionModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691752A06E03300DC360E /* PushAlertSoundSelectionModuleInput.swift */; }; - E19691822A06E03300DC360E /* PushAlertSoundSelectionTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691782A06E03300DC360E /* PushAlertSoundSelectionTableViewController.swift */; }; - E19691832A06E03300DC360E /* PushAlertSoundSelectionTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691782A06E03300DC360E /* PushAlertSoundSelectionTableViewController.swift */; }; - E19691842A06E03300DC360E /* PushAlertSoundSelectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691792A06E03300DC360E /* PushAlertSoundSelectionTableViewCell.swift */; }; - E19691852A06E03300DC360E /* PushAlertSoundSelectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19691792A06E03300DC360E /* PushAlertSoundSelectionTableViewCell.swift */; }; - E19691862A06E03300DC360E /* PushAlertSoundSelectionViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E196917A2A06E03300DC360E /* PushAlertSoundSelectionViewInput.swift */; }; - E19691872A06E03300DC360E /* PushAlertSoundSelectionViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E196917A2A06E03300DC360E /* PushAlertSoundSelectionViewInput.swift */; }; - E19691882A06E03300DC360E /* PushAlertSoundSelectionViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E196917B2A06E03300DC360E /* PushAlertSoundSelectionViewOutput.swift */; }; - E19691892A06E03300DC360E /* PushAlertSoundSelectionViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E196917B2A06E03300DC360E /* PushAlertSoundSelectionViewOutput.swift */; }; - E196918B2A06E15F00DC360E /* PushAlertSoundSelectionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E196918A2A06E15F00DC360E /* PushAlertSoundSelectionViewModel.swift */; }; - E196918C2A06E15F00DC360E /* PushAlertSoundSelectionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E196918A2A06E15F00DC360E /* PushAlertSoundSelectionViewModel.swift */; }; - E196918E2A06E2E100DC360E /* RuuviAlertSound+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E196918D2A06E2E100DC360E /* RuuviAlertSound+Extension.swift */; }; - E196918F2A06E2E100DC360E /* RuuviAlertSound+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E196918D2A06E2E100DC360E /* RuuviAlertSound+Extension.swift */; }; - E1972BE129587615000E2AEC /* CardsLargeImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1972BE029587615000E2AEC /* CardsLargeImageCell.swift */; }; - E1972BE229587615000E2AEC /* CardsLargeImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1972BE029587615000E2AEC /* CardsLargeImageCell.swift */; }; - E19EAF4C299679D8005827E4 /* pnservice.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = E17C469929956732008CFDD7 /* pnservice.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - E19EAF532996C828005827E4 /* Montserrat-ExtraBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E19EAF512996C828005827E4 /* Montserrat-ExtraBold.ttf */; }; - E19EAF542996C828005827E4 /* Montserrat-ExtraBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E19EAF512996C828005827E4 /* Montserrat-ExtraBold.ttf */; }; - E19EAF5B2996CF38005827E4 /* Muli-SemiBoldItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E19EAF5A2996CF38005827E4 /* Muli-SemiBoldItalic.ttf */; }; - E19EAF5C2996CF38005827E4 /* Muli-SemiBoldItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E19EAF5A2996CF38005827E4 /* Muli-SemiBoldItalic.ttf */; }; - E19EAF6629983650005827E4 /* AppUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF6529983650005827E4 /* AppUtility.swift */; }; - E19EAF6729983650005827E4 /* AppUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF6529983650005827E4 /* AppUtility.swift */; }; - E19EAF6929997711005827E4 /* SignInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF6829997711005827E4 /* SignInViewController.swift */; }; - E19EAF6A29997711005827E4 /* SignInViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF6829997711005827E4 /* SignInViewController.swift */; }; - E19EAF72299ADB2F005827E4 /* UIButton+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF71299ADB2F005827E4 /* UIButton+Extension.swift */; }; - E19EAF73299ADB2F005827E4 /* UIButton+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF71299ADB2F005827E4 /* UIButton+Extension.swift */; }; - E19EAF75299AE3B0005827E4 /* SignInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF74299AE3B0005827E4 /* SignInView.swift */; }; - E19EAF76299AE3B0005827E4 /* SignInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF74299AE3B0005827E4 /* SignInView.swift */; }; - E19EAF78299AE5EA005827E4 /* SignInVerifyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF77299AE5EA005827E4 /* SignInVerifyView.swift */; }; - E19EAF79299AE5EA005827E4 /* SignInVerifyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF77299AE5EA005827E4 /* SignInVerifyView.swift */; }; - E19EAF7B299BF94C005827E4 /* SignInBenefitsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF7A299BF94C005827E4 /* SignInBenefitsViewController.swift */; }; - E19EAF7C299BF94C005827E4 /* SignInBenefitsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF7A299BF94C005827E4 /* SignInBenefitsViewController.swift */; }; - E19EAF83299C1383005827E4 /* SignInModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF82299C1383005827E4 /* SignInModuleFactory.swift */; }; - E19EAF84299C1383005827E4 /* SignInModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF82299C1383005827E4 /* SignInModuleFactory.swift */; }; - E19EAF94299E6038005827E4 /* SignInBenefitsModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF93299E6038005827E4 /* SignInBenefitsModuleFactory.swift */; }; - E19EAF95299E6038005827E4 /* SignInBenefitsModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF93299E6038005827E4 /* SignInBenefitsModuleFactory.swift */; }; - E19EAF97299E6083005827E4 /* SignInBenefitsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF96299E6083005827E4 /* SignInBenefitsRouterInput.swift */; }; - E19EAF98299E6083005827E4 /* SignInBenefitsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF96299E6083005827E4 /* SignInBenefitsRouterInput.swift */; }; - E19EAF9A299E608E005827E4 /* SignInBenefitsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF99299E608E005827E4 /* SignInBenefitsRouter.swift */; }; - E19EAF9B299E608E005827E4 /* SignInBenefitsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF99299E608E005827E4 /* SignInBenefitsRouter.swift */; }; - E19EAF9E299E610A005827E4 /* SignInBenefitsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF9D299E610A005827E4 /* SignInBenefitsPresenter.swift */; }; - E19EAF9F299E610A005827E4 /* SignInBenefitsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAF9D299E610A005827E4 /* SignInBenefitsPresenter.swift */; }; - E19EAFA1299E61C5005827E4 /* SignInBenefitsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAFA0299E61C5005827E4 /* SignInBenefitsModuleInput.swift */; }; - E19EAFA2299E61C5005827E4 /* SignInBenefitsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAFA0299E61C5005827E4 /* SignInBenefitsModuleInput.swift */; }; - E19EAFA4299E6211005827E4 /* SignInBenefitsModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAFA3299E6211005827E4 /* SignInBenefitsModuleOutput.swift */; }; - E19EAFA5299E6211005827E4 /* SignInBenefitsModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAFA3299E6211005827E4 /* SignInBenefitsModuleOutput.swift */; }; - E19EAFA7299E62A7005827E4 /* SignInBenefitsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAFA6299E62A7005827E4 /* SignInBenefitsViewInput.swift */; }; - E19EAFA8299E62A7005827E4 /* SignInBenefitsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAFA6299E62A7005827E4 /* SignInBenefitsViewInput.swift */; }; - E19EAFAA299E62C0005827E4 /* SignInBenefitsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAFA9299E62C0005827E4 /* SignInBenefitsViewOutput.swift */; }; - E19EAFAB299E62C0005827E4 /* SignInBenefitsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAFA9299E62C0005827E4 /* SignInBenefitsViewOutput.swift */; }; - E19EAFAD299E82D1005827E4 /* SignInPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAFAC299E82D1005827E4 /* SignInPresenter.swift */; }; - E19EAFAE299E82D1005827E4 /* SignInPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAFAC299E82D1005827E4 /* SignInPresenter.swift */; }; - E19EAFB0299EB46D005827E4 /* NoSensorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAFAF299EB46D005827E4 /* NoSensorView.swift */; }; - E19EAFB1299EB46D005827E4 /* NoSensorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19EAFAF299EB46D005827E4 /* NoSensorView.swift */; }; - E1AB90552A0BFECE00543F61 /* RuuviLinkTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB90542A0BFECE00543F61 /* RuuviLinkTextView.swift */; }; - E1AB90562A0BFECE00543F61 /* RuuviLinkTextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB90542A0BFECE00543F61 /* RuuviLinkTextView.swift */; }; - E1AB905E2A0EB0D000543F61 /* SensorForceClaimModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB905D2A0EB0D000543F61 /* SensorForceClaimModuleFactory.swift */; }; - E1AB905F2A0EB0D000543F61 /* SensorForceClaimModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB905D2A0EB0D000543F61 /* SensorForceClaimModuleFactory.swift */; }; - E1AB90612A0EB11800543F61 /* SensorForceClaimPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB90602A0EB11800543F61 /* SensorForceClaimPresenter.swift */; }; - E1AB90622A0EB11800543F61 /* SensorForceClaimPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB90602A0EB11800543F61 /* SensorForceClaimPresenter.swift */; }; - E1AB90642A0EB13400543F61 /* SensorForceClaimModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB90632A0EB13400543F61 /* SensorForceClaimModuleInput.swift */; }; - E1AB90652A0EB13400543F61 /* SensorForceClaimModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB90632A0EB13400543F61 /* SensorForceClaimModuleInput.swift */; }; - E1AB90672A0EB1AD00543F61 /* SensorForceClaimRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB90662A0EB1AD00543F61 /* SensorForceClaimRouter.swift */; }; - E1AB90682A0EB1AD00543F61 /* SensorForceClaimRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB90662A0EB1AD00543F61 /* SensorForceClaimRouter.swift */; }; - E1AB906A2A0EB1BC00543F61 /* SensorForceClaimRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB90692A0EB1BC00543F61 /* SensorForceClaimRouterInput.swift */; }; - E1AB906B2A0EB1BC00543F61 /* SensorForceClaimRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB90692A0EB1BC00543F61 /* SensorForceClaimRouterInput.swift */; }; - E1AB90732A0EB24600543F61 /* SensorForceClaimViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB90722A0EB24600543F61 /* SensorForceClaimViewController.swift */; }; - E1AB90742A0EB24600543F61 /* SensorForceClaimViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB90722A0EB24600543F61 /* SensorForceClaimViewController.swift */; }; - E1AB907B2A0ECB6D00543F61 /* SensorForceClaimViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB907A2A0ECB6D00543F61 /* SensorForceClaimViewOutput.swift */; }; - E1AB907C2A0ECB6D00543F61 /* SensorForceClaimViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB907A2A0ECB6D00543F61 /* SensorForceClaimViewOutput.swift */; }; - E1AB907E2A0ECB7600543F61 /* SensorForceClaimViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB907D2A0ECB7600543F61 /* SensorForceClaimViewInput.swift */; }; - E1AB907F2A0ECB7600543F61 /* SensorForceClaimViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AB907D2A0ECB7600543F61 /* SensorForceClaimViewInput.swift */; }; - E1B20C872926CDE10023D739 /* UITextField+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B20C862926CDE10023D739 /* UITextField+Extension.swift */; }; - E1B20C882926CDE10023D739 /* UITextField+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B20C862926CDE10023D739 /* UITextField+Extension.swift */; }; - E1B20C8A2926D2FC0023D739 /* Double+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B20C892926D2FC0023D739 /* Double+Extension.swift */; }; - E1B20C8B2926D2FC0023D739 /* Double+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B20C892926D2FC0023D739 /* Double+Extension.swift */; }; - E1B57FEB29859CB800B441FB /* DevicesModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B57FEA29859CB800B441FB /* DevicesModuleFactory.swift */; }; - E1B57FEC29859CB800B441FB /* DevicesModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B57FEA29859CB800B441FB /* DevicesModuleFactory.swift */; }; - E1B57FEE29859CC900B441FB /* DevicesModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B57FED29859CC900B441FB /* DevicesModuleInput.swift */; }; - E1B57FEF29859CC900B441FB /* DevicesModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B57FED29859CC900B441FB /* DevicesModuleInput.swift */; }; - E1B57FF129859CD400B441FB /* DevicesPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B57FF029859CD400B441FB /* DevicesPresenter.swift */; }; - E1B57FF229859CD400B441FB /* DevicesPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B57FF029859CD400B441FB /* DevicesPresenter.swift */; }; - E1B57FF429859CE200B441FB /* DevicesTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B57FF329859CE200B441FB /* DevicesTableViewController.swift */; }; - E1B57FF529859CE200B441FB /* DevicesTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B57FF329859CE200B441FB /* DevicesTableViewController.swift */; }; - E1B57FF729859CEC00B441FB /* DevicesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B57FF629859CEC00B441FB /* DevicesTableViewCell.swift */; }; - E1B57FF829859CEC00B441FB /* DevicesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B57FF629859CEC00B441FB /* DevicesTableViewCell.swift */; }; - E1B57FFB29859D0700B441FB /* DevicesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B57FFA29859D0700B441FB /* DevicesViewModel.swift */; }; - E1B57FFC29859D0700B441FB /* DevicesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B57FFA29859D0700B441FB /* DevicesViewModel.swift */; }; - E1B57FFE29859D1800B441FB /* DevicesViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B57FFD29859D1800B441FB /* DevicesViewInput.swift */; }; - E1B57FFF29859D1800B441FB /* DevicesViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B57FFD29859D1800B441FB /* DevicesViewInput.swift */; }; - E1B5800129859D2300B441FB /* DevicesViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B5800029859D2300B441FB /* DevicesViewOutput.swift */; }; - E1B5800229859D2300B441FB /* DevicesViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B5800029859D2300B441FB /* DevicesViewOutput.swift */; }; - E1B5800529859E8900B441FB /* DevicesInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B5800429859E8900B441FB /* DevicesInteractor.swift */; }; - E1B5800629859E8900B441FB /* DevicesInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B5800429859E8900B441FB /* DevicesInteractor.swift */; }; - E1B5800829859EDE00B441FB /* DevicesInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B5800729859EDE00B441FB /* DevicesInteractorInput.swift */; }; - E1B5800929859EDE00B441FB /* DevicesInteractorInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B5800729859EDE00B441FB /* DevicesInteractorInput.swift */; }; - E1B5800B29859EEB00B441FB /* DevicesInteractorOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B5800A29859EEB00B441FB /* DevicesInteractorOutput.swift */; }; - E1B5800C29859EEB00B441FB /* DevicesInteractorOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B5800A29859EEB00B441FB /* DevicesInteractorOutput.swift */; }; - E1B5800E2986AE0800B441FB /* RuuviContextMenuButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B5800D2986AE0800B441FB /* RuuviContextMenuButton.swift */; }; - E1B5800F2986AE0800B441FB /* RuuviContextMenuButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B5800D2986AE0800B441FB /* RuuviContextMenuButton.swift */; }; - E1B7B5242AE989ED009D747E /* SensorRemovalModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B5232AE989ED009D747E /* SensorRemovalModuleFactory.swift */; }; - E1B7B5252AE989ED009D747E /* SensorRemovalModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B5232AE989ED009D747E /* SensorRemovalModuleFactory.swift */; }; - E1B7B5282AE98A37009D747E /* SensorRemovalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B5272AE98A37009D747E /* SensorRemovalViewController.swift */; }; - E1B7B5292AE98A37009D747E /* SensorRemovalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B5272AE98A37009D747E /* SensorRemovalViewController.swift */; }; - E1B7B52B2AE98A9F009D747E /* SensorRemovalViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B52A2AE98A9F009D747E /* SensorRemovalViewOutput.swift */; }; - E1B7B52C2AE98A9F009D747E /* SensorRemovalViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B52A2AE98A9F009D747E /* SensorRemovalViewOutput.swift */; }; - E1B7B52E2AE98AC4009D747E /* SensorRemovalViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B52D2AE98AC4009D747E /* SensorRemovalViewInput.swift */; }; - E1B7B52F2AE98AC4009D747E /* SensorRemovalViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B52D2AE98AC4009D747E /* SensorRemovalViewInput.swift */; }; - E1B7B5312AE98B00009D747E /* SensorRemovalRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B5302AE98B00009D747E /* SensorRemovalRouter.swift */; }; - E1B7B5322AE98B00009D747E /* SensorRemovalRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B5302AE98B00009D747E /* SensorRemovalRouter.swift */; }; - E1B7B5342AE98B16009D747E /* SensorRemovalRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B5332AE98B16009D747E /* SensorRemovalRouterInput.swift */; }; - E1B7B5352AE98B16009D747E /* SensorRemovalRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B5332AE98B16009D747E /* SensorRemovalRouterInput.swift */; }; - E1B7B5372AE98B72009D747E /* SensorRemovalModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B5362AE98B72009D747E /* SensorRemovalModuleInput.swift */; }; - E1B7B5382AE98B72009D747E /* SensorRemovalModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B5362AE98B72009D747E /* SensorRemovalModuleInput.swift */; }; - E1B7B53A2AE98B86009D747E /* SensorRemovalPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B5392AE98B86009D747E /* SensorRemovalPresenter.swift */; }; - E1B7B53B2AE98B86009D747E /* SensorRemovalPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B5392AE98B86009D747E /* SensorRemovalPresenter.swift */; }; - E1B7B53F2AEAD61A009D747E /* SensorRemovalModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B53E2AEAD61A009D747E /* SensorRemovalModuleOutput.swift */; }; - E1B7B5402AEAD61A009D747E /* SensorRemovalModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B7B53E2AEAD61A009D747E /* SensorRemovalModuleOutput.swift */; }; - E1BAC13A2A7598F000EA820E /* Muli-ExtraBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E1BAC1392A7598F000EA820E /* Muli-ExtraBold.ttf */; }; - E1BAC13B2A7598F000EA820E /* Muli-ExtraBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E1BAC1392A7598F000EA820E /* Muli-ExtraBold.ttf */; }; - E1C395D329B26044009301D3 /* UICollectionView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1C395D229B26044009301D3 /* UICollectionView+Extension.swift */; }; - E1C395D429B26044009301D3 /* UICollectionView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1C395D229B26044009301D3 /* UICollectionView+Extension.swift */; }; - E1CA28AE29201F34009E4423 /* RUAlertExpandButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CA28AD29201F34009E4423 /* RUAlertExpandButton.swift */; }; - E1CA28AF29201F34009E4423 /* RUAlertExpandButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CA28AD29201F34009E4423 /* RUAlertExpandButton.swift */; }; - E1CA28B8292037E4009E4423 /* RUAlertDetailsCellChildView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CA28B7292037E4009E4423 /* RUAlertDetailsCellChildView.swift */; }; - E1CA28B9292037E4009E4423 /* RUAlertDetailsCellChildView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CA28B7292037E4009E4423 /* RUAlertDetailsCellChildView.swift */; }; - E1CD77E728781A0E00F1F0EB /* UnitSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E1CD77E628781A0E00F1F0EB /* UnitSettings.storyboard */; }; - E1CD77E828781A0E00F1F0EB /* UnitSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E1CD77E628781A0E00F1F0EB /* UnitSettings.storyboard */; }; - E1CD77EC2878273500F1F0EB /* UnitSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD77EB2878273500F1F0EB /* UnitSettingsTableViewController.swift */; }; - E1CD77ED2878273500F1F0EB /* UnitSettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD77EB2878273500F1F0EB /* UnitSettingsTableViewController.swift */; }; - E1CD77F128782E8000F1F0EB /* UnitSettingsTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD77F028782E8000F1F0EB /* UnitSettingsTableConfigurator.swift */; }; - E1CD77F228782E8000F1F0EB /* UnitSettingsTableConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD77F028782E8000F1F0EB /* UnitSettingsTableConfigurator.swift */; }; - E1CD77F428782EA500F1F0EB /* UnitSettingsTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD77F328782EA500F1F0EB /* UnitSettingsTableInitializer.swift */; }; - E1CD77F528782EA500F1F0EB /* UnitSettingsTableInitializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD77F328782EA500F1F0EB /* UnitSettingsTableInitializer.swift */; }; - E1CD77F828782F2200F1F0EB /* UnitSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD77F728782F2200F1F0EB /* UnitSettingsPresenter.swift */; }; - E1CD77F928782F2200F1F0EB /* UnitSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD77F728782F2200F1F0EB /* UnitSettingsPresenter.swift */; }; - E1CD77FB28782F7100F1F0EB /* UnitSettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD77FA28782F7100F1F0EB /* UnitSettingsModuleInput.swift */; }; - E1CD77FC28782F7100F1F0EB /* UnitSettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD77FA28782F7100F1F0EB /* UnitSettingsModuleInput.swift */; }; - E1CD77FE28782F9900F1F0EB /* UnitSettingsModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD77FD28782F9900F1F0EB /* UnitSettingsModuleOutput.swift */; }; - E1CD77FF28782F9900F1F0EB /* UnitSettingsModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD77FD28782F9900F1F0EB /* UnitSettingsModuleOutput.swift */; }; - E1CD78012878302100F1F0EB /* UnitSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD78002878302100F1F0EB /* UnitSettingsViewInput.swift */; }; - E1CD78022878302100F1F0EB /* UnitSettingsViewInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD78002878302100F1F0EB /* UnitSettingsViewInput.swift */; }; - E1CD78042878302C00F1F0EB /* UnitSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD78032878302C00F1F0EB /* UnitSettingsViewOutput.swift */; }; - E1CD78052878302C00F1F0EB /* UnitSettingsViewOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD78032878302C00F1F0EB /* UnitSettingsViewOutput.swift */; }; - E1CD78082878308E00F1F0EB /* UnitSettingsItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD78072878308E00F1F0EB /* UnitSettingsItem.swift */; }; - E1CD78092878308E00F1F0EB /* UnitSettingsItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD78072878308E00F1F0EB /* UnitSettingsItem.swift */; }; - E1CD780C287830B100F1F0EB /* UnitSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD780B287830B100F1F0EB /* UnitSettingsRouter.swift */; }; - E1CD780D287830B100F1F0EB /* UnitSettingsRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD780B287830B100F1F0EB /* UnitSettingsRouter.swift */; }; - E1CD780F287830BF00F1F0EB /* UnitSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD780E287830BF00F1F0EB /* UnitSettingsRouterInput.swift */; }; - E1CD7810287830BF00F1F0EB /* UnitSettingsRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD780E287830BF00F1F0EB /* UnitSettingsRouterInput.swift */; }; - E1CD78122878379C00F1F0EB /* UnitSettingsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD78112878379C00F1F0EB /* UnitSettingsTableViewCell.swift */; }; - E1CD78132878379C00F1F0EB /* UnitSettingsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD78112878379C00F1F0EB /* UnitSettingsTableViewCell.swift */; }; - E1CE4C712959CE61005C023F /* DashboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CE4C702959CE61005C023F /* DashboardViewController.swift */; }; - E1CE4C722959CE61005C023F /* DashboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CE4C702959CE61005C023F /* DashboardViewController.swift */; }; - E1CE4C742959D08D005C023F /* DashboardImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CE4C732959D08D005C023F /* DashboardImageCell.swift */; }; - E1CE4C752959D08D005C023F /* DashboardImageCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CE4C732959D08D005C023F /* DashboardImageCell.swift */; }; - E1CE4C772959DF01005C023F /* DashboardIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CE4C762959DF01005C023F /* DashboardIndicatorView.swift */; }; - E1CE4C782959DF01005C023F /* DashboardIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CE4C762959DF01005C023F /* DashboardIndicatorView.swift */; }; - E1CE5E3F29F994DE00391109 /* AppGroupConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CE5E3E29F994DE00391109 /* AppGroupConstants.swift */; }; - E1CE5E4029F994DE00391109 /* AppGroupConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CE5E3E29F994DE00391109 /* AppGroupConstants.swift */; }; - E1CE5E4229FC39D000391109 /* DefaultsModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CE5E4129FC39D000391109 /* DefaultsModuleOutput.swift */; }; - E1CE5E4329FC39D000391109 /* DefaultsModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CE5E4129FC39D000391109 /* DefaultsModuleOutput.swift */; }; - E1CE5E472A016D4000391109 /* RuuviCustomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CE5E462A016D4000391109 /* RuuviCustomButton.swift */; }; - E1CE5E482A016D4000391109 /* RuuviCustomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CE5E462A016D4000391109 /* RuuviCustomButton.swift */; }; - E1D0238B29EB02C600EC0FFD /* RuuviUISwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D0238A29EB02C600EC0FFD /* RuuviUISwitch.swift */; }; - E1D0238C29EB02C600EC0FFD /* RuuviUISwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D0238A29EB02C600EC0FFD /* RuuviUISwitch.swift */; }; - E1D0238E29EB3F7D00EC0FFD /* YAxisValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D0238D29EB3F7D00EC0FFD /* YAxisValueFormatter.swift */; }; - E1D0238F29EB3F7D00EC0FFD /* YAxisValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1D0238D29EB3F7D00EC0FFD /* YAxisValueFormatter.swift */; }; - E1E102EE28F348B700815508 /* TagChartsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E102ED28F348B700815508 /* TagChartsHelper.swift */; }; - E1E102EF28F348B700815508 /* TagChartsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E102ED28F348B700815508 /* TagChartsHelper.swift */; }; - E1E1475C28E85EE700832B8C /* UIImageView+Init.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E1475B28E85EE700832B8C /* UIImageView+Init.swift */; }; - E1E1475D28E85EE700832B8C /* UIImageView+Init.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E1475B28E85EE700832B8C /* UIImageView+Init.swift */; }; - E1E3C330298C601200A59CB8 /* CardsViewModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E3C32F298C601200A59CB8 /* CardsViewModuleFactory.swift */; }; - E1E3C331298C601200A59CB8 /* CardsViewModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E3C32F298C601200A59CB8 /* CardsViewModuleFactory.swift */; }; - E1E3C333298D7FA500A59CB8 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E3C332298D7FA500A59CB8 /* UIImage+Extension.swift */; }; - E1E3C334298D7FA500A59CB8 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E3C332298D7FA500A59CB8 /* UIImage+Extension.swift */; }; - E1E3C336298D858D00A59CB8 /* TagChartsModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E3C335298D858D00A59CB8 /* TagChartsModuleFactory.swift */; }; - E1E3C337298D858D00A59CB8 /* TagChartsModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E3C335298D858D00A59CB8 /* TagChartsModuleFactory.swift */; }; - E1E3C339298EC9DC00A59CB8 /* DashboardModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E3C338298EC9DC00A59CB8 /* DashboardModuleFactory.swift */; }; - E1E3C33A298EC9DC00A59CB8 /* DashboardModuleFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E3C338298EC9DC00A59CB8 /* DashboardModuleFactory.swift */; }; - E1E3C33C298ED3E300A59CB8 /* CardsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E3C33B298ED3E300A59CB8 /* CardsPresenter.swift */; }; - E1E3C33D298ED3E300A59CB8 /* CardsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E3C33B298ED3E300A59CB8 /* CardsPresenter.swift */; }; - E1E3C33F298FDCCC00A59CB8 /* CardsModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E3C33E298FDCCC00A59CB8 /* CardsModuleOutput.swift */; }; - E1E3C340298FDCCC00A59CB8 /* CardsModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E3C33E298FDCCC00A59CB8 /* CardsModuleOutput.swift */; }; - E1E3C342299007B700A59CB8 /* TagSettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E3C341299007B700A59CB8 /* TagSettingsModuleInput.swift */; }; - E1E3C343299007B700A59CB8 /* TagSettingsModuleInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E3C341299007B700A59CB8 /* TagSettingsModuleInput.swift */; }; - E1E3C345299007DE00A59CB8 /* TagSettingsModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E3C344299007DE00A59CB8 /* TagSettingsModuleOutput.swift */; }; - E1E3C346299007DE00A59CB8 /* TagSettingsModuleOutput.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E3C344299007DE00A59CB8 /* TagSettingsModuleOutput.swift */; }; - E1E6C215296C9CB100B3D037 /* Int+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E6C214296C9CB100B3D037 /* Int+Extension.swift */; }; - E1E6C216296C9CB100B3D037 /* Int+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1E6C214296C9CB100B3D037 /* Int+Extension.swift */; }; - E1ED426928FF253B00302179 /* TagChartsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1ED426828FF253B00302179 /* TagChartsViewModel.swift */; }; - E1ED426A28FF253B00302179 /* TagChartsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1ED426828FF253B00302179 /* TagChartsViewModel.swift */; }; - E1ED426E28FF261D00302179 /* CustomYAxisRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1ED426B28FF261D00302179 /* CustomYAxisRenderer.swift */; }; - E1ED426F28FF261D00302179 /* CustomYAxisRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1ED426B28FF261D00302179 /* CustomYAxisRenderer.swift */; }; - E1ED427028FF261D00302179 /* XAxisValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1ED426C28FF261D00302179 /* XAxisValueFormatter.swift */; }; - E1ED427128FF261D00302179 /* XAxisValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1ED426C28FF261D00302179 /* XAxisValueFormatter.swift */; }; - E1ED427228FF261D00302179 /* CustomXAxisRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1ED426D28FF261D00302179 /* CustomXAxisRenderer.swift */; }; - E1ED427328FF261D00302179 /* CustomXAxisRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1ED426D28FF261D00302179 /* CustomXAxisRenderer.swift */; }; - E8C4E5B85668D51EC22BC75A /* SignInRouterInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E816312622E83E3B42001DC /* SignInRouterInput.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 34A8D497281EBFDB008A8698 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 64333D1D20B0C45900CDF4B6 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 34A8D488281EBFD9008A8698; - remoteInfo = "ruuvi-widgetsExtension"; - }; - 34A8D4BC281EE5AE008A8698 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 64333D1D20B0C45900CDF4B6 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 34A8D4B4281EE5AE008A8698; - remoteInfo = intents; - }; - 34D458E62821A06E00EA9F93 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 64333D1D20B0C45900CDF4B6 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 34A8D4B4281EE5AE008A8698; - remoteInfo = station_intents; - }; - 34D458EA2821A07600EA9F93 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 64333D1D20B0C45900CDF4B6 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 34A8D488281EBFD9008A8698; - remoteInfo = station_widgets; - }; - 64333D3A20B0C45A00CDF4B6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 64333D1D20B0C45900CDF4B6 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 64333D2420B0C45900CDF4B6; - remoteInfo = station; - }; - 64333D4520B0C45B00CDF4B6 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 64333D1D20B0C45900CDF4B6 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 64333D2420B0C45900CDF4B6; - remoteInfo = station; - }; - E17C469E29956732008CFDD7 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 64333D1D20B0C45900CDF4B6 /* Project object */; - proxyType = 1; - remoteGlobalIDString = E17C469829956732008CFDD7; - remoteInfo = pnservice; - }; - E196D5B02B0137A100B60A90 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 64333D1D20B0C45900CDF4B6 /* Project object */; - proxyType = 1; - remoteGlobalIDString = E17C469829956732008CFDD7; - remoteInfo = pnservice; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 34A8D49A281EBFDB008A8698 /* Embed Foundation Extensions */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 12; - dstPath = ""; - dstSubfolderSpec = 13; - files = ( - E17C46A029956732008CFDD7 /* pnservice.appex in Embed Foundation Extensions */, - 34A8D4BE281EE5AE008A8698 /* station_intents.appex in Embed Foundation Extensions */, - 34A8D499281EBFDB008A8698 /* station_widgets.appex in Embed Foundation Extensions */, - ); - name = "Embed Foundation Extensions"; - runOnlyForDeploymentPostprocessing = 0; - }; - 34D458E82821A06E00EA9F93 /* Embed Foundation Extensions */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 13; - files = ( - E19EAF4C299679D8005827E4 /* pnservice.appex in Embed Foundation Extensions */, - 34D458E52821A06E00EA9F93 /* station_intents.appex in Embed Foundation Extensions */, - 34D458E92821A07600EA9F93 /* station_widgets.appex in Embed Foundation Extensions */, - ); - name = "Embed Foundation Extensions"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 0E00C4F02684D97B009B3C24 /* ExportHeadersProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExportHeadersProvider.swift; sourceTree = ""; }; - 0E00C5072685D82B009B3C24 /* RuuviDaemonError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviDaemonError+LocalizedError.swift"; sourceTree = ""; }; - 0E02ABB9237598C600ED4629 /* RURangeSeekSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RURangeSeekSlider.swift; sourceTree = ""; }; - 0E02ABCA2379483A00ED4629 /* Double+Temperature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+Temperature.swift"; sourceTree = ""; }; - 0E0501202685E895007060C4 /* HeartbeatDaemonTitles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatDaemonTitles.swift; sourceTree = ""; }; - 0E09672422AE897000E85F48 /* CALayer+IB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CALayer+IB.swift"; sourceTree = ""; }; - 0E0A381823616AC3003A0364 /* UserDefaults+Optional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+Optional.swift"; sourceTree = ""; }; - 0E197C6523C4A47A0074015B /* MailComposerPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailComposerPresenter.swift; sourceTree = ""; }; - 0E197C6A23C4A52A0074015B /* MailComposerPresenterMessageUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailComposerPresenterMessageUI.swift; sourceTree = ""; }; - 0E197C6E23C4A7D00074015B /* Presentation.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Presentation.plist; sourceTree = ""; }; - 0E197C7323C5C7A20074015B /* InfoProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoProvider.swift; sourceTree = ""; }; - 0E197C7823C5CCBB0074015B /* InfoProviderImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoProviderImpl.swift; sourceTree = ""; }; - 0E197C7C23C5CD7C0074015B /* UIDevice+ReadableModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+ReadableModel.swift"; sourceTree = ""; }; - 0E197C8023C5CDBE0074015B /* iOSDeviceModelMapping.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = iOSDeviceModelMapping.plist; sourceTree = ""; }; - 0E1C1D9F22B36C100032F6CA /* RUError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUError.swift; sourceTree = ""; }; - 0E1C1DA722B387A00032F6CA /* AppAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppAssembly.swift; sourceTree = ""; }; - 0E1C1DBA22B3919F0032F6CA /* UIApplication+ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+ViewController.swift"; sourceTree = ""; }; - 0E1C1DBD22B3921E0032F6CA /* PresentationAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentationAssembly.swift; sourceTree = ""; }; - 0E1C1DD222B3BF180032F6CA /* CardsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsViewInput.swift; sourceTree = ""; }; - 0E1C1DD422B3BF3A0032F6CA /* CardsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsViewOutput.swift; sourceTree = ""; }; - 0E1C1DDC22B3C2160032F6CA /* CardsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsModuleInput.swift; sourceTree = ""; }; - 0E1C1DE122B3C25F0032F6CA /* CardsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsRouterInput.swift; sourceTree = ""; }; - 0E1C1DE322B3C2710032F6CA /* CardsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsRouter.swift; sourceTree = ""; }; - 0E1C1DF022B3FDE30032F6CA /* Menu.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Menu.storyboard; sourceTree = ""; }; - 0E1C1DF222B3FEFF0032F6CA /* MenuViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuViewInput.swift; sourceTree = ""; }; - 0E1C1DF422B3FF1D0032F6CA /* MenuViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuViewOutput.swift; sourceTree = ""; }; - 0E1C1DF722B3FF480032F6CA /* MenuTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableViewController.swift; sourceTree = ""; }; - 0E1C1DF922B3FFBF0032F6CA /* MenuRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuRouterInput.swift; sourceTree = ""; }; - 0E1C1DFB22B3FFD90032F6CA /* MenuRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuRouter.swift; sourceTree = ""; }; - 0E1C1DFD22B3FFFC0032F6CA /* MenuModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuModuleInput.swift; sourceTree = ""; }; - 0E1C1DFF22B400130032F6CA /* MenuPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuPresenter.swift; sourceTree = ""; }; - 0E1C1E0222B400590032F6CA /* MenuTableInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableInitializer.swift; sourceTree = ""; }; - 0E1C1E0422B400890032F6CA /* MenuTableConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableConfigurator.swift; sourceTree = ""; }; - 0E1C1E0822B4024E0032F6CA /* MenuTableTransitioningDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableTransitioningDelegate.swift; sourceTree = ""; }; - 0E1C1E0A22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTablePresentTransitionAnimation.swift; sourceTree = ""; }; - 0E1C1E0C22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableDismissTransitionAnimation.swift; sourceTree = ""; }; - 0E1C1E0E22B4049E0032F6CA /* MenuTablePresentationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTablePresentationController.swift; sourceTree = ""; }; - 0E211C29234C5FE900FC37B0 /* CardsRouterDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsRouterDelegate.swift; sourceTree = ""; }; - 0E25135E2684AEAD004A522A /* RuuviNotifierTitlesImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviNotifierTitlesImpl.swift; sourceTree = ""; }; - 0E290A842660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+AnyRuuviTagSensor.swift"; sourceTree = ""; }; - 0E2AFF9F266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviRepositoryError+LocalizedError.swift"; sourceTree = ""; }; - 0E2B339A26A2BC3F00366B01 /* AppRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRouter.swift; sourceTree = ""; }; - 0E2B339D26A2BCBE00366B01 /* OnboardRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardRouter.swift; sourceTree = ""; }; - 0E3CA70B267365B1000D9B25 /* Debouncer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Debouncer.swift; sourceTree = ""; }; - 0E502FB922B27D4800E8A6CC /* TemperatureUnit+Localization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TemperatureUnit+Localization.swift"; sourceTree = ""; }; - 0E53A3F2232DFC6200ACED49 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 0E53A3F4232DFC6400ACED49 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = ""; }; - 0E53A3F5232DFC6500ACED49 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/InfoPlist.strings; sourceTree = ""; }; - 0E53DA5F22CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeDownToDismissTransitioningDelegate.swift; sourceTree = ""; }; - 0E53DA6122CC93EB00BC6D64 /* SwipeDownToDismissTransitionAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeDownToDismissTransitionAnimation.swift; sourceTree = ""; }; - 0E53DA6322CC943900BC6D64 /* SwipeDownToDismissInteractiveTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeDownToDismissInteractiveTransition.swift; sourceTree = ""; }; - 0E53DA6622CC964200BC6D64 /* SwipeDownToDismissNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeDownToDismissNavigationController.swift; sourceTree = ""; }; - 0E5C300A22CF629100B52E39 /* PhotoPickerPresenterSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPickerPresenterSheet.swift; sourceTree = ""; }; - 0E5C302422D0B19600B52E39 /* AppStateService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStateService.swift; sourceTree = ""; }; - 0E5C302722D0B1C600B52E39 /* AppStateServiceImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStateServiceImpl.swift; sourceTree = ""; }; - 0E62299426AAA0570041DCDD /* DiscoverRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoverRouter.swift; sourceTree = ""; }; - 0E6C471623D305960016B46E /* StationUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StationUITests.swift; sourceTree = ""; }; - 0E70A45F22AF9567006CB87C /* ViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewInput.swift; sourceTree = ""; }; - 0E70A46222AF959E006CB87C /* Localizable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Localizable.swift; sourceTree = ""; }; - 0E84BF542397F29800A37E1A /* Heartbeat.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Heartbeat.storyboard; sourceTree = ""; }; - 0E84BF562397F33E00A37E1A /* HeartbeatViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatViewInput.swift; sourceTree = ""; }; - 0E84BF582397F3C600A37E1A /* HeartbeatViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatViewModel.swift; sourceTree = ""; }; - 0E84BF5A2397F3DF00A37E1A /* HeartbeatViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatViewOutput.swift; sourceTree = ""; }; - 0E84BF5E2397F6BE00A37E1A /* HeartbeatViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatViewController.swift; sourceTree = ""; }; - 0E84BF602397F73100A37E1A /* HeartbeatEnvironmentObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatEnvironmentObject.swift; sourceTree = ""; }; - 0E84BF622397F76A00A37E1A /* HeartbeatList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatList.swift; sourceTree = ""; }; - 0E84BF642397F9DC00A37E1A /* HeartbeatTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatTableViewController.swift; sourceTree = ""; }; - 0E84BF66239801AF00A37E1A /* HeartbeatRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatRouterInput.swift; sourceTree = ""; }; - 0E84BF68239801C100A37E1A /* HeartbeatRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatRouter.swift; sourceTree = ""; }; - 0E84BF6A239802A400A37E1A /* HeartbeatModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatModuleInput.swift; sourceTree = ""; }; - 0E84BF6C239802CA00A37E1A /* HeartbeatPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatPresenter.swift; sourceTree = ""; }; - 0E84BF6E2398031B00A37E1A /* HeartbeatInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatInitializer.swift; sourceTree = ""; }; - 0E84BF702398035C00A37E1A /* HeartbeatConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartbeatConfigurator.swift; sourceTree = ""; }; - 0E869E2A265E5399006F4870 /* FirebaseRemoteConfig.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = FirebaseRemoteConfig.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 0E8A100123845E5100A9CBA6 /* Defaults.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Defaults.storyboard; sourceTree = ""; }; - 0E8A100923845F3900A9CBA6 /* DefaultsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsViewController.swift; sourceTree = ""; }; - 0E8A100B23845F7100A9CBA6 /* DefaultsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsViewInput.swift; sourceTree = ""; }; - 0E8A100D23845F8C00A9CBA6 /* DefaultsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsViewOutput.swift; sourceTree = ""; }; - 0E8A100F23845FAE00A9CBA6 /* DefaultsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsViewModel.swift; sourceTree = ""; }; - 0E8A10112384605A00A9CBA6 /* DefaultsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsTableViewController.swift; sourceTree = ""; }; - 0E8A10132384610400A9CBA6 /* DefaultsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsRouter.swift; sourceTree = ""; }; - 0E8A10152384612300A9CBA6 /* DefaultsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsRouterInput.swift; sourceTree = ""; }; - 0E8A10172384613E00A9CBA6 /* DefaultsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsModuleInput.swift; sourceTree = ""; }; - 0E8A10192384615400A9CBA6 /* DefaultsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsPresenter.swift; sourceTree = ""; }; - 0E8A101B2384618700A9CBA6 /* DefaultsInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsInitializer.swift; sourceTree = ""; }; - 0E8A101D238461D400A9CBA6 /* DefaultsConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsConfigurator.swift; sourceTree = ""; }; - 0E8A101F2384633200A9CBA6 /* DefaultsEnvironmentObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsEnvironmentObject.swift; sourceTree = ""; }; - 0E8A10212384637F00A9CBA6 /* DefaultsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsList.swift; sourceTree = ""; }; - 0E8A102423846CEB00A9CBA6 /* DefaultsSwitchTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsSwitchTableViewCell.swift; sourceTree = ""; }; - 0E8BAC97245C716B00D380FB /* Combine.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Combine.framework; path = System/Library/Frameworks/Combine.framework; sourceTree = SDKROOT; }; - 0E8BAC9A245C718700D380FB /* Combine.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Combine.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/Combine.framework; sourceTree = DEVELOPER_DIR; }; - 0E8BD2AA23851CF2008B31EF /* DefaultsStepperTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsStepperTableViewCell.swift; sourceTree = ""; }; - 0E8BD404238566AB008B31EF /* station_dev.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = station_dev.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 0E97D79A268C881300FE9D5B /* DFUModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DFUModuleInput.swift; sourceTree = ""; }; - 0E97D79D268C884500FE9D5B /* DFUPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DFUPresenter.swift; sourceTree = ""; }; - 0E97D7A7268C922C00FE9D5B /* DFUInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DFUInteractor.swift; sourceTree = ""; }; - 0E9D0AAF231E9BD800C6BDA7 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; - 0E9D0AB0231EBEFD00C6BDA7 /* LocalizationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizationService.swift; sourceTree = ""; }; - 0E9E7759238CCE5F006D7013 /* String+Replace.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Replace.swift"; sourceTree = ""; }; - 0E9F97B422EC44930015ADE2 /* Networking.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Networking.plist; sourceTree = ""; }; - 0EA511B7261F3C2C00EE5D5E /* LocalFeatureToggleProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalFeatureToggleProvider.swift; sourceTree = ""; }; - 0EA796702664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviCloudError+LocalizedError.swift"; sourceTree = ""; }; - 0EA796742664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviCloudApiError+LocalizedError.swift"; sourceTree = ""; }; - 0EA796782664B37F002BA25D /* RuuviLocalError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviLocalError+LocalizedError.swift"; sourceTree = ""; }; - 0EA7967C2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviPersistenceError+LocalizedError.swift"; sourceTree = ""; }; - 0EA796802664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviPoolError+LocalizedError.swift"; sourceTree = ""; }; - 0EA796842664B84D002BA25D /* RuuviReactorError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviReactorError+LocalizedError.swift"; sourceTree = ""; }; - 0EA796882664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviServiceError+LocalizedError.swift"; sourceTree = ""; }; - 0EA7968C2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviStorageError+LocalizedError.swift"; sourceTree = ""; }; - 0EA7AB792680A68200C137AD /* RuuviCoreError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviCoreError+LocalizedError.swift"; sourceTree = ""; }; - 0EB48D6E2619D50A008E0D2D /* FeatureToggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureToggle.swift; sourceTree = ""; }; - 0EB48D8A2619D5AC008E0D2D /* FeatureToggleService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureToggleService.swift; sourceTree = ""; }; - 0EB48D942619D5E5008E0D2D /* FeatureToggleProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureToggleProvider.swift; sourceTree = ""; }; - 0EB48DA22619D7EE008E0D2D /* FirebaseFeatureToggleProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseFeatureToggleProvider.swift; sourceTree = ""; }; - 0EB48DDB2619E306008E0D2D /* FallbackFeatureToggleProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FallbackFeatureToggleProvider.swift; sourceTree = ""; }; - 0EB48DE5261A1816008E0D2D /* FeatureToggles.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = FeatureToggles.json; sourceTree = ""; }; - 0EB48DFB261B105D008E0D2D /* RemoteConfigService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteConfigService.swift; sourceTree = ""; }; - 0EB48E05261B1095008E0D2D /* FirebaseRemoteConfigService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseRemoteConfigService.swift; sourceTree = ""; }; - 0EB8ED19268EF36200C6B0FA /* DFUViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DFUViewModel.swift; sourceTree = ""; }; - 0EB8ED1D268EFF4200C6B0FA /* Publishers+System.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Publishers+System.swift"; sourceTree = ""; }; - 0EB8ED20268EFF6400C6B0FA /* Feedback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Feedback.swift; sourceTree = ""; }; - 0EB8ED24268F083700C6B0FA /* DFUUIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DFUUIView.swift; sourceTree = ""; }; - 0EB8ED28268F10E900C6B0FA /* Spinner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Spinner.swift; sourceTree = ""; }; - 0EB8ED2B268F111B00C6B0FA /* View+Any.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Any.swift"; sourceTree = ""; }; - 0EB8ED2E268F12FA00C6B0FA /* DFUModuleFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DFUModuleFactory.swift; sourceTree = ""; }; - 0EB8ED35268F685500C6B0FA /* URLSession+downloadTaskPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLSession+downloadTaskPublisher.swift"; sourceTree = ""; }; - 0EB8ED38268F6A6900C6B0FA /* ProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressBar.swift; sourceTree = ""; }; - 0EB8ED3B268F8CD900C6B0FA /* FirmwareRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirmwareRepository.swift; sourceTree = ""; }; - 0EB8ED3E26916D1700C6B0FA /* LargeButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LargeButtonStyle.swift; sourceTree = ""; }; - 0EB8ED422692005900C6B0FA /* Colors.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Colors.xcassets; sourceTree = ""; }; - 0EB8ED462692018000C6B0FA /* RuuviColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviColor.swift; sourceTree = ""; }; - 0EBAF064232002A00025A191 /* Language+Localization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Language+Localization.swift"; sourceTree = ""; }; - 0EBAF0832320120F0025A191 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/Localizable.strings; sourceTree = ""; }; - 0EC50F4F22CCB92000172EEB /* Observable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Observable.swift; sourceTree = ""; }; - 0EC50F5322CCBBE800172EEB /* NSObject+Observable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSObject+Observable.swift"; sourceTree = ""; }; - 0EC50F5522CCE46D00172EEB /* Optional.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Optional.swift; sourceTree = ""; }; - 0EC50F5822CF621000172EEB /* PhotoPickerPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoPickerPresenter.swift; sourceTree = ""; }; - 0ECA19692B138C3A00BEE4DB /* FeatureTogglesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeatureTogglesViewController.swift; sourceTree = ""; }; - 0ECDF1B42313D65500A09ACA /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; - 0ECDF1B62313D7DA00A09ACA /* station.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = station.entitlements; sourceTree = ""; }; - 0EE36E3E26957E000021B746 /* DFUInteractorInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DFUInteractorInput.swift; sourceTree = ""; }; - 0EE36E4126957E200021B746 /* LatestRelease.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LatestRelease.swift; sourceTree = ""; }; - 0EE49BB123B8C40D003012C2 /* MacInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = MacInfo.plist; sourceTree = ""; }; - 0EE49BB223B8C40D003012C2 /* DevInfo.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = DevInfo.plist; sourceTree = ""; }; - 0EEB20C522B7915C0015F9E0 /* CardsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsViewModel.swift; sourceTree = ""; }; - 0EEB20C822B7A7200015F9E0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; - 0EEB20CA22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableEmbededViewController.swift; sourceTree = ""; }; - 0EEB20CC22B7BD6C0015F9E0 /* MenuModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuModuleOutput.swift; sourceTree = ""; }; - 0EEB20D022B7C6F30015F9E0 /* Settings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Settings.storyboard; sourceTree = ""; }; - 0EEB20D222B7C7AC0015F9E0 /* SettingsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableViewController.swift; sourceTree = ""; }; - 0EEB20D522B7C7E70015F9E0 /* SettingsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewInput.swift; sourceTree = ""; }; - 0EEB20D722B7C8060015F9E0 /* SettingsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewOutput.swift; sourceTree = ""; }; - 0EEB20DC22B7C8650015F9E0 /* SettingsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsRouterInput.swift; sourceTree = ""; }; - 0EEB20DE22B7C8790015F9E0 /* SettingsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsRouter.swift; sourceTree = ""; }; - 0EEB20E022B7C8A90015F9E0 /* SettingsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsModuleInput.swift; sourceTree = ""; }; - 0EEB20E222B7C8C10015F9E0 /* SettingsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsPresenter.swift; sourceTree = ""; }; - 0EEB20E522B7C8F20015F9E0 /* SettingsTableInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableInitializer.swift; sourceTree = ""; }; - 0EEB20E722B7C92C0015F9E0 /* SettingsTableConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableConfigurator.swift; sourceTree = ""; }; - 0EEB20EE22B7D1580015F9E0 /* About.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = About.storyboard; sourceTree = ""; }; - 0EEB20F222B7D1900015F9E0 /* AboutViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewInput.swift; sourceTree = ""; }; - 0EEB20F422B7D1A40015F9E0 /* AboutViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewOutput.swift; sourceTree = ""; }; - 0EEB20F622B7D2090015F9E0 /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = ""; }; - 0EEB20F822B7D28C0015F9E0 /* AboutRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutRouterInput.swift; sourceTree = ""; }; - 0EEB20FA22B7D2990015F9E0 /* AboutRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutRouter.swift; sourceTree = ""; }; - 0EEB20FC22B7D2C90015F9E0 /* AboutModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutModuleInput.swift; sourceTree = ""; }; - 0EEB20FE22B7D2DD0015F9E0 /* AboutPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutPresenter.swift; sourceTree = ""; }; - 0EEB210022B7D2F50015F9E0 /* AboutInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutInitializer.swift; sourceTree = ""; }; - 0EEB210222B7D3210015F9E0 /* AboutConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutConfigurator.swift; sourceTree = ""; }; - 0EEB215922BA28860015F9E0 /* MenuTableTransitionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuTableTransitionManager.swift; sourceTree = ""; }; - 0EF2863022CBB00D0026C7A5 /* TagSettingsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsViewInput.swift; sourceTree = ""; }; - 0EF2863222CBB0250026C7A5 /* TagSettingsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsViewOutput.swift; sourceTree = ""; }; - 0EF4E33C26824ABD00D83CC7 /* RuuviDFUError+LocalizedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviDFUError+LocalizedError.swift"; sourceTree = ""; }; - 0EF4E33F26824EF500D83CC7 /* DfuFirmware+Log.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DfuFirmware+Log.swift"; sourceTree = ""; }; - 0EF5B72A22D62CD900D9D14A /* Date+Ruuvi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Ruuvi.swift"; sourceTree = ""; }; - 0EF5B75322DE153A00D9D14A /* HumidityUnit+Localization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HumidityUnit+Localization.swift"; sourceTree = ""; }; - 167F75FD2FDAD002C10686FA /* ShareViewInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareViewInput.swift; sourceTree = ""; }; - 2CFE01D4D914A918175D4BEA /* Pods-stationTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-stationTests.debug.xcconfig"; path = "Target Support Files/Pods-stationTests/Pods-stationTests.debug.xcconfig"; sourceTree = ""; }; - 310159B82644864400A5E8E8 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; - 310159B92644864C00A5E8E8 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/InfoPlist.strings; sourceTree = ""; }; - 340BE37127B54E25006D6C34 /* PresentationConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresentationConstants.swift; sourceTree = ""; }; - 340BE37427B54EE2006D6C34 /* AppAssemblyConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppAssemblyConstants.swift; sourceTree = ""; }; - 340BE37827B54F37006D6C34 /* Owner.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Owner.storyboard; sourceTree = ""; }; - 340BE37A27B54F37006D6C34 /* OwnerInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OwnerInitializer.swift; sourceTree = ""; }; - 340BE37B27B54F37006D6C34 /* OwnerConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OwnerConfigurator.swift; sourceTree = ""; }; - 340BE37D27B54F37006D6C34 /* OwnerPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OwnerPresenter.swift; sourceTree = ""; }; - 340BE37E27B54F37006D6C34 /* OwnerModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OwnerModuleInput.swift; sourceTree = ""; }; - 340BE38027B54F37006D6C34 /* OwnerViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OwnerViewInput.swift; sourceTree = ""; }; - 340BE38127B54F37006D6C34 /* OwnerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OwnerViewController.swift; sourceTree = ""; }; - 340BE38227B54F37006D6C34 /* OwnerViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OwnerViewOutput.swift; sourceTree = ""; }; - 340BE38427B54F37006D6C34 /* OwnerRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OwnerRouter.swift; sourceTree = ""; }; - 340BE38527B54F37006D6C34 /* OwnerRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OwnerRouterInput.swift; sourceTree = ""; }; - 340BE39A27B54FEB006D6C34 /* String+Email.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Email.swift"; sourceTree = ""; }; - 340BE39D27B56128006D6C34 /* ruuvi_logo_splash.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ruuvi_logo_splash.png; sourceTree = ""; }; - 341401EB282D03C8003DE721 /* MeasurementService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeasurementService.swift; sourceTree = ""; }; - 3414BFC72806D19C00C63BE9 /* RuuviCodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviCodeView.swift; sourceTree = ""; }; - 3414BFCA2806D1B300C63BE9 /* RuuviCodeTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviCodeTextField.swift; sourceTree = ""; }; - 3451BD8427E0F9870065A7A6 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; - 3451BD8527E0F9880065A7A6 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/InfoPlist.strings; sourceTree = ""; }; - 3490A4C227D9F2C70032BBAB /* UINavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UINavigationController.swift; sourceTree = ""; }; - 3493385C28300396009060E8 /* NetworkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = ""; }; - 3493386228300A73009060E8 /* SimpleWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleWidgetView.swift; sourceTree = ""; }; - 3493386428300ACC009060E8 /* UnauthorizedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnauthorizedView.swift; sourceTree = ""; }; - 3493386628300B05009060E8 /* EmptyWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyWidgetView.swift; sourceTree = ""; }; - 3493386B28300C49009060E8 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = ""; }; - 3493386E283014A0009060E8 /* Model+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Model+Extension.swift"; sourceTree = ""; }; - 34933872283014F6009060E8 /* WidgetSensorEnum.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetSensorEnum.swift; sourceTree = ""; }; - 34A8D489281EBFD9008A8698 /* station_widgets.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = station_widgets.appex; sourceTree = BUILT_PRODUCTS_DIR; }; - 34A8D48A281EBFD9008A8698 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; - 34A8D48C281EBFD9008A8698 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; - 34A8D48F281EBFD9008A8698 /* RuuviWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviWidgets.swift; sourceTree = ""; }; - 34A8D492281EBFDB008A8698 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 34A8D494281EBFDB008A8698 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 34A8D49E281EC2B6008A8698 /* ruuvi_widgets.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ruuvi_widgets.entitlements; sourceTree = ""; }; - 34A8D4A1281ED018008A8698 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; - 34A8D4A4281ED046008A8698 /* Montserrat-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Montserrat-Regular.ttf"; sourceTree = ""; }; - 34A8D4A5281ED046008A8698 /* Montserrat-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Montserrat-Bold.ttf"; sourceTree = ""; }; - 34A8D4A6281ED046008A8698 /* Muli-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Muli-Regular.ttf"; sourceTree = ""; }; - 34A8D4A7281ED046008A8698 /* Oswald-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Oswald-Bold.ttf"; sourceTree = ""; }; - 34A8D4A8281ED046008A8698 /* Oswald-ExtraLight.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Oswald-ExtraLight.ttf"; sourceTree = ""; }; - 34A8D4A9281ED046008A8698 /* Muli-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Muli-Bold.ttf"; sourceTree = ""; }; - 34A8D4B5281EE5AE008A8698 /* station_intents.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = station_intents.appex; sourceTree = BUILT_PRODUCTS_DIR; }; - 34A8D4B6281EE5AE008A8698 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; - 34A8D4B9281EE5AE008A8698 /* IntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentHandler.swift; sourceTree = ""; }; - 34A8D4BB281EE5AE008A8698 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 34A8D4C3281EEBF8008A8698 /* WidgetProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetProvider.swift; sourceTree = ""; }; - 34A8D4C5281EEC19008A8698 /* WidgetEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetEntry.swift; sourceTree = ""; }; - 34A8D4CA281FEF2E008A8698 /* station_intents.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = station_intents.entitlements; sourceTree = ""; }; - 34D458DF28216B2200EA9F93 /* WidgetAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetAssembly.swift; sourceTree = ""; }; - 34D458E128216C6900EA9F93 /* WidgetViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetViewModel.swift; sourceTree = ""; }; - 354B5B6F50E98F55D6A672BA /* ShareViewModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareViewModel.swift; sourceTree = ""; }; - 392F0E992BEAA3382C2CF709 /* ShareInitializer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareInitializer.swift; sourceTree = ""; }; - 3BC7A7F074761C1B58F7F946 /* Pods-station_dev.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-station_dev.debug.xcconfig"; path = "Target Support Files/Pods-station_dev/Pods-station_dev.debug.xcconfig"; sourceTree = ""; }; - 437F08C73081253CCDA3687A /* Pods-station_intents.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-station_intents.debug.xcconfig"; path = "Target Support Files/Pods-station_intents/Pods-station_intents.debug.xcconfig"; sourceTree = ""; }; - 47B3F8D904CAAB34D68A68DC /* Pods-station_widgets.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-station_widgets.release.xcconfig"; path = "Target Support Files/Pods-station_widgets/Pods-station_widgets.release.xcconfig"; sourceTree = ""; }; - 4A7D6325DFC865D2D11BD1D1 /* SignInViewInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInViewInput.swift; sourceTree = ""; }; - 4BD498E7491E278B4EF4919C /* SignInViewOutput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInViewOutput.swift; sourceTree = ""; }; - 4E816312622E83E3B42001DC /* SignInRouterInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInRouterInput.swift; sourceTree = ""; }; - 50760BEF3DF7F0DC671A0D42 /* Pods-station.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-station.debug.xcconfig"; path = "Target Support Files/Pods-station/Pods-station.debug.xcconfig"; sourceTree = ""; }; - 5710E4EF18D419D01D60405E /* ShareModuleOutput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareModuleOutput.swift; sourceTree = ""; }; - 5C35D73AC96D7B6765529406 /* Pods-station_widgets.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-station_widgets.debug.xcconfig"; path = "Target Support Files/Pods-station_widgets/Pods-station_widgets.debug.xcconfig"; sourceTree = ""; }; - 64333D2520B0C45900CDF4B6 /* station.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = station.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 64333D2820B0C45900CDF4B6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 64333D2F20B0C45A00CDF4B6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 64333D3220B0C45A00CDF4B6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 64333D3420B0C45A00CDF4B6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 64333D3920B0C45A00CDF4B6 /* stationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = stationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 64333D3D20B0C45A00CDF4B6 /* StationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StationTests.swift; sourceTree = ""; }; - 64333D3F20B0C45B00CDF4B6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 64333D4420B0C45B00CDF4B6 /* stationUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = stationUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 64333D4A20B0C45B00CDF4B6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 643C651E21C38F490037BE5B /* Montserrat-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Montserrat-Bold.ttf"; sourceTree = ""; }; - 643EEC2A2266435100D4E837 /* Oswald-ExtraLight.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Oswald-ExtraLight.ttf"; sourceTree = ""; }; - 6467818F225CFB170072856A /* Muli-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Muli-Regular.ttf"; sourceTree = ""; }; - 64678190225D02CE0072856A /* Muli-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Muli-Bold.ttf"; sourceTree = ""; }; - 6486970F20E042E000CCD7C1 /* Oswald-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Oswald-Bold.ttf"; sourceTree = ""; }; - 6486971120E0439200CCD7C1 /* Montserrat-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Montserrat-Regular.ttf"; sourceTree = ""; }; - 64A2DAE224310B2900DE6699 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = ""; }; - 64A2DAE324310B2900DE6699 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/InfoPlist.strings; sourceTree = ""; }; - 660EB29B266928E6000FD22B /* UIViewController+Alert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Alert.swift"; sourceTree = ""; }; - 66718A6B266BD0E800A380F8 /* Color+Ruuvi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Ruuvi.swift"; sourceTree = ""; }; - 66BC44832657AED400A03253 /* OffsetCorrection.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = OffsetCorrection.storyboard; sourceTree = ""; }; - 66BC44862657AED400A03253 /* OffsetCorrectionAppleInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionAppleInitializer.swift; sourceTree = ""; }; - 66BC44872657AED400A03253 /* OffsetCorrectionConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionConfigurator.swift; sourceTree = ""; }; - 66BC44892657AED400A03253 /* OffsetCorrectionModuleOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionModuleOutput.swift; sourceTree = ""; }; - 66BC448A2657AED400A03253 /* OffsetCorrectionPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionPresenter.swift; sourceTree = ""; }; - 66BC448B2657AED400A03253 /* OffsetCorrectionModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionModuleInput.swift; sourceTree = ""; }; - 66BC448E2657AED400A03253 /* OffsetCorrectionAppleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionAppleViewController.swift; sourceTree = ""; }; - 66BC448F2657AED400A03253 /* OffsetCorrectionViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionViewInput.swift; sourceTree = ""; }; - 66BC44902657AED400A03253 /* OffsetCorrectionViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionViewModel.swift; sourceTree = ""; }; - 66BC44912657AED400A03253 /* OffsetCorrectionViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionViewOutput.swift; sourceTree = ""; }; - 66BC44932657AED400A03253 /* OffsetCorrectionRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionRouter.swift; sourceTree = ""; }; - 66BC44942657AED400A03253 /* OffsetCorrectionRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OffsetCorrectionRouterInput.swift; sourceTree = ""; }; - 6AE2284D927021C0BEA560B0 /* ShareModuleInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareModuleInput.swift; sourceTree = ""; }; - 6F0552F1D17F403B7DE508B5 /* SignInRouter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInRouter.swift; sourceTree = ""; }; - 7097B76856D5F01896F963EC /* Pods_station_dev.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_station_dev.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 8018B7836CF8C748718825DD /* Pods_station.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_station.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 85F06A44D8D006FBFB90ABE0 /* Pods-station_dev.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-station_dev.release.xcconfig"; path = "Target Support Files/Pods-station_dev/Pods-station_dev.release.xcconfig"; sourceTree = ""; }; - 87EFB230083D471777FBE5D0 /* SignInModuleInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInModuleInput.swift; sourceTree = ""; }; - 8825D89E1A7CB4BDC6D12038 /* Pods-stationTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-stationTests.release.xcconfig"; path = "Target Support Files/Pods-stationTests/Pods-stationTests.release.xcconfig"; sourceTree = ""; }; - 9174E0B0C8F457647FEE639C /* Pods_stationTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_stationTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 9546F1EFEE8F8CFC22377BB4 /* ShareRouterInput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareRouterInput.swift; sourceTree = ""; }; - 9B3006A5FB2173EC6AA2728D /* SignInModuleOutput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInModuleOutput.swift; sourceTree = ""; }; - A907BB1024AE620A009DA3DB /* UIWindow+Orientation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindow+Orientation.swift"; sourceTree = ""; }; - A9100D82241AD1E4004007FD /* MockAlertPersistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAlertPersistence.swift; sourceTree = ""; }; - A91D02DD2511207200694733 /* SelectionTableConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionTableConfigurator.swift; sourceTree = ""; }; - A91D02DE2511207200694733 /* SelectionTableInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionTableInitializer.swift; sourceTree = ""; }; - A91D02E02511207200694733 /* SelectionPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionPresenter.swift; sourceTree = ""; }; - A91D02E12511207200694733 /* SelectionModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionModuleInput.swift; sourceTree = ""; }; - A91D02E32511207200694733 /* SelectionViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionViewInput.swift; sourceTree = ""; }; - A91D02E52511207200694733 /* SelectionTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionTableViewCell.swift; sourceTree = ""; }; - A91D02E62511207200694733 /* SelectionTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionTableViewController.swift; sourceTree = ""; }; - A91D02E72511207200694733 /* SelectionViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionViewOutput.swift; sourceTree = ""; }; - A91D02E92511207200694733 /* SelectionRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionRouter.swift; sourceTree = ""; }; - A91D02EA2511207200694733 /* SelectionRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectionRouterInput.swift; sourceTree = ""; }; - A91D030C251121C800694733 /* Selection.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Selection.storyboard; sourceTree = ""; }; - A91D0310251123B400694733 /* SelectionModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectionModuleOutput.swift; sourceTree = ""; }; - A91D0315251124F900694733 /* SelectionItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectionItem.swift; sourceTree = ""; }; - A91D031925113EAA00694733 /* UnitPressure+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UnitPressure+Extension.swift"; sourceTree = ""; }; - A92A66BC2450C640002918E7 /* UITableViewCell+ReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITableViewCell+ReusableView.swift"; sourceTree = ""; }; - A92C75DF24896BA100E332FE /* Appfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = Appfile; sourceTree = ""; }; - A92C75E024896BA100E332FE /* Fastfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = Fastfile; sourceTree = ""; }; - A92C75E124896BA100E332FE /* Gemfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = Gemfile; sourceTree = ""; }; - A92C75E2248982A000E332FE /* Pluginfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = Pluginfile; sourceTree = ""; }; - A92E3C4B24261CF900D981D5 /* MeasurementType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeasurementType.swift; sourceTree = ""; }; - A935E47525A49E8F009538C4 /* MeasurementsServiceFiSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeasurementsServiceFiSpec.swift; sourceTree = ""; }; - A935E47C25A49E9E009538C4 /* MeasurementsServiceRuSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeasurementsServiceRuSpec.swift; sourceTree = ""; }; - A93CDCCE25659BA600018C6C /* AlertPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertPresenter.swift; sourceTree = ""; }; - A93CDCDD25659BF600018C6C /* AlertPresenterImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertPresenterImpl.swift; sourceTree = ""; }; - A949A83A24707FD0006B7F4F /* LocalizedCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalizedCache.swift; sourceTree = ""; }; - A94FFD3B241C1D0D00888017 /* AlertServiceSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertServiceSpec.swift; sourceTree = ""; }; - A94FFD49241D45C600888017 /* MockRuuviTag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRuuviTag.swift; sourceTree = ""; }; - A94FFD4B241D512900888017 /* MockLocalNotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockLocalNotificationsManager.swift; sourceTree = ""; }; - A94FFD4D241D57E700888017 /* MockCalibrationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockCalibrationService.swift; sourceTree = ""; }; - A94FFD4F241D6BA300888017 /* MockAlertServiceObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAlertServiceObserver.swift; sourceTree = ""; }; - A9646454247BAE6A0001D55D /* ChartSettingsViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartSettingsViewInput.swift; sourceTree = ""; }; - A9646458247BAE6A0001D55D /* ChartSettingsStepperTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartSettingsStepperTableViewCell.swift; sourceTree = ""; }; - A9646459247BAE6A0001D55D /* ChartSettingsSwitchTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartSettingsSwitchTableViewCell.swift; sourceTree = ""; }; - A964645A247BAE6A0001D55D /* ChartSettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartSettingsTableViewController.swift; sourceTree = ""; }; - A964645B247BAE6A0001D55D /* ChartSettingsViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartSettingsViewOutput.swift; sourceTree = ""; }; - A964645C247BAE6A0001D55D /* ChartSettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartSettingsViewModel.swift; sourceTree = ""; }; - A964645E247BAE6A0001D55D /* ChartSettingsConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartSettingsConfigurator.swift; sourceTree = ""; }; - A964645F247BAE6A0001D55D /* ChartSettingsInitializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartSettingsInitializer.swift; sourceTree = ""; }; - A9646461247BAE6A0001D55D /* ChartModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartModuleInput.swift; sourceTree = ""; }; - A9646462247BAE6A0001D55D /* ChartSettingsPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartSettingsPresenter.swift; sourceTree = ""; }; - A9646464247BAE6A0001D55D /* ChartSettingsRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartSettingsRouterInput.swift; sourceTree = ""; }; - A9646465247BAE6A0001D55D /* ChartSettingsRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChartSettingsRouter.swift; sourceTree = ""; }; - A964648D247BAEBA0001D55D /* ChartSettings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = ChartSettings.storyboard; sourceTree = ""; }; - A96B1F2225A7943E00D3ED9C /* station.localization.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; name = station.localization.json; path = station.localization/station.localization.json; sourceTree = SOURCE_ROOT; }; - A971B0DB24215334008EF50D /* XCTest+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCTest+Extension.swift"; sourceTree = ""; }; - A976CA7D24A928C20099BDC1 /* ChartSettingsDisclosureTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartSettingsDisclosureTableViewCell.swift; sourceTree = ""; }; - A980573725807118000D03AB /* AboutViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewModel.swift; sourceTree = ""; }; - A986147A248C49B00030F197 /* Matchfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Matchfile; sourceTree = ""; }; - A9A48A5B244CD9E70004FD50 /* UIWindow+Shake.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIWindow+Shake.swift"; sourceTree = ""; }; - A9A67BF924C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSObjectProtocol+Invalidation.swift"; sourceTree = ""; }; - A9BB94CB2540AB610042B190 /* AlertViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertViewModel.swift; sourceTree = ""; }; - A9BD38B924F6108300904BBE /* Humidity+Offset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Humidity+Offset.swift"; sourceTree = ""; }; - A9E5993F25572CF700F9E5CC /* Share.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Share.storyboard; sourceTree = ""; }; - A9E599492557341F00F9E5CC /* ShareDescriptionTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareDescriptionTableViewCell.swift; sourceTree = ""; }; - A9E599572557345200F9E5CC /* ShareEmailInputTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareEmailInputTableViewCell.swift; sourceTree = ""; }; - A9E599602557346600F9E5CC /* ShareSendButtonTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareSendButtonTableViewCell.swift; sourceTree = ""; }; - A9E59969255734A000F9E5CC /* ShareEmailTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareEmailTableViewCell.swift; sourceTree = ""; }; - A9E6770D25A30D0A000B75A3 /* MeasurementsServiceEnSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MeasurementsServiceEnSpec.swift; sourceTree = ""; }; - A9E6771925A31556000B75A3 /* MeasurementsServiceSvSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeasurementsServiceSvSpec.swift; sourceTree = ""; }; - A9E6774725A33081000B75A3 /* String+Characters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Characters.swift"; sourceTree = ""; }; - A9FC78E82579671B00F94604 /* UniversalLinkCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalLinkCoordinator.swift; sourceTree = ""; }; - A9FC78FE2579675100F94604 /* UniversalLinkRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalLinkRouter.swift; sourceTree = ""; }; - A9FC790D2579676E00F94604 /* UniversalLinkRouterImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalLinkRouterImpl.swift; sourceTree = ""; }; - A9FC79162579678D00F94604 /* UniversalLinkCoordinatormpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UniversalLinkCoordinatormpl.swift; sourceTree = ""; }; - AB681E62A66E5924A87859B1 /* ShareConfigurator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareConfigurator.swift; sourceTree = ""; }; - B004B50BE06AD9034B2EFCB4 /* Pods_station_intents.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_station_intents.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - B3426764B50E4E9CA2A27704 /* Pods-station.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-station.release.xcconfig"; path = "Target Support Files/Pods-station/Pods-station.release.xcconfig"; sourceTree = ""; }; - B5EE8D004C84A07188EF2E3A /* Pods-station_intents.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-station_intents.release.xcconfig"; path = "Target Support Files/Pods-station_intents/Pods-station_intents.release.xcconfig"; sourceTree = ""; }; - BD7AE39C23B8C52BB202BB5E /* ShareRouter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareRouter.swift; sourceTree = ""; }; - CC1D67615D6DBA9E2FC5B402 /* SharePresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SharePresenter.swift; sourceTree = ""; }; - CE5C4AD5C54EF024669EAF47 /* ShareViewOutput.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareViewOutput.swift; sourceTree = ""; }; - D63A307EB55306A1D598FDAE /* Pods_station_widgets.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_station_widgets.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - E1072686291C49E500247625 /* SimpleWidgetViewInline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleWidgetViewInline.swift; sourceTree = ""; }; - E10E18712978AF3D002C78C3 /* TagSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsViewModel.swift; sourceTree = ""; }; - E10E18AA297D6664002C78C3 /* RuuviCloudModuleFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviCloudModuleFactory.swift; sourceTree = ""; }; - E10E18AD297D6672002C78C3 /* RuuviCloudPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviCloudPresenter.swift; sourceTree = ""; }; - E10E18B0297D6690002C78C3 /* RuuviCloudTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviCloudTableViewController.swift; sourceTree = ""; }; - E10E18B3297D67B8002C78C3 /* RuuviCloudViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviCloudViewModel.swift; sourceTree = ""; }; - E10E18B6297D67E8002C78C3 /* RuuviCloudViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviCloudViewInput.swift; sourceTree = ""; }; - E10E18B9297D67FC002C78C3 /* RuuviCloudViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviCloudViewOutput.swift; sourceTree = ""; }; - E10E18BC297D68EB002C78C3 /* RuuviCloudModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviCloudModuleInput.swift; sourceTree = ""; }; - E10E18C0297DD0CA002C78C3 /* RuuviCloudTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviCloudTableViewCell.swift; sourceTree = ""; }; - E10E18C3297DE3AF002C78C3 /* TagChartsMarkerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsMarkerView.swift; sourceTree = ""; }; - E1117007291C34A700ACCD72 /* SimpleWidgetViewRectangle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleWidgetViewRectangle.swift; sourceTree = ""; }; - E116706E29620AD4002DF7BF /* BackgroundSelectionButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSelectionButtonView.swift; sourceTree = ""; }; - E116707529634332002DF7BF /* BackgroundSelectionViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSelectionViewInput.swift; sourceTree = ""; }; - E116707829634363002DF7BF /* BackgroundSelectionViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSelectionViewOutput.swift; sourceTree = ""; }; - E1167081296346D5002DF7BF /* BackgroundSelectionModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSelectionModuleInput.swift; sourceTree = ""; }; - E116708429634708002DF7BF /* BackgroundSelectionPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSelectionPresenter.swift; sourceTree = ""; }; - E116708729634815002DF7BF /* BackgroundSelectionModuleFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSelectionModuleFactory.swift; sourceTree = ""; }; - E116708B29634D91002DF7BF /* BackgroundSelectionViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSelectionViewModel.swift; sourceTree = ""; }; - E116708E29635B53002DF7BF /* BackgroundSelectionUploadProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSelectionUploadProgressView.swift; sourceTree = ""; }; - E116AED12A059578003EF65A /* ruuvi_speak.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = ruuvi_speak.caf; sourceTree = ""; }; - E11989F429B7A46E002245CF /* UIView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Extension.swift"; sourceTree = ""; }; - E11989FE29BA60CE002245CF /* AppearanceSettingsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceSettingsTableViewController.swift; sourceTree = ""; }; - E1198A0129BA6193002245CF /* AppearanceSettingsTableViewBasicCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceSettingsTableViewBasicCell.swift; sourceTree = ""; }; - E1198A0729BA68B6002245CF /* AppearanceSettingsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceSettingsRouterInput.swift; sourceTree = ""; }; - E1198A0A29BA68BE002245CF /* AppearanceSettingsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceSettingsRouter.swift; sourceTree = ""; }; - E1198A0D29BA68FD002245CF /* AppearanceSettingsModuleFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceSettingsModuleFactory.swift; sourceTree = ""; }; - E1198A1029BA6910002245CF /* AppearanceSettingsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceSettingsPresenter.swift; sourceTree = ""; }; - E1198A1429BA6A06002245CF /* AppearanceSettingsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceSettingsViewOutput.swift; sourceTree = ""; }; - E1198A1729BA6A61002245CF /* AppearanceSettingsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceSettingsViewInput.swift; sourceTree = ""; }; - E1198A1A29BA6A79002245CF /* AppearanceSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceSettingsViewModel.swift; sourceTree = ""; }; - E1198A1D29BA6B7E002245CF /* AppearanceSettingsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceSettingsModuleInput.swift; sourceTree = ""; }; - E1198A2029BA6EC6002245CF /* RuuviTheme+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviTheme+Extension.swift"; sourceTree = ""; }; - E1198A2529BA763F002245CF /* ASSelectionModuleFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASSelectionModuleFactory.swift; sourceTree = ""; }; - E1198A2B29BA769A002245CF /* ASSelectionTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASSelectionTableViewController.swift; sourceTree = ""; }; - E1198A2E29BA76A8002245CF /* ASSelectionTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASSelectionTableViewCell.swift; sourceTree = ""; }; - E1198A3129BA76C1002245CF /* ASSelectionViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASSelectionViewOutput.swift; sourceTree = ""; }; - E1198A3429BA76CB002245CF /* ASSelectionViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASSelectionViewInput.swift; sourceTree = ""; }; - E1198A3729BA76DD002245CF /* ASSelectionPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASSelectionPresenter.swift; sourceTree = ""; }; - E1198A3A29BA76F1002245CF /* ASSelectionModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASSelectionModuleInput.swift; sourceTree = ""; }; - E11FDA6929A1757C003ADA7B /* splash_bg_layer_dark.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = splash_bg_layer_dark.jpg; sourceTree = ""; }; - E11FDA6C29A2A3C2003ADA7B /* DefaultsPlainTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsPlainTableViewCell.swift; sourceTree = ""; }; - E11FDA6F29A3F78D003ADA7B /* RuuviSimpleViewCompositionalLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviSimpleViewCompositionalLayout.swift; sourceTree = ""; }; - E128160A292ABCFA008E9282 /* SimpleWidgetViewCircular.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleWidgetViewCircular.swift; sourceTree = ""; }; - E1395BE9294F6C2A00C403C6 /* String+Localization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Localization.swift"; sourceTree = ""; }; - E1395BF0294F793000C403C6 /* AppDateFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDateFormatter.swift; sourceTree = ""; }; - E1395BF82954DAA200C403C6 /* CardsInteractorInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsInteractorInput.swift; sourceTree = ""; }; - E1395BFB2954DAAD00C403C6 /* CardsInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsInteractor.swift; sourceTree = ""; }; - E1395BFF2957944E00C403C6 /* CardsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsViewController.swift; sourceTree = ""; }; - E1395C022958A2A900C403C6 /* CardsIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsIndicatorView.swift; sourceTree = ""; }; - E1395C052958A33400C403C6 /* CardsBackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsBackgroundView.swift; sourceTree = ""; }; - E1597A2C295B6E6B00DFB70B /* UIFont+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIFont+Extension.swift"; sourceTree = ""; }; - E1597A2F295B909B00DFB70B /* DashboardPlainCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardPlainCell.swift; sourceTree = ""; }; - E1597A32295CC4F900DFB70B /* LowBatteryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LowBatteryView.swift; sourceTree = ""; }; - E1597A3C295CD52A00DFB70B /* DashboardRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardRouterInput.swift; sourceTree = ""; }; - E1597A3F295CD55300DFB70B /* DashboardRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardRouter.swift; sourceTree = ""; }; - E1597A42295CD58600DFB70B /* DashboardRouterDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardRouterDelegate.swift; sourceTree = ""; }; - E1597A45295CD5E400DFB70B /* DashboardModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardModuleInput.swift; sourceTree = ""; }; - E1597A48295CD5F800DFB70B /* DashboardPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardPresenter.swift; sourceTree = ""; }; - E1597A4B295CD66500DFB70B /* DashboardInteractorInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardInteractorInput.swift; sourceTree = ""; }; - E1597A4E295CD67900DFB70B /* DashboardInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardInteractor.swift; sourceTree = ""; }; - E1597A51295CD6BB00DFB70B /* DashboardViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardViewInput.swift; sourceTree = ""; }; - E1597A54295CD6E300DFB70B /* DashboardViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardViewOutput.swift; sourceTree = ""; }; - E1597A5B295E24D400DFB70B /* RuuviAssets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviAssets.swift; sourceTree = ""; }; - E1597A5E295F803400DFB70B /* UIColor+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+Extension.swift"; sourceTree = ""; }; - E1597A6429608CF300DFB70B /* GlobalHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalHelpers.swift; sourceTree = ""; }; - E1597A672960944600DFB70B /* DashboardCellDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardCellDelegate.swift; sourceTree = ""; }; - E1597A6E2961FEB800DFB70B /* BackgroundSelectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSelectionViewController.swift; sourceTree = ""; }; - E1597A712962000B00DFB70B /* BackgroundSelectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSelectionViewCell.swift; sourceTree = ""; }; - E1597A742962046500DFB70B /* BackgroundSelectionViewHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundSelectionViewHeader.swift; sourceTree = ""; }; - E16051E5285A15A1003FCA70 /* RuuviTagBatteryStatusProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviTagBatteryStatusProvider.swift; sourceTree = ""; }; - E16051E8285CB384003FCA70 /* AppStoreReviewHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStoreReviewHelper.swift; sourceTree = ""; }; - E16051EB285CBA57003FCA70 /* FileManager+Date.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+Date.swift"; sourceTree = ""; }; - E168B4AA2885C28000D6B5C6 /* MeasurementAccuracyTitles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeasurementAccuracyTitles.swift; sourceTree = ""; }; - E168B4AD2886AE4E00D6B5C6 /* MeasurementAccuracyType+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MeasurementAccuracyType+Extension.swift"; sourceTree = ""; }; - E168B4B52886AF1200D6B5C6 /* UnitSettingsType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitSettingsType.swift; sourceTree = ""; }; - E16B8F3B28D109DD0025B92D /* MyRuuvi.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = MyRuuvi.storyboard; sourceTree = ""; }; - E16B8F3E28D10CF50025B92D /* MyRuuviAccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyRuuviAccountViewController.swift; sourceTree = ""; }; - E16B8F4128D10DF90025B92D /* MyRuuviAccountViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyRuuviAccountViewInput.swift; sourceTree = ""; }; - E16B8F4428D10E2C0025B92D /* MyRuuviAccountViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyRuuviAccountViewOutput.swift; sourceTree = ""; }; - E16B8F4728D10E7A0025B92D /* MyRuuviAccountViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyRuuviAccountViewModel.swift; sourceTree = ""; }; - E16B8F4A28D1114F0025B92D /* MyRuuviAccountModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyRuuviAccountModuleInput.swift; sourceTree = ""; }; - E16B8F4D28D113230025B92D /* MyRuuviAccountInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyRuuviAccountInitializer.swift; sourceTree = ""; }; - E16B8F5028D113440025B92D /* MyRuuviAccountConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyRuuviAccountConfigurator.swift; sourceTree = ""; }; - E16B8F5328D113750025B92D /* MyRuuviAccountPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyRuuviAccountPresenter.swift; sourceTree = ""; }; - E16B8F5628D113CB0025B92D /* MyRuuviAccountRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyRuuviAccountRouterInput.swift; sourceTree = ""; }; - E16B8F5928D113EA0025B92D /* MyRuuviAccountRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyRuuviAccountRouter.swift; sourceTree = ""; }; - E17C469929956732008CFDD7 /* pnservice.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = pnservice.appex; sourceTree = BUILT_PRODUCTS_DIR; }; - E17C469B29956732008CFDD7 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; - E17C469D29956732008CFDD7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - E186AB2F2844A273004926FC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/RuuviWidgetsConfiguration.intentdefinition; sourceTree = ""; }; - E186AB322844A27C004926FC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/RuuviWidgetsConfiguration.strings; sourceTree = ""; }; - E186AB342844A27E004926FC /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/RuuviWidgetsConfiguration.strings; sourceTree = ""; }; - E18D04A028E879EE008EF5EC /* UIView+Init.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Init.swift"; sourceTree = ""; }; - E18D04A428E8A5A3008EF5EC /* TagChartsViewConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewConfigurator.swift; sourceTree = ""; }; - E18D04A828E8A6C0008EF5EC /* TagChartsViewPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewPresenter.swift; sourceTree = ""; }; - E18D04AB28E8A737008EF5EC /* TagChartsViewModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewModuleInput.swift; sourceTree = ""; }; - E18D04AE28E8A747008EF5EC /* TagChartsViewModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewModuleOutput.swift; sourceTree = ""; }; - E18D04B928E8B34F008EF5EC /* TagChartsViewInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewInteractor.swift; sourceTree = ""; }; - E18D04BC28E8B397008EF5EC /* TagChartsViewInteractorInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewInteractorInput.swift; sourceTree = ""; }; - E18D04BF28E8B3B0008EF5EC /* TagChartsViewInteractorOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewInteractorOutput.swift; sourceTree = ""; }; - E18D04C328E9DF77008EF5EC /* TagChartsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsView.swift; sourceTree = ""; }; - E18D04D028F1D027008EF5EC /* TagChartsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewInput.swift; sourceTree = ""; }; - E18D04D328F1D52A008EF5EC /* TagChartsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewOutput.swift; sourceTree = ""; }; - E18FD50928DF7B7900289359 /* TagChartsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewController.swift; sourceTree = ""; }; - E18FD50C28DF7E7100289359 /* UIView+Layout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Layout.swift"; sourceTree = ""; }; - E191F1E82968B6B100F1FEA6 /* TagSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsViewController.swift; sourceTree = ""; }; - E191F1EB2968BCF300F1FEA6 /* TagSettingsBasicCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsBasicCell.swift; sourceTree = ""; }; - E191F1F12968C2C900F1FEA6 /* TagSettingsAlertConfigCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsAlertConfigCell.swift; sourceTree = ""; }; - E191F1F42968D32000F1FEA6 /* TagSettingsExpandableSectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsExpandableSectionHeader.swift; sourceTree = ""; }; - E191F1F72968D33800F1FEA6 /* TagSettingsSimpleSectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsSimpleSectionHeader.swift; sourceTree = ""; }; - E191F1FA2969CD0100F1FEA6 /* TagSettingsBackgroundSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsBackgroundSelectionView.swift; sourceTree = ""; }; - E191F1FD2969D6C900F1FEA6 /* TagSettingsPlainCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsPlainCell.swift; sourceTree = ""; }; - E191F2082969E11F00F1FEA6 /* TagSettingsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsRouterInput.swift; sourceTree = ""; }; - E191F20B2969E14600F1FEA6 /* TagSettingsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsRouter.swift; sourceTree = ""; }; - E191F20E2969E1C300F1FEA6 /* TagSettingsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsPresenter.swift; sourceTree = ""; }; - E191F21A2969EF7B00F1FEA6 /* TagSettingsModuleFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsModuleFactory.swift; sourceTree = ""; }; - E191F21D2969FF6900F1FEA6 /* TagSettingsSwitchCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsSwitchCell.swift; sourceTree = ""; }; - E191F220296A00CE00F1FEA6 /* TagSettingsFooterCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsFooterCell.swift; sourceTree = ""; }; - E196914F2A06DCA400DC360E /* NotificationsSettingsModuleFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationsSettingsModuleFactory.swift; sourceTree = ""; }; - E19691522A06DCBB00DC360E /* NotificationsSettingsRouterInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationsSettingsRouterInput.swift; sourceTree = ""; }; - E19691532A06DCBB00DC360E /* NotificationsSettingsRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationsSettingsRouter.swift; sourceTree = ""; }; - E19691582A06DCD400DC360E /* NotificationsSettingsTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationsSettingsTableViewController.swift; sourceTree = ""; }; - E19691592A06DCD500DC360E /* NotificationsSettingsTextCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationsSettingsTextCell.swift; sourceTree = ""; }; - E196915A2A06DCD500DC360E /* NotificationsSettingsSwitchCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationsSettingsSwitchCell.swift; sourceTree = ""; }; - E19691612A06DCE500DC360E /* NotificationsSettingsViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationsSettingsViewInput.swift; sourceTree = ""; }; - E19691622A06DCE500DC360E /* NotificationsSettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationsSettingsViewModel.swift; sourceTree = ""; }; - E19691632A06DCE500DC360E /* NotificationsSettingsViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationsSettingsViewOutput.swift; sourceTree = ""; }; - E196916A2A06DCEF00DC360E /* NotificationsSettingsPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationsSettingsPresenter.swift; sourceTree = ""; }; - E196916B2A06DCEF00DC360E /* NotificationsSettingsModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationsSettingsModuleInput.swift; sourceTree = ""; }; - E19691722A06E03300DC360E /* PushAlertSoundSelectionModuleFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushAlertSoundSelectionModuleFactory.swift; sourceTree = ""; }; - E19691742A06E03300DC360E /* PushAlertSoundSelectionPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushAlertSoundSelectionPresenter.swift; sourceTree = ""; }; - E19691752A06E03300DC360E /* PushAlertSoundSelectionModuleInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushAlertSoundSelectionModuleInput.swift; sourceTree = ""; }; - E19691782A06E03300DC360E /* PushAlertSoundSelectionTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushAlertSoundSelectionTableViewController.swift; sourceTree = ""; }; - E19691792A06E03300DC360E /* PushAlertSoundSelectionTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushAlertSoundSelectionTableViewCell.swift; sourceTree = ""; }; - E196917A2A06E03300DC360E /* PushAlertSoundSelectionViewInput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushAlertSoundSelectionViewInput.swift; sourceTree = ""; }; - E196917B2A06E03300DC360E /* PushAlertSoundSelectionViewOutput.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushAlertSoundSelectionViewOutput.swift; sourceTree = ""; }; - E196918A2A06E15F00DC360E /* PushAlertSoundSelectionViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushAlertSoundSelectionViewModel.swift; sourceTree = ""; }; - E196918D2A06E2E100DC360E /* RuuviAlertSound+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RuuviAlertSound+Extension.swift"; sourceTree = ""; }; - E1972BE029587615000E2AEC /* CardsLargeImageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsLargeImageCell.swift; sourceTree = ""; }; - E19EAF502996BAAF005827E4 /* pnservice.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = pnservice.entitlements; sourceTree = ""; }; - E19EAF512996C828005827E4 /* Montserrat-ExtraBold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Montserrat-ExtraBold.ttf"; sourceTree = ""; }; - E19EAF5A2996CF38005827E4 /* Muli-SemiBoldItalic.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Muli-SemiBoldItalic.ttf"; sourceTree = ""; }; - E19EAF6529983650005827E4 /* AppUtility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppUtility.swift; sourceTree = ""; }; - E19EAF6829997711005827E4 /* SignInViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInViewController.swift; sourceTree = ""; }; - E19EAF6C299ACD95005827E4 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/RuuviWidgetsConfiguration.strings; sourceTree = ""; }; - E19EAF6E299ACD96005827E4 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/RuuviWidgetsConfiguration.strings; sourceTree = ""; }; - E19EAF70299ACD98005827E4 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/RuuviWidgetsConfiguration.strings; sourceTree = ""; }; - E19EAF71299ADB2F005827E4 /* UIButton+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIButton+Extension.swift"; sourceTree = ""; }; - E19EAF74299AE3B0005827E4 /* SignInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInView.swift; sourceTree = ""; }; - E19EAF77299AE5EA005827E4 /* SignInVerifyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInVerifyView.swift; sourceTree = ""; }; - E19EAF7A299BF94C005827E4 /* SignInBenefitsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInBenefitsViewController.swift; sourceTree = ""; }; - E19EAF82299C1383005827E4 /* SignInModuleFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInModuleFactory.swift; sourceTree = ""; }; - E19EAF93299E6038005827E4 /* SignInBenefitsModuleFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInBenefitsModuleFactory.swift; sourceTree = ""; }; - E19EAF96299E6083005827E4 /* SignInBenefitsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInBenefitsRouterInput.swift; sourceTree = ""; }; - E19EAF99299E608E005827E4 /* SignInBenefitsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInBenefitsRouter.swift; sourceTree = ""; }; - E19EAF9D299E610A005827E4 /* SignInBenefitsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInBenefitsPresenter.swift; sourceTree = ""; }; - E19EAFA0299E61C5005827E4 /* SignInBenefitsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInBenefitsModuleInput.swift; sourceTree = ""; }; - E19EAFA3299E6211005827E4 /* SignInBenefitsModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInBenefitsModuleOutput.swift; sourceTree = ""; }; - E19EAFA6299E62A7005827E4 /* SignInBenefitsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInBenefitsViewInput.swift; sourceTree = ""; }; - E19EAFA9299E62C0005827E4 /* SignInBenefitsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInBenefitsViewOutput.swift; sourceTree = ""; }; - E19EAFAC299E82D1005827E4 /* SignInPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInPresenter.swift; sourceTree = ""; }; - E19EAFAF299EB46D005827E4 /* NoSensorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoSensorView.swift; sourceTree = ""; }; - E1AB90542A0BFECE00543F61 /* RuuviLinkTextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviLinkTextView.swift; sourceTree = ""; }; - E1AB905D2A0EB0D000543F61 /* SensorForceClaimModuleFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorForceClaimModuleFactory.swift; sourceTree = ""; }; - E1AB90602A0EB11800543F61 /* SensorForceClaimPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorForceClaimPresenter.swift; sourceTree = ""; }; - E1AB90632A0EB13400543F61 /* SensorForceClaimModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorForceClaimModuleInput.swift; sourceTree = ""; }; - E1AB90662A0EB1AD00543F61 /* SensorForceClaimRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorForceClaimRouter.swift; sourceTree = ""; }; - E1AB90692A0EB1BC00543F61 /* SensorForceClaimRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorForceClaimRouterInput.swift; sourceTree = ""; }; - E1AB90722A0EB24600543F61 /* SensorForceClaimViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorForceClaimViewController.swift; sourceTree = ""; }; - E1AB907A2A0ECB6D00543F61 /* SensorForceClaimViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorForceClaimViewOutput.swift; sourceTree = ""; }; - E1AB907D2A0ECB7600543F61 /* SensorForceClaimViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorForceClaimViewInput.swift; sourceTree = ""; }; - E1B20C862926CDE10023D739 /* UITextField+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextField+Extension.swift"; sourceTree = ""; }; - E1B20C892926D2FC0023D739 /* Double+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+Extension.swift"; sourceTree = ""; }; - E1B57FEA29859CB800B441FB /* DevicesModuleFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevicesModuleFactory.swift; sourceTree = ""; }; - E1B57FED29859CC900B441FB /* DevicesModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevicesModuleInput.swift; sourceTree = ""; }; - E1B57FF029859CD400B441FB /* DevicesPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevicesPresenter.swift; sourceTree = ""; }; - E1B57FF329859CE200B441FB /* DevicesTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevicesTableViewController.swift; sourceTree = ""; }; - E1B57FF629859CEC00B441FB /* DevicesTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevicesTableViewCell.swift; sourceTree = ""; }; - E1B57FFA29859D0700B441FB /* DevicesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevicesViewModel.swift; sourceTree = ""; }; - E1B57FFD29859D1800B441FB /* DevicesViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevicesViewInput.swift; sourceTree = ""; }; - E1B5800029859D2300B441FB /* DevicesViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevicesViewOutput.swift; sourceTree = ""; }; - E1B5800429859E8900B441FB /* DevicesInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevicesInteractor.swift; sourceTree = ""; }; - E1B5800729859EDE00B441FB /* DevicesInteractorInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevicesInteractorInput.swift; sourceTree = ""; }; - E1B5800A29859EEB00B441FB /* DevicesInteractorOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevicesInteractorOutput.swift; sourceTree = ""; }; - E1B5800D2986AE0800B441FB /* RuuviContextMenuButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviContextMenuButton.swift; sourceTree = ""; }; - E1B7B5232AE989ED009D747E /* SensorRemovalModuleFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorRemovalModuleFactory.swift; sourceTree = ""; }; - E1B7B5272AE98A37009D747E /* SensorRemovalViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorRemovalViewController.swift; sourceTree = ""; }; - E1B7B52A2AE98A9F009D747E /* SensorRemovalViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorRemovalViewOutput.swift; sourceTree = ""; }; - E1B7B52D2AE98AC4009D747E /* SensorRemovalViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorRemovalViewInput.swift; sourceTree = ""; }; - E1B7B5302AE98B00009D747E /* SensorRemovalRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorRemovalRouter.swift; sourceTree = ""; }; - E1B7B5332AE98B16009D747E /* SensorRemovalRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorRemovalRouterInput.swift; sourceTree = ""; }; - E1B7B5362AE98B72009D747E /* SensorRemovalModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorRemovalModuleInput.swift; sourceTree = ""; }; - E1B7B5392AE98B86009D747E /* SensorRemovalPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorRemovalPresenter.swift; sourceTree = ""; }; - E1B7B53E2AEAD61A009D747E /* SensorRemovalModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorRemovalModuleOutput.swift; sourceTree = ""; }; - E1BAC1392A7598F000EA820E /* Muli-ExtraBold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Muli-ExtraBold.ttf"; sourceTree = ""; }; - E1C395D229B26044009301D3 /* UICollectionView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionView+Extension.swift"; sourceTree = ""; }; - E1CA28AD29201F34009E4423 /* RUAlertExpandButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUAlertExpandButton.swift; sourceTree = ""; }; - E1CA28B7292037E4009E4423 /* RUAlertDetailsCellChildView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RUAlertDetailsCellChildView.swift; sourceTree = ""; }; - E1CD77E628781A0E00F1F0EB /* UnitSettings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = UnitSettings.storyboard; sourceTree = ""; }; - E1CD77EB2878273500F1F0EB /* UnitSettingsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitSettingsTableViewController.swift; sourceTree = ""; }; - E1CD77F028782E8000F1F0EB /* UnitSettingsTableConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitSettingsTableConfigurator.swift; sourceTree = ""; }; - E1CD77F328782EA500F1F0EB /* UnitSettingsTableInitializer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitSettingsTableInitializer.swift; sourceTree = ""; }; - E1CD77F728782F2200F1F0EB /* UnitSettingsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitSettingsPresenter.swift; sourceTree = ""; }; - E1CD77FA28782F7100F1F0EB /* UnitSettingsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitSettingsModuleInput.swift; sourceTree = ""; }; - E1CD77FD28782F9900F1F0EB /* UnitSettingsModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitSettingsModuleOutput.swift; sourceTree = ""; }; - E1CD78002878302100F1F0EB /* UnitSettingsViewInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitSettingsViewInput.swift; sourceTree = ""; }; - E1CD78032878302C00F1F0EB /* UnitSettingsViewOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitSettingsViewOutput.swift; sourceTree = ""; }; - E1CD78072878308E00F1F0EB /* UnitSettingsItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitSettingsItem.swift; sourceTree = ""; }; - E1CD780B287830B100F1F0EB /* UnitSettingsRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitSettingsRouter.swift; sourceTree = ""; }; - E1CD780E287830BF00F1F0EB /* UnitSettingsRouterInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitSettingsRouterInput.swift; sourceTree = ""; }; - E1CD78112878379C00F1F0EB /* UnitSettingsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitSettingsTableViewCell.swift; sourceTree = ""; }; - E1CE4C702959CE61005C023F /* DashboardViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardViewController.swift; sourceTree = ""; }; - E1CE4C732959D08D005C023F /* DashboardImageCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardImageCell.swift; sourceTree = ""; }; - E1CE4C762959DF01005C023F /* DashboardIndicatorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardIndicatorView.swift; sourceTree = ""; }; - E1CE5E3E29F994DE00391109 /* AppGroupConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppGroupConstants.swift; sourceTree = ""; }; - E1CE5E4129FC39D000391109 /* DefaultsModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsModuleOutput.swift; sourceTree = ""; }; - E1CE5E462A016D4000391109 /* RuuviCustomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviCustomButton.swift; sourceTree = ""; }; - E1D0238A29EB02C600EC0FFD /* RuuviUISwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuuviUISwitch.swift; sourceTree = ""; }; - E1D0238D29EB3F7D00EC0FFD /* YAxisValueFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YAxisValueFormatter.swift; sourceTree = ""; }; - E1E102ED28F348B700815508 /* TagChartsHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsHelper.swift; sourceTree = ""; }; - E1E1475B28E85EE700832B8C /* UIImageView+Init.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImageView+Init.swift"; sourceTree = ""; }; - E1E3C32F298C601200A59CB8 /* CardsViewModuleFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsViewModuleFactory.swift; sourceTree = ""; }; - E1E3C332298D7FA500A59CB8 /* UIImage+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Extension.swift"; sourceTree = ""; }; - E1E3C335298D858D00A59CB8 /* TagChartsModuleFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsModuleFactory.swift; sourceTree = ""; }; - E1E3C338298EC9DC00A59CB8 /* DashboardModuleFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardModuleFactory.swift; sourceTree = ""; }; - E1E3C33B298ED3E300A59CB8 /* CardsPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsPresenter.swift; sourceTree = ""; }; - E1E3C33E298FDCCC00A59CB8 /* CardsModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardsModuleOutput.swift; sourceTree = ""; }; - E1E3C341299007B700A59CB8 /* TagSettingsModuleInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsModuleInput.swift; sourceTree = ""; }; - E1E3C344299007DE00A59CB8 /* TagSettingsModuleOutput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagSettingsModuleOutput.swift; sourceTree = ""; }; - E1E6C214296C9CB100B3D037 /* Int+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Int+Extension.swift"; sourceTree = ""; }; - E1ED426828FF253B00302179 /* TagChartsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagChartsViewModel.swift; sourceTree = ""; }; - E1ED426B28FF261D00302179 /* CustomYAxisRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomYAxisRenderer.swift; sourceTree = ""; }; - E1ED426C28FF261D00302179 /* XAxisValueFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XAxisValueFormatter.swift; sourceTree = ""; }; - E1ED426D28FF261D00302179 /* CustomXAxisRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomXAxisRenderer.swift; sourceTree = ""; }; - FC417B8977A47FFAE71585F0 /* ShareViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; }; - FC59D3B5AD8926DBDD79AA1C /* SignInViewModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SignInViewModel.swift; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 0E8BD3DC238566AB008B31EF /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 0EE36EB1269DC71B0021B746 /* Algorithms in Frameworks */, - 0EE36EB6269DC7E40021B746 /* Charts in Frameworks */, - 73949279A33A1BF08159FE0E /* Pods_station_dev.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 34A8D486281EBFD9008A8698 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 34A8D48D281EBFD9008A8698 /* SwiftUI.framework in Frameworks */, - 34A8D48B281EBFD9008A8698 /* WidgetKit.framework in Frameworks */, - D54F2103EF7E3360E7D09BC4 /* Pods_station_widgets.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 34A8D4B2281EE5AE008A8698 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 34A8D4B7281EE5AE008A8698 /* Intents.framework in Frameworks */, - 61E02A45E5B5666DBF1972A6 /* Pods_station_intents.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D2220B0C45900CDF4B6 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 0EE36EAF269DC70E0021B746 /* Algorithms in Frameworks */, - 0EE36EB4269DC7D90021B746 /* Charts in Frameworks */, - A98CCBB3BAF61A33CE4A2D1B /* Pods_station.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D3620B0C45A00CDF4B6 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 706E22795B6DE254AF39BB12 /* Pods_stationTests.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D4120B0C45B00CDF4B6 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E17C469629956732008CFDD7 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 0E02ABB8237598B200ED4629 /* RangeSeekSlider */ = { - isa = PBXGroup; - children = ( - 0E02ABB9237598C600ED4629 /* RURangeSeekSlider.swift */, - ); - path = RangeSeekSlider; - sourceTree = ""; - }; - 0E046F3722F0585E00BD4E9C /* Transitions */ = { - isa = PBXGroup; - children = ( - 0E046F3822F0589000BD4E9C /* SwipeDownToDismiss */, - ); - path = Transitions; - sourceTree = ""; - }; - 0E046F3822F0589000BD4E9C /* SwipeDownToDismiss */ = { - isa = PBXGroup; - children = ( - 0E53DA6622CC964200BC6D64 /* SwipeDownToDismissNavigationController.swift */, - 0E53DA5F22CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift */, - 0E53DA6122CC93EB00BC6D64 /* SwipeDownToDismissTransitionAnimation.swift */, - 0E53DA6322CC943900BC6D64 /* SwipeDownToDismissInteractiveTransition.swift */, - ); - path = SwipeDownToDismiss; - sourceTree = ""; - }; - 0E09671522AE74CB00E85F48 /* Application */ = { - isa = PBXGroup; - children = ( - 340BE37427B54EE2006D6C34 /* AppAssemblyConstants.swift */, - E1CE5E3E29F994DE00391109 /* AppGroupConstants.swift */, - 0E5C302322D0B16300B52E39 /* AppState */, - 0EB48D6D2619D4D4008E0D2D /* Features */, - 0E197C7223C5C7770074015B /* Info */, - A9FC78E7257966EF00F94604 /* UniversalLinks */, - 0E1C1DA722B387A00032F6CA /* AppAssembly.swift */, - 64333D2820B0C45900CDF4B6 /* AppDelegate.swift */, - ); - path = Application; - sourceTree = ""; - }; - 0E09671622AE74D600E85F48 /* Classes */ = { - isa = PBXGroup; - children = ( - 0E09671522AE74CB00E85F48 /* Application */, - 0E09671922AE764200E85F48 /* Presentation */, - 0E2B339926A2BC2500366B01 /* Routers */, - ); - path = Classes; - sourceTree = ""; - }; - 0E09671722AE762900E85F48 /* Resources */ = { - isa = PBXGroup; - children = ( - E116AED02A05955B003EF65A /* Sounds */, - E1597A5A295E24BB00DFB70B /* Assets */, - 0EB8ED412692004300C6B0FA /* Colors */, - 0EB48DE4261A17F4008E0D2D /* JSONs */, - 0E1C1DC722B396180032F6CA /* Strings */, - 0E09671A22AE769F00E85F48 /* Plists */, - 0E09671822AE763500E85F48 /* Images */, - 6486970E20E042BC00CCD7C1 /* Fonts */, - ); - path = Resources; - sourceTree = ""; - }; - 0E09671822AE763500E85F48 /* Images */ = { - isa = PBXGroup; - children = ( - E11FDA6929A1757C003ADA7B /* splash_bg_layer_dark.jpg */, - 340BE39D27B56128006D6C34 /* ruuvi_logo_splash.png */, - 64333D2F20B0C45A00CDF4B6 /* Assets.xcassets */, - ); - path = Images; - sourceTree = ""; - }; - 0E09671922AE764200E85F48 /* Presentation */ = { - isa = PBXGroup; - children = ( - 0E1C1DBC22B3920C0032F6CA /* Assembly */, - 0EC50F4E22CCB91000172EEB /* Binding */, - 0EB8ED452692017100C6B0FA /* Colors */, - 0E70A45E22AF9558006CB87C /* Contract */, - 0EE98A772649386000AAB3ED /* FLEX */, - 0E09671B22AE76B700E85F48 /* Launch */, - 0E70A46122AF958E006CB87C /* Localization */, - 0E09671C22AE76CC00E85F48 /* Modules */, - 0E1C1DAC22B38F220032F6CA /* Presenters */, - 0E046F3722F0585E00BD4E9C /* Transitions */, - ); - path = Presentation; - sourceTree = ""; - }; - 0E09671A22AE769F00E85F48 /* Plists */ = { - isa = PBXGroup; - children = ( - 0E9F97B422EC44930015ADE2 /* Networking.plist */, - 0E197C8023C5CDBE0074015B /* iOSDeviceModelMapping.plist */, - 0ECDF1B42313D65500A09ACA /* GoogleService-Info.plist */, - 64333D3420B0C45A00CDF4B6 /* Info.plist */, - 0EE49BB223B8C40D003012C2 /* DevInfo.plist */, - 0EE49BB123B8C40D003012C2 /* MacInfo.plist */, - ); - path = Plists; - sourceTree = ""; - }; - 0E09671B22AE76B700E85F48 /* Launch */ = { - isa = PBXGroup; - children = ( - 64333D3120B0C45A00CDF4B6 /* LaunchScreen.storyboard */, - ); - path = Launch; - sourceTree = ""; - }; - 0E09671C22AE76CC00E85F48 /* Modules */ = { - isa = PBXGroup; - children = ( - E16B8F3A28D108970025B92D /* My Ruuvi */, - 0EEB20E922B7D1350015F9E0 /* About */, - 0E1C1DCE22B3BDAE0032F6CA /* Dashboard */, - 0E1C1DEB22B3FDB40032F6CA /* Menu */, - 0EEB20CE22B7C6DA0015F9E0 /* Settings */, - 0EF2862522CBAF280026C7A5 /* TagSettings */, - 71A3760FF84549A5FB45C805 /* SignIn */, - DB47D7C8D6149FEA8DD05FDC /* Share */, - ); - path = Modules; - sourceTree = ""; - }; - 0E09672322AE895600E85F48 /* Extensions */ = { - isa = PBXGroup; - children = ( - E1395BEF294F791C00C403C6 /* Classess */, - 0EA7966F2664A7B3002BA25D /* Errors */, - 0E92A94B2686339300187E4F /* Structs */, - 0E290A842660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift */, - E1597A2C295B6E6B00DFB70B /* UIFont+Extension.swift */, - E1E6C214296C9CB100B3D037 /* Int+Extension.swift */, - E18FD50C28DF7E7100289359 /* UIView+Layout.swift */, - E18D04A028E879EE008EF5EC /* UIView+Init.swift */, - E11989F429B7A46E002245CF /* UIView+Extension.swift */, - E1597A5E295F803400DFB70B /* UIColor+Extension.swift */, - E1E1475B28E85EE700832B8C /* UIImageView+Init.swift */, - E1E3C332298D7FA500A59CB8 /* UIImage+Extension.swift */, - 0E09672422AE897000E85F48 /* CALayer+IB.swift */, - E16051EB285CBA57003FCA70 /* FileManager+Date.swift */, - 66718A6B266BD0E800A380F8 /* Color+Ruuvi.swift */, - 0EF5B72A22D62CD900D9D14A /* Date+Ruuvi.swift */, - 0EF4E33F26824EF500D83CC7 /* DfuFirmware+Log.swift */, - 0E02ABCA2379483A00ED4629 /* Double+Temperature.swift */, - 0EF5B75322DE153A00D9D14A /* HumidityUnit+Localization.swift */, - 0EBAF064232002A00025A191 /* Language+Localization.swift */, - 340BE39A27B54FEB006D6C34 /* String+Email.swift */, - E1395BE9294F6C2A00C403C6 /* String+Localization.swift */, - 0E502FB922B27D4800E8A6CC /* TemperatureUnit+Localization.swift */, - A92E3C4B24261CF900D981D5 /* MeasurementType.swift */, - E1B20C862926CDE10023D739 /* UITextField+Extension.swift */, - E19EAF71299ADB2F005827E4 /* UIButton+Extension.swift */, - E168B4AD2886AE4E00D6B5C6 /* MeasurementAccuracyType+Extension.swift */, - E168B4B52886AF1200D6B5C6 /* UnitSettingsType.swift */, - A9BD38B924F6108300904BBE /* Humidity+Offset.swift */, - A9A67BF924C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift */, - A9E6774725A33081000B75A3 /* String+Characters.swift */, - 0E9E7759238CCE5F006D7013 /* String+Replace.swift */, - E1B20C892926D2FC0023D739 /* Double+Extension.swift */, - 0E1C1DBA22B3919F0032F6CA /* UIApplication+ViewController.swift */, - 0E197C7C23C5CD7C0074015B /* UIDevice+ReadableModel.swift */, - A92A66BC2450C640002918E7 /* UITableViewCell+ReusableView.swift */, - E1C395D229B26044009301D3 /* UICollectionView+Extension.swift */, - 660EB29B266928E6000FD22B /* UIViewController+Alert.swift */, - A907BB1024AE620A009DA3DB /* UIWindow+Orientation.swift */, - A9A48A5B244CD9E70004FD50 /* UIWindow+Shake.swift */, - A91D031925113EAA00694733 /* UnitPressure+Extension.swift */, - E1198A2029BA6EC6002245CF /* RuuviTheme+Extension.swift */, - E196918D2A06E2E100DC360E /* RuuviAlertSound+Extension.swift */, - 0E0A381823616AC3003A0364 /* UserDefaults+Optional.swift */, - 3490A4C227D9F2C70032BBAB /* UINavigationController.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 0E197C6423C4A44C0074015B /* MailComposer */ = { - isa = PBXGroup; - children = ( - 0E197C6923C4A4960074015B /* MessageUI */, - 0E197C6523C4A47A0074015B /* MailComposerPresenter.swift */, - ); - path = MailComposer; - sourceTree = ""; - }; - 0E197C6923C4A4960074015B /* MessageUI */ = { - isa = PBXGroup; - children = ( - 0E197C6A23C4A52A0074015B /* MailComposerPresenterMessageUI.swift */, - ); - path = MessageUI; - sourceTree = ""; - }; - 0E197C7223C5C7770074015B /* Info */ = { - isa = PBXGroup; - children = ( - 0E197C7723C5CCA60074015B /* Impl */, - 0E197C7323C5C7A20074015B /* InfoProvider.swift */, - ); - path = Info; - sourceTree = ""; - }; - 0E197C7723C5CCA60074015B /* Impl */ = { - isa = PBXGroup; - children = ( - 0E197C7823C5CCBB0074015B /* InfoProviderImpl.swift */, - ); - path = Impl; - sourceTree = ""; - }; - 0E1C1DAC22B38F220032F6CA /* Presenters */ = { - isa = PBXGroup; - children = ( - A93CDCCC25659B8600018C6C /* Alert */, - 0E197C6423C4A44C0074015B /* MailComposer */, - 0EC50F5722CF61F700172EEB /* PhotoPicker */, - ); - path = Presenters; - sourceTree = ""; - }; - 0E1C1DBC22B3920C0032F6CA /* Assembly */ = { - isa = PBXGroup; - children = ( - 340BE37127B54E25006D6C34 /* PresentationConstants.swift */, - 0E1C1DBD22B3921E0032F6CA /* PresentationAssembly.swift */, - 0E197C6E23C4A7D00074015B /* Presentation.plist */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E1C1DC722B396180032F6CA /* Strings */ = { - isa = PBXGroup; - children = ( - A96B1F2225A7943E00D3ED9C /* station.localization.json */, - 0EEB20C922B7A7200015F9E0 /* Localizable.strings */, - 0E53A3F3232DFC6200ACED49 /* InfoPlist.strings */, - ); - path = Strings; - sourceTree = ""; - }; - 0E1C1DCE22B3BDAE0032F6CA /* Dashboard */ = { - isa = PBXGroup; - children = ( - E1CE4C6E2959CC2B005C023F /* Home */, - 0E8FD0D823336E8E00FFA577 /* Cards */, - 0E8FD0D923336EB200FFA577 /* Charts */, - E1597A6D2961FE9E00DFB70B /* Background */, - ); - path = Dashboard; - sourceTree = ""; - }; - 0E1C1DCF22B3BDBB0032F6CA /* View */ = { - isa = PBXGroup; - children = ( - E1395BFE2957943600C403C6 /* UI */, - 0E1C1DD222B3BF180032F6CA /* CardsViewInput.swift */, - 0E1C1DD422B3BF3A0032F6CA /* CardsViewOutput.swift */, - 0EEB20C522B7915C0015F9E0 /* CardsViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E1C1DDB22B3C1F30032F6CA /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E1C1DDC22B3C2160032F6CA /* CardsModuleInput.swift */, - E1E3C33E298FDCCC00A59CB8 /* CardsModuleOutput.swift */, - E1E3C33B298ED3E300A59CB8 /* CardsPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E1C1DE022B3C24F0032F6CA /* Router */ = { - isa = PBXGroup; - children = ( - 0E1C1DE122B3C25F0032F6CA /* CardsRouterInput.swift */, - 0E211C29234C5FE900FC37B0 /* CardsRouterDelegate.swift */, - 0E1C1DE322B3C2710032F6CA /* CardsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E1C1DE522B3C2900032F6CA /* Assembly */ = { - isa = PBXGroup; - children = ( - E1E3C32F298C601200A59CB8 /* CardsViewModuleFactory.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E1C1DEB22B3FDB40032F6CA /* Menu */ = { - isa = PBXGroup; - children = ( - 0E1C1DF022B3FDE30032F6CA /* Menu.storyboard */, - 0E1C1DEF22B3FDD60032F6CA /* Assembly */, - 0E1C1E0622B401A80032F6CA /* Transition */, - 0E1C1DEE22B3FDCC0032F6CA /* Presenter */, - 0E1C1DED22B3FDC70032F6CA /* Router */, - 0E1C1DEC22B3FDBB0032F6CA /* View */, - ); - path = Menu; - sourceTree = ""; - }; - 0E1C1DEC22B3FDBB0032F6CA /* View */ = { - isa = PBXGroup; - children = ( - 0E1C1DF622B3FF2F0032F6CA /* Table */, - 0E1C1DF222B3FEFF0032F6CA /* MenuViewInput.swift */, - 0E1C1DF422B3FF1D0032F6CA /* MenuViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E1C1DED22B3FDC70032F6CA /* Router */ = { - isa = PBXGroup; - children = ( - 0E1C1DF922B3FFBF0032F6CA /* MenuRouterInput.swift */, - 0E1C1DFB22B3FFD90032F6CA /* MenuRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E1C1DEE22B3FDCC0032F6CA /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E1C1DFD22B3FFFC0032F6CA /* MenuModuleInput.swift */, - 0EEB20CC22B7BD6C0015F9E0 /* MenuModuleOutput.swift */, - 0E1C1DFF22B400130032F6CA /* MenuPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E1C1DEF22B3FDD60032F6CA /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E1C1E0122B400470032F6CA /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E1C1DF622B3FF2F0032F6CA /* Table */ = { - isa = PBXGroup; - children = ( - 0EEB20CA22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift */, - 0E1C1DF722B3FF480032F6CA /* MenuTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E1C1E0122B400470032F6CA /* Table */ = { - isa = PBXGroup; - children = ( - 0E1C1E0222B400590032F6CA /* MenuTableInitializer.swift */, - 0E1C1E0422B400890032F6CA /* MenuTableConfigurator.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E1C1E0622B401A80032F6CA /* Transition */ = { - isa = PBXGroup; - children = ( - 0E1C1E0722B4022F0032F6CA /* Table */, - ); - path = Transition; - sourceTree = ""; - }; - 0E1C1E0722B4022F0032F6CA /* Table */ = { - isa = PBXGroup; - children = ( - 0EEB215922BA28860015F9E0 /* MenuTableTransitionManager.swift */, - 0E1C1E0822B4024E0032F6CA /* MenuTableTransitioningDelegate.swift */, - 0E1C1E0A22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift */, - 0E1C1E0C22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift */, - 0E1C1E0E22B4049E0032F6CA /* MenuTablePresentationController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E2B339926A2BC2500366B01 /* Routers */ = { - isa = PBXGroup; - children = ( - 0E2B339A26A2BC3F00366B01 /* AppRouter.swift */, - 0E2B339D26A2BCBE00366B01 /* OnboardRouter.swift */, - 0E62299426AAA0570041DCDD /* DiscoverRouter.swift */, - ); - path = Routers; - sourceTree = ""; - }; - 0E5C302322D0B16300B52E39 /* AppState */ = { - isa = PBXGroup; - children = ( - 0E5C302622D0B1A200B52E39 /* Impl */, - 0E5C302422D0B19600B52E39 /* AppStateService.swift */, - ); - path = AppState; - sourceTree = ""; - }; - 0E5C302622D0B1A200B52E39 /* Impl */ = { - isa = PBXGroup; - children = ( - 0E5C302722D0B1C600B52E39 /* AppStateServiceImpl.swift */, - ); - path = Impl; - sourceTree = ""; - }; - 0E70A45E22AF9558006CB87C /* Contract */ = { - isa = PBXGroup; - children = ( - 0E70A45F22AF9567006CB87C /* ViewInput.swift */, - ); - path = Contract; - sourceTree = ""; - }; - 0E70A46122AF958E006CB87C /* Localization */ = { - isa = PBXGroup; - children = ( - 0E70A46222AF959E006CB87C /* Localizable.swift */, - A949A83A24707FD0006B7F4F /* LocalizedCache.swift */, - 0E9D0AB0231EBEFD00C6BDA7 /* LocalizationService.swift */, - ); - path = Localization; - sourceTree = ""; - }; - 0E84BF4F2397F24D00A37E1A /* Heartbeat */ = { - isa = PBXGroup; - children = ( - 0E84BF542397F29800A37E1A /* Heartbeat.storyboard */, - 0E84BF532397F28800A37E1A /* Assembly */, - 0E84BF522397F28200A37E1A /* Presenter */, - 0E84BF512397F27E00A37E1A /* Router */, - 0E84BF502397F27900A37E1A /* View */, - ); - path = Heartbeat; - sourceTree = ""; - }; - 0E84BF502397F27900A37E1A /* View */ = { - isa = PBXGroup; - children = ( - 0E84BF5C2397F3E600A37E1A /* SwiftUI */, - 0E84BF5D2397F3F000A37E1A /* Table */, - 0E84BF562397F33E00A37E1A /* HeartbeatViewInput.swift */, - 0E84BF582397F3C600A37E1A /* HeartbeatViewModel.swift */, - 0E84BF5A2397F3DF00A37E1A /* HeartbeatViewOutput.swift */, - 0E84BF5E2397F6BE00A37E1A /* HeartbeatViewController.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E84BF512397F27E00A37E1A /* Router */ = { - isa = PBXGroup; - children = ( - 0E84BF66239801AF00A37E1A /* HeartbeatRouterInput.swift */, - 0E84BF68239801C100A37E1A /* HeartbeatRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E84BF522397F28200A37E1A /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E84BF6A239802A400A37E1A /* HeartbeatModuleInput.swift */, - 0E84BF6C239802CA00A37E1A /* HeartbeatPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E84BF532397F28800A37E1A /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E84BF6E2398031B00A37E1A /* HeartbeatInitializer.swift */, - 0E84BF702398035C00A37E1A /* HeartbeatConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E84BF5C2397F3E600A37E1A /* SwiftUI */ = { - isa = PBXGroup; - children = ( - 0E84BF622397F76A00A37E1A /* HeartbeatList.swift */, - 0E84BF602397F73100A37E1A /* HeartbeatEnvironmentObject.swift */, - ); - path = SwiftUI; - sourceTree = ""; - }; - 0E84BF5D2397F3F000A37E1A /* Table */ = { - isa = PBXGroup; - children = ( - 0E84BF642397F9DC00A37E1A /* HeartbeatTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E8A100023845E1200A9CBA6 /* Defaults */ = { - isa = PBXGroup; - children = ( - 0E8A100123845E5100A9CBA6 /* Defaults.storyboard */, - 0E8A100623845E9400A9CBA6 /* Assembly */, - 0E8A100523845E8A00A9CBA6 /* Presenter */, - 0E8A100423845E8200A9CBA6 /* Router */, - 0E8A100323845E7D00A9CBA6 /* View */, - ); - path = Defaults; - sourceTree = ""; - }; - 0E8A100323845E7D00A9CBA6 /* View */ = { - isa = PBXGroup; - children = ( - 0E8A100723845F1B00A9CBA6 /* SwiftUI */, - 0E8A100823845F2300A9CBA6 /* Table */, - 0E8A100923845F3900A9CBA6 /* DefaultsViewController.swift */, - 0E8A100B23845F7100A9CBA6 /* DefaultsViewInput.swift */, - 0E8A100D23845F8C00A9CBA6 /* DefaultsViewOutput.swift */, - 0E8A100F23845FAE00A9CBA6 /* DefaultsViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E8A100423845E8200A9CBA6 /* Router */ = { - isa = PBXGroup; - children = ( - 0E8A10152384612300A9CBA6 /* DefaultsRouterInput.swift */, - 0E8A10132384610400A9CBA6 /* DefaultsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0E8A100523845E8A00A9CBA6 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E8A10172384613E00A9CBA6 /* DefaultsModuleInput.swift */, - E1CE5E4129FC39D000391109 /* DefaultsModuleOutput.swift */, - 0E8A10192384615400A9CBA6 /* DefaultsPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E8A100623845E9400A9CBA6 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0E8A101B2384618700A9CBA6 /* DefaultsInitializer.swift */, - 0E8A101D238461D400A9CBA6 /* DefaultsConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 0E8A100723845F1B00A9CBA6 /* SwiftUI */ = { - isa = PBXGroup; - children = ( - 0E8A10212384637F00A9CBA6 /* DefaultsList.swift */, - 0E8A101F2384633200A9CBA6 /* DefaultsEnvironmentObject.swift */, - ); - path = SwiftUI; - sourceTree = ""; - }; - 0E8A100823845F2300A9CBA6 /* Table */ = { - isa = PBXGroup; - children = ( - 0E8A102323846CCE00A9CBA6 /* Cells */, - 0E8A10112384605A00A9CBA6 /* DefaultsTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0E8A102323846CCE00A9CBA6 /* Cells */ = { - isa = PBXGroup; - children = ( - 0E8A102423846CEB00A9CBA6 /* DefaultsSwitchTableViewCell.swift */, - E11FDA6C29A2A3C2003ADA7B /* DefaultsPlainTableViewCell.swift */, - 0E8BD2AA23851CF2008B31EF /* DefaultsStepperTableViewCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - 0E8FD0D823336E8E00FFA577 /* Cards */ = { - isa = PBXGroup; - children = ( - 0E1C1DE522B3C2900032F6CA /* Assembly */, - 0E1C1DDB22B3C1F30032F6CA /* Presenter */, - 0E1C1DE022B3C24F0032F6CA /* Router */, - 0E1C1DCF22B3BDBB0032F6CA /* View */, - E1395BF72954DA6900C403C6 /* Interactor */, - ); - path = Cards; - sourceTree = ""; - }; - 0E8FD0D923336EB200FFA577 /* Charts */ = { - isa = PBXGroup; - children = ( - E1E102EC28F348A700815508 /* Helpers */, - E18D04C228E9DF66008EF5EC /* View */, - E18D04B828E8B310008EF5EC /* Interactor */, - E18D04A728E8A6B0008EF5EC /* Presenter */, - E18D04A328E8A58A008EF5EC /* Assembly */, - ); - path = Charts; - sourceTree = ""; - }; - 0E92A94B2686339300187E4F /* Structs */ = { - isa = PBXGroup; - children = ( - 0E25135E2684AEAD004A522A /* RuuviNotifierTitlesImpl.swift */, - E16051E8285CB384003FCA70 /* AppStoreReviewHelper.swift */, - E19EAF6529983650005827E4 /* AppUtility.swift */, - 0E00C4F02684D97B009B3C24 /* ExportHeadersProvider.swift */, - 0E0501202685E895007060C4 /* HeartbeatDaemonTitles.swift */, - E16051E5285A15A1003FCA70 /* RuuviTagBatteryStatusProvider.swift */, - E168B4AA2885C28000D6B5C6 /* MeasurementAccuracyTitles.swift */, - E1597A6429608CF300DFB70B /* GlobalHelpers.swift */, - ); - path = Structs; - sourceTree = ""; - }; - 0E97D782268C826400FE9D5B /* DFU */ = { - isa = PBXGroup; - children = ( - 0EB8ED2E268F12FA00C6B0FA /* DFUModuleFactory.swift */, - 0EB8ED27268F10DB00C6B0FA /* Common */, - 0EB8ED1C268EFF1E00C6B0FA /* Extensions */, - 0EE36E3D26957DD90021B746 /* FirmwareRepository */, - 0E97D78D268C846200FE9D5B /* Presenter */, - 0E97D7A6268C921900FE9D5B /* Interactor */, - 0E97D78E268C84A300FE9D5B /* View */, - ); - path = DFU; - sourceTree = ""; - }; - 0E97D78D268C846200FE9D5B /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E97D79A268C881300FE9D5B /* DFUModuleInput.swift */, - 0E97D79D268C884500FE9D5B /* DFUPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0E97D78E268C84A300FE9D5B /* View */ = { - isa = PBXGroup; - children = ( - 0EB8ED23268F081800C6B0FA /* SwiftUI */, - 0EB8ED19268EF36200C6B0FA /* DFUViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - 0E97D7A6268C921900FE9D5B /* Interactor */ = { - isa = PBXGroup; - children = ( - 0EE36E3E26957E000021B746 /* DFUInteractorInput.swift */, - 0E97D7A7268C922C00FE9D5B /* DFUInteractor.swift */, - 0EE36E4126957E200021B746 /* LatestRelease.swift */, - ); - path = Interactor; - sourceTree = ""; - }; - 0EA7966F2664A7B3002BA25D /* Errors */ = { - isa = PBXGroup; - children = ( - 0E1C1D9F22B36C100032F6CA /* RUError.swift */, - 0E00C5072685D82B009B3C24 /* RuuviDaemonError+LocalizedError.swift */, - 0EA796702664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift */, - 0EA796742664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift */, - 0EA796782664B37F002BA25D /* RuuviLocalError+LocalizedError.swift */, - 0EA7967C2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift */, - 0EA796802664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift */, - 0EA796842664B84D002BA25D /* RuuviReactorError+LocalizedError.swift */, - 0EA796882664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift */, - 0EA7968C2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift */, - 0E2AFF9F266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift */, - 0EA7AB792680A68200C137AD /* RuuviCoreError+LocalizedError.swift */, - 0EF4E33C26824ABD00D83CC7 /* RuuviDFUError+LocalizedError.swift */, - ); - path = Errors; - sourceTree = ""; - }; - 0EB48D6D2619D4D4008E0D2D /* Features */ = { - isa = PBXGroup; - children = ( - 0EB48DFA261B1046008E0D2D /* RemoteConfig */, - 0EB48D932619D5D5008E0D2D /* Providers */, - 0EB48D6E2619D50A008E0D2D /* FeatureToggle.swift */, - 0EB48D8A2619D5AC008E0D2D /* FeatureToggleService.swift */, - ); - path = Features; - sourceTree = ""; - }; - 0EB48D932619D5D5008E0D2D /* Providers */ = { - isa = PBXGroup; - children = ( - 0EB48D942619D5E5008E0D2D /* FeatureToggleProvider.swift */, - 0EB48DA22619D7EE008E0D2D /* FirebaseFeatureToggleProvider.swift */, - 0EB48DDB2619E306008E0D2D /* FallbackFeatureToggleProvider.swift */, - 0EA511B7261F3C2C00EE5D5E /* LocalFeatureToggleProvider.swift */, - ); - path = Providers; - sourceTree = ""; - }; - 0EB48DE4261A17F4008E0D2D /* JSONs */ = { - isa = PBXGroup; - children = ( - 0EB48DE5261A1816008E0D2D /* FeatureToggles.json */, - ); - path = JSONs; - sourceTree = ""; - }; - 0EB48DFA261B1046008E0D2D /* RemoteConfig */ = { - isa = PBXGroup; - children = ( - 0EB48E04261B1085008E0D2D /* Firebase */, - 0EB48DFB261B105D008E0D2D /* RemoteConfigService.swift */, - ); - path = RemoteConfig; - sourceTree = ""; - }; - 0EB48E04261B1085008E0D2D /* Firebase */ = { - isa = PBXGroup; - children = ( - 0EB48E05261B1095008E0D2D /* FirebaseRemoteConfigService.swift */, - ); - path = Firebase; - sourceTree = ""; - }; - 0EB8ED1C268EFF1E00C6B0FA /* Extensions */ = { - isa = PBXGroup; - children = ( - 0EB8ED1D268EFF4200C6B0FA /* Publishers+System.swift */, - 0EB8ED2B268F111B00C6B0FA /* View+Any.swift */, - 0EB8ED35268F685500C6B0FA /* URLSession+downloadTaskPublisher.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - 0EB8ED23268F081800C6B0FA /* SwiftUI */ = { - isa = PBXGroup; - children = ( - 0EB8ED24268F083700C6B0FA /* DFUUIView.swift */, - ); - path = SwiftUI; - sourceTree = ""; - }; - 0EB8ED27268F10DB00C6B0FA /* Common */ = { - isa = PBXGroup; - children = ( - 0EB8ED28268F10E900C6B0FA /* Spinner.swift */, - 0EB8ED20268EFF6400C6B0FA /* Feedback.swift */, - 0EB8ED38268F6A6900C6B0FA /* ProgressBar.swift */, - 0EB8ED3E26916D1700C6B0FA /* LargeButtonStyle.swift */, - ); - path = Common; - sourceTree = ""; - }; - 0EB8ED412692004300C6B0FA /* Colors */ = { - isa = PBXGroup; - children = ( - 0EB8ED422692005900C6B0FA /* Colors.xcassets */, - ); - path = Colors; - sourceTree = ""; - }; - 0EB8ED452692017100C6B0FA /* Colors */ = { - isa = PBXGroup; - children = ( - 0EB8ED462692018000C6B0FA /* RuuviColor.swift */, - ); - path = Colors; - sourceTree = ""; - }; - 0EBAF062232000F50025A191 /* Module */ = { - isa = PBXGroup; - children = ( - 0EEB20D022B7C6F30015F9E0 /* Settings.storyboard */, - 0EEB20DB22B7C83E0015F9E0 /* Assembly */, - 0EEB20DA22B7C8380015F9E0 /* Presenter */, - 0EEB20D922B7C8330015F9E0 /* Router */, - 0EEB20CF22B7C6E40015F9E0 /* View */, - ); - path = Module; - sourceTree = ""; - }; - 0EBAF063232001080025A191 /* Submodules */ = { - isa = PBXGroup; - children = ( - E196914A2A059C7200DC360E /* Notifications */, - E11989F829BA605F002245CF /* Appearance */, - E1B57FE629859C7000B441FB /* Devices */, - A9828E54247BAC0700E7E9D4 /* Chart */, - 0E8A100023845E1200A9CBA6 /* Defaults */, - 0E84BF4F2397F24D00A37E1A /* Heartbeat */, - E1CD77E52878199600F1F0EB /* Unit Settings */, - A91D02D92511207200694733 /* Selection */, - E10E18A5297D65D1002C78C3 /* Ruuvi Cloud */, - ); - path = Submodules; - sourceTree = ""; - }; - 0EC50F4E22CCB91000172EEB /* Binding */ = { - isa = PBXGroup; - children = ( - 0EC50F4F22CCB92000172EEB /* Observable.swift */, - 0EC50F5522CCE46D00172EEB /* Optional.swift */, - 0EC50F5322CCBBE800172EEB /* NSObject+Observable.swift */, - ); - path = Binding; - sourceTree = ""; - }; - 0EC50F5722CF61F700172EEB /* PhotoPicker */ = { - isa = PBXGroup; - children = ( - 0EC50F5A22CF624200172EEB /* Sheet */, - 0EC50F5822CF621000172EEB /* PhotoPickerPresenter.swift */, - ); - path = PhotoPicker; - sourceTree = ""; - }; - 0EC50F5A22CF624200172EEB /* Sheet */ = { - isa = PBXGroup; - children = ( - 0E5C300A22CF629100B52E39 /* PhotoPickerPresenterSheet.swift */, - ); - path = Sheet; - sourceTree = ""; - }; - 0EE36E3D26957DD90021B746 /* FirmwareRepository */ = { - isa = PBXGroup; - children = ( - 0EB8ED3B268F8CD900C6B0FA /* FirmwareRepository.swift */, - ); - path = FirmwareRepository; - sourceTree = ""; - }; - 0EE98A772649386000AAB3ED /* FLEX */ = { - isa = PBXGroup; - children = ( - 0ECA19692B138C3A00BEE4DB /* FeatureTogglesViewController.swift */, - ); - path = FLEX; - sourceTree = ""; - }; - 0EEB20CE22B7C6DA0015F9E0 /* Settings */ = { - isa = PBXGroup; - children = ( - 0EBAF062232000F50025A191 /* Module */, - 0EBAF063232001080025A191 /* Submodules */, - ); - path = Settings; - sourceTree = ""; - }; - 0EEB20CF22B7C6E40015F9E0 /* View */ = { - isa = PBXGroup; - children = ( - 0EEB20D422B7C7BE0015F9E0 /* Table */, - 0EEB20D522B7C7E70015F9E0 /* SettingsViewInput.swift */, - 0EEB20D722B7C8060015F9E0 /* SettingsViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 0EEB20D422B7C7BE0015F9E0 /* Table */ = { - isa = PBXGroup; - children = ( - 0EEB20D222B7C7AC0015F9E0 /* SettingsTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0EEB20D922B7C8330015F9E0 /* Router */ = { - isa = PBXGroup; - children = ( - 0EEB20DC22B7C8650015F9E0 /* SettingsRouterInput.swift */, - 0EEB20DE22B7C8790015F9E0 /* SettingsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0EEB20DA22B7C8380015F9E0 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0EEB20E022B7C8A90015F9E0 /* SettingsModuleInput.swift */, - 0EEB20E222B7C8C10015F9E0 /* SettingsPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0EEB20DB22B7C83E0015F9E0 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0EEB20E422B7C8E60015F9E0 /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - 0EEB20E422B7C8E60015F9E0 /* Table */ = { - isa = PBXGroup; - children = ( - 0EEB20E522B7C8F20015F9E0 /* SettingsTableInitializer.swift */, - 0EEB20E722B7C92C0015F9E0 /* SettingsTableConfigurator.swift */, - ); - path = Table; - sourceTree = ""; - }; - 0EEB20E922B7D1350015F9E0 /* About */ = { - isa = PBXGroup; - children = ( - 0EEB20EE22B7D1580015F9E0 /* About.storyboard */, - 0EEB20ED22B7D14A0015F9E0 /* Assembly */, - 0EEB20EC22B7D1440015F9E0 /* Presenter */, - 0EEB20EB22B7D1400015F9E0 /* Router */, - 0EEB20EA22B7D13B0015F9E0 /* View */, - ); - path = About; - sourceTree = ""; - }; - 0EEB20EA22B7D13B0015F9E0 /* View */ = { - isa = PBXGroup; - children = ( - 0EEB20F222B7D1900015F9E0 /* AboutViewInput.swift */, - 0EEB20F422B7D1A40015F9E0 /* AboutViewOutput.swift */, - 0EEB20F622B7D2090015F9E0 /* AboutViewController.swift */, - A980573725807118000D03AB /* AboutViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - 0EEB20EB22B7D1400015F9E0 /* Router */ = { - isa = PBXGroup; - children = ( - 0EEB20F822B7D28C0015F9E0 /* AboutRouterInput.swift */, - 0EEB20FA22B7D2990015F9E0 /* AboutRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 0EEB20EC22B7D1440015F9E0 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0EEB20FC22B7D2C90015F9E0 /* AboutModuleInput.swift */, - 0EEB20FE22B7D2DD0015F9E0 /* AboutPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 0EEB20ED22B7D14A0015F9E0 /* Assembly */ = { - isa = PBXGroup; - children = ( - 0EEB210022B7D2F50015F9E0 /* AboutInitializer.swift */, - 0EEB210222B7D3210015F9E0 /* AboutConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 0EF2862522CBAF280026C7A5 /* TagSettings */ = { - isa = PBXGroup; - children = ( - E191F2042969DE5F00F1FEA6 /* Presenter */, - E191F2032969DE5700F1FEA6 /* Router */, - E191F2002969DE1F00F1FEA6 /* Assembly */, - 0EF2862622CBAF320026C7A5 /* View */, - 66BC44812657AED400A03253 /* Submodules */, - ); - path = TagSettings; - sourceTree = ""; - }; - 0EF2862622CBAF320026C7A5 /* View */ = { - isa = PBXGroup; - children = ( - E191F2022969DE3700F1FEA6 /* UI */, - E10E18712978AF3D002C78C3 /* TagSettingsViewModel.swift */, - 0EF2863022CBB00D0026C7A5 /* TagSettingsViewInput.swift */, - 0EF2863222CBB0250026C7A5 /* TagSettingsViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 11629D6C45208918E104E77F /* Assembly */ = { - isa = PBXGroup; - children = ( - E19EAF82299C1383005827E4 /* SignInModuleFactory.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 321CE77F6EB26F685032F835 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 0E869E2A265E5399006F4870 /* FirebaseRemoteConfig.framework */, - 0E8BAC97245C716B00D380FB /* Combine.framework */, - 0E8BAC9A245C718700D380FB /* Combine.framework */, - 8018B7836CF8C748718825DD /* Pods_station.framework */, - 9174E0B0C8F457647FEE639C /* Pods_stationTests.framework */, - 7097B76856D5F01896F963EC /* Pods_station_dev.framework */, - 34A8D48A281EBFD9008A8698 /* WidgetKit.framework */, - 34A8D48C281EBFD9008A8698 /* SwiftUI.framework */, - 34A8D4B6281EE5AE008A8698 /* Intents.framework */, - D63A307EB55306A1D598FDAE /* Pods_station_widgets.framework */, - B004B50BE06AD9034B2EFCB4 /* Pods_station_intents.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 340BE37727B54F37006D6C34 /* Owner */ = { - isa = PBXGroup; - children = ( - 340BE37827B54F37006D6C34 /* Owner.storyboard */, - 340BE37927B54F37006D6C34 /* Assembly */, - 340BE37C27B54F37006D6C34 /* Presenter */, - 340BE37F27B54F37006D6C34 /* View */, - 340BE38327B54F37006D6C34 /* Router */, - ); - path = Owner; - sourceTree = ""; - }; - 340BE37927B54F37006D6C34 /* Assembly */ = { - isa = PBXGroup; - children = ( - 340BE37A27B54F37006D6C34 /* OwnerInitializer.swift */, - 340BE37B27B54F37006D6C34 /* OwnerConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 340BE37C27B54F37006D6C34 /* Presenter */ = { - isa = PBXGroup; - children = ( - 340BE37D27B54F37006D6C34 /* OwnerPresenter.swift */, - 340BE37E27B54F37006D6C34 /* OwnerModuleInput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 340BE37F27B54F37006D6C34 /* View */ = { - isa = PBXGroup; - children = ( - 340BE38027B54F37006D6C34 /* OwnerViewInput.swift */, - 340BE38127B54F37006D6C34 /* OwnerViewController.swift */, - 340BE38227B54F37006D6C34 /* OwnerViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 340BE38327B54F37006D6C34 /* Router */ = { - isa = PBXGroup; - children = ( - 340BE38427B54F37006D6C34 /* OwnerRouter.swift */, - 340BE38527B54F37006D6C34 /* OwnerRouterInput.swift */, - ); - path = Router; - sourceTree = ""; - }; - 3414BFC62806D0EE00C63BE9 /* Helper */ = { - isa = PBXGroup; - children = ( - E19EAF74299AE3B0005827E4 /* SignInView.swift */, - E19EAF77299AE5EA005827E4 /* SignInVerifyView.swift */, - 3414BFC72806D19C00C63BE9 /* RuuviCodeView.swift */, - 3414BFCA2806D1B300C63BE9 /* RuuviCodeTextField.swift */, - ); - path = Helper; - sourceTree = ""; - }; - 3493386128300A62009060E8 /* View */ = { - isa = PBXGroup; - children = ( - 3493386228300A73009060E8 /* SimpleWidgetView.swift */, - E1117007291C34A700ACCD72 /* SimpleWidgetViewRectangle.swift */, - E128160A292ABCFA008E9282 /* SimpleWidgetViewCircular.swift */, - E1072686291C49E500247625 /* SimpleWidgetViewInline.swift */, - 3493386428300ACC009060E8 /* UnauthorizedView.swift */, - 3493386628300B05009060E8 /* EmptyWidgetView.swift */, - ); - path = View; - sourceTree = ""; - }; - 3493386828300C02009060E8 /* Assembly */ = { - isa = PBXGroup; - children = ( - 34D458DF28216B2200EA9F93 /* WidgetAssembly.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 3493386928300C21009060E8 /* View Model */ = { - isa = PBXGroup; - children = ( - 34D458E128216C6900EA9F93 /* WidgetViewModel.swift */, - ); - path = "View Model"; - sourceTree = ""; - }; - 3493386A28300C2A009060E8 /* Model */ = { - isa = PBXGroup; - children = ( - 34A8D4C5281EEC19008A8698 /* WidgetEntry.swift */, - 3493386E283014A0009060E8 /* Model+Extension.swift */, - ); - path = Model; - sourceTree = ""; - }; - 34933871283014E3009060E8 /* Enum */ = { - isa = PBXGroup; - children = ( - 34933872283014F6009060E8 /* WidgetSensorEnum.swift */, - ); - path = Enum; - sourceTree = ""; - }; - 34A8D48E281EBFD9008A8698 /* ruuvi-widgets */ = { - isa = PBXGroup; - children = ( - 34933871283014E3009060E8 /* Enum */, - 3493386A28300C2A009060E8 /* Model */, - 3493386928300C21009060E8 /* View Model */, - 3493386828300C02009060E8 /* Assembly */, - 3493386128300A62009060E8 /* View */, - 34A8D4B0281EE0C1008A8698 /* Provider */, - 34A8D4A0281ECFFB008A8698 /* Resources */, - 34A8D49F281ECFF5008A8698 /* Helper */, - 34A8D48F281EBFD9008A8698 /* RuuviWidgets.swift */, - E186AB302844A273004926FC /* RuuviWidgetsConfiguration.intentdefinition */, - 34A8D492281EBFDB008A8698 /* Assets.xcassets */, - 34A8D494281EBFDB008A8698 /* Info.plist */, - ); - path = "ruuvi-widgets"; - sourceTree = ""; - }; - 34A8D49F281ECFF5008A8698 /* Helper */ = { - isa = PBXGroup; - children = ( - 34A8D4A1281ED018008A8698 /* Extensions.swift */, - 341401EB282D03C8003DE721 /* MeasurementService.swift */, - 3493385C28300396009060E8 /* NetworkManager.swift */, - 3493386B28300C49009060E8 /* Constants.swift */, - ); - path = Helper; - sourceTree = ""; - }; - 34A8D4A0281ECFFB008A8698 /* Resources */ = { - isa = PBXGroup; - children = ( - 34A8D4A3281ED01C008A8698 /* Fonts */, - ); - path = Resources; - sourceTree = ""; - }; - 34A8D4A3281ED01C008A8698 /* Fonts */ = { - isa = PBXGroup; - children = ( - 34A8D4A5281ED046008A8698 /* Montserrat-Bold.ttf */, - 34A8D4A4281ED046008A8698 /* Montserrat-Regular.ttf */, - 34A8D4A9281ED046008A8698 /* Muli-Bold.ttf */, - 34A8D4A6281ED046008A8698 /* Muli-Regular.ttf */, - 34A8D4A7281ED046008A8698 /* Oswald-Bold.ttf */, - 34A8D4A8281ED046008A8698 /* Oswald-ExtraLight.ttf */, - ); - path = Fonts; - sourceTree = ""; - }; - 34A8D4B0281EE0C1008A8698 /* Provider */ = { - isa = PBXGroup; - children = ( - 34A8D4C3281EEBF8008A8698 /* WidgetProvider.swift */, - ); - path = Provider; - sourceTree = ""; - }; - 34A8D4B8281EE5AE008A8698 /* intents */ = { - isa = PBXGroup; - children = ( - 34A8D4B9281EE5AE008A8698 /* IntentHandler.swift */, - 34A8D4BB281EE5AE008A8698 /* Info.plist */, - ); - path = intents; - sourceTree = ""; - }; - 3D930628B855379BB9A9B1FF /* Assembly */ = { - isa = PBXGroup; - children = ( - AB681E62A66E5924A87859B1 /* ShareConfigurator.swift */, - 392F0E992BEAA3382C2CF709 /* ShareInitializer.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - 62FD66A56B206724C5DE9CFE /* Pods */ = { - isa = PBXGroup; - children = ( - 50760BEF3DF7F0DC671A0D42 /* Pods-station.debug.xcconfig */, - B3426764B50E4E9CA2A27704 /* Pods-station.release.xcconfig */, - 2CFE01D4D914A918175D4BEA /* Pods-stationTests.debug.xcconfig */, - 8825D89E1A7CB4BDC6D12038 /* Pods-stationTests.release.xcconfig */, - 3BC7A7F074761C1B58F7F946 /* Pods-station_dev.debug.xcconfig */, - 85F06A44D8D006FBFB90ABE0 /* Pods-station_dev.release.xcconfig */, - 5C35D73AC96D7B6765529406 /* Pods-station_widgets.debug.xcconfig */, - 47B3F8D904CAAB34D68A68DC /* Pods-station_widgets.release.xcconfig */, - 437F08C73081253CCDA3687A /* Pods-station_intents.debug.xcconfig */, - B5EE8D004C84A07188EF2E3A /* Pods-station_intents.release.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; - 64333D1C20B0C45900CDF4B6 = { - isa = PBXGroup; - children = ( - E19EAF502996BAAF005827E4 /* pnservice.entitlements */, - 34A8D4CA281FEF2E008A8698 /* station_intents.entitlements */, - 34A8D49E281EC2B6008A8698 /* ruuvi_widgets.entitlements */, - A92C75DD24896B7400E332FE /* Fastlane */, - 64333D2720B0C45900CDF4B6 /* station */, - 64333D3C20B0C45A00CDF4B6 /* stationTests */, - 64333D4720B0C45B00CDF4B6 /* stationUITests */, - 34A8D48E281EBFD9008A8698 /* ruuvi-widgets */, - 34A8D4B8281EE5AE008A8698 /* intents */, - E17C469A29956732008CFDD7 /* pnservice */, - 64333D2620B0C45900CDF4B6 /* Products */, - 62FD66A56B206724C5DE9CFE /* Pods */, - 321CE77F6EB26F685032F835 /* Frameworks */, - ); - sourceTree = ""; - }; - 64333D2620B0C45900CDF4B6 /* Products */ = { - isa = PBXGroup; - children = ( - 64333D2520B0C45900CDF4B6 /* station.app */, - 64333D3920B0C45A00CDF4B6 /* stationTests.xctest */, - 64333D4420B0C45B00CDF4B6 /* stationUITests.xctest */, - 0E8BD404238566AB008B31EF /* station_dev.app */, - 34A8D489281EBFD9008A8698 /* station_widgets.appex */, - 34A8D4B5281EE5AE008A8698 /* station_intents.appex */, - E17C469929956732008CFDD7 /* pnservice.appex */, - ); - name = Products; - sourceTree = ""; - }; - 64333D2720B0C45900CDF4B6 /* station */ = { - isa = PBXGroup; - children = ( - 0ECDF1B62313D7DA00A09ACA /* station.entitlements */, - 0E09671622AE74D600E85F48 /* Classes */, - 0E09672322AE895600E85F48 /* Extensions */, - 0E09671722AE762900E85F48 /* Resources */, - ); - path = station; - sourceTree = ""; - }; - 64333D3C20B0C45A00CDF4B6 /* stationTests */ = { - isa = PBXGroup; - children = ( - A971B0DA2421531C008EF50D /* Extensions */, - A94FFD25241C0F8000888017 /* Services */, - 64333D3D20B0C45A00CDF4B6 /* StationTests.swift */, - 64333D3F20B0C45B00CDF4B6 /* Info.plist */, - ); - path = stationTests; - sourceTree = ""; - }; - 64333D4720B0C45B00CDF4B6 /* stationUITests */ = { - isa = PBXGroup; - children = ( - 0E6C471623D305960016B46E /* StationUITests.swift */, - 64333D4A20B0C45B00CDF4B6 /* Info.plist */, - ); - path = stationUITests; - sourceTree = ""; - }; - 6486970E20E042BC00CCD7C1 /* Fonts */ = { - isa = PBXGroup; - children = ( - E19EAF512996C828005827E4 /* Montserrat-ExtraBold.ttf */, - 64678190225D02CE0072856A /* Muli-Bold.ttf */, - E19EAF5A2996CF38005827E4 /* Muli-SemiBoldItalic.ttf */, - E1BAC1392A7598F000EA820E /* Muli-ExtraBold.ttf */, - 6467818F225CFB170072856A /* Muli-Regular.ttf */, - 643C651E21C38F490037BE5B /* Montserrat-Bold.ttf */, - 6486971120E0439200CCD7C1 /* Montserrat-Regular.ttf */, - 6486970F20E042E000CCD7C1 /* Oswald-Bold.ttf */, - 643EEC2A2266435100D4E837 /* Oswald-ExtraLight.ttf */, - ); - path = Fonts; - sourceTree = ""; - }; - 66BC44812657AED400A03253 /* Submodules */ = { - isa = PBXGroup; - children = ( - E1B7B51E2AE9888C009D747E /* Removal */, - E1AB90572A0EAF4F00543F61 /* Force Claim */, - 340BE37727B54F37006D6C34 /* Owner */, - 0E97D782268C826400FE9D5B /* DFU */, - 66BC44822657AED400A03253 /* OffsetCorrection */, - ); - path = Submodules; - sourceTree = ""; - }; - 66BC44822657AED400A03253 /* OffsetCorrection */ = { - isa = PBXGroup; - children = ( - 66BC44832657AED400A03253 /* OffsetCorrection.storyboard */, - 66BC44842657AED400A03253 /* Assembly */, - 66BC44882657AED400A03253 /* Presenter */, - 66BC44922657AED400A03253 /* Router */, - 66BC448C2657AED400A03253 /* View */, - ); - path = OffsetCorrection; - sourceTree = ""; - }; - 66BC44842657AED400A03253 /* Assembly */ = { - isa = PBXGroup; - children = ( - 66BC44852657AED400A03253 /* Apple */, - ); - path = Assembly; - sourceTree = ""; - }; - 66BC44852657AED400A03253 /* Apple */ = { - isa = PBXGroup; - children = ( - 66BC44862657AED400A03253 /* OffsetCorrectionAppleInitializer.swift */, - 66BC44872657AED400A03253 /* OffsetCorrectionConfigurator.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 66BC44882657AED400A03253 /* Presenter */ = { - isa = PBXGroup; - children = ( - 66BC44892657AED400A03253 /* OffsetCorrectionModuleOutput.swift */, - 66BC448A2657AED400A03253 /* OffsetCorrectionPresenter.swift */, - 66BC448B2657AED400A03253 /* OffsetCorrectionModuleInput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 66BC448C2657AED400A03253 /* View */ = { - isa = PBXGroup; - children = ( - 66BC448D2657AED400A03253 /* Apple */, - 66BC448F2657AED400A03253 /* OffsetCorrectionViewInput.swift */, - 66BC44902657AED400A03253 /* OffsetCorrectionViewModel.swift */, - 66BC44912657AED400A03253 /* OffsetCorrectionViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - 66BC448D2657AED400A03253 /* Apple */ = { - isa = PBXGroup; - children = ( - 66BC448E2657AED400A03253 /* OffsetCorrectionAppleViewController.swift */, - ); - path = Apple; - sourceTree = ""; - }; - 66BC44922657AED400A03253 /* Router */ = { - isa = PBXGroup; - children = ( - 66BC44932657AED400A03253 /* OffsetCorrectionRouter.swift */, - 66BC44942657AED400A03253 /* OffsetCorrectionRouterInput.swift */, - ); - path = Router; - sourceTree = ""; - }; - 6C62E43912ACBCF757914A64 /* Router */ = { - isa = PBXGroup; - children = ( - 4E816312622E83E3B42001DC /* SignInRouterInput.swift */, - 6F0552F1D17F403B7DE508B5 /* SignInRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 71A3760FF84549A5FB45C805 /* SignIn */ = { - isa = PBXGroup; - children = ( - 11629D6C45208918E104E77F /* Assembly */, - 9430BF42054B093449B0B9FB /* Presenter */, - 6C62E43912ACBCF757914A64 /* Router */, - 975CCF09FE9E0AEF7A6CEEF8 /* View */, - E19EAF8E299E5F84005827E4 /* Submodules */, - ); - path = SignIn; - sourceTree = ""; - }; - 89F27275323C3CBC88A9180D /* View */ = { - isa = PBXGroup; - children = ( - A9E599482557340200F9E5CC /* Cells */, - 167F75FD2FDAD002C10686FA /* ShareViewInput.swift */, - CE5C4AD5C54EF024669EAF47 /* ShareViewOutput.swift */, - 354B5B6F50E98F55D6A672BA /* ShareViewModel.swift */, - 9607EC149920F19A54BE896D /* ViewController */, - ); - path = View; - sourceTree = ""; - }; - 910C826026E94BD80C07FBD2 /* Router */ = { - isa = PBXGroup; - children = ( - 9546F1EFEE8F8CFC22377BB4 /* ShareRouterInput.swift */, - BD7AE39C23B8C52BB202BB5E /* ShareRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - 9430BF42054B093449B0B9FB /* Presenter */ = { - isa = PBXGroup; - children = ( - 87EFB230083D471777FBE5D0 /* SignInModuleInput.swift */, - 9B3006A5FB2173EC6AA2728D /* SignInModuleOutput.swift */, - E19EAFAC299E82D1005827E4 /* SignInPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - 9607EC149920F19A54BE896D /* ViewController */ = { - isa = PBXGroup; - children = ( - FC417B8977A47FFAE71585F0 /* ShareViewController.swift */, - ); - path = ViewController; - sourceTree = ""; - }; - 975CCF09FE9E0AEF7A6CEEF8 /* View */ = { - isa = PBXGroup; - children = ( - E19EAF81299C1310005827E4 /* UI */, - 4A7D6325DFC865D2D11BD1D1 /* SignInViewInput.swift */, - 4BD498E7491E278B4EF4919C /* SignInViewOutput.swift */, - FC59D3B5AD8926DBDD79AA1C /* SignInViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - A9100D81241AD1D0004007FD /* Mock */ = { - isa = PBXGroup; - children = ( - A9100D82241AD1E4004007FD /* MockAlertPersistence.swift */, - A94FFD49241D45C600888017 /* MockRuuviTag.swift */, - A94FFD4B241D512900888017 /* MockLocalNotificationsManager.swift */, - A94FFD4D241D57E700888017 /* MockCalibrationService.swift */, - A94FFD4F241D6BA300888017 /* MockAlertServiceObserver.swift */, - ); - name = Mock; - path = ../..; - sourceTree = ""; - }; - A91D02D92511207200694733 /* Selection */ = { - isa = PBXGroup; - children = ( - A91D030C251121C800694733 /* Selection.storyboard */, - A91D02DB2511207200694733 /* Assembly */, - A91D02DF2511207200694733 /* Presenter */, - A91D02E22511207200694733 /* View */, - A91D0314251124E800694733 /* Model */, - A91D02E82511207200694733 /* Router */, - ); - path = Selection; - sourceTree = ""; - }; - A91D02DB2511207200694733 /* Assembly */ = { - isa = PBXGroup; - children = ( - A91D02DC2511207200694733 /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - A91D02DC2511207200694733 /* Table */ = { - isa = PBXGroup; - children = ( - A91D02DD2511207200694733 /* SelectionTableConfigurator.swift */, - A91D02DE2511207200694733 /* SelectionTableInitializer.swift */, - ); - path = Table; - sourceTree = ""; - }; - A91D02DF2511207200694733 /* Presenter */ = { - isa = PBXGroup; - children = ( - A91D02E02511207200694733 /* SelectionPresenter.swift */, - A91D02E12511207200694733 /* SelectionModuleInput.swift */, - A91D0310251123B400694733 /* SelectionModuleOutput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - A91D02E22511207200694733 /* View */ = { - isa = PBXGroup; - children = ( - A91D02E42511207200694733 /* Table */, - A91D02E32511207200694733 /* SelectionViewInput.swift */, - A91D02E72511207200694733 /* SelectionViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - A91D02E42511207200694733 /* Table */ = { - isa = PBXGroup; - children = ( - A91D02E52511207200694733 /* SelectionTableViewCell.swift */, - A91D02E62511207200694733 /* SelectionTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - A91D02E82511207200694733 /* Router */ = { - isa = PBXGroup; - children = ( - A91D02E92511207200694733 /* SelectionRouter.swift */, - A91D02EA2511207200694733 /* SelectionRouterInput.swift */, - ); - path = Router; - sourceTree = ""; - }; - A91D0314251124E800694733 /* Model */ = { - isa = PBXGroup; - children = ( - A91D0315251124F900694733 /* SelectionItem.swift */, - ); - path = Model; - sourceTree = ""; - }; - A92C75DD24896B7400E332FE /* Fastlane */ = { - isa = PBXGroup; - children = ( - A92C75DE24896BA100E332FE /* fastlane */, - A92C75E124896BA100E332FE /* Gemfile */, - ); - name = Fastlane; - sourceTree = ""; - }; - A92C75DE24896BA100E332FE /* fastlane */ = { - isa = PBXGroup; - children = ( - A986147A248C49B00030F197 /* Matchfile */, - A92C75E2248982A000E332FE /* Pluginfile */, - A92C75DF24896BA100E332FE /* Appfile */, - A92C75E024896BA100E332FE /* Fastfile */, - ); - path = fastlane; - sourceTree = ""; - }; - A93CDCCC25659B8600018C6C /* Alert */ = { - isa = PBXGroup; - children = ( - A93CDCDC25659BC500018C6C /* ViewModel */, - A93CDCCD25659B9400018C6C /* Impl */, - A93CDCCE25659BA600018C6C /* AlertPresenter.swift */, - ); - path = Alert; - sourceTree = ""; - }; - A93CDCCD25659B9400018C6C /* Impl */ = { - isa = PBXGroup; - children = ( - A93CDCDD25659BF600018C6C /* AlertPresenterImpl.swift */, - ); - path = Impl; - sourceTree = ""; - }; - A93CDCDC25659BC500018C6C /* ViewModel */ = { - isa = PBXGroup; - children = ( - A9BB94CB2540AB610042B190 /* AlertViewModel.swift */, - ); - path = ViewModel; - sourceTree = ""; - }; - A94FFD25241C0F8000888017 /* Services */ = { - isa = PBXGroup; - children = ( - A97B06482593B817003EE069 /* MeasurementsService */, - A94FFD27241C0FA400888017 /* Alert */, - ); - path = Services; - sourceTree = ""; - }; - A94FFD27241C0FA400888017 /* Alert */ = { - isa = PBXGroup; - children = ( - A94FFD3B241C1D0D00888017 /* AlertServiceSpec.swift */, - A9100D81241AD1D0004007FD /* Mock */, - ); - path = Alert; - sourceTree = ""; - }; - A9646453247BAE6A0001D55D /* View */ = { - isa = PBXGroup; - children = ( - A9646456247BAE6A0001D55D /* Table */, - A9646454247BAE6A0001D55D /* ChartSettingsViewInput.swift */, - A964645B247BAE6A0001D55D /* ChartSettingsViewOutput.swift */, - A964645C247BAE6A0001D55D /* ChartSettingsViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - A9646456247BAE6A0001D55D /* Table */ = { - isa = PBXGroup; - children = ( - A9646457247BAE6A0001D55D /* Cells */, - A964645A247BAE6A0001D55D /* ChartSettingsTableViewController.swift */, - ); - path = Table; - sourceTree = ""; - }; - A9646457247BAE6A0001D55D /* Cells */ = { - isa = PBXGroup; - children = ( - A9646458247BAE6A0001D55D /* ChartSettingsStepperTableViewCell.swift */, - A9646459247BAE6A0001D55D /* ChartSettingsSwitchTableViewCell.swift */, - A976CA7D24A928C20099BDC1 /* ChartSettingsDisclosureTableViewCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - A964645D247BAE6A0001D55D /* Assembly */ = { - isa = PBXGroup; - children = ( - A964645E247BAE6A0001D55D /* ChartSettingsConfigurator.swift */, - A964645F247BAE6A0001D55D /* ChartSettingsInitializer.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - A9646460247BAE6A0001D55D /* Presenter */ = { - isa = PBXGroup; - children = ( - A9646461247BAE6A0001D55D /* ChartModuleInput.swift */, - A9646462247BAE6A0001D55D /* ChartSettingsPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - A9646463247BAE6A0001D55D /* Router */ = { - isa = PBXGroup; - children = ( - A9646464247BAE6A0001D55D /* ChartSettingsRouterInput.swift */, - A9646465247BAE6A0001D55D /* ChartSettingsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - A971B0DA2421531C008EF50D /* Extensions */ = { - isa = PBXGroup; - children = ( - A971B0DB24215334008EF50D /* XCTest+Extension.swift */, - ); - path = Extensions; - sourceTree = ""; - }; - A97B06482593B817003EE069 /* MeasurementsService */ = { - isa = PBXGroup; - children = ( - A9E6770D25A30D0A000B75A3 /* MeasurementsServiceEnSpec.swift */, - A9E6771925A31556000B75A3 /* MeasurementsServiceSvSpec.swift */, - A935E47525A49E8F009538C4 /* MeasurementsServiceFiSpec.swift */, - A935E47C25A49E9E009538C4 /* MeasurementsServiceRuSpec.swift */, - ); - path = MeasurementsService; - sourceTree = ""; - }; - A9828E54247BAC0700E7E9D4 /* Chart */ = { - isa = PBXGroup; - children = ( - A964648D247BAEBA0001D55D /* ChartSettings.storyboard */, - A964645D247BAE6A0001D55D /* Assembly */, - A9646460247BAE6A0001D55D /* Presenter */, - A9646463247BAE6A0001D55D /* Router */, - A9646453247BAE6A0001D55D /* View */, - ); - path = Chart; - sourceTree = ""; - }; - A9E599482557340200F9E5CC /* Cells */ = { - isa = PBXGroup; - children = ( - A9E599492557341F00F9E5CC /* ShareDescriptionTableViewCell.swift */, - A9E599572557345200F9E5CC /* ShareEmailInputTableViewCell.swift */, - A9E599602557346600F9E5CC /* ShareSendButtonTableViewCell.swift */, - A9E59969255734A000F9E5CC /* ShareEmailTableViewCell.swift */, - ); - path = Cells; - sourceTree = ""; - }; - A9FC78E7257966EF00F94604 /* UniversalLinks */ = { - isa = PBXGroup; - children = ( - A9FC78F72579672600F94604 /* Router */, - A9FC78F62579671F00F94604 /* Coordinator */, - ); - path = UniversalLinks; - sourceTree = ""; - }; - A9FC78F62579671F00F94604 /* Coordinator */ = { - isa = PBXGroup; - children = ( - A9FC78FD2579673E00F94604 /* Impl */, - A9FC78E82579671B00F94604 /* UniversalLinkCoordinator.swift */, - ); - path = Coordinator; - sourceTree = ""; - }; - A9FC78F72579672600F94604 /* Router */ = { - isa = PBXGroup; - children = ( - A9FC79072579675600F94604 /* Impl */, - A9FC78FE2579675100F94604 /* UniversalLinkRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - A9FC78FD2579673E00F94604 /* Impl */ = { - isa = PBXGroup; - children = ( - A9FC79162579678D00F94604 /* UniversalLinkCoordinatormpl.swift */, - ); - path = Impl; - sourceTree = ""; - }; - A9FC79072579675600F94604 /* Impl */ = { - isa = PBXGroup; - children = ( - A9FC790D2579676E00F94604 /* UniversalLinkRouterImpl.swift */, - ); - path = Impl; - sourceTree = ""; - }; - C11DEEB04EEFF836E529DA0B /* Presenter */ = { - isa = PBXGroup; - children = ( - 6AE2284D927021C0BEA560B0 /* ShareModuleInput.swift */, - 5710E4EF18D419D01D60405E /* ShareModuleOutput.swift */, - CC1D67615D6DBA9E2FC5B402 /* SharePresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - DB47D7C8D6149FEA8DD05FDC /* Share */ = { - isa = PBXGroup; - children = ( - A9E5993F25572CF700F9E5CC /* Share.storyboard */, - 3D930628B855379BB9A9B1FF /* Assembly */, - C11DEEB04EEFF836E529DA0B /* Presenter */, - 910C826026E94BD80C07FBD2 /* Router */, - 89F27275323C3CBC88A9180D /* View */, - ); - path = Share; - sourceTree = ""; - }; - E10E18A5297D65D1002C78C3 /* Ruuvi Cloud */ = { - isa = PBXGroup; - children = ( - E10E18A6297D65EE002C78C3 /* Assembly */, - E10E18A7297D65F5002C78C3 /* Presenter */, - E10E18A9297D6600002C78C3 /* View */, - ); - path = "Ruuvi Cloud"; - sourceTree = ""; - }; - E10E18A6297D65EE002C78C3 /* Assembly */ = { - isa = PBXGroup; - children = ( - E10E18AA297D6664002C78C3 /* RuuviCloudModuleFactory.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - E10E18A7297D65F5002C78C3 /* Presenter */ = { - isa = PBXGroup; - children = ( - E10E18AD297D6672002C78C3 /* RuuviCloudPresenter.swift */, - E10E18BC297D68EB002C78C3 /* RuuviCloudModuleInput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - E10E18A9297D6600002C78C3 /* View */ = { - isa = PBXGroup; - children = ( - E10E18BF297DD0BA002C78C3 /* UI */, - E10E18B3297D67B8002C78C3 /* RuuviCloudViewModel.swift */, - E10E18B6297D67E8002C78C3 /* RuuviCloudViewInput.swift */, - E10E18B9297D67FC002C78C3 /* RuuviCloudViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - E10E18BF297DD0BA002C78C3 /* UI */ = { - isa = PBXGroup; - children = ( - E10E18B0297D6690002C78C3 /* RuuviCloudTableViewController.swift */, - E10E18C0297DD0CA002C78C3 /* RuuviCloudTableViewCell.swift */, - ); - path = UI; - sourceTree = ""; - }; - E1167071296341C0002DF7BF /* View */ = { - isa = PBXGroup; - children = ( - E116708A29634D7D002DF7BF /* UI */, - E116707529634332002DF7BF /* BackgroundSelectionViewInput.swift */, - E116707829634363002DF7BF /* BackgroundSelectionViewOutput.swift */, - E116708B29634D91002DF7BF /* BackgroundSelectionViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - E1167072296341C6002DF7BF /* Presenter */ = { - isa = PBXGroup; - children = ( - E1167081296346D5002DF7BF /* BackgroundSelectionModuleInput.swift */, - E116708429634708002DF7BF /* BackgroundSelectionPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - E1167073296341CE002DF7BF /* Assembly */ = { - isa = PBXGroup; - children = ( - E116708729634815002DF7BF /* BackgroundSelectionModuleFactory.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - E116708A29634D7D002DF7BF /* UI */ = { - isa = PBXGroup; - children = ( - E1597A6E2961FEB800DFB70B /* BackgroundSelectionViewController.swift */, - E116706E29620AD4002DF7BF /* BackgroundSelectionButtonView.swift */, - E1597A742962046500DFB70B /* BackgroundSelectionViewHeader.swift */, - E1597A712962000B00DFB70B /* BackgroundSelectionViewCell.swift */, - E116708E29635B53002DF7BF /* BackgroundSelectionUploadProgressView.swift */, - ); - path = UI; - sourceTree = ""; - }; - E116AED02A05955B003EF65A /* Sounds */ = { - isa = PBXGroup; - children = ( - E116AED12A059578003EF65A /* ruuvi_speak.caf */, - ); - path = Sounds; - sourceTree = ""; - }; - E11989F829BA605F002245CF /* Appearance */ = { - isa = PBXGroup; - children = ( - E11989FD29BA60AC002245CF /* Presenter */, - E11989FC29BA60A7002245CF /* View */, - E11989FA29BA6097002245CF /* Router */, - E11989F929BA608D002245CF /* Assembly */, - E1198A2329BA744F002245CF /* Selection */, - ); - path = Appearance; - sourceTree = ""; - }; - E11989F929BA608D002245CF /* Assembly */ = { - isa = PBXGroup; - children = ( - E1198A0D29BA68FD002245CF /* AppearanceSettingsModuleFactory.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - E11989FA29BA6097002245CF /* Router */ = { - isa = PBXGroup; - children = ( - E1198A0729BA68B6002245CF /* AppearanceSettingsRouterInput.swift */, - E1198A0A29BA68BE002245CF /* AppearanceSettingsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - E11989FC29BA60A7002245CF /* View */ = { - isa = PBXGroup; - children = ( - E1198A1329BA69F3002245CF /* UI */, - E1198A1429BA6A06002245CF /* AppearanceSettingsViewOutput.swift */, - E1198A1729BA6A61002245CF /* AppearanceSettingsViewInput.swift */, - E1198A1A29BA6A79002245CF /* AppearanceSettingsViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - E11989FD29BA60AC002245CF /* Presenter */ = { - isa = PBXGroup; - children = ( - E1198A1029BA6910002245CF /* AppearanceSettingsPresenter.swift */, - E1198A1D29BA6B7E002245CF /* AppearanceSettingsModuleInput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - E1198A1329BA69F3002245CF /* UI */ = { - isa = PBXGroup; - children = ( - E11989FE29BA60CE002245CF /* AppearanceSettingsTableViewController.swift */, - E1198A0129BA6193002245CF /* AppearanceSettingsTableViewBasicCell.swift */, - ); - path = UI; - sourceTree = ""; - }; - E1198A2329BA744F002245CF /* Selection */ = { - isa = PBXGroup; - children = ( - E1198A2929BA764D002245CF /* Presenter */, - E1198A2829BA7646002245CF /* View */, - E1198A2429BA75CF002245CF /* Assembly */, - ); - path = Selection; - sourceTree = ""; - }; - E1198A2429BA75CF002245CF /* Assembly */ = { - isa = PBXGroup; - children = ( - E1198A2529BA763F002245CF /* ASSelectionModuleFactory.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - E1198A2829BA7646002245CF /* View */ = { - isa = PBXGroup; - children = ( - E1198A2A29BA7667002245CF /* UI */, - E1198A3129BA76C1002245CF /* ASSelectionViewOutput.swift */, - E1198A3429BA76CB002245CF /* ASSelectionViewInput.swift */, - ); - path = View; - sourceTree = ""; - }; - E1198A2929BA764D002245CF /* Presenter */ = { - isa = PBXGroup; - children = ( - E1198A3729BA76DD002245CF /* ASSelectionPresenter.swift */, - E1198A3A29BA76F1002245CF /* ASSelectionModuleInput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - E1198A2A29BA7667002245CF /* UI */ = { - isa = PBXGroup; - children = ( - E1198A2B29BA769A002245CF /* ASSelectionTableViewController.swift */, - E1198A2E29BA76A8002245CF /* ASSelectionTableViewCell.swift */, - ); - path = UI; - sourceTree = ""; - }; - E1395BEF294F791C00C403C6 /* Classess */ = { - isa = PBXGroup; - children = ( - E1395BF0294F793000C403C6 /* AppDateFormatter.swift */, - E1D0238A29EB02C600EC0FFD /* RuuviUISwitch.swift */, - E1CE5E462A016D4000391109 /* RuuviCustomButton.swift */, - E1AB90542A0BFECE00543F61 /* RuuviLinkTextView.swift */, - ); - path = Classess; - sourceTree = ""; - }; - E1395BF72954DA6900C403C6 /* Interactor */ = { - isa = PBXGroup; - children = ( - E1395BF82954DAA200C403C6 /* CardsInteractorInput.swift */, - E1395BFB2954DAAD00C403C6 /* CardsInteractor.swift */, - ); - path = Interactor; - sourceTree = ""; - }; - E1395BFE2957943600C403C6 /* UI */ = { - isa = PBXGroup; - children = ( - E1395BFF2957944E00C403C6 /* CardsViewController.swift */, - E1972BE029587615000E2AEC /* CardsLargeImageCell.swift */, - E1395C022958A2A900C403C6 /* CardsIndicatorView.swift */, - E1395C052958A33400C403C6 /* CardsBackgroundView.swift */, - ); - path = UI; - sourceTree = ""; - }; - E1597A35295CD39000DFB70B /* Interactor */ = { - isa = PBXGroup; - children = ( - E1597A4B295CD66500DFB70B /* DashboardInteractorInput.swift */, - E1597A4E295CD67900DFB70B /* DashboardInteractor.swift */, - ); - path = Interactor; - sourceTree = ""; - }; - E1597A36295CD39A00DFB70B /* Assembly */ = { - isa = PBXGroup; - children = ( - E1E3C338298EC9DC00A59CB8 /* DashboardModuleFactory.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - E1597A37295CD3A200DFB70B /* Presenter */ = { - isa = PBXGroup; - children = ( - E1597A45295CD5E400DFB70B /* DashboardModuleInput.swift */, - E1597A48295CD5F800DFB70B /* DashboardPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - E1597A38295CD3B000DFB70B /* Router */ = { - isa = PBXGroup; - children = ( - E1597A3C295CD52A00DFB70B /* DashboardRouterInput.swift */, - E1597A3F295CD55300DFB70B /* DashboardRouter.swift */, - E1597A42295CD58600DFB70B /* DashboardRouterDelegate.swift */, - ); - path = Router; - sourceTree = ""; - }; - E1597A5A295E24BB00DFB70B /* Assets */ = { - isa = PBXGroup; - children = ( - E1597A5B295E24D400DFB70B /* RuuviAssets.swift */, - ); - path = Assets; - sourceTree = ""; - }; - E1597A6D2961FE9E00DFB70B /* Background */ = { - isa = PBXGroup; - children = ( - E1167073296341CE002DF7BF /* Assembly */, - E1167072296341C6002DF7BF /* Presenter */, - E1167071296341C0002DF7BF /* View */, - ); - path = Background; - sourceTree = ""; - }; - E16B8F3A28D108970025B92D /* My Ruuvi */ = { - isa = PBXGroup; - children = ( - E16B8F3B28D109DD0025B92D /* MyRuuvi.storyboard */, - E16B8F5F28D1144B0025B92D /* Assembly */, - E16B8F5E28D114320025B92D /* View */, - E16B8F5D28D114210025B92D /* Presenter */, - E16B8F5C28D114110025B92D /* Router */, - ); - path = "My Ruuvi"; - sourceTree = ""; - }; - E16B8F5C28D114110025B92D /* Router */ = { - isa = PBXGroup; - children = ( - E16B8F5628D113CB0025B92D /* MyRuuviAccountRouterInput.swift */, - E16B8F5928D113EA0025B92D /* MyRuuviAccountRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - E16B8F5D28D114210025B92D /* Presenter */ = { - isa = PBXGroup; - children = ( - E16B8F4A28D1114F0025B92D /* MyRuuviAccountModuleInput.swift */, - E16B8F5328D113750025B92D /* MyRuuviAccountPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - E16B8F5E28D114320025B92D /* View */ = { - isa = PBXGroup; - children = ( - E16B8F3E28D10CF50025B92D /* MyRuuviAccountViewController.swift */, - E16B8F4128D10DF90025B92D /* MyRuuviAccountViewInput.swift */, - E16B8F4428D10E2C0025B92D /* MyRuuviAccountViewOutput.swift */, - E16B8F4728D10E7A0025B92D /* MyRuuviAccountViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - E16B8F5F28D1144B0025B92D /* Assembly */ = { - isa = PBXGroup; - children = ( - E16B8F4D28D113230025B92D /* MyRuuviAccountInitializer.swift */, - E16B8F5028D113440025B92D /* MyRuuviAccountConfigurator.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - E17C469A29956732008CFDD7 /* pnservice */ = { - isa = PBXGroup; - children = ( - E17C469B29956732008CFDD7 /* NotificationService.swift */, - E17C469D29956732008CFDD7 /* Info.plist */, - ); - path = pnservice; - sourceTree = ""; - }; - E18D04A328E8A58A008EF5EC /* Assembly */ = { - isa = PBXGroup; - children = ( - E18D04A428E8A5A3008EF5EC /* TagChartsViewConfigurator.swift */, - E1E3C335298D858D00A59CB8 /* TagChartsModuleFactory.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - E18D04A728E8A6B0008EF5EC /* Presenter */ = { - isa = PBXGroup; - children = ( - E18D04A828E8A6C0008EF5EC /* TagChartsViewPresenter.swift */, - E18D04AB28E8A737008EF5EC /* TagChartsViewModuleInput.swift */, - E18D04AE28E8A747008EF5EC /* TagChartsViewModuleOutput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - E18D04B828E8B310008EF5EC /* Interactor */ = { - isa = PBXGroup; - children = ( - E18D04B928E8B34F008EF5EC /* TagChartsViewInteractor.swift */, - E18D04BC28E8B397008EF5EC /* TagChartsViewInteractorInput.swift */, - E18D04BF28E8B3B0008EF5EC /* TagChartsViewInteractorOutput.swift */, - ); - path = Interactor; - sourceTree = ""; - }; - E18D04C228E9DF66008EF5EC /* View */ = { - isa = PBXGroup; - children = ( - E1E3C34729903EBA00A59CB8 /* UI */, - E18D04D028F1D027008EF5EC /* TagChartsViewInput.swift */, - E18D04D328F1D52A008EF5EC /* TagChartsViewOutput.swift */, - E1ED426828FF253B00302179 /* TagChartsViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - E191F2002969DE1F00F1FEA6 /* Assembly */ = { - isa = PBXGroup; - children = ( - E191F21A2969EF7B00F1FEA6 /* TagSettingsModuleFactory.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - E191F2022969DE3700F1FEA6 /* UI */ = { - isa = PBXGroup; - children = ( - E1CA28B62920378D009E4423 /* RUAlertDetailsCellChildView */, - E1CA28AC29201EF0009E4423 /* RUAlertExpandButton */, - 0E02ABB8237598B200ED4629 /* RangeSeekSlider */, - E191F1FA2969CD0100F1FEA6 /* TagSettingsBackgroundSelectionView.swift */, - E191F1F42968D32000F1FEA6 /* TagSettingsExpandableSectionHeader.swift */, - E191F1F72968D33800F1FEA6 /* TagSettingsSimpleSectionHeader.swift */, - E191F1EB2968BCF300F1FEA6 /* TagSettingsBasicCell.swift */, - E191F1FD2969D6C900F1FEA6 /* TagSettingsPlainCell.swift */, - E191F21D2969FF6900F1FEA6 /* TagSettingsSwitchCell.swift */, - E191F220296A00CE00F1FEA6 /* TagSettingsFooterCell.swift */, - E191F1F12968C2C900F1FEA6 /* TagSettingsAlertConfigCell.swift */, - E191F1E82968B6B100F1FEA6 /* TagSettingsViewController.swift */, - ); - path = UI; - sourceTree = ""; - }; - E191F2032969DE5700F1FEA6 /* Router */ = { - isa = PBXGroup; - children = ( - E191F2082969E11F00F1FEA6 /* TagSettingsRouterInput.swift */, - E191F20B2969E14600F1FEA6 /* TagSettingsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - E191F2042969DE5F00F1FEA6 /* Presenter */ = { - isa = PBXGroup; - children = ( - 0E3CA70B267365B1000D9B25 /* Debouncer.swift */, - E191F20E2969E1C300F1FEA6 /* TagSettingsPresenter.swift */, - E1E3C341299007B700A59CB8 /* TagSettingsModuleInput.swift */, - E1E3C344299007DE00A59CB8 /* TagSettingsModuleOutput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - E196914A2A059C7200DC360E /* Notifications */ = { - isa = PBXGroup; - children = ( - E196914E2A059CAD00DC360E /* Assembly */, - E196914D2A059C8D00DC360E /* Router */, - E196914C2A059C8800DC360E /* View */, - E196914B2A059C8000DC360E /* Presenter */, - E19691702A06E03300DC360E /* Selection */, - ); - path = Notifications; - sourceTree = ""; - }; - E196914B2A059C8000DC360E /* Presenter */ = { - isa = PBXGroup; - children = ( - E196916B2A06DCEF00DC360E /* NotificationsSettingsModuleInput.swift */, - E196916A2A06DCEF00DC360E /* NotificationsSettingsPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - E196914C2A059C8800DC360E /* View */ = { - isa = PBXGroup; - children = ( - E19691612A06DCE500DC360E /* NotificationsSettingsViewInput.swift */, - E19691622A06DCE500DC360E /* NotificationsSettingsViewModel.swift */, - E19691632A06DCE500DC360E /* NotificationsSettingsViewOutput.swift */, - E1BCF0B52A06390A005729F4 /* UI */, - ); - path = View; - sourceTree = ""; - }; - E196914D2A059C8D00DC360E /* Router */ = { - isa = PBXGroup; - children = ( - E19691532A06DCBB00DC360E /* NotificationsSettingsRouter.swift */, - E19691522A06DCBB00DC360E /* NotificationsSettingsRouterInput.swift */, - ); - path = Router; - sourceTree = ""; - }; - E196914E2A059CAD00DC360E /* Assembly */ = { - isa = PBXGroup; - children = ( - E196914F2A06DCA400DC360E /* NotificationsSettingsModuleFactory.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - E19691702A06E03300DC360E /* Selection */ = { - isa = PBXGroup; - children = ( - E19691712A06E03300DC360E /* Assembly */, - E19691732A06E03300DC360E /* Presenter */, - E19691762A06E03300DC360E /* View */, - ); - path = Selection; - sourceTree = ""; - }; - E19691712A06E03300DC360E /* Assembly */ = { - isa = PBXGroup; - children = ( - E19691722A06E03300DC360E /* PushAlertSoundSelectionModuleFactory.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - E19691732A06E03300DC360E /* Presenter */ = { - isa = PBXGroup; - children = ( - E19691742A06E03300DC360E /* PushAlertSoundSelectionPresenter.swift */, - E19691752A06E03300DC360E /* PushAlertSoundSelectionModuleInput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - E19691762A06E03300DC360E /* View */ = { - isa = PBXGroup; - children = ( - E19691772A06E03300DC360E /* UI */, - E196917A2A06E03300DC360E /* PushAlertSoundSelectionViewInput.swift */, - E196917B2A06E03300DC360E /* PushAlertSoundSelectionViewOutput.swift */, - E196918A2A06E15F00DC360E /* PushAlertSoundSelectionViewModel.swift */, - ); - path = View; - sourceTree = ""; - }; - E19691772A06E03300DC360E /* UI */ = { - isa = PBXGroup; - children = ( - E19691782A06E03300DC360E /* PushAlertSoundSelectionTableViewController.swift */, - E19691792A06E03300DC360E /* PushAlertSoundSelectionTableViewCell.swift */, - ); - path = UI; - sourceTree = ""; - }; - E19EAF81299C1310005827E4 /* UI */ = { - isa = PBXGroup; - children = ( - 3414BFC62806D0EE00C63BE9 /* Helper */, - E19EAF6829997711005827E4 /* SignInViewController.swift */, - ); - path = UI; - sourceTree = ""; - }; - E19EAF8E299E5F84005827E4 /* Submodules */ = { - isa = PBXGroup; - children = ( - E19EAF8F299E5FE6005827E4 /* Sign In Benefits */, - ); - path = Submodules; - sourceTree = ""; - }; - E19EAF8F299E5FE6005827E4 /* Sign In Benefits */ = { - isa = PBXGroup; - children = ( - E19EAF9C299E60FD005827E4 /* Presenter */, - E19EAF92299E601F005827E4 /* View */, - E19EAF91299E6019005827E4 /* Router */, - E19EAF90299E6013005827E4 /* Assembly */, - ); - path = "Sign In Benefits"; - sourceTree = ""; - }; - E19EAF90299E6013005827E4 /* Assembly */ = { - isa = PBXGroup; - children = ( - E19EAF93299E6038005827E4 /* SignInBenefitsModuleFactory.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - E19EAF91299E6019005827E4 /* Router */ = { - isa = PBXGroup; - children = ( - E19EAF96299E6083005827E4 /* SignInBenefitsRouterInput.swift */, - E19EAF99299E608E005827E4 /* SignInBenefitsRouter.swift */, - ); - path = Router; - sourceTree = ""; - }; - E19EAF92299E601F005827E4 /* View */ = { - isa = PBXGroup; - children = ( - E19EAF7A299BF94C005827E4 /* SignInBenefitsViewController.swift */, - E19EAFA6299E62A7005827E4 /* SignInBenefitsViewInput.swift */, - E19EAFA9299E62C0005827E4 /* SignInBenefitsViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - E19EAF9C299E60FD005827E4 /* Presenter */ = { - isa = PBXGroup; - children = ( - E19EAF9D299E610A005827E4 /* SignInBenefitsPresenter.swift */, - E19EAFA0299E61C5005827E4 /* SignInBenefitsModuleInput.swift */, - E19EAFA3299E6211005827E4 /* SignInBenefitsModuleOutput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - E1AB90572A0EAF4F00543F61 /* Force Claim */ = { - isa = PBXGroup; - children = ( - E1AB905C2A0EAFA600543F61 /* Router */, - E1AB905A2A0EAF9400543F61 /* View */, - E1AB90592A0EAF8900543F61 /* Presenter */, - E1AB90582A0EAF8200543F61 /* Assembly */, - ); - path = "Force Claim"; - sourceTree = ""; - }; - E1AB90582A0EAF8200543F61 /* Assembly */ = { - isa = PBXGroup; - children = ( - E1AB905D2A0EB0D000543F61 /* SensorForceClaimModuleFactory.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - E1AB90592A0EAF8900543F61 /* Presenter */ = { - isa = PBXGroup; - children = ( - E1AB90602A0EB11800543F61 /* SensorForceClaimPresenter.swift */, - E1AB90632A0EB13400543F61 /* SensorForceClaimModuleInput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - E1AB905A2A0EAF9400543F61 /* View */ = { - isa = PBXGroup; - children = ( - E1AB90792A0EB26900543F61 /* UI */, - E1AB907A2A0ECB6D00543F61 /* SensorForceClaimViewOutput.swift */, - E1AB907D2A0ECB7600543F61 /* SensorForceClaimViewInput.swift */, - ); - path = View; - sourceTree = ""; - }; - E1AB905C2A0EAFA600543F61 /* Router */ = { - isa = PBXGroup; - children = ( - E1AB90662A0EB1AD00543F61 /* SensorForceClaimRouter.swift */, - E1AB90692A0EB1BC00543F61 /* SensorForceClaimRouterInput.swift */, - ); - path = Router; - sourceTree = ""; - }; - E1AB90792A0EB26900543F61 /* UI */ = { - isa = PBXGroup; - children = ( - E1AB90722A0EB24600543F61 /* SensorForceClaimViewController.swift */, - ); - path = UI; - sourceTree = ""; - }; - E1B57FE629859C7000B441FB /* Devices */ = { - isa = PBXGroup; - children = ( - E1B57FE729859C8D00B441FB /* Assembly */, - E1B57FE829859C9500B441FB /* Presenter */, - E1B5800329859E7900B441FB /* Interactor */, - E1B57FE929859C9E00B441FB /* View */, - ); - path = Devices; - sourceTree = ""; - }; - E1B57FE729859C8D00B441FB /* Assembly */ = { - isa = PBXGroup; - children = ( - E1B57FEA29859CB800B441FB /* DevicesModuleFactory.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - E1B57FE829859C9500B441FB /* Presenter */ = { - isa = PBXGroup; - children = ( - E1B57FED29859CC900B441FB /* DevicesModuleInput.swift */, - E1B57FF029859CD400B441FB /* DevicesPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - E1B57FE929859C9E00B441FB /* View */ = { - isa = PBXGroup; - children = ( - E1B57FF929859CF100B441FB /* UI */, - E1B57FFA29859D0700B441FB /* DevicesViewModel.swift */, - E1B57FFD29859D1800B441FB /* DevicesViewInput.swift */, - E1B5800029859D2300B441FB /* DevicesViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - E1B57FF929859CF100B441FB /* UI */ = { - isa = PBXGroup; - children = ( - E1B57FF329859CE200B441FB /* DevicesTableViewController.swift */, - E1B57FF629859CEC00B441FB /* DevicesTableViewCell.swift */, - ); - path = UI; - sourceTree = ""; - }; - E1B5800329859E7900B441FB /* Interactor */ = { - isa = PBXGroup; - children = ( - E1B5800429859E8900B441FB /* DevicesInteractor.swift */, - E1B5800729859EDE00B441FB /* DevicesInteractorInput.swift */, - E1B5800A29859EEB00B441FB /* DevicesInteractorOutput.swift */, - ); - path = Interactor; - sourceTree = ""; - }; - E1B7B51E2AE9888C009D747E /* Removal */ = { - isa = PBXGroup; - children = ( - E1B7B5222AE989C6009D747E /* Assembly */, - E1B7B5212AE989BD009D747E /* Presenter */, - E1B7B5202AE989B7009D747E /* View */, - E1B7B51F2AE989AF009D747E /* Router */, - ); - path = Removal; - sourceTree = ""; - }; - E1B7B51F2AE989AF009D747E /* Router */ = { - isa = PBXGroup; - children = ( - E1B7B5302AE98B00009D747E /* SensorRemovalRouter.swift */, - E1B7B5332AE98B16009D747E /* SensorRemovalRouterInput.swift */, - ); - path = Router; - sourceTree = ""; - }; - E1B7B5202AE989B7009D747E /* View */ = { - isa = PBXGroup; - children = ( - E1B7B5262AE98A2E009D747E /* UI */, - E1B7B52A2AE98A9F009D747E /* SensorRemovalViewOutput.swift */, - E1B7B52D2AE98AC4009D747E /* SensorRemovalViewInput.swift */, - ); - path = View; - sourceTree = ""; - }; - E1B7B5212AE989BD009D747E /* Presenter */ = { - isa = PBXGroup; - children = ( - E1B7B5362AE98B72009D747E /* SensorRemovalModuleInput.swift */, - E1B7B53E2AEAD61A009D747E /* SensorRemovalModuleOutput.swift */, - E1B7B5392AE98B86009D747E /* SensorRemovalPresenter.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - E1B7B5222AE989C6009D747E /* Assembly */ = { - isa = PBXGroup; - children = ( - E1B7B5232AE989ED009D747E /* SensorRemovalModuleFactory.swift */, - ); - path = Assembly; - sourceTree = ""; - }; - E1B7B5262AE98A2E009D747E /* UI */ = { - isa = PBXGroup; - children = ( - E1B7B5272AE98A37009D747E /* SensorRemovalViewController.swift */, - ); - path = UI; - sourceTree = ""; - }; - E1BCF0B52A06390A005729F4 /* UI */ = { - isa = PBXGroup; - children = ( - E196915A2A06DCD500DC360E /* NotificationsSettingsSwitchCell.swift */, - E19691582A06DCD400DC360E /* NotificationsSettingsTableViewController.swift */, - E19691592A06DCD500DC360E /* NotificationsSettingsTextCell.swift */, - ); - path = UI; - sourceTree = ""; - }; - E1CA28AC29201EF0009E4423 /* RUAlertExpandButton */ = { - isa = PBXGroup; - children = ( - E1CA28AD29201F34009E4423 /* RUAlertExpandButton.swift */, - ); - path = RUAlertExpandButton; - sourceTree = ""; - }; - E1CA28B62920378D009E4423 /* RUAlertDetailsCellChildView */ = { - isa = PBXGroup; - children = ( - E1CA28B7292037E4009E4423 /* RUAlertDetailsCellChildView.swift */, - ); - path = RUAlertDetailsCellChildView; - sourceTree = ""; - }; - E1CD77E52878199600F1F0EB /* Unit Settings */ = { - isa = PBXGroup; - children = ( - E1CD780A287830A300F1F0EB /* Router */, - E1CD78062878307500F1F0EB /* Model */, - E1CD77F628782F1100F1F0EB /* Presenter */, - E1CD77EE28782BAE00F1F0EB /* Assembly */, - E1CD77E92878271400F1F0EB /* View */, - E1CD77E628781A0E00F1F0EB /* UnitSettings.storyboard */, - ); - path = "Unit Settings"; - sourceTree = ""; - }; - E1CD77E92878271400F1F0EB /* View */ = { - isa = PBXGroup; - children = ( - E1CD77EA2878271900F1F0EB /* Table */, - E1CD78002878302100F1F0EB /* UnitSettingsViewInput.swift */, - E1CD78032878302C00F1F0EB /* UnitSettingsViewOutput.swift */, - ); - path = View; - sourceTree = ""; - }; - E1CD77EA2878271900F1F0EB /* Table */ = { - isa = PBXGroup; - children = ( - E1CD77EB2878273500F1F0EB /* UnitSettingsTableViewController.swift */, - E1CD78112878379C00F1F0EB /* UnitSettingsTableViewCell.swift */, - ); - path = Table; - sourceTree = ""; - }; - E1CD77EE28782BAE00F1F0EB /* Assembly */ = { - isa = PBXGroup; - children = ( - E1CD77EF28782BB800F1F0EB /* Table */, - ); - path = Assembly; - sourceTree = ""; - }; - E1CD77EF28782BB800F1F0EB /* Table */ = { - isa = PBXGroup; - children = ( - E1CD77F028782E8000F1F0EB /* UnitSettingsTableConfigurator.swift */, - E1CD77F328782EA500F1F0EB /* UnitSettingsTableInitializer.swift */, - ); - path = Table; - sourceTree = ""; - }; - E1CD77F628782F1100F1F0EB /* Presenter */ = { - isa = PBXGroup; - children = ( - E1CD77F728782F2200F1F0EB /* UnitSettingsPresenter.swift */, - E1CD77FA28782F7100F1F0EB /* UnitSettingsModuleInput.swift */, - E1CD77FD28782F9900F1F0EB /* UnitSettingsModuleOutput.swift */, - ); - path = Presenter; - sourceTree = ""; - }; - E1CD78062878307500F1F0EB /* Model */ = { - isa = PBXGroup; - children = ( - E1CD78072878308E00F1F0EB /* UnitSettingsItem.swift */, - ); - path = Model; - sourceTree = ""; - }; - E1CD780A287830A300F1F0EB /* Router */ = { - isa = PBXGroup; - children = ( - E1CD780B287830B100F1F0EB /* UnitSettingsRouter.swift */, - E1CD780E287830BF00F1F0EB /* UnitSettingsRouterInput.swift */, - ); - path = Router; - sourceTree = ""; - }; - E1CE4C6E2959CC2B005C023F /* Home */ = { - isa = PBXGroup; - children = ( - E1597A36295CD39A00DFB70B /* Assembly */, - E1597A38295CD3B000DFB70B /* Router */, - E1597A37295CD3A200DFB70B /* Presenter */, - E1597A35295CD39000DFB70B /* Interactor */, - E1CE4C6F2959CE50005C023F /* View */, - ); - path = Home; - sourceTree = ""; - }; - E1CE4C6F2959CE50005C023F /* View */ = { - isa = PBXGroup; - children = ( - E1CE4C702959CE61005C023F /* DashboardViewController.swift */, - E11FDA6F29A3F78D003ADA7B /* RuuviSimpleViewCompositionalLayout.swift */, - E19EAFAF299EB46D005827E4 /* NoSensorView.swift */, - E1B5800D2986AE0800B441FB /* RuuviContextMenuButton.swift */, - E1CE4C732959D08D005C023F /* DashboardImageCell.swift */, - E1597A2F295B909B00DFB70B /* DashboardPlainCell.swift */, - E1CE4C762959DF01005C023F /* DashboardIndicatorView.swift */, - E1597A32295CC4F900DFB70B /* LowBatteryView.swift */, - E1597A51295CD6BB00DFB70B /* DashboardViewInput.swift */, - E1597A54295CD6E300DFB70B /* DashboardViewOutput.swift */, - E1597A672960944600DFB70B /* DashboardCellDelegate.swift */, - ); - path = View; - sourceTree = ""; - }; - E1E102EC28F348A700815508 /* Helpers */ = { - isa = PBXGroup; - children = ( - E1ED426D28FF261D00302179 /* CustomXAxisRenderer.swift */, - E1ED426C28FF261D00302179 /* XAxisValueFormatter.swift */, - E1ED426B28FF261D00302179 /* CustomYAxisRenderer.swift */, - E1D0238D29EB3F7D00EC0FFD /* YAxisValueFormatter.swift */, - E1E102ED28F348B700815508 /* TagChartsHelper.swift */, - ); - path = Helpers; - sourceTree = ""; - }; - E1E3C34729903EBA00A59CB8 /* UI */ = { - isa = PBXGroup; - children = ( - E18FD50928DF7B7900289359 /* TagChartsViewController.swift */, - E18D04C328E9DF77008EF5EC /* TagChartsView.swift */, - E10E18C3297DE3AF002C78C3 /* TagChartsMarkerView.swift */, - ); - path = UI; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 0E8BD2AC238566AB008B31EF /* station_dev */ = { - isa = PBXNativeTarget; - buildConfigurationList = 0E8BD401238566AB008B31EF /* Build configuration list for PBXNativeTarget "station_dev" */; - buildPhases = ( - E863D26396BB0C54CBE4A62E /* [CP] Check Pods Manifest.lock */, - A96B1EF925A7208900D3ED9C /* SwiftGen */, - 0E8BD2AE238566AB008B31EF /* Sources */, - 0E8BD3DC238566AB008B31EF /* Frameworks */, - 0E8BD3DE238566AB008B31EF /* Resources */, - A9AB575A2413CCEC006FD3D2 /* Fetch secrets */, - 0E8301592393FC2B0003F2EF /* Swiftlint */, - A97B187EBF9FA48C611A8416 /* [CP] Embed Pods Frameworks */, - 34A8D49A281EBFDB008A8698 /* Embed Foundation Extensions */, - ); - buildRules = ( - ); - dependencies = ( - 34A8D498281EBFDB008A8698 /* PBXTargetDependency */, - 34A8D4BD281EE5AE008A8698 /* PBXTargetDependency */, - E17C469F29956732008CFDD7 /* PBXTargetDependency */, - ); - name = station_dev; - packageProductDependencies = ( - 0EE36EB0269DC71B0021B746 /* Algorithms */, - 0EE36EB5269DC7E40021B746 /* Charts */, - ); - productName = station; - productReference = 0E8BD404238566AB008B31EF /* station_dev.app */; - productType = "com.apple.product-type.application"; - }; - 34A8D488281EBFD9008A8698 /* station_widgets */ = { - isa = PBXNativeTarget; - buildConfigurationList = 34A8D49D281EBFDB008A8698 /* Build configuration list for PBXNativeTarget "station_widgets" */; - buildPhases = ( - 617DFCDC39B3A39446D538AB /* [CP] Check Pods Manifest.lock */, - 34A8D485281EBFD9008A8698 /* Sources */, - 34A8D486281EBFD9008A8698 /* Frameworks */, - 34A8D487281EBFD9008A8698 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = station_widgets; - productName = "ruuvi-widgetsExtension"; - productReference = 34A8D489281EBFD9008A8698 /* station_widgets.appex */; - productType = "com.apple.product-type.app-extension"; - }; - 34A8D4B4281EE5AE008A8698 /* station_intents */ = { - isa = PBXNativeTarget; - buildConfigurationList = 34A8D4BF281EE5AF008A8698 /* Build configuration list for PBXNativeTarget "station_intents" */; - buildPhases = ( - 067E08286183586536130F33 /* [CP] Check Pods Manifest.lock */, - 34A8D4B1281EE5AE008A8698 /* Sources */, - 34A8D4B2281EE5AE008A8698 /* Frameworks */, - 34A8D4B3281EE5AE008A8698 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = station_intents; - productName = intents; - productReference = 34A8D4B5281EE5AE008A8698 /* station_intents.appex */; - productType = "com.apple.product-type.app-extension"; - }; - 64333D2420B0C45900CDF4B6 /* station */ = { - isa = PBXNativeTarget; - buildConfigurationList = 64333D4D20B0C45B00CDF4B6 /* Build configuration list for PBXNativeTarget "station" */; - buildPhases = ( - 3B795AA21A4595A8AEAE7172 /* [CP] Check Pods Manifest.lock */, - 31884FB625C7442E002BC63F /* SwiftGen */, - 64333D2120B0C45900CDF4B6 /* Sources */, - 64333D2220B0C45900CDF4B6 /* Frameworks */, - 64333D2320B0C45900CDF4B6 /* Resources */, - 60666212F80D3A3EAC265637 /* [CP] Embed Pods Frameworks */, - 34D458E82821A06E00EA9F93 /* Embed Foundation Extensions */, - A986147C248CD47A0030F197 /* Crashlytics */, - A9AB57592413CCAB006FD3D2 /* Fetch secrets */, - ); - buildRules = ( - ); - dependencies = ( - 34D458EB2821A07600EA9F93 /* PBXTargetDependency */, - 34D458E72821A06E00EA9F93 /* PBXTargetDependency */, - E196D5B12B0137A100B60A90 /* PBXTargetDependency */, - ); - name = station; - packageProductDependencies = ( - 0EE36EAE269DC70E0021B746 /* Algorithms */, - 0EE36EB3269DC7D90021B746 /* Charts */, - ); - productName = station; - productReference = 64333D2520B0C45900CDF4B6 /* station.app */; - productType = "com.apple.product-type.application"; - }; - 64333D3820B0C45A00CDF4B6 /* stationTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 64333D5020B0C45B00CDF4B6 /* Build configuration list for PBXNativeTarget "stationTests" */; - buildPhases = ( - E237490C592528A732D4EB7D /* [CP] Check Pods Manifest.lock */, - 64333D3520B0C45A00CDF4B6 /* Sources */, - 64333D3620B0C45A00CDF4B6 /* Frameworks */, - 64333D3720B0C45A00CDF4B6 /* Resources */, - B2718B0350BA2A18235E5F63 /* [CP] Embed Pods Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 64333D3B20B0C45A00CDF4B6 /* PBXTargetDependency */, - ); - name = stationTests; - productName = stationTests; - productReference = 64333D3920B0C45A00CDF4B6 /* stationTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 64333D4320B0C45B00CDF4B6 /* stationUITests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 64333D5320B0C45B00CDF4B6 /* Build configuration list for PBXNativeTarget "stationUITests" */; - buildPhases = ( - 64333D4020B0C45B00CDF4B6 /* Sources */, - 64333D4120B0C45B00CDF4B6 /* Frameworks */, - 64333D4220B0C45B00CDF4B6 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 64333D4620B0C45B00CDF4B6 /* PBXTargetDependency */, - ); - name = stationUITests; - productName = stationUITests; - productReference = 64333D4420B0C45B00CDF4B6 /* stationUITests.xctest */; - productType = "com.apple.product-type.bundle.ui-testing"; - }; - E17C469829956732008CFDD7 /* pnservice */ = { - isa = PBXNativeTarget; - buildConfigurationList = E17C46A329956732008CFDD7 /* Build configuration list for PBXNativeTarget "pnservice" */; - buildPhases = ( - E17C469529956732008CFDD7 /* Sources */, - E17C469629956732008CFDD7 /* Frameworks */, - E17C469729956732008CFDD7 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = pnservice; - productName = pnservice; - productReference = E17C469929956732008CFDD7 /* pnservice.appex */; - productType = "com.apple.product-type.app-extension"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 64333D1D20B0C45900CDF4B6 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 1420; - LastUpgradeCheck = 1410; - ORGANIZATIONNAME = "Ruuvi Innovations Oy"; - TargetAttributes = { - 34A8D488281EBFD9008A8698 = { - CreatedOnToolsVersion = 13.3.1; - }; - 34A8D4B4281EE5AE008A8698 = { - CreatedOnToolsVersion = 13.3.1; - }; - 64333D2420B0C45900CDF4B6 = { - CreatedOnToolsVersion = 9.3.1; - SystemCapabilities = { - com.apple.Push = { - enabled = 1; - }; - }; - }; - 64333D3820B0C45A00CDF4B6 = { - CreatedOnToolsVersion = 9.3.1; - TestTargetID = 64333D2420B0C45900CDF4B6; - }; - 64333D4320B0C45B00CDF4B6 = { - CreatedOnToolsVersion = 9.3.1; - LastSwiftMigration = 1130; - TestTargetID = 64333D2420B0C45900CDF4B6; - }; - E17C469829956732008CFDD7 = { - CreatedOnToolsVersion = 14.2; - }; - }; - }; - buildConfigurationList = 64333D2020B0C45900CDF4B6 /* Build configuration list for PBXProject "station" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ru, - fi, - sv, - fr, - de, - ); - mainGroup = 64333D1C20B0C45900CDF4B6; - packageReferences = ( - 0EE36EAD269DC70E0021B746 /* XCRemoteSwiftPackageReference "swift-algorithms" */, - 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts" */, - ); - productRefGroup = 64333D2620B0C45900CDF4B6 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 64333D2420B0C45900CDF4B6 /* station */, - 0E8BD2AC238566AB008B31EF /* station_dev */, - 64333D3820B0C45A00CDF4B6 /* stationTests */, - 64333D4320B0C45B00CDF4B6 /* stationUITests */, - 34A8D488281EBFD9008A8698 /* station_widgets */, - 34A8D4B4281EE5AE008A8698 /* station_intents */, - E17C469829956732008CFDD7 /* pnservice */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 0E8BD3DE238566AB008B31EF /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 0E8BD3DF238566AB008B31EF /* Montserrat-Regular.ttf in Resources */, - 0E8BD3E0238566AB008B31EF /* About.storyboard in Resources */, - 0E8BD3E1238566AB008B31EF /* GoogleService-Info.plist in Resources */, - 0E197C7023C4A7D00074015B /* Presentation.plist in Resources */, - 66BC44962657AED400A03253 /* OffsetCorrection.storyboard in Resources */, - 0E8BD3E3238566AB008B31EF /* Networking.plist in Resources */, - 340BE39F27B56129006D6C34 /* ruuvi_logo_splash.png in Resources */, - 0E8BD3E6238566AB008B31EF /* Defaults.storyboard in Resources */, - 0E8BD3E8238566AB008B31EF /* LaunchScreen.storyboard in Resources */, - 0E8BD3EA238566AB008B31EF /* Oswald-Bold.ttf in Resources */, - E11FDA6B29A1757C003ADA7B /* splash_bg_layer_dark.jpg in Resources */, - E16B8F3D28D109DD0025B92D /* MyRuuvi.storyboard in Resources */, - E19EAF5C2996CF38005827E4 /* Muli-SemiBoldItalic.ttf in Resources */, - 0E8BD3EB238566AB008B31EF /* Localizable.strings in Resources */, - E1CD77E828781A0E00F1F0EB /* UnitSettings.storyboard in Resources */, - E116AED32A059578003EF65A /* ruuvi_speak.caf in Resources */, - 0E8BD3EF238566AB008B31EF /* Muli-Regular.ttf in Resources */, - E19EAF542996C828005827E4 /* Montserrat-ExtraBold.ttf in Resources */, - 0E8BD3F0238566AB008B31EF /* Oswald-ExtraLight.ttf in Resources */, - 340BE38727B54F37006D6C34 /* Owner.storyboard in Resources */, - 0EAD33D72399273D00EC5BAA /* Heartbeat.storyboard in Resources */, - 0E8BD3F3238566AB008B31EF /* InfoPlist.strings in Resources */, - A9E5994125572CF700F9E5CC /* Share.storyboard in Resources */, - 0E8BD3F5238566AB008B31EF /* Assets.xcassets in Resources */, - A91D030E251121C800694733 /* Selection.storyboard in Resources */, - 0E8BD3F8238566AB008B31EF /* Menu.storyboard in Resources */, - A964648F247BAEBA0001D55D /* ChartSettings.storyboard in Resources */, - 0E8BD3FA238566AB008B31EF /* Settings.storyboard in Resources */, - 0EB8ED442692005900C6B0FA /* Colors.xcassets in Resources */, - 0EB48DE7261A1816008E0D2D /* FeatureToggles.json in Resources */, - 0E8BD3FB238566AB008B31EF /* Muli-Bold.ttf in Resources */, - 0E197C8223C5CDBE0074015B /* iOSDeviceModelMapping.plist in Resources */, - 0E8BD3FD238566AB008B31EF /* Montserrat-Bold.ttf in Resources */, - E1BAC13B2A7598F000EA820E /* Muli-ExtraBold.ttf in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 34A8D487281EBFD9008A8698 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 34A8D4AA281ED046008A8698 /* Montserrat-Regular.ttf in Resources */, - 34A8D4AD281ED046008A8698 /* Oswald-Bold.ttf in Resources */, - 34A8D4AE281ED046008A8698 /* Oswald-ExtraLight.ttf in Resources */, - 34A8D493281EBFDB008A8698 /* Assets.xcassets in Resources */, - 34A8D4AC281ED046008A8698 /* Muli-Regular.ttf in Resources */, - 3493385B282FAB0D009060E8 /* Localizable.strings in Resources */, - 34A8D4AF281ED046008A8698 /* Muli-Bold.ttf in Resources */, - 34A8D4AB281ED046008A8698 /* Montserrat-Bold.ttf in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 34A8D4B3281EE5AE008A8698 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 34F266A52832489900AE79D9 /* Localizable.strings in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D2320B0C45900CDF4B6 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 6486971220E0439200CCD7C1 /* Montserrat-Regular.ttf in Resources */, - 0EEB20EF22B7D1580015F9E0 /* About.storyboard in Resources */, - 0ECDF1B52313D65500A09ACA /* GoogleService-Info.plist in Resources */, - 0E197C6F23C4A7D00074015B /* Presentation.plist in Resources */, - 66BC44952657AED400A03253 /* OffsetCorrection.storyboard in Resources */, - 0E9F97B522EC44930015ADE2 /* Networking.plist in Resources */, - 340BE39E27B56129006D6C34 /* ruuvi_logo_splash.png in Resources */, - 0E8A100223845E5100A9CBA6 /* Defaults.storyboard in Resources */, - 64333D3320B0C45A00CDF4B6 /* LaunchScreen.storyboard in Resources */, - 6486971020E0436A00CCD7C1 /* Oswald-Bold.ttf in Resources */, - E11FDA6A29A1757C003ADA7B /* splash_bg_layer_dark.jpg in Resources */, - E16B8F3C28D109DD0025B92D /* MyRuuvi.storyboard in Resources */, - E19EAF5B2996CF38005827E4 /* Muli-SemiBoldItalic.ttf in Resources */, - 0EEB20C722B7A7200015F9E0 /* Localizable.strings in Resources */, - E1CD77E728781A0E00F1F0EB /* UnitSettings.storyboard in Resources */, - E116AED22A059578003EF65A /* ruuvi_speak.caf in Resources */, - 64678192225D03330072856A /* Muli-Regular.ttf in Resources */, - E19EAF532996C828005827E4 /* Montserrat-ExtraBold.ttf in Resources */, - 643EEC2B2266435100D4E837 /* Oswald-ExtraLight.ttf in Resources */, - 340BE38627B54F37006D6C34 /* Owner.storyboard in Resources */, - 0E53A3F1232DFC6200ACED49 /* InfoPlist.strings in Resources */, - 0E84BF552397F29800A37E1A /* Heartbeat.storyboard in Resources */, - A9E5994025572CF700F9E5CC /* Share.storyboard in Resources */, - 64333D3020B0C45A00CDF4B6 /* Assets.xcassets in Resources */, - A91D030D251121C800694733 /* Selection.storyboard in Resources */, - 0E1C1DF122B3FDE30032F6CA /* Menu.storyboard in Resources */, - A964648E247BAEBA0001D55D /* ChartSettings.storyboard in Resources */, - 0EEB20D122B7C6F30015F9E0 /* Settings.storyboard in Resources */, - 0EB8ED432692005900C6B0FA /* Colors.xcassets in Resources */, - 0EB48DE6261A1816008E0D2D /* FeatureToggles.json in Resources */, - 64678191225D03300072856A /* Muli-Bold.ttf in Resources */, - 0E197C8123C5CDBE0074015B /* iOSDeviceModelMapping.plist in Resources */, - 643C651F21C38F490037BE5B /* Montserrat-Bold.ttf in Resources */, - E1BAC13A2A7598F000EA820E /* Muli-ExtraBold.ttf in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D3720B0C45A00CDF4B6 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D4220B0C45B00CDF4B6 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E17C469729956732008CFDD7 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E17C46A429957763008CFDD7 /* Localizable.strings in Resources */, - E116AED42A059578003EF65A /* ruuvi_speak.caf in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 067E08286183586536130F33 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-station_intents-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 0E8301592393FC2B0003F2EF /* Swiftlint */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = Swiftlint; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\nif which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; - }; - 31884FB625C7442E002BC63F /* SwiftGen */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = SwiftGen; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "if [[ -f \"${PODS_ROOT}/SwiftGen/bin/swiftgen\" ]]; then\n \"${PODS_ROOT}/SwiftGen/bin/swiftgen\"\nelse\n echo \"warning: SwiftGen is not installed. Run 'pod install --repo-update' to install it.\"\nfi\n"; - }; - 3B795AA21A4595A8AEAE7172 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-station-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - 60666212F80D3A3EAC265637 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-station/Pods-station-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 617DFCDC39B3A39446D538AB /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-station_widgets-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - A96B1EF925A7208900D3ED9C /* SwiftGen */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - name = SwiftGen; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "if [[ -f \"${PODS_ROOT}/SwiftGen/bin/swiftgen\" ]]; then\n \"${PODS_ROOT}/SwiftGen/bin/swiftgen\"\nelse\n echo \"warning: SwiftGen is not installed. Run 'pod install --repo-update' to install it.\"\nfi\n"; - }; - A97B187EBF9FA48C611A8416 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-station_dev/Pods-station_dev-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - A986147C248CD47A0030F197 /* Crashlytics */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}", - "$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", - ); - name = Crashlytics; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/FirebaseCrashlytics/run\"\n"; - }; - A9AB57592413CCAB006FD3D2 /* Fetch secrets */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(SRCROOT)/station/Classes/Networking/Assembly/Networking.plist", - "$(SRCROOT)/station/Resources/Plists/GoogleService-Info.plist", - ); - name = "Fetch secrets"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "BUILD_APP_DIR=${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}\ngit clone git@github.com:ruuvi/com.ruuvi.station.ios.keystore.git\nif [ $? -eq 0 ]; then\n /bin/cp -rf com.ruuvi.station.ios.keystore/GoogleService-Info.plist \"$BUILD_APP_DIR/GoogleService-Info.plist\"\n /bin/cp -rf com.ruuvi.station.ios.keystore/Networking.plist \"$BUILD_APP_DIR/Networking.plist\"\n rm -rf com.ruuvi.station.ios.keystore\nelse\n if grep -q \"{ set your API key here }\" $SCRIPT_INPUT_FILE_0; then\n echo \"warning: Missing OpenWeatherMap API key. In order to make Virtual Sensors work please obtain API key on https://openweathermap.org and put into station/Classes/Networking/Assembly/Networking.plist\"\n fi\n if grep -q \"1:925543306936:ios:84f5fda343c52e7671c64d\" $SCRIPT_INPUT_FILE_1; then\n echo \"warning: Demo GoogleServices credentials. If you want to use your own GoogleServices credentials, please replace the station/Resources/Plists/GoogleService-Info.plist file\"\n fi\nfi\n"; - }; - A9AB575A2413CCEC006FD3D2 /* Fetch secrets */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 12; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(SRCROOT)/station/Classes/Networking/Assembly/Networking.plist", - "$(SRCROOT)/station/Resources/Plists/GoogleService-Info.plist", - ); - name = "Fetch secrets"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "BUILD_APP_DIR=${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}\ngit clone git@github.com:ruuvi/com.ruuvi.station.ios.keystore.git\nif [ $? -eq 0 ]; then\n /bin/cp -rf com.ruuvi.station.ios.keystore/GoogleService-Info.plist \"$BUILD_APP_DIR/GoogleService-Info.plist\"\n /bin/cp -rf com.ruuvi.station.ios.keystore/Networking.plist \"$BUILD_APP_DIR/Networking.plist\"\n rm -rf com.ruuvi.station.ios.keystore\nelse\n if grep -q \"{ set your API key here }\" $SCRIPT_INPUT_FILE_0; then\n echo \"warning: Missing OpenWeatherMap API key. In order to make Virtual Sensors work please obtain API key on https://openweathermap.org and put into station/Classes/Networking/Assembly/Networking.plist\"\n fi\n if grep -q \"1:925543306936:ios:84f5fda343c52e7671c64d\" $SCRIPT_INPUT_FILE_1; then\n echo \"warning: Demo GoogleServices credentials. If you want to use your own GoogleServices credentials, please replace the station/Resources/Plists/GoogleService-Info.plist file\"\n fi\nfi\n"; - }; - B2718B0350BA2A18235E5F63 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-stationTests/Pods-stationTests-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - E237490C592528A732D4EB7D /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-stationTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - E863D26396BB0C54CBE4A62E /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-station_dev-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 0E8BD2AE238566AB008B31EF /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 0EE36E4326957E200021B746 /* LatestRelease.swift in Sources */, - 0E8BD2B3238566AB008B31EF /* Optional.swift in Sources */, - 0EA7968A2664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift in Sources */, - E1AB90742A0EB24600543F61 /* SensorForceClaimViewController.swift in Sources */, - E1AB905F2A0EB0D000543F61 /* SensorForceClaimModuleFactory.swift in Sources */, - 0E8BD2B8238566AB008B31EF /* CALayer+IB.swift in Sources */, - 0E8BD2BA238566AB008B31EF /* MenuTablePresentationController.swift in Sources */, - E1972BE229587615000E2AEC /* CardsLargeImageCell.swift in Sources */, - E16B8F5528D113750025B92D /* MyRuuviAccountPresenter.swift in Sources */, - 0E8BD2BD238566AB008B31EF /* TagSettingsViewInput.swift in Sources */, - 0EAD33DE2399273D00EC5BAA /* HeartbeatList.swift in Sources */, - E191F1FC2969CD0100F1FEA6 /* TagSettingsBackgroundSelectionView.swift in Sources */, - 0E8BD2BE238566AB008B31EF /* DefaultsViewOutput.swift in Sources */, - E18D04B028E8A747008EF5EC /* TagChartsViewModuleOutput.swift in Sources */, - E1597A44295CD58600DFB70B /* DashboardRouterDelegate.swift in Sources */, - E10E18B8297D67E8002C78C3 /* RuuviCloudViewInput.swift in Sources */, - E16B8F4028D10CF50025B92D /* MyRuuviAccountViewController.swift in Sources */, - E1CE5E482A016D4000391109 /* RuuviCustomButton.swift in Sources */, - 0E8BD2BF238566AB008B31EF /* MenuPresenter.swift in Sources */, - E16B8F4328D10DF90025B92D /* MyRuuviAccountViewInput.swift in Sources */, - 340BE39327B54F37006D6C34 /* OwnerViewController.swift in Sources */, - E1AB906B2A0EB1BC00543F61 /* SensorForceClaimRouterInput.swift in Sources */, - E1395BF2294F793000C403C6 /* AppDateFormatter.swift in Sources */, - E1B57FF829859CEC00B441FB /* DevicesTableViewCell.swift in Sources */, - 0E8BD2C1238566AB008B31EF /* MenuTableViewController.swift in Sources */, - 0E8BD2C2238566AB008B31EF /* AboutRouterInput.swift in Sources */, - A9646473247BAE6B0001D55D /* ChartSettingsTableViewController.swift in Sources */, - E191F1F62968D32000F1FEA6 /* TagSettingsExpandableSectionHeader.swift in Sources */, - 0EB48DFD261B105D008E0D2D /* RemoteConfigService.swift in Sources */, - 0EA796762664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift in Sources */, - 66BC44992657AED400A03253 /* OffsetCorrectionAppleInitializer.swift in Sources */, - 0E8BD2C6238566AB008B31EF /* AboutViewOutput.swift in Sources */, - A9646485247BAE6B0001D55D /* ChartSettingsPresenter.swift in Sources */, - 0EAD33D82399273D00EC5BAA /* HeartbeatInitializer.swift in Sources */, - E1CE5E4329FC39D000391109 /* DefaultsModuleOutput.swift in Sources */, - E1B7B5382AE98B72009D747E /* SensorRemovalModuleInput.swift in Sources */, - E19EAF98299E6083005827E4 /* SignInBenefitsRouterInput.swift in Sources */, - E186AB2C2844A273004926FC /* RuuviWidgetsConfiguration.intentdefinition in Sources */, - 0EA511B9261F3C2C00EE5D5E /* LocalFeatureToggleProvider.swift in Sources */, - 0E197C7E23C5CD7C0074015B /* UIDevice+ReadableModel.swift in Sources */, - E19EAF9B299E608E005827E4 /* SignInBenefitsRouter.swift in Sources */, - 0E9E775B238CCE5F006D7013 /* String+Replace.swift in Sources */, - E1E3C340298FDCCC00A59CB8 /* CardsModuleOutput.swift in Sources */, - A91D02FE2511207300694733 /* SelectionTableViewCell.swift in Sources */, - 0E8BD2CE238566AB008B31EF /* Language+Localization.swift in Sources */, - A91D02F82511207300694733 /* SelectionModuleInput.swift in Sources */, - E19691512A06DCA400DC360E /* NotificationsSettingsModuleFactory.swift in Sources */, - E10E18AF297D6672002C78C3 /* RuuviCloudPresenter.swift in Sources */, - E19EAF76299AE3B0005827E4 /* SignInView.swift in Sources */, - A92A66BE2450C64A002918E7 /* UITableViewCell+ReusableView.swift in Sources */, - 0E8BD2D1238566AB008B31EF /* DefaultsPresenter.swift in Sources */, - E1198A3029BA76A8002245CF /* ASSelectionTableViewCell.swift in Sources */, - E1B7B5292AE98A37009D747E /* SensorRemovalViewController.swift in Sources */, - 0E8BD2D4238566AB008B31EF /* SettingsPresenter.swift in Sources */, - E1AB90652A0EB13400543F61 /* SensorForceClaimModuleInput.swift in Sources */, - A91D02F52511207300694733 /* SelectionPresenter.swift in Sources */, - E116708629634708002DF7BF /* BackgroundSelectionPresenter.swift in Sources */, - 0E197C6C23C4A52A0074015B /* MailComposerPresenterMessageUI.swift in Sources */, - 0E197C6723C4A47A0074015B /* MailComposerPresenter.swift in Sources */, - A9A48A5D244CD9EB0004FD50 /* UIWindow+Shake.swift in Sources */, - A9FC79002579675100F94604 /* UniversalLinkRouter.swift in Sources */, - E1ED426A28FF253B00302179 /* TagChartsViewModel.swift in Sources */, - 0E8BD2D6238566AB008B31EF /* MenuTablePresentTransitionAnimation.swift in Sources */, - 0E8BD2DA238566AB008B31EF /* MenuModuleOutput.swift in Sources */, - E1198A3629BA76CB002245CF /* ASSelectionViewInput.swift in Sources */, - 0E3CA70D267365B1000D9B25 /* Debouncer.swift in Sources */, - E116707A29634363002DF7BF /* BackgroundSelectionViewOutput.swift in Sources */, - 66BC449C2657AED400A03253 /* OffsetCorrectionConfigurator.swift in Sources */, - E10E18BB297D67FC002C78C3 /* RuuviCloudViewOutput.swift in Sources */, - E1E3C343299007B700A59CB8 /* TagSettingsModuleInput.swift in Sources */, - 0E62299626AAA0570041DCDD /* DiscoverRouter.swift in Sources */, - 0E8BD2DD238566AB008B31EF /* Localizable.swift in Sources */, - 0E97D7A9268C922C00FE9D5B /* DFUInteractor.swift in Sources */, - E19691572A06DCBB00DC360E /* NotificationsSettingsRouter.swift in Sources */, - 0EE36E4026957E010021B746 /* DFUInteractorInput.swift in Sources */, - E19EAF79299AE5EA005827E4 /* SignInVerifyView.swift in Sources */, - E168B4B72886AF1200D6B5C6 /* UnitSettingsType.swift in Sources */, - E1B5800929859EDE00B441FB /* DevicesInteractorInput.swift in Sources */, - E1597A34295CC4F900DFB70B /* LowBatteryView.swift in Sources */, - E1198A0029BA60CE002245CF /* AppearanceSettingsTableViewController.swift in Sources */, - 340BE39727B54F38006D6C34 /* OwnerRouter.swift in Sources */, - 66BC44B12657AED400A03253 /* OffsetCorrectionViewOutput.swift in Sources */, - E19691672A06DCE500DC360E /* NotificationsSettingsViewModel.swift in Sources */, - E1198A3C29BA76F1002245CF /* ASSelectionModuleInput.swift in Sources */, - E19EAF6A29997711005827E4 /* SignInViewController.swift in Sources */, - 0E8BD2E0238566AB008B31EF /* DefaultsList.swift in Sources */, - E16B8F4F28D113230025B92D /* MyRuuviAccountInitializer.swift in Sources */, - 0E8BD2E4238566AB008B31EF /* CardsViewOutput.swift in Sources */, - 0E8BD2E5238566AB008B31EF /* DefaultsSwitchTableViewCell.swift in Sources */, - A9FC79182579678D00F94604 /* UniversalLinkCoordinatormpl.swift in Sources */, - E1E102EF28F348B700815508 /* TagChartsHelper.swift in Sources */, - 0E8BD2E6238566AB008B31EF /* DefaultsViewInput.swift in Sources */, - E191F1EA2968B6B100F1FEA6 /* TagSettingsViewController.swift in Sources */, - E1167083296346D5002DF7BF /* BackgroundSelectionModuleInput.swift in Sources */, - 0E8BD2E9238566AB008B31EF /* MenuTableConfigurator.swift in Sources */, - 0EAD33E22399273D00EC5BAA /* HeartbeatViewModel.swift in Sources */, - E1597A6629608CF300DFB70B /* GlobalHelpers.swift in Sources */, - A949A83C24707FDD006B7F4F /* LocalizedCache.swift in Sources */, - E1597A4A295CD5F800DFB70B /* DashboardPresenter.swift in Sources */, - 0E8BD2ED238566AB008B31EF /* DefaultsStepperTableViewCell.swift in Sources */, - E18D04C128E8B3B0008EF5EC /* TagChartsViewInteractorOutput.swift in Sources */, - E19EAFA2299E61C5005827E4 /* SignInBenefitsModuleInput.swift in Sources */, - E1B5800229859D2300B441FB /* DevicesViewOutput.swift in Sources */, - E19EAFAE299E82D1005827E4 /* SignInPresenter.swift in Sources */, - E116707029620AD4002DF7BF /* BackgroundSelectionButtonView.swift in Sources */, - E1CD7810287830BF00F1F0EB /* UnitSettingsRouterInput.swift in Sources */, - E1B57FFF29859D1800B441FB /* DevicesViewInput.swift in Sources */, - 0EB48D962619D5E5008E0D2D /* FeatureToggleProvider.swift in Sources */, - E196915C2A06DCD500DC360E /* NotificationsSettingsTableViewController.swift in Sources */, - E19691812A06E03300DC360E /* PushAlertSoundSelectionModuleInput.swift in Sources */, - 0EA7967A2664B37F002BA25D /* RuuviLocalError+LocalizedError.swift in Sources */, - E19691832A06E03300DC360E /* PushAlertSoundSelectionTableViewController.swift in Sources */, - A91D0317251124F900694733 /* SelectionItem.swift in Sources */, - 0E8BD2F0238566AB008B31EF /* SettingsRouter.swift in Sources */, - 340BE37627B54EE2006D6C34 /* AppAssemblyConstants.swift in Sources */, - E1E3C331298C601200A59CB8 /* CardsViewModuleFactory.swift in Sources */, - E1B7B5322AE98B00009D747E /* SensorRemovalRouter.swift in Sources */, - E19EAF73299ADB2F005827E4 /* UIButton+Extension.swift in Sources */, - 0E8BD2F3238566AB008B31EF /* SwipeDownToDismissNavigationController.swift in Sources */, - 0E8BD2F4238566AB008B31EF /* DefaultsRouterInput.swift in Sources */, - 0E8BD2F5238566AB008B31EF /* AboutPresenter.swift in Sources */, - E1597A732962000B00DFB70B /* BackgroundSelectionViewCell.swift in Sources */, - E1B57FF229859CD400B441FB /* DevicesPresenter.swift in Sources */, - E18D04AA28E8A6C0008EF5EC /* TagChartsViewPresenter.swift in Sources */, - E1597A762962046500DFB70B /* BackgroundSelectionViewHeader.swift in Sources */, - 0E8BD2FC238566AB008B31EF /* Observable.swift in Sources */, - 0E8BD300238566AB008B31EF /* TagSettingsViewOutput.swift in Sources */, - 0E8BD302238566AB008B31EF /* CardsViewModel.swift in Sources */, - E19EAFA5299E6211005827E4 /* SignInBenefitsModuleOutput.swift in Sources */, - E10E18732978AF3D002C78C3 /* TagSettingsViewModel.swift in Sources */, - 0E8BD303238566AB008B31EF /* UIApplication+ViewController.swift in Sources */, - A92E3C6C2426767E00D981D5 /* MeasurementType.swift in Sources */, - E1198A3329BA76C1002245CF /* ASSelectionViewOutput.swift in Sources */, - E1ED426F28FF261D00302179 /* CustomYAxisRenderer.swift in Sources */, - 0EB8ED2A268F10E900C6B0FA /* Spinner.swift in Sources */, - 0E8BD30F238566AB008B31EF /* PhotoPickerPresenterSheet.swift in Sources */, - 0E8BD310238566AB008B31EF /* AboutConfigurator.swift in Sources */, - 0E8BD311238566AB008B31EF /* AboutViewInput.swift in Sources */, - E1CD78132878379C00F1F0EB /* UnitSettingsTableViewCell.swift in Sources */, - A9646470247BAE6B0001D55D /* ChartSettingsSwitchTableViewCell.swift in Sources */, - 0E8BD314238566AB008B31EF /* DefaultsViewController.swift in Sources */, - E1B57FF529859CE200B441FB /* DevicesTableViewController.swift in Sources */, - E1E3C346299007DE00A59CB8 /* TagSettingsModuleOutput.swift in Sources */, - 66BC44AB2657AED400A03253 /* OffsetCorrectionViewInput.swift in Sources */, - 0E8BD316238566AB008B31EF /* DefaultsViewModel.swift in Sources */, - E1198A1C29BA6A79002245CF /* AppearanceSettingsViewModel.swift in Sources */, - E1198A0F29BA68FD002245CF /* AppearanceSettingsModuleFactory.swift in Sources */, - E1198A2729BA763F002245CF /* ASSelectionModuleFactory.swift in Sources */, - 0E8BD318238566AB008B31EF /* TemperatureUnit+Localization.swift in Sources */, - 0EB8ED2D268F111B00C6B0FA /* View+Any.swift in Sources */, - E168B4AC2885C28000D6B5C6 /* MeasurementAccuracyTitles.swift in Sources */, - E1CD77F228782E8000F1F0EB /* UnitSettingsTableConfigurator.swift in Sources */, - E11989F629B7A46E002245CF /* UIView+Extension.swift in Sources */, - E1395C012957944E00C403C6 /* CardsViewController.swift in Sources */, - 0E8BD31A238566AB008B31EF /* DefaultsConfigurator.swift in Sources */, - 0E8BD31B238566AB008B31EF /* MenuRouter.swift in Sources */, - 0EAD33D92399273D00EC5BAA /* HeartbeatConfigurator.swift in Sources */, - A9E599592557345200F9E5CC /* ShareEmailInputTableViewCell.swift in Sources */, - E1D0238C29EB02C600EC0FFD /* RuuviUISwitch.swift in Sources */, - 0EB8ED482692018000C6B0FA /* RuuviColor.swift in Sources */, - 0EB48D8C2619D5AC008E0D2D /* FeatureToggleService.swift in Sources */, - E1597A4D295CD66500DFB70B /* DashboardInteractorInput.swift in Sources */, - E1B57FEF29859CC900B441FB /* DevicesModuleInput.swift in Sources */, - 0EB48DDD2619E306008E0D2D /* FallbackFeatureToggleProvider.swift in Sources */, - A9646482247BAE6B0001D55D /* ChartModuleInput.swift in Sources */, - 0E8BD320238566AB008B31EF /* DefaultsInitializer.swift in Sources */, - E19691652A06DCE500DC360E /* NotificationsSettingsViewInput.swift in Sources */, - E16B8F5228D113440025B92D /* MyRuuviAccountConfigurator.swift in Sources */, - E116708D29634D91002DF7BF /* BackgroundSelectionViewModel.swift in Sources */, - E18D04C528E9DF77008EF5EC /* TagChartsView.swift in Sources */, - 0E97D79C268C881300FE9D5B /* DFUModuleInput.swift in Sources */, - E1597A31295B909B00DFB70B /* DashboardPlainCell.swift in Sources */, - E10E18AC297D6664002C78C3 /* RuuviCloudModuleFactory.swift in Sources */, - 0E2AFFA1266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift in Sources */, - 0E8BD326238566AB008B31EF /* MenuTableInitializer.swift in Sources */, - E1CD78052878302C00F1F0EB /* UnitSettingsViewOutput.swift in Sources */, - E1CA28AF29201F34009E4423 /* RUAlertExpandButton.swift in Sources */, - E19EAFAB299E62C0005827E4 /* SignInBenefitsViewOutput.swift in Sources */, - E191F222296A00CE00F1FEA6 /* TagSettingsFooterCell.swift in Sources */, - 66BC44A52657AED400A03253 /* OffsetCorrectionModuleInput.swift in Sources */, - A9E5994B2557341F00F9E5CC /* ShareDescriptionTableViewCell.swift in Sources */, - E1B7B53B2AE98B86009D747E /* SensorRemovalPresenter.swift in Sources */, - A91D0312251123B400694733 /* SelectionModuleOutput.swift in Sources */, - 0EAD33E02399273D00EC5BAA /* HeartbeatTableViewController.swift in Sources */, - 0EA796722664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift in Sources */, - A91D02F22511207200694733 /* SelectionTableInitializer.swift in Sources */, - A93CDCDF25659BF600018C6C /* AlertPresenterImpl.swift in Sources */, - E18D04BB28E8B34F008EF5EC /* TagChartsViewInteractor.swift in Sources */, - E19EAFA8299E62A7005827E4 /* SignInBenefitsViewInput.swift in Sources */, - 0EB8ED3D268F8CD900C6B0FA /* FirmwareRepository.swift in Sources */, - E19691872A06E03300DC360E /* PushAlertSoundSelectionViewInput.swift in Sources */, - E168B4AF2886AE4E00D6B5C6 /* MeasurementAccuracyType+Extension.swift in Sources */, - E1597A47295CD5E400DFB70B /* DashboardModuleInput.swift in Sources */, - 0E8BD330238566AB008B31EF /* AboutInitializer.swift in Sources */, - E19691692A06DCE500DC360E /* NotificationsSettingsViewOutput.swift in Sources */, - 0E8BD332238566AB008B31EF /* MenuTableEmbededViewController.swift in Sources */, - A907BB1224AE620D009DA3DB /* UIWindow+Orientation.swift in Sources */, - E1198A1929BA6A61002245CF /* AppearanceSettingsViewInput.swift in Sources */, - E16B8F4C28D1114F0025B92D /* MyRuuviAccountModuleInput.swift in Sources */, - E16051EA285CB384003FCA70 /* AppStoreReviewHelper.swift in Sources */, - E1CD77ED2878273500F1F0EB /* UnitSettingsTableViewController.swift in Sources */, - 0EAD33DD2399273D00EC5BAA /* HeartbeatRouter.swift in Sources */, - 0E2B339C26A2BC3F00366B01 /* AppRouter.swift in Sources */, - 660EB29D266928E6000FD22B /* UIViewController+Alert.swift in Sources */, - E196917D2A06E03300DC360E /* PushAlertSoundSelectionModuleFactory.swift in Sources */, - E1D0238F29EB3F7D00EC0FFD /* YAxisValueFormatter.swift in Sources */, - E1B7B5252AE989ED009D747E /* SensorRemovalModuleFactory.swift in Sources */, - 0E8BD335238566AB008B31EF /* Date+Ruuvi.swift in Sources */, - 0EA796862664B84D002BA25D /* RuuviReactorError+LocalizedError.swift in Sources */, - 0EF4E34126824EF500D83CC7 /* DfuFirmware+Log.swift in Sources */, - 0EB8ED37268F685500C6B0FA /* URLSession+downloadTaskPublisher.swift in Sources */, - E11FDA6E29A2A3C6003ADA7B /* DefaultsPlainTableViewCell.swift in Sources */, - E191F20A2969E11F00F1FEA6 /* TagSettingsRouterInput.swift in Sources */, - E1CD77FF28782F9900F1F0EB /* UnitSettingsModuleOutput.swift in Sources */, - A91D02FB2511207300694733 /* SelectionViewInput.swift in Sources */, - 0E8BD343238566AB008B31EF /* SettingsTableViewController.swift in Sources */, - 3414BFCC2806D1B300C63BE9 /* RuuviCodeTextField.swift in Sources */, - E1AB90562A0BFECE00543F61 /* RuuviLinkTextView.swift in Sources */, - 0EAD33DC2399273D00EC5BAA /* HeartbeatRouterInput.swift in Sources */, - E1CD780D287830B100F1F0EB /* UnitSettingsRouter.swift in Sources */, - E19EAFB1299EB46D005827E4 /* NoSensorView.swift in Sources */, - 66BC449F2657AED400A03253 /* OffsetCorrectionModuleOutput.swift in Sources */, - E1CE5E4029F994DE00391109 /* AppGroupConstants.swift in Sources */, - 0EAD33DF2399273D00EC5BAA /* HeartbeatEnvironmentObject.swift in Sources */, - E19EAF6729983650005827E4 /* AppUtility.swift in Sources */, - 0E8BD345238566AB008B31EF /* SwipeDownToDismissTransitionAnimation.swift in Sources */, - A9E5996B255734A000F9E5CC /* ShareEmailTableViewCell.swift in Sources */, - 0E8BD348238566AB008B31EF /* SettingsRouterInput.swift in Sources */, - E1C395D429B26044009301D3 /* UICollectionView+Extension.swift in Sources */, - E1CD77FC28782F7100F1F0EB /* UnitSettingsModuleInput.swift in Sources */, - 0EAD33E32399273D00EC5BAA /* HeartbeatViewOutput.swift in Sources */, - 0E8BD34A238566AB008B31EF /* MenuTableTransitionManager.swift in Sources */, - E1395BEB294F6C2A00C403C6 /* String+Localization.swift in Sources */, - 0EA7968E2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift in Sources */, - A976CA7F24A928C20099BDC1 /* ChartSettingsDisclosureTableViewCell.swift in Sources */, - E1198A0329BA6193002245CF /* AppearanceSettingsTableViewBasicCell.swift in Sources */, - 0E8BD34C238566AB008B31EF /* DefaultsRouter.swift in Sources */, - 340BE38927B54F37006D6C34 /* OwnerInitializer.swift in Sources */, - E19691892A06E03300DC360E /* PushAlertSoundSelectionViewOutput.swift in Sources */, - 0EB8ED30268F12FA00C6B0FA /* DFUModuleFactory.swift in Sources */, - A91D03042511207300694733 /* SelectionViewOutput.swift in Sources */, - E18D04D528F1D52A008EF5EC /* TagChartsViewOutput.swift in Sources */, - 0EB8ED1F268EFF4200C6B0FA /* Publishers+System.swift in Sources */, - E1198A0C29BA68BE002245CF /* AppearanceSettingsRouter.swift in Sources */, - E1E3C334298D7FA500A59CB8 /* UIImage+Extension.swift in Sources */, - E1E6C216296C9CB100B3D037 /* Int+Extension.swift in Sources */, - 3414BFC92806D19C00C63BE9 /* RuuviCodeView.swift in Sources */, - 0E197C7523C5C7A20074015B /* InfoProvider.swift in Sources */, - E1CE4C722959CE61005C023F /* DashboardViewController.swift in Sources */, - E1B7B5402AEAD61A009D747E /* SensorRemovalModuleOutput.swift in Sources */, - 0E2513602684AEAD004A522A /* RuuviNotifierTitlesImpl.swift in Sources */, - E1B5800F2986AE0800B441FB /* RuuviContextMenuButton.swift in Sources */, - A91D03072511207300694733 /* SelectionRouter.swift in Sources */, - 0E8BD353238566AB008B31EF /* LocalizationService.swift in Sources */, - 3490A4C427D9F2C80032BBAB /* UINavigationController.swift in Sources */, - E1597A41295CD55300DFB70B /* DashboardRouter.swift in Sources */, - 0E8BD354238566AB008B31EF /* RURangeSeekSlider.swift in Sources */, - 0E8BD355238566AB008B31EF /* CardsModuleInput.swift in Sources */, - 0EB48D702619D50A008E0D2D /* FeatureToggle.swift in Sources */, - 340BE39527B54F38006D6C34 /* OwnerViewOutput.swift in Sources */, - E16B8F4628D10E2C0025B92D /* MyRuuviAccountViewOutput.swift in Sources */, - E1198A1629BA6A06002245CF /* AppearanceSettingsViewOutput.swift in Sources */, - 0E8BD35B238566AB008B31EF /* PresentationAssembly.swift in Sources */, - E1B20C8B2926D2FC0023D739 /* Double+Extension.swift in Sources */, - E1CA28B9292037E4009E4423 /* RUAlertDetailsCellChildView.swift in Sources */, - E18D04AD28E8A737008EF5EC /* TagChartsViewModuleInput.swift in Sources */, - A91D02EF2511207200694733 /* SelectionTableConfigurator.swift in Sources */, - E10E18C5297DE3AF002C78C3 /* TagChartsMarkerView.swift in Sources */, - E1395C072958A33400C403C6 /* CardsBackgroundView.swift in Sources */, - E191F1FF2969D6C900F1FEA6 /* TagSettingsPlainCell.swift in Sources */, - E1597A60295F803400DFB70B /* UIColor+Extension.swift in Sources */, - E19691552A06DCBB00DC360E /* NotificationsSettingsRouterInput.swift in Sources */, - 0E8BD35D238566AB008B31EF /* AboutModuleInput.swift in Sources */, - E1AB907F2A0ECB7600543F61 /* SensorForceClaimViewInput.swift in Sources */, - 0EAD33DA2399273D00EC5BAA /* HeartbeatModuleInput.swift in Sources */, - 0EB8ED1B268EF36200C6B0FA /* DFUViewModel.swift in Sources */, - 340BE37327B54E26006D6C34 /* PresentationConstants.swift in Sources */, - A91D03012511207300694733 /* SelectionTableViewController.swift in Sources */, - 340BE39127B54F37006D6C34 /* OwnerViewInput.swift in Sources */, - E1E3C33A298EC9DC00A59CB8 /* DashboardModuleFactory.swift in Sources */, - E1198A0929BA68B6002245CF /* AppearanceSettingsRouterInput.swift in Sources */, - 0E8BD364238566AB008B31EF /* MenuRouterInput.swift in Sources */, - 0EA796822664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift in Sources */, - E1CD77F928782F2200F1F0EB /* UnitSettingsPresenter.swift in Sources */, - 340BE39927B54F38006D6C34 /* OwnerRouterInput.swift in Sources */, - A9A67BFB24C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift in Sources */, - E1B7B5352AE98B16009D747E /* SensorRemovalRouterInput.swift in Sources */, - E191F21F2969FF6900F1FEA6 /* TagSettingsSwitchCell.swift in Sources */, - 0E8BD368238566AB008B31EF /* Double+Temperature.swift in Sources */, - E1395BFD2954DAAD00C403C6 /* CardsInteractor.swift in Sources */, - 0EB8ED3A268F6A6900C6B0FA /* ProgressBar.swift in Sources */, - E196916D2A06DCEF00DC360E /* NotificationsSettingsPresenter.swift in Sources */, - E191F21C2969EF7B00F1FEA6 /* TagSettingsModuleFactory.swift in Sources */, - 0E8BD36B238566AB008B31EF /* AppStateServiceImpl.swift in Sources */, - E1B7B52C2AE98A9F009D747E /* SensorRemovalViewOutput.swift in Sources */, - E1CD78022878302100F1F0EB /* UnitSettingsViewInput.swift in Sources */, - E19EAF84299C1383005827E4 /* SignInModuleFactory.swift in Sources */, - A980573925807118000D03AB /* AboutViewModel.swift in Sources */, - E19EAF9F299E610A005827E4 /* SignInBenefitsPresenter.swift in Sources */, - E1198A1F29BA6B7E002245CF /* AppearanceSettingsModuleInput.swift in Sources */, - 0E8BD36D238566AB008B31EF /* MenuViewOutput.swift in Sources */, - 0EAD33DB2399273D00EC5BAA /* HeartbeatPresenter.swift in Sources */, - 0E8BD372238566AB008B31EF /* SwipeDownToDismissTransitioningDelegate.swift in Sources */, - E19EAF95299E6038005827E4 /* SignInBenefitsModuleFactory.swift in Sources */, - 0E8BD373238566AB008B31EF /* MenuViewInput.swift in Sources */, - E196918F2A06E2E100DC360E /* RuuviAlertSound+Extension.swift in Sources */, - A9E6774925A33081000B75A3 /* String+Characters.swift in Sources */, - E196915E2A06DCD500DC360E /* NotificationsSettingsTextCell.swift in Sources */, - A91D030A2511207300694733 /* SelectionRouterInput.swift in Sources */, - 0EAD33E42399273D00EC5BAA /* HeartbeatViewController.swift in Sources */, - E191F20D2969E14600F1FEA6 /* TagSettingsRouter.swift in Sources */, - 0E8BD377238566AB008B31EF /* AboutViewController.swift in Sources */, - E16B8F5B28D113EA0025B92D /* MyRuuviAccountRouter.swift in Sources */, - 66BC44A22657AED400A03253 /* OffsetCorrectionPresenter.swift in Sources */, - 66BC44AE2657AED400A03253 /* OffsetCorrectionViewModel.swift in Sources */, - A9FC790F2579676E00F94604 /* UniversalLinkRouterImpl.swift in Sources */, - 0E8BD37A238566AB008B31EF /* DefaultsEnvironmentObject.swift in Sources */, - 0E8BD37C238566AB008B31EF /* ViewInput.swift in Sources */, - 0E8BD37D238566AB008B31EF /* UserDefaults+Optional.swift in Sources */, - 0E8BD37F238566AB008B31EF /* CardsViewInput.swift in Sources */, - 0E8BD382238566AB008B31EF /* AboutRouter.swift in Sources */, - 66718A6D266BD0E800A380F8 /* Color+Ruuvi.swift in Sources */, - E1AB90622A0EB11800543F61 /* SensorForceClaimPresenter.swift in Sources */, - A964647F247BAE6B0001D55D /* ChartSettingsInitializer.swift in Sources */, - A93CDCD025659BA600018C6C /* AlertPresenter.swift in Sources */, - 0E8BD389238566AB008B31EF /* PhotoPickerPresenter.swift in Sources */, - E1597A692960944600DFB70B /* DashboardCellDelegate.swift in Sources */, - 0E00C4F22684D97B009B3C24 /* ExportHeadersProvider.swift in Sources */, - E18D04BE28E8B397008EF5EC /* TagChartsViewInteractorInput.swift in Sources */, - E1ED427128FF261D00302179 /* XAxisValueFormatter.swift in Sources */, - A964646D247BAE6B0001D55D /* ChartSettingsStepperTableViewCell.swift in Sources */, - 0E8BD38D238566AB008B31EF /* DefaultsModuleInput.swift in Sources */, - E196918C2A06E15F00DC360E /* PushAlertSoundSelectionViewModel.swift in Sources */, - E1CD78092878308E00F1F0EB /* UnitSettingsItem.swift in Sources */, - E1B57FFC29859D0700B441FB /* DevicesViewModel.swift in Sources */, - 0E8BD392238566AB008B31EF /* HumidityUnit+Localization.swift in Sources */, - 0E8BD393238566AB008B31EF /* SwipeDownToDismissInteractiveTransition.swift in Sources */, - E1E3C33D298ED3E300A59CB8 /* CardsPresenter.swift in Sources */, - E1395C042958A2A900C403C6 /* CardsIndicatorView.swift in Sources */, - 0EB48E07261B1095008E0D2D /* FirebaseRemoteConfigService.swift in Sources */, - E191F1F92968D33800F1FEA6 /* TagSettingsSimpleSectionHeader.swift in Sources */, - 0E8BD395238566AB008B31EF /* NSObject+Observable.swift in Sources */, - E1E3C337298D858D00A59CB8 /* TagChartsModuleFactory.swift in Sources */, - 0E00C5092685D82B009B3C24 /* RuuviDaemonError+LocalizedError.swift in Sources */, - 0EF4E33E26824ABD00D83CC7 /* RuuviDFUError+LocalizedError.swift in Sources */, - E191F2102969E1C300F1FEA6 /* TagSettingsPresenter.swift in Sources */, - 0E8BD399238566AB008B31EF /* AppAssembly.swift in Sources */, - E16051ED285CBA57003FCA70 /* FileManager+Date.swift in Sources */, - E1597A3E295CD52A00DFB70B /* DashboardRouterInput.swift in Sources */, - E10E18B2297D6690002C78C3 /* RuuviCloudTableViewController.swift in Sources */, - 0E8BD39A238566AB008B31EF /* AppStateService.swift in Sources */, - A9646467247BAE6B0001D55D /* ChartSettingsViewInput.swift in Sources */, - 0E8BD39B238566AB008B31EF /* MenuTableDismissTransitionAnimation.swift in Sources */, - E1AB90682A0EB1AD00543F61 /* SensorForceClaimRouter.swift in Sources */, - 0E8BD39E238566AB008B31EF /* SettingsTableConfigurator.swift in Sources */, - E18D04A628E8A5A3008EF5EC /* TagChartsViewConfigurator.swift in Sources */, - E116709029635B53002DF7BF /* BackgroundSelectionUploadProgressView.swift in Sources */, - 0EB8ED4026916D1700C6B0FA /* LargeButtonStyle.swift in Sources */, - E1E1475D28E85EE700832B8C /* UIImageView+Init.swift in Sources */, - 0E8BD3A5238566AB008B31EF /* SettingsTableInitializer.swift in Sources */, - 0EA7967E2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift in Sources */, - 0EAD33E12399273D00EC5BAA /* HeartbeatViewInput.swift in Sources */, - E1AB907C2A0ECB6D00543F61 /* SensorForceClaimViewOutput.swift in Sources */, - 340BE39C27B54FEC006D6C34 /* String+Email.swift in Sources */, - E1B7B52F2AE98AC4009D747E /* SensorRemovalViewInput.swift in Sources */, - E10E18B5297D67B8002C78C3 /* RuuviCloudViewModel.swift in Sources */, - E1198A2229BA6EC6002245CF /* RuuviTheme+Extension.swift in Sources */, - 0E8BD3AA238566AB008B31EF /* AppDelegate.swift in Sources */, - E16B8F4928D10E7A0025B92D /* MyRuuviAccountViewModel.swift in Sources */, - E1B57FEC29859CB800B441FB /* DevicesModuleFactory.swift in Sources */, - E18FD50E28DF7E7100289359 /* UIView+Layout.swift in Sources */, - E19691602A06DCD500DC360E /* NotificationsSettingsSwitchCell.swift in Sources */, - E11FDA7129A3F78D003ADA7B /* RuuviSimpleViewCompositionalLayout.swift in Sources */, - E1198A3929BA76DD002245CF /* ASSelectionPresenter.swift in Sources */, - 340BE38B27B54F37006D6C34 /* OwnerConfigurator.swift in Sources */, - E191F1F32968C2C900F1FEA6 /* TagSettingsAlertConfigCell.swift in Sources */, - 0EA7AB7B2680A68200C137AD /* RuuviCoreError+LocalizedError.swift in Sources */, - A9BD38BB24F6108300904BBE /* Humidity+Offset.swift in Sources */, - 0E8BD3AD238566AB008B31EF /* RUError.swift in Sources */, - E1597A5D295E24D400DFB70B /* RuuviAssets.swift in Sources */, - A964647C247BAE6B0001D55D /* ChartSettingsConfigurator.swift in Sources */, - 0EB8ED22268EFF6400C6B0FA /* Feedback.swift in Sources */, - 0E97D79F268C884500FE9D5B /* DFUPresenter.swift in Sources */, - 0E0501222685E895007060C4 /* HeartbeatDaemonTitles.swift in Sources */, - E1CE4C782959DF01005C023F /* DashboardIndicatorView.swift in Sources */, - E1ED427328FF261D00302179 /* CustomXAxisRenderer.swift in Sources */, - 0E2B339F26A2BCBE00366B01 /* OnboardRouter.swift in Sources */, - 0E8BD3B4238566AB008B31EF /* MenuModuleInput.swift in Sources */, - E116708929634815002DF7BF /* BackgroundSelectionModuleFactory.swift in Sources */, - 0E8BD3B7238566AB008B31EF /* DefaultsTableViewController.swift in Sources */, - E16051E7285A15A1003FCA70 /* RuuviTagBatteryStatusProvider.swift in Sources */, - 0E8BD3BA238566AB008B31EF /* MenuTableTransitioningDelegate.swift in Sources */, - E19EAF7C299BF94C005827E4 /* SignInBenefitsViewController.swift in Sources */, - E18D04D228F1D027008EF5EC /* TagChartsViewInput.swift in Sources */, - A9FC78EA2579671B00F94604 /* UniversalLinkCoordinator.swift in Sources */, - E1597A50295CD67900DFB70B /* DashboardInteractor.swift in Sources */, - E1B5800C29859EEB00B441FB /* DevicesInteractorOutput.swift in Sources */, - 0E8BD3C2238566AB008B31EF /* SettingsViewOutput.swift in Sources */, - 0E290A862660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift in Sources */, - A9646476247BAE6B0001D55D /* ChartSettingsViewOutput.swift in Sources */, - E191F1ED2968BCF300F1FEA6 /* TagSettingsBasicCell.swift in Sources */, - 0E8BD3C5238566AB008B31EF /* SettingsModuleInput.swift in Sources */, - 0EB48DA42619D7EE008E0D2D /* FirebaseFeatureToggleProvider.swift in Sources */, - 0E197C7A23C5CCBC0074015B /* InfoProviderImpl.swift in Sources */, - 0E8BD3CA238566AB008B31EF /* CardsRouter.swift in Sources */, - E10E18BE297D68EB002C78C3 /* RuuviCloudModuleInput.swift in Sources */, - 0ECA196B2B138C3A00BEE4DB /* FeatureTogglesViewController.swift in Sources */, - E10E18C2297DD0CA002C78C3 /* RuuviCloudTableViewCell.swift in Sources */, - E1198A2D29BA769A002245CF /* ASSelectionTableViewController.swift in Sources */, - A9646488247BAE6B0001D55D /* ChartSettingsRouterInput.swift in Sources */, - 0E8BD3CC238566AB008B31EF /* CardsRouterInput.swift in Sources */, - A91D031B25113EAA00694733 /* UnitPressure+Extension.swift in Sources */, - E1395BFA2954DAA200C403C6 /* CardsInteractorInput.swift in Sources */, - E196917F2A06E03300DC360E /* PushAlertSoundSelectionPresenter.swift in Sources */, - A9E599622557346600F9E5CC /* ShareSendButtonTableViewCell.swift in Sources */, - A9646479247BAE6B0001D55D /* ChartSettingsViewModel.swift in Sources */, - E1CE4C752959D08D005C023F /* DashboardImageCell.swift in Sources */, - 340BE38F27B54F37006D6C34 /* OwnerModuleInput.swift in Sources */, - E1597A56295CD6E300DFB70B /* DashboardViewOutput.swift in Sources */, - 340BE38D27B54F37006D6C34 /* OwnerPresenter.swift in Sources */, - 0E8BD3CF238566AB008B31EF /* SettingsViewInput.swift in Sources */, - E1CD77F528782EA500F1F0EB /* UnitSettingsTableInitializer.swift in Sources */, - 0E8BD3D2238566AB008B31EF /* CardsRouterDelegate.swift in Sources */, - E18D04A228E879EE008EF5EC /* UIView+Init.swift in Sources */, - E16B8F5828D113CB0025B92D /* MyRuuviAccountRouterInput.swift in Sources */, - 66BC44A82657AED400A03253 /* OffsetCorrectionAppleViewController.swift in Sources */, - E1B5800629859E8900B441FB /* DevicesInteractor.swift in Sources */, - A964648B247BAE6B0001D55D /* ChartSettingsRouter.swift in Sources */, - 66BC44B42657AED400A03253 /* OffsetCorrectionRouter.swift in Sources */, - 66BC44B72657AED400A03253 /* OffsetCorrectionRouterInput.swift in Sources */, - E116707729634332002DF7BF /* BackgroundSelectionViewInput.swift in Sources */, - 08E830207D43DAF06076D647 /* SignInModuleInput.swift in Sources */, - 8A37F49EA3B84BB415491B03 /* SignInModuleOutput.swift in Sources */, - E8C4E5B85668D51EC22BC75A /* SignInRouterInput.swift in Sources */, - D037B55274A07756F884696B /* SignInRouter.swift in Sources */, - ABCA915676F9A8C975D9F2A3 /* SignInViewInput.swift in Sources */, - 34238B2C062103E10D2BC65D /* SignInViewOutput.swift in Sources */, - 74E67721EFA7BF9397D52B1F /* SignInViewModel.swift in Sources */, - 0EB8ED26268F083700C6B0FA /* DFUUIView.swift in Sources */, - E1597A702961FEB900DFB70B /* BackgroundSelectionViewController.swift in Sources */, - A9BB94CD2540AB610042B190 /* AlertViewModel.swift in Sources */, - E1198A1229BA6910002245CF /* AppearanceSettingsPresenter.swift in Sources */, - 4F8FB6FCCB69D64B47FF440B /* ShareConfigurator.swift in Sources */, - 898D45D0BF0ABBCB2E68FBE9 /* ShareInitializer.swift in Sources */, - E196916F2A06DCEF00DC360E /* NotificationsSettingsModuleInput.swift in Sources */, - C9D6ACA6CB9694F6C33414CE /* ShareModuleInput.swift in Sources */, - 248444E4B7F8C3D6454D4D1B /* ShareModuleOutput.swift in Sources */, - 26BA929FDA200CCAC9964651 /* SharePresenter.swift in Sources */, - E1597A2E295B6E6B00DFB70B /* UIFont+Extension.swift in Sources */, - B198F488C89E6DFFD1EECAF3 /* ShareRouterInput.swift in Sources */, - 6204554EB76ED0EFDE0DC290 /* ShareRouter.swift in Sources */, - B6FA27492FB1F63393783EFC /* ShareViewInput.swift in Sources */, - E1B20C882926CDE10023D739 /* UITextField+Extension.swift in Sources */, - 3BA1E7A8054CF95D80BAE3F9 /* ShareViewOutput.swift in Sources */, - E19691852A06E03300DC360E /* PushAlertSoundSelectionTableViewCell.swift in Sources */, - 2BB81E4733D8EC40BECC68EF /* ShareViewModel.swift in Sources */, - E18FD50B28DF7B7900289359 /* TagChartsViewController.swift in Sources */, - E1597A53295CD6BB00DFB70B /* DashboardViewInput.swift in Sources */, - B2A3FB2578B246F6CBBF0CA9 /* ShareViewController.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 34A8D485281EBFD9008A8698 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 3493385D28300396009060E8 /* NetworkManager.swift in Sources */, - E128160B292ABCFA008E9282 /* SimpleWidgetViewCircular.swift in Sources */, - 34D458E228216C6900EA9F93 /* WidgetViewModel.swift in Sources */, - E186AB2D2844A273004926FC /* RuuviWidgetsConfiguration.intentdefinition in Sources */, - 34A8D4A2281ED018008A8698 /* Extensions.swift in Sources */, - 3493386328300A73009060E8 /* SimpleWidgetView.swift in Sources */, - 34933873283014F6009060E8 /* WidgetSensorEnum.swift in Sources */, - 3493386F283014A0009060E8 /* Model+Extension.swift in Sources */, - 3493386528300ACC009060E8 /* UnauthorizedView.swift in Sources */, - E1117008291C34A700ACCD72 /* SimpleWidgetViewRectangle.swift in Sources */, - 34D458E028216B2200EA9F93 /* WidgetAssembly.swift in Sources */, - 3493386C28300C49009060E8 /* Constants.swift in Sources */, - 34A8D4C6281EEC19008A8698 /* WidgetEntry.swift in Sources */, - 341401EC282D03C8003DE721 /* MeasurementService.swift in Sources */, - E1072687291C49E500247625 /* SimpleWidgetViewInline.swift in Sources */, - 34A8D490281EBFD9008A8698 /* RuuviWidgets.swift in Sources */, - 3493386728300B06009060E8 /* EmptyWidgetView.swift in Sources */, - 34A8D4C4281EEBF8008A8698 /* WidgetProvider.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 34A8D4B1281EE5AE008A8698 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 34933874283014F6009060E8 /* WidgetSensorEnum.swift in Sources */, - 34933870283014A0009060E8 /* Model+Extension.swift in Sources */, - 34D458E328217BF600EA9F93 /* WidgetViewModel.swift in Sources */, - 3493385F283006CB009060E8 /* Extensions.swift in Sources */, - 34A8D4BA281EE5AE008A8698 /* IntentHandler.swift in Sources */, - 34933860283006F4009060E8 /* WidgetEntry.swift in Sources */, - 34D458E428217C5900EA9F93 /* WidgetAssembly.swift in Sources */, - E186AB2E2844A273004926FC /* RuuviWidgetsConfiguration.intentdefinition in Sources */, - 3493385E28300679009060E8 /* MeasurementService.swift in Sources */, - 3493386D28300DC3009060E8 /* Constants.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D2120B0C45900CDF4B6 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E1E3C330298C601200A59CB8 /* CardsViewModuleFactory.swift in Sources */, - 0EA796792664B37F002BA25D /* RuuviLocalError+LocalizedError.swift in Sources */, - 66BC44A72657AED400A03253 /* OffsetCorrectionAppleViewController.swift in Sources */, - E19EAFAD299E82D1005827E4 /* SignInPresenter.swift in Sources */, - 0EA7967D2664B50A002BA25D /* RuuviPersistenceError+LocalizedError.swift in Sources */, - 0EC50F5622CCE46D00172EEB /* Optional.swift in Sources */, - E16B8F5128D113440025B92D /* MyRuuviAccountConfigurator.swift in Sources */, - E1AB907E2A0ECB7600543F61 /* SensorForceClaimViewInput.swift in Sources */, - A9B57442253B994700DB7353 /* SignInRouter.swift in Sources */, - E1597A752962046500DFB70B /* BackgroundSelectionViewHeader.swift in Sources */, - E116708C29634D91002DF7BF /* BackgroundSelectionViewModel.swift in Sources */, - 66BC44A42657AED400A03253 /* OffsetCorrectionModuleInput.swift in Sources */, - 0E09672522AE897000E85F48 /* CALayer+IB.swift in Sources */, - 0E3CA70C267365B1000D9B25 /* Debouncer.swift in Sources */, - A92A66BD2450C640002918E7 /* UITableViewCell+ReusableView.swift in Sources */, - A93CDCDE25659BF600018C6C /* AlertPresenterImpl.swift in Sources */, - E1B57FEE29859CC900B441FB /* DevicesModuleInput.swift in Sources */, - 0ECA196A2B138C3A00BEE4DB /* FeatureTogglesViewController.swift in Sources */, - 0E1C1E0F22B4049F0032F6CA /* MenuTablePresentationController.swift in Sources */, - 340BE39B27B54FEC006D6C34 /* String+Email.swift in Sources */, - E116707929634363002DF7BF /* BackgroundSelectionViewOutput.swift in Sources */, - 0E00C4F12684D97B009B3C24 /* ExportHeadersProvider.swift in Sources */, - E1B7B5312AE98B00009D747E /* SensorRemovalRouter.swift in Sources */, - A9646472247BAE6B0001D55D /* ChartSettingsTableViewController.swift in Sources */, - 0EF4E34026824EF500D83CC7 /* DfuFirmware+Log.swift in Sources */, - E11989F529B7A46E002245CF /* UIView+Extension.swift in Sources */, - E19691542A06DCBB00DC360E /* NotificationsSettingsRouterInput.swift in Sources */, - E191F1F52968D32000F1FEA6 /* TagSettingsExpandableSectionHeader.swift in Sources */, - 0EF2863122CBB00D0026C7A5 /* TagSettingsViewInput.swift in Sources */, - E19EAF9A299E608E005827E4 /* SignInBenefitsRouter.swift in Sources */, - E1198A1B29BA6A79002245CF /* AppearanceSettingsViewModel.swift in Sources */, - A9B57447253B994700DB7353 /* SignInModuleOutput.swift in Sources */, - 0E8A100E23845F8C00A9CBA6 /* DefaultsViewOutput.swift in Sources */, - E1597A722962000B00DFB70B /* BackgroundSelectionViewCell.swift in Sources */, - 0E1C1E0022B400130032F6CA /* MenuPresenter.swift in Sources */, - A91D03062511207300694733 /* SelectionRouter.swift in Sources */, - E196918B2A06E15F00DC360E /* PushAlertSoundSelectionViewModel.swift in Sources */, - 0E1C1DF822B3FF480032F6CA /* MenuTableViewController.swift in Sources */, - E196915D2A06DCD500DC360E /* NotificationsSettingsTextCell.swift in Sources */, - 0EEB20F922B7D28C0015F9E0 /* AboutRouterInput.swift in Sources */, - E1CD77F828782F2200F1F0EB /* UnitSettingsPresenter.swift in Sources */, - 0E84BF572397F33E00A37E1A /* HeartbeatViewInput.swift in Sources */, - A91D0316251124F900694733 /* SelectionItem.swift in Sources */, - 0EEB20F522B7D1A40015F9E0 /* AboutViewOutput.swift in Sources */, - A98D3F15256CBD600066588B /* ShareViewOutput.swift in Sources */, - E1167082296346D5002DF7BF /* BackgroundSelectionModuleInput.swift in Sources */, - E1AB906A2A0EB1BC00543F61 /* SensorForceClaimRouterInput.swift in Sources */, - E1198A3529BA76CB002245CF /* ASSelectionViewInput.swift in Sources */, - 0EB48D952619D5E5008E0D2D /* FeatureToggleProvider.swift in Sources */, - A9E5994A2557341F00F9E5CC /* ShareDescriptionTableViewCell.swift in Sources */, - E1ED427228FF261D00302179 /* CustomXAxisRenderer.swift in Sources */, - A91D03092511207300694733 /* SelectionRouterInput.swift in Sources */, - A964647E247BAE6B0001D55D /* ChartSettingsInitializer.swift in Sources */, - A98D3F11256CBD600066588B /* ShareRouter.swift in Sources */, - E1597A46295CD5E400DFB70B /* DashboardModuleInput.swift in Sources */, - E16B8F4E28D113230025B92D /* MyRuuviAccountInitializer.swift in Sources */, - A976CA7E24A928C20099BDC1 /* ChartSettingsDisclosureTableViewCell.swift in Sources */, - E19EAF7B299BF94C005827E4 /* SignInBenefitsViewController.swift in Sources */, - 0E9E775A238CCE5F006D7013 /* String+Replace.swift in Sources */, - E19EAFB0299EB46D005827E4 /* NoSensorView.swift in Sources */, - 0EB8ED2C268F111B00C6B0FA /* View+Any.swift in Sources */, - 0E197C7D23C5CD7C0074015B /* UIDevice+ReadableModel.swift in Sources */, - E19EAF6929997711005827E4 /* SignInViewController.swift in Sources */, - 0EBAF065232002A00025A191 /* Language+Localization.swift in Sources */, - 66BC44982657AED400A03253 /* OffsetCorrectionAppleInitializer.swift in Sources */, - E1B7B53F2AEAD61A009D747E /* SensorRemovalModuleOutput.swift in Sources */, - 0E84BF592397F3C600A37E1A /* HeartbeatViewModel.swift in Sources */, - 0EB8ED472692018000C6B0FA /* RuuviColor.swift in Sources */, - E1597A4F295CD67900DFB70B /* DashboardInteractor.swift in Sources */, - E16B8F4828D10E7A0025B92D /* MyRuuviAccountViewModel.swift in Sources */, - 0E8A101A2384615400A9CBA6 /* DefaultsPresenter.swift in Sources */, - E19EAF94299E6038005827E4 /* SignInBenefitsModuleFactory.swift in Sources */, - A9B57446253B994700DB7353 /* SignInModuleInput.swift in Sources */, - E186AB2B2844A273004926FC /* RuuviWidgetsConfiguration.intentdefinition in Sources */, - A91D02F72511207300694733 /* SelectionModuleInput.swift in Sources */, - E1ED426928FF253B00302179 /* TagChartsViewModel.swift in Sources */, - A9FC78FF2579675100F94604 /* UniversalLinkRouter.swift in Sources */, - E18D04BD28E8B397008EF5EC /* TagChartsViewInteractorInput.swift in Sources */, - E1CA28B8292037E4009E4423 /* RUAlertDetailsCellChildView.swift in Sources */, - E10E18C1297DD0CA002C78C3 /* RuuviCloudTableViewCell.swift in Sources */, - E16B8F5728D113CB0025B92D /* MyRuuviAccountRouterInput.swift in Sources */, - A9BB94CC2540AB610042B190 /* AlertViewModel.swift in Sources */, - 0E97D79E268C884500FE9D5B /* DFUPresenter.swift in Sources */, - E1CD77FE28782F9900F1F0EB /* UnitSettingsModuleOutput.swift in Sources */, - 0EEB20E322B7C8C10015F9E0 /* SettingsPresenter.swift in Sources */, - E1597A49295CD5F800DFB70B /* DashboardPresenter.swift in Sources */, - E1E3C336298D858D00A59CB8 /* TagChartsModuleFactory.swift in Sources */, - 0EE36E3F26957E010021B746 /* DFUInteractorInput.swift in Sources */, - 0E197C6B23C4A52A0074015B /* MailComposerPresenterMessageUI.swift in Sources */, - E1395BF92954DAA200C403C6 /* CardsInteractorInput.swift in Sources */, - E1B7B52E2AE98AC4009D747E /* SensorRemovalViewInput.swift in Sources */, - E191F20F2969E1C300F1FEA6 /* TagSettingsPresenter.swift in Sources */, - 0E197C6623C4A47A0074015B /* MailComposerPresenter.swift in Sources */, - E1E3C339298EC9DC00A59CB8 /* DashboardModuleFactory.swift in Sources */, - 0E97D79B268C881300FE9D5B /* DFUModuleInput.swift in Sources */, - E1CD77FB28782F7100F1F0EB /* UnitSettingsModuleInput.swift in Sources */, - E10E18B1297D6690002C78C3 /* RuuviCloudTableViewController.swift in Sources */, - 0E1C1E0B22B403290032F6CA /* MenuTablePresentTransitionAnimation.swift in Sources */, - E1CD780C287830B100F1F0EB /* UnitSettingsRouter.swift in Sources */, - E1B57FF729859CEC00B441FB /* DevicesTableViewCell.swift in Sources */, - 0E0501212685E895007060C4 /* HeartbeatDaemonTitles.swift in Sources */, - 0EEB20CD22B7BD6C0015F9E0 /* MenuModuleOutput.swift in Sources */, - 0E70A46322AF959E006CB87C /* Localizable.swift in Sources */, - E1AB90672A0EB1AD00543F61 /* SensorForceClaimRouter.swift in Sources */, - 66BC44B02657AED400A03253 /* OffsetCorrectionViewOutput.swift in Sources */, - E1CD78012878302100F1F0EB /* UnitSettingsViewInput.swift in Sources */, - E1198A1129BA6910002245CF /* AppearanceSettingsPresenter.swift in Sources */, - 0EA511B8261F3C2C00EE5D5E /* LocalFeatureToggleProvider.swift in Sources */, - A9E599582557345200F9E5CC /* ShareEmailInputTableViewCell.swift in Sources */, - A91D02F12511207200694733 /* SelectionTableInitializer.swift in Sources */, - E1B20C8A2926D2FC0023D739 /* Double+Extension.swift in Sources */, - E1395C032958A2A900C403C6 /* CardsIndicatorView.swift in Sources */, - E1198A0829BA68B6002245CF /* AppearanceSettingsRouterInput.swift in Sources */, - 0E8A10222384637F00A9CBA6 /* DefaultsList.swift in Sources */, - E1CE4C772959DF01005C023F /* DashboardIndicatorView.swift in Sources */, - 0E1C1DD522B3BF3A0032F6CA /* CardsViewOutput.swift in Sources */, - E1597A30295B909B00DFB70B /* DashboardPlainCell.swift in Sources */, - 340BE37227B54E25006D6C34 /* PresentationConstants.swift in Sources */, - 0E8A102523846CEB00A9CBA6 /* DefaultsSwitchTableViewCell.swift in Sources */, - 0E8A100C23845F7100A9CBA6 /* DefaultsViewInput.swift in Sources */, - E1B57FFB29859D0700B441FB /* DevicesViewModel.swift in Sources */, - E1395BF1294F793000C403C6 /* AppDateFormatter.swift in Sources */, - E18D04C028E8B3B0008EF5EC /* TagChartsViewInteractorOutput.swift in Sources */, - E19EAF72299ADB2F005827E4 /* UIButton+Extension.swift in Sources */, - E1AB905E2A0EB0D000543F61 /* SensorForceClaimModuleFactory.swift in Sources */, - 66718A6C266BD0E800A380F8 /* Color+Ruuvi.swift in Sources */, - E116708F29635B53002DF7BF /* BackgroundSelectionUploadProgressView.swift in Sources */, - E1972BE129587615000E2AEC /* CardsLargeImageCell.swift in Sources */, - 660EB29C266928E6000FD22B /* UIViewController+Alert.swift in Sources */, - 0E1C1E0522B400890032F6CA /* MenuTableConfigurator.swift in Sources */, - 0E2AFFA0266A91AE001A374D /* RuuviRepositoryError+LocalizedError.swift in Sources */, - 0E8BD2AB23851CF2008B31EF /* DefaultsStepperTableViewCell.swift in Sources */, - 340BE39827B54F38006D6C34 /* OwnerRouterInput.swift in Sources */, - 0EEB20DF22B7C8790015F9E0 /* SettingsRouter.swift in Sources */, - 340BE38827B54F37006D6C34 /* OwnerInitializer.swift in Sources */, - E1CD77EC2878273500F1F0EB /* UnitSettingsTableViewController.swift in Sources */, - 0E53DA6722CC964200BC6D64 /* SwipeDownToDismissNavigationController.swift in Sources */, - A9B57448253B994700DB7353 /* SignInViewModel.swift in Sources */, - E10E18B7297D67E8002C78C3 /* RuuviCloudViewInput.swift in Sources */, - 0E8A10162384612300A9CBA6 /* DefaultsRouterInput.swift in Sources */, - E116708829634815002DF7BF /* BackgroundSelectionModuleFactory.swift in Sources */, - 0EA796712664A7E0002BA25D /* RuuviCloudError+LocalizedError.swift in Sources */, - E1E3C333298D7FA500A59CB8 /* UIImage+Extension.swift in Sources */, - E11989FF29BA60CE002245CF /* AppearanceSettingsTableViewController.swift in Sources */, - E196916C2A06DCEF00DC360E /* NotificationsSettingsPresenter.swift in Sources */, - 0EEB20FF22B7D2DD0015F9E0 /* AboutPresenter.swift in Sources */, - E1B5800529859E8900B441FB /* DevicesInteractor.swift in Sources */, - 0E84BF612397F73100A37E1A /* HeartbeatEnvironmentObject.swift in Sources */, - E19EAF78299AE5EA005827E4 /* SignInVerifyView.swift in Sources */, - E10E18B4297D67B8002C78C3 /* RuuviCloudViewModel.swift in Sources */, - A964648A247BAE6B0001D55D /* ChartSettingsRouter.swift in Sources */, - 0EB8ED29268F10E900C6B0FA /* Spinner.swift in Sources */, - 0EA796852664B84D002BA25D /* RuuviReactorError+LocalizedError.swift in Sources */, - E1597A6F2961FEB800DFB70B /* BackgroundSelectionViewController.swift in Sources */, - E19EAFA4299E6211005827E4 /* SignInBenefitsModuleOutput.swift in Sources */, - E116708529634708002DF7BF /* BackgroundSelectionPresenter.swift in Sources */, - 0EC50F5022CCB92000172EEB /* Observable.swift in Sources */, - E1AB90552A0BFECE00543F61 /* RuuviLinkTextView.swift in Sources */, - E1198A1829BA6A61002245CF /* AppearanceSettingsViewInput.swift in Sources */, - A9BD38BA24F6108300904BBE /* Humidity+Offset.swift in Sources */, - 0EF2863322CBB0250026C7A5 /* TagSettingsViewOutput.swift in Sources */, - 0EEB20C622B7915C0015F9E0 /* CardsViewModel.swift in Sources */, - 0E00C5082685D82B009B3C24 /* RuuviDaemonError+LocalizedError.swift in Sources */, - A98D3F13256CBD600066588B /* SharePresenter.swift in Sources */, - E1395C002957944E00C403C6 /* CardsViewController.swift in Sources */, - E1597A3D295CD52A00DFB70B /* DashboardRouterInput.swift in Sources */, - 0E1C1DBB22B3919F0032F6CA /* UIApplication+ViewController.swift in Sources */, - E1CE5E4229FC39D000391109 /* DefaultsModuleOutput.swift in Sources */, - E1D0238B29EB02C600EC0FFD /* RuuviUISwitch.swift in Sources */, - A9E599612557346600F9E5CC /* ShareSendButtonTableViewCell.swift in Sources */, - 0EF4E33D26824ABD00D83CC7 /* RuuviDFUError+LocalizedError.swift in Sources */, - E1198A1E29BA6B7E002245CF /* AppearanceSettingsModuleInput.swift in Sources */, - 3414BFCB2806D1B300C63BE9 /* RuuviCodeTextField.swift in Sources */, - E16B8F4228D10DF90025B92D /* MyRuuviAccountViewInput.swift in Sources */, - A98D3F0E256CBD600066588B /* ShareRouterInput.swift in Sources */, - E168B4AB2885C28000D6B5C6 /* MeasurementAccuracyTitles.swift in Sources */, - 0E5C300B22CF629100B52E39 /* PhotoPickerPresenterSheet.swift in Sources */, - E1198A3B29BA76F1002245CF /* ASSelectionModuleInput.swift in Sources */, - E1597A4C295CD66500DFB70B /* DashboardInteractorInput.swift in Sources */, - 340BE38A27B54F37006D6C34 /* OwnerConfigurator.swift in Sources */, - 0EEB210322B7D3220015F9E0 /* AboutConfigurator.swift in Sources */, - 0EEB20F322B7D1900015F9E0 /* AboutViewInput.swift in Sources */, - E1198A3829BA76DD002245CF /* ASSelectionPresenter.swift in Sources */, - 0EB8ED1A268EF36200C6B0FA /* DFUViewModel.swift in Sources */, - E1CD77F428782EA500F1F0EB /* UnitSettingsTableInitializer.swift in Sources */, - A964646C247BAE6B0001D55D /* ChartSettingsStepperTableViewCell.swift in Sources */, - 0E8A100A23845F3900A9CBA6 /* DefaultsViewController.swift in Sources */, - E1D0238E29EB3F7D00EC0FFD /* YAxisValueFormatter.swift in Sources */, - E1CE5E3F29F994DE00391109 /* AppGroupConstants.swift in Sources */, - 0E84BF712398035C00A37E1A /* HeartbeatConfigurator.swift in Sources */, - E1AB907B2A0ECB6D00543F61 /* SensorForceClaimViewOutput.swift in Sources */, - E19EAFA1299E61C5005827E4 /* SignInBenefitsModuleInput.swift in Sources */, - E191F2092969E11F00F1FEA6 /* TagSettingsRouterInput.swift in Sources */, - 0EB8ED2F268F12FA00C6B0FA /* DFUModuleFactory.swift in Sources */, - E1198A0229BA6193002245CF /* AppearanceSettingsTableViewBasicCell.swift in Sources */, - A91D02EE2511207200694733 /* SelectionTableConfigurator.swift in Sources */, - 66BC44B32657AED400A03253 /* OffsetCorrectionRouter.swift in Sources */, - E19EAFAA299E62C0005827E4 /* SignInBenefitsViewOutput.swift in Sources */, - 0E8A101023845FAE00A9CBA6 /* DefaultsViewModel.swift in Sources */, - 0E502FBA22B27D4800E8A6CC /* TemperatureUnit+Localization.swift in Sources */, - E191F1F22968C2C900F1FEA6 /* TagSettingsAlertConfigCell.swift in Sources */, - 0E8A101E238461D400A9CBA6 /* DefaultsConfigurator.swift in Sources */, - 66BC449B2657AED400A03253 /* OffsetCorrectionConfigurator.swift in Sources */, - 0E2B339E26A2BCBE00366B01 /* OnboardRouter.swift in Sources */, - 0E1C1DFC22B3FFD90032F6CA /* MenuRouter.swift in Sources */, - 0EA796812664B7DC002BA25D /* RuuviPoolError+LocalizedError.swift in Sources */, - 0EA7968D2664B91E002BA25D /* RuuviStorageError+LocalizedError.swift in Sources */, - 0E8A101C2384618700A9CBA6 /* DefaultsInitializer.swift in Sources */, - A9E5996A255734A000F9E5CC /* ShareEmailTableViewCell.swift in Sources */, - 0E1C1E0322B400590032F6CA /* MenuTableInitializer.swift in Sources */, - 66BC44B62657AED400A03253 /* OffsetCorrectionRouterInput.swift in Sources */, - A92E3C4C24261CF900D981D5 /* MeasurementType.swift in Sources */, - A9FC78E92579671B00F94604 /* UniversalLinkCoordinator.swift in Sources */, - A93CDCCF25659BA600018C6C /* AlertPresenter.swift in Sources */, - E1597A2D295B6E6B00DFB70B /* UIFont+Extension.swift in Sources */, - A9646487247BAE6B0001D55D /* ChartSettingsRouterInput.swift in Sources */, - E196917C2A06E03300DC360E /* PushAlertSoundSelectionModuleFactory.swift in Sources */, - 0EEB210122B7D2F50015F9E0 /* AboutInitializer.swift in Sources */, - E16B8F4B28D1114F0025B92D /* MyRuuviAccountModuleInput.swift in Sources */, - 0EEB20CB22B7B37C0015F9E0 /* MenuTableEmbededViewController.swift in Sources */, - E168B4AE2886AE4E00D6B5C6 /* MeasurementAccuracyType+Extension.swift in Sources */, - A98D3F06256CBD410066588B /* ShareModuleInput.swift in Sources */, - A949A83B24707FD0006B7F4F /* LocalizedCache.swift in Sources */, - 0E84BF5F2397F6BE00A37E1A /* HeartbeatViewController.swift in Sources */, - E191F1F82968D33800F1FEA6 /* TagSettingsSimpleSectionHeader.swift in Sources */, - E191F1EC2968BCF300F1FEA6 /* TagSettingsBasicCell.swift in Sources */, - E1AB90612A0EB11800543F61 /* SensorForceClaimPresenter.swift in Sources */, - 0E84BF67239801AF00A37E1A /* HeartbeatRouterInput.swift in Sources */, - 0EB48DDC2619E306008E0D2D /* FallbackFeatureToggleProvider.swift in Sources */, - 0EF5B72B22D62CD900D9D14A /* Date+Ruuvi.swift in Sources */, - E19691842A06E03300DC360E /* PushAlertSoundSelectionTableViewCell.swift in Sources */, - A98D3F0F256CBD600066588B /* ShareViewInput.swift in Sources */, - 0EB8ED3F26916D1700C6B0FA /* LargeButtonStyle.swift in Sources */, - E1CD77F128782E8000F1F0EB /* UnitSettingsTableConfigurator.swift in Sources */, - 0EB8ED25268F083700C6B0FA /* DFUUIView.swift in Sources */, - E1597A5C295E24D400DFB70B /* RuuviAssets.swift in Sources */, - E19691682A06DCE500DC360E /* NotificationsSettingsViewOutput.swift in Sources */, - E1E3C342299007B700A59CB8 /* TagSettingsModuleInput.swift in Sources */, - E1ED427028FF261D00302179 /* XAxisValueFormatter.swift in Sources */, - E1B7B53A2AE98B86009D747E /* SensorRemovalPresenter.swift in Sources */, - A980573825807118000D03AB /* AboutViewModel.swift in Sources */, - A9A67BFA24C5C8A500C710D6 /* NSObjectProtocol+Invalidation.swift in Sources */, - 0EB8ED3C268F8CD900C6B0FA /* FirmwareRepository.swift in Sources */, - E1E3C345299007DE00A59CB8 /* TagSettingsModuleOutput.swift in Sources */, - E1B57FEB29859CB800B441FB /* DevicesModuleFactory.swift in Sources */, - E1B5800E2986AE0800B441FB /* RuuviContextMenuButton.swift in Sources */, - E1CE5E472A016D4000391109 /* RuuviCustomButton.swift in Sources */, - A9646478247BAE6B0001D55D /* ChartSettingsViewModel.swift in Sources */, - A9B57441253B994700DB7353 /* SignInRouterInput.swift in Sources */, - E1B5800B29859EEB00B441FB /* DevicesInteractorOutput.swift in Sources */, - E1597A6529608CF300DFB70B /* GlobalHelpers.swift in Sources */, - E16B8F5428D113750025B92D /* MyRuuviAccountPresenter.swift in Sources */, - A9646484247BAE6B0001D55D /* ChartSettingsPresenter.swift in Sources */, - E19EAFA7299E62A7005827E4 /* SignInBenefitsViewInput.swift in Sources */, - E196917E2A06E03300DC360E /* PushAlertSoundSelectionPresenter.swift in Sources */, - E1B5800129859D2300B441FB /* DevicesViewOutput.swift in Sources */, - A91D031A25113EAA00694733 /* UnitPressure+Extension.swift in Sources */, - 0EB48E06261B1095008E0D2D /* FirebaseRemoteConfigService.swift in Sources */, - 0EEB20D322B7C7AC0015F9E0 /* SettingsTableViewController.swift in Sources */, - E191F221296A00CE00F1FEA6 /* TagSettingsFooterCell.swift in Sources */, - 0E53DA6222CC93EB00BC6D64 /* SwipeDownToDismissTransitionAnimation.swift in Sources */, - A9646481247BAE6B0001D55D /* ChartModuleInput.swift in Sources */, - 0E84BF6F2398031B00A37E1A /* HeartbeatInitializer.swift in Sources */, - A9E6774825A33081000B75A3 /* String+Characters.swift in Sources */, - 0EEB20DD22B7C8650015F9E0 /* SettingsRouterInput.swift in Sources */, - 0EEB215A22BA28860015F9E0 /* MenuTableTransitionManager.swift in Sources */, - E196915F2A06DCD500DC360E /* NotificationsSettingsSwitchCell.swift in Sources */, - A91D02FD2511207300694733 /* SelectionTableViewCell.swift in Sources */, - E10E18BA297D67FC002C78C3 /* RuuviCloudViewOutput.swift in Sources */, - E19691562A06DCBB00DC360E /* NotificationsSettingsRouter.swift in Sources */, - E10E18722978AF3D002C78C3 /* TagSettingsViewModel.swift in Sources */, - 340BE39627B54F38006D6C34 /* OwnerRouter.swift in Sources */, - E18D04AF28E8A747008EF5EC /* TagChartsViewModuleOutput.swift in Sources */, - 0E8A10142384610400A9CBA6 /* DefaultsRouter.swift in Sources */, - 0E197C7423C5C7A20074015B /* InfoProvider.swift in Sources */, - E19EAF9E299E610A005827E4 /* SignInBenefitsPresenter.swift in Sources */, - 340BE38C27B54F37006D6C34 /* OwnerPresenter.swift in Sources */, - E18FD50A28DF7B7900289359 /* TagChartsViewController.swift in Sources */, - E10E18BD297D68EB002C78C3 /* RuuviCloudModuleInput.swift in Sources */, - E1CD78082878308E00F1F0EB /* UnitSettingsItem.swift in Sources */, - 0E9D0AB1231EBEFD00C6BDA7 /* LocalizationService.swift in Sources */, - E16B8F3F28D10CF50025B92D /* MyRuuviAccountViewController.swift in Sources */, - E19691662A06DCE500DC360E /* NotificationsSettingsViewModel.swift in Sources */, - 0E02ABBA237598C600ED4629 /* RURangeSeekSlider.swift in Sources */, - E191F1FB2969CD0100F1FEA6 /* TagSettingsBackgroundSelectionView.swift in Sources */, - E1CD78042878302C00F1F0EB /* UnitSettingsViewOutput.swift in Sources */, - E19691642A06DCE500DC360E /* NotificationsSettingsViewInput.swift in Sources */, - E16051EC285CBA57003FCA70 /* FileManager+Date.swift in Sources */, - 0EA796892664B8CB002BA25D /* RuuviServiceError+LocalizedError.swift in Sources */, - 0E1C1DDD22B3C2160032F6CA /* CardsModuleInput.swift in Sources */, - A91D02FA2511207300694733 /* SelectionViewInput.swift in Sources */, - E116707629634332002DF7BF /* BackgroundSelectionViewInput.swift in Sources */, - 0E25135F2684AEAD004A522A /* RuuviNotifierTitlesImpl.swift in Sources */, - E18D04A928E8A6C0008EF5EC /* TagChartsViewPresenter.swift in Sources */, - A98D3F0C256CBD600066588B /* ShareConfigurator.swift in Sources */, - E19691502A06DCA400DC360E /* NotificationsSettingsModuleFactory.swift in Sources */, - 0EA7AB7A2680A68200C137AD /* RuuviCoreError+LocalizedError.swift in Sources */, - E16051E9285CB384003FCA70 /* AppStoreReviewHelper.swift in Sources */, - E18FD50D28DF7E7100289359 /* UIView+Layout.swift in Sources */, - E1395BEA294F6C2A00C403C6 /* String+Localization.swift in Sources */, - 66BC44AA2657AED400A03253 /* OffsetCorrectionViewInput.swift in Sources */, - 0E1C1DBE22B3921E0032F6CA /* PresentationAssembly.swift in Sources */, - E1E1475C28E85EE700832B8C /* UIImageView+Init.swift in Sources */, - E18D04BA28E8B34F008EF5EC /* TagChartsViewInteractor.swift in Sources */, - A9FC79172579678D00F94604 /* UniversalLinkCoordinatormpl.swift in Sources */, - 340BE37527B54EE2006D6C34 /* AppAssemblyConstants.swift in Sources */, - 0EEB20FD22B7D2C90015F9E0 /* AboutModuleInput.swift in Sources */, - E16B8F5A28D113EA0025B92D /* MyRuuviAccountRouter.swift in Sources */, - A9B57443253B994700DB7353 /* SignInViewInput.swift in Sources */, - E1B20C872926CDE10023D739 /* UITextField+Extension.swift in Sources */, - E19EAF75299AE3B0005827E4 /* SignInView.swift in Sources */, - 0E1C1DFA22B3FFBF0032F6CA /* MenuRouterInput.swift in Sources */, - E1B7B5282AE98A37009D747E /* SensorRemovalViewController.swift in Sources */, - 66BC44AD2657AED400A03253 /* OffsetCorrectionViewModel.swift in Sources */, - 0EE36E4226957E200021B746 /* LatestRelease.swift in Sources */, - 0E02ABCB2379483A00ED4629 /* Double+Temperature.swift in Sources */, - 0EB48D8B2619D5AC008E0D2D /* FeatureToggleService.swift in Sources */, - E1198A3229BA76C1002245CF /* ASSelectionViewOutput.swift in Sources */, - E19691882A06E03300DC360E /* PushAlertSoundSelectionViewOutput.swift in Sources */, - 0E5C302822D0B1C600B52E39 /* AppStateServiceImpl.swift in Sources */, - 0E1C1DF522B3FF1D0032F6CA /* MenuViewOutput.swift in Sources */, - E18D04AC28E8A737008EF5EC /* TagChartsViewModuleInput.swift in Sources */, - 0EB8ED1E268EFF4200C6B0FA /* Publishers+System.swift in Sources */, - 0E53DA6022CC93A700BC6D64 /* SwipeDownToDismissTransitioningDelegate.swift in Sources */, - 0EB8ED39268F6A6900C6B0FA /* ProgressBar.swift in Sources */, - 0E1C1DF322B3FEFF0032F6CA /* MenuViewInput.swift in Sources */, - 0EB48DFC261B105D008E0D2D /* RemoteConfigService.swift in Sources */, - E1597A5F295F803400DFB70B /* UIColor+Extension.swift in Sources */, - 66BC44A12657AED400A03253 /* OffsetCorrectionPresenter.swift in Sources */, - E1CD780F287830BF00F1F0EB /* UnitSettingsRouterInput.swift in Sources */, - E1AB90732A0EB24600543F61 /* SensorForceClaimViewController.swift in Sources */, - 0EEB20F722B7D2090015F9E0 /* AboutViewController.swift in Sources */, - E116706F29620AD4002DF7BF /* BackgroundSelectionButtonView.swift in Sources */, - 0E8A10202384633200A9CBA6 /* DefaultsEnvironmentObject.swift in Sources */, - A98D3F14256CBD600066588B /* ShareModuleOutput.swift in Sources */, - E191F21E2969FF6900F1FEA6 /* TagSettingsSwitchCell.swift in Sources */, - E1CE4C742959D08D005C023F /* DashboardImageCell.swift in Sources */, - E19691862A06E03300DC360E /* PushAlertSoundSelectionViewInput.swift in Sources */, - A98D3F10256CBD600066588B /* ShareViewModel.swift in Sources */, - 0E70A46022AF9567006CB87C /* ViewInput.swift in Sources */, - E19691802A06E03300DC360E /* PushAlertSoundSelectionModuleInput.swift in Sources */, - 0E0A381923616AC3003A0364 /* UserDefaults+Optional.swift in Sources */, - 340BE39227B54F37006D6C34 /* OwnerViewController.swift in Sources */, - E196915B2A06DCD500DC360E /* NotificationsSettingsTableViewController.swift in Sources */, - E1198A2629BA763F002245CF /* ASSelectionModuleFactory.swift in Sources */, - 0E1C1DD322B3BF180032F6CA /* CardsViewInput.swift in Sources */, - E1198A2C29BA769A002245CF /* ASSelectionTableViewController.swift in Sources */, - E1B57FF429859CE200B441FB /* DevicesTableViewController.swift in Sources */, - E1E3C33F298FDCCC00A59CB8 /* CardsModuleOutput.swift in Sources */, - 0EEB20FB22B7D2990015F9E0 /* AboutRouter.swift in Sources */, - E191F20C2969E14600F1FEA6 /* TagSettingsRouter.swift in Sources */, - 0E84BF6D239802CA00A37E1A /* HeartbeatPresenter.swift in Sources */, - 0EC50F5922CF621000172EEB /* PhotoPickerPresenter.swift in Sources */, - E1CA28AE29201F34009E4423 /* RUAlertExpandButton.swift in Sources */, - 0E8A10182384613E00A9CBA6 /* DefaultsModuleInput.swift in Sources */, - 66BC449E2657AED400A03253 /* OffsetCorrectionModuleOutput.swift in Sources */, - 0EB8ED21268EFF6400C6B0FA /* Feedback.swift in Sources */, - 0EF5B75422DE153A00D9D14A /* HumidityUnit+Localization.swift in Sources */, - A91D03032511207300694733 /* SelectionViewOutput.swift in Sources */, - E1597A40295CD55300DFB70B /* DashboardRouter.swift in Sources */, - 0EB48DA32619D7EE008E0D2D /* FirebaseFeatureToggleProvider.swift in Sources */, - E168B4B62886AF1200D6B5C6 /* UnitSettingsType.swift in Sources */, - E19691822A06E03300DC360E /* PushAlertSoundSelectionTableViewController.swift in Sources */, - E1395BFC2954DAAD00C403C6 /* CardsInteractor.swift in Sources */, - 3414BFC82806D19C00C63BE9 /* RuuviCodeView.swift in Sources */, - 0E53DA6422CC943900BC6D64 /* SwipeDownToDismissInteractiveTransition.swift in Sources */, - E1597A43295CD58600DFB70B /* DashboardRouterDelegate.swift in Sources */, - 0EC50F5422CCBBE800172EEB /* NSObject+Observable.swift in Sources */, - E18D04A528E8A5A3008EF5EC /* TagChartsViewConfigurator.swift in Sources */, - E1B7B5242AE989ED009D747E /* SensorRemovalModuleFactory.swift in Sources */, - 0E1C1DA822B387A00032F6CA /* AppAssembly.swift in Sources */, - 0E5C302522D0B19600B52E39 /* AppStateService.swift in Sources */, - 0E1C1E0D22B4043C0032F6CA /* MenuTableDismissTransitionAnimation.swift in Sources */, - 0E84BF69239801C100A37E1A /* HeartbeatRouter.swift in Sources */, - E1395C062958A33400C403C6 /* CardsBackgroundView.swift in Sources */, - E10E18C4297DE3AF002C78C3 /* TagChartsMarkerView.swift in Sources */, - E11FDA7029A3F78D003ADA7B /* RuuviSimpleViewCompositionalLayout.swift in Sources */, - 0EEB20E822B7C92C0015F9E0 /* SettingsTableConfigurator.swift in Sources */, - E1198A0B29BA68BE002245CF /* AppearanceSettingsRouter.swift in Sources */, - E191F1FE2969D6C900F1FEA6 /* TagSettingsPlainCell.swift in Sources */, - E1E102EE28F348B700815508 /* TagChartsHelper.swift in Sources */, - E191F1E92968B6B100F1FEA6 /* TagSettingsViewController.swift in Sources */, - E1E6C215296C9CB100B3D037 /* Int+Extension.swift in Sources */, - A9FC790E2579676E00F94604 /* UniversalLinkRouterImpl.swift in Sources */, - A964647B247BAE6B0001D55D /* ChartSettingsConfigurator.swift in Sources */, - E1597A55295CD6E300DFB70B /* DashboardViewOutput.swift in Sources */, - E1597A33295CC4F900DFB70B /* LowBatteryView.swift in Sources */, - 0EEB20E622B7C8F20015F9E0 /* SettingsTableInitializer.swift in Sources */, - E1198A1529BA6A06002245CF /* AppearanceSettingsViewOutput.swift in Sources */, - E16051E6285A15A1003FCA70 /* RuuviTagBatteryStatusProvider.swift in Sources */, - E1B7B5342AE98B16009D747E /* SensorRemovalRouterInput.swift in Sources */, - A907BB1124AE620A009DA3DB /* UIWindow+Orientation.swift in Sources */, - 64333D2920B0C45900CDF4B6 /* AppDelegate.swift in Sources */, - E19EAF6629983650005827E4 /* AppUtility.swift in Sources */, - 0EA796752664B0FC002BA25D /* RuuviCloudApiError+LocalizedError.swift in Sources */, - E1B7B5372AE98B72009D747E /* SensorRemovalModuleInput.swift in Sources */, - E18D04D428F1D52A008EF5EC /* TagChartsViewOutput.swift in Sources */, - 0E1C1DA022B36C100032F6CA /* RUError.swift in Sources */, - 0E97D7A8268C922C00FE9D5B /* DFUInteractor.swift in Sources */, - E10E18AE297D6672002C78C3 /* RuuviCloudPresenter.swift in Sources */, - 340BE38E27B54F37006D6C34 /* OwnerModuleInput.swift in Sources */, - 0E1C1DFE22B3FFFC0032F6CA /* MenuModuleInput.swift in Sources */, - 0E8A10122384605A00A9CBA6 /* DefaultsTableViewController.swift in Sources */, - 0E1C1E0922B4024E0032F6CA /* MenuTableTransitioningDelegate.swift in Sources */, - E1198A2129BA6EC6002245CF /* RuuviTheme+Extension.swift in Sources */, - A98D3F12256CBD600066588B /* ShareViewController.swift in Sources */, - 0EEB20D822B7C8060015F9E0 /* SettingsViewOutput.swift in Sources */, - A91D0311251123B400694733 /* SelectionModuleOutput.swift in Sources */, - 3490A4C327D9F2C80032BBAB /* UINavigationController.swift in Sources */, - E1C395D329B26044009301D3 /* UICollectionView+Extension.swift in Sources */, - 0EEB20E122B7C8A90015F9E0 /* SettingsModuleInput.swift in Sources */, - E196916E2A06DCEF00DC360E /* NotificationsSettingsModuleInput.swift in Sources */, - E1E3C33C298ED3E300A59CB8 /* CardsPresenter.swift in Sources */, - E16B8F4528D10E2C0025B92D /* MyRuuviAccountViewOutput.swift in Sources */, - A9B5744A253B994700DB7353 /* SignInViewOutput.swift in Sources */, - E19EAF83299C1383005827E4 /* SignInModuleFactory.swift in Sources */, - E1CE4C712959CE61005C023F /* DashboardViewController.swift in Sources */, - E1B57FF129859CD400B441FB /* DevicesPresenter.swift in Sources */, - 0E84BF652397F9DC00A37E1A /* HeartbeatTableViewController.swift in Sources */, - E11FDA6D29A2A3C2003ADA7B /* DefaultsPlainTableViewCell.swift in Sources */, - E1198A2F29BA76A8002245CF /* ASSelectionTableViewCell.swift in Sources */, - E18D04C428E9DF77008EF5EC /* TagChartsView.swift in Sources */, - 0EB48D6F2619D50A008E0D2D /* FeatureToggle.swift in Sources */, - E18D04A128E879EE008EF5EC /* UIView+Init.swift in Sources */, - E191F21B2969EF7B00F1FEA6 /* TagSettingsModuleFactory.swift in Sources */, - E1198A0E29BA68FD002245CF /* AppearanceSettingsModuleFactory.swift in Sources */, - 0E1C1DE422B3C2710032F6CA /* CardsRouter.swift in Sources */, - E19EAF97299E6083005827E4 /* SignInBenefitsRouterInput.swift in Sources */, - 0E1C1DE222B3C25F0032F6CA /* CardsRouterInput.swift in Sources */, - 0E197C7923C5CCBC0074015B /* InfoProviderImpl.swift in Sources */, - A9646466247BAE6B0001D55D /* ChartSettingsViewInput.swift in Sources */, - 0E2B339B26A2BC3F00366B01 /* AppRouter.swift in Sources */, - 0EB8ED36268F685500C6B0FA /* URLSession+downloadTaskPublisher.swift in Sources */, - 0E84BF5B2397F3DF00A37E1A /* HeartbeatViewOutput.swift in Sources */, - 0EEB20D622B7C7E70015F9E0 /* SettingsViewInput.swift in Sources */, - E196918E2A06E2E100DC360E /* RuuviAlertSound+Extension.swift in Sources */, - 0E62299526AAA0570041DCDD /* DiscoverRouter.swift in Sources */, - 340BE39427B54F37006D6C34 /* OwnerViewOutput.swift in Sources */, - E10E18AB297D6664002C78C3 /* RuuviCloudModuleFactory.swift in Sources */, - E1ED426E28FF261D00302179 /* CustomYAxisRenderer.swift in Sources */, - 0E211C2A234C5FE900FC37B0 /* CardsRouterDelegate.swift in Sources */, - 0E84BF6B239802A400A37E1A /* HeartbeatModuleInput.swift in Sources */, - E18D04D128F1D027008EF5EC /* TagChartsViewInput.swift in Sources */, - A9646475247BAE6B0001D55D /* ChartSettingsViewOutput.swift in Sources */, - E1B5800829859EDE00B441FB /* DevicesInteractorInput.swift in Sources */, - A91D03002511207300694733 /* SelectionTableViewController.swift in Sources */, - E1AB90642A0EB13400543F61 /* SensorForceClaimModuleInput.swift in Sources */, - A964646F247BAE6B0001D55D /* ChartSettingsSwitchTableViewCell.swift in Sources */, - E1B7B52B2AE98A9F009D747E /* SensorRemovalViewOutput.swift in Sources */, - A98D3F0D256CBD600066588B /* ShareInitializer.swift in Sources */, - 0E84BF632397F76A00A37E1A /* HeartbeatList.swift in Sources */, - 340BE39027B54F37006D6C34 /* OwnerViewInput.swift in Sources */, - A91D02F42511207300694733 /* SelectionPresenter.swift in Sources */, - E1CD78122878379C00F1F0EB /* UnitSettingsTableViewCell.swift in Sources */, - E1597A682960944600DFB70B /* DashboardCellDelegate.swift in Sources */, - 0E290A852660E5DF009AAA29 /* Array+AnyRuuviTagSensor.swift in Sources */, - E1597A52295CD6BB00DFB70B /* DashboardViewInput.swift in Sources */, - E1B57FFE29859D1800B441FB /* DevicesViewInput.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D3520B0C45A00CDF4B6 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - A9E6775125A331D6000B75A3 /* MeasurementsServiceEnSpec.swift in Sources */, - A94FFD4C241D512900888017 /* MockLocalNotificationsManager.swift in Sources */, - A935E47625A49E8F009538C4 /* MeasurementsServiceFiSpec.swift in Sources */, - A94FFD48241C34EA00888017 /* MockAlertPersistence.swift in Sources */, - A94FFD4A241D45C600888017 /* MockRuuviTag.swift in Sources */, - A9E6775C25A331E1000B75A3 /* MeasurementsServiceSvSpec.swift in Sources */, - A935E47D25A49E9E009538C4 /* MeasurementsServiceRuSpec.swift in Sources */, - A94FFD50241D6BA300888017 /* MockAlertServiceObserver.swift in Sources */, - A9E6774B25A33081000B75A3 /* String+Characters.swift in Sources */, - A971B0DC24215334008EF50D /* XCTest+Extension.swift in Sources */, - A94FFD4E241D57E700888017 /* MockCalibrationService.swift in Sources */, - 64333D3E20B0C45A00CDF4B6 /* StationTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 64333D4020B0C45B00CDF4B6 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 0E6C471723D305960016B46E /* StationUITests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E17C469529956732008CFDD7 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E17C469C29956732008CFDD7 /* NotificationService.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 34A8D498281EBFDB008A8698 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 34A8D488281EBFD9008A8698 /* station_widgets */; - targetProxy = 34A8D497281EBFDB008A8698 /* PBXContainerItemProxy */; - }; - 34A8D4BD281EE5AE008A8698 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 34A8D4B4281EE5AE008A8698 /* station_intents */; - targetProxy = 34A8D4BC281EE5AE008A8698 /* PBXContainerItemProxy */; - }; - 34D458E72821A06E00EA9F93 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 34A8D4B4281EE5AE008A8698 /* station_intents */; - targetProxy = 34D458E62821A06E00EA9F93 /* PBXContainerItemProxy */; - }; - 34D458EB2821A07600EA9F93 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 34A8D488281EBFD9008A8698 /* station_widgets */; - targetProxy = 34D458EA2821A07600EA9F93 /* PBXContainerItemProxy */; - }; - 64333D3B20B0C45A00CDF4B6 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 64333D2420B0C45900CDF4B6 /* station */; - targetProxy = 64333D3A20B0C45A00CDF4B6 /* PBXContainerItemProxy */; - }; - 64333D4620B0C45B00CDF4B6 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 64333D2420B0C45900CDF4B6 /* station */; - targetProxy = 64333D4520B0C45B00CDF4B6 /* PBXContainerItemProxy */; - }; - E17C469F29956732008CFDD7 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = E17C469829956732008CFDD7 /* pnservice */; - targetProxy = E17C469E29956732008CFDD7 /* PBXContainerItemProxy */; - }; - E196D5B12B0137A100B60A90 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = E17C469829956732008CFDD7 /* pnservice */; - targetProxy = E196D5B02B0137A100B60A90 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 0E53A3F3232DFC6200ACED49 /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 0E53A3F2232DFC6200ACED49 /* en */, - 0E53A3F4232DFC6400ACED49 /* ru */, - 0E53A3F5232DFC6500ACED49 /* fi */, - 64A2DAE324310B2900DE6699 /* sv */, - 310159B92644864C00A5E8E8 /* fr */, - 3451BD8527E0F9880065A7A6 /* de */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; - 0EEB20C922B7A7200015F9E0 /* Localizable.strings */ = { - isa = PBXVariantGroup; - children = ( - 0EEB20C822B7A7200015F9E0 /* en */, - 0E9D0AAF231E9BD800C6BDA7 /* ru */, - 0EBAF0832320120F0025A191 /* fi */, - 64A2DAE224310B2900DE6699 /* sv */, - 310159B82644864400A5E8E8 /* fr */, - 3451BD8427E0F9870065A7A6 /* de */, - ); - name = Localizable.strings; - sourceTree = ""; - }; - 64333D3120B0C45A00CDF4B6 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 64333D3220B0C45A00CDF4B6 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; - E186AB302844A273004926FC /* RuuviWidgetsConfiguration.intentdefinition */ = { - isa = PBXVariantGroup; - children = ( - E186AB2F2844A273004926FC /* Base */, - E186AB322844A27C004926FC /* en */, - E186AB342844A27E004926FC /* fi */, - E19EAF6C299ACD95005827E4 /* de */, - E19EAF6E299ACD96005827E4 /* fr */, - E19EAF70299ACD98005827E4 /* sv */, - ); - name = RuuviWidgetsConfiguration.intentdefinition; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 0E8BD402238566AB008B31EF /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 3BC7A7F074761C1B58F7F946 /* Pods-station_dev.debug.xcconfig */; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = station/station.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 421; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 4MUYJ4YYH4; - INFOPLIST_FILE = "$(SRCROOT)/station/Resources/Plists/DevInfo.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 2.5.1; - OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS -D DEVELOPMENT"; - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.station; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - PROVISIONING_PROFILE_SPECIFIER = "match Development com.ruuvi.station"; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AdHoc com.ruuvi.station"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 0E8BD403238566AB008B31EF /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 85F06A44D8D006FBFB90ABE0 /* Pods-station_dev.release.xcconfig */; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = station/station.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 421; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 4MUYJ4YYH4; - INFOPLIST_FILE = "$(SRCROOT)/station/Resources/Plists/DevInfo.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 2.5.1; - OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS"; - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.station; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - PROVISIONING_PROFILE_SPECIFIER = "match Development com.ruuvi.station"; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AdHoc com.ruuvi.station"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 34A8D49B281EBFDB008A8698 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 5C35D73AC96D7B6765529406 /* Pods-station_widgets.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CODE_SIGN_ENTITLEMENTS = ruuvi_widgets.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 420; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 4MUYJ4YYH4; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = "ruuvi-widgets/Info.plist"; - INFOPLIST_KEY_CFBundleDisplayName = "Ruuvi Station"; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Ruuvi Innovations Oy. All rights reserved."; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - MARKETING_VERSION = 2.5.0; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.station.widgets; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match Development com.ruuvi.station.widgets"; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AdHoc com.ruuvi.station.widgets"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 34A8D49C281EBFDB008A8698 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 47B3F8D904CAAB34D68A68DC /* Pods-station_widgets.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CODE_SIGN_ENTITLEMENTS = ruuvi_widgets.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 420; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 4MUYJ4YYH4; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = "ruuvi-widgets/Info.plist"; - INFOPLIST_KEY_CFBundleDisplayName = "Ruuvi Station"; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Ruuvi Innovations Oy. All rights reserved."; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - MARKETING_VERSION = 2.5.0; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.station.widgets; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match Development com.ruuvi.station.widgets"; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AdHoc com.ruuvi.station.widgets"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 34A8D4C0281EE5AF008A8698 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 437F08C73081253CCDA3687A /* Pods-station_intents.debug.xcconfig */; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CODE_SIGN_ENTITLEMENTS = station_intents.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 420; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 4MUYJ4YYH4; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = intents/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = "Ruuvi Station"; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Ruuvi Innovations Oy. All rights reserved."; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - MARKETING_VERSION = 2.5.0; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.station.intents; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match Development com.ruuvi.station.intents"; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AdHoc com.ruuvi.station.intents"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 34A8D4C1281EE5AF008A8698 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = B5EE8D004C84A07188EF2E3A /* Pods-station_intents.release.xcconfig */; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; - CODE_SIGN_ENTITLEMENTS = station_intents.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 420; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 4MUYJ4YYH4; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = intents/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = "Ruuvi Station"; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2022 Ruuvi Innovations Oy. All rights reserved."; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - MARKETING_VERSION = 2.5.0; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.station.intents; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match Development com.ruuvi.station.intents"; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AdHoc com.ruuvi.station.intents"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 64333D4B20B0C45B00CDF4B6 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 64333D4C20B0C45B00CDF4B6 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 64333D4E20B0C45B00CDF4B6 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 50760BEF3DF7F0DC671A0D42 /* Pods-station.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = station/station.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 421; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 4MUYJ4YYH4; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "\"${PODS_CONFIGURATION_BUILD_DIR}/BTKit\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/Charts\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/FLEX\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreDiagnostics\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstanceID\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/FirebaseMessaging\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/FutureX\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/GRDB.swift\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/GestureInstructions\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransportCCTSupport\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/Humidity\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/LightRoute\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/Localize-Swift\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/Nantes\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/Protobuf\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/RangeSeekSlider\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/Realm\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/RealmSwift\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/RxSwift\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/Swinject\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/SwinjectPropertyLoader\"", - "\"${PODS_CONFIGURATION_BUILD_DIR}/nanopb\"", - "\"${PODS_ROOT}/FirebaseAnalytics/Frameworks\"", - "\"${PODS_ROOT}/GoogleAppMeasurement/Frameworks\"", - ); - INFOPLIST_FILE = "$(SRCROOT)/station/Resources/Plists/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 2.5.1; - OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS"; - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.station; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - PROVISIONING_PROFILE_SPECIFIER = "match Development com.ruuvi.station"; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AdHoc com.ruuvi.station"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 64333D4F20B0C45B00CDF4B6 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = B3426764B50E4E9CA2A27704 /* Pods-station.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_ENTITLEMENTS = station/station.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 421; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 4MUYJ4YYH4; - INFOPLIST_FILE = "$(SRCROOT)/station/Resources/Plists/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 2.5.1; - OTHER_SWIFT_FLAGS = "$(inherited) -D COCOAPODS"; - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.station; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = ""; - PROVISIONING_PROFILE_SPECIFIER = "match Development com.ruuvi.station"; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AdHoc com.ruuvi.station"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 64333D5120B0C45B00CDF4B6 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 2CFE01D4D914A918175D4BEA /* Pods-stationTests.debug.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - INFOPLIST_FILE = stationTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.stationTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/station.app/station"; - }; - name = Debug; - }; - 64333D5220B0C45B00CDF4B6 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 8825D89E1A7CB4BDC6D12038 /* Pods-stationTests.release.xcconfig */; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - INFOPLIST_FILE = stationTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.stationTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/station.app/station"; - }; - name = Release; - }; - 64333D5420B0C45B00CDF4B6 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - INFOPLIST_FILE = stationUITests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.stationUITests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_TARGET_NAME = station; - }; - name = Debug; - }; - 64333D5520B0C45B00CDF4B6 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 4MUYJ4YYH4; - INFOPLIST_FILE = stationUITests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.stationUITests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_TARGET_NAME = station; - }; - name = Release; - }; - E17C46A129956732008CFDD7 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CODE_SIGN_ENTITLEMENTS = pnservice.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 420; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 4MUYJ4YYH4; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = pnservice/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = "Ruuvi Station"; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Ruuvi Innovations Oy. All rights reserved."; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - MARKETING_VERSION = 2.5.0; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.station.pnservice; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AdHoc com.ruuvi.station.pnservice"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - E17C46A229956732008CFDD7 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CODE_SIGN_ENTITLEMENTS = pnservice.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 420; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 4MUYJ4YYH4; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = pnservice/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = "Ruuvi Station"; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 Ruuvi Innovations Oy. All rights reserved."; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - MARKETING_VERSION = 2.5.0; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.ruuvi.station.pnservice; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "match AdHoc com.ruuvi.station.pnservice"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 0E8BD401238566AB008B31EF /* Build configuration list for PBXNativeTarget "station_dev" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 0E8BD402238566AB008B31EF /* Debug */, - 0E8BD403238566AB008B31EF /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 34A8D49D281EBFDB008A8698 /* Build configuration list for PBXNativeTarget "station_widgets" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 34A8D49B281EBFDB008A8698 /* Debug */, - 34A8D49C281EBFDB008A8698 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 34A8D4BF281EE5AF008A8698 /* Build configuration list for PBXNativeTarget "station_intents" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 34A8D4C0281EE5AF008A8698 /* Debug */, - 34A8D4C1281EE5AF008A8698 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 64333D2020B0C45900CDF4B6 /* Build configuration list for PBXProject "station" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 64333D4B20B0C45B00CDF4B6 /* Debug */, - 64333D4C20B0C45B00CDF4B6 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 64333D4D20B0C45B00CDF4B6 /* Build configuration list for PBXNativeTarget "station" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 64333D4E20B0C45B00CDF4B6 /* Debug */, - 64333D4F20B0C45B00CDF4B6 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 64333D5020B0C45B00CDF4B6 /* Build configuration list for PBXNativeTarget "stationTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 64333D5120B0C45B00CDF4B6 /* Debug */, - 64333D5220B0C45B00CDF4B6 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 64333D5320B0C45B00CDF4B6 /* Build configuration list for PBXNativeTarget "stationUITests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 64333D5420B0C45B00CDF4B6 /* Debug */, - 64333D5520B0C45B00CDF4B6 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - E17C46A329956732008CFDD7 /* Build configuration list for PBXNativeTarget "pnservice" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E17C46A129956732008CFDD7 /* Debug */, - E17C46A229956732008CFDD7 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - 0EE36EAD269DC70E0021B746 /* XCRemoteSwiftPackageReference "swift-algorithms" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/apple/swift-algorithms"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.0.0; - }; - }; - 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/danielgindi/Charts.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 4.1.0; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 0EE36EAE269DC70E0021B746 /* Algorithms */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE36EAD269DC70E0021B746 /* XCRemoteSwiftPackageReference "swift-algorithms" */; - productName = Algorithms; - }; - 0EE36EB0269DC71B0021B746 /* Algorithms */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE36EAD269DC70E0021B746 /* XCRemoteSwiftPackageReference "swift-algorithms" */; - productName = Algorithms; - }; - 0EE36EB3269DC7D90021B746 /* Charts */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts" */; - productName = Charts; - }; - 0EE36EB5269DC7E40021B746 /* Charts */ = { - isa = XCSwiftPackageProductDependency; - package = 0EE36EB2269DC7D90021B746 /* XCRemoteSwiftPackageReference "Charts" */; - productName = Charts; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 64333D1D20B0C45900CDF4B6 /* Project object */; -} diff --git a/station.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/station.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100755 index 919434a62..000000000 --- a/station.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/station.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/station.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100755 index 18d981003..000000000 --- a/station.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/station.xcworkspace/contents.xcworkspacedata b/station.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 33941877f..000000000 --- a/station.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/station.xcworkspace/xcshareddata/IDETemplateMacros.plist b/station.xcworkspace/xcshareddata/IDETemplateMacros.plist deleted file mode 100644 index 508b04a54..000000000 --- a/station.xcworkspace/xcshareddata/IDETemplateMacros.plist +++ /dev/null @@ -1,14 +0,0 @@ - - - - - FILEHEADER - -// ___FILENAME___ -// ___PACKAGENAME___ -// -// Created by ___FULLUSERNAME___ on ___DATE___. -// Copyright © ___YEAR___ Ruuvi Innovations Oy. BSD-3-Clause. -// - - diff --git a/station.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/station.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d981003..000000000 --- a/station.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/station.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/station.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index 21ba9472b..000000000 --- a/station.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,10 +0,0 @@ - - - - - DisableBuildSystemDeprecationDiagnostic - - PreviewsEnabled - - - diff --git a/station.xcworkspace/xcshareddata/xcschemes/station.xcscheme b/station.xcworkspace/xcshareddata/xcschemes/station.xcscheme deleted file mode 100644 index 2bb0fb085..000000000 --- a/station.xcworkspace/xcshareddata/xcschemes/station.xcscheme +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/station.xcworkspace/xcshareddata/xcschemes/station_dev.xcscheme b/station.xcworkspace/xcshareddata/xcschemes/station_dev.xcscheme deleted file mode 100644 index 4476d324c..000000000 --- a/station.xcworkspace/xcshareddata/xcschemes/station_dev.xcscheme +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/station.xcworkspace/xcshareddata/xcschemes/station_intents.xcscheme b/station.xcworkspace/xcshareddata/xcschemes/station_intents.xcscheme deleted file mode 100644 index ed7ba1f2d..000000000 --- a/station.xcworkspace/xcshareddata/xcschemes/station_intents.xcscheme +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/station.xcworkspace/xcshareddata/xcschemes/station_widgets.xcscheme b/station.xcworkspace/xcshareddata/xcschemes/station_widgets.xcscheme deleted file mode 100644 index cdb70842d..000000000 --- a/station.xcworkspace/xcshareddata/xcschemes/station_widgets.xcscheme +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/widget_frameworks.yml b/widget.yml similarity index 100% rename from widget_frameworks.yml rename to widget.yml diff --git a/widget_spm.yml b/widget_spm.yml deleted file mode 100644 index ea6235e2e..000000000 --- a/widget_spm.yml +++ /dev/null @@ -1,56 +0,0 @@ -targets: - station.widgets: - type: app-extension - platform: iOS - info: - path: ruuvi-widgets/Info.plist - properties: - NSExtension: - NSExtensionPointIdentifier: com.apple.widgetkit-extension - UIAppFonts: [Oswald-Bold.ttf,Oswald-ExtraLight.ttf,Muli-Regular.ttf,Muli-Bold.ttf,Montserrat-Bold.ttf,Montserrat-Regular.ttf] - CFBundleDisplayName: Ruuvi Station - CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString: $(MARKETING_VERSION) - CFBundleVersion: $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright: Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. - settings: - base: - CODE_SIGN_ENTITLEMENTS: ruuvi_widgets.entitlements - configs: - Alpha: - CODE_SIGN_IDENTITY: "iPhone Distribution" - PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.widgets" - Debug: - CODE_SIGN_STYLE: Automatic - Release: - CODE_SIGN_IDENTITY: "iPhone Distribution" - PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.widgets" - EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" - sources: - - path: ruuvi-widgets - resources: - - path: station/Resources/Strings/ - dependencies: - - package: Swinject - - package: BTKit - - package: Future - - package: GRDB - - package: Humidity - - package: Realm - - package: KeychainAccess - - package: Realm - product: RealmSwift - - package: RuuviUser - - package: RuuviUser - product: RuuviUserCoordinator - - package: RuuviCloud - - package: RuuviCloud - product: RuuviCloudPure - - package: RuuviCloud - product: RuuviCloudApi - - package: RuuviOntology - - package: RuuviPool - - package: RuuviLocal - - package: RuuviPersistence - - package: RuuviContext - - package: RuuviLocalization \ No newline at end of file From 0a51f497d75f5da24cfd77a1657c314cf0bdb0cc Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Tue, 12 Dec 2023 21:26:56 +0200 Subject: [PATCH 40/84] Use Ruuvi as xcodeproj name (#1769) Motivation: branding. What: renamed frameworks xcodeproj to `Ruuvi`. --- .github/workflows/firebase.yml | 67 ++++++++---- .github/workflows/firebase_frameworks.yml | 120 ---------------------- .gitignore | 3 +- Makefile | 2 +- README.md | 4 +- project.yml | 2 +- 6 files changed, 52 insertions(+), 146 deletions(-) delete mode 100644 .github/workflows/firebase_frameworks.yml diff --git a/.github/workflows/firebase.yml b/.github/workflows/firebase.yml index b01e5a1ca..010a560ce 100644 --- a/.github/workflows/firebase.yml +++ b/.github/workflows/firebase.yml @@ -1,13 +1,21 @@ -name: Upload to Firebase +name: Deploy to Firebase [Ruuvi Station] on: - workflow_dispatch: + pull_request: + types: + - closed + branches: [alpha] jobs: build: - runs-on: macos-latest + if: github.event.pull_request.merged == true + runs-on: macos-13 steps: + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '15' + - name: Checkout repository uses: actions/checkout@v4 @@ -20,18 +28,7 @@ jobs: run: rm -rf ${{ github.workspace }}/station.localization - name: Clone localisation submodule - run: git clone -b dev https://github.com/ruuvi/station.localization.git ${{ github.workspace }}/station.localization - - - name: Cocoapods Cache - uses: actions/cache@v2 - with: - path: Pods - key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} - restore-keys: | - ${{ runner.os }}-pods- - - - name: CocoaPods Install - run: pod install + run: git clone -b master https://github.com/ruuvi/station.localization.git ${{ github.workspace }}/station.localization - name: Install the Apple certificate and provisioning profiles env: @@ -57,10 +54,33 @@ jobs: echo -n "${{ secrets.INTENTS_APP_ADHOC_PROVISION_PROFILE_BASE64 }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/match_AdHoc_com.ruuvi.station.intents.mobileprovision echo -n "${{ secrets.PNSERVICE_APP_ADHOC_PROVISION_PROFILE_BASE64 }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/match_AdHoc_com.ruuvi.station.pnservice.mobileprovision - - name: Build app + - name: Increment build number run: | - xcodebuild -workspace station.xcworkspace -scheme station_dev -configuration Debug -archivePath ./Build/Station_Dev.xcarchive archive -allowProvisioningUpdates + make set_build_number + + - name: Tools cache + uses: actions/cache@v2 + with: + path: .tools/ + key: ${{ runner.os }}-tools-${{ hashFiles('/.tools/') }} + restore-keys: | + ${{ runner.os }}-tools- + - name: Make xcodeproj + run: | + make xcodeproj + + - name: SPM Cache + uses: actions/cache@v2 + with: + path: ~/Library/Developer/Xcode/DerivedData/Ruuvi*/SourcePackages/ + key: ${{ runner.os }}-Ruuvi-${{ hashFiles('Ruuvi.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }} + restore-keys: | + ${{ runner.os }}-Ruuvi- + + - name: Build app + run: | + xcodebuild -project Ruuvi.xcodeproj -scheme station -configuration Alpha -archivePath ./Build/Station_Dev.xcarchive archive -allowProvisioningUpdates - name: Export IPA env: EXPORT_PLIST: ${{ secrets.ADHOC_EXPORT_OPTIONS }} @@ -69,14 +89,21 @@ jobs: echo -n "$EXPORT_PLIST" | base64 --decode > $EXPORT_PLIST_PATH xcodebuild -exportArchive -archivePath ./Build/Station_Dev.xcarchive -exportOptionsPlist $EXPORT_PLIST_PATH -exportPath ${{ runner.temp }}/export + - name: Build Changelog + id: build_changelog + uses: mikepenz/release-changelog-builder-action@v4.1.0 + + - name: Install firebase CLI + run: | + make installed_firebase + - name: Distribute to Firebase run: | - curl -sL https://firebase.tools | bash - firebase appdistribution:distribute ${{ runner.temp }}/export/*.ipa \ + .tools/firebase/firebase appdistribution:distribute ${{ runner.temp }}/export/*.ipa \ --app ${{ secrets.GOOGLE_APP_ID }} \ --token ${{ secrets.FIREBASE_REFRESH_TOKEN }} \ --groups ${{ secrets.ALPHA_TESTERS_GROUP }} \ - --release-notes "Features, enhancements and bug fixes." + --release-notes "${{ steps.build_changelog.outputs.changelog }}" - name: Zip dSYM files run: | diff --git a/.github/workflows/firebase_frameworks.yml b/.github/workflows/firebase_frameworks.yml deleted file mode 100644 index cebbc12c2..000000000 --- a/.github/workflows/firebase_frameworks.yml +++ /dev/null @@ -1,120 +0,0 @@ -name: Deploy to Firebase [frameworks] - -on: - pull_request: - types: - - closed - branches: [alpha] - -jobs: - build: - if: github.event.pull_request.merged == true - runs-on: macos-13 - - steps: - - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: '15' - - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup SSH - uses: webfactory/ssh-agent@v0.8.0 - with: - ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} - - - name: Remove existing localisation directory - run: rm -rf ${{ github.workspace }}/station.localization - - - name: Clone localisation submodule - run: git clone -b master https://github.com/ruuvi/station.localization.git ${{ github.workspace }}/station.localization - - - name: Install the Apple certificate and provisioning profiles - env: - BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }} - P12_PASSWORD: ${{ secrets.P12_PASSWORD }} - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} - run: | - CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 - KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db - - echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode > $CERTIFICATE_PATH - - security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH - security set-keychain-settings -lut 21600 $KEYCHAIN_PATH - security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH - - security import $CERTIFICATE_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH - security list-keychain -d user -s $KEYCHAIN_PATH - - mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles - echo -n "${{ secrets.MAIN_APP_ADHOC_PROVISION_PROFILE_BASE64 }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/match_AdHoc_com.ruuvi.station.mobileprovision - echo -n "${{ secrets.WIDGETS_APP_ADHOC_PROVISION_PROFILE_BASE64 }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/match_AdHoc_com.ruuvi.station.widgets.mobileprovision - echo -n "${{ secrets.INTENTS_APP_ADHOC_PROVISION_PROFILE_BASE64 }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/match_AdHoc_com.ruuvi.station.intents.mobileprovision - echo -n "${{ secrets.PNSERVICE_APP_ADHOC_PROVISION_PROFILE_BASE64 }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/match_AdHoc_com.ruuvi.station.pnservice.mobileprovision - - - name: Increment build number - run: | - make set_build_number - - - name: Tools cache - uses: actions/cache@v2 - with: - path: .tools/ - key: ${{ runner.os }}-tools-${{ hashFiles('/.tools/') }} - restore-keys: | - ${{ runner.os }}-tools- - - - name: Make xcodeproj - run: | - make xcodeproj - - - name: SPM Cache - uses: actions/cache@v2 - with: - path: ~/Library/Developer/Xcode/DerivedData/frameworks*/SourcePackages/ - key: ${{ runner.os }}-frameworks-${{ hashFiles('frameworks.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }} - restore-keys: | - ${{ runner.os }}-frameworks- - - - name: Build app - run: | - xcodebuild -project frameworks.xcodeproj -scheme station -configuration Alpha -archivePath ./Build/Station_Dev.xcarchive archive -allowProvisioningUpdates - - name: Export IPA - env: - EXPORT_PLIST: ${{ secrets.ADHOC_EXPORT_OPTIONS }} - run: | - EXPORT_PLIST_PATH=${{ runner.temp }}/ExportOptions.plist - echo -n "$EXPORT_PLIST" | base64 --decode > $EXPORT_PLIST_PATH - xcodebuild -exportArchive -archivePath ./Build/Station_Dev.xcarchive -exportOptionsPlist $EXPORT_PLIST_PATH -exportPath ${{ runner.temp }}/export - - - name: Build Changelog - id: build_changelog - uses: mikepenz/release-changelog-builder-action@v4.1.0 - - - name: Install firebase CLI - run: | - make installed_firebase - - - name: Distribute to Firebase - run: | - .tools/firebase/firebase appdistribution:distribute ${{ runner.temp }}/export/*.ipa \ - --app ${{ secrets.GOOGLE_APP_ID }} \ - --token ${{ secrets.FIREBASE_REFRESH_TOKEN }} \ - --groups ${{ secrets.ALPHA_TESTERS_GROUP }} \ - --release-notes "${{ steps.build_changelog.outputs.changelog }}" - - - name: Zip dSYM files - run: | - find ${{ runner.temp }}/export -name '*.dSYM' | xargs -I \{\} zip -r \{\}.zip \{\} - - - name: Upload dSYM to Firebase - run: | - find ${{ runner.temp }}/export -name '*.dSYM.zip' | xargs -I \{\} firebase crashlytics:upload-symbols --app ${{ secrets.GOOGLE_APP_ID }} -g \{\} - - - name: Clean up keychain and provisioning profiles - if: ${{ always() }} - run: | - security delete-keychain $RUNNER_TEMP/app-signing.keychain-db - rm -rf ~/Library/MobileDevice/Provisioning\ Profiles/* diff --git a/.gitignore b/.gitignore index c27536ba3..edcf80ae4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,8 +2,7 @@ .tools # Generated -spm.xcodeproj -frameworks.xcodeproj +Ruuvi.xcodeproj # Private station/Resources/Plists/GoogleService-Info.plist diff --git a/Makefile b/Makefile index d1f3cfaea..bd7da8519 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ installed_xcodegen: .tools/xcodegen/bin/xcodegen # builds station target with frameworks build configuration for iOS build: d=$$(date +%s)\ - ; xcodebuild -project frameworks.xcodeproj -scheme station -configuration Release -sdk iphoneos17.0 build\ + ; xcodebuild -project Ruuvi.xcodeproj -scheme station -configuration Release -sdk iphoneos17.0 build\ && echo "Build took $$(($$(date +%s)-d)) seconds" # sets the build number to current datetime diff --git a/README.md b/README.md index 739d9aad4..fe51a3401 100644 --- a/README.md +++ b/README.md @@ -53,10 +53,10 @@ git clone --recursive https://github.com/ruuvi/com.ruuvi.station.ios.git cd com.ruuvi.station.ios ``` -2. Make and open the `frameworks.xcodeproj` +2. Make and open the `Ruuvi.xcodeproj` ```zsh make -xed frameworks.xcodeproj +xed Ruuvi.xcodeproj ``` 3. Configure Signing diff --git a/project.yml b/project.yml index 0f223a674..61c286b08 100644 --- a/project.yml +++ b/project.yml @@ -1,6 +1,6 @@ BUILD_NUMBER: &BUILD_NUMBER 1 APP_VERSION: &APP_VERSION 2.5.2 -APP_NAME: &APP_NAME frameworks +APP_NAME: &APP_NAME Ruuvi DEVELOPMENT_TEAM: &DEVELOPMENT_TEAM 4MUYJ4YYH4 BUNDLE_ID_PREFIX: &BUNDLE_ID_PREFIX com.ruuvi From 1ddaf5f4fae4f0e241bb4356eddf1fff87177843 Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Tue, 12 Dec 2023 20:59:06 +0100 Subject: [PATCH 41/84] feature: Show cloud saving state on sensor settings #1600 --- .../ActivityPresenterRuuviLogo.swift | 3 ++ .../Sources/RuuviCloud/RuuviCloud.swift | 18 +++++++ .../RuuviCloudPure/RuuviCloudPure.swift | 30 ++++++++++- .../Presenter/TagSettingsPresenter.swift | 53 +++++++++++++++++++ 4 files changed, 102 insertions(+), 2 deletions(-) diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift index 312022224..ae77b5891 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift @@ -34,6 +34,9 @@ public extension ActivityPresenterRuuviLogo { } func update(with state: ActivityPresenterState) { + // Reset start time with state update since we want to show + // latest state message before dismissing the presenter. + startTime = CFAbsoluteTimeGetCurrent() activityPresenterViewProvider.updateState(state) } diff --git a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift index f08705581..627085a28 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift @@ -223,3 +223,21 @@ public enum MimeType: String, Codable { case gif = "image/gif" case jpg = "image/jpeg" } + +// MARK: State Observer +public extension Notification.Name { + static let RuuviCloudRequestStateDidChange = + Notification.Name("RuuviCloudRequestStateDidChange") +} + +public enum RuuviCloudRequestStateKey: String { + case state + case macId +} + +public enum RuuviCloudRequestStateType: String { + case loading + case success + case failed + case complete +} diff --git a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift index 7f289dc5c..fbb6291ef 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift @@ -53,10 +53,12 @@ public final class RuuviCloudPure: RuuviCloud { description: String?, for macId: MACIdentifier ) -> Future { + notifyListener(state: .loading, macId: macId.mac) let promise = Promise() guard let apiKey = user.apiKey else { promise.fail(error: .notAuthorized) + notifyListener(state: .failed, macId: macId.mac) return promise.future } let request = RuuviCloudApiPostAlertRequest( @@ -71,8 +73,9 @@ public final class RuuviCloudPure: RuuviCloud { timestamp: Int(Date().timeIntervalSince1970) ) api.postAlert(request, authorization: apiKey) - .on(success: { _ in + .on(success: { [weak self] _ in promise.succeed(value: ()) + self?.notifyListener(state: .success, macId: macId.mac) }, failure: { [weak self] error in let uniqueKey = macId.value + "-" + type.rawValue + "-" + settingType.rawValue self?.createQueuedRequest( @@ -82,6 +85,9 @@ public final class RuuviCloudPure: RuuviCloud { ) promise.fail(error: .api(error)) + self?.notifyListener(state: .failed, macId: macId.mac) + }, completion: { [weak self] in + self?.notifyListener(state: .complete, macId: macId.mac) }) return promise.future } @@ -676,10 +682,12 @@ public final class RuuviCloudPure: RuuviCloud { name: String, for sensor: RuuviTagSensor ) -> Future { + notifyListener(state: .loading, macId: sensor.id) let promise = Promise() guard let apiKey = user.apiKey else { promise.fail(error: .notAuthorized) + notifyListener(state: .failed, macId: sensor.id) return promise.future } let request = RuuviCloudApiSensorUpdateRequest( @@ -691,8 +699,9 @@ public final class RuuviCloudPure: RuuviCloud { timestamp: Int(Date().timeIntervalSince1970) ) api.update(request, authorization: apiKey) - .on(success: { _ in + .on(success: { [weak self] _ in promise.succeed(value: sensor.with(name: name).any) + self?.notifyListener(state: .success, macId: sensor.id) }, failure: { [weak self] error in let uniqueKey = sensor.id + "-name" self?.createQueuedRequest( @@ -701,6 +710,9 @@ public final class RuuviCloudPure: RuuviCloud { uniqueKey: uniqueKey ) promise.fail(error: .api(error)) + self?.notifyListener(state: .failed, macId: sensor.id) + }, completion: { [weak self] in + self?.notifyListener(state: .complete, macId: sensor.id) }) return promise.future } @@ -1362,6 +1374,20 @@ public final class RuuviCloudPure: RuuviCloud { ) pool?.createQueuedRequest(request) } + + private func notifyListener( + state: RuuviCloudRequestStateType, + macId: String + ) { + NotificationCenter.default.post( + name: .RuuviCloudRequestStateDidChange, + object: nil, + userInfo: [ + RuuviCloudRequestStateKey.macId: macId, + RuuviCloudRequestStateKey.state: state, + ] + ) + } } // swiftlint:enable file_length diff --git a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift index c04c5432f..b3bb33f7c 100644 --- a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift +++ b/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift @@ -18,6 +18,7 @@ import RuuviNotifier import RuuviPool import RuuviPresenters import RuuviUser +import RuuviCloud class TagSettingsPresenter: NSObject, TagSettingsModuleInput { weak var view: TagSettingsViewInput! @@ -78,6 +79,7 @@ class TagSettingsPresenter: NSObject, TagSettingsModuleInput { private var appDidBecomeActiveToken: NSObjectProtocol? private var alertDidChangeToken: NSObjectProtocol? private var backgroundToken: NSObjectProtocol? + private var cloudRequestStateToken: NSObjectProtocol? private var mutedTillTimer: Timer? private var exportFileUrl: URL? private var previousAdvertisementSequence: Int? @@ -109,6 +111,7 @@ class TagSettingsPresenter: NSObject, TagSettingsModuleInput { appDidBecomeActiveToken?.invalidate() alertDidChangeToken?.invalidate() backgroundToken?.invalidate() + cloudRequestStateToken?.invalidate() timer?.invalidate() NotificationCenter.default.removeObserver(self) } @@ -143,6 +146,7 @@ class TagSettingsPresenter: NSObject, TagSettingsModuleInput { startObservingConnectionStatus() startObservingApplicationState() startObservingAlertChanges() + startObservingCloudRequestState() startMutedTillTimer() startListeningToRuuviTagsAlertStatus() processAlerts() @@ -1139,6 +1143,30 @@ extension TagSettingsPresenter { ) } + private func startObservingCloudRequestState() { + cloudRequestStateToken?.invalidate() + cloudRequestStateToken = nil + + cloudRequestStateToken = NotificationCenter + .default + .addObserver( + forName: .RuuviCloudRequestStateDidChange, + object: nil, + queue: .main, + using: { [weak self] notification in + guard let self, + let userInfo = notification.userInfo, + let macId = userInfo[RuuviCloudRequestStateKey.macId] as? String, + macId == self.ruuviTag.macId?.value, + let state = userInfo[RuuviCloudRequestStateKey.state] as? RuuviCloudRequestStateType + else { + return + } + self.presentActivityIndicator(with: state) + } + ) + } + private func reloadMutedTill() { if let mutedTill = viewModel.temperatureAlertMutedTill.value, mutedTill < Date() { @@ -1768,6 +1796,31 @@ extension TagSettingsPresenter { localSyncState.setGattSyncDate(nil, for: ruuviTag.macId) settings.setOwnerCheckDate(for: ruuviTag.macId, value: nil) } + + private func presentActivityIndicator(with state: RuuviCloudRequestStateType) { + switch state { + case .loading: + activityPresenter.show( + with: .loading( + message: RuuviLocalization.activitySavingToCloud + ) + ) + case .success: + activityPresenter.update( + with: .success( + message: RuuviLocalization.activitySavingSuccess + ) + ) + case .failed: + activityPresenter.update( + with: .success( + message: RuuviLocalization.activitySavingFail + ) + ) + case .complete: + activityPresenter.dismiss() + } + } } extension TagSettingsPresenter { From 50d57f9e5231aca19435a0f0277dd24abcc9feb3 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Wed, 13 Dec 2023 00:15:52 +0200 Subject: [PATCH 42/84] Reorganise the project (#1772) * Move Station App and extensions to folder Apps Motivation: enabler to think on different apps made from lego modules. * fix networking plist and update localizable * fixes * beauty names of modules * modify README --- .travis.yml | 13 - .../Plists => Apps/RuuviStation}/Info.plist | 0 .../RuuviStation/Intents}/Info.plist | 0 .../Intents/Sources}/IntentHandler.swift | 0 .../Intents/Sources/Intents.entitlements | 0 .../RuuviStation/Intents/target.yml | 18 +- .../NotificationService}/Info.plist | 0 .../Sources/NotificationService.entitlements | 0 .../Sources}/NotificationService.swift | 0 .../NotificationService/target.yml | 15 +- .../Classes/Application/AppAssembly.swift | 0 .../Application/AppAssemblyConstants.swift | 2 - .../Classes/Application/AppDelegate.swift | 0 .../Application/AppGroupConstants.swift | 0 .../AppState/AppStateService.swift | 0 .../AppState/Impl/AppStateServiceImpl.swift | 0 .../Application/Features/FeatureToggle.swift | 0 .../Features/FeatureToggleService.swift | 0 .../FallbackFeatureToggleProvider.swift | 0 .../Providers/FeatureToggleProvider.swift | 0 .../FirebaseFeatureToggleProvider.swift | 0 .../LocalFeatureToggleProvider.swift | 0 .../FirebaseRemoteConfigService.swift | 0 .../RemoteConfig/RemoteConfigService.swift | 0 .../Info/Impl/InfoProviderImpl.swift | 0 .../Application/Info/InfoProvider.swift | 0 .../Impl/UniversalLinkCoordinatormpl.swift | 0 .../UniversalLinkCoordinator.swift | 0 .../Router/Impl/UniversalLinkRouterImpl.swift | 0 .../Router/UniversalLinkRouter.swift | 0 .../Presentation/Assembly/Presentation.plist | 0 .../Assembly/PresentationAssembly.swift | 0 .../Assembly/PresentationConstants.swift | 0 .../Binding/NSObject+Observable.swift | 0 .../Presentation/Binding/Observable.swift | 0 .../Presentation/Binding/Optional.swift | 0 .../Presentation/Colors/RuuviColor.swift | 0 .../Presentation/Contract/ViewInput.swift | 0 .../FLEX/FeatureTogglesViewController.swift | 0 .../Launch/Base.lproj/LaunchScreen.storyboard | 0 .../Launch/fr.lproj/LaunchScreen.strings | 0 .../Modules/About/About.storyboard | 0 .../About/Assembly/AboutConfigurator.swift | 0 .../About/Assembly/AboutInitializer.swift | 0 .../About/Presenter/AboutModuleInput.swift | 0 .../About/Presenter/AboutPresenter.swift | 0 .../Modules/About/Router/AboutRouter.swift | 0 .../About/Router/AboutRouterInput.swift | 0 .../About/View/AboutViewController.swift | 0 .../Modules/About/View/AboutViewInput.swift | 0 .../Modules/About/View/AboutViewModel.swift | 0 .../Modules/About/View/AboutViewOutput.swift | 0 .../BackgroundSelectionModuleFactory.swift | 0 .../BackgroundSelectionModuleInput.swift | 0 .../BackgroundSelectionPresenter.swift | 0 .../View/BackgroundSelectionViewInput.swift | 0 .../View/BackgroundSelectionViewModel.swift | 0 .../View/BackgroundSelectionViewOutput.swift | 0 .../UI/BackgroundSelectionButtonView.swift | 0 ...ackgroundSelectionUploadProgressView.swift | 0 .../View/UI/BackgroundSelectionViewCell.swift | 0 .../BackgroundSelectionViewController.swift | 0 .../UI/BackgroundSelectionViewHeader.swift | 0 .../Assembly/CardsViewModuleFactory.swift | 0 .../Cards/Interactor/CardsInteractor.swift | 0 .../Interactor/CardsInteractorInput.swift | 0 .../Cards/Presenter/CardsModuleInput.swift | 0 .../Cards/Presenter/CardsModuleOutput.swift | 0 .../Cards/Presenter/CardsPresenter.swift | 0 .../Dashboard/Cards/Router/CardsRouter.swift | 0 .../Cards/Router/CardsRouterDelegate.swift | 0 .../Cards/Router/CardsRouterInput.swift | 0 .../Dashboard/Cards/View/CardsViewInput.swift | 0 .../Dashboard/Cards/View/CardsViewModel.swift | 0 .../Cards/View/CardsViewOutput.swift | 0 .../Cards/View/UI/CardsBackgroundView.swift | 0 .../Cards/View/UI/CardsIndicatorView.swift | 0 .../Cards/View/UI/CardsLargeImageCell.swift | 0 .../Cards/View/UI/CardsViewController.swift | 0 .../Assembly/TagChartsModuleFactory.swift | 0 .../Assembly/TagChartsViewConfigurator.swift | 0 .../Charts/Helpers/CustomXAxisRenderer.swift | 0 .../Charts/Helpers/CustomYAxisRenderer.swift | 0 .../Charts/Helpers/TagChartsHelper.swift | 0 .../Charts/Helpers/XAxisValueFormatter.swift | 0 .../Charts/Helpers/YAxisValueFormatter.swift | 0 .../Interactor/TagChartsViewInteractor.swift | 0 .../TagChartsViewInteractorInput.swift | 0 .../TagChartsViewInteractorOutput.swift | 0 .../Presenter/TagChartsViewModuleInput.swift | 0 .../Presenter/TagChartsViewModuleOutput.swift | 0 .../Presenter/TagChartsViewPresenter.swift | 0 .../Charts/View/TagChartsViewInput.swift | 0 .../Charts/View/TagChartsViewModel.swift | 0 .../Charts/View/TagChartsViewOutput.swift | 0 .../Charts/View/UI/TagChartsMarkerView.swift | 0 .../Charts/View/UI/TagChartsView.swift | 0 .../View/UI/TagChartsViewController.swift | 0 .../Assembly/DashboardModuleFactory.swift | 0 .../Home/Interactor/DashboardInteractor.swift | 0 .../Interactor/DashboardInteractorInput.swift | 0 .../Home/Presenter/DashboardModuleInput.swift | 0 .../Home/Presenter/DashboardPresenter.swift | 0 .../Home/Router/DashboardRouter.swift | 0 .../Home/Router/DashboardRouterDelegate.swift | 0 .../Home/Router/DashboardRouterInput.swift | 0 .../Home/View/DashboardCellDelegate.swift | 0 .../Home/View/DashboardImageCell.swift | 0 .../Home/View/DashboardIndicatorView.swift | 0 .../Home/View/DashboardPlainCell.swift | 0 .../Home/View/DashboardViewController.swift | 0 .../Home/View/DashboardViewInput.swift | 0 .../Home/View/DashboardViewOutput.swift | 0 .../Dashboard/Home/View/LowBatteryView.swift | 0 .../Dashboard/Home/View/NoSensorView.swift | 0 .../Home/View/RuuviContextMenuButton.swift | 0 .../RuuviSimpleViewCompositionalLayout.swift | 0 .../Table/MenuTableConfigurator.swift | 0 .../Assembly/Table/MenuTableInitializer.swift | 0 .../Presentation/Modules/Menu/Menu.storyboard | 0 .../Menu/Presenter/MenuModuleInput.swift | 0 .../Menu/Presenter/MenuModuleOutput.swift | 0 .../Menu/Presenter/MenuPresenter.swift | 0 .../Modules/Menu/Router/MenuRouter.swift | 0 .../Modules/Menu/Router/MenuRouterInput.swift | 0 .../MenuTableDismissTransitionAnimation.swift | 0 .../MenuTablePresentTransitionAnimation.swift | 0 .../MenuTablePresentationController.swift | 0 .../Table/MenuTableTransitionManager.swift | 0 .../MenuTableTransitioningDelegate.swift | 0 .../Modules/Menu/View/MenuViewInput.swift | 0 .../Modules/Menu/View/MenuViewOutput.swift | 0 .../MenuTableEmbededViewController.swift | 0 .../View/Table/MenuTableViewController.swift | 0 .../Assembly/MyRuuviAccountConfigurator.swift | 0 .../Assembly/MyRuuviAccountInitializer.swift | 0 .../Modules/My Ruuvi/MyRuuvi.storyboard | 0 .../Presenter/MyRuuviAccountModuleInput.swift | 0 .../Presenter/MyRuuviAccountPresenter.swift | 0 .../Router/MyRuuviAccountRouter.swift | 0 .../Router/MyRuuviAccountRouterInput.swift | 0 .../View/MyRuuviAccountViewController.swift | 0 .../View/MyRuuviAccountViewInput.swift | 0 .../View/MyRuuviAccountViewModel.swift | 0 .../View/MyRuuviAccountViewOutput.swift | 0 .../Table/SettingsTableConfigurator.swift | 0 .../Table/SettingsTableInitializer.swift | 0 .../Presenter/SettingsModuleInput.swift | 0 .../Module/Presenter/SettingsPresenter.swift | 0 .../Module/Router/SettingsRouter.swift | 0 .../Module/Router/SettingsRouterInput.swift | 0 .../Settings/Module/Settings.storyboard | 0 .../Module/View/SettingsViewInput.swift | 0 .../Module/View/SettingsViewOutput.swift | 0 .../Table/SettingsTableViewController.swift | 0 .../AppearanceSettingsModuleFactory.swift | 0 .../AppearanceSettingsModuleInput.swift | 0 .../AppearanceSettingsPresenter.swift | 0 .../Router/AppearanceSettingsRouter.swift | 0 .../AppearanceSettingsRouterInput.swift | 0 .../Assembly/ASSelectionModuleFactory.swift | 0 .../Presenter/ASSelectionModuleInput.swift | 0 .../Presenter/ASSelectionPresenter.swift | 0 .../Selection/View/ASSelectionViewInput.swift | 0 .../View/ASSelectionViewOutput.swift | 0 .../View/UI/ASSelectionTableViewCell.swift | 0 .../UI/ASSelectionTableViewController.swift | 0 .../View/AppearanceSettingsViewInput.swift | 0 .../View/AppearanceSettingsViewModel.swift | 0 .../View/AppearanceSettingsViewOutput.swift | 0 ...AppearanceSettingsTableViewBasicCell.swift | 0 ...ppearanceSettingsTableViewController.swift | 0 .../Assembly/ChartSettingsConfigurator.swift | 0 .../Assembly/ChartSettingsInitializer.swift | 0 .../Submodules/Chart/ChartSettings.storyboard | 0 .../Chart/Presenter/ChartModuleInput.swift | 0 .../Presenter/ChartSettingsPresenter.swift | 0 .../Chart/Router/ChartSettingsRouter.swift | 0 .../Router/ChartSettingsRouterInput.swift | 0 .../Chart/View/ChartSettingsViewInput.swift | 0 .../Chart/View/ChartSettingsViewModel.swift | 0 .../Chart/View/ChartSettingsViewOutput.swift | 0 ...ChartSettingsDisclosureTableViewCell.swift | 0 .../ChartSettingsStepperTableViewCell.swift | 0 .../ChartSettingsSwitchTableViewCell.swift | 0 .../ChartSettingsTableViewController.swift | 0 .../Assembly/DefaultsConfigurator.swift | 0 .../Assembly/DefaultsInitializer.swift | 0 .../Submodules/Defaults/Defaults.storyboard | 0 .../Presenter/DefaultsModuleInput.swift | 0 .../Presenter/DefaultsModuleOutput.swift | 0 .../Presenter/DefaultsPresenter.swift | 0 .../Defaults/Router/DefaultsRouter.swift | 0 .../Defaults/Router/DefaultsRouterInput.swift | 0 .../View/DefaultsViewController.swift | 0 .../Defaults/View/DefaultsViewInput.swift | 0 .../Defaults/View/DefaultsViewModel.swift | 0 .../Defaults/View/DefaultsViewOutput.swift | 0 .../SwiftUI/DefaultsEnvironmentObject.swift | 0 .../Defaults/View/SwiftUI/DefaultsList.swift | 0 .../Cells/DefaultsPlainTableViewCell.swift | 0 .../Cells/DefaultsStepperTableViewCell.swift | 0 .../Cells/DefaultsSwitchTableViewCell.swift | 0 .../Table/DefaultsTableViewController.swift | 0 .../Assembly/DevicesModuleFactory.swift | 0 .../Interactor/DevicesInteractor.swift | 0 .../Interactor/DevicesInteractorInput.swift | 0 .../Interactor/DevicesInteractorOutput.swift | 0 .../Presenter/DevicesModuleInput.swift | 0 .../Devices/Presenter/DevicesPresenter.swift | 0 .../Devices/View/DevicesViewInput.swift | 0 .../Devices/View/DevicesViewModel.swift | 0 .../Devices/View/DevicesViewOutput.swift | 0 .../View/UI/DevicesTableViewCell.swift | 0 .../View/UI/DevicesTableViewController.swift | 0 .../Assembly/HeartbeatConfigurator.swift | 0 .../Assembly/HeartbeatInitializer.swift | 0 .../Submodules/Heartbeat/Heartbeat.storyboard | 0 .../Presenter/HeartbeatModuleInput.swift | 0 .../Presenter/HeartbeatPresenter.swift | 0 .../Heartbeat/Router/HeartbeatRouter.swift | 0 .../Router/HeartbeatRouterInput.swift | 0 .../View/HeartbeatViewController.swift | 0 .../Heartbeat/View/HeartbeatViewInput.swift | 0 .../Heartbeat/View/HeartbeatViewModel.swift | 0 .../Heartbeat/View/HeartbeatViewOutput.swift | 0 .../SwiftUI/HeartbeatEnvironmentObject.swift | 0 .../View/SwiftUI/HeartbeatList.swift | 0 .../Table/HeartbeatTableViewController.swift | 0 .../NotificationsSettingsModuleFactory.swift | 0 .../NotificationsSettingsModuleInput.swift | 0 .../NotificationsSettingsPresenter.swift | 0 .../Router/NotificationsSettingsRouter.swift | 0 .../NotificationsSettingsRouterInput.swift | 0 ...PushAlertSoundSelectionModuleFactory.swift | 0 .../PushAlertSoundSelectionModuleInput.swift | 0 .../PushAlertSoundSelectionPresenter.swift | 0 .../PushAlertSoundSelectionViewInput.swift | 0 .../PushAlertSoundSelectionViewModel.swift | 0 .../PushAlertSoundSelectionViewOutput.swift | 0 ...PushAlertSoundSelectionTableViewCell.swift | 0 ...ertSoundSelectionTableViewController.swift | 0 .../View/NotificationsSettingsViewInput.swift | 0 .../View/NotificationsSettingsViewModel.swift | 0 .../NotificationsSettingsViewOutput.swift | 0 .../UI/NotificationsSettingsSwitchCell.swift | 0 ...ficationsSettingsTableViewController.swift | 0 .../UI/NotificationsSettingsTextCell.swift | 0 .../Assembly/RuuviCloudModuleFactory.swift | 0 .../Presenter/RuuviCloudModuleInput.swift | 0 .../Presenter/RuuviCloudPresenter.swift | 0 .../View/RuuviCloudViewInput.swift | 0 .../View/RuuviCloudViewModel.swift | 0 .../View/RuuviCloudViewOutput.swift | 0 .../View/UI/RuuviCloudTableViewCell.swift | 0 .../UI/RuuviCloudTableViewController.swift | 0 .../Table/SelectionTableConfigurator.swift | 0 .../Table/SelectionTableInitializer.swift | 0 .../Selection/Model/SelectionItem.swift | 0 .../Presenter/SelectionModuleInput.swift | 0 .../Presenter/SelectionModuleOutput.swift | 0 .../Presenter/SelectionPresenter.swift | 0 .../Selection/Router/SelectionRouter.swift | 0 .../Router/SelectionRouterInput.swift | 0 .../Submodules/Selection/Selection.storyboard | 0 .../Selection/View/SelectionViewInput.swift | 0 .../Selection/View/SelectionViewOutput.swift | 0 .../View/Table/SelectionTableViewCell.swift | 0 .../Table/SelectionTableViewController.swift | 0 .../Table/UnitSettingsTableConfigurator.swift | 0 .../Table/UnitSettingsTableInitializer.swift | 0 .../Model/UnitSettingsItem.swift | 0 .../Presenter/UnitSettingsModuleInput.swift | 0 .../Presenter/UnitSettingsModuleOutput.swift | 0 .../Presenter/UnitSettingsPresenter.swift | 0 .../Router/UnitSettingsRouter.swift | 0 .../Router/UnitSettingsRouterInput.swift | 0 .../Unit Settings/UnitSettings.storyboard | 0 .../Table/UnitSettingsTableViewCell.swift | 0 .../UnitSettingsTableViewController.swift | 0 .../View/UnitSettingsViewInput.swift | 0 .../View/UnitSettingsViewOutput.swift | 0 .../Share/Assembly/ShareConfigurator.swift | 0 .../Share/Assembly/ShareInitializer.swift | 0 .../Share/Presenter/ShareModuleInput.swift | 0 .../Share/Presenter/ShareModuleOutput.swift | 0 .../Share/Presenter/SharePresenter.swift | 0 .../Modules/Share/Router/ShareRouter.swift | 0 .../Share/Router/ShareRouterInput.swift | 0 .../Modules/Share/Share.storyboard | 0 .../Cells/ShareDescriptionTableViewCell.swift | 0 .../Cells/ShareEmailInputTableViewCell.swift | 0 .../View/Cells/ShareEmailTableViewCell.swift | 0 .../Cells/ShareSendButtonTableViewCell.swift | 0 .../Modules/Share/View/ShareViewInput.swift | 0 .../Modules/Share/View/ShareViewModel.swift | 0 .../Modules/Share/View/ShareViewOutput.swift | 0 .../ViewController/ShareViewController.swift | 0 .../SignIn/Assembly/SignInModuleFactory.swift | 0 .../SignIn/Presenter/SignInModuleInput.swift | 0 .../SignIn/Presenter/SignInModuleOutput.swift | 0 .../SignIn/Presenter/SignInPresenter.swift | 0 .../Modules/SignIn/Router/SignInRouter.swift | 0 .../SignIn/Router/SignInRouterInput.swift | 0 .../SignInBenefitsModuleFactory.swift | 0 .../Presenter/SignInBenefitsModuleInput.swift | 0 .../SignInBenefitsModuleOutput.swift | 0 .../Presenter/SignInBenefitsPresenter.swift | 0 .../Router/SignInBenefitsRouter.swift | 0 .../Router/SignInBenefitsRouterInput.swift | 0 .../View/SignInBenefitsViewController.swift | 0 .../View/SignInBenefitsViewInput.swift | 0 .../View/SignInBenefitsViewOutput.swift | 0 .../Modules/SignIn/View/SignInViewInput.swift | 0 .../Modules/SignIn/View/SignInViewModel.swift | 0 .../SignIn/View/SignInViewOutput.swift | 0 .../View/UI/Helper/RuuviCodeTextField.swift | 0 .../SignIn/View/UI/Helper/RuuviCodeView.swift | 0 .../View/UI/Helper/SignInVerifyView.swift | 0 .../SignIn/View/UI/Helper/SignInView.swift | 0 .../SignIn/View/UI/SignInViewController.swift | 0 .../Assembly/TagSettingsModuleFactory.swift | 0 .../TagSettings/Presenter/Debouncer.swift | 0 .../Presenter/TagSettingsModuleInput.swift | 0 .../Presenter/TagSettingsModuleOutput.swift | 0 .../Presenter/TagSettingsPresenter.swift | 0 .../Router/TagSettingsRouter.swift | 0 .../Router/TagSettingsRouterInput.swift | 0 .../Submodules/DFU/DFUModuleFactory.swift | 0 .../DFU/Interactor/DFUInteractor.swift | 0 .../DFU/Interactor/DFUInteractorInput.swift | 0 .../DFU/Interactor/LatestRelease.swift | 0 .../DFU/Presenter/DFUModuleInput.swift | 0 .../DFU/Presenter/DFUPresenter.swift | 0 .../Submodules/DFU/View/DFUViewModel.swift | 0 .../DFU/View/SwiftUI/DFUUIView.swift | 0 .../SensorForceClaimModuleFactory.swift | 0 .../SensorForceClaimModuleInput.swift | 0 .../Presenter/SensorForceClaimPresenter.swift | 0 .../Router/SensorForceClaimRouter.swift | 0 .../Router/SensorForceClaimRouterInput.swift | 0 .../View/SensorForceClaimViewInput.swift | 0 .../View/SensorForceClaimViewOutput.swift | 0 .../UI/SensorForceClaimViewController.swift | 0 .../OffsetCorrectionAppleInitializer.swift | 0 .../Apple/OffsetCorrectionConfigurator.swift | 0 .../OffsetCorrection.storyboard | 0 .../OffsetCorrectionModuleInput.swift | 0 .../OffsetCorrectionModuleOutput.swift | 0 .../Presenter/OffsetCorrectionPresenter.swift | 0 .../Router/OffsetCorrectionRouter.swift | 0 .../Router/OffsetCorrectionRouterInput.swift | 0 .../OffsetCorrectionAppleViewController.swift | 0 .../View/OffsetCorrectionViewInput.swift | 0 .../View/OffsetCorrectionViewModel.swift | 0 .../View/OffsetCorrectionViewOutput.swift | 0 .../Owner/Assembly/OwnerConfigurator.swift | 0 .../Owner/Assembly/OwnerInitializer.swift | 0 .../Submodules/Owner/Owner.storyboard | 0 .../Owner/Presenter/OwnerModuleInput.swift | 0 .../Owner/Presenter/OwnerPresenter.swift | 0 .../Submodules/Owner/Router/OwnerRouter.swift | 0 .../Owner/Router/OwnerRouterInput.swift | 0 .../Owner/View/OwnerViewController.swift | 0 .../Owner/View/OwnerViewInput.swift | 0 .../Owner/View/OwnerViewOutput.swift | 0 .../Assembly/SensorRemovalModuleFactory.swift | 0 .../Presenter/SensorRemovalModuleInput.swift | 0 .../Presenter/SensorRemovalModuleOutput.swift | 0 .../Presenter/SensorRemovalPresenter.swift | 0 .../Removal/Router/SensorRemovalRouter.swift | 0 .../Router/SensorRemovalRouterInput.swift | 0 .../Removal/View/SensorRemovalViewInput.swift | 0 .../View/SensorRemovalViewOutput.swift | 0 .../View/UI/SensorRemovalViewController.swift | 0 .../View/TagSettingsViewInput.swift | 0 .../View/TagSettingsViewModel.swift | 0 .../View/TagSettingsViewOutput.swift | 0 .../RUAlertDetailsCellChildView.swift | 0 .../RUAlertExpandButton.swift | 0 .../RangeSeekSlider/RURangeSeekSlider.swift | 0 .../View/UI/TagSettingsAlertConfigCell.swift | 0 .../TagSettingsBackgroundSelectionView.swift | 0 .../View/UI/TagSettingsBasicCell.swift | 0 .../TagSettingsExpandableSectionHeader.swift | 0 .../View/UI/TagSettingsFooterCell.swift | 0 .../View/UI/TagSettingsPlainCell.swift | 0 .../UI/TagSettingsSimpleSectionHeader.swift | 0 .../View/UI/TagSettingsSwitchCell.swift | 0 .../View/UI/TagSettingsViewController.swift | 0 .../Presenters/Alert/AlertPresenter.swift | 0 .../Alert/Impl/AlertPresenterImpl.swift | 0 .../Alert/ViewModel/AlertViewModel.swift | 0 .../MailComposer/MailComposerPresenter.swift | 0 .../MailComposerPresenterMessageUI.swift | 0 .../PhotoPicker/PhotoPickerPresenter.swift | 0 .../Sheet/PhotoPickerPresenterSheet.swift | 0 ...peDownToDismissInteractiveTransition.swift | 0 ...ipeDownToDismissNavigationController.swift | 0 ...wipeDownToDismissTransitionAnimation.swift | 0 ...peDownToDismissTransitioningDelegate.swift | 0 .../Sources}/Classes/Routers/AppRouter.swift | 0 .../Classes/Routers/DiscoverRouter.swift | 0 .../Classes/Routers/OnboardRouter.swift | 0 .../Extensions/Array+AnyRuuviTagSensor.swift | 0 .../Sources}/Extensions/CALayer+IB.swift | 0 .../Classess/AppDateFormatter.swift | 0 .../Classess/RuuviCustomButton.swift | 0 .../Classess/RuuviLinkTextView.swift | 0 .../Extensions/Classess/RuuviUISwitch.swift | 0 .../Sources}/Extensions/Color+Ruuvi.swift | 0 .../Sources}/Extensions/Date+Ruuvi.swift | 0 .../Sources}/Extensions/DfuFirmware+Log.swift | 0 .../Extensions/Double+Extension.swift | 0 .../Extensions/Double+Temperature.swift | 0 .../Sources}/Extensions/Errors/RUError.swift | 0 .../RuuviCloudApiError+LocalizedError.swift | 0 .../RuuviCloudError+LocalizedError.swift | 0 .../RuuviCoreError+LocalizedError.swift | 0 .../Errors/RuuviDFUError+LocalizedError.swift | 0 .../RuuviDaemonError+LocalizedError.swift | 0 .../RuuviLocalError+LocalizedError.swift | 0 ...RuuviPersistenceError+LocalizedError.swift | 0 .../RuuviPoolError+LocalizedError.swift | 0 .../RuuviReactorError+LocalizedError.swift | 0 .../RuuviRepositoryError+LocalizedError.swift | 0 .../RuuviServiceError+LocalizedError.swift | 0 .../RuuviStorageError+LocalizedError.swift | 0 .../Extensions/FileManager+Date.swift | 0 .../Sources}/Extensions/Humidity+Offset.swift | 0 .../HumidityUnit+Localization.swift | 0 .../Sources}/Extensions/Int+Extension.swift | 0 .../Extensions/Language+Localization.swift | 0 .../MeasurementAccuracyType+Extension.swift | 0 .../Sources}/Extensions/MeasurementType.swift | 0 .../NSObjectProtocol+Invalidation.swift | 0 .../RuuviAlertSound+Extension.swift | 0 .../Extensions/RuuviTheme+Extension.swift | 0 .../Extensions/String+Characters.swift | 0 .../Sources}/Extensions/String+Email.swift | 0 .../Sources}/Extensions/String+Replace.swift | 0 .../Structs/AppStoreReviewHelper.swift | 0 .../Extensions/Structs/AppUtility.swift | 0 .../Structs/ExportHeadersProvider.swift | 0 .../Extensions/Structs/GlobalHelpers.swift | 0 .../Structs/HeartbeatDaemonTitles.swift | 0 .../Structs/MeasurementAccuracyTitles.swift | 0 .../Structs/RuuviNotifierTitlesImpl.swift | 0 .../RuuviTagBatteryStatusProvider.swift | 0 .../TemperatureUnit+Localization.swift | 0 .../UIApplication+ViewController.swift | 0 .../Extensions/UIButton+Extension.swift | 0 .../UICollectionView+Extension.swift | 0 .../Extensions/UIColor+Extension.swift | 0 .../Extensions/UIDevice+ReadableModel.swift | 0 .../Extensions/UIFont+Extension.swift | 0 .../Extensions/UIImage+Extension.swift | 0 .../Extensions/UIImageView+Init.swift | 0 .../Extensions/UINavigationController.swift | 0 .../UITableViewCell+ReusableView.swift | 0 .../Extensions/UITextField+Extension.swift | 0 .../Extensions/UIView+Extension.swift | 0 .../Sources}/Extensions/UIView+Init.swift | 0 .../Sources}/Extensions/UIView+Layout.swift | 0 .../Extensions/UIViewController+Alert.swift | 0 .../Extensions/UIWindow+Orientation.swift | 0 .../Sources}/Extensions/UIWindow+Shake.swift | 0 .../Extensions/UnitPressure+Extension.swift | 0 .../Extensions/UnitSettingsType.swift | 0 .../Extensions/UserDefaults+Optional.swift | 0 .../Resources/Assets/RuuviAssets.swift | 0 .../Colors/Colors.xcassets}/Contents.json | 0 .../RuuviDashboardBG.colorset/Contents.json | 0 .../Contents.json | 0 .../Contents.json | 0 .../Contents.json | 0 .../RuuviDustyBlue.colorset/Contents.json | 0 .../RuuviGraphBGColor.colorset/Contents.json | 0 .../Contents.json | 0 .../Contents.json | 0 .../Contents.json | 0 .../RuuviGreen.colorset/Contents.json | 0 .../RuuviLineColor.colorset/Contents.json | 0 .../RuuviLogoTintColor.colorset/Contents.json | 0 .../RuuviMenuTextColor.colorset/Contents.json | 0 .../RuuviMenuTintColor.colorset/Contents.json | 0 .../RuuviOrangeColor.colorset/Contents.json | 0 .../RuuviPrimary.colorset/Contents.json | 0 .../RuuviPurple.colorset/Contents.json | 0 .../RuuviSecondary.colorset/Contents.json | 0 .../Contents.json | 0 .../Contents.json | 0 .../Contents.json | 0 .../RuuviTextColor.colorset/Contents.json | 0 .../RuuviTintColor.colorset/Contents.json | 0 .../Contents.json | 0 .../Contents.json | 0 .../Resources/Fonts/Montserrat-Bold.ttf | Bin .../Resources/Fonts/Montserrat-ExtraBold.ttf | Bin .../Resources/Fonts/Montserrat-Regular.ttf | Bin .../Sources}/Resources/Fonts/Muli-Bold.ttf | Bin .../Resources/Fonts/Muli-ExtraBold.ttf | Bin .../Sources}/Resources/Fonts/Muli-Regular.ttf | Bin .../Resources/Fonts/Muli-SemiBoldItalic.ttf | Bin .../Sources}/Resources/Fonts/Oswald-Bold.ttf | Bin .../Resources/Fonts/Oswald-ExtraLight.ttf | Bin .../AppIcon.appiconset/Contents.json | 0 .../AppIcon.appiconset/Icon-20.png | Bin .../AppIcon.appiconset/Icon-20@2x-1.png | Bin .../AppIcon.appiconset/Icon-20@2x.png | Bin .../AppIcon.appiconset/Icon-20@3x.png | Bin .../AppIcon.appiconset/Icon-29.png | Bin .../AppIcon.appiconset/Icon-29@2x-1.png | Bin .../AppIcon.appiconset/Icon-29@2x.png | Bin .../AppIcon.appiconset/Icon-29@3x.png | Bin .../AppIcon.appiconset/Icon-40.png | Bin .../AppIcon.appiconset/Icon-40@2x-1.png | Bin .../AppIcon.appiconset/Icon-40@2x.png | Bin .../AppIcon.appiconset/Icon-40@3x.png | Bin .../AppIcon.appiconset/Icon-60@2x.png | Bin .../AppIcon.appiconset/Icon-60@3x.png | Bin .../AppIcon.appiconset/Icon-76.png | Bin .../AppIcon.appiconset/Icon-76@2x.png | Bin .../AppIcon.appiconset/Icon-83.5@2x.png | Bin .../AppIcon.appiconset/iTunesArtwork@2x.png | Bin .../Images}/Assets.xcassets/Contents.json | 0 .../Default Backgrounds}/Contents.json | 0 .../bg1.imageset/Contents.json | 0 .../Default Backgrounds/bg1.imageset/bg1.jpg | Bin .../bg10.imageset/Contents.json | 0 .../bg10.imageset/new_bg5.jpeg | Bin .../bg11.imageset/Contents.json | 0 .../bg11.imageset/new_bg6.jpeg | Bin .../bg12.imageset/Contents.json | 0 .../bg12.imageset/new_bg7.jpeg | Bin .../bg13.imageset/Contents.json | 0 .../bg13.imageset/new_bg8.jpeg | Bin .../bg14.imageset/Contents.json | 0 .../bg14.imageset/new_bg9.jpeg | Bin .../bg15.imageset/Contents.json | 0 .../bg15.imageset/new_bg10.jpeg | Bin .../bg16.imageset/Contents.json | 0 .../bg16.imageset/new_bg2.jpg | Bin .../bg2.imageset/Contents.json | 0 .../Default Backgrounds/bg2.imageset/bg2.jpg | Bin .../bg3.imageset/Contents.json | 0 .../Default Backgrounds/bg3.imageset/bg3.jpg | Bin .../bg4.imageset/Contents.json | 0 .../Default Backgrounds/bg4.imageset/bg4.jpg | Bin .../bg5.imageset/Contents.json | 0 .../Default Backgrounds/bg5.imageset/bg5.jpg | Bin .../bg6.imageset/Contents.json | 0 .../Default Backgrounds/bg6.imageset/bg6.jpg | Bin .../bg7.imageset/Contents.json | 0 .../Default Backgrounds/bg7.imageset/bg7.jpg | Bin .../bg8.imageset/Contents.json | 0 .../Default Backgrounds/bg8.imageset/bg8.jpg | Bin .../bg9.imageset/Contents.json | 0 .../Default Backgrounds/bg9.imageset/bg9.jpg | Bin .../arrow_drop_down.imageset/Contents.json | 0 .../arrow_drop_down.svg | 0 .../Contents.json | 0 ...eline_keyboard_backspace_white_48pt_1x.png | Bin ...eline_keyboard_backspace_white_48pt_2x.png | Bin ...eline_keyboard_backspace_white_48pt_3x.png | Bin .../Contents.json | 0 .../baseline_menu_white_48pt_1x.png | Bin .../baseline_menu_white_48pt_2x.png | Bin .../baseline_menu_white_48pt_3x.png | Bin .../Contents.json | 0 .../baseline_settings_white_48pt_1x.png | Bin .../baseline_settings_white_48pt_2x.png | Bin .../baseline_settings_white_48pt_3x.png | Bin .../beaver-mail.imageset/Contents.json | 0 .../beaver-mail.imageset/beaver-mail.png | Bin .../Contents.json | 0 .../bluetooth_connected-24px.pdf | Bin .../Contents.json | 0 .../bluetooth_disabled_black_108x108.png | Bin .../bluetooth_icon.imageset/Contents.json | 0 .../bluetooth_white_108x108.png | Bin .../checkmark_icon.imageset/Contents.json | 0 ...seline_check_circle_outline_black_18dp.png | Bin .../chevron.down.imageset/Contents.json | 0 .../chevron.down.imageset/chevron.down.pdf | Bin .../chevron.up.imageset/Contents.json | 0 .../chevron.up.imageset/chevron.up.pdf | Bin .../chevron_back.imageset/Contents.json | 0 .../chevron_back.imageset/chevron_back.png | Bin .../chevron_back.imageset/chevron_back@2x.png | Bin .../chevron_back.imageset/chevron_back@3x.png | Bin .../dismiss-modal-icon.imageset/Contents.json | 0 .../dismiss-modal-icon.imageset/down.png | Bin .../dismiss-modal-icon.imageset/down@2x.png | Bin .../dismiss-modal-icon.imageset/down@3x.png | Bin .../edit_pen.imageset/Contents.json | 0 .../edit_pen.imageset/edit_pen.svg | 0 .../eye_circle.imageset/Contents.json | 0 .../eye_circle.imageset/eye_circle.png | Bin .../Contents.json | 0 .../gesture-assistant-hand.imageset/hand.pdf | Bin .../gradient_layer.imageset/Contents.json | 0 .../gradient_layer.png | Bin .../ic_refresh.imageset/Contents.json | 0 .../ic_refresh.imageset/ic_refresh_24px.pdf | Bin .../icon-alert-active.imageset/Contents.json | 0 .../icon-alert-active.imageset/active.pdf | Bin .../icon-alert-off.imageset/Contents.json | 0 .../icon-alert-off.imageset/alert-off.pdf | Bin .../icon-alert-on.imageset/Contents.json | 0 .../icon-alert-on.imageset/alert-on.pdf | Bin .../icon-bg-camera.imageset/Contents.json | 0 .../icon-bg-camera-1.pdf | Bin .../Contents.json | 0 .../icon-bluetooth-connected.pdf | Bin .../icon-bluetooth.imageset/Contents.json | 0 .../icon-bluetooth.pdf | Bin .../icon-cards-button.imageset/Contents.json | 0 .../icon-cards-button.imageset/vector.pdf | Bin .../icon-charts-button.imageset/Contents.json | 0 .../icon-charts-button.imageset/vector-3.pdf | Bin .../icon-connectable.imageset/Contents.json | 0 .../icons8-connected-1.png | Bin .../icons8-connected-2.png | Bin .../icons8-connected.png | Bin .../icon-connection-1.imageset/Contents.json | 0 .../icon-connection-1.png | Bin .../icon-connection-2.imageset/Contents.json | 0 .../icon-connection-2.png | Bin .../icon-connection-3.imageset/Contents.json | 0 .../icon-connection-3.png | Bin .../Contents.json | 0 .../delete_forever_48px.pdf | Bin .../icon-download.imageset/Contents.json | 0 .../icon-download.imageset/download.pdf | Bin .../icon-gateway.imageset/Contents.json | 0 .../icon-gateway.imageset/icon-gateway.pdf | Bin .../Contents.json | 0 .../icon-measure-humidity.png | Bin .../Contents.json | 0 .../icon-measure.png | Bin .../icon-measure@2x.png | Bin .../icon_measure@3x.png | Bin .../Contents.json | 0 .../icon-measure-movement.pdf | Bin .../Contents.json | 0 .../icon-measure-pressure.png | Bin .../Contents.json | 0 .../icon-measure-signal.png | Bin .../icon-refresh.imageset/Contents.json | 0 .../icon-refresh.imageset/sync_48px.pdf | Bin .../icon-warning.imageset/Contents.json | 0 .../icon-warning.imageset/warning-sign.pdf | Bin .../Contents.json | 0 .../icon-weatherstation.pdf | Bin .../icon_back_arrow.imageset/Contents.json | 0 .../icon_back_arrow.imageset/icons8-back.pdf | Bin .../icon_sync_bt.imageset/Contents.json | 0 .../icon_sync_bt.imageset/icon_sync_bt.png | Bin .../iphone_icon.imageset/Contents.json | 0 .../iphone_icon.imageset/phone_black.png | Bin .../Contents.json | 0 .../location-picker-pin-icon.png | Bin .../location-picker-pin-icon@2x.png | Bin .../location-picker-pin-icon@3x.png | Bin .../more_3dot.imageset/Contents.json | 0 .../more_3dot.imageset/more_3dot.pdf | Bin .../no-image.imageset/Contents.json | 0 .../no-image.imageset/icons8-no_image.pdf | Bin .../plus_icon.imageset/Contents.json | 0 .../icons8-plus-math-filled-100.png | Bin .../ruuvi_logo_.imageset/Contents.json | 0 .../ruuvi_logo_.imageset}/ruuvi_logo.png | Bin .../Contents.json | 0 .../web-ruuvi-eye-nega.pdf | Bin .../ruuvi_station.imageset/Contents.json | 0 .../ruuvi_station.imageset/ruuvi_station.png | Bin .../ruuvi_station_2x.png | Bin .../ruuvi_station_3x.png | Bin .../sign_in_bg_layer.imageset/Contents.json | 0 .../bg_layer_dark.jpg | Bin .../Contents.json | 0 .../baseline_clear_black_36pt_1x.png | Bin .../baseline_clear_black_36pt_2x.png | Bin .../baseline_clear_black_36pt_3x.png | Bin .../Contents.json | 0 .../info_icon.png | Bin .../tag_bg_layer.imageset/Contents.json | 0 .../tag_bg_layer.imageset/tag_bg_layer.png | Bin .../welcome_friend.imageset/Contents.json | 0 .../title-welcome1x.png | Bin .../title-welcome2x.png | Bin .../title-welcome3x.png | Bin .../Resources/Images/ruuvi_logo_splash.png | Bin .../Resources/Images/splash_bg_layer_dark.jpg | Bin .../Resources/JSONs/FeatureToggles.json | 0 .../Resources/Plists/GoogleService-Info.plist | 0 .../Resources/Plists/Networking.plist | 2 - .../Plists/iOSDeviceModelMapping.plist | 0 .../Sources}/Resources/Sounds/ruuvi_speak.caf | Bin .../Strings/de.lproj/InfoPlist.strings | 0 .../Strings/en.lproj/InfoPlist.strings | 0 .../Strings/fi.lproj/InfoPlist.strings | 0 .../Strings/fr.lproj/InfoPlist.strings | 0 .../Strings/ru.lproj/InfoPlist.strings | 0 .../Strings/sv.lproj/InfoPlist.strings | 0 .../RuuviStation/Sources/Station.entitlements | 0 .../Unit}/Extensions/XCTest+Extension.swift | 0 .../RuuviStation/Tests/Unit}/Info.plist | 0 .../Tests/Unit}/MockAlertPersistence.swift | 0 .../Unit}/MockAlertServiceObserver.swift | 0 .../Tests/Unit}/MockCalibrationService.swift | 0 .../Unit}/MockLocalNotificationsManager.swift | 0 .../Tests/Unit}/MockRuuviTag.swift | 0 .../Services/Alert/AlertServiceSpec.swift | 0 .../MeasurementsServiceEnSpec.swift | 0 .../MeasurementsServiceFiSpec.swift | 0 .../MeasurementsServiceRuSpec.swift | 0 .../MeasurementsServiceSvSpec.swift | 0 .../Tests/Unit}/StationTests.swift | 0 .../RuuviStation/Widgets}/Info.plist | 0 .../Sources}/Assembly/WidgetAssembly.swift | 0 .../AccentColor.colorset/Contents.json | 0 .../AppIcon.appiconset/Contents.json | 0 .../BackgroundColor.colorset/Contents.json | 0 .../BodyTextColor.colorset/Contents.json | 0 .../Assets.xcassets/Colors}/Contents.json | 0 .../Colors/LogoColor.colorset/Contents.json | 0 .../SensorNameColor1.colorset/Contents.json | 0 .../SensorNameColor2.colorset/Contents.json | 0 .../UnitTextColor.colorset/Contents.json | 0 .../Sources/Assets.xcassets}/Contents.json | 0 .../eye_circle.imageset/Contents.json | 0 .../web-ruuvi-eye-nega.png | Bin .../ruuvi_logo.imageset/Contents.json | 0 .../ruuvi_logo.imageset}/ruuvi_logo.png | Bin ...RuuviWidgetsConfiguration.intentdefinition | 0 .../Sources}/Enum/WidgetSensorEnum.swift | 0 .../Widgets/Sources}/Helper/Constants.swift | 0 .../Widgets/Sources}/Helper/Extensions.swift | 0 .../Sources}/Helper/MeasurementService.swift | 0 .../Sources}/Helper/NetworkManager.swift | 0 Apps/RuuviStation/Widgets/Sources/Info.plist | 40 + .../Sources}/Model/Model+Extension.swift | 0 .../Widgets/Sources}/Model/WidgetEntry.swift | 0 .../Sources}/Provider/WidgetProvider.swift | 0 .../Resources/Fonts/Montserrat-Bold.ttf | Bin .../Resources/Fonts/Montserrat-Regular.ttf | Bin .../Sources}/Resources/Fonts/Muli-Bold.ttf | Bin .../Sources}/Resources/Fonts/Muli-Regular.ttf | Bin .../Sources}/Resources/Fonts/Oswald-Bold.ttf | Bin .../Resources/Fonts/Oswald-ExtraLight.ttf | Bin .../Widgets/Sources}/RuuviWidgets.swift | 0 .../Sources}/View Model/WidgetViewModel.swift | 0 .../Sources}/View/EmptyWidgetView.swift | 0 .../Sources}/View/SimpleWidgetView.swift | 0 .../View/SimpleWidgetViewCircular.swift | 0 .../View/SimpleWidgetViewInline.swift | 0 .../View/SimpleWidgetViewRectangle.swift | 0 .../Sources}/View/UnauthorizedView.swift | 0 .../Widgets/Sources/Widgets.entitlements | 0 .../RuuviWidgetsConfiguration.strings | 0 .../RuuviWidgetsConfiguration.strings | 0 .../RuuviWidgetsConfiguration.strings | 0 .../RuuviWidgetsConfiguration.strings | 0 .../RuuviWidgetsConfiguration.strings | 0 .../RuuviStation/Widgets/target.yml | 15 +- Apps/RuuviStation/target.yml | 138 + .../RuuviLocalization/RuuviLocalization.swift | 4514 ++++++++--------- Common/RuuviLocalization/target.yml | 3 + Common/RuuviPresenters/target.yml | 3 + Modules/RuuviDiscover/target.yml | 3 + Modules/RuuviFirmware/target.yml | 3 + Modules/RuuviOnboard/target.yml | 3 + Packages/RuuviAnalytics/target.yml | 3 + Packages/RuuviCloud/target.yml | 3 + Packages/RuuviContext/target.yml | 3 + Packages/RuuviCore/target.yml | 3 + Packages/RuuviDFU/target.yml | 3 + Packages/RuuviDaemon/target.yml | 3 + Packages/RuuviLocal/target.yml | 3 + Packages/RuuviMigration/target.yml | 3 + Packages/RuuviNotification/target.yml | 3 + Packages/RuuviNotifier/target.yml | 3 + Packages/RuuviOntology/target.yml | 3 + Packages/RuuviPersistence/target.yml | 3 + Packages/RuuviPool/target.yml | 3 + Packages/RuuviReactor/target.yml | 3 + Packages/RuuviRepository/target.yml | 3 + Packages/RuuviService/target.yml | 3 + Packages/RuuviStorage/target.yml | 3 + Packages/RuuviUser/target.yml | 3 + README.md | 5 +- project.yml | 187 +- station/Resources/Plists/DevInfo.plist | 97 - stationUITests/Info.plist | 22 - stationUITests/StationUITests.swift | 9 - 797 files changed, 2353 insertions(+), 2793 deletions(-) delete mode 100644 .travis.yml rename {station/Resources/Plists => Apps/RuuviStation}/Info.plist (100%) rename {intents => Apps/RuuviStation/Intents}/Info.plist (100%) rename {intents => Apps/RuuviStation/Intents/Sources}/IntentHandler.swift (100%) rename ruuvi_widgets.entitlements => Apps/RuuviStation/Intents/Sources/Intents.entitlements (100%) rename intents.yml => Apps/RuuviStation/Intents/target.yml (85%) rename {pnservice => Apps/RuuviStation/NotificationService}/Info.plist (100%) rename pnservice.entitlements => Apps/RuuviStation/NotificationService/Sources/NotificationService.entitlements (100%) rename {pnservice => Apps/RuuviStation/NotificationService/Sources}/NotificationService.swift (100%) rename pnservice.yml => Apps/RuuviStation/NotificationService/target.yml (76%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/AppAssembly.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/AppAssemblyConstants.swift (84%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/AppDelegate.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/AppGroupConstants.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/AppState/AppStateService.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/AppState/Impl/AppStateServiceImpl.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/Features/FeatureToggle.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/Features/FeatureToggleService.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/Features/Providers/FallbackFeatureToggleProvider.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/Features/Providers/FeatureToggleProvider.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/Features/Providers/FirebaseFeatureToggleProvider.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/Features/Providers/LocalFeatureToggleProvider.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/Features/RemoteConfig/Firebase/FirebaseRemoteConfigService.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/Features/RemoteConfig/RemoteConfigService.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/Info/Impl/InfoProviderImpl.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/Info/InfoProvider.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/UniversalLinks/Coordinator/Impl/UniversalLinkCoordinatormpl.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/UniversalLinks/Coordinator/UniversalLinkCoordinator.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/UniversalLinks/Router/Impl/UniversalLinkRouterImpl.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Application/UniversalLinks/Router/UniversalLinkRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Assembly/Presentation.plist (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Assembly/PresentationAssembly.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Assembly/PresentationConstants.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Binding/NSObject+Observable.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Binding/Observable.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Binding/Optional.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Colors/RuuviColor.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Contract/ViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/FLEX/FeatureTogglesViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Launch/Base.lproj/LaunchScreen.storyboard (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Launch/fr.lproj/LaunchScreen.strings (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/About/About.storyboard (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/About/Assembly/AboutConfigurator.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/About/Assembly/AboutInitializer.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/About/Presenter/AboutModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/About/Router/AboutRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/About/Router/AboutRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/About/View/AboutViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/About/View/AboutViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/About/View/AboutViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/About/View/AboutViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Background/Assembly/BackgroundSelectionModuleFactory.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Cards/Assembly/CardsViewModuleFactory.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractor.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractorInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouterDelegate.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsIndicatorView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsModuleFactory.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsViewConfigurator.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/Helpers/XAxisValueFormatter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractor.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractorInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouterDelegate.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/View/DashboardCellDelegate.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/View/RuuviContextMenuButton.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Dashboard/Home/View/RuuviSimpleViewCompositionalLayout.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableConfigurator.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableInitializer.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/Menu.storyboard (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/Presenter/MenuModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/Presenter/MenuModuleOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/Presenter/MenuPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/Router/MenuRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/Router/MenuRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableDismissTransitionAnimation.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentTransitionAnimation.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentationController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitionManager.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitioningDelegate.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/View/MenuViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/View/MenuViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountConfigurator.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountInitializer.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/My Ruuvi/MyRuuvi.storyboard (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/My Ruuvi/Router/MyRuuviAccountRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/My Ruuvi/Router/MyRuuviAccountRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableConfigurator.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableInitializer.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Module/Settings.storyboard (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Module/View/SettingsViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Module/View/SettingsViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/Assembly/AppearanceSettingsModuleFactory.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Assembly/ASSelectionModuleFactory.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/ASSelectionViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/ASSelectionViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/AppearanceSettingsViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/AppearanceSettingsViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/AppearanceSettingsViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Chart/Assembly/ChartSettingsConfigurator.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Chart/Assembly/ChartSettingsInitializer.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Chart/ChartSettings.storyboard (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Chart/Router/ChartSettingsRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Chart/Router/ChartSettingsRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsDisclosureTableViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsSwitchTableViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/Assembly/DefaultsConfigurator.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/Assembly/DefaultsInitializer.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/Defaults.storyboard (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsModuleOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/Router/DefaultsRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/Router/DefaultsRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsEnvironmentObject.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsList.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsPlainTableViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsStepperTableViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsSwitchTableViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Devices/Assembly/DevicesModuleFactory.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Devices/Interactor/DevicesInteractor.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Devices/Interactor/DevicesInteractorInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Devices/Interactor/DevicesInteractorOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Devices/Presenter/DevicesModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Devices/Presenter/DevicesPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Assembly/HeartbeatConfigurator.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Assembly/HeartbeatInitializer.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Heartbeat.storyboard (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Presenter/HeartbeatModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Presenter/HeartbeatPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Router/HeartbeatRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Router/HeartbeatRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatEnvironmentObject.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/Assembly/NotificationsSettingsModuleFactory.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Assembly/PushAlertSoundSelectionModuleFactory.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/PushAlertSoundSelectionViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/PushAlertSoundSelectionViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/PushAlertSoundSelectionViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Assembly/RuuviCloudModuleFactory.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Selection/Assembly/Table/SelectionTableConfigurator.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Selection/Assembly/Table/SelectionTableInitializer.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Selection/Model/SelectionItem.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionModuleOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Selection/Router/SelectionRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Selection/Router/SelectionRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Selection/Selection.storyboard (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Selection/View/SelectionViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Selection/View/SelectionViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Assembly/Table/UnitSettingsTableConfigurator.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Assembly/Table/UnitSettingsTableInitializer.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Model/UnitSettingsItem.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsModuleOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Router/UnitSettingsRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Router/UnitSettingsRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/UnitSettings.storyboard (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/UnitSettingsViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/UnitSettingsViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Share/Assembly/ShareConfigurator.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Share/Assembly/ShareInitializer.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Share/Presenter/ShareModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Share/Presenter/ShareModuleOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Share/Router/ShareRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Share/Router/ShareRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Share/Share.storyboard (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Share/View/Cells/ShareDescriptionTableViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Share/View/Cells/ShareEmailInputTableViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Share/View/Cells/ShareEmailTableViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Share/View/Cells/ShareSendButtonTableViewCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Share/View/ShareViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Share/View/ShareViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Share/View/ShareViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/Assembly/SignInModuleFactory.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/Presenter/SignInModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/Presenter/SignInModuleOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/Router/SignInRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/Router/SignInRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Assembly/SignInBenefitsModuleFactory.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsModuleOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Router/SignInBenefitsRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Router/SignInBenefitsRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/View/SignInViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/View/SignInViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/View/SignInViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeTextField.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Assembly/TagSettingsModuleFactory.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Presenter/Debouncer.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/DFU/DFUModuleFactory.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractorInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/LatestRelease.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Assembly/SensorForceClaimModuleFactory.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Router/SensorForceClaimRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Router/SensorForceClaimRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/SensorForceClaimViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/SensorForceClaimViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionAppleInitializer.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionConfigurator.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/OffsetCorrection.storyboard (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionModuleOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Router/OffsetCorrectionRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Router/OffsetCorrectionRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerConfigurator.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerInitializer.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Owner.storyboard (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Assembly/SensorRemovalModuleFactory.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalModuleInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalModuleOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Router/SensorRemovalRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Router/SensorRemovalRouterInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/SensorRemovalViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/SensorRemovalViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewInput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewOutput.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/View/UI/RangeSeekSlider/RURangeSeekSlider.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsFooterCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Presenters/Alert/AlertPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Presenters/Alert/ViewModel/AlertViewModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Presenters/MailComposer/MailComposerPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Presenters/MailComposer/MessageUI/MailComposerPresenterMessageUI.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Presenters/PhotoPicker/PhotoPickerPresenter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Presenters/PhotoPicker/Sheet/PhotoPickerPresenterSheet.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissInteractiveTransition.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissNavigationController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitionAnimation.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitioningDelegate.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Routers/AppRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Routers/DiscoverRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Classes/Routers/OnboardRouter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Array+AnyRuuviTagSensor.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/CALayer+IB.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Classess/AppDateFormatter.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Classess/RuuviCustomButton.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Classess/RuuviLinkTextView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Classess/RuuviUISwitch.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Color+Ruuvi.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Date+Ruuvi.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/DfuFirmware+Log.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Double+Extension.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Double+Temperature.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Errors/RUError.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Errors/RuuviCloudApiError+LocalizedError.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Errors/RuuviCloudError+LocalizedError.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Errors/RuuviCoreError+LocalizedError.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Errors/RuuviDFUError+LocalizedError.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Errors/RuuviDaemonError+LocalizedError.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Errors/RuuviLocalError+LocalizedError.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Errors/RuuviPoolError+LocalizedError.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Errors/RuuviReactorError+LocalizedError.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Errors/RuuviRepositoryError+LocalizedError.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Errors/RuuviServiceError+LocalizedError.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Errors/RuuviStorageError+LocalizedError.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/FileManager+Date.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Humidity+Offset.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/HumidityUnit+Localization.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Int+Extension.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Language+Localization.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/MeasurementAccuracyType+Extension.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/MeasurementType.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/NSObjectProtocol+Invalidation.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/RuuviAlertSound+Extension.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/RuuviTheme+Extension.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/String+Characters.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/String+Email.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/String+Replace.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Structs/AppStoreReviewHelper.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Structs/AppUtility.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Structs/ExportHeadersProvider.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Structs/GlobalHelpers.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Structs/HeartbeatDaemonTitles.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Structs/MeasurementAccuracyTitles.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Structs/RuuviNotifierTitlesImpl.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/Structs/RuuviTagBatteryStatusProvider.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/TemperatureUnit+Localization.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UIApplication+ViewController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UIButton+Extension.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UICollectionView+Extension.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UIColor+Extension.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UIDevice+ReadableModel.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UIFont+Extension.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UIImage+Extension.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UIImageView+Init.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UINavigationController.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UITableViewCell+ReusableView.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UITextField+Extension.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UIView+Extension.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UIView+Init.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UIView+Layout.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UIViewController+Alert.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UIWindow+Orientation.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UIWindow+Shake.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UnitPressure+Extension.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UnitSettingsType.swift (100%) rename {station => Apps/RuuviStation/Sources}/Extensions/UserDefaults+Optional.swift (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Assets/RuuviAssets.swift (100%) rename {ruuvi-widgets/Assets.xcassets/Colors => Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets}/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviDashboardBG.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviDashboardCardBG.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviDashboardIndicator.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviDashboardIndicatorBig.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviDustyBlue.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviGraphBGColor.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviGraphFillColor.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviGraphLineColor.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviGraphMarkerColor.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviGreen.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviLineColor.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviLogoTintColor.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviMenuTextColor.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviMenuTintColor.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviOrangeColor.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviPrimary.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviPurple.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviSecondary.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviSwitchDisabledThumbTint.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviSwitchDisabledTint.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviSwitchEnabledTint.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviTextColor.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/RuuviTintColor.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/TagSettingsItemHeaderColor.colorset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Colors/Colors.xcassets/TagSettingsSectionHeaderColor.colorset/Contents.json (100%) rename {ruuvi-widgets => Apps/RuuviStation/Sources}/Resources/Fonts/Montserrat-Bold.ttf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Fonts/Montserrat-ExtraBold.ttf (100%) rename {ruuvi-widgets => Apps/RuuviStation/Sources}/Resources/Fonts/Montserrat-Regular.ttf (100%) rename {ruuvi-widgets => Apps/RuuviStation/Sources}/Resources/Fonts/Muli-Bold.ttf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Fonts/Muli-ExtraBold.ttf (100%) rename {ruuvi-widgets => Apps/RuuviStation/Sources}/Resources/Fonts/Muli-Regular.ttf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Fonts/Muli-SemiBoldItalic.ttf (100%) rename {ruuvi-widgets => Apps/RuuviStation/Sources}/Resources/Fonts/Oswald-Bold.ttf (100%) rename {ruuvi-widgets => Apps/RuuviStation/Sources}/Resources/Fonts/Oswald-ExtraLight.ttf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20@2x-1.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40@2x-1.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-76.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/AppIcon.appiconset/iTunesArtwork@2x.png (100%) rename {ruuvi-widgets => Apps/RuuviStation/Sources/Resources/Images}/Assets.xcassets/Contents.json (100%) rename {station/Resources/Colors/Colors.xcassets => Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds}/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg1.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg1.imageset/bg1.jpg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg10.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg10.imageset/new_bg5.jpeg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg11.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg11.imageset/new_bg6.jpeg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg12.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg12.imageset/new_bg7.jpeg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg13.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg13.imageset/new_bg8.jpeg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg14.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg14.imageset/new_bg9.jpeg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg15.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg15.imageset/new_bg10.jpeg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg16.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg16.imageset/new_bg2.jpg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg2.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg2.imageset/bg2.jpg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg3.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg3.imageset/bg3.jpg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg4.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg4.imageset/bg4.jpg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg5.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg5.imageset/bg5.jpg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg6.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg6.imageset/bg6.jpg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg7.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg7.imageset/bg7.jpg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg8.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg8.imageset/bg8.jpg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg9.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/Default Backgrounds/bg9.imageset/bg9.jpg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/arrow_drop_down.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/arrow_drop_down.imageset/arrow_drop_down.svg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_1x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_2x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_3x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_1x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_2x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_3x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_1x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_2x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_3x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/beaver-mail.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/beaver-mail.imageset/beaver-mail.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/bluetooth-connected.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/bluetooth-connected.imageset/bluetooth_connected-24px.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/bluetooth_disabled_icon.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/bluetooth_disabled_icon.imageset/bluetooth_disabled_black_108x108.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/bluetooth_icon.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/bluetooth_icon.imageset/bluetooth_white_108x108.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/checkmark_icon.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/checkmark_icon.imageset/baseline_check_circle_outline_black_18dp.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/chevron.down.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/chevron.down.imageset/chevron.down.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/chevron.up.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/chevron.up.imageset/chevron.up.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/chevron_back.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back@2x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back@3x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down@2x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down@3x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/edit_pen.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/edit_pen.imageset/edit_pen.svg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/eye_circle.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/eye_circle.imageset/eye_circle.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/gesture-assistant-hand.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/gesture-assistant-hand.imageset/hand.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/gradient_layer.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/gradient_layer.imageset/gradient_layer.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/ic_refresh.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/ic_refresh.imageset/ic_refresh_24px.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-alert-active.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-alert-active.imageset/active.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-alert-off.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-alert-off.imageset/alert-off.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-alert-on.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-alert-on.imageset/alert-on.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-bg-camera.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-bg-camera.imageset/icon-bg-camera-1.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-bluetooth-connected.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-bluetooth-connected.imageset/icon-bluetooth-connected.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-bluetooth.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-bluetooth.imageset/icon-bluetooth.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-cards-button.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-cards-button.imageset/vector.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-charts-button.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-charts-button.imageset/vector-3.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-connectable.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected-1.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected-2.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-connection-1.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-connection-1.imageset/icon-connection-1.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-connection-2.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-connection-2.imageset/icon-connection-2.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-connection-3.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-connection-3.imageset/icon-connection-3.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-delete-forever.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-delete-forever.imageset/delete_forever_48px.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-download.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-download.imageset/download.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-gateway.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-gateway.imageset/icon-gateway.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-measure-humidity.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-measure-humidity.imageset/icon-measure-humidity.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-measure-location.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon-measure.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon-measure@2x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon_measure@3x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-measure-movement.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-measure-movement.imageset/icon-measure-movement.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-measure-pressure.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-measure-pressure.imageset/icon-measure-pressure.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-measure-signal.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-measure-signal.imageset/icon-measure-signal.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-refresh.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-refresh.imageset/sync_48px.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-warning.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-warning.imageset/warning-sign.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-weatherstation.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon-weatherstation.imageset/icon-weatherstation.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon_back_arrow.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon_back_arrow.imageset/icons8-back.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon_sync_bt.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/icon_sync_bt.imageset/icon_sync_bt.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/iphone_icon.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/iphone_icon.imageset/phone_black.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@2x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@3x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/more_3dot.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/more_3dot.imageset/more_3dot.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/no-image.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/no-image.imageset/icons8-no_image.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/plus_icon.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/plus_icon.imageset/icons8-plus-math-filled-100.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset/Contents.json (100%) rename {ruuvi-widgets/Assets.xcassets/ruuvi_logo.imageset => Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset}/ruuvi_logo.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/web-ruuvi-eye-nega.pdf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/ruuvi_station.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station_2x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station_3x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/sign_in_bg_layer.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/sign_in_bg_layer.imageset/bg_layer_dark.jpg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_1x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_2x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_3x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/tag-settings-info-icon.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/tag-settings-info-icon.imageset/info_icon.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/tag_bg_layer.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/tag_bg_layer.imageset/tag_bg_layer.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/welcome_friend.imageset/Contents.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome1x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome2x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome3x.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/ruuvi_logo_splash.png (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Images/splash_bg_layer_dark.jpg (100%) rename {station => Apps/RuuviStation/Sources}/Resources/JSONs/FeatureToggles.json (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Plists/GoogleService-Info.plist (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Plists/Networking.plist (81%) rename {station => Apps/RuuviStation/Sources}/Resources/Plists/iOSDeviceModelMapping.plist (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Sounds/ruuvi_speak.caf (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Strings/de.lproj/InfoPlist.strings (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Strings/en.lproj/InfoPlist.strings (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Strings/fi.lproj/InfoPlist.strings (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Strings/fr.lproj/InfoPlist.strings (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Strings/ru.lproj/InfoPlist.strings (100%) rename {station => Apps/RuuviStation/Sources}/Resources/Strings/sv.lproj/InfoPlist.strings (100%) rename station/station.entitlements => Apps/RuuviStation/Sources/Station.entitlements (100%) rename {stationTests => Apps/RuuviStation/Tests/Unit}/Extensions/XCTest+Extension.swift (100%) rename {stationTests => Apps/RuuviStation/Tests/Unit}/Info.plist (100%) rename {stationTests => Apps/RuuviStation/Tests/Unit}/MockAlertPersistence.swift (100%) rename {stationTests => Apps/RuuviStation/Tests/Unit}/MockAlertServiceObserver.swift (100%) rename {stationTests => Apps/RuuviStation/Tests/Unit}/MockCalibrationService.swift (100%) rename {stationTests => Apps/RuuviStation/Tests/Unit}/MockLocalNotificationsManager.swift (100%) rename {stationTests => Apps/RuuviStation/Tests/Unit}/MockRuuviTag.swift (100%) rename {stationTests => Apps/RuuviStation/Tests/Unit}/Services/Alert/AlertServiceSpec.swift (100%) rename {stationTests => Apps/RuuviStation/Tests/Unit}/Services/MeasurementsService/MeasurementsServiceEnSpec.swift (100%) rename {stationTests => Apps/RuuviStation/Tests/Unit}/Services/MeasurementsService/MeasurementsServiceFiSpec.swift (100%) rename {stationTests => Apps/RuuviStation/Tests/Unit}/Services/MeasurementsService/MeasurementsServiceRuSpec.swift (100%) rename {stationTests => Apps/RuuviStation/Tests/Unit}/Services/MeasurementsService/MeasurementsServiceSvSpec.swift (100%) rename {stationTests => Apps/RuuviStation/Tests/Unit}/StationTests.swift (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets}/Info.plist (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Assembly/WidgetAssembly.swift (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Assets.xcassets/AccentColor.colorset/Contents.json (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Assets.xcassets/Colors/BackgroundColor.colorset/Contents.json (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Assets.xcassets/Colors/BodyTextColor.colorset/Contents.json (100%) rename {station/Resources/Images/Assets.xcassets => Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors}/Contents.json (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Assets.xcassets/Colors/LogoColor.colorset/Contents.json (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Assets.xcassets/Colors/SensorNameColor1.colorset/Contents.json (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Assets.xcassets/Colors/SensorNameColor2.colorset/Contents.json (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Assets.xcassets/Colors/UnitTextColor.colorset/Contents.json (100%) rename {station/Resources/Images/Assets.xcassets/Default Backgrounds => Apps/RuuviStation/Widgets/Sources/Assets.xcassets}/Contents.json (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Assets.xcassets/eye_circle.imageset/Contents.json (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Assets.xcassets/eye_circle.imageset/web-ruuvi-eye-nega.png (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Assets.xcassets/ruuvi_logo.imageset/Contents.json (100%) rename {station/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset => Apps/RuuviStation/Widgets/Sources/Assets.xcassets/ruuvi_logo.imageset}/ruuvi_logo.png (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Base.lproj/RuuviWidgetsConfiguration.intentdefinition (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Enum/WidgetSensorEnum.swift (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Helper/Constants.swift (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Helper/Extensions.swift (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Helper/MeasurementService.swift (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Helper/NetworkManager.swift (100%) create mode 100644 Apps/RuuviStation/Widgets/Sources/Info.plist rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Model/Model+Extension.swift (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Model/WidgetEntry.swift (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/Provider/WidgetProvider.swift (100%) rename {station => Apps/RuuviStation/Widgets/Sources}/Resources/Fonts/Montserrat-Bold.ttf (100%) rename {station => Apps/RuuviStation/Widgets/Sources}/Resources/Fonts/Montserrat-Regular.ttf (100%) rename {station => Apps/RuuviStation/Widgets/Sources}/Resources/Fonts/Muli-Bold.ttf (100%) rename {station => Apps/RuuviStation/Widgets/Sources}/Resources/Fonts/Muli-Regular.ttf (100%) rename {station => Apps/RuuviStation/Widgets/Sources}/Resources/Fonts/Oswald-Bold.ttf (100%) rename {station => Apps/RuuviStation/Widgets/Sources}/Resources/Fonts/Oswald-ExtraLight.ttf (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/RuuviWidgets.swift (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/View Model/WidgetViewModel.swift (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/View/EmptyWidgetView.swift (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/View/SimpleWidgetView.swift (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/View/SimpleWidgetViewCircular.swift (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/View/SimpleWidgetViewInline.swift (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/View/SimpleWidgetViewRectangle.swift (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/View/UnauthorizedView.swift (100%) rename station_intents.entitlements => Apps/RuuviStation/Widgets/Sources/Widgets.entitlements (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/de.lproj/RuuviWidgetsConfiguration.strings (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/en.lproj/RuuviWidgetsConfiguration.strings (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/fi.lproj/RuuviWidgetsConfiguration.strings (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/fr.lproj/RuuviWidgetsConfiguration.strings (100%) rename {ruuvi-widgets => Apps/RuuviStation/Widgets/Sources}/sv.lproj/RuuviWidgetsConfiguration.strings (100%) rename widget.yml => Apps/RuuviStation/Widgets/target.yml (86%) create mode 100644 Apps/RuuviStation/target.yml delete mode 100644 station/Resources/Plists/DevInfo.plist delete mode 100644 stationUITests/Info.plist delete mode 100644 stationUITests/StationUITests.swift diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4e0477610..000000000 --- a/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: swift -osx_image: xcode11.6 -xcode_workspace: station.xcworkspace -xcode_scheme: station -script: - - xcodebuild clean build -sdk iphonesimulator -workspace station.xcworkspace -scheme station CODE_SIGNING_REQUIRED=NO | xcpretty -branches: - only: - - master -before_install: - - bundle install - - pod repo update - - pod install diff --git a/station/Resources/Plists/Info.plist b/Apps/RuuviStation/Info.plist similarity index 100% rename from station/Resources/Plists/Info.plist rename to Apps/RuuviStation/Info.plist diff --git a/intents/Info.plist b/Apps/RuuviStation/Intents/Info.plist similarity index 100% rename from intents/Info.plist rename to Apps/RuuviStation/Intents/Info.plist diff --git a/intents/IntentHandler.swift b/Apps/RuuviStation/Intents/Sources/IntentHandler.swift similarity index 100% rename from intents/IntentHandler.swift rename to Apps/RuuviStation/Intents/Sources/IntentHandler.swift diff --git a/ruuvi_widgets.entitlements b/Apps/RuuviStation/Intents/Sources/Intents.entitlements similarity index 100% rename from ruuvi_widgets.entitlements rename to Apps/RuuviStation/Intents/Sources/Intents.entitlements diff --git a/intents.yml b/Apps/RuuviStation/Intents/target.yml similarity index 85% rename from intents.yml rename to Apps/RuuviStation/Intents/target.yml index 070846e13..e7fb5fd84 100644 --- a/intents.yml +++ b/Apps/RuuviStation/Intents/target.yml @@ -1,9 +1,10 @@ +--- targets: station.intents: type: app-extension platform: iOS info: - path: intents/Info.plist + path: Info.plist properties: NSExtension: NSExtensionAttributes: @@ -19,7 +20,7 @@ targets: NSHumanReadableCopyright: Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. settings: base: - CODE_SIGN_ENTITLEMENTS: station_intents.entitlements + CODE_SIGN_ENTITLEMENTS: Apps/RuuviStation/Intents/Sources/Intents.entitlements configs: Alpha: CODE_SIGN_IDENTITY: "iPhone Distribution" @@ -32,10 +33,15 @@ targets: CODE_SIGN_IDENTITY: "iPhone Distribution" PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.intents" sources: - - path: intents - - path: ruuvi-widgets - excludes: - - Info.plist + - path: Sources + name: Intents + excludes: + - "*.entitlements" + - Info.plist + - path: ../Widgets/Sources/ + excludes: + - "*.entitlements" + - Info.plist dependencies: - package: Swinject - package: BTKit diff --git a/pnservice/Info.plist b/Apps/RuuviStation/NotificationService/Info.plist similarity index 100% rename from pnservice/Info.plist rename to Apps/RuuviStation/NotificationService/Info.plist diff --git a/pnservice.entitlements b/Apps/RuuviStation/NotificationService/Sources/NotificationService.entitlements similarity index 100% rename from pnservice.entitlements rename to Apps/RuuviStation/NotificationService/Sources/NotificationService.entitlements diff --git a/pnservice/NotificationService.swift b/Apps/RuuviStation/NotificationService/Sources/NotificationService.swift similarity index 100% rename from pnservice/NotificationService.swift rename to Apps/RuuviStation/NotificationService/Sources/NotificationService.swift diff --git a/pnservice.yml b/Apps/RuuviStation/NotificationService/target.yml similarity index 76% rename from pnservice.yml rename to Apps/RuuviStation/NotificationService/target.yml index cac393f9b..9e36cde40 100644 --- a/pnservice.yml +++ b/Apps/RuuviStation/NotificationService/target.yml @@ -1,9 +1,10 @@ +--- targets: station.pnservice: type: app-extension platform: iOS info: - path: pnservice/Info.plist + path: Info.plist properties: NSExtension: NSExtensionPointIdentifier: com.apple.usernotifications.service @@ -15,7 +16,7 @@ targets: NSHumanReadableCopyright: Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. settings: base: - CODE_SIGN_ENTITLEMENTS: pnservice.entitlements + CODE_SIGN_ENTITLEMENTS: Apps/RuuviStation/NotificationService/Sources/NotificationService.entitlements configs: Alpha: CODE_SIGN_IDENTITY: "iPhone Distribution" @@ -28,7 +29,11 @@ targets: CODE_SIGN_IDENTITY: "iPhone Distribution" PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.pnservice" sources: - - path: pnservice + - path: Sources + name: NotificationService + excludes: + - "*.entitlements" + - Info.plist resources: - - path: station/Resources/Strings/ - - path: station/Resources/Sounds/ \ No newline at end of file + - path: ../Sources/Resources/Strings/ + - path: ../Sources/Resources/Sounds/ \ No newline at end of file diff --git a/station/Classes/Application/AppAssembly.swift b/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift similarity index 100% rename from station/Classes/Application/AppAssembly.swift rename to Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift diff --git a/station/Classes/Application/AppAssemblyConstants.swift b/Apps/RuuviStation/Sources/Classes/Application/AppAssemblyConstants.swift similarity index 84% rename from station/Classes/Application/AppAssemblyConstants.swift rename to Apps/RuuviStation/Sources/Classes/Application/AppAssemblyConstants.swift index a01aa429d..f5741582d 100644 --- a/station/Classes/Application/AppAssemblyConstants.swift +++ b/Apps/RuuviStation/Sources/Classes/Application/AppAssemblyConstants.swift @@ -1,7 +1,6 @@ import Foundation struct Networking: Codable { - var OpenWeatherMapAPIKey: String var RuuviCloudURL: String var RuuviCloudURLDev: String } @@ -11,7 +10,6 @@ enum AppAssemblyConstants { static let xml = FileManager.default.contents(atPath: networkingPath)! static let networkingPlist = try! PropertyListDecoder().decode(Networking.self, from: xml) - static let openWeatherMapApiKey = networkingPlist.OpenWeatherMapAPIKey static let ruuviCloudUrl = networkingPlist.RuuviCloudURL static let ruuviCloudUrlDev = networkingPlist.RuuviCloudURLDev static let simpleWidgetKindId = "ruuvi.simpleWidget" diff --git a/station/Classes/Application/AppDelegate.swift b/Apps/RuuviStation/Sources/Classes/Application/AppDelegate.swift similarity index 100% rename from station/Classes/Application/AppDelegate.swift rename to Apps/RuuviStation/Sources/Classes/Application/AppDelegate.swift diff --git a/station/Classes/Application/AppGroupConstants.swift b/Apps/RuuviStation/Sources/Classes/Application/AppGroupConstants.swift similarity index 100% rename from station/Classes/Application/AppGroupConstants.swift rename to Apps/RuuviStation/Sources/Classes/Application/AppGroupConstants.swift diff --git a/station/Classes/Application/AppState/AppStateService.swift b/Apps/RuuviStation/Sources/Classes/Application/AppState/AppStateService.swift similarity index 100% rename from station/Classes/Application/AppState/AppStateService.swift rename to Apps/RuuviStation/Sources/Classes/Application/AppState/AppStateService.swift diff --git a/station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift b/Apps/RuuviStation/Sources/Classes/Application/AppState/Impl/AppStateServiceImpl.swift similarity index 100% rename from station/Classes/Application/AppState/Impl/AppStateServiceImpl.swift rename to Apps/RuuviStation/Sources/Classes/Application/AppState/Impl/AppStateServiceImpl.swift diff --git a/station/Classes/Application/Features/FeatureToggle.swift b/Apps/RuuviStation/Sources/Classes/Application/Features/FeatureToggle.swift similarity index 100% rename from station/Classes/Application/Features/FeatureToggle.swift rename to Apps/RuuviStation/Sources/Classes/Application/Features/FeatureToggle.swift diff --git a/station/Classes/Application/Features/FeatureToggleService.swift b/Apps/RuuviStation/Sources/Classes/Application/Features/FeatureToggleService.swift similarity index 100% rename from station/Classes/Application/Features/FeatureToggleService.swift rename to Apps/RuuviStation/Sources/Classes/Application/Features/FeatureToggleService.swift diff --git a/station/Classes/Application/Features/Providers/FallbackFeatureToggleProvider.swift b/Apps/RuuviStation/Sources/Classes/Application/Features/Providers/FallbackFeatureToggleProvider.swift similarity index 100% rename from station/Classes/Application/Features/Providers/FallbackFeatureToggleProvider.swift rename to Apps/RuuviStation/Sources/Classes/Application/Features/Providers/FallbackFeatureToggleProvider.swift diff --git a/station/Classes/Application/Features/Providers/FeatureToggleProvider.swift b/Apps/RuuviStation/Sources/Classes/Application/Features/Providers/FeatureToggleProvider.swift similarity index 100% rename from station/Classes/Application/Features/Providers/FeatureToggleProvider.swift rename to Apps/RuuviStation/Sources/Classes/Application/Features/Providers/FeatureToggleProvider.swift diff --git a/station/Classes/Application/Features/Providers/FirebaseFeatureToggleProvider.swift b/Apps/RuuviStation/Sources/Classes/Application/Features/Providers/FirebaseFeatureToggleProvider.swift similarity index 100% rename from station/Classes/Application/Features/Providers/FirebaseFeatureToggleProvider.swift rename to Apps/RuuviStation/Sources/Classes/Application/Features/Providers/FirebaseFeatureToggleProvider.swift diff --git a/station/Classes/Application/Features/Providers/LocalFeatureToggleProvider.swift b/Apps/RuuviStation/Sources/Classes/Application/Features/Providers/LocalFeatureToggleProvider.swift similarity index 100% rename from station/Classes/Application/Features/Providers/LocalFeatureToggleProvider.swift rename to Apps/RuuviStation/Sources/Classes/Application/Features/Providers/LocalFeatureToggleProvider.swift diff --git a/station/Classes/Application/Features/RemoteConfig/Firebase/FirebaseRemoteConfigService.swift b/Apps/RuuviStation/Sources/Classes/Application/Features/RemoteConfig/Firebase/FirebaseRemoteConfigService.swift similarity index 100% rename from station/Classes/Application/Features/RemoteConfig/Firebase/FirebaseRemoteConfigService.swift rename to Apps/RuuviStation/Sources/Classes/Application/Features/RemoteConfig/Firebase/FirebaseRemoteConfigService.swift diff --git a/station/Classes/Application/Features/RemoteConfig/RemoteConfigService.swift b/Apps/RuuviStation/Sources/Classes/Application/Features/RemoteConfig/RemoteConfigService.swift similarity index 100% rename from station/Classes/Application/Features/RemoteConfig/RemoteConfigService.swift rename to Apps/RuuviStation/Sources/Classes/Application/Features/RemoteConfig/RemoteConfigService.swift diff --git a/station/Classes/Application/Info/Impl/InfoProviderImpl.swift b/Apps/RuuviStation/Sources/Classes/Application/Info/Impl/InfoProviderImpl.swift similarity index 100% rename from station/Classes/Application/Info/Impl/InfoProviderImpl.swift rename to Apps/RuuviStation/Sources/Classes/Application/Info/Impl/InfoProviderImpl.swift diff --git a/station/Classes/Application/Info/InfoProvider.swift b/Apps/RuuviStation/Sources/Classes/Application/Info/InfoProvider.swift similarity index 100% rename from station/Classes/Application/Info/InfoProvider.swift rename to Apps/RuuviStation/Sources/Classes/Application/Info/InfoProvider.swift diff --git a/station/Classes/Application/UniversalLinks/Coordinator/Impl/UniversalLinkCoordinatormpl.swift b/Apps/RuuviStation/Sources/Classes/Application/UniversalLinks/Coordinator/Impl/UniversalLinkCoordinatormpl.swift similarity index 100% rename from station/Classes/Application/UniversalLinks/Coordinator/Impl/UniversalLinkCoordinatormpl.swift rename to Apps/RuuviStation/Sources/Classes/Application/UniversalLinks/Coordinator/Impl/UniversalLinkCoordinatormpl.swift diff --git a/station/Classes/Application/UniversalLinks/Coordinator/UniversalLinkCoordinator.swift b/Apps/RuuviStation/Sources/Classes/Application/UniversalLinks/Coordinator/UniversalLinkCoordinator.swift similarity index 100% rename from station/Classes/Application/UniversalLinks/Coordinator/UniversalLinkCoordinator.swift rename to Apps/RuuviStation/Sources/Classes/Application/UniversalLinks/Coordinator/UniversalLinkCoordinator.swift diff --git a/station/Classes/Application/UniversalLinks/Router/Impl/UniversalLinkRouterImpl.swift b/Apps/RuuviStation/Sources/Classes/Application/UniversalLinks/Router/Impl/UniversalLinkRouterImpl.swift similarity index 100% rename from station/Classes/Application/UniversalLinks/Router/Impl/UniversalLinkRouterImpl.swift rename to Apps/RuuviStation/Sources/Classes/Application/UniversalLinks/Router/Impl/UniversalLinkRouterImpl.swift diff --git a/station/Classes/Application/UniversalLinks/Router/UniversalLinkRouter.swift b/Apps/RuuviStation/Sources/Classes/Application/UniversalLinks/Router/UniversalLinkRouter.swift similarity index 100% rename from station/Classes/Application/UniversalLinks/Router/UniversalLinkRouter.swift rename to Apps/RuuviStation/Sources/Classes/Application/UniversalLinks/Router/UniversalLinkRouter.swift diff --git a/station/Classes/Presentation/Assembly/Presentation.plist b/Apps/RuuviStation/Sources/Classes/Presentation/Assembly/Presentation.plist similarity index 100% rename from station/Classes/Presentation/Assembly/Presentation.plist rename to Apps/RuuviStation/Sources/Classes/Presentation/Assembly/Presentation.plist diff --git a/station/Classes/Presentation/Assembly/PresentationAssembly.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Assembly/PresentationAssembly.swift similarity index 100% rename from station/Classes/Presentation/Assembly/PresentationAssembly.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Assembly/PresentationAssembly.swift diff --git a/station/Classes/Presentation/Assembly/PresentationConstants.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Assembly/PresentationConstants.swift similarity index 100% rename from station/Classes/Presentation/Assembly/PresentationConstants.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Assembly/PresentationConstants.swift diff --git a/station/Classes/Presentation/Binding/NSObject+Observable.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Binding/NSObject+Observable.swift similarity index 100% rename from station/Classes/Presentation/Binding/NSObject+Observable.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Binding/NSObject+Observable.swift diff --git a/station/Classes/Presentation/Binding/Observable.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Binding/Observable.swift similarity index 100% rename from station/Classes/Presentation/Binding/Observable.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Binding/Observable.swift diff --git a/station/Classes/Presentation/Binding/Optional.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Binding/Optional.swift similarity index 100% rename from station/Classes/Presentation/Binding/Optional.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Binding/Optional.swift diff --git a/station/Classes/Presentation/Colors/RuuviColor.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Colors/RuuviColor.swift similarity index 100% rename from station/Classes/Presentation/Colors/RuuviColor.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Colors/RuuviColor.swift diff --git a/station/Classes/Presentation/Contract/ViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Contract/ViewInput.swift similarity index 100% rename from station/Classes/Presentation/Contract/ViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Contract/ViewInput.swift diff --git a/station/Classes/Presentation/FLEX/FeatureTogglesViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/FLEX/FeatureTogglesViewController.swift similarity index 100% rename from station/Classes/Presentation/FLEX/FeatureTogglesViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/FLEX/FeatureTogglesViewController.swift diff --git a/station/Classes/Presentation/Launch/Base.lproj/LaunchScreen.storyboard b/Apps/RuuviStation/Sources/Classes/Presentation/Launch/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from station/Classes/Presentation/Launch/Base.lproj/LaunchScreen.storyboard rename to Apps/RuuviStation/Sources/Classes/Presentation/Launch/Base.lproj/LaunchScreen.storyboard diff --git a/station/Classes/Presentation/Launch/fr.lproj/LaunchScreen.strings b/Apps/RuuviStation/Sources/Classes/Presentation/Launch/fr.lproj/LaunchScreen.strings similarity index 100% rename from station/Classes/Presentation/Launch/fr.lproj/LaunchScreen.strings rename to Apps/RuuviStation/Sources/Classes/Presentation/Launch/fr.lproj/LaunchScreen.strings diff --git a/station/Classes/Presentation/Modules/About/About.storyboard b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/About.storyboard similarity index 100% rename from station/Classes/Presentation/Modules/About/About.storyboard rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/About.storyboard diff --git a/station/Classes/Presentation/Modules/About/Assembly/AboutConfigurator.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Assembly/AboutConfigurator.swift similarity index 100% rename from station/Classes/Presentation/Modules/About/Assembly/AboutConfigurator.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Assembly/AboutConfigurator.swift diff --git a/station/Classes/Presentation/Modules/About/Assembly/AboutInitializer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Assembly/AboutInitializer.swift similarity index 100% rename from station/Classes/Presentation/Modules/About/Assembly/AboutInitializer.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Assembly/AboutInitializer.swift diff --git a/station/Classes/Presentation/Modules/About/Presenter/AboutModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Presenter/AboutModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/About/Presenter/AboutModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Presenter/AboutModuleInput.swift diff --git a/station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift diff --git a/station/Classes/Presentation/Modules/About/Router/AboutRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Router/AboutRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/About/Router/AboutRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Router/AboutRouter.swift diff --git a/station/Classes/Presentation/Modules/About/Router/AboutRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Router/AboutRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/About/Router/AboutRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Router/AboutRouterInput.swift diff --git a/station/Classes/Presentation/Modules/About/View/AboutViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/View/AboutViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/About/View/AboutViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/View/AboutViewController.swift diff --git a/station/Classes/Presentation/Modules/About/View/AboutViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/View/AboutViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/About/View/AboutViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/View/AboutViewInput.swift diff --git a/station/Classes/Presentation/Modules/About/View/AboutViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/View/AboutViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/About/View/AboutViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/View/AboutViewModel.swift diff --git a/station/Classes/Presentation/Modules/About/View/AboutViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/View/AboutViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/About/View/AboutViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/View/AboutViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/Assembly/BackgroundSelectionModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/Assembly/BackgroundSelectionModuleFactory.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Background/Assembly/BackgroundSelectionModuleFactory.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/Assembly/BackgroundSelectionModuleFactory.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewInput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewModel.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/BackgroundSelectionViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewCell.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Assembly/CardsViewModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Assembly/CardsViewModuleFactory.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Cards/Assembly/CardsViewModuleFactory.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Assembly/CardsViewModuleFactory.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractor.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractor.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractor.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractor.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractorInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractorInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractorInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Interactor/CardsInteractorInput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsModuleOutput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouterDelegate.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouterDelegate.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouterDelegate.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouterDelegate.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouterInput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewInput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsIndicatorView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsIndicatorView.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsIndicatorView.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsIndicatorView.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsModuleFactory.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsModuleFactory.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsModuleFactory.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsViewConfigurator.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsViewConfigurator.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsViewConfigurator.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Assembly/TagChartsViewConfigurator.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/XAxisValueFormatter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/XAxisValueFormatter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/XAxisValueFormatter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/XAxisValueFormatter.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractor.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractor.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractor.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractor.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorInput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Interactor/TagChartsViewInteractorOutput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewModuleOutput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractorInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractorInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractorInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractorInput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouterDelegate.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouterDelegate.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouterDelegate.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouterDelegate.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouterInput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardCellDelegate.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardCellDelegate.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardCellDelegate.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardCellDelegate.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviContextMenuButton.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/RuuviContextMenuButton.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviContextMenuButton.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/RuuviContextMenuButton.swift diff --git a/station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviSimpleViewCompositionalLayout.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/RuuviSimpleViewCompositionalLayout.swift similarity index 100% rename from station/Classes/Presentation/Modules/Dashboard/Home/View/RuuviSimpleViewCompositionalLayout.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/RuuviSimpleViewCompositionalLayout.swift diff --git a/station/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableConfigurator.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableConfigurator.swift similarity index 100% rename from station/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableConfigurator.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableConfigurator.swift diff --git a/station/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableInitializer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableInitializer.swift similarity index 100% rename from station/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableInitializer.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Assembly/Table/MenuTableInitializer.swift diff --git a/station/Classes/Presentation/Modules/Menu/Menu.storyboard b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Menu.storyboard similarity index 100% rename from station/Classes/Presentation/Modules/Menu/Menu.storyboard rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Menu.storyboard diff --git a/station/Classes/Presentation/Modules/Menu/Presenter/MenuModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Presenter/MenuModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Menu/Presenter/MenuModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Presenter/MenuModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Menu/Presenter/MenuModuleOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Presenter/MenuModuleOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Menu/Presenter/MenuModuleOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Presenter/MenuModuleOutput.swift diff --git a/station/Classes/Presentation/Modules/Menu/Presenter/MenuPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Presenter/MenuPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Menu/Presenter/MenuPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Presenter/MenuPresenter.swift diff --git a/station/Classes/Presentation/Modules/Menu/Router/MenuRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Router/MenuRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Menu/Router/MenuRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Router/MenuRouter.swift diff --git a/station/Classes/Presentation/Modules/Menu/Router/MenuRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Router/MenuRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Menu/Router/MenuRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Router/MenuRouterInput.swift diff --git a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableDismissTransitionAnimation.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableDismissTransitionAnimation.swift similarity index 100% rename from station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableDismissTransitionAnimation.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableDismissTransitionAnimation.swift diff --git a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentTransitionAnimation.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentTransitionAnimation.swift similarity index 100% rename from station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentTransitionAnimation.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentTransitionAnimation.swift diff --git a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentationController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentationController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentationController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Transition/Table/MenuTablePresentationController.swift diff --git a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitionManager.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitionManager.swift similarity index 100% rename from station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitionManager.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitionManager.swift diff --git a/station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitioningDelegate.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitioningDelegate.swift similarity index 100% rename from station/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitioningDelegate.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/Transition/Table/MenuTableTransitioningDelegate.swift diff --git a/station/Classes/Presentation/Modules/Menu/View/MenuViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/View/MenuViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Menu/View/MenuViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/View/MenuViewInput.swift diff --git a/station/Classes/Presentation/Modules/Menu/View/MenuViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/View/MenuViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Menu/View/MenuViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/View/MenuViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift diff --git a/station/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift diff --git a/station/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountConfigurator.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountConfigurator.swift similarity index 100% rename from station/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountConfigurator.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountConfigurator.swift diff --git a/station/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountInitializer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountInitializer.swift similarity index 100% rename from station/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountInitializer.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/Assembly/MyRuuviAccountInitializer.swift diff --git a/station/Classes/Presentation/Modules/My Ruuvi/MyRuuvi.storyboard b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/MyRuuvi.storyboard similarity index 100% rename from station/Classes/Presentation/Modules/My Ruuvi/MyRuuvi.storyboard rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/MyRuuvi.storyboard diff --git a/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountModuleInput.swift diff --git a/station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/Presenter/MyRuuviAccountPresenter.swift diff --git a/station/Classes/Presentation/Modules/My Ruuvi/Router/MyRuuviAccountRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/Router/MyRuuviAccountRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/My Ruuvi/Router/MyRuuviAccountRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/Router/MyRuuviAccountRouter.swift diff --git a/station/Classes/Presentation/Modules/My Ruuvi/Router/MyRuuviAccountRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/Router/MyRuuviAccountRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/My Ruuvi/Router/MyRuuviAccountRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/Router/MyRuuviAccountRouterInput.swift diff --git a/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift diff --git a/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewInput.swift diff --git a/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewModel.swift diff --git a/station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableConfigurator.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableConfigurator.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableConfigurator.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableConfigurator.swift diff --git a/station/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableInitializer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableInitializer.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableInitializer.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableInitializer.swift diff --git a/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Router/SettingsRouterInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Module/Settings.storyboard b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Settings.storyboard similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Module/Settings.storyboard rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Settings.storyboard diff --git a/station/Classes/Presentation/Modules/Settings/Module/View/SettingsViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/View/SettingsViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Module/View/SettingsViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/View/SettingsViewInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Module/View/SettingsViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/View/SettingsViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Module/View/SettingsViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/View/SettingsViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Assembly/AppearanceSettingsModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Assembly/AppearanceSettingsModuleFactory.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Assembly/AppearanceSettingsModuleFactory.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Assembly/AppearanceSettingsModuleFactory.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Presenter/AppearanceSettingsPresenter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Router/AppearanceSettingsRouterInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Assembly/ASSelectionModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Assembly/ASSelectionModuleFactory.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Assembly/ASSelectionModuleFactory.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Assembly/ASSelectionModuleFactory.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/Presenter/ASSelectionPresenter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/ASSelectionViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/ASSelectionViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/ASSelectionViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/ASSelectionViewInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/ASSelectionViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/ASSelectionViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/ASSelectionViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/ASSelectionViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/AppearanceSettingsViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/AppearanceSettingsViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/AppearanceSettingsViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/AppearanceSettingsViewInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/AppearanceSettingsViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/AppearanceSettingsViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/AppearanceSettingsViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/AppearanceSettingsViewModel.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/AppearanceSettingsViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/AppearanceSettingsViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/AppearanceSettingsViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/AppearanceSettingsViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Assembly/ChartSettingsConfigurator.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/Assembly/ChartSettingsConfigurator.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Chart/Assembly/ChartSettingsConfigurator.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/Assembly/ChartSettingsConfigurator.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Assembly/ChartSettingsInitializer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/Assembly/ChartSettingsInitializer.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Chart/Assembly/ChartSettingsInitializer.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/Assembly/ChartSettingsInitializer.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/ChartSettings.storyboard b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/ChartSettings.storyboard similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Chart/ChartSettings.storyboard rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/ChartSettings.storyboard diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/Presenter/ChartSettingsPresenter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Router/ChartSettingsRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/Router/ChartSettingsRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Chart/Router/ChartSettingsRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/Router/ChartSettingsRouter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/Router/ChartSettingsRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/Router/ChartSettingsRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Chart/Router/ChartSettingsRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/Router/ChartSettingsRouterInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewModel.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/ChartSettingsViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsDisclosureTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsDisclosureTableViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsDisclosureTableViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsDisclosureTableViewCell.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsStepperTableViewCell.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsSwitchTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsSwitchTableViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsSwitchTableViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/Cells/ChartSettingsSwitchTableViewCell.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Assembly/DefaultsConfigurator.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Assembly/DefaultsConfigurator.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Assembly/DefaultsConfigurator.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Assembly/DefaultsConfigurator.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Assembly/DefaultsInitializer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Assembly/DefaultsInitializer.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Assembly/DefaultsInitializer.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Assembly/DefaultsInitializer.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Defaults.storyboard b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Defaults.storyboard similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Defaults.storyboard rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Defaults.storyboard diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsModuleOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsModuleOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsModuleOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsModuleOutput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Router/DefaultsRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Router/DefaultsRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Router/DefaultsRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Router/DefaultsRouter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Router/DefaultsRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Router/DefaultsRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/Router/DefaultsRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Router/DefaultsRouterInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewModel.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsEnvironmentObject.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsEnvironmentObject.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsEnvironmentObject.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsEnvironmentObject.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsList.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsList.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsList.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/SwiftUI/DefaultsList.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsPlainTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsPlainTableViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsPlainTableViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsPlainTableViewCell.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsStepperTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsStepperTableViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsStepperTableViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsStepperTableViewCell.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsSwitchTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsSwitchTableViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsSwitchTableViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/Cells/DefaultsSwitchTableViewCell.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/Assembly/DevicesModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/Assembly/DevicesModuleFactory.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Devices/Assembly/DevicesModuleFactory.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/Assembly/DevicesModuleFactory.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/Interactor/DevicesInteractor.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/Interactor/DevicesInteractor.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Devices/Interactor/DevicesInteractor.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/Interactor/DevicesInteractor.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/Interactor/DevicesInteractorInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/Interactor/DevicesInteractorInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Devices/Interactor/DevicesInteractorInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/Interactor/DevicesInteractorInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/Interactor/DevicesInteractorOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/Interactor/DevicesInteractorOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Devices/Interactor/DevicesInteractorOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/Interactor/DevicesInteractorOutput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/Presenter/DevicesModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/Presenter/DevicesModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Devices/Presenter/DevicesModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/Presenter/DevicesModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/Presenter/DevicesPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/Presenter/DevicesPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Devices/Presenter/DevicesPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/Presenter/DevicesPresenter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewModel.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/DevicesViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Assembly/HeartbeatConfigurator.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Assembly/HeartbeatConfigurator.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Assembly/HeartbeatConfigurator.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Assembly/HeartbeatConfigurator.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Assembly/HeartbeatInitializer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Assembly/HeartbeatInitializer.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Assembly/HeartbeatInitializer.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Assembly/HeartbeatInitializer.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Heartbeat.storyboard b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Heartbeat.storyboard similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Heartbeat.storyboard rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Heartbeat.storyboard diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Presenter/HeartbeatModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Presenter/HeartbeatModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Presenter/HeartbeatModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Presenter/HeartbeatModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Presenter/HeartbeatPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Presenter/HeartbeatPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Presenter/HeartbeatPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Presenter/HeartbeatPresenter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Router/HeartbeatRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Router/HeartbeatRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Router/HeartbeatRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Router/HeartbeatRouter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Router/HeartbeatRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Router/HeartbeatRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Router/HeartbeatRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/Router/HeartbeatRouterInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewModel.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatEnvironmentObject.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatEnvironmentObject.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatEnvironmentObject.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatEnvironmentObject.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/SwiftUI/HeartbeatList.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Assembly/NotificationsSettingsModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Assembly/NotificationsSettingsModuleFactory.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Assembly/NotificationsSettingsModuleFactory.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Assembly/NotificationsSettingsModuleFactory.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Presenter/NotificationsSettingsPresenter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Router/NotificationsSettingsRouterInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Assembly/PushAlertSoundSelectionModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Assembly/PushAlertSoundSelectionModuleFactory.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Assembly/PushAlertSoundSelectionModuleFactory.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Assembly/PushAlertSoundSelectionModuleFactory.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/Presenter/PushAlertSoundSelectionPresenter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/PushAlertSoundSelectionViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/PushAlertSoundSelectionViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/PushAlertSoundSelectionViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/PushAlertSoundSelectionViewInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/PushAlertSoundSelectionViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/PushAlertSoundSelectionViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/PushAlertSoundSelectionViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/PushAlertSoundSelectionViewModel.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/PushAlertSoundSelectionViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/PushAlertSoundSelectionViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/PushAlertSoundSelectionViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/PushAlertSoundSelectionViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewModel.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/NotificationsSettingsViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Assembly/RuuviCloudModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Assembly/RuuviCloudModuleFactory.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Assembly/RuuviCloudModuleFactory.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Assembly/RuuviCloudModuleFactory.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/Presenter/RuuviCloudPresenter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewModel.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/RuuviCloudViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Assembly/Table/SelectionTableConfigurator.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Assembly/Table/SelectionTableConfigurator.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Selection/Assembly/Table/SelectionTableConfigurator.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Assembly/Table/SelectionTableConfigurator.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Assembly/Table/SelectionTableInitializer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Assembly/Table/SelectionTableInitializer.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Selection/Assembly/Table/SelectionTableInitializer.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Assembly/Table/SelectionTableInitializer.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Model/SelectionItem.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Model/SelectionItem.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Selection/Model/SelectionItem.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Model/SelectionItem.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionModuleOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionModuleOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionModuleOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionModuleOutput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Presenter/SelectionPresenter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Router/SelectionRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Router/SelectionRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Selection/Router/SelectionRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Router/SelectionRouter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Router/SelectionRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Router/SelectionRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Selection/Router/SelectionRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Router/SelectionRouterInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/Selection.storyboard b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Selection.storyboard similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Selection/Selection.storyboard rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/Selection.storyboard diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/SelectionViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/View/SelectionViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/SelectionViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/View/SelectionViewInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/SelectionViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/View/SelectionViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/SelectionViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/View/SelectionViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewCell.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Assembly/Table/UnitSettingsTableConfigurator.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Assembly/Table/UnitSettingsTableConfigurator.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Assembly/Table/UnitSettingsTableConfigurator.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Assembly/Table/UnitSettingsTableConfigurator.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Assembly/Table/UnitSettingsTableInitializer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Assembly/Table/UnitSettingsTableInitializer.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Assembly/Table/UnitSettingsTableInitializer.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Assembly/Table/UnitSettingsTableInitializer.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Model/UnitSettingsItem.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Model/UnitSettingsItem.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Model/UnitSettingsItem.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Model/UnitSettingsItem.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsModuleOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsModuleOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsModuleOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsModuleOutput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Presenter/UnitSettingsPresenter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Router/UnitSettingsRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Router/UnitSettingsRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Router/UnitSettingsRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Router/UnitSettingsRouter.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Router/UnitSettingsRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Router/UnitSettingsRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Router/UnitSettingsRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/Router/UnitSettingsRouterInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/UnitSettings.storyboard b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/UnitSettings.storyboard similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/UnitSettings.storyboard rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/UnitSettings.storyboard diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewCell.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/UnitSettingsViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/UnitSettingsViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/UnitSettingsViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/UnitSettingsViewInput.swift diff --git a/station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/UnitSettingsViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/UnitSettingsViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/UnitSettingsViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/UnitSettingsViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Share/Assembly/ShareConfigurator.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/Assembly/ShareConfigurator.swift similarity index 100% rename from station/Classes/Presentation/Modules/Share/Assembly/ShareConfigurator.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/Assembly/ShareConfigurator.swift diff --git a/station/Classes/Presentation/Modules/Share/Assembly/ShareInitializer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/Assembly/ShareInitializer.swift similarity index 100% rename from station/Classes/Presentation/Modules/Share/Assembly/ShareInitializer.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/Assembly/ShareInitializer.swift diff --git a/station/Classes/Presentation/Modules/Share/Presenter/ShareModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/Presenter/ShareModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Share/Presenter/ShareModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/Presenter/ShareModuleInput.swift diff --git a/station/Classes/Presentation/Modules/Share/Presenter/ShareModuleOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/Presenter/ShareModuleOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Share/Presenter/ShareModuleOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/Presenter/ShareModuleOutput.swift diff --git a/station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/Presenter/SharePresenter.swift diff --git a/station/Classes/Presentation/Modules/Share/Router/ShareRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/Router/ShareRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/Share/Router/ShareRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/Router/ShareRouter.swift diff --git a/station/Classes/Presentation/Modules/Share/Router/ShareRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/Router/ShareRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Share/Router/ShareRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/Router/ShareRouterInput.swift diff --git a/station/Classes/Presentation/Modules/Share/Share.storyboard b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/Share.storyboard similarity index 100% rename from station/Classes/Presentation/Modules/Share/Share.storyboard rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/Share.storyboard diff --git a/station/Classes/Presentation/Modules/Share/View/Cells/ShareDescriptionTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/Cells/ShareDescriptionTableViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Share/View/Cells/ShareDescriptionTableViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/Cells/ShareDescriptionTableViewCell.swift diff --git a/station/Classes/Presentation/Modules/Share/View/Cells/ShareEmailInputTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/Cells/ShareEmailInputTableViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Share/View/Cells/ShareEmailInputTableViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/Cells/ShareEmailInputTableViewCell.swift diff --git a/station/Classes/Presentation/Modules/Share/View/Cells/ShareEmailTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/Cells/ShareEmailTableViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Share/View/Cells/ShareEmailTableViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/Cells/ShareEmailTableViewCell.swift diff --git a/station/Classes/Presentation/Modules/Share/View/Cells/ShareSendButtonTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/Cells/ShareSendButtonTableViewCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/Share/View/Cells/ShareSendButtonTableViewCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/Cells/ShareSendButtonTableViewCell.swift diff --git a/station/Classes/Presentation/Modules/Share/View/ShareViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ShareViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Share/View/ShareViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ShareViewInput.swift diff --git a/station/Classes/Presentation/Modules/Share/View/ShareViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ShareViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/Share/View/ShareViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ShareViewModel.swift diff --git a/station/Classes/Presentation/Modules/Share/View/ShareViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ShareViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/Share/View/ShareViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ShareViewOutput.swift diff --git a/station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift diff --git a/station/Classes/Presentation/Modules/SignIn/Assembly/SignInModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Assembly/SignInModuleFactory.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/Assembly/SignInModuleFactory.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Assembly/SignInModuleFactory.swift diff --git a/station/Classes/Presentation/Modules/SignIn/Presenter/SignInModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Presenter/SignInModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/Presenter/SignInModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Presenter/SignInModuleInput.swift diff --git a/station/Classes/Presentation/Modules/SignIn/Presenter/SignInModuleOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Presenter/SignInModuleOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/Presenter/SignInModuleOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Presenter/SignInModuleOutput.swift diff --git a/station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Presenter/SignInPresenter.swift diff --git a/station/Classes/Presentation/Modules/SignIn/Router/SignInRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Router/SignInRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/Router/SignInRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Router/SignInRouter.swift diff --git a/station/Classes/Presentation/Modules/SignIn/Router/SignInRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Router/SignInRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/Router/SignInRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Router/SignInRouterInput.swift diff --git a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Assembly/SignInBenefitsModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Assembly/SignInBenefitsModuleFactory.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Assembly/SignInBenefitsModuleFactory.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Assembly/SignInBenefitsModuleFactory.swift diff --git a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsModuleInput.swift diff --git a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsModuleOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsModuleOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsModuleOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsModuleOutput.swift diff --git a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Presenter/SignInBenefitsPresenter.swift diff --git a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Router/SignInBenefitsRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Router/SignInBenefitsRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Router/SignInBenefitsRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Router/SignInBenefitsRouter.swift diff --git a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Router/SignInBenefitsRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Router/SignInBenefitsRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Router/SignInBenefitsRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/Router/SignInBenefitsRouterInput.swift diff --git a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift diff --git a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewInput.swift diff --git a/station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewOutput.swift diff --git a/station/Classes/Presentation/Modules/SignIn/View/SignInViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/SignInViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/View/SignInViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/SignInViewInput.swift diff --git a/station/Classes/Presentation/Modules/SignIn/View/SignInViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/SignInViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/View/SignInViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/SignInViewModel.swift diff --git a/station/Classes/Presentation/Modules/SignIn/View/SignInViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/SignInViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/View/SignInViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/SignInViewOutput.swift diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeTextField.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeTextField.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeTextField.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeTextField.swift diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeView.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeView.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/Helper/RuuviCodeView.swift diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift diff --git a/station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Assembly/TagSettingsModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Assembly/TagSettingsModuleFactory.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Assembly/TagSettingsModuleFactory.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Assembly/TagSettingsModuleFactory.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Presenter/Debouncer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/Debouncer.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Presenter/Debouncer.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/Debouncer.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsModuleOutput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouterInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/DFUModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/DFUModuleFactory.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/DFUModuleFactory.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/DFUModuleFactory.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractor.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractorInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractorInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractorInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/DFUInteractorInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/LatestRelease.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/LatestRelease.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/LatestRelease.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Interactor/LatestRelease.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUModuleInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Assembly/SensorForceClaimModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Assembly/SensorForceClaimModuleFactory.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Assembly/SensorForceClaimModuleFactory.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Assembly/SensorForceClaimModuleFactory.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimModuleInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Presenter/SensorForceClaimPresenter.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Router/SensorForceClaimRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Router/SensorForceClaimRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Router/SensorForceClaimRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Router/SensorForceClaimRouter.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Router/SensorForceClaimRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Router/SensorForceClaimRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Router/SensorForceClaimRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/Router/SensorForceClaimRouterInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/SensorForceClaimViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/SensorForceClaimViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/SensorForceClaimViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/SensorForceClaimViewInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/SensorForceClaimViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/SensorForceClaimViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/SensorForceClaimViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/SensorForceClaimViewOutput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionAppleInitializer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionAppleInitializer.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionAppleInitializer.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionAppleInitializer.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionConfigurator.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionConfigurator.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionConfigurator.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Assembly/Apple/OffsetCorrectionConfigurator.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/OffsetCorrection.storyboard b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/OffsetCorrection.storyboard similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/OffsetCorrection.storyboard rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/OffsetCorrection.storyboard diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionModuleInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionModuleOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionModuleOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionModuleOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionModuleOutput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Presenter/OffsetCorrectionPresenter.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Router/OffsetCorrectionRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Router/OffsetCorrectionRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Router/OffsetCorrectionRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Router/OffsetCorrectionRouter.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Router/OffsetCorrectionRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Router/OffsetCorrectionRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Router/OffsetCorrectionRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/Router/OffsetCorrectionRouterInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewModel.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/OffsetCorrectionViewOutput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerConfigurator.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerConfigurator.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerConfigurator.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerConfigurator.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerInitializer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerInitializer.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerInitializer.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Assembly/OwnerInitializer.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Owner.storyboard b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Owner.storyboard similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Owner.storyboard rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Owner.storyboard diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerModuleInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Presenter/OwnerPresenter.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouterInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewOutput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Assembly/SensorRemovalModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Assembly/SensorRemovalModuleFactory.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Assembly/SensorRemovalModuleFactory.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Assembly/SensorRemovalModuleFactory.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalModuleInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalModuleInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalModuleInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalModuleOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalModuleOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalModuleOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalModuleOutput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalPresenter.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Presenter/SensorRemovalPresenter.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Router/SensorRemovalRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Router/SensorRemovalRouter.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Router/SensorRemovalRouter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Router/SensorRemovalRouter.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Router/SensorRemovalRouterInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Router/SensorRemovalRouterInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Router/SensorRemovalRouterInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/Router/SensorRemovalRouterInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/SensorRemovalViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/SensorRemovalViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/SensorRemovalViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/SensorRemovalViewInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/SensorRemovalViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/SensorRemovalViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/SensorRemovalViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/SensorRemovalViewOutput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewInput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewInput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewInput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewModel.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewOutput.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewOutput.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewOutput.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/RangeSeekSlider/RURangeSeekSlider.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RangeSeekSlider/RURangeSeekSlider.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/View/UI/RangeSeekSlider/RURangeSeekSlider.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RangeSeekSlider/RURangeSeekSlider.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsFooterCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsFooterCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsFooterCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsFooterCell.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift diff --git a/station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift similarity index 100% rename from station/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift diff --git a/station/Classes/Presentation/Presenters/Alert/AlertPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Presenters/Alert/AlertPresenter.swift similarity index 100% rename from station/Classes/Presentation/Presenters/Alert/AlertPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Presenters/Alert/AlertPresenter.swift diff --git a/station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift similarity index 100% rename from station/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Presenters/Alert/Impl/AlertPresenterImpl.swift diff --git a/station/Classes/Presentation/Presenters/Alert/ViewModel/AlertViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Presenters/Alert/ViewModel/AlertViewModel.swift similarity index 100% rename from station/Classes/Presentation/Presenters/Alert/ViewModel/AlertViewModel.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Presenters/Alert/ViewModel/AlertViewModel.swift diff --git a/station/Classes/Presentation/Presenters/MailComposer/MailComposerPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Presenters/MailComposer/MailComposerPresenter.swift similarity index 100% rename from station/Classes/Presentation/Presenters/MailComposer/MailComposerPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Presenters/MailComposer/MailComposerPresenter.swift diff --git a/station/Classes/Presentation/Presenters/MailComposer/MessageUI/MailComposerPresenterMessageUI.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Presenters/MailComposer/MessageUI/MailComposerPresenterMessageUI.swift similarity index 100% rename from station/Classes/Presentation/Presenters/MailComposer/MessageUI/MailComposerPresenterMessageUI.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Presenters/MailComposer/MessageUI/MailComposerPresenterMessageUI.swift diff --git a/station/Classes/Presentation/Presenters/PhotoPicker/PhotoPickerPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Presenters/PhotoPicker/PhotoPickerPresenter.swift similarity index 100% rename from station/Classes/Presentation/Presenters/PhotoPicker/PhotoPickerPresenter.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Presenters/PhotoPicker/PhotoPickerPresenter.swift diff --git a/station/Classes/Presentation/Presenters/PhotoPicker/Sheet/PhotoPickerPresenterSheet.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Presenters/PhotoPicker/Sheet/PhotoPickerPresenterSheet.swift similarity index 100% rename from station/Classes/Presentation/Presenters/PhotoPicker/Sheet/PhotoPickerPresenterSheet.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Presenters/PhotoPicker/Sheet/PhotoPickerPresenterSheet.swift diff --git a/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissInteractiveTransition.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissInteractiveTransition.swift similarity index 100% rename from station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissInteractiveTransition.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissInteractiveTransition.swift diff --git a/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissNavigationController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissNavigationController.swift similarity index 100% rename from station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissNavigationController.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissNavigationController.swift diff --git a/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitionAnimation.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitionAnimation.swift similarity index 100% rename from station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitionAnimation.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitionAnimation.swift diff --git a/station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitioningDelegate.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitioningDelegate.swift similarity index 100% rename from station/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitioningDelegate.swift rename to Apps/RuuviStation/Sources/Classes/Presentation/Transitions/SwipeDownToDismiss/SwipeDownToDismissTransitioningDelegate.swift diff --git a/station/Classes/Routers/AppRouter.swift b/Apps/RuuviStation/Sources/Classes/Routers/AppRouter.swift similarity index 100% rename from station/Classes/Routers/AppRouter.swift rename to Apps/RuuviStation/Sources/Classes/Routers/AppRouter.swift diff --git a/station/Classes/Routers/DiscoverRouter.swift b/Apps/RuuviStation/Sources/Classes/Routers/DiscoverRouter.swift similarity index 100% rename from station/Classes/Routers/DiscoverRouter.swift rename to Apps/RuuviStation/Sources/Classes/Routers/DiscoverRouter.swift diff --git a/station/Classes/Routers/OnboardRouter.swift b/Apps/RuuviStation/Sources/Classes/Routers/OnboardRouter.swift similarity index 100% rename from station/Classes/Routers/OnboardRouter.swift rename to Apps/RuuviStation/Sources/Classes/Routers/OnboardRouter.swift diff --git a/station/Extensions/Array+AnyRuuviTagSensor.swift b/Apps/RuuviStation/Sources/Extensions/Array+AnyRuuviTagSensor.swift similarity index 100% rename from station/Extensions/Array+AnyRuuviTagSensor.swift rename to Apps/RuuviStation/Sources/Extensions/Array+AnyRuuviTagSensor.swift diff --git a/station/Extensions/CALayer+IB.swift b/Apps/RuuviStation/Sources/Extensions/CALayer+IB.swift similarity index 100% rename from station/Extensions/CALayer+IB.swift rename to Apps/RuuviStation/Sources/Extensions/CALayer+IB.swift diff --git a/station/Extensions/Classess/AppDateFormatter.swift b/Apps/RuuviStation/Sources/Extensions/Classess/AppDateFormatter.swift similarity index 100% rename from station/Extensions/Classess/AppDateFormatter.swift rename to Apps/RuuviStation/Sources/Extensions/Classess/AppDateFormatter.swift diff --git a/station/Extensions/Classess/RuuviCustomButton.swift b/Apps/RuuviStation/Sources/Extensions/Classess/RuuviCustomButton.swift similarity index 100% rename from station/Extensions/Classess/RuuviCustomButton.swift rename to Apps/RuuviStation/Sources/Extensions/Classess/RuuviCustomButton.swift diff --git a/station/Extensions/Classess/RuuviLinkTextView.swift b/Apps/RuuviStation/Sources/Extensions/Classess/RuuviLinkTextView.swift similarity index 100% rename from station/Extensions/Classess/RuuviLinkTextView.swift rename to Apps/RuuviStation/Sources/Extensions/Classess/RuuviLinkTextView.swift diff --git a/station/Extensions/Classess/RuuviUISwitch.swift b/Apps/RuuviStation/Sources/Extensions/Classess/RuuviUISwitch.swift similarity index 100% rename from station/Extensions/Classess/RuuviUISwitch.swift rename to Apps/RuuviStation/Sources/Extensions/Classess/RuuviUISwitch.swift diff --git a/station/Extensions/Color+Ruuvi.swift b/Apps/RuuviStation/Sources/Extensions/Color+Ruuvi.swift similarity index 100% rename from station/Extensions/Color+Ruuvi.swift rename to Apps/RuuviStation/Sources/Extensions/Color+Ruuvi.swift diff --git a/station/Extensions/Date+Ruuvi.swift b/Apps/RuuviStation/Sources/Extensions/Date+Ruuvi.swift similarity index 100% rename from station/Extensions/Date+Ruuvi.swift rename to Apps/RuuviStation/Sources/Extensions/Date+Ruuvi.swift diff --git a/station/Extensions/DfuFirmware+Log.swift b/Apps/RuuviStation/Sources/Extensions/DfuFirmware+Log.swift similarity index 100% rename from station/Extensions/DfuFirmware+Log.swift rename to Apps/RuuviStation/Sources/Extensions/DfuFirmware+Log.swift diff --git a/station/Extensions/Double+Extension.swift b/Apps/RuuviStation/Sources/Extensions/Double+Extension.swift similarity index 100% rename from station/Extensions/Double+Extension.swift rename to Apps/RuuviStation/Sources/Extensions/Double+Extension.swift diff --git a/station/Extensions/Double+Temperature.swift b/Apps/RuuviStation/Sources/Extensions/Double+Temperature.swift similarity index 100% rename from station/Extensions/Double+Temperature.swift rename to Apps/RuuviStation/Sources/Extensions/Double+Temperature.swift diff --git a/station/Extensions/Errors/RUError.swift b/Apps/RuuviStation/Sources/Extensions/Errors/RUError.swift similarity index 100% rename from station/Extensions/Errors/RUError.swift rename to Apps/RuuviStation/Sources/Extensions/Errors/RUError.swift diff --git a/station/Extensions/Errors/RuuviCloudApiError+LocalizedError.swift b/Apps/RuuviStation/Sources/Extensions/Errors/RuuviCloudApiError+LocalizedError.swift similarity index 100% rename from station/Extensions/Errors/RuuviCloudApiError+LocalizedError.swift rename to Apps/RuuviStation/Sources/Extensions/Errors/RuuviCloudApiError+LocalizedError.swift diff --git a/station/Extensions/Errors/RuuviCloudError+LocalizedError.swift b/Apps/RuuviStation/Sources/Extensions/Errors/RuuviCloudError+LocalizedError.swift similarity index 100% rename from station/Extensions/Errors/RuuviCloudError+LocalizedError.swift rename to Apps/RuuviStation/Sources/Extensions/Errors/RuuviCloudError+LocalizedError.swift diff --git a/station/Extensions/Errors/RuuviCoreError+LocalizedError.swift b/Apps/RuuviStation/Sources/Extensions/Errors/RuuviCoreError+LocalizedError.swift similarity index 100% rename from station/Extensions/Errors/RuuviCoreError+LocalizedError.swift rename to Apps/RuuviStation/Sources/Extensions/Errors/RuuviCoreError+LocalizedError.swift diff --git a/station/Extensions/Errors/RuuviDFUError+LocalizedError.swift b/Apps/RuuviStation/Sources/Extensions/Errors/RuuviDFUError+LocalizedError.swift similarity index 100% rename from station/Extensions/Errors/RuuviDFUError+LocalizedError.swift rename to Apps/RuuviStation/Sources/Extensions/Errors/RuuviDFUError+LocalizedError.swift diff --git a/station/Extensions/Errors/RuuviDaemonError+LocalizedError.swift b/Apps/RuuviStation/Sources/Extensions/Errors/RuuviDaemonError+LocalizedError.swift similarity index 100% rename from station/Extensions/Errors/RuuviDaemonError+LocalizedError.swift rename to Apps/RuuviStation/Sources/Extensions/Errors/RuuviDaemonError+LocalizedError.swift diff --git a/station/Extensions/Errors/RuuviLocalError+LocalizedError.swift b/Apps/RuuviStation/Sources/Extensions/Errors/RuuviLocalError+LocalizedError.swift similarity index 100% rename from station/Extensions/Errors/RuuviLocalError+LocalizedError.swift rename to Apps/RuuviStation/Sources/Extensions/Errors/RuuviLocalError+LocalizedError.swift diff --git a/station/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift b/Apps/RuuviStation/Sources/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift similarity index 100% rename from station/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift rename to Apps/RuuviStation/Sources/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift diff --git a/station/Extensions/Errors/RuuviPoolError+LocalizedError.swift b/Apps/RuuviStation/Sources/Extensions/Errors/RuuviPoolError+LocalizedError.swift similarity index 100% rename from station/Extensions/Errors/RuuviPoolError+LocalizedError.swift rename to Apps/RuuviStation/Sources/Extensions/Errors/RuuviPoolError+LocalizedError.swift diff --git a/station/Extensions/Errors/RuuviReactorError+LocalizedError.swift b/Apps/RuuviStation/Sources/Extensions/Errors/RuuviReactorError+LocalizedError.swift similarity index 100% rename from station/Extensions/Errors/RuuviReactorError+LocalizedError.swift rename to Apps/RuuviStation/Sources/Extensions/Errors/RuuviReactorError+LocalizedError.swift diff --git a/station/Extensions/Errors/RuuviRepositoryError+LocalizedError.swift b/Apps/RuuviStation/Sources/Extensions/Errors/RuuviRepositoryError+LocalizedError.swift similarity index 100% rename from station/Extensions/Errors/RuuviRepositoryError+LocalizedError.swift rename to Apps/RuuviStation/Sources/Extensions/Errors/RuuviRepositoryError+LocalizedError.swift diff --git a/station/Extensions/Errors/RuuviServiceError+LocalizedError.swift b/Apps/RuuviStation/Sources/Extensions/Errors/RuuviServiceError+LocalizedError.swift similarity index 100% rename from station/Extensions/Errors/RuuviServiceError+LocalizedError.swift rename to Apps/RuuviStation/Sources/Extensions/Errors/RuuviServiceError+LocalizedError.swift diff --git a/station/Extensions/Errors/RuuviStorageError+LocalizedError.swift b/Apps/RuuviStation/Sources/Extensions/Errors/RuuviStorageError+LocalizedError.swift similarity index 100% rename from station/Extensions/Errors/RuuviStorageError+LocalizedError.swift rename to Apps/RuuviStation/Sources/Extensions/Errors/RuuviStorageError+LocalizedError.swift diff --git a/station/Extensions/FileManager+Date.swift b/Apps/RuuviStation/Sources/Extensions/FileManager+Date.swift similarity index 100% rename from station/Extensions/FileManager+Date.swift rename to Apps/RuuviStation/Sources/Extensions/FileManager+Date.swift diff --git a/station/Extensions/Humidity+Offset.swift b/Apps/RuuviStation/Sources/Extensions/Humidity+Offset.swift similarity index 100% rename from station/Extensions/Humidity+Offset.swift rename to Apps/RuuviStation/Sources/Extensions/Humidity+Offset.swift diff --git a/station/Extensions/HumidityUnit+Localization.swift b/Apps/RuuviStation/Sources/Extensions/HumidityUnit+Localization.swift similarity index 100% rename from station/Extensions/HumidityUnit+Localization.swift rename to Apps/RuuviStation/Sources/Extensions/HumidityUnit+Localization.swift diff --git a/station/Extensions/Int+Extension.swift b/Apps/RuuviStation/Sources/Extensions/Int+Extension.swift similarity index 100% rename from station/Extensions/Int+Extension.swift rename to Apps/RuuviStation/Sources/Extensions/Int+Extension.swift diff --git a/station/Extensions/Language+Localization.swift b/Apps/RuuviStation/Sources/Extensions/Language+Localization.swift similarity index 100% rename from station/Extensions/Language+Localization.swift rename to Apps/RuuviStation/Sources/Extensions/Language+Localization.swift diff --git a/station/Extensions/MeasurementAccuracyType+Extension.swift b/Apps/RuuviStation/Sources/Extensions/MeasurementAccuracyType+Extension.swift similarity index 100% rename from station/Extensions/MeasurementAccuracyType+Extension.swift rename to Apps/RuuviStation/Sources/Extensions/MeasurementAccuracyType+Extension.swift diff --git a/station/Extensions/MeasurementType.swift b/Apps/RuuviStation/Sources/Extensions/MeasurementType.swift similarity index 100% rename from station/Extensions/MeasurementType.swift rename to Apps/RuuviStation/Sources/Extensions/MeasurementType.swift diff --git a/station/Extensions/NSObjectProtocol+Invalidation.swift b/Apps/RuuviStation/Sources/Extensions/NSObjectProtocol+Invalidation.swift similarity index 100% rename from station/Extensions/NSObjectProtocol+Invalidation.swift rename to Apps/RuuviStation/Sources/Extensions/NSObjectProtocol+Invalidation.swift diff --git a/station/Extensions/RuuviAlertSound+Extension.swift b/Apps/RuuviStation/Sources/Extensions/RuuviAlertSound+Extension.swift similarity index 100% rename from station/Extensions/RuuviAlertSound+Extension.swift rename to Apps/RuuviStation/Sources/Extensions/RuuviAlertSound+Extension.swift diff --git a/station/Extensions/RuuviTheme+Extension.swift b/Apps/RuuviStation/Sources/Extensions/RuuviTheme+Extension.swift similarity index 100% rename from station/Extensions/RuuviTheme+Extension.swift rename to Apps/RuuviStation/Sources/Extensions/RuuviTheme+Extension.swift diff --git a/station/Extensions/String+Characters.swift b/Apps/RuuviStation/Sources/Extensions/String+Characters.swift similarity index 100% rename from station/Extensions/String+Characters.swift rename to Apps/RuuviStation/Sources/Extensions/String+Characters.swift diff --git a/station/Extensions/String+Email.swift b/Apps/RuuviStation/Sources/Extensions/String+Email.swift similarity index 100% rename from station/Extensions/String+Email.swift rename to Apps/RuuviStation/Sources/Extensions/String+Email.swift diff --git a/station/Extensions/String+Replace.swift b/Apps/RuuviStation/Sources/Extensions/String+Replace.swift similarity index 100% rename from station/Extensions/String+Replace.swift rename to Apps/RuuviStation/Sources/Extensions/String+Replace.swift diff --git a/station/Extensions/Structs/AppStoreReviewHelper.swift b/Apps/RuuviStation/Sources/Extensions/Structs/AppStoreReviewHelper.swift similarity index 100% rename from station/Extensions/Structs/AppStoreReviewHelper.swift rename to Apps/RuuviStation/Sources/Extensions/Structs/AppStoreReviewHelper.swift diff --git a/station/Extensions/Structs/AppUtility.swift b/Apps/RuuviStation/Sources/Extensions/Structs/AppUtility.swift similarity index 100% rename from station/Extensions/Structs/AppUtility.swift rename to Apps/RuuviStation/Sources/Extensions/Structs/AppUtility.swift diff --git a/station/Extensions/Structs/ExportHeadersProvider.swift b/Apps/RuuviStation/Sources/Extensions/Structs/ExportHeadersProvider.swift similarity index 100% rename from station/Extensions/Structs/ExportHeadersProvider.swift rename to Apps/RuuviStation/Sources/Extensions/Structs/ExportHeadersProvider.swift diff --git a/station/Extensions/Structs/GlobalHelpers.swift b/Apps/RuuviStation/Sources/Extensions/Structs/GlobalHelpers.swift similarity index 100% rename from station/Extensions/Structs/GlobalHelpers.swift rename to Apps/RuuviStation/Sources/Extensions/Structs/GlobalHelpers.swift diff --git a/station/Extensions/Structs/HeartbeatDaemonTitles.swift b/Apps/RuuviStation/Sources/Extensions/Structs/HeartbeatDaemonTitles.swift similarity index 100% rename from station/Extensions/Structs/HeartbeatDaemonTitles.swift rename to Apps/RuuviStation/Sources/Extensions/Structs/HeartbeatDaemonTitles.swift diff --git a/station/Extensions/Structs/MeasurementAccuracyTitles.swift b/Apps/RuuviStation/Sources/Extensions/Structs/MeasurementAccuracyTitles.swift similarity index 100% rename from station/Extensions/Structs/MeasurementAccuracyTitles.swift rename to Apps/RuuviStation/Sources/Extensions/Structs/MeasurementAccuracyTitles.swift diff --git a/station/Extensions/Structs/RuuviNotifierTitlesImpl.swift b/Apps/RuuviStation/Sources/Extensions/Structs/RuuviNotifierTitlesImpl.swift similarity index 100% rename from station/Extensions/Structs/RuuviNotifierTitlesImpl.swift rename to Apps/RuuviStation/Sources/Extensions/Structs/RuuviNotifierTitlesImpl.swift diff --git a/station/Extensions/Structs/RuuviTagBatteryStatusProvider.swift b/Apps/RuuviStation/Sources/Extensions/Structs/RuuviTagBatteryStatusProvider.swift similarity index 100% rename from station/Extensions/Structs/RuuviTagBatteryStatusProvider.swift rename to Apps/RuuviStation/Sources/Extensions/Structs/RuuviTagBatteryStatusProvider.swift diff --git a/station/Extensions/TemperatureUnit+Localization.swift b/Apps/RuuviStation/Sources/Extensions/TemperatureUnit+Localization.swift similarity index 100% rename from station/Extensions/TemperatureUnit+Localization.swift rename to Apps/RuuviStation/Sources/Extensions/TemperatureUnit+Localization.swift diff --git a/station/Extensions/UIApplication+ViewController.swift b/Apps/RuuviStation/Sources/Extensions/UIApplication+ViewController.swift similarity index 100% rename from station/Extensions/UIApplication+ViewController.swift rename to Apps/RuuviStation/Sources/Extensions/UIApplication+ViewController.swift diff --git a/station/Extensions/UIButton+Extension.swift b/Apps/RuuviStation/Sources/Extensions/UIButton+Extension.swift similarity index 100% rename from station/Extensions/UIButton+Extension.swift rename to Apps/RuuviStation/Sources/Extensions/UIButton+Extension.swift diff --git a/station/Extensions/UICollectionView+Extension.swift b/Apps/RuuviStation/Sources/Extensions/UICollectionView+Extension.swift similarity index 100% rename from station/Extensions/UICollectionView+Extension.swift rename to Apps/RuuviStation/Sources/Extensions/UICollectionView+Extension.swift diff --git a/station/Extensions/UIColor+Extension.swift b/Apps/RuuviStation/Sources/Extensions/UIColor+Extension.swift similarity index 100% rename from station/Extensions/UIColor+Extension.swift rename to Apps/RuuviStation/Sources/Extensions/UIColor+Extension.swift diff --git a/station/Extensions/UIDevice+ReadableModel.swift b/Apps/RuuviStation/Sources/Extensions/UIDevice+ReadableModel.swift similarity index 100% rename from station/Extensions/UIDevice+ReadableModel.swift rename to Apps/RuuviStation/Sources/Extensions/UIDevice+ReadableModel.swift diff --git a/station/Extensions/UIFont+Extension.swift b/Apps/RuuviStation/Sources/Extensions/UIFont+Extension.swift similarity index 100% rename from station/Extensions/UIFont+Extension.swift rename to Apps/RuuviStation/Sources/Extensions/UIFont+Extension.swift diff --git a/station/Extensions/UIImage+Extension.swift b/Apps/RuuviStation/Sources/Extensions/UIImage+Extension.swift similarity index 100% rename from station/Extensions/UIImage+Extension.swift rename to Apps/RuuviStation/Sources/Extensions/UIImage+Extension.swift diff --git a/station/Extensions/UIImageView+Init.swift b/Apps/RuuviStation/Sources/Extensions/UIImageView+Init.swift similarity index 100% rename from station/Extensions/UIImageView+Init.swift rename to Apps/RuuviStation/Sources/Extensions/UIImageView+Init.swift diff --git a/station/Extensions/UINavigationController.swift b/Apps/RuuviStation/Sources/Extensions/UINavigationController.swift similarity index 100% rename from station/Extensions/UINavigationController.swift rename to Apps/RuuviStation/Sources/Extensions/UINavigationController.swift diff --git a/station/Extensions/UITableViewCell+ReusableView.swift b/Apps/RuuviStation/Sources/Extensions/UITableViewCell+ReusableView.swift similarity index 100% rename from station/Extensions/UITableViewCell+ReusableView.swift rename to Apps/RuuviStation/Sources/Extensions/UITableViewCell+ReusableView.swift diff --git a/station/Extensions/UITextField+Extension.swift b/Apps/RuuviStation/Sources/Extensions/UITextField+Extension.swift similarity index 100% rename from station/Extensions/UITextField+Extension.swift rename to Apps/RuuviStation/Sources/Extensions/UITextField+Extension.swift diff --git a/station/Extensions/UIView+Extension.swift b/Apps/RuuviStation/Sources/Extensions/UIView+Extension.swift similarity index 100% rename from station/Extensions/UIView+Extension.swift rename to Apps/RuuviStation/Sources/Extensions/UIView+Extension.swift diff --git a/station/Extensions/UIView+Init.swift b/Apps/RuuviStation/Sources/Extensions/UIView+Init.swift similarity index 100% rename from station/Extensions/UIView+Init.swift rename to Apps/RuuviStation/Sources/Extensions/UIView+Init.swift diff --git a/station/Extensions/UIView+Layout.swift b/Apps/RuuviStation/Sources/Extensions/UIView+Layout.swift similarity index 100% rename from station/Extensions/UIView+Layout.swift rename to Apps/RuuviStation/Sources/Extensions/UIView+Layout.swift diff --git a/station/Extensions/UIViewController+Alert.swift b/Apps/RuuviStation/Sources/Extensions/UIViewController+Alert.swift similarity index 100% rename from station/Extensions/UIViewController+Alert.swift rename to Apps/RuuviStation/Sources/Extensions/UIViewController+Alert.swift diff --git a/station/Extensions/UIWindow+Orientation.swift b/Apps/RuuviStation/Sources/Extensions/UIWindow+Orientation.swift similarity index 100% rename from station/Extensions/UIWindow+Orientation.swift rename to Apps/RuuviStation/Sources/Extensions/UIWindow+Orientation.swift diff --git a/station/Extensions/UIWindow+Shake.swift b/Apps/RuuviStation/Sources/Extensions/UIWindow+Shake.swift similarity index 100% rename from station/Extensions/UIWindow+Shake.swift rename to Apps/RuuviStation/Sources/Extensions/UIWindow+Shake.swift diff --git a/station/Extensions/UnitPressure+Extension.swift b/Apps/RuuviStation/Sources/Extensions/UnitPressure+Extension.swift similarity index 100% rename from station/Extensions/UnitPressure+Extension.swift rename to Apps/RuuviStation/Sources/Extensions/UnitPressure+Extension.swift diff --git a/station/Extensions/UnitSettingsType.swift b/Apps/RuuviStation/Sources/Extensions/UnitSettingsType.swift similarity index 100% rename from station/Extensions/UnitSettingsType.swift rename to Apps/RuuviStation/Sources/Extensions/UnitSettingsType.swift diff --git a/station/Extensions/UserDefaults+Optional.swift b/Apps/RuuviStation/Sources/Extensions/UserDefaults+Optional.swift similarity index 100% rename from station/Extensions/UserDefaults+Optional.swift rename to Apps/RuuviStation/Sources/Extensions/UserDefaults+Optional.swift diff --git a/station/Resources/Assets/RuuviAssets.swift b/Apps/RuuviStation/Sources/Resources/Assets/RuuviAssets.swift similarity index 100% rename from station/Resources/Assets/RuuviAssets.swift rename to Apps/RuuviStation/Sources/Resources/Assets/RuuviAssets.swift diff --git a/ruuvi-widgets/Assets.xcassets/Colors/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/Contents.json similarity index 100% rename from ruuvi-widgets/Assets.xcassets/Colors/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviDashboardBG.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardBG.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviDashboardBG.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardBG.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviDashboardCardBG.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardCardBG.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviDashboardCardBG.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardCardBG.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviDashboardIndicator.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardIndicator.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviDashboardIndicator.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardIndicator.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviDashboardIndicatorBig.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardIndicatorBig.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviDashboardIndicatorBig.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardIndicatorBig.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviDustyBlue.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDustyBlue.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviDustyBlue.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDustyBlue.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviGraphBGColor.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphBGColor.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviGraphBGColor.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphBGColor.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviGraphFillColor.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphFillColor.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviGraphFillColor.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphFillColor.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviGraphLineColor.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphLineColor.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviGraphLineColor.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphLineColor.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviGraphMarkerColor.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphMarkerColor.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviGraphMarkerColor.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphMarkerColor.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviGreen.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGreen.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviGreen.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGreen.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviLineColor.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviLineColor.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviLineColor.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviLineColor.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviLogoTintColor.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviLogoTintColor.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviLogoTintColor.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviLogoTintColor.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviMenuTextColor.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviMenuTextColor.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviMenuTextColor.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviMenuTextColor.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviMenuTintColor.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviMenuTintColor.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviMenuTintColor.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviMenuTintColor.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviOrangeColor.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviOrangeColor.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviOrangeColor.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviOrangeColor.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviPrimary.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviPrimary.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviPrimary.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviPrimary.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviPurple.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviPurple.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviPurple.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviPurple.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviSecondary.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSecondary.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviSecondary.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSecondary.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviSwitchDisabledThumbTint.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSwitchDisabledThumbTint.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviSwitchDisabledThumbTint.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSwitchDisabledThumbTint.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviSwitchDisabledTint.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSwitchDisabledTint.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviSwitchDisabledTint.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSwitchDisabledTint.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviSwitchEnabledTint.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSwitchEnabledTint.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviSwitchEnabledTint.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSwitchEnabledTint.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviTextColor.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviTextColor.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviTextColor.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviTextColor.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/RuuviTintColor.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviTintColor.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/RuuviTintColor.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviTintColor.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/TagSettingsItemHeaderColor.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/TagSettingsItemHeaderColor.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/TagSettingsItemHeaderColor.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/TagSettingsItemHeaderColor.colorset/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/TagSettingsSectionHeaderColor.colorset/Contents.json b/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/TagSettingsSectionHeaderColor.colorset/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/TagSettingsSectionHeaderColor.colorset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/TagSettingsSectionHeaderColor.colorset/Contents.json diff --git a/ruuvi-widgets/Resources/Fonts/Montserrat-Bold.ttf b/Apps/RuuviStation/Sources/Resources/Fonts/Montserrat-Bold.ttf similarity index 100% rename from ruuvi-widgets/Resources/Fonts/Montserrat-Bold.ttf rename to Apps/RuuviStation/Sources/Resources/Fonts/Montserrat-Bold.ttf diff --git a/station/Resources/Fonts/Montserrat-ExtraBold.ttf b/Apps/RuuviStation/Sources/Resources/Fonts/Montserrat-ExtraBold.ttf similarity index 100% rename from station/Resources/Fonts/Montserrat-ExtraBold.ttf rename to Apps/RuuviStation/Sources/Resources/Fonts/Montserrat-ExtraBold.ttf diff --git a/ruuvi-widgets/Resources/Fonts/Montserrat-Regular.ttf b/Apps/RuuviStation/Sources/Resources/Fonts/Montserrat-Regular.ttf similarity index 100% rename from ruuvi-widgets/Resources/Fonts/Montserrat-Regular.ttf rename to Apps/RuuviStation/Sources/Resources/Fonts/Montserrat-Regular.ttf diff --git a/ruuvi-widgets/Resources/Fonts/Muli-Bold.ttf b/Apps/RuuviStation/Sources/Resources/Fonts/Muli-Bold.ttf similarity index 100% rename from ruuvi-widgets/Resources/Fonts/Muli-Bold.ttf rename to Apps/RuuviStation/Sources/Resources/Fonts/Muli-Bold.ttf diff --git a/station/Resources/Fonts/Muli-ExtraBold.ttf b/Apps/RuuviStation/Sources/Resources/Fonts/Muli-ExtraBold.ttf similarity index 100% rename from station/Resources/Fonts/Muli-ExtraBold.ttf rename to Apps/RuuviStation/Sources/Resources/Fonts/Muli-ExtraBold.ttf diff --git a/ruuvi-widgets/Resources/Fonts/Muli-Regular.ttf b/Apps/RuuviStation/Sources/Resources/Fonts/Muli-Regular.ttf similarity index 100% rename from ruuvi-widgets/Resources/Fonts/Muli-Regular.ttf rename to Apps/RuuviStation/Sources/Resources/Fonts/Muli-Regular.ttf diff --git a/station/Resources/Fonts/Muli-SemiBoldItalic.ttf b/Apps/RuuviStation/Sources/Resources/Fonts/Muli-SemiBoldItalic.ttf similarity index 100% rename from station/Resources/Fonts/Muli-SemiBoldItalic.ttf rename to Apps/RuuviStation/Sources/Resources/Fonts/Muli-SemiBoldItalic.ttf diff --git a/ruuvi-widgets/Resources/Fonts/Oswald-Bold.ttf b/Apps/RuuviStation/Sources/Resources/Fonts/Oswald-Bold.ttf similarity index 100% rename from ruuvi-widgets/Resources/Fonts/Oswald-Bold.ttf rename to Apps/RuuviStation/Sources/Resources/Fonts/Oswald-Bold.ttf diff --git a/ruuvi-widgets/Resources/Fonts/Oswald-ExtraLight.ttf b/Apps/RuuviStation/Sources/Resources/Fonts/Oswald-ExtraLight.ttf similarity index 100% rename from ruuvi-widgets/Resources/Fonts/Oswald-ExtraLight.ttf rename to Apps/RuuviStation/Sources/Resources/Fonts/Oswald-ExtraLight.ttf diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20@2x-1.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20@2x-1.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20@2x-1.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20@2x-1.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29@2x-1.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40@2x-1.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40@2x-1.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40@2x-1.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40@2x-1.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-76.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-76.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-76.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-76.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png diff --git a/station/Resources/Images/Assets.xcassets/AppIcon.appiconset/iTunesArtwork@2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/iTunesArtwork@2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/AppIcon.appiconset/iTunesArtwork@2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/AppIcon.appiconset/iTunesArtwork@2x.png diff --git a/ruuvi-widgets/Assets.xcassets/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Contents.json similarity index 100% rename from ruuvi-widgets/Assets.xcassets/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Contents.json diff --git a/station/Resources/Colors/Colors.xcassets/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/Contents.json similarity index 100% rename from station/Resources/Colors/Colors.xcassets/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg1.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg1.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg1.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg1.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg1.imageset/bg1.jpg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg1.imageset/bg1.jpg similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg1.imageset/bg1.jpg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg1.imageset/bg1.jpg diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg10.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg10.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg10.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg10.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg10.imageset/new_bg5.jpeg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg10.imageset/new_bg5.jpeg similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg10.imageset/new_bg5.jpeg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg10.imageset/new_bg5.jpeg diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg11.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg11.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg11.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg11.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg11.imageset/new_bg6.jpeg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg11.imageset/new_bg6.jpeg similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg11.imageset/new_bg6.jpeg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg11.imageset/new_bg6.jpeg diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg12.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg12.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg12.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg12.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg12.imageset/new_bg7.jpeg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg12.imageset/new_bg7.jpeg similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg12.imageset/new_bg7.jpeg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg12.imageset/new_bg7.jpeg diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg13.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg13.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg13.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg13.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg13.imageset/new_bg8.jpeg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg13.imageset/new_bg8.jpeg similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg13.imageset/new_bg8.jpeg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg13.imageset/new_bg8.jpeg diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg14.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg14.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg14.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg14.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg14.imageset/new_bg9.jpeg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg14.imageset/new_bg9.jpeg similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg14.imageset/new_bg9.jpeg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg14.imageset/new_bg9.jpeg diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg15.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg15.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg15.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg15.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg15.imageset/new_bg10.jpeg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg15.imageset/new_bg10.jpeg similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg15.imageset/new_bg10.jpeg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg15.imageset/new_bg10.jpeg diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg16.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg16.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg16.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg16.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg16.imageset/new_bg2.jpg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg16.imageset/new_bg2.jpg similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg16.imageset/new_bg2.jpg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg16.imageset/new_bg2.jpg diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg2.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg2.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg2.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg2.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg2.imageset/bg2.jpg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg2.imageset/bg2.jpg similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg2.imageset/bg2.jpg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg2.imageset/bg2.jpg diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg3.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg3.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg3.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg3.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg3.imageset/bg3.jpg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg3.imageset/bg3.jpg similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg3.imageset/bg3.jpg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg3.imageset/bg3.jpg diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg4.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg4.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg4.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg4.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg4.imageset/bg4.jpg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg4.imageset/bg4.jpg similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg4.imageset/bg4.jpg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg4.imageset/bg4.jpg diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg5.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg5.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg5.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg5.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg5.imageset/bg5.jpg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg5.imageset/bg5.jpg similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg5.imageset/bg5.jpg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg5.imageset/bg5.jpg diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg6.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg6.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg6.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg6.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg6.imageset/bg6.jpg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg6.imageset/bg6.jpg similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg6.imageset/bg6.jpg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg6.imageset/bg6.jpg diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg7.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg7.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg7.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg7.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg7.imageset/bg7.jpg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg7.imageset/bg7.jpg similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg7.imageset/bg7.jpg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg7.imageset/bg7.jpg diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg8.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg8.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg8.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg8.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg8.imageset/bg8.jpg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg8.imageset/bg8.jpg similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg8.imageset/bg8.jpg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg8.imageset/bg8.jpg diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg9.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg9.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg9.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg9.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/bg9.imageset/bg9.jpg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg9.imageset/bg9.jpg similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/bg9.imageset/bg9.jpg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/Default Backgrounds/bg9.imageset/bg9.jpg diff --git a/station/Resources/Images/Assets.xcassets/arrow_drop_down.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/arrow_drop_down.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/arrow_drop_down.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/arrow_drop_down.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/arrow_drop_down.imageset/arrow_drop_down.svg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/arrow_drop_down.imageset/arrow_drop_down.svg similarity index 100% rename from station/Resources/Images/Assets.xcassets/arrow_drop_down.imageset/arrow_drop_down.svg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/arrow_drop_down.imageset/arrow_drop_down.svg diff --git a/station/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_1x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_1x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_1x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_1x.png diff --git a/station/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_2x.png diff --git a/station/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_3x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_3x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_3x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_3x.png diff --git a/station/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_1x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_1x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_1x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_1x.png diff --git a/station/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_2x.png diff --git a/station/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_3x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_3x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_3x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_3x.png diff --git a/station/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_1x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_1x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_1x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_1x.png diff --git a/station/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_2x.png diff --git a/station/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_3x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_3x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_3x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_3x.png diff --git a/station/Resources/Images/Assets.xcassets/beaver-mail.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/beaver-mail.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/beaver-mail.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/beaver-mail.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/beaver-mail.imageset/beaver-mail.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/beaver-mail.imageset/beaver-mail.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/beaver-mail.imageset/beaver-mail.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/beaver-mail.imageset/beaver-mail.png diff --git a/station/Resources/Images/Assets.xcassets/bluetooth-connected.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth-connected.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/bluetooth-connected.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth-connected.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/bluetooth-connected.imageset/bluetooth_connected-24px.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth-connected.imageset/bluetooth_connected-24px.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/bluetooth-connected.imageset/bluetooth_connected-24px.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth-connected.imageset/bluetooth_connected-24px.pdf diff --git a/station/Resources/Images/Assets.xcassets/bluetooth_disabled_icon.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_disabled_icon.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/bluetooth_disabled_icon.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_disabled_icon.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/bluetooth_disabled_icon.imageset/bluetooth_disabled_black_108x108.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_disabled_icon.imageset/bluetooth_disabled_black_108x108.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/bluetooth_disabled_icon.imageset/bluetooth_disabled_black_108x108.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_disabled_icon.imageset/bluetooth_disabled_black_108x108.png diff --git a/station/Resources/Images/Assets.xcassets/bluetooth_icon.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_icon.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/bluetooth_icon.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_icon.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/bluetooth_icon.imageset/bluetooth_white_108x108.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_icon.imageset/bluetooth_white_108x108.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/bluetooth_icon.imageset/bluetooth_white_108x108.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_icon.imageset/bluetooth_white_108x108.png diff --git a/station/Resources/Images/Assets.xcassets/checkmark_icon.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/checkmark_icon.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/checkmark_icon.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/checkmark_icon.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/checkmark_icon.imageset/baseline_check_circle_outline_black_18dp.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/checkmark_icon.imageset/baseline_check_circle_outline_black_18dp.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/checkmark_icon.imageset/baseline_check_circle_outline_black_18dp.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/checkmark_icon.imageset/baseline_check_circle_outline_black_18dp.png diff --git a/station/Resources/Images/Assets.xcassets/chevron.down.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron.down.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/chevron.down.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron.down.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/chevron.down.imageset/chevron.down.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron.down.imageset/chevron.down.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/chevron.down.imageset/chevron.down.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron.down.imageset/chevron.down.pdf diff --git a/station/Resources/Images/Assets.xcassets/chevron.up.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron.up.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/chevron.up.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron.up.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/chevron.up.imageset/chevron.up.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron.up.imageset/chevron.up.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/chevron.up.imageset/chevron.up.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron.up.imageset/chevron.up.pdf diff --git a/station/Resources/Images/Assets.xcassets/chevron_back.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron_back.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/chevron_back.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron_back.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back.png diff --git a/station/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back@2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back@2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back@2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back@2x.png diff --git a/station/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back@3x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back@3x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back@3x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back@3x.png diff --git a/station/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down.png diff --git a/station/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down@2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down@2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down@2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down@2x.png diff --git a/station/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down@3x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down@3x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down@3x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down@3x.png diff --git a/station/Resources/Images/Assets.xcassets/edit_pen.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/edit_pen.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/edit_pen.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/edit_pen.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/edit_pen.imageset/edit_pen.svg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/edit_pen.imageset/edit_pen.svg similarity index 100% rename from station/Resources/Images/Assets.xcassets/edit_pen.imageset/edit_pen.svg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/edit_pen.imageset/edit_pen.svg diff --git a/station/Resources/Images/Assets.xcassets/eye_circle.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/eye_circle.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/eye_circle.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/eye_circle.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/eye_circle.imageset/eye_circle.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/eye_circle.imageset/eye_circle.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/eye_circle.imageset/eye_circle.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/eye_circle.imageset/eye_circle.png diff --git a/station/Resources/Images/Assets.xcassets/gesture-assistant-hand.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gesture-assistant-hand.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/gesture-assistant-hand.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gesture-assistant-hand.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/gesture-assistant-hand.imageset/hand.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gesture-assistant-hand.imageset/hand.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/gesture-assistant-hand.imageset/hand.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gesture-assistant-hand.imageset/hand.pdf diff --git a/station/Resources/Images/Assets.xcassets/gradient_layer.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gradient_layer.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/gradient_layer.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gradient_layer.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/gradient_layer.imageset/gradient_layer.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gradient_layer.imageset/gradient_layer.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/gradient_layer.imageset/gradient_layer.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gradient_layer.imageset/gradient_layer.png diff --git a/station/Resources/Images/Assets.xcassets/ic_refresh.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ic_refresh.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/ic_refresh.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ic_refresh.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/ic_refresh.imageset/ic_refresh_24px.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ic_refresh.imageset/ic_refresh_24px.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/ic_refresh.imageset/ic_refresh_24px.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ic_refresh.imageset/ic_refresh_24px.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon-alert-active.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-active.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-alert-active.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-active.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-alert-active.imageset/active.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-active.imageset/active.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-alert-active.imageset/active.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-active.imageset/active.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon-alert-off.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-off.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-alert-off.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-off.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-alert-off.imageset/alert-off.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-off.imageset/alert-off.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-alert-off.imageset/alert-off.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-off.imageset/alert-off.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon-alert-on.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-on.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-alert-on.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-on.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-alert-on.imageset/alert-on.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-on.imageset/alert-on.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-alert-on.imageset/alert-on.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-on.imageset/alert-on.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon-bg-camera.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bg-camera.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-bg-camera.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bg-camera.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-bg-camera.imageset/icon-bg-camera-1.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bg-camera.imageset/icon-bg-camera-1.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-bg-camera.imageset/icon-bg-camera-1.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bg-camera.imageset/icon-bg-camera-1.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon-bluetooth-connected.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bluetooth-connected.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-bluetooth-connected.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bluetooth-connected.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-bluetooth-connected.imageset/icon-bluetooth-connected.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bluetooth-connected.imageset/icon-bluetooth-connected.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-bluetooth-connected.imageset/icon-bluetooth-connected.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bluetooth-connected.imageset/icon-bluetooth-connected.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon-bluetooth.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bluetooth.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-bluetooth.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bluetooth.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-bluetooth.imageset/icon-bluetooth.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bluetooth.imageset/icon-bluetooth.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-bluetooth.imageset/icon-bluetooth.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bluetooth.imageset/icon-bluetooth.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon-cards-button.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-cards-button.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-cards-button.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-cards-button.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-cards-button.imageset/vector.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-cards-button.imageset/vector.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-cards-button.imageset/vector.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-cards-button.imageset/vector.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon-charts-button.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-charts-button.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-charts-button.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-charts-button.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-charts-button.imageset/vector-3.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-charts-button.imageset/vector-3.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-charts-button.imageset/vector-3.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-charts-button.imageset/vector-3.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon-connectable.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connectable.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-connectable.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connectable.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected-1.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected-1.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected-1.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected-1.png diff --git a/station/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected-2.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected-2.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected-2.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected-2.png diff --git a/station/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected.png diff --git a/station/Resources/Images/Assets.xcassets/icon-connection-1.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-1.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-connection-1.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-1.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-connection-1.imageset/icon-connection-1.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-1.imageset/icon-connection-1.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-connection-1.imageset/icon-connection-1.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-1.imageset/icon-connection-1.png diff --git a/station/Resources/Images/Assets.xcassets/icon-connection-2.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-2.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-connection-2.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-2.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-connection-2.imageset/icon-connection-2.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-2.imageset/icon-connection-2.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-connection-2.imageset/icon-connection-2.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-2.imageset/icon-connection-2.png diff --git a/station/Resources/Images/Assets.xcassets/icon-connection-3.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-3.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-connection-3.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-3.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-connection-3.imageset/icon-connection-3.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-3.imageset/icon-connection-3.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-connection-3.imageset/icon-connection-3.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-3.imageset/icon-connection-3.png diff --git a/station/Resources/Images/Assets.xcassets/icon-delete-forever.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-delete-forever.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-delete-forever.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-delete-forever.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-delete-forever.imageset/delete_forever_48px.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-delete-forever.imageset/delete_forever_48px.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-delete-forever.imageset/delete_forever_48px.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-delete-forever.imageset/delete_forever_48px.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon-download.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-download.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-download.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-download.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-download.imageset/download.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-download.imageset/download.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-download.imageset/download.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-download.imageset/download.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon-gateway.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-gateway.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-gateway.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-gateway.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-gateway.imageset/icon-gateway.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-gateway.imageset/icon-gateway.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-gateway.imageset/icon-gateway.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-gateway.imageset/icon-gateway.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon-measure-humidity.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-humidity.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-measure-humidity.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-humidity.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-measure-humidity.imageset/icon-measure-humidity.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-humidity.imageset/icon-measure-humidity.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-measure-humidity.imageset/icon-measure-humidity.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-humidity.imageset/icon-measure-humidity.png diff --git a/station/Resources/Images/Assets.xcassets/icon-measure-location.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-measure-location.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon-measure.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon-measure.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon-measure.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon-measure.png diff --git a/station/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon-measure@2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon-measure@2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon-measure@2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon-measure@2x.png diff --git a/station/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon_measure@3x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon_measure@3x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon_measure@3x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon_measure@3x.png diff --git a/station/Resources/Images/Assets.xcassets/icon-measure-movement.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-movement.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-measure-movement.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-movement.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-measure-movement.imageset/icon-measure-movement.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-movement.imageset/icon-measure-movement.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-measure-movement.imageset/icon-measure-movement.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-movement.imageset/icon-measure-movement.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon-measure-pressure.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-pressure.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-measure-pressure.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-pressure.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-measure-pressure.imageset/icon-measure-pressure.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-pressure.imageset/icon-measure-pressure.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-measure-pressure.imageset/icon-measure-pressure.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-pressure.imageset/icon-measure-pressure.png diff --git a/station/Resources/Images/Assets.xcassets/icon-measure-signal.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-signal.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-measure-signal.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-signal.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-measure-signal.imageset/icon-measure-signal.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-signal.imageset/icon-measure-signal.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-measure-signal.imageset/icon-measure-signal.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-signal.imageset/icon-measure-signal.png diff --git a/station/Resources/Images/Assets.xcassets/icon-refresh.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-refresh.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-refresh.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-refresh.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-refresh.imageset/sync_48px.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-refresh.imageset/sync_48px.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-refresh.imageset/sync_48px.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-refresh.imageset/sync_48px.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon-warning.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-warning.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-warning.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-warning.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-warning.imageset/warning-sign.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-warning.imageset/warning-sign.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-warning.imageset/warning-sign.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-warning.imageset/warning-sign.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon-weatherstation.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-weatherstation.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-weatherstation.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-weatherstation.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon-weatherstation.imageset/icon-weatherstation.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-weatherstation.imageset/icon-weatherstation.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon-weatherstation.imageset/icon-weatherstation.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-weatherstation.imageset/icon-weatherstation.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon_back_arrow.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon_back_arrow.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon_back_arrow.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon_back_arrow.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon_back_arrow.imageset/icons8-back.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon_back_arrow.imageset/icons8-back.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon_back_arrow.imageset/icons8-back.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon_back_arrow.imageset/icons8-back.pdf diff --git a/station/Resources/Images/Assets.xcassets/icon_sync_bt.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon_sync_bt.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon_sync_bt.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon_sync_bt.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/icon_sync_bt.imageset/icon_sync_bt.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon_sync_bt.imageset/icon_sync_bt.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/icon_sync_bt.imageset/icon_sync_bt.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon_sync_bt.imageset/icon_sync_bt.png diff --git a/station/Resources/Images/Assets.xcassets/iphone_icon.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/iphone_icon.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/iphone_icon.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/iphone_icon.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/iphone_icon.imageset/phone_black.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/iphone_icon.imageset/phone_black.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/iphone_icon.imageset/phone_black.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/iphone_icon.imageset/phone_black.png diff --git a/station/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon.png diff --git a/station/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@2x.png diff --git a/station/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@3x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@3x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@3x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@3x.png diff --git a/station/Resources/Images/Assets.xcassets/more_3dot.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/more_3dot.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/more_3dot.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/more_3dot.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/more_3dot.imageset/more_3dot.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/more_3dot.imageset/more_3dot.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/more_3dot.imageset/more_3dot.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/more_3dot.imageset/more_3dot.pdf diff --git a/station/Resources/Images/Assets.xcassets/no-image.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/no-image.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/no-image.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/no-image.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/no-image.imageset/icons8-no_image.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/no-image.imageset/icons8-no_image.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/no-image.imageset/icons8-no_image.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/no-image.imageset/icons8-no_image.pdf diff --git a/station/Resources/Images/Assets.xcassets/plus_icon.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/plus_icon.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/plus_icon.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/plus_icon.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/plus_icon.imageset/icons8-plus-math-filled-100.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/plus_icon.imageset/icons8-plus-math-filled-100.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/plus_icon.imageset/icons8-plus-math-filled-100.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/plus_icon.imageset/icons8-plus-math-filled-100.png diff --git a/station/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset/Contents.json diff --git a/ruuvi-widgets/Assets.xcassets/ruuvi_logo.imageset/ruuvi_logo.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset/ruuvi_logo.png similarity index 100% rename from ruuvi-widgets/Assets.xcassets/ruuvi_logo.imageset/ruuvi_logo.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset/ruuvi_logo.png diff --git a/station/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/web-ruuvi-eye-nega.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/web-ruuvi-eye-nega.pdf similarity index 100% rename from station/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/web-ruuvi-eye-nega.pdf rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/web-ruuvi-eye-nega.pdf diff --git a/station/Resources/Images/Assets.xcassets/ruuvi_station.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/ruuvi_station.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station.png diff --git a/station/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station_2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station_2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station_2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station_2x.png diff --git a/station/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station_3x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station_3x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station_3x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station_3x.png diff --git a/station/Resources/Images/Assets.xcassets/sign_in_bg_layer.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/sign_in_bg_layer.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/sign_in_bg_layer.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/sign_in_bg_layer.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/sign_in_bg_layer.imageset/bg_layer_dark.jpg b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/sign_in_bg_layer.imageset/bg_layer_dark.jpg similarity index 100% rename from station/Resources/Images/Assets.xcassets/sign_in_bg_layer.imageset/bg_layer_dark.jpg rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/sign_in_bg_layer.imageset/bg_layer_dark.jpg diff --git a/station/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_1x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_1x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_1x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_1x.png diff --git a/station/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_2x.png diff --git a/station/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_3x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_3x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_3x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_3x.png diff --git a/station/Resources/Images/Assets.xcassets/tag-settings-info-icon.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag-settings-info-icon.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/tag-settings-info-icon.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag-settings-info-icon.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/tag-settings-info-icon.imageset/info_icon.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag-settings-info-icon.imageset/info_icon.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/tag-settings-info-icon.imageset/info_icon.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag-settings-info-icon.imageset/info_icon.png diff --git a/station/Resources/Images/Assets.xcassets/tag_bg_layer.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag_bg_layer.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/tag_bg_layer.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag_bg_layer.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/tag_bg_layer.imageset/tag_bg_layer.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag_bg_layer.imageset/tag_bg_layer.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/tag_bg_layer.imageset/tag_bg_layer.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag_bg_layer.imageset/tag_bg_layer.png diff --git a/station/Resources/Images/Assets.xcassets/welcome_friend.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/welcome_friend.imageset/Contents.json rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome1x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome1x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome1x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome1x.png diff --git a/station/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome2x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome2x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome2x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome2x.png diff --git a/station/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome3x.png b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome3x.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome3x.png rename to Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome3x.png diff --git a/station/Resources/Images/ruuvi_logo_splash.png b/Apps/RuuviStation/Sources/Resources/Images/ruuvi_logo_splash.png similarity index 100% rename from station/Resources/Images/ruuvi_logo_splash.png rename to Apps/RuuviStation/Sources/Resources/Images/ruuvi_logo_splash.png diff --git a/station/Resources/Images/splash_bg_layer_dark.jpg b/Apps/RuuviStation/Sources/Resources/Images/splash_bg_layer_dark.jpg similarity index 100% rename from station/Resources/Images/splash_bg_layer_dark.jpg rename to Apps/RuuviStation/Sources/Resources/Images/splash_bg_layer_dark.jpg diff --git a/station/Resources/JSONs/FeatureToggles.json b/Apps/RuuviStation/Sources/Resources/JSONs/FeatureToggles.json similarity index 100% rename from station/Resources/JSONs/FeatureToggles.json rename to Apps/RuuviStation/Sources/Resources/JSONs/FeatureToggles.json diff --git a/station/Resources/Plists/GoogleService-Info.plist b/Apps/RuuviStation/Sources/Resources/Plists/GoogleService-Info.plist similarity index 100% rename from station/Resources/Plists/GoogleService-Info.plist rename to Apps/RuuviStation/Sources/Resources/Plists/GoogleService-Info.plist diff --git a/station/Resources/Plists/Networking.plist b/Apps/RuuviStation/Sources/Resources/Plists/Networking.plist similarity index 81% rename from station/Resources/Plists/Networking.plist rename to Apps/RuuviStation/Sources/Resources/Plists/Networking.plist index 42fcbc762..33a933d9b 100644 --- a/station/Resources/Plists/Networking.plist +++ b/Apps/RuuviStation/Sources/Resources/Plists/Networking.plist @@ -2,8 +2,6 @@ - OpenWeatherMapAPIKey - { set your API key here } RuuviCloudURL https://network.ruuvi.com RuuviCloudURLDev diff --git a/station/Resources/Plists/iOSDeviceModelMapping.plist b/Apps/RuuviStation/Sources/Resources/Plists/iOSDeviceModelMapping.plist similarity index 100% rename from station/Resources/Plists/iOSDeviceModelMapping.plist rename to Apps/RuuviStation/Sources/Resources/Plists/iOSDeviceModelMapping.plist diff --git a/station/Resources/Sounds/ruuvi_speak.caf b/Apps/RuuviStation/Sources/Resources/Sounds/ruuvi_speak.caf similarity index 100% rename from station/Resources/Sounds/ruuvi_speak.caf rename to Apps/RuuviStation/Sources/Resources/Sounds/ruuvi_speak.caf diff --git a/station/Resources/Strings/de.lproj/InfoPlist.strings b/Apps/RuuviStation/Sources/Resources/Strings/de.lproj/InfoPlist.strings similarity index 100% rename from station/Resources/Strings/de.lproj/InfoPlist.strings rename to Apps/RuuviStation/Sources/Resources/Strings/de.lproj/InfoPlist.strings diff --git a/station/Resources/Strings/en.lproj/InfoPlist.strings b/Apps/RuuviStation/Sources/Resources/Strings/en.lproj/InfoPlist.strings similarity index 100% rename from station/Resources/Strings/en.lproj/InfoPlist.strings rename to Apps/RuuviStation/Sources/Resources/Strings/en.lproj/InfoPlist.strings diff --git a/station/Resources/Strings/fi.lproj/InfoPlist.strings b/Apps/RuuviStation/Sources/Resources/Strings/fi.lproj/InfoPlist.strings similarity index 100% rename from station/Resources/Strings/fi.lproj/InfoPlist.strings rename to Apps/RuuviStation/Sources/Resources/Strings/fi.lproj/InfoPlist.strings diff --git a/station/Resources/Strings/fr.lproj/InfoPlist.strings b/Apps/RuuviStation/Sources/Resources/Strings/fr.lproj/InfoPlist.strings similarity index 100% rename from station/Resources/Strings/fr.lproj/InfoPlist.strings rename to Apps/RuuviStation/Sources/Resources/Strings/fr.lproj/InfoPlist.strings diff --git a/station/Resources/Strings/ru.lproj/InfoPlist.strings b/Apps/RuuviStation/Sources/Resources/Strings/ru.lproj/InfoPlist.strings similarity index 100% rename from station/Resources/Strings/ru.lproj/InfoPlist.strings rename to Apps/RuuviStation/Sources/Resources/Strings/ru.lproj/InfoPlist.strings diff --git a/station/Resources/Strings/sv.lproj/InfoPlist.strings b/Apps/RuuviStation/Sources/Resources/Strings/sv.lproj/InfoPlist.strings similarity index 100% rename from station/Resources/Strings/sv.lproj/InfoPlist.strings rename to Apps/RuuviStation/Sources/Resources/Strings/sv.lproj/InfoPlist.strings diff --git a/station/station.entitlements b/Apps/RuuviStation/Sources/Station.entitlements similarity index 100% rename from station/station.entitlements rename to Apps/RuuviStation/Sources/Station.entitlements diff --git a/stationTests/Extensions/XCTest+Extension.swift b/Apps/RuuviStation/Tests/Unit/Extensions/XCTest+Extension.swift similarity index 100% rename from stationTests/Extensions/XCTest+Extension.swift rename to Apps/RuuviStation/Tests/Unit/Extensions/XCTest+Extension.swift diff --git a/stationTests/Info.plist b/Apps/RuuviStation/Tests/Unit/Info.plist similarity index 100% rename from stationTests/Info.plist rename to Apps/RuuviStation/Tests/Unit/Info.plist diff --git a/stationTests/MockAlertPersistence.swift b/Apps/RuuviStation/Tests/Unit/MockAlertPersistence.swift similarity index 100% rename from stationTests/MockAlertPersistence.swift rename to Apps/RuuviStation/Tests/Unit/MockAlertPersistence.swift diff --git a/stationTests/MockAlertServiceObserver.swift b/Apps/RuuviStation/Tests/Unit/MockAlertServiceObserver.swift similarity index 100% rename from stationTests/MockAlertServiceObserver.swift rename to Apps/RuuviStation/Tests/Unit/MockAlertServiceObserver.swift diff --git a/stationTests/MockCalibrationService.swift b/Apps/RuuviStation/Tests/Unit/MockCalibrationService.swift similarity index 100% rename from stationTests/MockCalibrationService.swift rename to Apps/RuuviStation/Tests/Unit/MockCalibrationService.swift diff --git a/stationTests/MockLocalNotificationsManager.swift b/Apps/RuuviStation/Tests/Unit/MockLocalNotificationsManager.swift similarity index 100% rename from stationTests/MockLocalNotificationsManager.swift rename to Apps/RuuviStation/Tests/Unit/MockLocalNotificationsManager.swift diff --git a/stationTests/MockRuuviTag.swift b/Apps/RuuviStation/Tests/Unit/MockRuuviTag.swift similarity index 100% rename from stationTests/MockRuuviTag.swift rename to Apps/RuuviStation/Tests/Unit/MockRuuviTag.swift diff --git a/stationTests/Services/Alert/AlertServiceSpec.swift b/Apps/RuuviStation/Tests/Unit/Services/Alert/AlertServiceSpec.swift similarity index 100% rename from stationTests/Services/Alert/AlertServiceSpec.swift rename to Apps/RuuviStation/Tests/Unit/Services/Alert/AlertServiceSpec.swift diff --git a/stationTests/Services/MeasurementsService/MeasurementsServiceEnSpec.swift b/Apps/RuuviStation/Tests/Unit/Services/MeasurementsService/MeasurementsServiceEnSpec.swift similarity index 100% rename from stationTests/Services/MeasurementsService/MeasurementsServiceEnSpec.swift rename to Apps/RuuviStation/Tests/Unit/Services/MeasurementsService/MeasurementsServiceEnSpec.swift diff --git a/stationTests/Services/MeasurementsService/MeasurementsServiceFiSpec.swift b/Apps/RuuviStation/Tests/Unit/Services/MeasurementsService/MeasurementsServiceFiSpec.swift similarity index 100% rename from stationTests/Services/MeasurementsService/MeasurementsServiceFiSpec.swift rename to Apps/RuuviStation/Tests/Unit/Services/MeasurementsService/MeasurementsServiceFiSpec.swift diff --git a/stationTests/Services/MeasurementsService/MeasurementsServiceRuSpec.swift b/Apps/RuuviStation/Tests/Unit/Services/MeasurementsService/MeasurementsServiceRuSpec.swift similarity index 100% rename from stationTests/Services/MeasurementsService/MeasurementsServiceRuSpec.swift rename to Apps/RuuviStation/Tests/Unit/Services/MeasurementsService/MeasurementsServiceRuSpec.swift diff --git a/stationTests/Services/MeasurementsService/MeasurementsServiceSvSpec.swift b/Apps/RuuviStation/Tests/Unit/Services/MeasurementsService/MeasurementsServiceSvSpec.swift similarity index 100% rename from stationTests/Services/MeasurementsService/MeasurementsServiceSvSpec.swift rename to Apps/RuuviStation/Tests/Unit/Services/MeasurementsService/MeasurementsServiceSvSpec.swift diff --git a/stationTests/StationTests.swift b/Apps/RuuviStation/Tests/Unit/StationTests.swift similarity index 100% rename from stationTests/StationTests.swift rename to Apps/RuuviStation/Tests/Unit/StationTests.swift diff --git a/ruuvi-widgets/Info.plist b/Apps/RuuviStation/Widgets/Info.plist similarity index 100% rename from ruuvi-widgets/Info.plist rename to Apps/RuuviStation/Widgets/Info.plist diff --git a/ruuvi-widgets/Assembly/WidgetAssembly.swift b/Apps/RuuviStation/Widgets/Sources/Assembly/WidgetAssembly.swift similarity index 100% rename from ruuvi-widgets/Assembly/WidgetAssembly.swift rename to Apps/RuuviStation/Widgets/Sources/Assembly/WidgetAssembly.swift diff --git a/ruuvi-widgets/Assets.xcassets/AccentColor.colorset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from ruuvi-widgets/Assets.xcassets/AccentColor.colorset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/ruuvi-widgets/Assets.xcassets/AppIcon.appiconset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from ruuvi-widgets/Assets.xcassets/AppIcon.appiconset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/ruuvi-widgets/Assets.xcassets/Colors/BackgroundColor.colorset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/BackgroundColor.colorset/Contents.json similarity index 100% rename from ruuvi-widgets/Assets.xcassets/Colors/BackgroundColor.colorset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/BackgroundColor.colorset/Contents.json diff --git a/ruuvi-widgets/Assets.xcassets/Colors/BodyTextColor.colorset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/BodyTextColor.colorset/Contents.json similarity index 100% rename from ruuvi-widgets/Assets.xcassets/Colors/BodyTextColor.colorset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/BodyTextColor.colorset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Contents.json b/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/Contents.json diff --git a/ruuvi-widgets/Assets.xcassets/Colors/LogoColor.colorset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/LogoColor.colorset/Contents.json similarity index 100% rename from ruuvi-widgets/Assets.xcassets/Colors/LogoColor.colorset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/LogoColor.colorset/Contents.json diff --git a/ruuvi-widgets/Assets.xcassets/Colors/SensorNameColor1.colorset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/SensorNameColor1.colorset/Contents.json similarity index 100% rename from ruuvi-widgets/Assets.xcassets/Colors/SensorNameColor1.colorset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/SensorNameColor1.colorset/Contents.json diff --git a/ruuvi-widgets/Assets.xcassets/Colors/SensorNameColor2.colorset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/SensorNameColor2.colorset/Contents.json similarity index 100% rename from ruuvi-widgets/Assets.xcassets/Colors/SensorNameColor2.colorset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/SensorNameColor2.colorset/Contents.json diff --git a/ruuvi-widgets/Assets.xcassets/Colors/UnitTextColor.colorset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/UnitTextColor.colorset/Contents.json similarity index 100% rename from ruuvi-widgets/Assets.xcassets/Colors/UnitTextColor.colorset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/UnitTextColor.colorset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/Default Backgrounds/Contents.json b/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Contents.json similarity index 100% rename from station/Resources/Images/Assets.xcassets/Default Backgrounds/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Contents.json diff --git a/ruuvi-widgets/Assets.xcassets/eye_circle.imageset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/eye_circle.imageset/Contents.json similarity index 100% rename from ruuvi-widgets/Assets.xcassets/eye_circle.imageset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Assets.xcassets/eye_circle.imageset/Contents.json diff --git a/ruuvi-widgets/Assets.xcassets/eye_circle.imageset/web-ruuvi-eye-nega.png b/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/eye_circle.imageset/web-ruuvi-eye-nega.png similarity index 100% rename from ruuvi-widgets/Assets.xcassets/eye_circle.imageset/web-ruuvi-eye-nega.png rename to Apps/RuuviStation/Widgets/Sources/Assets.xcassets/eye_circle.imageset/web-ruuvi-eye-nega.png diff --git a/ruuvi-widgets/Assets.xcassets/ruuvi_logo.imageset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/ruuvi_logo.imageset/Contents.json similarity index 100% rename from ruuvi-widgets/Assets.xcassets/ruuvi_logo.imageset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Assets.xcassets/ruuvi_logo.imageset/Contents.json diff --git a/station/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset/ruuvi_logo.png b/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/ruuvi_logo.imageset/ruuvi_logo.png similarity index 100% rename from station/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset/ruuvi_logo.png rename to Apps/RuuviStation/Widgets/Sources/Assets.xcassets/ruuvi_logo.imageset/ruuvi_logo.png diff --git a/ruuvi-widgets/Base.lproj/RuuviWidgetsConfiguration.intentdefinition b/Apps/RuuviStation/Widgets/Sources/Base.lproj/RuuviWidgetsConfiguration.intentdefinition similarity index 100% rename from ruuvi-widgets/Base.lproj/RuuviWidgetsConfiguration.intentdefinition rename to Apps/RuuviStation/Widgets/Sources/Base.lproj/RuuviWidgetsConfiguration.intentdefinition diff --git a/ruuvi-widgets/Enum/WidgetSensorEnum.swift b/Apps/RuuviStation/Widgets/Sources/Enum/WidgetSensorEnum.swift similarity index 100% rename from ruuvi-widgets/Enum/WidgetSensorEnum.swift rename to Apps/RuuviStation/Widgets/Sources/Enum/WidgetSensorEnum.swift diff --git a/ruuvi-widgets/Helper/Constants.swift b/Apps/RuuviStation/Widgets/Sources/Helper/Constants.swift similarity index 100% rename from ruuvi-widgets/Helper/Constants.swift rename to Apps/RuuviStation/Widgets/Sources/Helper/Constants.swift diff --git a/ruuvi-widgets/Helper/Extensions.swift b/Apps/RuuviStation/Widgets/Sources/Helper/Extensions.swift similarity index 100% rename from ruuvi-widgets/Helper/Extensions.swift rename to Apps/RuuviStation/Widgets/Sources/Helper/Extensions.swift diff --git a/ruuvi-widgets/Helper/MeasurementService.swift b/Apps/RuuviStation/Widgets/Sources/Helper/MeasurementService.swift similarity index 100% rename from ruuvi-widgets/Helper/MeasurementService.swift rename to Apps/RuuviStation/Widgets/Sources/Helper/MeasurementService.swift diff --git a/ruuvi-widgets/Helper/NetworkManager.swift b/Apps/RuuviStation/Widgets/Sources/Helper/NetworkManager.swift similarity index 100% rename from ruuvi-widgets/Helper/NetworkManager.swift rename to Apps/RuuviStation/Widgets/Sources/Helper/NetworkManager.swift diff --git a/Apps/RuuviStation/Widgets/Sources/Info.plist b/Apps/RuuviStation/Widgets/Sources/Info.plist new file mode 100644 index 000000000..df44555c2 --- /dev/null +++ b/Apps/RuuviStation/Widgets/Sources/Info.plist @@ -0,0 +1,40 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Ruuvi Station + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSExtension + + NSExtensionPointIdentifier + com.apple.widgetkit-extension + + NSHumanReadableCopyright + Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. + UIAppFonts + + Oswald-Bold.ttf + Oswald-ExtraLight.ttf + Muli-Regular.ttf + Muli-Bold.ttf + Montserrat-Bold.ttf + Montserrat-Regular.ttf + + + diff --git a/ruuvi-widgets/Model/Model+Extension.swift b/Apps/RuuviStation/Widgets/Sources/Model/Model+Extension.swift similarity index 100% rename from ruuvi-widgets/Model/Model+Extension.swift rename to Apps/RuuviStation/Widgets/Sources/Model/Model+Extension.swift diff --git a/ruuvi-widgets/Model/WidgetEntry.swift b/Apps/RuuviStation/Widgets/Sources/Model/WidgetEntry.swift similarity index 100% rename from ruuvi-widgets/Model/WidgetEntry.swift rename to Apps/RuuviStation/Widgets/Sources/Model/WidgetEntry.swift diff --git a/ruuvi-widgets/Provider/WidgetProvider.swift b/Apps/RuuviStation/Widgets/Sources/Provider/WidgetProvider.swift similarity index 100% rename from ruuvi-widgets/Provider/WidgetProvider.swift rename to Apps/RuuviStation/Widgets/Sources/Provider/WidgetProvider.swift diff --git a/station/Resources/Fonts/Montserrat-Bold.ttf b/Apps/RuuviStation/Widgets/Sources/Resources/Fonts/Montserrat-Bold.ttf similarity index 100% rename from station/Resources/Fonts/Montserrat-Bold.ttf rename to Apps/RuuviStation/Widgets/Sources/Resources/Fonts/Montserrat-Bold.ttf diff --git a/station/Resources/Fonts/Montserrat-Regular.ttf b/Apps/RuuviStation/Widgets/Sources/Resources/Fonts/Montserrat-Regular.ttf similarity index 100% rename from station/Resources/Fonts/Montserrat-Regular.ttf rename to Apps/RuuviStation/Widgets/Sources/Resources/Fonts/Montserrat-Regular.ttf diff --git a/station/Resources/Fonts/Muli-Bold.ttf b/Apps/RuuviStation/Widgets/Sources/Resources/Fonts/Muli-Bold.ttf similarity index 100% rename from station/Resources/Fonts/Muli-Bold.ttf rename to Apps/RuuviStation/Widgets/Sources/Resources/Fonts/Muli-Bold.ttf diff --git a/station/Resources/Fonts/Muli-Regular.ttf b/Apps/RuuviStation/Widgets/Sources/Resources/Fonts/Muli-Regular.ttf similarity index 100% rename from station/Resources/Fonts/Muli-Regular.ttf rename to Apps/RuuviStation/Widgets/Sources/Resources/Fonts/Muli-Regular.ttf diff --git a/station/Resources/Fonts/Oswald-Bold.ttf b/Apps/RuuviStation/Widgets/Sources/Resources/Fonts/Oswald-Bold.ttf similarity index 100% rename from station/Resources/Fonts/Oswald-Bold.ttf rename to Apps/RuuviStation/Widgets/Sources/Resources/Fonts/Oswald-Bold.ttf diff --git a/station/Resources/Fonts/Oswald-ExtraLight.ttf b/Apps/RuuviStation/Widgets/Sources/Resources/Fonts/Oswald-ExtraLight.ttf similarity index 100% rename from station/Resources/Fonts/Oswald-ExtraLight.ttf rename to Apps/RuuviStation/Widgets/Sources/Resources/Fonts/Oswald-ExtraLight.ttf diff --git a/ruuvi-widgets/RuuviWidgets.swift b/Apps/RuuviStation/Widgets/Sources/RuuviWidgets.swift similarity index 100% rename from ruuvi-widgets/RuuviWidgets.swift rename to Apps/RuuviStation/Widgets/Sources/RuuviWidgets.swift diff --git a/ruuvi-widgets/View Model/WidgetViewModel.swift b/Apps/RuuviStation/Widgets/Sources/View Model/WidgetViewModel.swift similarity index 100% rename from ruuvi-widgets/View Model/WidgetViewModel.swift rename to Apps/RuuviStation/Widgets/Sources/View Model/WidgetViewModel.swift diff --git a/ruuvi-widgets/View/EmptyWidgetView.swift b/Apps/RuuviStation/Widgets/Sources/View/EmptyWidgetView.swift similarity index 100% rename from ruuvi-widgets/View/EmptyWidgetView.swift rename to Apps/RuuviStation/Widgets/Sources/View/EmptyWidgetView.swift diff --git a/ruuvi-widgets/View/SimpleWidgetView.swift b/Apps/RuuviStation/Widgets/Sources/View/SimpleWidgetView.swift similarity index 100% rename from ruuvi-widgets/View/SimpleWidgetView.swift rename to Apps/RuuviStation/Widgets/Sources/View/SimpleWidgetView.swift diff --git a/ruuvi-widgets/View/SimpleWidgetViewCircular.swift b/Apps/RuuviStation/Widgets/Sources/View/SimpleWidgetViewCircular.swift similarity index 100% rename from ruuvi-widgets/View/SimpleWidgetViewCircular.swift rename to Apps/RuuviStation/Widgets/Sources/View/SimpleWidgetViewCircular.swift diff --git a/ruuvi-widgets/View/SimpleWidgetViewInline.swift b/Apps/RuuviStation/Widgets/Sources/View/SimpleWidgetViewInline.swift similarity index 100% rename from ruuvi-widgets/View/SimpleWidgetViewInline.swift rename to Apps/RuuviStation/Widgets/Sources/View/SimpleWidgetViewInline.swift diff --git a/ruuvi-widgets/View/SimpleWidgetViewRectangle.swift b/Apps/RuuviStation/Widgets/Sources/View/SimpleWidgetViewRectangle.swift similarity index 100% rename from ruuvi-widgets/View/SimpleWidgetViewRectangle.swift rename to Apps/RuuviStation/Widgets/Sources/View/SimpleWidgetViewRectangle.swift diff --git a/ruuvi-widgets/View/UnauthorizedView.swift b/Apps/RuuviStation/Widgets/Sources/View/UnauthorizedView.swift similarity index 100% rename from ruuvi-widgets/View/UnauthorizedView.swift rename to Apps/RuuviStation/Widgets/Sources/View/UnauthorizedView.swift diff --git a/station_intents.entitlements b/Apps/RuuviStation/Widgets/Sources/Widgets.entitlements similarity index 100% rename from station_intents.entitlements rename to Apps/RuuviStation/Widgets/Sources/Widgets.entitlements diff --git a/ruuvi-widgets/de.lproj/RuuviWidgetsConfiguration.strings b/Apps/RuuviStation/Widgets/Sources/de.lproj/RuuviWidgetsConfiguration.strings similarity index 100% rename from ruuvi-widgets/de.lproj/RuuviWidgetsConfiguration.strings rename to Apps/RuuviStation/Widgets/Sources/de.lproj/RuuviWidgetsConfiguration.strings diff --git a/ruuvi-widgets/en.lproj/RuuviWidgetsConfiguration.strings b/Apps/RuuviStation/Widgets/Sources/en.lproj/RuuviWidgetsConfiguration.strings similarity index 100% rename from ruuvi-widgets/en.lproj/RuuviWidgetsConfiguration.strings rename to Apps/RuuviStation/Widgets/Sources/en.lproj/RuuviWidgetsConfiguration.strings diff --git a/ruuvi-widgets/fi.lproj/RuuviWidgetsConfiguration.strings b/Apps/RuuviStation/Widgets/Sources/fi.lproj/RuuviWidgetsConfiguration.strings similarity index 100% rename from ruuvi-widgets/fi.lproj/RuuviWidgetsConfiguration.strings rename to Apps/RuuviStation/Widgets/Sources/fi.lproj/RuuviWidgetsConfiguration.strings diff --git a/ruuvi-widgets/fr.lproj/RuuviWidgetsConfiguration.strings b/Apps/RuuviStation/Widgets/Sources/fr.lproj/RuuviWidgetsConfiguration.strings similarity index 100% rename from ruuvi-widgets/fr.lproj/RuuviWidgetsConfiguration.strings rename to Apps/RuuviStation/Widgets/Sources/fr.lproj/RuuviWidgetsConfiguration.strings diff --git a/ruuvi-widgets/sv.lproj/RuuviWidgetsConfiguration.strings b/Apps/RuuviStation/Widgets/Sources/sv.lproj/RuuviWidgetsConfiguration.strings similarity index 100% rename from ruuvi-widgets/sv.lproj/RuuviWidgetsConfiguration.strings rename to Apps/RuuviStation/Widgets/Sources/sv.lproj/RuuviWidgetsConfiguration.strings diff --git a/widget.yml b/Apps/RuuviStation/Widgets/target.yml similarity index 86% rename from widget.yml rename to Apps/RuuviStation/Widgets/target.yml index 86c6f773d..28fb675e5 100644 --- a/widget.yml +++ b/Apps/RuuviStation/Widgets/target.yml @@ -1,9 +1,10 @@ +--- targets: station.widgets: type: app-extension platform: iOS info: - path: ruuvi-widgets/Info.plist + path: Info.plist properties: NSExtension: NSExtensionPointIdentifier: com.apple.widgetkit-extension @@ -15,7 +16,7 @@ targets: NSHumanReadableCopyright: Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. settings: base: - CODE_SIGN_ENTITLEMENTS: ruuvi_widgets.entitlements + CODE_SIGN_ENTITLEMENTS: Apps/RuuviStation/Widgets/Sources/Widgets.entitlements configs: Alpha: CODE_SIGN_IDENTITY: "iPhone Distribution" @@ -27,10 +28,14 @@ targets: CODE_SIGN_IDENTITY: "iPhone Distribution" PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.widgets" EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" - sources: - - path: ruuvi-widgets + sources: + - path: Sources/ + name: Widgets + excludes: + - "*.entitlements" + - Info.plist resources: - - path: station/Resources/Strings/ + - path: ../Sources/Resources/Strings/ dependencies: - package: Swinject - package: BTKit diff --git a/Apps/RuuviStation/target.yml b/Apps/RuuviStation/target.yml new file mode 100644 index 000000000..d897952f5 --- /dev/null +++ b/Apps/RuuviStation/target.yml @@ -0,0 +1,138 @@ +--- +targets: + station: + type: application + platform: iOS + sources: + - path: Sources/ + name: Station + excludes: + - "*.entitlements" + - Info.plist + # - path: Widgets/Sources/Widgets.entitlements + # name: Widgets + # - path: Intents/Sources/Intents.entitlements + # name: Intents + # - path: NotificationService/Sources/NotificationService.entitlements + dependencies: + - target: "station.widgets" + - target: "station.intents" + - target: "station.pnservice" + - package: BTKit + - package: Charts + - package: GRDB + - package: LightRoute + - package: Swinject + - package: RangeSeekSlider + - package: NordicDFU + - package: GestureInstructions + - package: Firebase + product: FirebaseMessaging + - package: Firebase + product: FirebaseRemoteConfig + - package: KeychainAccess + - package: Humidity + - package: Future + - package: Realm + - package: Realm + product: RealmSwift + - package: FLEX + - target: RuuviAnalytics + - target: RuuviCloud + - target: RuuviContext + - target: RuuviCore + - target: RuuviDaemon + - target: RuuviDFU + - target: RuuviLocal + - target: RuuviMigration + - target: RuuviNotification + - target: RuuviNotifier + - target: RuuviOntology + - target: RuuviPersistence + - target: RuuviPool + - target: RuuviReactor + - target: RuuviRepository + - target: RuuviService + - target: RuuviStorage + - target: RuuviUser + - target: RuuviPresenters + - target: RuuviDiscover + - target: RuuviOnboard + - target: RuuviFirmware + - target: RuuviLocalization + info: + path: Info.plist + properties: + CFBundleDisplayName: Ruuvi Station + CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString: "$(MARKETING_VERSION)" + CFBundleVersion: $(CURRENT_PROJECT_VERSION) + UISupportedInterfaceOrientations: [UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight, UIInterfaceOrientationPortrait] + UILaunchStoryboardName: LaunchScreen + BGTaskSchedulerPermittedIdentifiers: [com.ruuvi.station.BackgroundProcessServiceiOS13.dataPruning] + FirebaseMessagingAutoInitEnabled: false + LSApplicationQueriesSchemes: [https, http, mailto] + LSRequiresIPhoneOS: true + NFCReaderUsageDescription: Allows user to claim a RuuviTag using NFC when the user has physical access to the sensor + NSBluetoothAlwaysUsageDescription: The app uses Bluetooth LE to read data from Ruuvi Sensors + NSBluetoothPeripheralUsageDescription: The app uses Bluetooth LE to read data from RuuviTag sensors. + NSCameraUsageDescription: Ruuvi Station needs to access your camera in order to be able to capture photos and use them as sensor background. + NSLocationAlwaysAndWhenInUseUsageDescription: Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. + NSLocationAlwaysUsageDescription: Ruuvi Station needs to access your location while being in background in order to pull data for Virtual Sensors for your current location and display alerts. + NSLocationUsageDescription: Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. + NSLocationWhenInUseUsageDescription: Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. + NSPhotoLibraryUsageDescription: Ruuvi Station needs to access your camera roll to enable selecting the background for the sensor. + NSUserActivityTypes: [RuuviTagSelectionIntent] + UIAppFonts: [Oswald-Bold.ttf,Oswald-ExtraLight.ttf,Muli-Regular.ttf,Muli-Bold.ttf,Muli-SemiBoldItalic.ttf,Muli-ExtraBold.ttf,Montserrat-Bold.ttf,Montserrat-Regular.ttf,Montserrat-ExtraBold.ttf] + UIBackgroundModes: [bluetooth-central, processing, remote-notification] + UIRequiredDeviceCapabilities: [armv7] + UIRequiresFullScreen: true + UIStatusBarStyle: UIStatusBarStyleLightContent + UISupportedInterfaceOrientations~ipad: [UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight,UIInterfaceOrientationPortrait, UIInterfaceOrientationPortraitUpsideDown] + UIViewControllerBasedStatusBarAppearance: true + settings: + base: + MERGED_BINARY_TYPE: "manual" + TARGETED_DEVICE_FAMILY: 1,2 + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true + CODE_SIGN_ENTITLEMENTS: Apps/RuuviStation/Sources/Station.entitlements + configs: + Alpha: + CODE_SIGN_IDENTITY: "iPhone Distribution" + PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station" + Debug: + CODE_SIGN_STYLE: Automatic + OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries + Release: + EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" + CODE_SIGN_IDENTITY: "iPhone Distribution" + PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station" + preBuildScripts: + - path: ../../scripts/build/generate_l10n.sh + name: Generate L10N + inputFiles: + - $(SRCROOT)/station.localization/station.localization.json + outputFiles: + - $(SRCROOT)/Apps/RuuviStation/Sources/Resources/Strings/en.lproj/Localizable.strings + - $(SRCROOT)/Apps/RuuviStation/Sources/Resources/Strings/sv.lproj/Localizable.strings + - $(SRCROOT)/Apps/RuuviStation/Sources/Resources/Strings/ru.lproj/Localizable.strings + - $(SRCROOT)/Apps/RuuviStation/Sources/Resources/Strings/fi.lproj/Localizable.strings + - $(SRCROOT)/Apps/RuuviStation/Sources/Resources/Strings/fr.lproj/Localizable.strings + - $(SRCROOT)/Apps/RuuviStation/Sources/Resources/Strings/de.lproj/Localizable.strings + postCompileScripts: + - path: ../../scripts/build/lint.sh + name: Lint + basedOnDependencyAnalysis: false + postBuildScripts: + - path: ../../scripts/build/load_keystore.sh + name: Load Keystore + inputFiles: + - $(SRCROOT)/Apps/RuuviStation/Sources/Classes/Networking/Assembly/Networking.plist + - $(SRCROOT)/Apps/RuuviStation/Sources/Resources/Plists/GoogleService-Info.plist + runOnlyWhenInstalling: true + basedOnDependencyAnalysis: false +schemes: + station: + build: + targets: + station: all \ No newline at end of file diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift b/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift index ed5342077..3d3ae71ea 100644 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift +++ b/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift @@ -40,7 +40,6 @@ public enum RuuviLocalization { public static func alertCloudConnectionDescription(_ p1: Int) -> String { RuuviLocalization.tr("Localizable", "alert_cloud_connection_description", p1, fallback: "Alert if sensor data hasn't been updated to the cloud for longer than %d minutes.") } - /// Enter the desired delay to be used in minutes before alert is triggered. Minimum value is 2 minutes. public static let alertCloudConnectionDialogDescription = RuuviLocalization.tr("Localizable", "alert_cloud_connection_dialog_description", fallback: "Enter the desired delay to be used in minutes before alert is triggered. Minimum value is 2 minutes.") /// Set cloud connection alert @@ -51,42 +50,34 @@ public enum RuuviLocalization { public static func alertNotificationHumidityHighThreshold(_ p1: Any) -> String { RuuviLocalization.tr("Localizable", "alert_notification_humidity_high_threshold", String(describing: p1), fallback: "Air Humidity is above %@") } - /// Air Humidity is below %@ public static func alertNotificationHumidityLowThreshold(_ p1: Any) -> String { RuuviLocalization.tr("Localizable", "alert_notification_humidity_low_threshold", String(describing: p1), fallback: "Air Humidity is below %@") } - /// Air Pressure is above %@ public static func alertNotificationPressureHighThreshold(_ p1: Any) -> String { RuuviLocalization.tr("Localizable", "alert_notification_pressure_high_threshold", String(describing: p1), fallback: "Air Pressure is above %@") } - /// Air Pressure is below %@ public static func alertNotificationPressureLowThreshold(_ p1: Any) -> String { RuuviLocalization.tr("Localizable", "alert_notification_pressure_low_threshold", String(describing: p1), fallback: "Air Pressure is below %@") } - /// Signal strength is above %@ public static func alertNotificationRssiHighThreshold(_ p1: Any) -> String { RuuviLocalization.tr("Localizable", "alert_notification_rssi_high_threshold", String(describing: p1), fallback: "Signal strength is above %@") } - /// Signal strength is below %@ public static func alertNotificationRssiLowThreshold(_ p1: Any) -> String { RuuviLocalization.tr("Localizable", "alert_notification_rssi_low_threshold", String(describing: p1), fallback: "Signal strength is below %@") } - /// Temperature is above %@ public static func alertNotificationTemperatureHighThreshold(_ p1: Any) -> String { RuuviLocalization.tr("Localizable", "alert_notification_temperature_high_threshold", String(describing: p1), fallback: "Temperature is above %@") } - /// Temperature is below %@ public static func alertNotificationTemperatureLowThreshold(_ p1: Any) -> String { RuuviLocalization.tr("Localizable", "alert_notification_temperature_low_threshold", String(describing: p1), fallback: "Temperature is below %@") } - /// All public static let all = RuuviLocalization.tr("Localizable", "all", fallback: "All") /// App Theme @@ -166,7 +157,7 @@ public enum RuuviLocalization { /// Seems that you don't have any Ruuvi sensors added yet. public static let dashboardNoSensorsMessage = RuuviLocalization.tr("Localizable", "dashboard_no_sensors_message", fallback: "Seems that you don't have any Ruuvi sensors added yet.") /// You are not signed in. - /// + /// /// If you have an account and have already added Ruuvi sensors to it, they will automatically synchronise with Ruuvi Station mobile app when you sign in. public static let dashboardNoSensorsMessageSignedOut = RuuviLocalization.tr("Localizable", "dashboard_no_sensors_message_signed_out", fallback: "You are not signed in.\n\nIf you have an account and have already added Ruuvi sensors to it, they will automatically synchronise with Ruuvi Station mobile app when you sign in.") /// 1 day @@ -193,7 +184,6 @@ public enum RuuviLocalization { public static func dayX(_ p1: Float) -> String { RuuviLocalization.tr("Localizable", "day_x", p1, fallback: "%.0f days") } - /// dBm public static let dBm = RuuviLocalization.tr("Localizable", "dBm", fallback: "dBm") /// Are you sure? @@ -208,7 +198,7 @@ public enum RuuviLocalization { public static let done = RuuviLocalization.tr("Localizable", "Done", fallback: "Done") /// Download public static let download = RuuviLocalization.tr("Localizable", "download", fallback: "Download") - /// No data available + /// No data available /// in the selected history window. public static let emptyChartMessage = RuuviLocalization.tr("Localizable", "empty_chart_message", fallback: "No data available \nin the selected history window.") /// Enter Code @@ -228,17 +218,17 @@ public enum RuuviLocalization { /// This sensor has been claimed by another user. You can force the ownership to your account if you have physical access to this sensor. Each Ruuvi sensor can have only one owner. public static let forceClaimSensorDescription1 = RuuviLocalization.tr("Localizable", "force_claim_sensor_description1", fallback: "This sensor has been claimed by another user. You can force the ownership to your account if you have physical access to this sensor. Each Ruuvi sensor can have only one owner.") /// Force Claim is done by using Near-Field Communication (NFC). Make sure NFC is enabled on your mobile device. - /// + /// /// 1. Touch your Ruuvi sensor with your mobile device to start the claiming process. - /// + /// /// 2. When successfully claimed, you will be sent back to Sensor Settings. - /// + /// /// If claiming was unsuccessful or NFC is not available on your device: - /// + /// /// 1. Open the cover of your Ruuvi sensor. - /// + /// /// 2. Locate the round black button (or button "B" in case your sensor has 2 buttons) on the white circuit board and press it briefly, then tap on Use BT button to start the claiming process. - /// + /// /// 3. When successfully claimed you will be sent back to Sensor Settings. public static let forceClaimSensorDescription2 = RuuviLocalization.tr("Localizable", "force_claim_sensor_description2", fallback: "Force Claim is done by using Near-Field Communication (NFC). Make sure NFC is enabled on your mobile device.\n\n\t1. Touch your Ruuvi sensor with your mobile device to start the claiming process.\n\n\t2. When successfully claimed, you will be sent back to Sensor Settings.\n\nIf claiming was unsuccessful or NFC is not available on your device:\n\n\t1. Open the cover of your Ruuvi sensor.\n\n\t2. Locate the round black button (or button \"B\" in case your sensor has 2 buttons) on the white circuit board and press it briefly, then tap on Use BT button to start the claiming process.\n\n\t3. When successfully claimed you will be sent back to Sensor Settings.") /// Full image view @@ -248,7 +238,7 @@ public enum RuuviLocalization { /// g/m³ public static let gm³ = RuuviLocalization.tr("Localizable", "g/m³", fallback: "g/m³") /// Ruuvi Station downloads the internal history of the sensor for the last 10 days if the measurement history is available. - /// + /// /// The history is downloaded using a Bluetooth connection. Make sure you are near the sensor. public static let gattSyncDescription = RuuviLocalization.tr("Localizable", "gatt_sync_description", fallback: "Ruuvi Station downloads the internal history of the sensor for the last 10 days if the measurement history is available.\n\nThe history is downloaded using a Bluetooth connection. Make sure you are near the sensor.") /// Go to sensor card @@ -365,7 +355,6 @@ public enum RuuviLocalization { public static func readingHistoryX(_ p1: Float) -> String { RuuviLocalization.tr("Localizable", "reading_history_x", p1, fallback: "Reading Bluetooth: %.0f") } - /// Remove public static let remove = RuuviLocalization.tr("Localizable", "Remove", fallback: "Remove") /// By removing the sensor, your sensor ownership status will be revoked and sensor settings, such as name, background image, calibration settings and alert settings will be removed. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner. @@ -375,11 +364,11 @@ public enum RuuviLocalization { /// Remove cloud history public static let removeCloudHistoryTitle = RuuviLocalization.tr("Localizable", "remove_cloud_history_title", fallback: "Remove cloud history") /// If you choose to remove this sensor, it will result in the deletion of your locally stored measurement history, along with the removal of any related sensor settings like name, background image, calibration, and alert configurations. - /// + /// /// You can add this sensor later again, if needed. public static let removeLocalSensorDescription = RuuviLocalization.tr("Localizable", "remove_local_sensor_description", fallback: "If you choose to remove this sensor, it will result in the deletion of your locally stored measurement history, along with the removal of any related sensor settings like name, background image, calibration, and alert configurations.\n\nYou can add this sensor later again, if needed.") /// If you choose to remove this shared sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore. - /// + /// /// You will also lose any related sensor settings like name, background image and alert configurations. public static let removeSharedSensorDescription = RuuviLocalization.tr("Localizable", "remove_shared_sensor_description", fallback: "If you choose to remove this shared sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore.\n\nYou will also lose any related sensor settings like name, background image and alert configurations.") /// Rename @@ -440,7 +429,6 @@ public enum RuuviLocalization { public static func sharedToX(_ p1: Int, _ p2: Int) -> String { RuuviLocalization.tr("Localizable", "shared_to_x", p1, p2, fallback: "Shared to %d/%d") } - /// Continue public static let signInContinue = RuuviLocalization.tr("Localizable", "sign_in_continue", fallback: "Continue") /// Sign in or create a free Ruuvi account @@ -479,7 +467,6 @@ public enum RuuviLocalization { public static func uploadingProgress(_ p1: Float) -> String { RuuviLocalization.tr("Localizable", "uploading_progress", p1, fallback: "Uploading: %.0f") } - /// Use BT public static let useBluetooth = RuuviLocalization.tr("Localizable", "use_bluetooth", fallback: "Use BT") /// Use NFC @@ -499,2521 +486,2153 @@ public enum RuuviLocalization { /// °F public static let ºF = RuuviLocalization.tr("Localizable", "ºF", fallback: "°F") public enum About { - public enum AboutHelp { - /// Ruuvi Station is an easy-to-use application that allows you to monitor the measurement data of Ruuvi sensors. - public static let contents = RuuviLocalization.tr("Localizable", "About.AboutHelp.contents", fallback: "Ruuvi Station is an easy-to-use application that allows you to monitor the measurement data of Ruuvi sensors.") - /// About / Help - public static let header = RuuviLocalization.tr("Localizable", "About.AboutHelp.header", fallback: "About / Help") - } - - public enum DatabaseSize { - /// Database size: %@ - public static func text(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "About.DatabaseSize.text", String(describing: p1), fallback: "Database size: %@") - } - } - - public enum MeasurementsCount { - /// Number of locally stored measurements: %d - public static func text(_ p1: Int) -> String { - RuuviLocalization.tr("Localizable", "About.MeasurementsCount.text", p1, fallback: "Number of locally stored measurements: %d") - } - } - - public enum More { - /// Ruuvi's website: ruuvi.com - /// Ruuvi Forum: f.ruuvi.com - /// Ruuvi Blog: ruuvi.com/blog - /// Ruuvi on Twitter: twitter.com/ruuvicom - public static let contents = RuuviLocalization.tr("Localizable", "About.More.contents", fallback: "Ruuvi's website: ruuvi.com\nRuuvi Forum: f.ruuvi.com\nRuuvi Blog: ruuvi.com/blog\nRuuvi on Twitter: twitter.com/ruuvicom") - /// More to read - public static let header = RuuviLocalization.tr("Localizable", "About.More.header", fallback: "More to read") - } - - public enum OpenSource { - /// Just like Ruuvi sensors, Ruuvi Station apps are open source. Follow the development and contribute at: github.com/ruuvi - public static let contents = RuuviLocalization.tr("Localizable", "About.OpenSource.contents", fallback: "Just like Ruuvi sensors, Ruuvi Station apps are open source. Follow the development and contribute at: github.com/ruuvi") - /// Open-source - public static let header = RuuviLocalization.tr("Localizable", "About.OpenSource.header", fallback: "Open-source") - } - - public enum OperationsManual { - /// Get started using the Ruuvi Station mobile application with our online guides: ruuvi.com/support/station-mobile - public static let contents = RuuviLocalization.tr("Localizable", "About.OperationsManual.contents", fallback: "Get started using the Ruuvi Station mobile application with our online guides: ruuvi.com/support/station-mobile") - /// Operations manual - public static let header = RuuviLocalization.tr("Localizable", "About.OperationsManual.header", fallback: "Operations manual") - } - - public enum Privacy { - /// By using the application, you accept Ruuvi's standard terms and conditions: ruuvi.com/terms - public static let contents = RuuviLocalization.tr("Localizable", "About.Privacy.contents", fallback: "By using the application, you accept Ruuvi's standard terms and conditions: ruuvi.com/terms") - /// Privacy policy - public static let header = RuuviLocalization.tr("Localizable", "About.Privacy.header", fallback: "Privacy policy") - } - - public enum TagsCount { - /// Added sensors: %d - public static func text(_ p1: Int) -> String { - RuuviLocalization.tr("Localizable", "About.TagsCount.text", p1, fallback: "Added sensors: %d") - } - } - - public enum Troubleshooting { - /// Find help using the Ruuvi Station apps, Ruuvi products and Ruuvi Cloud service from our support center: ruuvi.com/support - public static let contents = RuuviLocalization.tr("Localizable", "About.Troubleshooting.contents", fallback: "Find help using the Ruuvi Station apps, Ruuvi products and Ruuvi Cloud service from our support center: ruuvi.com/support") - /// Troubleshooting - public static let header = RuuviLocalization.tr("Localizable", "About.Troubleshooting.header", fallback: "Troubleshooting") - } - - public enum Version { - /// Version - public static let text = RuuviLocalization.tr("Localizable", "About.Version.text", fallback: "Version") - } + public enum AboutHelp { + /// Ruuvi Station is an easy-to-use application that allows you to monitor the measurement data of Ruuvi sensors. + public static let contents = RuuviLocalization.tr("Localizable", "About.AboutHelp.contents", fallback: "Ruuvi Station is an easy-to-use application that allows you to monitor the measurement data of Ruuvi sensors.") + /// About / Help + public static let header = RuuviLocalization.tr("Localizable", "About.AboutHelp.header", fallback: "About / Help") + } + public enum DatabaseSize { + /// Database size: %@ + public static func text(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "About.DatabaseSize.text", String(describing: p1), fallback: "Database size: %@") + } + } + public enum MeasurementsCount { + /// Number of locally stored measurements: %d + public static func text(_ p1: Int) -> String { + RuuviLocalization.tr("Localizable", "About.MeasurementsCount.text", p1, fallback: "Number of locally stored measurements: %d") + } + } + public enum More { + /// Ruuvi's website: ruuvi.com + /// Ruuvi Forum: f.ruuvi.com + /// Ruuvi Blog: ruuvi.com/blog + /// Ruuvi on Twitter: twitter.com/ruuvicom + public static let contents = RuuviLocalization.tr("Localizable", "About.More.contents", fallback: "Ruuvi's website: ruuvi.com\nRuuvi Forum: f.ruuvi.com\nRuuvi Blog: ruuvi.com/blog\nRuuvi on Twitter: twitter.com/ruuvicom") + /// More to read + public static let header = RuuviLocalization.tr("Localizable", "About.More.header", fallback: "More to read") + } + public enum OpenSource { + /// Just like Ruuvi sensors, Ruuvi Station apps are open source. Follow the development and contribute at: github.com/ruuvi + public static let contents = RuuviLocalization.tr("Localizable", "About.OpenSource.contents", fallback: "Just like Ruuvi sensors, Ruuvi Station apps are open source. Follow the development and contribute at: github.com/ruuvi") + /// Open-source + public static let header = RuuviLocalization.tr("Localizable", "About.OpenSource.header", fallback: "Open-source") + } + public enum OperationsManual { + /// Get started using the Ruuvi Station mobile application with our online guides: ruuvi.com/support/station-mobile + public static let contents = RuuviLocalization.tr("Localizable", "About.OperationsManual.contents", fallback: "Get started using the Ruuvi Station mobile application with our online guides: ruuvi.com/support/station-mobile") + /// Operations manual + public static let header = RuuviLocalization.tr("Localizable", "About.OperationsManual.header", fallback: "Operations manual") + } + public enum Privacy { + /// By using the application, you accept Ruuvi's standard terms and conditions: ruuvi.com/terms + public static let contents = RuuviLocalization.tr("Localizable", "About.Privacy.contents", fallback: "By using the application, you accept Ruuvi's standard terms and conditions: ruuvi.com/terms") + /// Privacy policy + public static let header = RuuviLocalization.tr("Localizable", "About.Privacy.header", fallback: "Privacy policy") + } + public enum TagsCount { + /// Added sensors: %d + public static func text(_ p1: Int) -> String { + RuuviLocalization.tr("Localizable", "About.TagsCount.text", p1, fallback: "Added sensors: %d") + } + } + public enum Troubleshooting { + /// Find help using the Ruuvi Station apps, Ruuvi products and Ruuvi Cloud service from our support center: ruuvi.com/support + public static let contents = RuuviLocalization.tr("Localizable", "About.Troubleshooting.contents", fallback: "Find help using the Ruuvi Station apps, Ruuvi products and Ruuvi Cloud service from our support center: ruuvi.com/support") + /// Troubleshooting + public static let header = RuuviLocalization.tr("Localizable", "About.Troubleshooting.header", fallback: "Troubleshooting") + } + public enum Version { + /// Version + public static let text = RuuviLocalization.tr("Localizable", "About.Version.text", fallback: "Version") + } } - public enum Background { - public enum Interval { - public enum Every { - /// every - public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Every.string", fallback: "every") - } - - public enum Min { - /// min - public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Min.string", fallback: "min") - } - - public enum Sec { - /// sec - public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Sec.string", fallback: "sec") - } + public enum Interval { + public enum Every { + /// every + public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Every.string", fallback: "every") + } + public enum Min { + /// min + public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Min.string", fallback: "min") + } + public enum Sec { + /// sec + public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Sec.string", fallback: "sec") + } + } + public enum KeepConnection { + /// Keep the Connection + public static let title = RuuviLocalization.tr("Localizable", "Background.KeepConnection.title", fallback: "Keep the Connection") + } + public enum PresentNotifications { + /// Show Notifications + public static let title = RuuviLocalization.tr("Localizable", "Background.PresentNotifications.title", fallback: "Show Notifications") + } + public enum ReadRSSITitle { + /// Read RSSI + public static let title = RuuviLocalization.tr("Localizable", "Background.readRSSITitle.title", fallback: "Read RSSI") + } + } + public enum BluetoothError { + /// Disconnected + public static let disconnected = RuuviLocalization.tr("Localizable", "BluetoothError.disconnected", fallback: "Disconnected") + } + public enum Cards { + public enum Alert { + public enum AlreadyLoggedIn { + /// User %@ is already signed in. If you'd like to use a different account, please sign out first and then try again. + public static func message(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "Cards.Alert.AlreadyLoggedIn.message", String(describing: p1), fallback: "User %@ is already signed in. If you'd like to use a different account, please sign out first and then try again.") + } + } + } + public enum BluetoothDisabledAlert { + /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. + public static let message = RuuviLocalization.tr("Localizable", "Cards.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") + /// Bluetooth is not enabled + public static let title = RuuviLocalization.tr("Localizable", "Cards.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") + } + public enum Connected { + /// Connected + public static let title = RuuviLocalization.tr("Localizable", "Cards.Connected.title", fallback: "Connected") + } + public enum Error { + public enum ReverseGeocodingFailed { + /// Failed to load data for Virtual Sensor. Reverse geocode operation limit exceeded. + public static let message = RuuviLocalization.tr("Localizable", "Cards.Error.ReverseGeocodingFailed.message", fallback: "Failed to load data for Virtual Sensor. Reverse geocode operation limit exceeded.") + } + } + public enum KeepConnectionDialog { + /// Seems like you are running a connectable firmware on your Ruuvi device. Would you like to keep the connection open to this Ruuvi device in the background? This will allow histograms and alerts to work even when the application is minimised. + public static let message = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.message", fallback: "Seems like you are running a connectable firmware on your Ruuvi device. Would you like to keep the connection open to this Ruuvi device in the background? This will allow histograms and alerts to work even when the application is minimised.") + public enum Dismiss { + /// Cancel + public static let title = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.Dismiss.title", fallback: "Cancel") } - public enum KeepConnection { - /// Keep the Connection - public static let title = RuuviLocalization.tr("Localizable", "Background.KeepConnection.title", fallback: "Keep the Connection") + /// Keep the Connection + public static let title = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.KeepConnection.title", fallback: "Keep the Connection") + } + } + public enum LegacyFirmwareUpdateDialog { + /// Looks like your sensor is using an old firmware software version. To access new features such as history graphs, alerts and cloud services, updating is mandatory. + public static let message = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.message", fallback: "Looks like your sensor is using an old firmware software version. To access new features such as history graphs, alerts and cloud services, updating is mandatory.") + public enum CancelConfirmation { + /// Are you sure? Without updating, you won't be able to claim ownership of the sensor, download history graphs and set alerts. The update also includes bug fixes. If you cancel now, you can start the update process again from the sensor's settings page. + public static let message = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message", fallback: "Are you sure? Without updating, you won't be able to claim ownership of the sensor, download history graphs and set alerts. The update also includes bug fixes. If you cancel now, you can start the update process again from the sensor's settings page.") + } + public enum CheckForUpdate { + /// Check for update + public static let title = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title", fallback: "Check for update") + } + } + public enum Movements { + /// movements + public static let title = RuuviLocalization.tr("Localizable", "Cards.Movements.title", fallback: "movements") + } + public enum NoSensors { + /// No sensors added + /// Press here to add sensors + public static let title = RuuviLocalization.tr("Localizable", "Cards.NoSensors.title", fallback: "No sensors added\nPress here to add sensors") + } + public enum UpdatedLabel { + public enum NoData { + /// No data during the last 10 days + public static let message = RuuviLocalization.tr("Localizable", "Cards.UpdatedLabel.NoData.message", fallback: "No data during the last 10 days") + } + } + public enum WebTagAPILimitExcededError { + public enum Alert { + /// Please try again in 5 minutes + public static let message = RuuviLocalization.tr("Localizable", "Cards.WebTagAPILimitExcededError.Alert.message", fallback: "Please try again in 5 minutes") + /// Too many requests + public static let title = RuuviLocalization.tr("Localizable", "Cards.WebTagAPILimitExcededError.Alert.title", fallback: "Too many requests") } - - public enum PresentNotifications { - /// Show Notifications - public static let title = RuuviLocalization.tr("Localizable", "Background.PresentNotifications.title", fallback: "Show Notifications") + } + } + public enum ChartSettings { + public enum AllPoints { + /// Charts may be updated slowly when enabled. + public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.AllPoints.description", fallback: "Charts may be updated slowly when enabled.") + /// Show all measurements + public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.AllPoints.title", fallback: "Show all measurements") + } + public enum DrawDots { + /// Small dots will help to understand when measurements were collected. + public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.DrawDots.description", fallback: "Small dots will help to understand when measurements were collected.") + /// Show datapoints + public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.DrawDots.title", fallback: "Show datapoints") + } + public enum Duration { + /// Configure the period of history to be shown on chart from 1 to 10 days. + public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.Duration.description", fallback: "Configure the period of history to be shown on chart from 1 to 10 days.") + /// Chart History View Period + public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.Duration.title", fallback: "Chart History View Period") + } + } + public enum CoreError { + /// Failed to get current location + public static let failedToGetCurrentLocation = RuuviLocalization.tr("Localizable", "CoreError.failedToGetCurrentLocation", fallback: "Failed to get current location") + /// Failed to get data from response + public static let failedToGetDataFromResponse = RuuviLocalization.tr("Localizable", "CoreError.failedToGetDataFromResponse", fallback: "Failed to get data from response") + /// Failed to get background directory + public static let failedToGetDocumentsDirectory = RuuviLocalization.tr("Localizable", "CoreError.failedToGetDocumentsDirectory", fallback: "Failed to get background directory") + /// Failed to get PNG representation + public static let failedToGetPngRepresentation = RuuviLocalization.tr("Localizable", "CoreError.failedToGetPngRepresentation", fallback: "Failed to get PNG representation") + /// Missing permission for Location Services + public static let locationPermissionDenied = RuuviLocalization.tr("Localizable", "CoreError.locationPermissionDenied", fallback: "Missing permission for Location Services") + /// Location permission authorisation status is not determined + public static let locationPermissionNotDetermined = RuuviLocalization.tr("Localizable", "CoreError.locationPermissionNotDetermined", fallback: "Location permission authorisation status is not determined") + /// Object invalidated + public static let objectInvalidated = RuuviLocalization.tr("Localizable", "CoreError.objectInvalidated", fallback: "Object invalidated") + /// Object not found + public static let objectNotFound = RuuviLocalization.tr("Localizable", "CoreError.objectNotFound", fallback: "Object not found") + /// Unable to send email + public static let unableToSendEmail = RuuviLocalization.tr("Localizable", "CoreError.unableToSendEmail", fallback: "Unable to send email") + } + public enum DFUUIView { + /// You are running the latest firmware version, no need to update + public static let alreadyOnLatest = RuuviLocalization.tr("Localizable", "DFUUIView.alreadyOnLatest", fallback: "You are running the latest firmware version, no need to update") + /// Current version: + public static let currentTitle = RuuviLocalization.tr("Localizable", "DFUUIView.currentTitle", fallback: "Current version:") + /// Do not close the app or power off the sensor during the update. + public static let doNotCloseTitle = RuuviLocalization.tr("Localizable", "DFUUIView.doNotCloseTitle", fallback: "Do not close the app or power off the sensor during the update.") + /// Downloading the latest firmware to be updated... + public static let downloadingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.downloadingTitle", fallback: "Downloading the latest firmware to be updated...") + /// Latest available Ruuvi Firmware version: + public static let latestTitle = RuuviLocalization.tr("Localizable", "DFUUIView.latestTitle", fallback: "Latest available Ruuvi Firmware version:") + /// 2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label. + public static let locateBootButtonTitle = RuuviLocalization.tr("Localizable", "DFUUIView.locateBootButtonTitle", fallback: "2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label.") + /// Firmware Update + public static let navigationTitle = RuuviLocalization.tr("Localizable", "DFUUIView.navigationTitle", fallback: "Firmware Update") + /// Your sensor doesn't report its current firmware version. Either you're not in its Bluetooth range, it's connected to another phone, or it's running a very old firmware version. + public static let notReportingDescription = RuuviLocalization.tr("Localizable", "DFUUIView.notReportingDescription", fallback: "Your sensor doesn't report its current firmware version. Either you're not in its Bluetooth range, it's connected to another phone, or it's running a very old firmware version.") + /// 1. Open the cover of your Ruuvi sensor + public static let openCoverTitle = RuuviLocalization.tr("Localizable", "DFUUIView.openCoverTitle", fallback: "1. Open the cover of your Ruuvi sensor") + /// Prepare your sensor + public static let prepareTitle = RuuviLocalization.tr("Localizable", "DFUUIView.prepareTitle", fallback: "Prepare your sensor") + /// Searching for a sensor + public static let searchingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.searchingTitle", fallback: "Searching for a sensor") + /// 3. Set the sensor to updating mode: + public static let setUpdatingModeTitle = RuuviLocalization.tr("Localizable", "DFUUIView.setUpdatingModeTitle", fallback: "3. Set the sensor to updating mode:") + /// Start the update + public static let startTitle = RuuviLocalization.tr("Localizable", "DFUUIView.startTitle", fallback: "Start the update") + /// Start update process + public static let startUpdateProcess = RuuviLocalization.tr("Localizable", "DFUUIView.startUpdateProcess", fallback: "Start update process") + /// Update successful + public static let successfulTitle = RuuviLocalization.tr("Localizable", "DFUUIView.successfulTitle", fallback: "Update successful") + /// 3.2. If your sensor has a single button: keep the button pressed for 10 seconds. + public static let toBootModeOneButtonDescription = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeOneButtonDescription", fallback: "3.2. If your sensor has a single button: keep the button pressed for 10 seconds.") + /// 4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”. + public static let toBootModeSuccessTitle = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeSuccessTitle", fallback: "4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”.") + /// 3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”. + public static let toBootModeTwoButtonsDescription = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeTwoButtonsDescription", fallback: "3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”.") + /// Updating... + public static let updatingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.updatingTitle", fallback: "Updating...") + public enum DBMigration { + public enum Error { + /// The update was successful, but an unexpected database migration error occurred. To continue using this sensor, please remove it from the app and then add it again. + public static let message = RuuviLocalization.tr("Localizable", "DFUUIView.DBMigration.Error.message", fallback: "The update was successful, but an unexpected database migration error occurred. To continue using this sensor, please remove it from the app and then add it again.") } - - public enum ReadRSSITitle { - /// Read RSSI - public static let title = RuuviLocalization.tr("Localizable", "Background.readRSSITitle.title", fallback: "Read RSSI") + } + public enum LowBattery { + public enum Warning { + /// Sensor's battery voltage seems to be low and the firmware update process may fail. We recommend to replace the battery before updating. + public static let message = RuuviLocalization.tr("Localizable", "DFUUIView.lowBattery.warning.message", fallback: "Sensor's battery voltage seems to be low and the firmware update process may fail. We recommend to replace the battery before updating.") } + } } - - public enum BluetoothError { - /// Disconnected - public static let disconnected = RuuviLocalization.tr("Localizable", "BluetoothError.disconnected", fallback: "Disconnected") + public enum Defaults { + public enum AlertsMuteInterval { + /// Alerts Mute Interval + public static let title = RuuviLocalization.tr("Localizable", "Defaults.AlertsMuteInterval.title", fallback: "Alerts Mute Interval") + } + public enum AlertsRepeatInterval { + /// Alerts Interval + public static let title = RuuviLocalization.tr("Localizable", "Defaults.AlertsRepeatInterval.title", fallback: "Alerts Interval") + } + public enum AppLaunchRequiredForReview { + public enum Count { + /// App launch count to ask for review for the first time + public static let title = RuuviLocalization.tr("Localizable", "Defaults.AppLaunchRequiredForReview.Count.title", fallback: "App launch count to ask for review for the first time") + } + } + public enum AskReviewIfLaunchDivisibleBy { + public enum Count { + /// Ask review if app launch divisible by + public static let title = RuuviLocalization.tr("Localizable", "Defaults.AskReviewIfLaunchDivisibleBy.Count.title", fallback: "Ask review if app launch divisible by") + } + } + public enum CardsSwipeHint { + /// Cards Swipe Hint Was Shown + public static let title = RuuviLocalization.tr("Localizable", "Defaults.CardsSwipeHint.title", fallback: "Cards Swipe Hint Was Shown") + } + public enum ChartDurationHours { + /// Chart Duration + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartDurationHours.title", fallback: "Chart Duration") + } + public enum ChartIntervalSeconds { + /// Chart Interval + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartIntervalSeconds.title", fallback: "Chart Interval") + } + public enum ChartsSwipeInstructionWasShown { + /// Charts Swipe Hint Was Shown + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartsSwipeInstructionWasShown.title", fallback: "Charts Swipe Hint Was Shown") + } + public enum ConnectionTimeout { + /// Connection Timeout + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ConnectionTimeout.title", fallback: "Connection Timeout") + } + public enum DashboardTapActionChart { + /// Show Chart on Dashboard Card Tap + public static let title = RuuviLocalization.tr("Localizable", "Defaults.DashboardTapActionChart.title", fallback: "Show Chart on Dashboard Card Tap") + } + public enum DevServer { + /// Changing Ruuvi Cloud endpoint requires signing out from current session and restart the app. Are you sure? + public static let message = RuuviLocalization.tr("Localizable", "Defaults.DevServer.message", fallback: "Changing Ruuvi Cloud endpoint requires signing out from current session and restart the app. Are you sure?") + /// Use Dev Server + public static let title = RuuviLocalization.tr("Localizable", "Defaults.DevServer.title", fallback: "Use Dev Server") + } + public enum HideNFC { + /// Hide NFC Option for sensor contest + public static let title = RuuviLocalization.tr("Localizable", "Defaults.HideNFC.title", fallback: "Hide NFC Option for sensor contest") + } + public enum Interval { + public enum Hour { + /// h + public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Hour.string", fallback: "h") + } + public enum Min { + /// min + public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Min.string", fallback: "min") + } + public enum Sec { + /// sec + public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Sec.string", fallback: "sec") + } + } + public enum PruningOffsetHours { + /// Pruning Offset Hours + public static let title = RuuviLocalization.tr("Localizable", "Defaults.PruningOffsetHours.title", fallback: "Pruning Offset Hours") + } + public enum ServiceTimeout { + /// Service Timeout + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ServiceTimeout.title", fallback: "Service Timeout") + } + public enum ShowEmailAlertsSettings { + /// Show email alerts settings + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ShowEmailAlertsSettings.title", fallback: "Show email alerts settings") + } + public enum ShowPushAlertsSettings { + /// Show push alerts settings + public static let title = RuuviLocalization.tr("Localizable", "Defaults.ShowPushAlertsSettings.title", fallback: "Show push alerts settings") + } + public enum UserAuthorized { + /// User Authorized + public static let title = RuuviLocalization.tr("Localizable", "Defaults.UserAuthorized.title", fallback: "User Authorized") + } + public enum WebPullInterval { + /// Web Alerts Interval + public static let title = RuuviLocalization.tr("Localizable", "Defaults.WebPullInterval.title", fallback: "Web Alerts Interval") + } + public enum WelcomeShown { + /// Welcome Displayed + public static let title = RuuviLocalization.tr("Localizable", "Defaults.WelcomeShown.title", fallback: "Welcome Displayed") + } + public enum NavigationItem { + /// Defaults + public static let title = RuuviLocalization.tr("Localizable", "Defaults.navigationItem.title", fallback: "Defaults") + } } - - public enum Cards { - public enum Alert { - public enum AlreadyLoggedIn { - /// User %@ is already signed in. If you'd like to use a different account, please sign out first and then try again. - public static func message(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "Cards.Alert.AlreadyLoggedIn.message", String(describing: p1), fallback: "User %@ is already signed in. If you'd like to use a different account, please sign out first and then try again.") - } - } + public enum Devices { + /// Token Id + public static let tokenId = RuuviLocalization.tr("Localizable", "Devices.tokenId", fallback: "Token Id") + } + public enum DfuDevicesScanner { + public enum BluetoothDisabled { + /// (Bluetooth is disabled) + public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabled.text", fallback: "(Bluetooth is disabled)") + } + public enum BluetoothDisabledAlert { + /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. + public static let message = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") + /// Bluetooth is not enabled + public static let title = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") + } + public enum Description { + /// Find and select sensor "RuuviBoot". + public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.Description.text", fallback: "Find and select sensor \"RuuviBoot\".") + } + public enum NoDevice { + /// (No sensors in Bluetooth range) + public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.NoDevice.text", fallback: "(No sensors in Bluetooth range)") + } + public enum Title { + /// Devices + public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.Title.text", fallback: "Devices") + } + } + public enum DfuFlash { + public enum Cancel { + /// CANCEL + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Cancel.text", fallback: "CANCEL") + } + public enum CancelAlert { + /// Are you sure you want to cancel the firmware update process? + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.CancelAlert.text", fallback: "Are you sure you want to cancel the firmware update process?") + } + public enum Finish { + /// FINISH + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Finish.text", fallback: "FINISH") + } + public enum FinishGuide { + /// Firmware update process has been completed successfully. + /// Your RuuviTag sensor is ready for use! + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.FinishGuide.text", fallback: "Firmware update process has been completed successfully.\nYour RuuviTag sensor is ready for use!") + } + public enum Firmware { + public enum BootloaderSize { + /// Bootloader size + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.BootloaderSize.text", fallback: "Bootloader size") + } + public enum FileName { + /// File name + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.FileName.text", fallback: "File name") + } + public enum Parts { + /// Parts + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.Parts.text", fallback: "Parts") + } + public enum Size { + /// Size + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.Size.text", fallback: "Size") + } + public enum SoftDeviceSize { + /// Soft Device size + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.SoftDeviceSize.text", fallback: "Soft Device size") + } + } + public enum FirmwareSelectionGuide { + /// Locate the previously downloaded ZIP file on your mobile device. + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.FirmwareSelectionGuide.text", fallback: "Locate the previously downloaded ZIP file on your mobile device.") + } + public enum OpenDocumentPicker { + /// OPEN DOCUMENT PICKER + public static let title = RuuviLocalization.tr("Localizable", "DfuFlash.OpenDocumentPicker.title", fallback: "OPEN DOCUMENT PICKER") + } + public enum Progress { + /// Progress + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Progress.text", fallback: "Progress") + } + public enum Start { + /// Start + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Start.text", fallback: "Start") + } + public enum Step { + /// Step + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Step.text", fallback: "Step") + } + public enum Steps { + public enum Completed { + /// Completed + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.Completed.text", fallback: "Completed") + } + public enum PackageSelection { + /// Package selection + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.PackageSelection.text", fallback: "Package selection") + } + public enum ReadyForUpload { + /// Ready For upload + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.ReadyForUpload.text", fallback: "Ready For upload") + } + public enum Uploading { + /// Uploading + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.Uploading.text", fallback: "Uploading") + } + } + public enum Title { + /// DFU Flash + public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Title.text", fallback: "DFU Flash") + } + } + public enum DiscoverTable { + public enum BluetoothDisabledAlert { + /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. + public static let message = RuuviLocalization.tr("Localizable", "DiscoverTable.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") + /// Bluetooth is not enabled + public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") + } + public enum GetMoreSensors { + public enum Button { + /// Buy Ruuvi Sensors + public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.GetMoreSensors.button.title", fallback: "Buy Ruuvi Sensors") + } + } + public enum NavigationItem { + /// Add a New Sensor + public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.NavigationItem.title", fallback: "Add a New Sensor") + } + public enum NoDevicesSection { + public enum BluetoothDisabled { + /// (Bluetooth is disabled) + public static let text = RuuviLocalization.tr("Localizable", "DiscoverTable.NoDevicesSection.BluetoothDisabled.text", fallback: "(Bluetooth is disabled)") + } + public enum NotFound { + /// (No sensors in Bluetooth range) + public static let text = RuuviLocalization.tr("Localizable", "DiscoverTable.NoDevicesSection.NotFound.text", fallback: "(No sensors in Bluetooth range)") + } + } + public enum RuuviDevice { + /// Ruuvi + public static let `prefix` = RuuviLocalization.tr("Localizable", "DiscoverTable.RuuviDevice.prefix", fallback: "Ruuvi") + } + public enum SectionTitle { + /// Nearby Ruuvi sensors + public static let devices = RuuviLocalization.tr("Localizable", "DiscoverTable.SectionTitle.Devices", fallback: "Nearby Ruuvi sensors") + /// Virtual sensors + public static let webTags = RuuviLocalization.tr("Localizable", "DiscoverTable.SectionTitle.WebTags", fallback: "Virtual sensors") + } + public enum WebTagsInfoDialog { + /// Virtual Sensors show public weather data provided by local weather stations. + public static let message = RuuviLocalization.tr("Localizable", "DiscoverTable.WebTagsInfoDialog.message", fallback: "Virtual Sensors show public weather data provided by local weather stations.") + } + } + public enum ErrorPresenterAlert { + /// Error + public static let error = RuuviLocalization.tr("Localizable", "ErrorPresenterAlert.Error", fallback: "Error") + /// OK + public static let ok = RuuviLocalization.tr("Localizable", "ErrorPresenterAlert.OK", fallback: "OK") + } + public enum ExpectedError { + /// Unable to remove a connected device that is not reachable. Please check your Bluetooth connection. + public static let failedToDeleteTag = RuuviLocalization.tr("Localizable", "ExpectedError.failedToDeleteTag", fallback: "Unable to remove a connected device that is not reachable. Please check your Bluetooth connection.") + /// App is already in the process of syncing logs with this sensor + public static let isAlreadySyncingLogsWithThisTag = RuuviLocalization.tr("Localizable", "ExpectedError.isAlreadySyncingLogsWithThisTag", fallback: "App is already in the process of syncing logs with this sensor") + /// Missing OpenWeatherMap API Key. Please get one from openweathermap.org website and enter it in the station/Classes/Networking/Assembly/Networking.plist file + public static let missingOpenWeatherMapAPIKey = RuuviLocalization.tr("Localizable", "ExpectedError.missingOpenWeatherMapAPIKey", fallback: "Missing OpenWeatherMap API Key. Please get one from openweathermap.org website and enter it in the station/Classes/Networking/Assembly/Networking.plist file") + } + public enum ExportService { + /// Acceleration X + public static let accelerationX = RuuviLocalization.tr("Localizable", "ExportService.AccelerationX", fallback: "Acceleration X") + /// Acceleration Y + public static let accelerationY = RuuviLocalization.tr("Localizable", "ExportService.AccelerationY", fallback: "Acceleration Y") + /// Acceleration Z + public static let accelerationZ = RuuviLocalization.tr("Localizable", "ExportService.AccelerationZ", fallback: "Acceleration Z") + /// Date + public static let date = RuuviLocalization.tr("Localizable", "ExportService.Date", fallback: "Date") + /// Dew point (%@) + public static func dewPoint(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "ExportService.DewPoint", String(describing: p1), fallback: "Dew point (%@)") + } + /// Humidity (%@) + public static func humidity(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "ExportService.Humidity", String(describing: p1), fallback: "Humidity (%@)") + } + /// ISO8601 + public static let iso8601 = RuuviLocalization.tr("Localizable", "ExportService.ISO8601", fallback: "ISO8601") + /// Measurement Sequence Number + public static let measurementSequenceNumber = RuuviLocalization.tr("Localizable", "ExportService.MeasurementSequenceNumber", fallback: "Measurement Sequence Number") + /// Movement Counter + public static let movementCounter = RuuviLocalization.tr("Localizable", "ExportService.MovementCounter", fallback: "Movement Counter") + /// Pressure (%@) + public static func pressure(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "ExportService.Pressure", String(describing: p1), fallback: "Pressure (%@)") + } + /// Temperature (%@) + public static func temperature(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "ExportService.Temperature", String(describing: p1), fallback: "Temperature (%@)") + } + /// TX Power + public static let txPower = RuuviLocalization.tr("Localizable", "ExportService.TXPower", fallback: "TX Power") + /// Voltage (V) + public static let voltage = RuuviLocalization.tr("Localizable", "ExportService.Voltage", fallback: "Voltage (V)") + } + public enum Foreground { + public enum Interval { + public enum All { + /// All + public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.All.string", fallback: "All") } - - public enum BluetoothDisabledAlert { - /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. - public static let message = RuuviLocalization.tr("Localizable", "Cards.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") - /// Bluetooth is not enabled - public static let title = RuuviLocalization.tr("Localizable", "Cards.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") + public enum Every { + /// Every + public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.Every.string", fallback: "Every") } - - public enum Connected { - /// Connected - public static let title = RuuviLocalization.tr("Localizable", "Cards.Connected.title", fallback: "Connected") + public enum Min { + /// min + public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.Min.string", fallback: "min") } - - public enum Error { - public enum ReverseGeocodingFailed { - /// Failed to load data for Virtual Sensor. Reverse geocode operation limit exceeded. - public static let message = RuuviLocalization.tr("Localizable", "Cards.Error.ReverseGeocodingFailed.message", fallback: "Failed to load data for Virtual Sensor. Reverse geocode operation limit exceeded.") - } + } + public enum NavigationItem { + /// Foreground + public static let title = RuuviLocalization.tr("Localizable", "Foreground.navigationItem.title", fallback: "Foreground") + } + } + public enum ForegroundRow { + public enum Advertisement { + /// ADVERTISEMENTS + public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.advertisement.section", fallback: "ADVERTISEMENTS") + /// Save advertisements + public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.advertisement.title", fallback: "Save advertisements") + } + public enum Connection { + /// LOGS + public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.connection.section", fallback: "LOGS") + /// Connect and sync logs + public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.connection.title", fallback: "Connect and sync logs") + } + public enum WebTags { + /// VIRTUAL SENSORS + public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.webTags.section", fallback: "VIRTUAL SENSORS") + /// Load and save from web + public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.webTags.title", fallback: "Load and save from web") + } + } + public enum Heartbeat { + public enum Interval { + public enum All { + /// All + public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.All.string", fallback: "All") } - - public enum KeepConnectionDialog { - /// Seems like you are running a connectable firmware on your Ruuvi device. Would you like to keep the connection open to this Ruuvi device in the background? This will allow histograms and alerts to work even when the application is minimised. - public static let message = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.message", fallback: "Seems like you are running a connectable firmware on your Ruuvi device. Would you like to keep the connection open to this Ruuvi device in the background? This will allow histograms and alerts to work even when the application is minimised.") - public enum Dismiss { - /// Cancel - public static let title = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.Dismiss.title", fallback: "Cancel") - } - - public enum KeepConnection { - /// Keep the Connection - public static let title = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.KeepConnection.title", fallback: "Keep the Connection") - } + public enum Every { + /// every + public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Every.string", fallback: "every") } - - public enum LegacyFirmwareUpdateDialog { - /// Looks like your sensor is using an old firmware software version. To access new features such as history graphs, alerts and cloud services, updating is mandatory. - public static let message = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.message", fallback: "Looks like your sensor is using an old firmware software version. To access new features such as history graphs, alerts and cloud services, updating is mandatory.") - public enum CancelConfirmation { - /// Are you sure? Without updating, you won't be able to claim ownership of the sensor, download history graphs and set alerts. The update also includes bug fixes. If you cancel now, you can start the update process again from the sensor's settings page. - public static let message = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message", fallback: "Are you sure? Without updating, you won't be able to claim ownership of the sensor, download history graphs and set alerts. The update also includes bug fixes. If you cancel now, you can start the update process again from the sensor's settings page.") - } - - public enum CheckForUpdate { - /// Check for update - public static let title = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title", fallback: "Check for update") - } + public enum Min { + /// min + public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Min.string", fallback: "min") } - - public enum Movements { - /// movements - public static let title = RuuviLocalization.tr("Localizable", "Cards.Movements.title", fallback: "movements") + public enum Sec { + /// sec + public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Sec.string", fallback: "sec") } - - public enum NoSensors { - /// No sensors added - /// Press here to add sensors - public static let title = RuuviLocalization.tr("Localizable", "Cards.NoSensors.title", fallback: "No sensors added\nPress here to add sensors") + } + public enum ReadRSSITitle { + /// Read RSSI + public static let title = RuuviLocalization.tr("Localizable", "Heartbeat.readRSSITitle.title", fallback: "Read RSSI") + } + } + public enum HumidityCalibration { + public enum Button { + public enum Calibrate { + /// Calibrate + public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Calibrate.title", fallback: "Calibrate") } - - public enum UpdatedLabel { - public enum NoData { - /// No data during the last 10 days - public static let message = RuuviLocalization.tr("Localizable", "Cards.UpdatedLabel.NoData.message", fallback: "No data during the last 10 days") - } + public enum Clear { + /// Clear + public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Clear.title", fallback: "Clear") + } + public enum Close { + /// Close + public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Close.title", fallback: "Close") + } + } + public enum CalibrationConfirmationAlert { + /// You are going to calibrate humidity offset. Tap "Confirm" to continue + public static let message = RuuviLocalization.tr("Localizable", "HumidityCalibration.CalibrationConfirmationAlert.message", fallback: "You are going to calibrate humidity offset. Tap \"Confirm\" to continue") + /// Are you sure? + public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.CalibrationConfirmationAlert.title", fallback: "Are you sure?") + } + public enum ClearCalibrationConfirmationAlert { + /// You are going to clear humidity offset. This can't be undone. Tap "Confirm" to continue. + public static let message = RuuviLocalization.tr("Localizable", "HumidityCalibration.ClearCalibrationConfirmationAlert.message", fallback: "You are going to clear humidity offset. This can't be undone. Tap \"Confirm\" to continue.") + /// Are you sure? + public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.ClearCalibrationConfirmationAlert.title", fallback: "Are you sure?") + } + public enum Description { + /// In order to measure relative humidity as accurately as possible, a sodium chloride (salt) calibration is recommended. See video tutorials on how to easily do this at home. + public static let text = RuuviLocalization.tr("Localizable", "HumidityCalibration.Description.text", fallback: "In order to measure relative humidity as accurately as possible, a sodium chloride (salt) calibration is recommended. See video tutorials on how to easily do this at home.") + } + public enum Label { + public enum Note { + /// Note that calibration data will be stored locally in your mobile device. After Ruuvi Station uninstall and install, you may need to recalibrate. + public static let text = RuuviLocalization.tr("Localizable", "HumidityCalibration.Label.note.text", fallback: "Note that calibration data will be stored locally in your mobile device. After Ruuvi Station uninstall and install, you may need to recalibrate.") + } + } + public enum VideoTutorials { + /// video tutorials + public static let link = RuuviLocalization.tr("Localizable", "HumidityCalibration.VideoTutorials.link", fallback: "video tutorials") + } + public enum LastCalibrationDate { + /// Calibrated: %@ + public static func format(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "HumidityCalibration.lastCalibrationDate.format", String(describing: p1), fallback: "Calibrated: %@") + } + } + } + public enum HumidityUnit { + public enum Dew { + /// Dew point (%@) + public static func title(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "HumidityUnit.Dew.title", String(describing: p1), fallback: "Dew point (%@)") + } + } + public enum Percent { + /// Relative (%) + public static let title = RuuviLocalization.tr("Localizable", "HumidityUnit.Percent.title", fallback: "Relative (%)") + } + public enum Gm3 { + /// Absolute (g/m³) + public static let title = RuuviLocalization.tr("Localizable", "HumidityUnit.gm3.title", fallback: "Absolute (g/m³)") + } + } + public enum Interval { + public enum Day { + /// Day + public static let string = RuuviLocalization.tr("Localizable", "Interval.Day.string", fallback: "Day") + } + public enum Days { + /// Days + public static let string = RuuviLocalization.tr("Localizable", "Interval.Days.string", fallback: "Days") + } + } + public enum Language { + /// English + public static let english = RuuviLocalization.tr("Localizable", "Language.English", fallback: "English") + /// Suomi + public static let finnish = RuuviLocalization.tr("Localizable", "Language.Finnish", fallback: "Suomi") + /// Français + public static let french = RuuviLocalization.tr("Localizable", "Language.French", fallback: "Français") + /// Deutsch + public static let german = RuuviLocalization.tr("Localizable", "Language.German", fallback: "Deutsch") + /// Русский + public static let russian = RuuviLocalization.tr("Localizable", "Language.Russian", fallback: "Русский") + /// Svenska + public static let swedish = RuuviLocalization.tr("Localizable", "Language.Swedish", fallback: "Svenska") + } + public enum LocalNotificationsManager { + public enum DidConnect { + /// Connected + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidConnect.title", fallback: "Connected") + } + public enum DidDisconnect { + /// Disconnected + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidDisconnect.title", fallback: "Disconnected") + } + public enum DidMove { + /// Movement detected! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidMove.title", fallback: "Movement detected!") + } + public enum Disable { + /// Turn off + public static let button = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.Disable.button", fallback: "Turn off") + } + public enum HighDewPoint { + /// Dew Point is too high! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighDewPoint.title", fallback: "Dew Point is too high!") + } + public enum HighHumidity { + /// Air Humidity is too high! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighHumidity.title", fallback: "Air Humidity is too high!") + } + public enum HighPressure { + /// Air Pressure is too high! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighPressure.title", fallback: "Air Pressure is too high!") + } + public enum HighSignal { + /// Signal strength is too high! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighSignal.title", fallback: "Signal strength is too high!") + } + public enum HighTemperature { + /// Temperature is too high! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighTemperature.title", fallback: "Temperature is too high!") + } + public enum LowDewPoint { + /// Dew Point is too low! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowDewPoint.title", fallback: "Dew Point is too low!") + } + public enum LowHumidity { + /// Air Humidity is too low! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowHumidity.title", fallback: "Air Humidity is too low!") + } + public enum LowPressure { + /// Air Pressure is too low! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowPressure.title", fallback: "Air Pressure is too low!") + } + public enum LowSignal { + /// Signal strength is too low! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowSignal.title", fallback: "Signal strength is too low!") + } + public enum LowTemperature { + /// Temperature is too low! + public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowTemperature.title", fallback: "Temperature is too low!") + } + public enum Mute { + /// Mute for an hour + public static let button = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.Mute.button", fallback: "Mute for an hour") + } + } + public enum Menu { + public enum BuyGateway { + public enum Url { + /// https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios + public static let ios = RuuviLocalization.tr("Localizable", "Menu.BuyGateway.URL.IOS", fallback: "https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") } - - public enum WebTagAPILimitExcededError { - public enum Alert { - /// Please try again in 5 minutes - public static let message = RuuviLocalization.tr("Localizable", "Cards.WebTagAPILimitExcededError.Alert.message", fallback: "Please try again in 5 minutes") - /// Too many requests - public static let title = RuuviLocalization.tr("Localizable", "Cards.WebTagAPILimitExcededError.Alert.title", fallback: "Too many requests") - } + } + public enum Label { + public enum AboutHelp { + /// About / Help + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AboutHelp.text", fallback: "About / Help") } - } - - public enum ChartSettings { - public enum AllPoints { - /// Charts may be updated slowly when enabled. - public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.AllPoints.description", fallback: "Charts may be updated slowly when enabled.") - /// Show all measurements - public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.AllPoints.title", fallback: "Show all measurements") + public enum AddAnNewSensor { + /// Add a New Sensor + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AddAnNewSensor.text", fallback: "Add a New Sensor") } - - public enum DrawDots { - /// Small dots will help to understand when measurements were collected. - public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.DrawDots.description", fallback: "Small dots will help to understand when measurements were collected.") - /// Show datapoints - public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.DrawDots.title", fallback: "Show datapoints") + public enum AppSettings { + /// App Settings + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AppSettings.text", fallback: "App Settings") } - - public enum Duration { - /// Configure the period of history to be shown on chart from 1 to 10 days. - public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.Duration.description", fallback: "Configure the period of history to be shown on chart from 1 to 10 days.") - /// Chart History View Period - public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.Duration.title", fallback: "Chart History View Period") + public enum BuyRuuviGateway { + /// Buy Ruuvi Gateway + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.BuyRuuviGateway.text", fallback: "Buy Ruuvi Gateway") } + public enum Feedback { + /// Send Feedback + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.Feedback.text", fallback: "Send Feedback") + } + public enum GetMoreSensors { + /// Buy Ruuvi Sensors + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.GetMoreSensors.text", fallback: "Buy Ruuvi Sensors") + } + public enum MyRuuviAccount { + /// My Ruuvi Account + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.MyRuuviAccount.text", fallback: "My Ruuvi Account") + } + public enum WhatToMeasure { + /// What to measure with Ruuvi? + public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.WhatToMeasure.text", fallback: "What to measure with Ruuvi?") + } + } + public enum LoggedIn { + /// Signed in: + public static let title = RuuviLocalization.tr("Localizable", "Menu.LoggedIn.title", fallback: "Signed in:") + } + public enum Measure { + public enum Url { + /// https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios + public static let ios = RuuviLocalization.tr("Localizable", "Menu.Measure.URL.IOS", fallback: "https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") + } + } + public enum RuuviNetworkStatus { + /// Ruuvi Cloud status + public static let text = RuuviLocalization.tr("Localizable", "Menu.RuuviNetworkStatus.text", fallback: "Ruuvi Cloud status") + } + public enum SignOut { + /// Sign out + public static let text = RuuviLocalization.tr("Localizable", "Menu.SignOut.text", fallback: "Sign out") + } } - - public enum CoreError { - /// Failed to get current location - public static let failedToGetCurrentLocation = RuuviLocalization.tr("Localizable", "CoreError.failedToGetCurrentLocation", fallback: "Failed to get current location") - /// Failed to get data from response - public static let failedToGetDataFromResponse = RuuviLocalization.tr("Localizable", "CoreError.failedToGetDataFromResponse", fallback: "Failed to get data from response") - /// Failed to get background directory - public static let failedToGetDocumentsDirectory = RuuviLocalization.tr("Localizable", "CoreError.failedToGetDocumentsDirectory", fallback: "Failed to get background directory") - /// Failed to get PNG representation - public static let failedToGetPngRepresentation = RuuviLocalization.tr("Localizable", "CoreError.failedToGetPngRepresentation", fallback: "Failed to get PNG representation") - /// Missing permission for Location Services - public static let locationPermissionDenied = RuuviLocalization.tr("Localizable", "CoreError.locationPermissionDenied", fallback: "Missing permission for Location Services") - /// Location permission authorisation status is not determined - public static let locationPermissionNotDetermined = RuuviLocalization.tr("Localizable", "CoreError.locationPermissionNotDetermined", fallback: "Location permission authorisation status is not determined") - /// Object invalidated - public static let objectInvalidated = RuuviLocalization.tr("Localizable", "CoreError.objectInvalidated", fallback: "Object invalidated") - /// Object not found - public static let objectNotFound = RuuviLocalization.tr("Localizable", "CoreError.objectNotFound", fallback: "Object not found") - /// Unable to send email - public static let unableToSendEmail = RuuviLocalization.tr("Localizable", "CoreError.unableToSendEmail", fallback: "Unable to send email") + public enum MenuTableViewController { + /// none + public static let `none` = RuuviLocalization.tr("Localizable", "MenuTableViewController.None", fallback: "none") + /// User: %@ + public static func user(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "MenuTableViewController.User", String(describing: p1), fallback: "User: %@") + } } - - public enum DFUUIView { - /// You are running the latest firmware version, no need to update - public static let alreadyOnLatest = RuuviLocalization.tr("Localizable", "DFUUIView.alreadyOnLatest", fallback: "You are running the latest firmware version, no need to update") - /// Current version: - public static let currentTitle = RuuviLocalization.tr("Localizable", "DFUUIView.currentTitle", fallback: "Current version:") - /// Do not close the app or power off the sensor during the update. - public static let doNotCloseTitle = RuuviLocalization.tr("Localizable", "DFUUIView.doNotCloseTitle", fallback: "Do not close the app or power off the sensor during the update.") - /// Downloading the latest firmware to be updated... - public static let downloadingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.downloadingTitle", fallback: "Downloading the latest firmware to be updated...") - /// Latest available Ruuvi Firmware version: - public static let latestTitle = RuuviLocalization.tr("Localizable", "DFUUIView.latestTitle", fallback: "Latest available Ruuvi Firmware version:") - /// 2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label. - public static let locateBootButtonTitle = RuuviLocalization.tr("Localizable", "DFUUIView.locateBootButtonTitle", fallback: "2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label.") - /// Firmware Update - public static let navigationTitle = RuuviLocalization.tr("Localizable", "DFUUIView.navigationTitle", fallback: "Firmware Update") - /// Your sensor doesn't report its current firmware version. Either you're not in its Bluetooth range, it's connected to another phone, or it's running a very old firmware version. - public static let notReportingDescription = RuuviLocalization.tr("Localizable", "DFUUIView.notReportingDescription", fallback: "Your sensor doesn't report its current firmware version. Either you're not in its Bluetooth range, it's connected to another phone, or it's running a very old firmware version.") - /// 1. Open the cover of your Ruuvi sensor - public static let openCoverTitle = RuuviLocalization.tr("Localizable", "DFUUIView.openCoverTitle", fallback: "1. Open the cover of your Ruuvi sensor") - /// Prepare your sensor - public static let prepareTitle = RuuviLocalization.tr("Localizable", "DFUUIView.prepareTitle", fallback: "Prepare your sensor") - /// Searching for a sensor - public static let searchingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.searchingTitle", fallback: "Searching for a sensor") - /// 3. Set the sensor to updating mode: - public static let setUpdatingModeTitle = RuuviLocalization.tr("Localizable", "DFUUIView.setUpdatingModeTitle", fallback: "3. Set the sensor to updating mode:") - /// Start the update - public static let startTitle = RuuviLocalization.tr("Localizable", "DFUUIView.startTitle", fallback: "Start the update") - /// Start update process - public static let startUpdateProcess = RuuviLocalization.tr("Localizable", "DFUUIView.startUpdateProcess", fallback: "Start update process") - /// Update successful - public static let successfulTitle = RuuviLocalization.tr("Localizable", "DFUUIView.successfulTitle", fallback: "Update successful") - /// 3.2. If your sensor has a single button: keep the button pressed for 10 seconds. - public static let toBootModeOneButtonDescription = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeOneButtonDescription", fallback: "3.2. If your sensor has a single button: keep the button pressed for 10 seconds.") - /// 4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”. - public static let toBootModeSuccessTitle = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeSuccessTitle", fallback: "4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”.") - /// 3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”. - public static let toBootModeTwoButtonsDescription = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeTwoButtonsDescription", fallback: "3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”.") - /// Updating... - public static let updatingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.updatingTitle", fallback: "Updating...") - public enum DBMigration { - public enum Error { - /// The update was successful, but an unexpected database migration error occurred. To continue using this sensor, please remove it from the app and then add it again. - public static let message = RuuviLocalization.tr("Localizable", "DFUUIView.DBMigration.Error.message", fallback: "The update was successful, but an unexpected database migration error occurred. To continue using this sensor, please remove it from the app and then add it again.") - } - } - - public enum LowBattery { - public enum Warning { - /// Sensor's battery voltage seems to be low and the firmware update process may fail. We recommend to replace the battery before updating. - public static let message = RuuviLocalization.tr("Localizable", "DFUUIView.lowBattery.warning.message", fallback: "Sensor's battery voltage seems to be low and the firmware update process may fail. We recommend to replace the battery before updating.") - } + public enum MyRuuvi { + public enum Settings { + public enum DeleteAccount { + /// Delete Account + public static let title = RuuviLocalization.tr("Localizable", "MyRuuvi.Settings.DeleteAccount.title", fallback: "Delete Account") + public enum Confirmation { + /// A confirmation has been sent to your email. To proceed with the deletion, please check your inbox and follow the instructions. + public static let message = RuuviLocalization.tr("Localizable", "MyRuuvi.Settings.DeleteAccount.Confirmation.message", fallback: "A confirmation has been sent to your email. To proceed with the deletion, please check your inbox and follow the instructions.") + } } + } } - - public enum Defaults { - public enum AlertsMuteInterval { - /// Alerts Mute Interval - public static let title = RuuviLocalization.tr("Localizable", "Defaults.AlertsMuteInterval.title", fallback: "Alerts Mute Interval") + public enum OWMError { + /// API limit exceeded + public static let apiLimitExceeded = RuuviLocalization.tr("Localizable", "OWMError.apiLimitExceeded", fallback: "API limit exceeded") + /// Failed to parse Open Weather Map response + public static let failedToParseOpenWeatherMapResponse = RuuviLocalization.tr("Localizable", "OWMError.failedToParseOpenWeatherMapResponse", fallback: "Failed to parse Open Weather Map response") + /// Invalid API Key + public static let invalidApiKey = RuuviLocalization.tr("Localizable", "OWMError.invalidApiKey", fallback: "Invalid API Key") + /// Not an HTTP response + public static let notAHttpResponse = RuuviLocalization.tr("Localizable", "OWMError.notAHttpResponse", fallback: "Not an HTTP response") + } + public enum OffsetCorrection { + public enum Calibrate { + /// Offset correction + public static let button = RuuviLocalization.tr("Localizable", "OffsetCorrection.Calibrate.button", fallback: "Offset correction") + } + public enum CalibrationDescription { + /// In normal use, it's not necessary to adjust the offset. + /// + /// If you're an advanced user and you'd like to manually configure the factory calibrated sensors, it's possible to do so. + /// + /// Calibration tips are available on ruuvi.com/support + public static let text = RuuviLocalization.tr("Localizable", "OffsetCorrection.CalibrationDescription.text", fallback: "In normal use, it's not necessary to adjust the offset.\n\nIf you're an advanced user and you'd like to manually configure the factory calibrated sensors, it's possible to do so.\n\nCalibration tips are available on ruuvi.com/support") + } + public enum CorrectedValue { + /// Corrected value + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.CorrectedValue.title", fallback: "Corrected value") + } + public enum Dialog { + public enum Calibration { + /// Clear calibration settings? + public static let clearConfirm = RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.ClearConfirm", fallback: "Clear calibration settings?") + /// Enter the expected humidity value from sensor under current conditions (%@): + public static func enterHumidity(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterHumidity", String(describing: p1), fallback: "Enter the expected humidity value from sensor under current conditions (%@): ") + } + /// Enter the expected pressure value from sensor under current conditions (%@): + public static func enterPressure(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterPressure", String(describing: p1), fallback: "Enter the expected pressure value from sensor under current conditions (%@): ") + } + /// Enter the expected temperature value from sensor under current conditions (%@): + public static func enterTemperature(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterTemperature", String(describing: p1), fallback: "Enter the expected temperature value from sensor under current conditions (%@): ") + } + /// Calibration setup + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.Title", fallback: "Calibration setup") + } + } + public enum Humidity { + /// Humidity offset + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Humidity.Title", fallback: "Humidity offset") + } + public enum OriginalValue { + /// Original measured value + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.OriginalValue.title", fallback: "Original measured value") + } + public enum Pressure { + /// Pressure offset + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Pressure.Title", fallback: "Pressure offset") + } + public enum Temperature { + /// Temperature offset + public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Temperature.Title", fallback: "Temperature offset") + } + } + public enum Owner { + /// Claim sensor + public static let title = RuuviLocalization.tr("Localizable", "Owner.title", fallback: "Claim sensor") + public enum Claim { + /// Do you own this sensor? If yes, please claim ownership of the sensor and it'll be added to your Ruuvi account. Each Ruuvi sensor can have only one owner. To claim ownership, you need to be signed in. + /// + /// Benefits: + /// + /// ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud + /// + /// ● Access sensors remotely over the Internet (requires a Ruuvi Gateway) + /// + /// ● Share sensors with friends and family (requires a Ruuvi Gateway) + /// + /// ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway) + public static let description = RuuviLocalization.tr("Localizable", "Owner.Claim.description", fallback: "Do you own this sensor? If yes, please claim ownership of the sensor and it'll be added to your Ruuvi account. Each Ruuvi sensor can have only one owner. To claim ownership, you need to be signed in.\n\nBenefits:\n\n ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud\n\n ● Access sensors remotely over the Internet (requires a Ruuvi Gateway)\n\n ● Share sensors with friends and family (requires a Ruuvi Gateway)\n\n ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway)") + } + public enum ClaimOwnership { + /// Claim ownership + public static let button = RuuviLocalization.tr("Localizable", "Owner.ClaimOwnership.button", fallback: "Claim ownership") + } + } + public enum PermissionPresenter { + /// Settings + public static let settings = RuuviLocalization.tr("Localizable", "PermissionPresenter.settings", fallback: "Settings") + public enum NoCameraAccess { + /// Ruuvi Station needs to access your camera to enable this feature. + public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoCameraAccess.message", fallback: "Ruuvi Station needs to access your camera to enable this feature.") + } + public enum NoLocationAccess { + /// Ruuvi Station needs to access your location to enable this feature. + public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoLocationAccess.message", fallback: "Ruuvi Station needs to access your location to enable this feature.") + } + public enum NoPhotoLibraryAccess { + /// Ruuvi Station needs to access your camera library to enable this feature. + public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoPhotoLibraryAccess.message", fallback: "Ruuvi Station needs to access your camera library to enable this feature.") + } + public enum NoPushNotificationsPermission { + /// Ruuvi Station needs push notifications permission to enable this feature + public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoPushNotificationsPermission.message", fallback: "Ruuvi Station needs push notifications permission to enable this feature") + } + } + public enum PhotoPicker { + public enum Sheet { + /// Take photo + public static let camera = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.camera", fallback: "Take photo") + /// Choose from files + public static let files = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.files", fallback: "Choose from files") + /// Choose from the library + public static let library = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.library", fallback: "Choose from the library") + /// Pick a photo + public static let message = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.message", fallback: "Pick a photo") + } + } + public enum Ruuvi { + public enum BuySensors { + public enum Menu { + public enum Url { + /// https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios + public static let ios = RuuviLocalization.tr("Localizable", "Ruuvi.BuySensors.Menu.URL.IOS", fallback: "https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios") + } } - - public enum AlertsRepeatInterval { - /// Alerts Interval - public static let title = RuuviLocalization.tr("Localizable", "Defaults.AlertsRepeatInterval.title", fallback: "Alerts Interval") + public enum Url { + /// https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios + public static let ios = RuuviLocalization.tr("Localizable", "Ruuvi.BuySensors.URL.IOS", fallback: "https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") } - - public enum AppLaunchRequiredForReview { - public enum Count { - /// App launch count to ask for review for the first time - public static let title = RuuviLocalization.tr("Localizable", "Defaults.AppLaunchRequiredForReview.Count.title", fallback: "App launch count to ask for review for the first time") - } + } + } + public enum RuuviCloudApiError { + /// Empty response + public static let emptyResponse = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.emptyResponse", fallback: "Empty response") + /// Failed to get data from response + public static let failedToGetDataFromResponse = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.failedToGetDataFromResponse", fallback: "Failed to get data from response") + /// Unexpected HTTP status code + public static let unexpectedHTTPStatusCode = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.unexpectedHTTPStatusCode", fallback: "Unexpected HTTP status code") + } + public enum RuuviCloudError { + /// Not authorised + public static let notAuthorized = RuuviLocalization.tr("Localizable", "RuuviCloudError.NotAuthorized", fallback: "Not authorised") + } + public enum RuuviDfuError { + /// Failed to construct UUID + public static let failedToConstructUUID = RuuviLocalization.tr("Localizable", "RuuviDfuError.failedToConstructUUID", fallback: "Failed to construct UUID") + /// Invalid firmware file + public static let invalidFirmwareFile = RuuviLocalization.tr("Localizable", "RuuviDfuError.invalidFirmwareFile", fallback: "Invalid firmware file") + } + public enum RuuviLocalError { + /// Failed to get background directory + public static let failedToGetDocumentsDirectory = RuuviLocalization.tr("Localizable", "RuuviLocalError.failedToGetDocumentsDirectory", fallback: "Failed to get background directory") + /// Failed to get JPG representation + public static let failedToGetJpegRepresentation = RuuviLocalization.tr("Localizable", "RuuviLocalError.failedToGetJpegRepresentation", fallback: "Failed to get JPG representation") + } + public enum RuuviOnboard { + public enum Access { + /// Access data for each linked sensor in real time and explore history graphs. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Access.title", fallback: "Access data for each linked sensor in real time and explore history graphs.") + } + public enum Alerts { + /// Set alerts and get notified whenever your limits are hit. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Alerts.title", fallback: "Set alerts and get notified whenever your limits are hit.") + } + public enum Cloud { + /// Claim ownership of your sensors with a free Ruuvi Cloud account. + public static let subtitle = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.subtitle", fallback: "Claim ownership of your sensors with a free Ruuvi Cloud account.") + /// Sign in to use the full potential of the app. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.title", fallback: "Sign in to use the full potential of the app.") + public enum Benefits { + /// Benefits: + /// + /// ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud + /// + /// ● Access sensors remotely over the Internet (requires a Ruuvi Gateway) + /// + /// ● Share sensors with friends and family (requires a Ruuvi Gateway) + /// + /// ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway) + public static let message = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Benefits.message", fallback: "Benefits:\n\n ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud\n\n ● Access sensors remotely over the Internet (requires a Ruuvi Gateway)\n\n ● Share sensors with friends and family (requires a Ruuvi Gateway)\n\n ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway)") + } + public enum Details { + /// Details + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Details.title", fallback: "Details") + } + public enum Skip { + /// Are you sure you want to skip sign in? + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.title", fallback: "Are you sure you want to skip sign in?") + public enum GoBack { + /// Go back + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.GoBack.title", fallback: "Go back") + } + public enum Yes { + /// Yes, skip + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.Yes.title", fallback: "Yes, skip") + } + } + public enum Subtitle { + /// Great! You already signed in! + public static let signed = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.subtitle.signed", fallback: "Great! You already signed in!") + } + } + public enum Measure { + /// Measure environmental data: temperature, relative humidity and air pressure. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Measure.title", fallback: "Measure environmental data: temperature, relative humidity and air pressure.") + } + public enum Start { + /// Press SCAN to find and add nearby sensors to your Ruuvi Station. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Start.title", fallback: "Press SCAN to find and add nearby sensors to your Ruuvi Station.") + } + public enum Welcome { + /// Swipe to see what Ruuvi Station can do for you. + public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Welcome.title", fallback: "Swipe to see what Ruuvi Station can do for you.") + } + } + public enum RuuviPersistenceError { + /// Failed to find sensor + public static let failedToFindRuuviTag = RuuviLocalization.tr("Localizable", "RuuviPersistenceError.failedToFindRuuviTag", fallback: "Failed to find sensor") + } + public enum RuuviServiceError { + /// Both local and MAC identifiers are nil + public static let bothLuidAndMacAreNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.bothLuidAndMacAreNil", fallback: "Both local and MAC identifiers are nil") + /// Failed to find or generate background image + public static let failedToFindOrGenerateBackgroundImage = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToFindOrGenerateBackgroundImage", fallback: "Failed to find or generate background image") + /// Failed to get JPG representation + public static let failedToGetJpegRepresentation = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToGetJpegRepresentation", fallback: "Failed to get JPG representation") + /// Failed to parse response. + public static let failedToParseNetworkResponse = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToParseNetworkResponse", fallback: "Failed to parse response.") + /// MAC identifier is nil + public static let macIdIsNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.macIdIsNil", fallback: "MAC identifier is nil") + /// Photo URL is nil + public static let pictureUrlIsNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.pictureUrlIsNil", fallback: "Photo URL is nil") + } + public enum Settings { + public enum BackgroundScanning { + /// Data logging interval + public static let interval = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.interval", fallback: "Data logging interval") + /// Background Scanning + public static let title = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.title", fallback: "Background Scanning") + public enum Footer { + /// Important note: Bluetooth background history logging and Bluetooth alerts work only when background scanning is enabled. If you disable the background scanning, all paired Ruuvi sensors will be automatically unpaired and you need to pair them again from their settings pages. + public static let message = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.Footer.message", fallback: "Important note: Bluetooth background history logging and Bluetooth alerts work only when background scanning is enabled. If you disable the background scanning, all paired Ruuvi sensors will be automatically unpaired and you need to pair them again from their settings pages.") + } + } + public enum ChooseHumidityUnit { + /// Choose the humidity unit you want to be displayed. + public static let text = RuuviLocalization.tr("Localizable", "Settings.ChooseHumidityUnit.text", fallback: "Choose the humidity unit you want to be displayed.") + } + public enum ChoosePressureUnit { + /// Choose the pressure unit you want to be displayed. + public static let text = RuuviLocalization.tr("Localizable", "Settings.ChoosePressureUnit.text", fallback: "Choose the pressure unit you want to be displayed.") + } + public enum ChooseTemperatureUnit { + /// Choose the temperature unit you want to be displayed. + public static let text = RuuviLocalization.tr("Localizable", "Settings.ChooseTemperatureUnit.text", fallback: "Choose the temperature unit you want to be displayed.") + } + public enum Humidity { + public enum Resolution { + /// Humidity Resolution + public static let title = RuuviLocalization.tr("Localizable", "Settings.Humidity.Resolution.title", fallback: "Humidity Resolution") + } + } + public enum Label { + /// Chart Settings + public static let chart = RuuviLocalization.tr("Localizable", "Settings.Label.Chart", fallback: "Chart Settings") + /// Cloud mode + public static let cloudMode = RuuviLocalization.tr("Localizable", "Settings.Label.CloudMode", fallback: "Cloud mode") + /// Defaults + public static let defaults = RuuviLocalization.tr("Localizable", "Settings.Label.Defaults", fallback: "Defaults") + /// Foreground + public static let foreground = RuuviLocalization.tr("Localizable", "Settings.Label.Foreground", fallback: "Foreground") + /// Humidity + public static let humidity = RuuviLocalization.tr("Localizable", "Settings.Label.Humidity", fallback: "Humidity") + /// Pressure + public static let pressure = RuuviLocalization.tr("Localizable", "Settings.Label.Pressure", fallback: "Pressure") + /// Temperature + public static let temperature = RuuviLocalization.tr("Localizable", "Settings.Label.Temperature", fallback: "Temperature") + public enum CloudMode { + /// Refresh nearby cloud sensors only from the cloud by ignoring their Bluetooth messages and receiving alerts only by email. Requires a Ruuvi Gateway router. + public static let description = RuuviLocalization.tr("Localizable", "Settings.Label.CloudMode.description", fallback: "Refresh nearby cloud sensors only from the cloud by ignoring their Bluetooth messages and receiving alerts only by email. Requires a Ruuvi Gateway router.") + } + public enum HumidityUnit { + /// Humidity Unit + public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.HumidityUnit.text", fallback: "Humidity Unit") } - - public enum AskReviewIfLaunchDivisibleBy { - public enum Count { - /// Ask review if app launch divisible by - public static let title = RuuviLocalization.tr("Localizable", "Defaults.AskReviewIfLaunchDivisibleBy.Count.title", fallback: "Ask review if app launch divisible by") - } + public enum Language { + /// Language + public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.Language.text", fallback: "Language") } - - public enum CardsSwipeHint { - /// Cards Swipe Hint Was Shown - public static let title = RuuviLocalization.tr("Localizable", "Defaults.CardsSwipeHint.title", fallback: "Cards Swipe Hint Was Shown") + public enum PressureUnit { + /// Pressure Unit + public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.PressureUnit.text", fallback: "Pressure Unit") } - - public enum ChartDurationHours { - /// Chart Duration - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartDurationHours.title", fallback: "Chart Duration") + public enum TemperatureUnit { + /// Temperature Unit + public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.TemperatureUnit.text", fallback: "Temperature Unit") } - - public enum ChartIntervalSeconds { - /// Chart Interval - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartIntervalSeconds.title", fallback: "Chart Interval") + } + public enum Language { + public enum Dialog { + /// Open settings and tap Language to change language of the app. + /// If you cannot see the Language option in the settings, make sure that you have at least one preferred language added in system settings: Settings -> General -> Language & Region. + public static let message = RuuviLocalization.tr("Localizable", "Settings.Language.Dialog.message", fallback: "Open settings and tap Language to change language of the app.\nIf you cannot see the Language option in the settings, make sure that you have at least one preferred language added in system settings: Settings -> General -> Language & Region.") + /// Select Language + public static let title = RuuviLocalization.tr("Localizable", "Settings.Language.Dialog.title", fallback: "Select Language") + } + } + public enum Measurement { + public enum Resolution { + /// Select how accurately you'd like to see the sensors' live measurement values in the app. This setting doesn't affect history charts or alerts. + public static let description = RuuviLocalization.tr("Localizable", "Settings.Measurement.Resolution.description", fallback: "Select how accurately you'd like to see the sensors' live measurement values in the app. This setting doesn't affect history charts or alerts.") + /// Resolution + public static let title = RuuviLocalization.tr("Localizable", "Settings.Measurement.Resolution.title", fallback: "Resolution") + } + public enum Unit { + /// Unit + public static let title = RuuviLocalization.tr("Localizable", "Settings.Measurement.Unit.title", fallback: "Unit") + } + } + public enum Pressure { + public enum Resolution { + /// Pressure Resolution + public static let title = RuuviLocalization.tr("Localizable", "Settings.Pressure.Resolution.title", fallback: "Pressure Resolution") + } + } + public enum SectionHeader { + public enum Application { + /// APPLICATION + public static let title = RuuviLocalization.tr("Localizable", "Settings.SectionHeader.Application.title", fallback: "APPLICATION") } - - public enum ChartsSwipeInstructionWasShown { - /// Charts Swipe Hint Was Shown - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartsSwipeInstructionWasShown.title", fallback: "Charts Swipe Hint Was Shown") + public enum General { + /// GENERAL + public static let title = RuuviLocalization.tr("Localizable", "Settings.SectionHeader.General.title", fallback: "GENERAL") } - - public enum ConnectionTimeout { - /// Connection Timeout - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ConnectionTimeout.title", fallback: "Connection Timeout") + } + public enum SegmentedControl { + public enum Humidity { + public enum Absolute { + /// Abs + public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.Absolute.title", fallback: "Abs") + } + public enum DewPoint { + /// Dew + public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.DewPoint.title", fallback: "Dew") + } + public enum Relative { + /// Rel + public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.Relative.title", fallback: "Rel") + } + } + } + public enum Temperature { + public enum Resolution { + /// Temperature Resolution + public static let title = RuuviLocalization.tr("Localizable", "Settings.Temperature.Resolution.title", fallback: "Temperature Resolution") + } + } + public enum NavigationItem { + /// Settings + public static let title = RuuviLocalization.tr("Localizable", "Settings.navigationItem.title", fallback: "Settings") + } + } + public enum Share { + public enum Send { + /// Send + public static let button = RuuviLocalization.tr("Localizable", "Share.Send.button", fallback: "Send") + } + public enum Success { + /// Successfully shared sensor + public static let message = RuuviLocalization.tr("Localizable", "Share.Success.message", fallback: "Successfully shared sensor") + } + } + public enum SharePresenter { + public enum UnshareSensor { + /// Do you want to unshare sensor for %@? + public static func message(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "SharePresenter.UnshareSensor.Message", String(describing: p1), fallback: "Do you want to unshare sensor for %@?") } - - public enum DashboardTapActionChart { - /// Show Chart on Dashboard Card Tap - public static let title = RuuviLocalization.tr("Localizable", "Defaults.DashboardTapActionChart.title", fallback: "Show Chart on Dashboard Card Tap") + } + } + public enum ShareViewController { + /// You can share the sensor with friends and family if it's in range of a Ruuvi Gateway. + /// + /// Receiver will be notified by email. If the receiver doesn't have a Ruuvi account, a free Ruuvi account will automatically be created at first log in. + /// + /// Note that the sensor's custom name and background image will be shared. The name and image sync is one time only, and after this, they can be privately customised by the receiver. Offset values (if any) set by the owner, will be automatically synced, and the receiver will always see the final corrected values. + public static let description = RuuviLocalization.tr("Localizable", "ShareViewController.Description", fallback: "You can share the sensor with friends and family if it's in range of a Ruuvi Gateway.\n\nReceiver will be notified by email. If the receiver doesn't have a Ruuvi account, a free Ruuvi account will automatically be created at first log in.\n\nNote that the sensor's custom name and background image will be shared. The name and image sync is one time only, and after this, they can be privately customised by the receiver. Offset values (if any) set by the owner, will be automatically synced, and the receiver will always see the final corrected values.") + /// Share sensor + public static let title = RuuviLocalization.tr("Localizable", "ShareViewController.Title", fallback: "Share sensor") + public enum AddFriend { + /// Add friend + public static let title = RuuviLocalization.tr("Localizable", "ShareViewController.addFriend.Title", fallback: "Add friend") + } + public enum EmailTextField { + /// Type email + public static let placeholder = RuuviLocalization.tr("Localizable", "ShareViewController.emailTextField.placeholder", fallback: "Type email") + } + public enum SharedEmails { + /// You have used %d/%d of maximum shares of this sensor. The sensor has been shared to following users: + public static func title(_ p1: Int, _ p2: Int) -> String { + RuuviLocalization.tr("Localizable", "ShareViewController.sharedEmails.Title", p1, p2, fallback: "You have used %d/%d of maximum shares of this sensor. The sensor has been shared to following users:") + } + } + } + public enum SignIn { + /// We've sent a one-time password to your email %@. Sign in by entering it here: + public static func checkMailbox(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "SignIn.CheckMailbox", String(describing: p1), fallback: "We've sent a one-time password to your email %@. Sign in by entering it here:") + } + /// Code + public static let codeHint = RuuviLocalization.tr("Localizable", "SignIn.CodeHint", fallback: "Code") + /// Email + public static let emailPlaceholder = RuuviLocalization.tr("Localizable", "SignIn.EmailPlaceholder", fallback: "Email") + /// Email sent + public static let emailSent = RuuviLocalization.tr("Localizable", "SignIn.EmailSent", fallback: "Email sent") + /// Please enter verification code + public static let enterVerificationCode = RuuviLocalization.tr("Localizable", "SignIn.EnterVerificationCode", fallback: "Please enter verification code") + /// Request a code + public static let requestCode = RuuviLocalization.tr("Localizable", "SignIn.RequestCode", fallback: "Request a code") + /// Submit + public static let submitCode = RuuviLocalization.tr("Localizable", "SignIn.SubmitCode", fallback: "Submit") + /// verification code in format: CJSM + public static let verificationCodePlaceholder = RuuviLocalization.tr("Localizable", "SignIn.VerificationCodePlaceholder", fallback: "verification code in format: CJSM") + public enum EmailMismatch { + public enum Alert { + /// Oops, you've requested the code for %@, but used the code for %@. Please double check that you are using the code for %@ + public static func message(_ p1: Any, _ p2: Any, _ p3: Any) -> String { + RuuviLocalization.tr("Localizable", "SignIn.EmailMismatch.Alert.message", String(describing: p1), String(describing: p2), String(describing: p3), fallback: "Oops, you've requested the code for %@, but used the code for %@. Please double check that you are using the code for %@") + } } - - public enum DevServer { - /// Changing Ruuvi Cloud endpoint requires signing out from current session and restart the app. Are you sure? - public static let message = RuuviLocalization.tr("Localizable", "Defaults.DevServer.message", fallback: "Changing Ruuvi Cloud endpoint requires signing out from current session and restart the app. Are you sure?") - /// Use Dev Server - public static let title = RuuviLocalization.tr("Localizable", "Defaults.DevServer.title", fallback: "Use Dev Server") + } + public enum EmailMissing { + public enum Alert { + /// Oops, the email you've used to get the code was not saved. Please try to sign in again. + public static let message = RuuviLocalization.tr("Localizable", "SignIn.EmailMissing.Alert.message", fallback: "Oops, the email you've used to get the code was not saved. Please try to sign in again.") + } + } + public enum SubtitleLabel { + /// To enjoy all the features, create a free account or sign in to your existing Ruuvi account by entering your email address. + public static let text = RuuviLocalization.tr("Localizable", "SignIn.SubtitleLabel.text", fallback: "To enjoy all the features, create a free account or sign in to your existing Ruuvi account by entering your email address.") + } + public enum Sync { + /// Downloading content from the cloud. Please wait. + public static let message = RuuviLocalization.tr("Localizable", "SignIn.Sync.message", fallback: "Downloading content from the cloud. Please wait.") + } + public enum Title { + /// Sign in + public static let text = RuuviLocalization.tr("Localizable", "SignIn.Title.text", fallback: "Sign in") + } + public enum TitleLabel { + /// Sign in to + /// Ruuvi + /// Station + public static let text = RuuviLocalization.tr("Localizable", "SignIn.TitleLabel.text", fallback: "Sign in to\nRuuvi\nStation") + } + } + public enum TagCharts { + public enum AbortSync { + public enum Alert { + /// Sometimes the history download is slow due to the Bluetooth connectivity. Please wait a moment. + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.AbortSync.Alert.message", fallback: "Sometimes the history download is slow due to the Bluetooth connectivity. Please wait a moment.") } - - public enum HideNFC { - /// Hide NFC Option for sensor contest - public static let title = RuuviLocalization.tr("Localizable", "Defaults.HideNFC.title", fallback: "Hide NFC Option for sensor contest") + public enum Button { + /// Abort download + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.AbortSync.Button.title", fallback: "Abort download") + } + } + public enum BluetoothDisabledAlert { + /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") + /// Bluetooth is not enabled + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") + } + public enum Clear { + /// Clear + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Clear.title", fallback: "Clear") + } + public enum DeleteHistoryConfirmationDialog { + /// Clear the local history data from the app? + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.message", fallback: "Clear the local history data from the app?") + /// Are you sure? + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.title", fallback: "Are you sure?") + public enum Button { + public enum Delete { + /// Delete + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.button.delete.title", fallback: "Delete") + } } - - public enum Interval { - public enum Hour { - /// h - public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Hour.string", fallback: "h") - } - - public enum Min { - /// min - public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Min.string", fallback: "min") - } - - public enum Sec { - /// sec - public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Sec.string", fallback: "sec") - } + } + public enum Dismiss { + public enum Alert { + /// The history download via Bluetooth connection is in progress. Please wait. + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.Dismiss.Alert.message", fallback: "The history download via Bluetooth connection is in progress. Please wait.") + } + } + public enum Export { + /// EXPORT + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Export.title", fallback: "EXPORT") + } + public enum FailedToSyncDialog { + /// Bluetooth history download failed. Check that you're within Bluetooth range, your sensor has firmware that supports downloading and that the sensor is not simultaneously connected to another iOS device. Sensor connection is reserved for Ruuvi Station when using connected mode in iOS. + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.FailedToSyncDialog.message", fallback: "Bluetooth history download failed. Check that you're within Bluetooth range, your sensor has firmware that supports downloading and that the sensor is not simultaneously connected to another iOS device. Sensor connection is reserved for Ruuvi Station when using connected mode in iOS.") + /// Download failed + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.FailedToSyncDialog.title", fallback: "Download failed") + } + public enum NoChartData { + /// No chart data available + public static let text = RuuviLocalization.tr("Localizable", "TagCharts.NoChartData.text", fallback: "No chart data available") + } + public enum Status { + /// Connecting... + public static let connecting = RuuviLocalization.tr("Localizable", "TagCharts.Status.Connecting", fallback: "Connecting...") + /// Disconnecting... + public static let disconnecting = RuuviLocalization.tr("Localizable", "TagCharts.Status.Disconnecting", fallback: "Disconnecting...") + /// Error + public static let error = RuuviLocalization.tr("Localizable", "TagCharts.Status.Error", fallback: "Error") + /// Reading history + public static let readingHistory = RuuviLocalization.tr("Localizable", "TagCharts.Status.ReadingHistory", fallback: "Reading history") + /// Synchronising... + public static let serving = RuuviLocalization.tr("Localizable", "TagCharts.Status.Serving", fallback: "Synchronising...") + /// Success + public static let success = RuuviLocalization.tr("Localizable", "TagCharts.Status.Success", fallback: "Success") + } + public enum Sync { + /// Sync + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Sync.title", fallback: "Sync") + } + public enum SyncConfirmationDialog { + /// Download history data from the sensor? + public static let message = RuuviLocalization.tr("Localizable", "TagCharts.SyncConfirmationDialog.message", fallback: "Download history data from the sensor?") + /// Are you sure? + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.SyncConfirmationDialog.title", fallback: "Are you sure?") + } + public enum TryAgain { + /// Try again + public static let title = RuuviLocalization.tr("Localizable", "TagCharts.TryAgain.title", fallback: "Try again") + } + } + public enum TagChartsPresenter { + /// Synchronised: %@ + public static func numberOfPointsSynchronizedOverNetwork(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "TagChartsPresenter.NumberOfPointsSynchronizedOverNetwork", String(describing: p1), fallback: "Synchronised: %@") + } + } + public enum TagSettings { + /// Share + public static let shareButton = RuuviLocalization.tr("Localizable", "TagSettings.ShareButton", fallback: "Share") + public enum AirHumidityAlert { + /// Air Humidity (%@) + public static func title(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.AirHumidityAlert.title", String(describing: p1), fallback: "Air Humidity (%@)") + } + } + public enum Alert { + public enum CustomDescription { + /// Set custom description... + public static let placeholder = RuuviLocalization.tr("Localizable", "TagSettings.Alert.CustomDescription.placeholder", fallback: "Set custom description...") + /// Alert custom description + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.CustomDescription.title", fallback: "Alert custom description") + } + public enum SetHumidity { + /// Set humidity alert + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetHumidity.title", fallback: "Set humidity alert") + } + public enum SetPressure { + /// Set pressure alert + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetPressure.title", fallback: "Set pressure alert") + } + public enum SetRSSI { + /// Set signal strength alert + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetRSSI.title", fallback: "Set signal strength alert") + } + public enum SetTemperature { + /// Set temperature alert + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetTemperature.title", fallback: "Set temperature alert") + } + } + public enum AlertSettings { + public enum Dialog { + /// Max (%.0f) + public static func max(_ p1: Float) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.AlertSettings.Dialog.Max", p1, fallback: "Max (%.0f)") + } + /// Min (%.0f) + public static func min(_ p1: Float) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.AlertSettings.Dialog.Min", p1, fallback: "Min (%.0f)") + } + } + } + public enum Alerts { + /// Off + public static let off = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Off", fallback: "Off") + public enum Connection { + /// Alert when connected/disconnected + public static let description = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Connection.description", fallback: "Alert when connected/disconnected") } - - public enum PruningOffsetHours { - /// Pruning Offset Hours - public static let title = RuuviLocalization.tr("Localizable", "Defaults.PruningOffsetHours.title", fallback: "Pruning Offset Hours") + public enum DewPoint { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.Alerts.DewPoint.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } } - - public enum ServiceTimeout { - /// Service Timeout - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ServiceTimeout.title", fallback: "Service Timeout") + public enum Humidity { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Humidity.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } } - - public enum ShowEmailAlertsSettings { - /// Show email alerts settings - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ShowEmailAlertsSettings.title", fallback: "Show email alerts settings") + public enum Movement { + /// Alert when sensor is moved + public static let description = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Movement.description", fallback: "Alert when sensor is moved") } - - public enum ShowPushAlertsSettings { - /// Show push alerts settings - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ShowPushAlertsSettings.title", fallback: "Show push alerts settings") + public enum Pressure { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Pressure.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } } - - public enum UserAuthorized { - /// User Authorized - public static let title = RuuviLocalization.tr("Localizable", "Defaults.UserAuthorized.title", fallback: "User Authorized") + public enum Temperature { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Temperature.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } } - - public enum WebPullInterval { - /// Web Alerts Interval - public static let title = RuuviLocalization.tr("Localizable", "Defaults.WebPullInterval.title", fallback: "Web Alerts Interval") + } + public enum AlertsAreDisabled { + public enum Dialog { + public enum BothNotConnectedAndNoPNPermission { + /// Alerts are disabled because the device is not connected and missing push notification permission. Please connect to the device first. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.BothNotConnectedAndNoPNPermission.message", fallback: "Alerts are disabled because the device is not connected and missing push notification permission. Please connect to the device first.") + } + public enum Connect { + /// Connect + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.Connect.title", fallback: "Connect") + } + public enum NotConnected { + /// Alerts are disabled because you are not connected to the device. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.NotConnected.message", fallback: "Alerts are disabled because you are not connected to the device.") + } + } + } + public enum BatteryStatusLabel { + public enum Ok { + /// Battery OK + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.BatteryStatusLabel.Ok.message", fallback: "Battery OK") + } + public enum Replace { + /// Low battery + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.BatteryStatusLabel.Replace.message", fallback: "Low battery") + } + } + public enum ClaimTagButton { + /// Claim ownership + public static let claim = RuuviLocalization.tr("Localizable", "TagSettings.ClaimTagButton.Claim", fallback: "Claim ownership") + } + public enum ConnectStatus { + /// Disconnected + public static let disconnected = RuuviLocalization.tr("Localizable", "TagSettings.ConnectStatus.Disconnected", fallback: "Disconnected") + } + public enum ConnectionAlert { + /// Connection + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.ConnectionAlert.title", fallback: "Connection") + } + public enum DataSource { + public enum Advertisement { + /// Advertisement + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Advertisement.title", fallback: "Advertisement") + } + public enum Heartbeat { + /// Heartbeat + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Heartbeat.title", fallback: "Heartbeat") + } + public enum Network { + /// Cloud + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Network.title", fallback: "Cloud") + } + } + public enum EmptyValue { + /// - + public static let sign = RuuviLocalization.tr("Localizable", "TagSettings.EmptyValue.sign", fallback: "-") + } + public enum Firmware { + /// Current version + public static let currentVersion = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.CurrentVersion", fallback: "Current version") + /// Update + public static let updateFirmware = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.UpdateFirmware", fallback: "Update") + public enum CurrentVersion { + /// Very old + public static let veryOld = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.CurrentVersion.VeryOld", fallback: "Very old") + } + } + public enum General { + public enum Owner { + /// No owner + public static let `none` = RuuviLocalization.tr("Localizable", "TagSettings.General.Owner.none", fallback: "No owner") + } + } + public enum HumidityIsClipped { + public enum Alert { + /// Humidity value is greater than 100% after calibration. This value doesn't make sense, so the value has been adjusted to 100%. + public static func message(_ p1: Float) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.message", p1, fallback: "Humidity value is greater than 100% after calibration. This value doesn't make sense, so the value has been adjusted to 100%.") + } + /// Humidity is adjusted + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.title", fallback: "Humidity is adjusted") + public enum Fix { + /// Fix + public static let button = RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.Fix.button", fallback: "Fix") + } + } + } + public enum Label { + public enum Alerts { + /// Alerts + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.alerts.text", fallback: "Alerts") } - - public enum WelcomeShown { - /// Welcome Displayed - public static let title = RuuviLocalization.tr("Localizable", "Defaults.WelcomeShown.title", fallback: "Welcome Displayed") + public enum Disabled { + /// DISABLED? + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.disabled.text", fallback: "DISABLED?") } - - public enum NavigationItem { - /// Defaults - public static let title = RuuviLocalization.tr("Localizable", "Defaults.navigationItem.title", fallback: "Defaults") + public enum MoreInfo { + /// More info + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.moreInfo.text", fallback: "More info") } - } - - public enum Devices { - /// Token Id - public static let tokenId = RuuviLocalization.tr("Localizable", "Devices.tokenId", fallback: "Token Id") - } - - public enum DfuDevicesScanner { - public enum BluetoothDisabled { - /// (Bluetooth is disabled) - public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabled.text", fallback: "(Bluetooth is disabled)") + public enum NoValues { + /// NO VALUES? + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.noValues.text", fallback: "NO VALUES?") } - - public enum BluetoothDisabledAlert { - /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. - public static let message = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") - /// Bluetooth is not enabled - public static let title = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") + } + public enum Mac { + public enum Alert { + /// MAC Address + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Mac.Alert.title", fallback: "MAC Address") + } + } + public enum MovementAlert { + /// Movement + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.MovementAlert.title", fallback: "Movement") + } + public enum NetworkInfo { + /// Owner + public static let owner = RuuviLocalization.tr("Localizable", "TagSettings.NetworkInfo.Owner", fallback: "Owner") + } + public enum NotShared { + /// Not shared + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.NotShared.title", fallback: "Not shared") + } + public enum OffsetCorrection { + /// Humidity + public static let humidity = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Humidity", fallback: "Humidity") + /// Pressure + public static let pressure = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Pressure", fallback: "Pressure") + /// Temperature + public static let temperature = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Temperature", fallback: "Temperature") + } + public enum PairAndBackgroundScan { + /// Alerts are not available over Bluetooth connection if background scanning is not enabled. Only one iOS device can be paired to a Ruuvi sensor at a time. + public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.description", fallback: "Alerts are not available over Bluetooth connection if background scanning is not enabled. Only one iOS device can be paired to a Ruuvi sensor at a time.") + public enum Paired { + /// Paired and background scan is on + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Paired.title", fallback: "Paired and background scan is on") + } + public enum Pairing { + /// Connecting to the sensor + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Pairing.title", fallback: "Connecting to the sensor") + } + public enum Unpaired { + /// Pair and use background scan + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Unpaired.title", fallback: "Pair and use background scan") + } + } + public enum PairError { + public enum CloudMode { + /// The sensor cannot be connected to via Bluetooth when the cloud mode is active. You can re-enable the Bluetooth connection for the cloud sensors by disabling cloud mode in the app settings. + public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairError.CloudMode.description", fallback: "The sensor cannot be connected to via Bluetooth when the cloud mode is active. You can re-enable the Bluetooth connection for the cloud sensors by disabling cloud mode in the app settings.") + } + public enum Timeout { + /// Connection timed out. Pairing was unsuccessful. Please try again. + public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairError.Timeout.description", fallback: "Connection timed out. Pairing was unsuccessful. Please try again.") + } + } + public enum PressureAlert { + /// Air Pressure (%@) + public static func title(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.PressureAlert.title", String(describing: p1), fallback: "Air Pressure (%@)") + } + } + public enum RemoveThisSensor { + /// Remove this sensor + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.RemoveThisSensor.title", fallback: "Remove this sensor") + } + public enum SectionHeader { + public enum BTConnection { + /// BLUETOOTH CONNECTION + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.BTConnection.title", fallback: "BLUETOOTH CONNECTION") + } + public enum Calibration { + /// CALIBRATION + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Calibration.title", fallback: "CALIBRATION") } - - public enum Description { - /// Find and select sensor "RuuviBoot". - public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.Description.text", fallback: "Find and select sensor \"RuuviBoot\".") + public enum Firmware { + /// Firmware + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Firmware.title", fallback: "Firmware") } - - public enum NoDevice { - /// (No sensors in Bluetooth range) - public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.NoDevice.text", fallback: "(No sensors in Bluetooth range)") + public enum General { + /// General + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.General.title", fallback: "General") } - - public enum Title { - /// Devices - public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.Title.text", fallback: "Devices") + public enum Name { + /// NAME + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Name.title", fallback: "NAME") } - } - - public enum DfuFlash { - public enum Cancel { - /// CANCEL - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Cancel.text", fallback: "CANCEL") + public enum NetworkInfo { + /// NETWORK INFO + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.NetworkInfo.title", fallback: "NETWORK INFO") } - - public enum CancelAlert { - /// Are you sure you want to cancel the firmware update process? - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.CancelAlert.text", fallback: "Are you sure you want to cancel the firmware update process?") + public enum OffsetCorrection { + /// OFFSET CORRECTION + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.OffsetCorrection.Title", fallback: "OFFSET CORRECTION") } - - public enum Finish { - /// FINISH - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Finish.text", fallback: "FINISH") + public enum Remove { + /// REMOVE + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Remove.title", fallback: "REMOVE") } - - public enum FinishGuide { - /// Firmware update process has been completed successfully. - /// Your RuuviTag sensor is ready for use! - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.FinishGuide.text", fallback: "Firmware update process has been completed successfully.\nYour RuuviTag sensor is ready for use!") - } - - public enum Firmware { - public enum BootloaderSize { - /// Bootloader size - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.BootloaderSize.text", fallback: "Bootloader size") - } - - public enum FileName { - /// File name - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.FileName.text", fallback: "File name") - } - - public enum Parts { - /// Parts - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.Parts.text", fallback: "Parts") - } - - public enum Size { - /// Size - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.Size.text", fallback: "Size") - } - - public enum SoftDeviceSize { - /// Soft Device size - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.SoftDeviceSize.text", fallback: "Soft Device size") - } - } - - public enum FirmwareSelectionGuide { - /// Locate the previously downloaded ZIP file on your mobile device. - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.FirmwareSelectionGuide.text", fallback: "Locate the previously downloaded ZIP file on your mobile device.") - } - - public enum OpenDocumentPicker { - /// OPEN DOCUMENT PICKER - public static let title = RuuviLocalization.tr("Localizable", "DfuFlash.OpenDocumentPicker.title", fallback: "OPEN DOCUMENT PICKER") - } - - public enum Progress { - /// Progress - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Progress.text", fallback: "Progress") - } - - public enum Start { - /// Start - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Start.text", fallback: "Start") - } - - public enum Step { - /// Step - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Step.text", fallback: "Step") - } - - public enum Steps { - public enum Completed { - /// Completed - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.Completed.text", fallback: "Completed") - } - - public enum PackageSelection { - /// Package selection - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.PackageSelection.text", fallback: "Package selection") - } - - public enum ReadyForUpload { - /// Ready For upload - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.ReadyForUpload.text", fallback: "Ready For upload") - } - - public enum Uploading { - /// Uploading - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.Uploading.text", fallback: "Uploading") - } - } - - public enum Title { - /// DFU Flash - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Title.text", fallback: "DFU Flash") - } - } - - public enum DiscoverTable { - public enum BluetoothDisabledAlert { - /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. - public static let message = RuuviLocalization.tr("Localizable", "DiscoverTable.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") - /// Bluetooth is not enabled - public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") - } - - public enum GetMoreSensors { - public enum Button { - /// Buy Ruuvi Sensors - public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.GetMoreSensors.button.title", fallback: "Buy Ruuvi Sensors") - } - } - - public enum NavigationItem { - /// Add a New Sensor - public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.NavigationItem.title", fallback: "Add a New Sensor") - } - - public enum NoDevicesSection { - public enum BluetoothDisabled { - /// (Bluetooth is disabled) - public static let text = RuuviLocalization.tr("Localizable", "DiscoverTable.NoDevicesSection.BluetoothDisabled.text", fallback: "(Bluetooth is disabled)") - } - - public enum NotFound { - /// (No sensors in Bluetooth range) - public static let text = RuuviLocalization.tr("Localizable", "DiscoverTable.NoDevicesSection.NotFound.text", fallback: "(No sensors in Bluetooth range)") - } - } - - public enum RuuviDevice { - /// Ruuvi - public static let prefix = RuuviLocalization.tr("Localizable", "DiscoverTable.RuuviDevice.prefix", fallback: "Ruuvi") - } - - public enum SectionTitle { - /// Nearby Ruuvi sensors - public static let devices = RuuviLocalization.tr("Localizable", "DiscoverTable.SectionTitle.Devices", fallback: "Nearby Ruuvi sensors") - /// Virtual sensors - public static let webTags = RuuviLocalization.tr("Localizable", "DiscoverTable.SectionTitle.WebTags", fallback: "Virtual sensors") - } - - public enum WebTagsInfoDialog { - /// Virtual Sensors show public weather data provided by local weather stations. - public static let message = RuuviLocalization.tr("Localizable", "DiscoverTable.WebTagsInfoDialog.message", fallback: "Virtual Sensors show public weather data provided by local weather stations.") - } - } - - public enum ErrorPresenterAlert { - /// Error - public static let error = RuuviLocalization.tr("Localizable", "ErrorPresenterAlert.Error", fallback: "Error") - /// OK - public static let ok = RuuviLocalization.tr("Localizable", "ErrorPresenterAlert.OK", fallback: "OK") - } - - public enum ExpectedError { - /// Unable to remove a connected device that is not reachable. Please check your Bluetooth connection. - public static let failedToDeleteTag = RuuviLocalization.tr("Localizable", "ExpectedError.failedToDeleteTag", fallback: "Unable to remove a connected device that is not reachable. Please check your Bluetooth connection.") - /// App is already in the process of syncing logs with this sensor - public static let isAlreadySyncingLogsWithThisTag = RuuviLocalization.tr("Localizable", "ExpectedError.isAlreadySyncingLogsWithThisTag", fallback: "App is already in the process of syncing logs with this sensor") - /// Missing OpenWeatherMap API Key. Please get one from openweathermap.org website and enter it in the station/Classes/Networking/Assembly/Networking.plist file - public static let missingOpenWeatherMapAPIKey = RuuviLocalization.tr("Localizable", "ExpectedError.missingOpenWeatherMapAPIKey", fallback: "Missing OpenWeatherMap API Key. Please get one from openweathermap.org website and enter it in the station/Classes/Networking/Assembly/Networking.plist file") - } - - public enum ExportService { - /// Acceleration X - public static let accelerationX = RuuviLocalization.tr("Localizable", "ExportService.AccelerationX", fallback: "Acceleration X") - /// Acceleration Y - public static let accelerationY = RuuviLocalization.tr("Localizable", "ExportService.AccelerationY", fallback: "Acceleration Y") - /// Acceleration Z - public static let accelerationZ = RuuviLocalization.tr("Localizable", "ExportService.AccelerationZ", fallback: "Acceleration Z") - /// Date - public static let date = RuuviLocalization.tr("Localizable", "ExportService.Date", fallback: "Date") - /// Dew point (%@) - public static func dewPoint(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "ExportService.DewPoint", String(describing: p1), fallback: "Dew point (%@)") - } - - /// Humidity (%@) - public static func humidity(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "ExportService.Humidity", String(describing: p1), fallback: "Humidity (%@)") - } - - /// ISO8601 - public static let iso8601 = RuuviLocalization.tr("Localizable", "ExportService.ISO8601", fallback: "ISO8601") - /// Measurement Sequence Number - public static let measurementSequenceNumber = RuuviLocalization.tr("Localizable", "ExportService.MeasurementSequenceNumber", fallback: "Measurement Sequence Number") - /// Movement Counter - public static let movementCounter = RuuviLocalization.tr("Localizable", "ExportService.MovementCounter", fallback: "Movement Counter") - /// Pressure (%@) - public static func pressure(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "ExportService.Pressure", String(describing: p1), fallback: "Pressure (%@)") - } - - /// Temperature (%@) - public static func temperature(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "ExportService.Temperature", String(describing: p1), fallback: "Temperature (%@)") - } - - /// TX Power - public static let txPower = RuuviLocalization.tr("Localizable", "ExportService.TXPower", fallback: "TX Power") - /// Voltage (V) - public static let voltage = RuuviLocalization.tr("Localizable", "ExportService.Voltage", fallback: "Voltage (V)") - } - - public enum Foreground { - public enum Interval { - public enum All { - /// All - public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.All.string", fallback: "All") - } - - public enum Every { - /// Every - public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.Every.string", fallback: "Every") - } - - public enum Min { - /// min - public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.Min.string", fallback: "min") - } - } - - public enum NavigationItem { - /// Foreground - public static let title = RuuviLocalization.tr("Localizable", "Foreground.navigationItem.title", fallback: "Foreground") - } - } - - public enum ForegroundRow { - public enum Advertisement { - /// ADVERTISEMENTS - public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.advertisement.section", fallback: "ADVERTISEMENTS") - /// Save advertisements - public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.advertisement.title", fallback: "Save advertisements") - } - - public enum Connection { - /// LOGS - public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.connection.section", fallback: "LOGS") - /// Connect and sync logs - public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.connection.title", fallback: "Connect and sync logs") - } - - public enum WebTags { - /// VIRTUAL SENSORS - public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.webTags.section", fallback: "VIRTUAL SENSORS") - /// Load and save from web - public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.webTags.title", fallback: "Load and save from web") - } - } - - public enum Heartbeat { - public enum Interval { - public enum All { - /// All - public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.All.string", fallback: "All") - } - - public enum Every { - /// every - public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Every.string", fallback: "every") - } - - public enum Min { - /// min - public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Min.string", fallback: "min") - } - - public enum Sec { - /// sec - public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Sec.string", fallback: "sec") - } - } - - public enum ReadRSSITitle { - /// Read RSSI - public static let title = RuuviLocalization.tr("Localizable", "Heartbeat.readRSSITitle.title", fallback: "Read RSSI") - } - } - - public enum HumidityCalibration { - public enum Button { - public enum Calibrate { - /// Calibrate - public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Calibrate.title", fallback: "Calibrate") - } - - public enum Clear { - /// Clear - public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Clear.title", fallback: "Clear") - } - - public enum Close { - /// Close - public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Close.title", fallback: "Close") - } - } - - public enum CalibrationConfirmationAlert { - /// You are going to calibrate humidity offset. Tap "Confirm" to continue - public static let message = RuuviLocalization.tr("Localizable", "HumidityCalibration.CalibrationConfirmationAlert.message", fallback: "You are going to calibrate humidity offset. Tap \"Confirm\" to continue") - /// Are you sure? - public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.CalibrationConfirmationAlert.title", fallback: "Are you sure?") - } - - public enum ClearCalibrationConfirmationAlert { - /// You are going to clear humidity offset. This can't be undone. Tap "Confirm" to continue. - public static let message = RuuviLocalization.tr("Localizable", "HumidityCalibration.ClearCalibrationConfirmationAlert.message", fallback: "You are going to clear humidity offset. This can't be undone. Tap \"Confirm\" to continue.") - /// Are you sure? - public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.ClearCalibrationConfirmationAlert.title", fallback: "Are you sure?") - } - - public enum Description { - /// In order to measure relative humidity as accurately as possible, a sodium chloride (salt) calibration is recommended. See video tutorials on how to easily do this at home. - public static let text = RuuviLocalization.tr("Localizable", "HumidityCalibration.Description.text", fallback: "In order to measure relative humidity as accurately as possible, a sodium chloride (salt) calibration is recommended. See video tutorials on how to easily do this at home.") - } - - public enum Label { - public enum Note { - /// Note that calibration data will be stored locally in your mobile device. After Ruuvi Station uninstall and install, you may need to recalibrate. - public static let text = RuuviLocalization.tr("Localizable", "HumidityCalibration.Label.note.text", fallback: "Note that calibration data will be stored locally in your mobile device. After Ruuvi Station uninstall and install, you may need to recalibrate.") - } - } - - public enum VideoTutorials { - /// video tutorials - public static let link = RuuviLocalization.tr("Localizable", "HumidityCalibration.VideoTutorials.link", fallback: "video tutorials") - } - - public enum LastCalibrationDate { - /// Calibrated: %@ - public static func format(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "HumidityCalibration.lastCalibrationDate.format", String(describing: p1), fallback: "Calibrated: %@") - } - } - } - - public enum HumidityUnit { - public enum Dew { - /// Dew point (%@) - public static func title(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "HumidityUnit.Dew.title", String(describing: p1), fallback: "Dew point (%@)") - } - } - - public enum Percent { - /// Relative (%) - public static let title = RuuviLocalization.tr("Localizable", "HumidityUnit.Percent.title", fallback: "Relative (%)") - } - - public enum Gm3 { - /// Absolute (g/m³) - public static let title = RuuviLocalization.tr("Localizable", "HumidityUnit.gm3.title", fallback: "Absolute (g/m³)") - } - } - - public enum Interval { - public enum Day { - /// Day - public static let string = RuuviLocalization.tr("Localizable", "Interval.Day.string", fallback: "Day") - } - - public enum Days { - /// Days - public static let string = RuuviLocalization.tr("Localizable", "Interval.Days.string", fallback: "Days") - } - } - - public enum Language { - /// English - public static let english = RuuviLocalization.tr("Localizable", "Language.English", fallback: "English") - /// Suomi - public static let finnish = RuuviLocalization.tr("Localizable", "Language.Finnish", fallback: "Suomi") - /// Français - public static let french = RuuviLocalization.tr("Localizable", "Language.French", fallback: "Français") - /// Deutsch - public static let german = RuuviLocalization.tr("Localizable", "Language.German", fallback: "Deutsch") - /// Русский - public static let russian = RuuviLocalization.tr("Localizable", "Language.Russian", fallback: "Русский") - /// Svenska - public static let swedish = RuuviLocalization.tr("Localizable", "Language.Swedish", fallback: "Svenska") - } - - public enum LocalNotificationsManager { - public enum DidConnect { - /// Connected - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidConnect.title", fallback: "Connected") - } - - public enum DidDisconnect { - /// Disconnected - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidDisconnect.title", fallback: "Disconnected") - } - - public enum DidMove { - /// Movement detected! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidMove.title", fallback: "Movement detected!") - } - - public enum Disable { - /// Turn off - public static let button = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.Disable.button", fallback: "Turn off") - } - - public enum HighDewPoint { - /// Dew Point is too high! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighDewPoint.title", fallback: "Dew Point is too high!") - } - - public enum HighHumidity { - /// Air Humidity is too high! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighHumidity.title", fallback: "Air Humidity is too high!") - } - - public enum HighPressure { - /// Air Pressure is too high! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighPressure.title", fallback: "Air Pressure is too high!") - } - - public enum HighSignal { - /// Signal strength is too high! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighSignal.title", fallback: "Signal strength is too high!") - } - - public enum HighTemperature { - /// Temperature is too high! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighTemperature.title", fallback: "Temperature is too high!") - } - - public enum LowDewPoint { - /// Dew Point is too low! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowDewPoint.title", fallback: "Dew Point is too low!") - } - - public enum LowHumidity { - /// Air Humidity is too low! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowHumidity.title", fallback: "Air Humidity is too low!") - } - - public enum LowPressure { - /// Air Pressure is too low! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowPressure.title", fallback: "Air Pressure is too low!") - } - - public enum LowSignal { - /// Signal strength is too low! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowSignal.title", fallback: "Signal strength is too low!") - } - - public enum LowTemperature { - /// Temperature is too low! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowTemperature.title", fallback: "Temperature is too low!") - } - - public enum Mute { - /// Mute for an hour - public static let button = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.Mute.button", fallback: "Mute for an hour") - } - } - - public enum Menu { - public enum BuyGateway { - public enum Url { - /// https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios - public static let ios = RuuviLocalization.tr("Localizable", "Menu.BuyGateway.URL.IOS", fallback: "https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") - } - } - - public enum Label { - public enum AboutHelp { - /// About / Help - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AboutHelp.text", fallback: "About / Help") - } - - public enum AddAnNewSensor { - /// Add a New Sensor - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AddAnNewSensor.text", fallback: "Add a New Sensor") - } - - public enum AppSettings { - /// App Settings - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AppSettings.text", fallback: "App Settings") - } - - public enum BuyRuuviGateway { - /// Buy Ruuvi Gateway - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.BuyRuuviGateway.text", fallback: "Buy Ruuvi Gateway") - } - - public enum Feedback { - /// Send Feedback - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.Feedback.text", fallback: "Send Feedback") - } - - public enum GetMoreSensors { - /// Buy Ruuvi Sensors - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.GetMoreSensors.text", fallback: "Buy Ruuvi Sensors") - } - - public enum MyRuuviAccount { - /// My Ruuvi Account - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.MyRuuviAccount.text", fallback: "My Ruuvi Account") - } - - public enum WhatToMeasure { - /// What to measure with Ruuvi? - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.WhatToMeasure.text", fallback: "What to measure with Ruuvi?") - } - } - - public enum LoggedIn { - /// Signed in: - public static let title = RuuviLocalization.tr("Localizable", "Menu.LoggedIn.title", fallback: "Signed in:") - } - - public enum Measure { - public enum Url { - /// https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios - public static let ios = RuuviLocalization.tr("Localizable", "Menu.Measure.URL.IOS", fallback: "https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") - } - } - - public enum RuuviNetworkStatus { - /// Ruuvi Cloud status - public static let text = RuuviLocalization.tr("Localizable", "Menu.RuuviNetworkStatus.text", fallback: "Ruuvi Cloud status") - } - - public enum SignOut { - /// Sign out - public static let text = RuuviLocalization.tr("Localizable", "Menu.SignOut.text", fallback: "Sign out") - } - } - - public enum MenuTableViewController { - /// none - public static let none = RuuviLocalization.tr("Localizable", "MenuTableViewController.None", fallback: "none") - /// User: %@ - public static func user(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "MenuTableViewController.User", String(describing: p1), fallback: "User: %@") - } - } - - public enum MyRuuvi { - public enum Settings { - public enum DeleteAccount { - /// Delete Account - public static let title = RuuviLocalization.tr("Localizable", "MyRuuvi.Settings.DeleteAccount.title", fallback: "Delete Account") - public enum Confirmation { - /// A confirmation has been sent to your email. To proceed with the deletion, please check your inbox and follow the instructions. - public static let message = RuuviLocalization.tr("Localizable", "MyRuuvi.Settings.DeleteAccount.Confirmation.message", fallback: "A confirmation has been sent to your email. To proceed with the deletion, please check your inbox and follow the instructions.") - } - } - } - } - - public enum OWMError { - /// API limit exceeded - public static let apiLimitExceeded = RuuviLocalization.tr("Localizable", "OWMError.apiLimitExceeded", fallback: "API limit exceeded") - /// Failed to parse Open Weather Map response - public static let failedToParseOpenWeatherMapResponse = RuuviLocalization.tr("Localizable", "OWMError.failedToParseOpenWeatherMapResponse", fallback: "Failed to parse Open Weather Map response") - /// Invalid API Key - public static let invalidApiKey = RuuviLocalization.tr("Localizable", "OWMError.invalidApiKey", fallback: "Invalid API Key") - /// Not an HTTP response - public static let notAHttpResponse = RuuviLocalization.tr("Localizable", "OWMError.notAHttpResponse", fallback: "Not an HTTP response") - } - - public enum OffsetCorrection { - public enum Calibrate { - /// Offset correction - public static let button = RuuviLocalization.tr("Localizable", "OffsetCorrection.Calibrate.button", fallback: "Offset correction") - } - - public enum CalibrationDescription { - /// In normal use, it's not necessary to adjust the offset. - /// - /// If you're an advanced user and you'd like to manually configure the factory calibrated sensors, it's possible to do so. - /// - /// Calibration tips are available on ruuvi.com/support - public static let text = RuuviLocalization.tr("Localizable", "OffsetCorrection.CalibrationDescription.text", fallback: "In normal use, it's not necessary to adjust the offset.\n\nIf you're an advanced user and you'd like to manually configure the factory calibrated sensors, it's possible to do so.\n\nCalibration tips are available on ruuvi.com/support") - } - - public enum CorrectedValue { - /// Corrected value - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.CorrectedValue.title", fallback: "Corrected value") - } - - public enum Dialog { - public enum Calibration { - /// Clear calibration settings? - public static let clearConfirm = RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.ClearConfirm", fallback: "Clear calibration settings?") - /// Enter the expected humidity value from sensor under current conditions (%@): - public static func enterHumidity(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterHumidity", String(describing: p1), fallback: "Enter the expected humidity value from sensor under current conditions (%@): ") - } - - /// Enter the expected pressure value from sensor under current conditions (%@): - public static func enterPressure(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterPressure", String(describing: p1), fallback: "Enter the expected pressure value from sensor under current conditions (%@): ") - } - - /// Enter the expected temperature value from sensor under current conditions (%@): - public static func enterTemperature(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterTemperature", String(describing: p1), fallback: "Enter the expected temperature value from sensor under current conditions (%@): ") - } - - /// Calibration setup - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.Title", fallback: "Calibration setup") - } - } - - public enum Humidity { - /// Humidity offset - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Humidity.Title", fallback: "Humidity offset") - } - - public enum OriginalValue { - /// Original measured value - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.OriginalValue.title", fallback: "Original measured value") - } - - public enum Pressure { - /// Pressure offset - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Pressure.Title", fallback: "Pressure offset") - } - - public enum Temperature { - /// Temperature offset - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Temperature.Title", fallback: "Temperature offset") - } - } - - public enum Owner { - /// Claim sensor - public static let title = RuuviLocalization.tr("Localizable", "Owner.title", fallback: "Claim sensor") - public enum Claim { - /// Do you own this sensor? If yes, please claim ownership of the sensor and it'll be added to your Ruuvi account. Each Ruuvi sensor can have only one owner. To claim ownership, you need to be signed in. - /// - /// Benefits: - /// - /// ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud - /// - /// ● Access sensors remotely over the Internet (requires a Ruuvi Gateway) - /// - /// ● Share sensors with friends and family (requires a Ruuvi Gateway) - /// - /// ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway) - public static let description = RuuviLocalization.tr("Localizable", "Owner.Claim.description", fallback: "Do you own this sensor? If yes, please claim ownership of the sensor and it'll be added to your Ruuvi account. Each Ruuvi sensor can have only one owner. To claim ownership, you need to be signed in.\n\nBenefits:\n\n ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud\n\n ● Access sensors remotely over the Internet (requires a Ruuvi Gateway)\n\n ● Share sensors with friends and family (requires a Ruuvi Gateway)\n\n ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway)") - } - - public enum ClaimOwnership { - /// Claim ownership - public static let button = RuuviLocalization.tr("Localizable", "Owner.ClaimOwnership.button", fallback: "Claim ownership") - } - } - - public enum PermissionPresenter { - /// Settings - public static let settings = RuuviLocalization.tr("Localizable", "PermissionPresenter.settings", fallback: "Settings") - public enum NoCameraAccess { - /// Ruuvi Station needs to access your camera to enable this feature. - public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoCameraAccess.message", fallback: "Ruuvi Station needs to access your camera to enable this feature.") - } - - public enum NoLocationAccess { - /// Ruuvi Station needs to access your location to enable this feature. - public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoLocationAccess.message", fallback: "Ruuvi Station needs to access your location to enable this feature.") - } - - public enum NoPhotoLibraryAccess { - /// Ruuvi Station needs to access your camera library to enable this feature. - public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoPhotoLibraryAccess.message", fallback: "Ruuvi Station needs to access your camera library to enable this feature.") - } - - public enum NoPushNotificationsPermission { - /// Ruuvi Station needs push notifications permission to enable this feature - public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoPushNotificationsPermission.message", fallback: "Ruuvi Station needs push notifications permission to enable this feature") - } - } - - public enum PhotoPicker { - public enum Sheet { - /// Take photo - public static let camera = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.camera", fallback: "Take photo") - /// Choose from files - public static let files = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.files", fallback: "Choose from files") - /// Choose from the library - public static let library = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.library", fallback: "Choose from the library") - /// Pick a photo - public static let message = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.message", fallback: "Pick a photo") - } - } - - public enum Ruuvi { - public enum BuySensors { - public enum Menu { - public enum Url { - /// https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios - public static let ios = RuuviLocalization.tr("Localizable", "Ruuvi.BuySensors.Menu.URL.IOS", fallback: "https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios") - } - } - - public enum Url { - /// https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios - public static let ios = RuuviLocalization.tr("Localizable", "Ruuvi.BuySensors.URL.IOS", fallback: "https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") - } - } - } - - public enum RuuviCloudApiError { - /// Empty response - public static let emptyResponse = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.emptyResponse", fallback: "Empty response") - /// Failed to get data from response - public static let failedToGetDataFromResponse = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.failedToGetDataFromResponse", fallback: "Failed to get data from response") - /// Unexpected HTTP status code - public static let unexpectedHTTPStatusCode = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.unexpectedHTTPStatusCode", fallback: "Unexpected HTTP status code") - } - - public enum RuuviCloudError { - /// Not authorised - public static let notAuthorized = RuuviLocalization.tr("Localizable", "RuuviCloudError.NotAuthorized", fallback: "Not authorised") - } - - public enum RuuviDfuError { - /// Failed to construct UUID - public static let failedToConstructUUID = RuuviLocalization.tr("Localizable", "RuuviDfuError.failedToConstructUUID", fallback: "Failed to construct UUID") - /// Invalid firmware file - public static let invalidFirmwareFile = RuuviLocalization.tr("Localizable", "RuuviDfuError.invalidFirmwareFile", fallback: "Invalid firmware file") - } - - public enum RuuviLocalError { - /// Failed to get background directory - public static let failedToGetDocumentsDirectory = RuuviLocalization.tr("Localizable", "RuuviLocalError.failedToGetDocumentsDirectory", fallback: "Failed to get background directory") - /// Failed to get JPG representation - public static let failedToGetJpegRepresentation = RuuviLocalization.tr("Localizable", "RuuviLocalError.failedToGetJpegRepresentation", fallback: "Failed to get JPG representation") - } - - public enum RuuviOnboard { - public enum Access { - /// Access data for each linked sensor in real time and explore history graphs. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Access.title", fallback: "Access data for each linked sensor in real time and explore history graphs.") - } - - public enum Alerts { - /// Set alerts and get notified whenever your limits are hit. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Alerts.title", fallback: "Set alerts and get notified whenever your limits are hit.") - } - - public enum Cloud { - /// Claim ownership of your sensors with a free Ruuvi Cloud account. - public static let subtitle = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.subtitle", fallback: "Claim ownership of your sensors with a free Ruuvi Cloud account.") - /// Sign in to use the full potential of the app. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.title", fallback: "Sign in to use the full potential of the app.") - public enum Benefits { - /// Benefits: - /// - /// ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud - /// - /// ● Access sensors remotely over the Internet (requires a Ruuvi Gateway) - /// - /// ● Share sensors with friends and family (requires a Ruuvi Gateway) - /// - /// ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway) - public static let message = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Benefits.message", fallback: "Benefits:\n\n ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud\n\n ● Access sensors remotely over the Internet (requires a Ruuvi Gateway)\n\n ● Share sensors with friends and family (requires a Ruuvi Gateway)\n\n ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway)") - } - - public enum Details { - /// Details - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Details.title", fallback: "Details") - } - - public enum Skip { - /// Are you sure you want to skip sign in? - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.title", fallback: "Are you sure you want to skip sign in?") - public enum GoBack { - /// Go back - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.GoBack.title", fallback: "Go back") - } - - public enum Yes { - /// Yes, skip - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.Yes.title", fallback: "Yes, skip") - } - } - - public enum Subtitle { - /// Great! You already signed in! - public static let signed = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.subtitle.signed", fallback: "Great! You already signed in!") - } - } - - public enum Measure { - /// Measure environmental data: temperature, relative humidity and air pressure. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Measure.title", fallback: "Measure environmental data: temperature, relative humidity and air pressure.") - } - - public enum Start { - /// Press SCAN to find and add nearby sensors to your Ruuvi Station. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Start.title", fallback: "Press SCAN to find and add nearby sensors to your Ruuvi Station.") - } - - public enum Welcome { - /// Swipe to see what Ruuvi Station can do for you. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Welcome.title", fallback: "Swipe to see what Ruuvi Station can do for you.") - } - } - - public enum RuuviPersistenceError { - /// Failed to find sensor - public static let failedToFindRuuviTag = RuuviLocalization.tr("Localizable", "RuuviPersistenceError.failedToFindRuuviTag", fallback: "Failed to find sensor") - } - - public enum RuuviServiceError { - /// Both local and MAC identifiers are nil - public static let bothLuidAndMacAreNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.bothLuidAndMacAreNil", fallback: "Both local and MAC identifiers are nil") - /// Failed to find or generate background image - public static let failedToFindOrGenerateBackgroundImage = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToFindOrGenerateBackgroundImage", fallback: "Failed to find or generate background image") - /// Failed to get JPG representation - public static let failedToGetJpegRepresentation = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToGetJpegRepresentation", fallback: "Failed to get JPG representation") - /// Failed to parse response. - public static let failedToParseNetworkResponse = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToParseNetworkResponse", fallback: "Failed to parse response.") - /// MAC identifier is nil - public static let macIdIsNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.macIdIsNil", fallback: "MAC identifier is nil") - /// Photo URL is nil - public static let pictureUrlIsNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.pictureUrlIsNil", fallback: "Photo URL is nil") - } - - public enum Settings { - public enum BackgroundScanning { - /// Data logging interval - public static let interval = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.interval", fallback: "Data logging interval") - /// Background Scanning - public static let title = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.title", fallback: "Background Scanning") - public enum Footer { - /// Important note: Bluetooth background history logging and Bluetooth alerts work only when background scanning is enabled. If you disable the background scanning, all paired Ruuvi sensors will be automatically unpaired and you need to pair them again from their settings pages. - public static let message = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.Footer.message", fallback: "Important note: Bluetooth background history logging and Bluetooth alerts work only when background scanning is enabled. If you disable the background scanning, all paired Ruuvi sensors will be automatically unpaired and you need to pair them again from their settings pages.") - } - } - - public enum ChooseHumidityUnit { - /// Choose the humidity unit you want to be displayed. - public static let text = RuuviLocalization.tr("Localizable", "Settings.ChooseHumidityUnit.text", fallback: "Choose the humidity unit you want to be displayed.") - } - - public enum ChoosePressureUnit { - /// Choose the pressure unit you want to be displayed. - public static let text = RuuviLocalization.tr("Localizable", "Settings.ChoosePressureUnit.text", fallback: "Choose the pressure unit you want to be displayed.") - } - - public enum ChooseTemperatureUnit { - /// Choose the temperature unit you want to be displayed. - public static let text = RuuviLocalization.tr("Localizable", "Settings.ChooseTemperatureUnit.text", fallback: "Choose the temperature unit you want to be displayed.") - } - - public enum Humidity { - public enum Resolution { - /// Humidity Resolution - public static let title = RuuviLocalization.tr("Localizable", "Settings.Humidity.Resolution.title", fallback: "Humidity Resolution") - } - } - - public enum Label { - /// Chart Settings - public static let chart = RuuviLocalization.tr("Localizable", "Settings.Label.Chart", fallback: "Chart Settings") - /// Cloud mode - public static let cloudMode = RuuviLocalization.tr("Localizable", "Settings.Label.CloudMode", fallback: "Cloud mode") - /// Defaults - public static let defaults = RuuviLocalization.tr("Localizable", "Settings.Label.Defaults", fallback: "Defaults") - /// Foreground - public static let foreground = RuuviLocalization.tr("Localizable", "Settings.Label.Foreground", fallback: "Foreground") - /// Humidity - public static let humidity = RuuviLocalization.tr("Localizable", "Settings.Label.Humidity", fallback: "Humidity") - /// Pressure - public static let pressure = RuuviLocalization.tr("Localizable", "Settings.Label.Pressure", fallback: "Pressure") - /// Temperature - public static let temperature = RuuviLocalization.tr("Localizable", "Settings.Label.Temperature", fallback: "Temperature") - public enum CloudMode { - /// Refresh nearby cloud sensors only from the cloud by ignoring their Bluetooth messages and receiving alerts only by email. Requires a Ruuvi Gateway router. - public static let description = RuuviLocalization.tr("Localizable", "Settings.Label.CloudMode.description", fallback: "Refresh nearby cloud sensors only from the cloud by ignoring their Bluetooth messages and receiving alerts only by email. Requires a Ruuvi Gateway router.") - } - - public enum HumidityUnit { - /// Humidity Unit - public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.HumidityUnit.text", fallback: "Humidity Unit") - } - - public enum Language { - /// Language - public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.Language.text", fallback: "Language") - } - - public enum PressureUnit { - /// Pressure Unit - public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.PressureUnit.text", fallback: "Pressure Unit") - } - - public enum TemperatureUnit { - /// Temperature Unit - public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.TemperatureUnit.text", fallback: "Temperature Unit") - } - } - - public enum Language { - public enum Dialog { - /// Open settings and tap Language to change language of the app. - /// If you cannot see the Language option in the settings, make sure that you have at least one preferred language added in system settings: Settings -> General -> Language & Region. - public static let message = RuuviLocalization.tr("Localizable", "Settings.Language.Dialog.message", fallback: "Open settings and tap Language to change language of the app.\nIf you cannot see the Language option in the settings, make sure that you have at least one preferred language added in system settings: Settings -> General -> Language & Region.") - /// Select Language - public static let title = RuuviLocalization.tr("Localizable", "Settings.Language.Dialog.title", fallback: "Select Language") - } - } - - public enum Measurement { - public enum Resolution { - /// Select how accurately you'd like to see the sensors' live measurement values in the app. This setting doesn't affect history charts or alerts. - public static let description = RuuviLocalization.tr("Localizable", "Settings.Measurement.Resolution.description", fallback: "Select how accurately you'd like to see the sensors' live measurement values in the app. This setting doesn't affect history charts or alerts.") - /// Resolution - public static let title = RuuviLocalization.tr("Localizable", "Settings.Measurement.Resolution.title", fallback: "Resolution") - } - - public enum Unit { - /// Unit - public static let title = RuuviLocalization.tr("Localizable", "Settings.Measurement.Unit.title", fallback: "Unit") - } - } - - public enum Pressure { - public enum Resolution { - /// Pressure Resolution - public static let title = RuuviLocalization.tr("Localizable", "Settings.Pressure.Resolution.title", fallback: "Pressure Resolution") - } - } - - public enum SectionHeader { - public enum Application { - /// APPLICATION - public static let title = RuuviLocalization.tr("Localizable", "Settings.SectionHeader.Application.title", fallback: "APPLICATION") - } - - public enum General { - /// GENERAL - public static let title = RuuviLocalization.tr("Localizable", "Settings.SectionHeader.General.title", fallback: "GENERAL") - } - } - - public enum SegmentedControl { - public enum Humidity { - public enum Absolute { - /// Abs - public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.Absolute.title", fallback: "Abs") - } - - public enum DewPoint { - /// Dew - public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.DewPoint.title", fallback: "Dew") - } - - public enum Relative { - /// Rel - public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.Relative.title", fallback: "Rel") - } - } - } - - public enum Temperature { - public enum Resolution { - /// Temperature Resolution - public static let title = RuuviLocalization.tr("Localizable", "Settings.Temperature.Resolution.title", fallback: "Temperature Resolution") - } - } - - public enum NavigationItem { - /// Settings - public static let title = RuuviLocalization.tr("Localizable", "Settings.navigationItem.title", fallback: "Settings") - } - } - - public enum Share { - public enum Send { - /// Send - public static let button = RuuviLocalization.tr("Localizable", "Share.Send.button", fallback: "Send") - } - - public enum Success { - /// Successfully shared sensor - public static let message = RuuviLocalization.tr("Localizable", "Share.Success.message", fallback: "Successfully shared sensor") - } - } - - public enum SharePresenter { - public enum UnshareSensor { - /// Do you want to unshare sensor for %@? - public static func message(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "SharePresenter.UnshareSensor.Message", String(describing: p1), fallback: "Do you want to unshare sensor for %@?") - } - } - } - - public enum ShareViewController { - /// You can share the sensor with friends and family if it's in range of a Ruuvi Gateway. - /// - /// Receiver will be notified by email. If the receiver doesn't have a Ruuvi account, a free Ruuvi account will automatically be created at first log in. - /// - /// Note that the sensor's custom name and background image will be shared. The name and image sync is one time only, and after this, they can be privately customised by the receiver. Offset values (if any) set by the owner, will be automatically synced, and the receiver will always see the final corrected values. - public static let description = RuuviLocalization.tr("Localizable", "ShareViewController.Description", fallback: "You can share the sensor with friends and family if it's in range of a Ruuvi Gateway.\n\nReceiver will be notified by email. If the receiver doesn't have a Ruuvi account, a free Ruuvi account will automatically be created at first log in.\n\nNote that the sensor's custom name and background image will be shared. The name and image sync is one time only, and after this, they can be privately customised by the receiver. Offset values (if any) set by the owner, will be automatically synced, and the receiver will always see the final corrected values.") - /// Share sensor - public static let title = RuuviLocalization.tr("Localizable", "ShareViewController.Title", fallback: "Share sensor") - public enum AddFriend { - /// Add friend - public static let title = RuuviLocalization.tr("Localizable", "ShareViewController.addFriend.Title", fallback: "Add friend") - } - - public enum EmailTextField { - /// Type email - public static let placeholder = RuuviLocalization.tr("Localizable", "ShareViewController.emailTextField.placeholder", fallback: "Type email") - } - - public enum SharedEmails { - /// You have used %d/%d of maximum shares of this sensor. The sensor has been shared to following users: - public static func title(_ p1: Int, _ p2: Int) -> String { - RuuviLocalization.tr("Localizable", "ShareViewController.sharedEmails.Title", p1, p2, fallback: "You have used %d/%d of maximum shares of this sensor. The sensor has been shared to following users:") - } - } - } - - public enum SignIn { - /// We've sent a one-time password to your email %@. Sign in by entering it here: - public static func checkMailbox(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "SignIn.CheckMailbox", String(describing: p1), fallback: "We've sent a one-time password to your email %@. Sign in by entering it here:") - } - - /// Code - public static let codeHint = RuuviLocalization.tr("Localizable", "SignIn.CodeHint", fallback: "Code") - /// Email - public static let emailPlaceholder = RuuviLocalization.tr("Localizable", "SignIn.EmailPlaceholder", fallback: "Email") - /// Email sent - public static let emailSent = RuuviLocalization.tr("Localizable", "SignIn.EmailSent", fallback: "Email sent") - /// Please enter verification code - public static let enterVerificationCode = RuuviLocalization.tr("Localizable", "SignIn.EnterVerificationCode", fallback: "Please enter verification code") - /// Request a code - public static let requestCode = RuuviLocalization.tr("Localizable", "SignIn.RequestCode", fallback: "Request a code") - /// Submit - public static let submitCode = RuuviLocalization.tr("Localizable", "SignIn.SubmitCode", fallback: "Submit") - /// verification code in format: CJSM - public static let verificationCodePlaceholder = RuuviLocalization.tr("Localizable", "SignIn.VerificationCodePlaceholder", fallback: "verification code in format: CJSM") - public enum EmailMismatch { - public enum Alert { - /// Oops, you've requested the code for %@, but used the code for %@. Please double check that you are using the code for %@ - public static func message(_ p1: Any, _ p2: Any, _ p3: Any) -> String { - RuuviLocalization.tr("Localizable", "SignIn.EmailMismatch.Alert.message", String(describing: p1), String(describing: p2), String(describing: p3), fallback: "Oops, you've requested the code for %@, but used the code for %@. Please double check that you are using the code for %@") - } - } - } - - public enum EmailMissing { - public enum Alert { - /// Oops, the email you've used to get the code was not saved. Please try to sign in again. - public static let message = RuuviLocalization.tr("Localizable", "SignIn.EmailMissing.Alert.message", fallback: "Oops, the email you've used to get the code was not saved. Please try to sign in again.") - } - } - - public enum SubtitleLabel { - /// To enjoy all the features, create a free account or sign in to your existing Ruuvi account by entering your email address. - public static let text = RuuviLocalization.tr("Localizable", "SignIn.SubtitleLabel.text", fallback: "To enjoy all the features, create a free account or sign in to your existing Ruuvi account by entering your email address.") - } - - public enum Sync { - /// Downloading content from the cloud. Please wait. - public static let message = RuuviLocalization.tr("Localizable", "SignIn.Sync.message", fallback: "Downloading content from the cloud. Please wait.") - } - - public enum Title { - /// Sign in - public static let text = RuuviLocalization.tr("Localizable", "SignIn.Title.text", fallback: "Sign in") - } - - public enum TitleLabel { - /// Sign in to - /// Ruuvi - /// Station - public static let text = RuuviLocalization.tr("Localizable", "SignIn.TitleLabel.text", fallback: "Sign in to\nRuuvi\nStation") - } - } - - public enum TagCharts { - public enum AbortSync { - public enum Alert { - /// Sometimes the history download is slow due to the Bluetooth connectivity. Please wait a moment. - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.AbortSync.Alert.message", fallback: "Sometimes the history download is slow due to the Bluetooth connectivity. Please wait a moment.") - } - - public enum Button { - /// Abort download - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.AbortSync.Button.title", fallback: "Abort download") - } - } - - public enum BluetoothDisabledAlert { - /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") - /// Bluetooth is not enabled - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") - } - - public enum Clear { - /// Clear - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Clear.title", fallback: "Clear") - } - - public enum DeleteHistoryConfirmationDialog { - /// Clear the local history data from the app? - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.message", fallback: "Clear the local history data from the app?") - /// Are you sure? - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.title", fallback: "Are you sure?") - public enum Button { - public enum Delete { - /// Delete - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.button.delete.title", fallback: "Delete") - } - } - } - - public enum Dismiss { - public enum Alert { - /// The history download via Bluetooth connection is in progress. Please wait. - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.Dismiss.Alert.message", fallback: "The history download via Bluetooth connection is in progress. Please wait.") - } - } - - public enum Export { - /// EXPORT - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Export.title", fallback: "EXPORT") - } - - public enum FailedToSyncDialog { - /// Bluetooth history download failed. Check that you're within Bluetooth range, your sensor has firmware that supports downloading and that the sensor is not simultaneously connected to another iOS device. Sensor connection is reserved for Ruuvi Station when using connected mode in iOS. - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.FailedToSyncDialog.message", fallback: "Bluetooth history download failed. Check that you're within Bluetooth range, your sensor has firmware that supports downloading and that the sensor is not simultaneously connected to another iOS device. Sensor connection is reserved for Ruuvi Station when using connected mode in iOS.") - /// Download failed - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.FailedToSyncDialog.title", fallback: "Download failed") - } - - public enum NoChartData { - /// No chart data available - public static let text = RuuviLocalization.tr("Localizable", "TagCharts.NoChartData.text", fallback: "No chart data available") - } - - public enum Status { - /// Connecting... - public static let connecting = RuuviLocalization.tr("Localizable", "TagCharts.Status.Connecting", fallback: "Connecting...") - /// Disconnecting... - public static let disconnecting = RuuviLocalization.tr("Localizable", "TagCharts.Status.Disconnecting", fallback: "Disconnecting...") - /// Error - public static let error = RuuviLocalization.tr("Localizable", "TagCharts.Status.Error", fallback: "Error") - /// Reading history - public static let readingHistory = RuuviLocalization.tr("Localizable", "TagCharts.Status.ReadingHistory", fallback: "Reading history") - /// Synchronising... - public static let serving = RuuviLocalization.tr("Localizable", "TagCharts.Status.Serving", fallback: "Synchronising...") - /// Success - public static let success = RuuviLocalization.tr("Localizable", "TagCharts.Status.Success", fallback: "Success") - } - - public enum Sync { - /// Sync - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Sync.title", fallback: "Sync") - } - - public enum SyncConfirmationDialog { - /// Download history data from the sensor? - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.SyncConfirmationDialog.message", fallback: "Download history data from the sensor?") - /// Are you sure? - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.SyncConfirmationDialog.title", fallback: "Are you sure?") - } - - public enum TryAgain { - /// Try again - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.TryAgain.title", fallback: "Try again") - } - } - - public enum TagChartsPresenter { - /// Synchronised: %@ - public static func numberOfPointsSynchronizedOverNetwork(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "TagChartsPresenter.NumberOfPointsSynchronizedOverNetwork", String(describing: p1), fallback: "Synchronised: %@") - } - } - - public enum TagSettings { - /// Share - public static let shareButton = RuuviLocalization.tr("Localizable", "TagSettings.ShareButton", fallback: "Share") - public enum AirHumidityAlert { - /// Air Humidity (%@) - public static func title(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.AirHumidityAlert.title", String(describing: p1), fallback: "Air Humidity (%@)") - } - } - - public enum Alert { - public enum CustomDescription { - /// Set custom description... - public static let placeholder = RuuviLocalization.tr("Localizable", "TagSettings.Alert.CustomDescription.placeholder", fallback: "Set custom description...") - /// Alert custom description - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.CustomDescription.title", fallback: "Alert custom description") - } - - public enum SetHumidity { - /// Set humidity alert - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetHumidity.title", fallback: "Set humidity alert") - } - - public enum SetPressure { - /// Set pressure alert - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetPressure.title", fallback: "Set pressure alert") - } - - public enum SetRSSI { - /// Set signal strength alert - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetRSSI.title", fallback: "Set signal strength alert") - } - - public enum SetTemperature { - /// Set temperature alert - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetTemperature.title", fallback: "Set temperature alert") - } - } - - public enum AlertSettings { - public enum Dialog { - /// Max (%.0f) - public static func max(_ p1: Float) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.AlertSettings.Dialog.Max", p1, fallback: "Max (%.0f)") - } - - /// Min (%.0f) - public static func min(_ p1: Float) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.AlertSettings.Dialog.Min", p1, fallback: "Min (%.0f)") - } - } - } - - public enum Alerts { - /// Off - public static let off = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Off", fallback: "Off") - public enum Connection { - /// Alert when connected/disconnected - public static let description = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Connection.description", fallback: "Alert when connected/disconnected") - } - - public enum DewPoint { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.Alerts.DewPoint.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - - public enum Humidity { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Humidity.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - - public enum Movement { - /// Alert when sensor is moved - public static let description = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Movement.description", fallback: "Alert when sensor is moved") - } - - public enum Pressure { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Pressure.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - - public enum Temperature { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Temperature.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - } - - public enum AlertsAreDisabled { - public enum Dialog { - public enum BothNotConnectedAndNoPNPermission { - /// Alerts are disabled because the device is not connected and missing push notification permission. Please connect to the device first. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.BothNotConnectedAndNoPNPermission.message", fallback: "Alerts are disabled because the device is not connected and missing push notification permission. Please connect to the device first.") - } - - public enum Connect { - /// Connect - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.Connect.title", fallback: "Connect") - } - - public enum NotConnected { - /// Alerts are disabled because you are not connected to the device. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.NotConnected.message", fallback: "Alerts are disabled because you are not connected to the device.") - } - } - } - - public enum BatteryStatusLabel { - public enum Ok { - /// Battery OK - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.BatteryStatusLabel.Ok.message", fallback: "Battery OK") - } - - public enum Replace { - /// Low battery - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.BatteryStatusLabel.Replace.message", fallback: "Low battery") - } - } - - public enum ClaimTagButton { - /// Claim ownership - public static let claim = RuuviLocalization.tr("Localizable", "TagSettings.ClaimTagButton.Claim", fallback: "Claim ownership") - } - - public enum ConnectStatus { - /// Disconnected - public static let disconnected = RuuviLocalization.tr("Localizable", "TagSettings.ConnectStatus.Disconnected", fallback: "Disconnected") - } - - public enum ConnectionAlert { - /// Connection - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.ConnectionAlert.title", fallback: "Connection") - } - - public enum DataSource { - public enum Advertisement { - /// Advertisement - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Advertisement.title", fallback: "Advertisement") - } - - public enum Heartbeat { - /// Heartbeat - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Heartbeat.title", fallback: "Heartbeat") - } - - public enum Network { - /// Cloud - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Network.title", fallback: "Cloud") - } - } - - public enum EmptyValue { - /// - - public static let sign = RuuviLocalization.tr("Localizable", "TagSettings.EmptyValue.sign", fallback: "-") - } - - public enum Firmware { - /// Current version - public static let currentVersion = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.CurrentVersion", fallback: "Current version") - /// Update - public static let updateFirmware = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.UpdateFirmware", fallback: "Update") - public enum CurrentVersion { - /// Very old - public static let veryOld = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.CurrentVersion.VeryOld", fallback: "Very old") - } - } - - public enum General { - public enum Owner { - /// No owner - public static let none = RuuviLocalization.tr("Localizable", "TagSettings.General.Owner.none", fallback: "No owner") - } - } - - public enum HumidityIsClipped { - public enum Alert { - /// Humidity value is greater than 100% after calibration. This value doesn't make sense, so the value has been adjusted to 100%. - public static func message(_ p1: Float) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.message", p1, fallback: "Humidity value is greater than 100% after calibration. This value doesn't make sense, so the value has been adjusted to 100%.") - } - - /// Humidity is adjusted - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.title", fallback: "Humidity is adjusted") - public enum Fix { - /// Fix - public static let button = RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.Fix.button", fallback: "Fix") - } - } - } - - public enum Label { - public enum Alerts { - /// Alerts - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.alerts.text", fallback: "Alerts") - } - - public enum Disabled { - /// DISABLED? - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.disabled.text", fallback: "DISABLED?") - } - - public enum MoreInfo { - /// More info - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.moreInfo.text", fallback: "More info") - } - - public enum NoValues { - /// NO VALUES? - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.noValues.text", fallback: "NO VALUES?") - } - } - - public enum Mac { - public enum Alert { - /// MAC Address - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Mac.Alert.title", fallback: "MAC Address") - } - } - - public enum MovementAlert { - /// Movement - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.MovementAlert.title", fallback: "Movement") - } - - public enum NetworkInfo { - /// Owner - public static let owner = RuuviLocalization.tr("Localizable", "TagSettings.NetworkInfo.Owner", fallback: "Owner") - } - - public enum NotShared { - /// Not shared - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.NotShared.title", fallback: "Not shared") - } - - public enum OffsetCorrection { - /// Humidity - public static let humidity = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Humidity", fallback: "Humidity") - /// Pressure - public static let pressure = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Pressure", fallback: "Pressure") - /// Temperature - public static let temperature = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Temperature", fallback: "Temperature") - } - - public enum PairAndBackgroundScan { - /// Alerts are not available over Bluetooth connection if background scanning is not enabled. Only one iOS device can be paired to a Ruuvi sensor at a time. - public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.description", fallback: "Alerts are not available over Bluetooth connection if background scanning is not enabled. Only one iOS device can be paired to a Ruuvi sensor at a time.") - public enum Paired { - /// Paired and background scan is on - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Paired.title", fallback: "Paired and background scan is on") - } - - public enum Pairing { - /// Connecting to the sensor - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Pairing.title", fallback: "Connecting to the sensor") - } - - public enum Unpaired { - /// Pair and use background scan - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Unpaired.title", fallback: "Pair and use background scan") - } - } - - public enum PairError { - public enum CloudMode { - /// The sensor cannot be connected to via Bluetooth when the cloud mode is active. You can re-enable the Bluetooth connection for the cloud sensors by disabling cloud mode in the app settings. - public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairError.CloudMode.description", fallback: "The sensor cannot be connected to via Bluetooth when the cloud mode is active. You can re-enable the Bluetooth connection for the cloud sensors by disabling cloud mode in the app settings.") - } - - public enum Timeout { - /// Connection timed out. Pairing was unsuccessful. Please try again. - public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairError.Timeout.description", fallback: "Connection timed out. Pairing was unsuccessful. Please try again.") - } - } - - public enum PressureAlert { - /// Air Pressure (%@) - public static func title(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.PressureAlert.title", String(describing: p1), fallback: "Air Pressure (%@)") - } - } - - public enum RemoveThisSensor { - /// Remove this sensor - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.RemoveThisSensor.title", fallback: "Remove this sensor") - } - - public enum SectionHeader { - public enum BTConnection { - /// BLUETOOTH CONNECTION - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.BTConnection.title", fallback: "BLUETOOTH CONNECTION") - } - - public enum Calibration { - /// CALIBRATION - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Calibration.title", fallback: "CALIBRATION") - } - - public enum Firmware { - /// Firmware - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Firmware.title", fallback: "Firmware") - } - - public enum General { - /// General - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.General.title", fallback: "General") - } - - public enum Name { - /// NAME - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Name.title", fallback: "NAME") - } - - public enum NetworkInfo { - /// NETWORK INFO - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.NetworkInfo.title", fallback: "NETWORK INFO") - } - - public enum OffsetCorrection { - /// OFFSET CORRECTION - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.OffsetCorrection.Title", fallback: "OFFSET CORRECTION") - } - - public enum Remove { - /// REMOVE - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Remove.title", fallback: "REMOVE") - } - } - - public enum Share { - /// Share - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Share.title", fallback: "Share") - } - - public enum Shared { - /// Shared - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Shared.title", fallback: "Shared") - } - - public enum Uuid { - public enum Alert { - /// UUID - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UUID.Alert.title", fallback: "UUID") - } - } - - public enum UpdateFirmware { - public enum Alert { - /// In order to see missing values: - /// If you are using the latest firmware, set RAWv2 mode by pressing "B" on a sensor. - /// Or update your sensor with the latest firmware. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.message", fallback: "In order to see missing values:\nIf you are using the latest firmware, set RAWv2 mode by pressing \"B\" on a sensor.\nOr update your sensor with the latest firmware.") - /// RAWv2 mode is required - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.title", fallback: "RAWv2 mode is required") - public enum Buttons { - public enum LearnMore { - /// Learn more - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.Buttons.LearnMore.title", fallback: "Learn more") - } - } - } - } - - public enum AccelerationXTitleLabel { - /// Acceleration X - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationXTitleLabel.text", fallback: "Acceleration X") - } - - public enum AccelerationYTitleLabel { - /// Acceleration Y - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationYTitleLabel.text", fallback: "Acceleration Y") - } - - public enum AccelerationZTitleLabel { - /// Acceleration Z - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationZTitleLabel.text", fallback: "Acceleration Z") - } - - public enum BackgroundImageLabel { - /// Background image - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.backgroundImageLabel.text", fallback: "Background image") - } - - public enum BatteryVoltageTitleLabel { - /// Battery Voltage - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.batteryVoltageTitleLabel.text", fallback: "Battery Voltage") - } - - public enum ConfirmSharedTagRemovalDialog { - /// If you remove the sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmSharedTagRemovalDialog.message", fallback: "If you remove the sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore.") - } - - public enum ConfirmTagRemovalDialog { - /// Do you want to remove the sensor? You can add it again later, if needed. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagRemovalDialog.message", fallback: "Do you want to remove the sensor? You can add it again later, if needed.") - /// Remove sensor - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagRemovalDialog.title", fallback: "Remove sensor") - } - - public enum ConfirmTagUnclaimAndRemoveDialog { - /// By removing the sensor, your sensor ownership status will be revoked. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagUnclaimAndRemoveDialog.message", fallback: "By removing the sensor, your sensor ownership status will be revoked. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner.") - } - - public enum DataFormatTitleLabel { - /// Data Format - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dataFormatTitleLabel.text", fallback: "Data Format") - } - - public enum DataSourceTitleLabel { - /// Data Received Via - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dataSourceTitleLabel.text", fallback: "Data Received Via") - } - - public enum DewPointAlertTitleLabel { - /// Dew Point - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dewPointAlertTitleLabel.text", fallback: "Dew Point") - } - - public enum HumidityTitleLabel { - /// Humidity - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.humidityTitleLabel.text", fallback: "Humidity") - } - - public enum MacAddressTitleLabel { - /// MAC Address - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.macAddressTitleLabel.text", fallback: "MAC Address") - } - - public enum McTitleLabel { - /// Movement Counter - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.mcTitleLabel.text", fallback: "Movement Counter") - } - - public enum MsnTitleLabel { - /// Measurement Sequence Number - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.msnTitleLabel.text", fallback: "Measurement Sequence Number") - } - - public enum NavigationItem { - /// Sensor Settings - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.navigationItem.title", fallback: "Sensor Settings") - } - - public enum RssiTitleLabel { - /// Signal Strength (RSSI) - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.rssiTitleLabel.text", fallback: "Signal Strength (RSSI)") - } - - public enum TagNameTitleLabel { - /// Name - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.tagNameTitleLabel.text", fallback: "Name") - public enum Rename { - /// Your sensors are displayed in alphabetical order. - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.tagNameTitleLabel.rename.text", fallback: "Your sensors are displayed in alphabetical order.") - } - } - - public enum TemperatureAlertTitleLabel { - /// Temperature (%@) - public static func text(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.temperatureAlertTitleLabel.text", String(describing: p1), fallback: "Temperature (%@)") - } - } - - public enum TxPowerTitleLabel { - /// Tx Power - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.txPowerTitleLabel.text", fallback: "Tx Power") - } - - public enum UuidTitleLabel { - /// UUID - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.uuidTitleLabel.text", fallback: "UUID") + } + public enum Share { + /// Share + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Share.title", fallback: "Share") + } + public enum Shared { + /// Shared + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Shared.title", fallback: "Shared") + } + public enum Uuid { + public enum Alert { + /// UUID + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UUID.Alert.title", fallback: "UUID") } + } + public enum UpdateFirmware { + public enum Alert { + /// In order to see missing values: + /// If you are using the latest firmware, set RAWv2 mode by pressing "B" on a sensor. + /// Or update your sensor with the latest firmware. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.message", fallback: "In order to see missing values:\nIf you are using the latest firmware, set RAWv2 mode by pressing \"B\" on a sensor.\nOr update your sensor with the latest firmware.") + /// RAWv2 mode is required + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.title", fallback: "RAWv2 mode is required") + public enum Buttons { + public enum LearnMore { + /// Learn more + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.Buttons.LearnMore.title", fallback: "Learn more") + } + } + } + } + public enum AccelerationXTitleLabel { + /// Acceleration X + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationXTitleLabel.text", fallback: "Acceleration X") + } + public enum AccelerationYTitleLabel { + /// Acceleration Y + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationYTitleLabel.text", fallback: "Acceleration Y") + } + public enum AccelerationZTitleLabel { + /// Acceleration Z + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationZTitleLabel.text", fallback: "Acceleration Z") + } + public enum BackgroundImageLabel { + /// Background image + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.backgroundImageLabel.text", fallback: "Background image") + } + public enum BatteryVoltageTitleLabel { + /// Battery Voltage + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.batteryVoltageTitleLabel.text", fallback: "Battery Voltage") + } + public enum ConfirmSharedTagRemovalDialog { + /// If you remove the sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmSharedTagRemovalDialog.message", fallback: "If you remove the sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore.") + } + public enum ConfirmTagRemovalDialog { + /// Do you want to remove the sensor? You can add it again later, if needed. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagRemovalDialog.message", fallback: "Do you want to remove the sensor? You can add it again later, if needed.") + /// Remove sensor + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagRemovalDialog.title", fallback: "Remove sensor") + } + public enum ConfirmTagUnclaimAndRemoveDialog { + /// By removing the sensor, your sensor ownership status will be revoked. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner. + public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagUnclaimAndRemoveDialog.message", fallback: "By removing the sensor, your sensor ownership status will be revoked. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner.") + } + public enum DataFormatTitleLabel { + /// Data Format + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dataFormatTitleLabel.text", fallback: "Data Format") + } + public enum DataSourceTitleLabel { + /// Data Received Via + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dataSourceTitleLabel.text", fallback: "Data Received Via") + } + public enum DewPointAlertTitleLabel { + /// Dew Point + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dewPointAlertTitleLabel.text", fallback: "Dew Point") + } + public enum HumidityTitleLabel { + /// Humidity + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.humidityTitleLabel.text", fallback: "Humidity") + } + public enum MacAddressTitleLabel { + /// MAC Address + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.macAddressTitleLabel.text", fallback: "MAC Address") + } + public enum McTitleLabel { + /// Movement Counter + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.mcTitleLabel.text", fallback: "Movement Counter") + } + public enum MsnTitleLabel { + /// Measurement Sequence Number + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.msnTitleLabel.text", fallback: "Measurement Sequence Number") + } + public enum NavigationItem { + /// Sensor Settings + public static let title = RuuviLocalization.tr("Localizable", "TagSettings.navigationItem.title", fallback: "Sensor Settings") + } + public enum RssiTitleLabel { + /// Signal Strength (RSSI) + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.rssiTitleLabel.text", fallback: "Signal Strength (RSSI)") + } + public enum TagNameTitleLabel { + /// Name + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.tagNameTitleLabel.text", fallback: "Name") + public enum Rename { + /// Your sensors are displayed in alphabetical order. + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.tagNameTitleLabel.rename.text", fallback: "Your sensors are displayed in alphabetical order.") + } + } + public enum TemperatureAlertTitleLabel { + /// Temperature (%@) + public static func text(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "TagSettings.temperatureAlertTitleLabel.text", String(describing: p1), fallback: "Temperature (%@)") + } + } + public enum TxPowerTitleLabel { + /// Tx Power + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.txPowerTitleLabel.text", fallback: "Tx Power") + } + public enum UuidTitleLabel { + /// UUID + public static let text = RuuviLocalization.tr("Localizable", "TagSettings.uuidTitleLabel.text", fallback: "UUID") + } } - public enum TagsManagerPresenter { - public enum SignOutConfirmAlert { - /// When you sign out, sensors the ownerships of which you've claimed on the sensor Settings page will be automatically removed from the app. When you sign in again using the same email address, the sensors will be returned from the cloud. - /// - /// Do you want to sign out? - public static let message = RuuviLocalization.tr("Localizable", "TagsManagerPresenter.SignOutConfirmAlert.Message", fallback: "When you sign out, sensors the ownerships of which you've claimed on the sensor Settings page will be automatically removed from the app. When you sign in again using the same email address, the sensors will be returned from the cloud.\n\nDo you want to sign out?") - } + public enum SignOutConfirmAlert { + /// When you sign out, sensors the ownerships of which you've claimed on the sensor Settings page will be automatically removed from the app. When you sign in again using the same email address, the sensors will be returned from the cloud. + /// + /// Do you want to sign out? + public static let message = RuuviLocalization.tr("Localizable", "TagsManagerPresenter.SignOutConfirmAlert.Message", fallback: "When you sign out, sensors the ownerships of which you've claimed on the sensor Settings page will be automatically removed from the app. When you sign in again using the same email address, the sensors will be returned from the cloud.\n\nDo you want to sign out?") + } } - public enum TemperatureUnit { - public enum Celsius { - /// Celsius (℃) - public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Celsius.title", fallback: "Celsius (℃)") - } - - public enum Fahrenheit { - /// Fahrenheit (℉) - public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Fahrenheit.title", fallback: "Fahrenheit (℉)") - } - - public enum Kelvin { - /// Kelvin (K) - public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Kelvin.title", fallback: "Kelvin (K)") - } + public enum Celsius { + /// Celsius (℃) + public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Celsius.title", fallback: "Celsius (℃)") + } + public enum Fahrenheit { + /// Fahrenheit (℉) + public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Fahrenheit.title", fallback: "Fahrenheit (℉)") + } + public enum Kelvin { + /// Kelvin (K) + public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Kelvin.title", fallback: "Kelvin (K)") + } } - public enum UnexpectedError { - /// Attempt to read data from Realm without LUID - public static let attemptToReadDataFromRealmWithoutLUID = RuuviLocalization.tr("Localizable", "UnexpectedError.attemptToReadDataFromRealmWithoutLUID", fallback: "Attempt to read data from Realm without LUID") - /// Both local and MAC identifiers are nil - public static let bothLuidAndMacAreNil = RuuviLocalization.tr("Localizable", "UnexpectedError.bothLuidAndMacAreNil", fallback: "Both local and MAC identifiers are nil") - /// Both callback result and error are nil - public static let callbackErrorAndResultAreNil = RuuviLocalization.tr("Localizable", "UnexpectedError.callbackErrorAndResultAreNil", fallback: "Both callback result and error are nil") - /// Caller was deallocated during operation - public static let callerDeinitedDuringOperation = RuuviLocalization.tr("Localizable", "UnexpectedError.callerDeinitedDuringOperation", fallback: "Caller was deallocated during operation") - /// Failed to find logs for the sensor - public static let failedToFindLogsForTheTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindLogsForTheTag", fallback: "Failed to find logs for the sensor") - /// Failed to find or generate background image - public static let failedToFindOrGenerateBackgroundImage = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindOrGenerateBackgroundImage", fallback: "Failed to find or generate background image") - /// Failed to find sensor - public static let failedToFindRuuviTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindRuuviTag", fallback: "Failed to find sensor") - /// Failed to find virtual sensor - public static let failedToFindVirtualTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindVirtualTag", fallback: "Failed to find virtual sensor") - /// Failed to reverse geocode location - public static let failedToReverseGeocodeCoordinate = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToReverseGeocodeCoordinate", fallback: "Failed to reverse geocode location") - /// View Model UUID is nil - public static let viewModelUUIDIsNil = RuuviLocalization.tr("Localizable", "UnexpectedError.viewModelUUIDIsNil", fallback: "View Model UUID is nil") + /// Attempt to read data from Realm without LUID + public static let attemptToReadDataFromRealmWithoutLUID = RuuviLocalization.tr("Localizable", "UnexpectedError.attemptToReadDataFromRealmWithoutLUID", fallback: "Attempt to read data from Realm without LUID") + /// Both local and MAC identifiers are nil + public static let bothLuidAndMacAreNil = RuuviLocalization.tr("Localizable", "UnexpectedError.bothLuidAndMacAreNil", fallback: "Both local and MAC identifiers are nil") + /// Both callback result and error are nil + public static let callbackErrorAndResultAreNil = RuuviLocalization.tr("Localizable", "UnexpectedError.callbackErrorAndResultAreNil", fallback: "Both callback result and error are nil") + /// Caller was deallocated during operation + public static let callerDeinitedDuringOperation = RuuviLocalization.tr("Localizable", "UnexpectedError.callerDeinitedDuringOperation", fallback: "Caller was deallocated during operation") + /// Failed to find logs for the sensor + public static let failedToFindLogsForTheTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindLogsForTheTag", fallback: "Failed to find logs for the sensor") + /// Failed to find or generate background image + public static let failedToFindOrGenerateBackgroundImage = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindOrGenerateBackgroundImage", fallback: "Failed to find or generate background image") + /// Failed to find sensor + public static let failedToFindRuuviTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindRuuviTag", fallback: "Failed to find sensor") + /// Failed to find virtual sensor + public static let failedToFindVirtualTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindVirtualTag", fallback: "Failed to find virtual sensor") + /// Failed to reverse geocode location + public static let failedToReverseGeocodeCoordinate = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToReverseGeocodeCoordinate", fallback: "Failed to reverse geocode location") + /// View Model UUID is nil + public static let viewModelUUIDIsNil = RuuviLocalization.tr("Localizable", "UnexpectedError.viewModelUUIDIsNil", fallback: "View Model UUID is nil") } - public enum UnitPressure { - public enum Hectopascal { - /// Hectopascal (hPa) - public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.hectopascal.title", fallback: "Hectopascal (hPa)") - } - - public enum InchOfMercury { - /// Inch of mercury (inHg) - public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.inchOfMercury.title", fallback: "Inch of mercury (inHg)") - } - - public enum MillimetreOfMercury { - /// Millimetre of mercury (mmHg) - public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.millimetreOfMercury.title", fallback: "Millimetre of mercury (mmHg)") - } + public enum Hectopascal { + /// Hectopascal (hPa) + public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.hectopascal.title", fallback: "Hectopascal (hPa)") + } + public enum InchOfMercury { + /// Inch of mercury (inHg) + public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.inchOfMercury.title", fallback: "Inch of mercury (inHg)") + } + public enum MillimetreOfMercury { + /// Millimetre of mercury (mmHg) + public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.millimetreOfMercury.title", fallback: "Millimetre of mercury (mmHg)") + } } - public enum UpdateFirmware { - public enum Download { - /// To start with the update process, first download the latest software package on the device you're going to use for updates. Latest version is available on ruuvi.com/software-update - public static let content = RuuviLocalization.tr("Localizable", "UpdateFirmware.Download.content", fallback: "To start with the update process, first download the latest software package on the device you're going to use for updates. Latest version is available on ruuvi.com/software-update") - /// DOWNLOAD LATEST FIRMWARE - public static let header = RuuviLocalization.tr("Localizable", "UpdateFirmware.Download.header", fallback: "DOWNLOAD LATEST FIRMWARE") - } - - public enum NextButton { - /// NEXT - public static let title = RuuviLocalization.tr("Localizable", "UpdateFirmware.NextButton.title", fallback: "NEXT") - } - - public enum SetDfu { - /// Open the RuuviTag's enclosure by pulling it open with your fingers or gently with a flat head screw driver. - /// - /// Set RuuviTag to bootloader mode by holding down button B and pressing reset button R. Red indicator LED light will light up and stay on. If your device has only 1 button, keep it pressed 10 seconds to enter the bootloader. - public static let content = RuuviLocalization.tr("Localizable", "UpdateFirmware.SetDfu.content", fallback: "Open the RuuviTag's enclosure by pulling it open with your fingers or gently with a flat head screw driver.\n\nSet RuuviTag to bootloader mode by holding down button B and pressing reset button R. Red indicator LED light will light up and stay on. If your device has only 1 button, keep it pressed 10 seconds to enter the bootloader.") - /// SET RUUVI TAG TO DFU MODE - public static let header = RuuviLocalization.tr("Localizable", "UpdateFirmware.SetDfu.header", fallback: "SET RUUVI TAG TO DFU MODE") - } - - public enum Title { - /// Update Firmware - public static let text = RuuviLocalization.tr("Localizable", "UpdateFirmware.Title.text", fallback: "Update Firmware") - } + public enum Download { + /// To start with the update process, first download the latest software package on the device you're going to use for updates. Latest version is available on ruuvi.com/software-update + public static let content = RuuviLocalization.tr("Localizable", "UpdateFirmware.Download.content", fallback: "To start with the update process, first download the latest software package on the device you're going to use for updates. Latest version is available on ruuvi.com/software-update") + /// DOWNLOAD LATEST FIRMWARE + public static let header = RuuviLocalization.tr("Localizable", "UpdateFirmware.Download.header", fallback: "DOWNLOAD LATEST FIRMWARE") + } + public enum NextButton { + /// NEXT + public static let title = RuuviLocalization.tr("Localizable", "UpdateFirmware.NextButton.title", fallback: "NEXT") + } + public enum SetDfu { + /// Open the RuuviTag's enclosure by pulling it open with your fingers or gently with a flat head screw driver. + /// + /// Set RuuviTag to bootloader mode by holding down button B and pressing reset button R. Red indicator LED light will light up and stay on. If your device has only 1 button, keep it pressed 10 seconds to enter the bootloader. + public static let content = RuuviLocalization.tr("Localizable", "UpdateFirmware.SetDfu.content", fallback: "Open the RuuviTag's enclosure by pulling it open with your fingers or gently with a flat head screw driver.\n\nSet RuuviTag to bootloader mode by holding down button B and pressing reset button R. Red indicator LED light will light up and stay on. If your device has only 1 button, keep it pressed 10 seconds to enter the bootloader.") + /// SET RUUVI TAG TO DFU MODE + public static let header = RuuviLocalization.tr("Localizable", "UpdateFirmware.SetDfu.header", fallback: "SET RUUVI TAG TO DFU MODE") + } + public enum Title { + /// Update Firmware + public static let text = RuuviLocalization.tr("Localizable", "UpdateFirmware.Title.text", fallback: "Update Firmware") + } } - public enum UserApiError { - /// Maximum claim count for the user reached - public static let erClaimCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_CLAIM_COUNT_REACHED", fallback: "Maximum claim count for the user reached") - /// Data already exists, cannot update - public static let erConflict = RuuviLocalization.tr("Localizable", "UserApiError.ER_CONFLICT", fallback: "Data already exists, cannot update") - /// Forbidden - public static let erForbidden = RuuviLocalization.tr("Localizable", "UserApiError.ER_FORBIDDEN", fallback: "Forbidden") - /// Gateway already whitelisted - public static let erGatewayAlreadyWhitelisted = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_ALREADY_WHITELISTED", fallback: "Gateway already whitelisted") - /// Gateway not found - public static let erGatewayNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_NOT_FOUND", fallback: "Gateway not found") - /// Gateway status report failed - public static let erGatewayStatusReportFailed = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED", fallback: "Gateway status report failed") - /// Internal error - public static let erInternal = RuuviLocalization.tr("Localizable", "UserApiError.ER_INTERNAL", fallback: "Internal error") - /// Invalid density mode - public static let erInvalidDensityMode = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_DENSITY_MODE", fallback: "Invalid density mode") - /// Invalid email address - public static let erInvalidEmailAddress = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_EMAIL_ADDRESS", fallback: "Invalid email address") - /// Invalid ENUM value given - public static let erInvalidEnumValue = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_ENUM_VALUE", fallback: "Invalid ENUM value given") - /// Invalid request format - public static let erInvalidFormat = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_FORMAT", fallback: "Invalid request format") - /// Invalid MAC-address - public static let erInvalidMacAddress = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_MAC_ADDRESS", fallback: "Invalid MAC-address") - /// Invalid sort mode - public static let erInvalidSortMode = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_SORT_MODE", fallback: "Invalid sort mode") - /// Invalid time range - public static let erInvalidTimeRange = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_TIME_RANGE", fallback: "Invalid time range") - /// Missing argument - public static let erMissingArgument = RuuviLocalization.tr("Localizable", "UserApiError.ER_MISSING_ARGUMENT", fallback: "Missing argument") - /// In order to share a sensor, it must have data - public static let erNoDataToShare = RuuviLocalization.tr("Localizable", "UserApiError.ER_NO_DATA_TO_SHARE", fallback: "In order to share a sensor, it must have data") - /// Newer data already exists, cannot update - public static let erOldEntry = RuuviLocalization.tr("Localizable", "UserApiError.ER_OLD_ENTRY", fallback: "Newer data already exists, cannot update") - /// Sensor already claimed by %@ - public static func erSensorAlreadyClaimed(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_CLAIMED", String(describing: p1), fallback: "Sensor already claimed by %@") - } - - /// Sensor already claimed - public static let erSensorAlreadyClaimedNoEmail = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_CLAIMED_NO_EMAIL", fallback: "Sensor already claimed") - /// The sensor has already been registered - public static let erSensorAlreadyRegistered = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_REGISTERED", fallback: "The sensor has already been registered") - /// This sensor is already shared - public static let erSensorAlreadyShared = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_SHARED", fallback: "This sensor is already shared") - /// Sensor not found - public static let erSensorNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_NOT_FOUND", fallback: "Sensor not found") - /// Maximum share count for the sensor reached - public static let erSensorShareCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_SHARE_COUNT_REACHED", fallback: "Maximum share count for the sensor reached") - /// The share limit is reached - public static let erShareCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_SHARE_COUNT_REACHED", fallback: "The share limit is reached") - /// Data storage error - public static let erSubDataStorageError = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUB_DATA_STORAGE_ERROR", fallback: "Data storage error") - /// No user - public static let erSubNoUser = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUB_NO_USER", fallback: "No user") - /// Tried to add duplicate subscription to a code - public static let erSubscriptionCodeExists = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_CODE_EXISTS", fallback: "Tried to add duplicate subscription to a code") - /// Tried to claim already used code - public static let erSubscriptionCodeUsed = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_CODE_USED", fallback: "Tried to claim already used code") - /// Subscription is not found - public static let erSubscriptionNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_NOT_FOUND", fallback: "Subscription is not found") - /// Too many requests - public static let erThrottled = RuuviLocalization.tr("Localizable", "UserApiError.ER_THROTTLED", fallback: "Too many requests") - /// Token is expired - public static let erTokenExpired = RuuviLocalization.tr("Localizable", "UserApiError.ER_TOKEN_EXPIRED", fallback: "Token is expired") - /// Unable to send email - public static let erUnableToSendEmail = RuuviLocalization.tr("Localizable", "UserApiError.ER_UNABLE_TO_SEND_EMAIL", fallback: "Unable to send email") - /// Unauthorised - public static let erUnauthorized = RuuviLocalization.tr("Localizable", "UserApiError.ER_UNAUTHORIZED", fallback: "Unauthorised") - /// User not found - public static let erUserNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_USER_NOT_FOUND", fallback: "User not found") - /// Operation was successful - public static let ok = RuuviLocalization.tr("Localizable", "UserApiError.OK", fallback: "Operation was successful") + /// Maximum claim count for the user reached + public static let erClaimCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_CLAIM_COUNT_REACHED", fallback: "Maximum claim count for the user reached") + /// Data already exists, cannot update + public static let erConflict = RuuviLocalization.tr("Localizable", "UserApiError.ER_CONFLICT", fallback: "Data already exists, cannot update") + /// Forbidden + public static let erForbidden = RuuviLocalization.tr("Localizable", "UserApiError.ER_FORBIDDEN", fallback: "Forbidden") + /// Gateway already whitelisted + public static let erGatewayAlreadyWhitelisted = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_ALREADY_WHITELISTED", fallback: "Gateway already whitelisted") + /// Gateway not found + public static let erGatewayNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_NOT_FOUND", fallback: "Gateway not found") + /// Gateway status report failed + public static let erGatewayStatusReportFailed = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED", fallback: "Gateway status report failed") + /// Internal error + public static let erInternal = RuuviLocalization.tr("Localizable", "UserApiError.ER_INTERNAL", fallback: "Internal error") + /// Invalid density mode + public static let erInvalidDensityMode = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_DENSITY_MODE", fallback: "Invalid density mode") + /// Invalid email address + public static let erInvalidEmailAddress = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_EMAIL_ADDRESS", fallback: "Invalid email address") + /// Invalid ENUM value given + public static let erInvalidEnumValue = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_ENUM_VALUE", fallback: "Invalid ENUM value given") + /// Invalid request format + public static let erInvalidFormat = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_FORMAT", fallback: "Invalid request format") + /// Invalid MAC-address + public static let erInvalidMacAddress = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_MAC_ADDRESS", fallback: "Invalid MAC-address") + /// Invalid sort mode + public static let erInvalidSortMode = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_SORT_MODE", fallback: "Invalid sort mode") + /// Invalid time range + public static let erInvalidTimeRange = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_TIME_RANGE", fallback: "Invalid time range") + /// Missing argument + public static let erMissingArgument = RuuviLocalization.tr("Localizable", "UserApiError.ER_MISSING_ARGUMENT", fallback: "Missing argument") + /// In order to share a sensor, it must have data + public static let erNoDataToShare = RuuviLocalization.tr("Localizable", "UserApiError.ER_NO_DATA_TO_SHARE", fallback: "In order to share a sensor, it must have data") + /// Newer data already exists, cannot update + public static let erOldEntry = RuuviLocalization.tr("Localizable", "UserApiError.ER_OLD_ENTRY", fallback: "Newer data already exists, cannot update") + /// Sensor already claimed by %@ + public static func erSensorAlreadyClaimed(_ p1: Any) -> String { + RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_CLAIMED", String(describing: p1), fallback: "Sensor already claimed by %@") + } + /// Sensor already claimed + public static let erSensorAlreadyClaimedNoEmail = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_CLAIMED_NO_EMAIL", fallback: "Sensor already claimed") + /// The sensor has already been registered + public static let erSensorAlreadyRegistered = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_REGISTERED", fallback: "The sensor has already been registered") + /// This sensor is already shared + public static let erSensorAlreadyShared = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_SHARED", fallback: "This sensor is already shared") + /// Sensor not found + public static let erSensorNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_NOT_FOUND", fallback: "Sensor not found") + /// Maximum share count for the sensor reached + public static let erSensorShareCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_SHARE_COUNT_REACHED", fallback: "Maximum share count for the sensor reached") + /// The share limit is reached + public static let erShareCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_SHARE_COUNT_REACHED", fallback: "The share limit is reached") + /// Data storage error + public static let erSubDataStorageError = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUB_DATA_STORAGE_ERROR", fallback: "Data storage error") + /// No user + public static let erSubNoUser = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUB_NO_USER", fallback: "No user") + /// Tried to add duplicate subscription to a code + public static let erSubscriptionCodeExists = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_CODE_EXISTS", fallback: "Tried to add duplicate subscription to a code") + /// Tried to claim already used code + public static let erSubscriptionCodeUsed = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_CODE_USED", fallback: "Tried to claim already used code") + /// Subscription is not found + public static let erSubscriptionNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_NOT_FOUND", fallback: "Subscription is not found") + /// Too many requests + public static let erThrottled = RuuviLocalization.tr("Localizable", "UserApiError.ER_THROTTLED", fallback: "Too many requests") + /// Token is expired + public static let erTokenExpired = RuuviLocalization.tr("Localizable", "UserApiError.ER_TOKEN_EXPIRED", fallback: "Token is expired") + /// Unable to send email + public static let erUnableToSendEmail = RuuviLocalization.tr("Localizable", "UserApiError.ER_UNABLE_TO_SEND_EMAIL", fallback: "Unable to send email") + /// Unauthorised + public static let erUnauthorized = RuuviLocalization.tr("Localizable", "UserApiError.ER_UNAUTHORIZED", fallback: "Unauthorised") + /// User not found + public static let erUserNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_USER_NOT_FOUND", fallback: "User not found") + /// Operation was successful + public static let ok = RuuviLocalization.tr("Localizable", "UserApiError.OK", fallback: "Operation was successful") } - public enum WebTagLocationSource { - /// Your location - public static let current = RuuviLocalization.tr("Localizable", "WebTagLocationSource.current", fallback: "Your location") - /// Pick from the map - public static let manual = RuuviLocalization.tr("Localizable", "WebTagLocationSource.manual", fallback: "Pick from the map") + /// Your location + public static let current = RuuviLocalization.tr("Localizable", "WebTagLocationSource.current", fallback: "Your location") + /// Pick from the map + public static let manual = RuuviLocalization.tr("Localizable", "WebTagLocationSource.manual", fallback: "Pick from the map") } - public enum WebTagSettings { - public enum AirHumidityAlert { - /// Air Humidity - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.AirHumidityAlert.title", fallback: "Air Humidity") + public enum AirHumidityAlert { + /// Air Humidity + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.AirHumidityAlert.title", fallback: "Air Humidity") + } + public enum Alerts { + /// Off + public static let off = RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Off", fallback: "Off") + public enum DewPoint { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.DewPoint.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } } - - public enum Alerts { - /// Off - public static let off = RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Off", fallback: "Off") - public enum DewPoint { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.DewPoint.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - - public enum Humidity { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Humidity.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - - public enum Pressure { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Pressure.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - - public enum Temperature { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Temperature.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } + public enum Humidity { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Humidity.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } } - - public enum AlertsAreDisabled { - public enum Dialog { - public enum BothNoPNPermissionAndNoLocationPermission { - /// In order to enable virtual sensor alerts please always grant location and notification permissions in Settings. - public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.AlertsAreDisabled.Dialog.BothNoPNPermissionAndNoLocationPermission.message", fallback: "In order to enable virtual sensor alerts please always grant location and notification permissions in Settings.") - } - - public enum Settings { - /// Settings - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.AlertsAreDisabled.Dialog.Settings.title", fallback: "Settings") - } - } + public enum Pressure { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Pressure.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } } - - public enum Button { - public enum Remove { - /// REMOVE THIS VIRTUAL SENSOR - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.Button.Remove.title", fallback: "REMOVE THIS VIRTUAL SENSOR") - } + public enum Temperature { + /// Alert when less than %.0f or more than %.0f + public static func description(_ p1: Float, _ p2: Float) -> String { + RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Temperature.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") + } } - - public enum Label { - public enum BackgroundImage { - /// BACKGROUND - /// IMAGE - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.BackgroundImage.text", fallback: "BACKGROUND\nIMAGE") - } - - public enum Location { - /// Location - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.Location.text", fallback: "Location") - } - - public enum TagName { - /// Sensor Name - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.TagName.text", fallback: "Sensor Name") - } - - public enum Alerts { - /// ALERTS - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.alerts.text", fallback: "ALERTS") - } - - public enum Disabled { - /// DISABLED? - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.disabled.text", fallback: "DISABLED?") - } + } + public enum AlertsAreDisabled { + public enum Dialog { + public enum BothNoPNPermissionAndNoLocationPermission { + /// In order to enable virtual sensor alerts please always grant location and notification permissions in Settings. + public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.AlertsAreDisabled.Dialog.BothNoPNPermissionAndNoLocationPermission.message", fallback: "In order to enable virtual sensor alerts please always grant location and notification permissions in Settings.") + } + public enum Settings { + /// Settings + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.AlertsAreDisabled.Dialog.Settings.title", fallback: "Settings") + } + } + } + public enum Button { + public enum Remove { + /// REMOVE THIS VIRTUAL SENSOR + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.Button.Remove.title", fallback: "REMOVE THIS VIRTUAL SENSOR") + } + } + public enum Label { + public enum BackgroundImage { + /// BACKGROUND + /// IMAGE + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.BackgroundImage.text", fallback: "BACKGROUND\nIMAGE") } - public enum Location { - /// Your location - public static let current = RuuviLocalization.tr("Localizable", "WebTagSettings.Location.Current", fallback: "Your location") - } - - public enum PressureAlert { - /// Air Pressure - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.PressureAlert.title", fallback: "Air Pressure") - } - - public enum SectionHeader { - public enum MoreInfo { - /// MORE INFO - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.SectionHeader.MoreInfo.title", fallback: "MORE INFO") - } - - public enum Name { - /// NAME - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.SectionHeader.Name.title", fallback: "NAME") - } - } - - public enum ConfirmClearLocationDialog { - /// Are you sure you want to clear location for this virtual sensor? Current location will be used instead. - public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmClearLocationDialog.message", fallback: "Are you sure you want to clear location for this virtual sensor? Current location will be used instead.") - /// Clear Location - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmClearLocationDialog.title", fallback: "Clear Location") - } - - public enum ConfirmTagRemovalDialog { - /// Are you sure you want to remove this virtual sensor? - public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmTagRemovalDialog.message", fallback: "Are you sure you want to remove this virtual sensor?") - /// Remove virtual sensor - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmTagRemovalDialog.title", fallback: "Remove virtual sensor") + /// Location + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.Location.text", fallback: "Location") } - - public enum DewPointAlertTitleLabel { - /// Dew Point - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.dewPointAlertTitleLabel.text", fallback: "Dew Point") + public enum TagName { + /// Sensor Name + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.TagName.text", fallback: "Sensor Name") } - - public enum NavigationItem { - /// Virtual Sensor Settings - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.navigationItem.title", fallback: "Virtual Sensor Settings") + public enum Alerts { + /// ALERTS + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.alerts.text", fallback: "ALERTS") } - - public enum TemperatureAlertTitleLabel { - /// Temperature - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.temperatureAlertTitleLabel.text", fallback: "Temperature") + public enum Disabled { + /// DISABLED? + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.disabled.text", fallback: "DISABLED?") } + } + public enum Location { + /// Your location + public static let current = RuuviLocalization.tr("Localizable", "WebTagSettings.Location.Current", fallback: "Your location") + } + public enum PressureAlert { + /// Air Pressure + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.PressureAlert.title", fallback: "Air Pressure") + } + public enum SectionHeader { + public enum MoreInfo { + /// MORE INFO + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.SectionHeader.MoreInfo.title", fallback: "MORE INFO") + } + public enum Name { + /// NAME + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.SectionHeader.Name.title", fallback: "NAME") + } + } + public enum ConfirmClearLocationDialog { + /// Are you sure you want to clear location for this virtual sensor? Current location will be used instead. + public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmClearLocationDialog.message", fallback: "Are you sure you want to clear location for this virtual sensor? Current location will be used instead.") + /// Clear Location + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmClearLocationDialog.title", fallback: "Clear Location") + } + public enum ConfirmTagRemovalDialog { + /// Are you sure you want to remove this virtual sensor? + public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmTagRemovalDialog.message", fallback: "Are you sure you want to remove this virtual sensor?") + /// Remove virtual sensor + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmTagRemovalDialog.title", fallback: "Remove virtual sensor") + } + public enum DewPointAlertTitleLabel { + /// Dew Point + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.dewPointAlertTitleLabel.text", fallback: "Dew Point") + } + public enum NavigationItem { + /// Virtual Sensor Settings + public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.navigationItem.title", fallback: "Virtual Sensor Settings") + } + public enum TemperatureAlertTitleLabel { + /// Temperature + public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.temperatureAlertTitleLabel.text", fallback: "Temperature") + } } - public enum Welcome { - public enum Description { - /// To find nearby sensors and receive live sensor data, press 'scan'. - public static let text = RuuviLocalization.tr("Localizable", "Welcome.description.text", fallback: "To find nearby sensors and receive live sensor data, press 'scan'.") - } - - public enum Scan { - /// SCAN - public static let title = RuuviLocalization.tr("Localizable", "Welcome.scan.title", fallback: "SCAN") - } + public enum Description { + /// To find nearby sensors and receive live sensor data, press 'scan'. + public static let text = RuuviLocalization.tr("Localizable", "Welcome.description.text", fallback: "To find nearby sensors and receive live sensor data, press 'scan'.") + } + public enum Scan { + /// SCAN + public static let title = RuuviLocalization.tr("Localizable", "Welcome.scan.title", fallback: "SCAN") + } } - public enum Widgets { - public enum Description { - /// Create widgets of your favourite Ruuvi sensors. Widgets update from the Ruuvi Cloud. A Ruuvi Gateway router is required. - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Description.message", fallback: "Create widgets of your favourite Ruuvi sensors. Widgets update from the Ruuvi Cloud. A Ruuvi Gateway router is required.") + public enum Description { + /// Create widgets of your favourite Ruuvi sensors. Widgets update from the Ruuvi Cloud. A Ruuvi Gateway router is required. + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Description.message", fallback: "Create widgets of your favourite Ruuvi sensors. Widgets update from the Ruuvi Cloud. A Ruuvi Gateway router is required.") + } + public enum Loading { + /// loading... + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Loading.message", fallback: "loading...") + } + public enum Select { + public enum Sensor { + /// Selected Ruuvi sensor + public static let title = RuuviLocalization.tr("Localizable", "Widgets.Select.Sensor.title", fallback: "Selected Ruuvi sensor") } - - public enum Loading { - /// loading... - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Loading.message", fallback: "loading...") + } + public enum Sensor { + public enum `Type` { + /// Selected sensor type + public static let title = RuuviLocalization.tr("Localizable", "Widgets.Sensor.Type.title", fallback: "Selected sensor type") } - - public enum Select { - public enum Sensor { - /// Selected Ruuvi sensor - public static let title = RuuviLocalization.tr("Localizable", "Widgets.Select.Sensor.title", fallback: "Selected Ruuvi sensor") - } + } + public enum Unauthorized { + public enum Inline { + /// Sign in to Ruuvi Station + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unauthorized.Inline.message", fallback: "Sign in to Ruuvi Station") } - - public enum Sensor { - public enum `Type` { - /// Selected sensor type - public static let title = RuuviLocalization.tr("Localizable", "Widgets.Sensor.Type.title", fallback: "Selected sensor type") - } + public enum Regular { + /// Sign in to use the widget. + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unauthorized.Regular.message", fallback: "Sign in to use the widget.") } - - public enum Unauthorized { - public enum Inline { - /// Sign in to Ruuvi Station - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unauthorized.Inline.message", fallback: "Sign in to Ruuvi Station") - } - - public enum Regular { - /// Sign in to use the widget. - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unauthorized.Regular.message", fallback: "Sign in to use the widget.") - } + } + public enum Unconfigured { + public enum Circular { + /// +Add + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Circular.message", fallback: "+Add") } - - public enum Unconfigured { - public enum Circular { - /// +Add - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Circular.message", fallback: "+Add") - } - - public enum Inline { - /// Add sensor to use Ruuvi Widget - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Inline.message", fallback: "Add sensor to use Ruuvi Widget") - } - - public enum Rectangular { - /// Add sensor to use Ruuvi Widget - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Rectangular.message", fallback: "Add sensor to use Ruuvi Widget") - } - - public enum Simple { - /// Force tap to edit the widget. - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Simple.message", fallback: "Force tap to edit the widget.") - } + public enum Inline { + /// Add sensor to use Ruuvi Widget + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Inline.message", fallback: "Add sensor to use Ruuvi Widget") } + public enum Rectangular { + /// Add sensor to use Ruuvi Widget + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Rectangular.message", fallback: "Add sensor to use Ruuvi Widget") + } + public enum Simple { + /// Force tap to edit the widget. + public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Simple.message", fallback: "Force tap to edit the widget.") + } + } } } - // swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length // swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces @@ -3030,12 +2649,11 @@ extension RuuviLocalization { private final class BundleToken { static let bundle: Bundle = { #if SWIFT_PACKAGE - return Bundle.module + return Bundle.module #else - return Bundle(for: BundleToken.self) + return Bundle(for: BundleToken.self) #endif }() } - // swiftlint:enable convenience_type // swiftlint:enable all diff --git a/Common/RuuviLocalization/target.yml b/Common/RuuviLocalization/target.yml index 4ca8e70b3..0dab3ce6f 100644 --- a/Common/RuuviLocalization/target.yml +++ b/Common/RuuviLocalization/target.yml @@ -3,3 +3,6 @@ targets: RuuviLocalization: templates: - CommonFramework + sources: + - path: Sources + name: Localization diff --git a/Common/RuuviPresenters/target.yml b/Common/RuuviPresenters/target.yml index c4afef536..ab973ecd8 100644 --- a/Common/RuuviPresenters/target.yml +++ b/Common/RuuviPresenters/target.yml @@ -3,3 +3,6 @@ targets: RuuviPresenters: templates: - CommonFramework + sources: + - path: Sources + name: Presenters diff --git a/Modules/RuuviDiscover/target.yml b/Modules/RuuviDiscover/target.yml index 70b917c73..8d63f051f 100644 --- a/Modules/RuuviDiscover/target.yml +++ b/Modules/RuuviDiscover/target.yml @@ -3,6 +3,9 @@ targets: RuuviDiscover: templates: - Module + sources: + - path: Sources + name: Discover dependencies: - package: BTKit - package: Future diff --git a/Modules/RuuviFirmware/target.yml b/Modules/RuuviFirmware/target.yml index 5ef05adf0..58c77d97e 100644 --- a/Modules/RuuviFirmware/target.yml +++ b/Modules/RuuviFirmware/target.yml @@ -1,6 +1,9 @@ --- targets: RuuviFirmware: + sources: + - path: Sources + name: Firmware settings: base: MERGEABLE_LIBRARY: false diff --git a/Modules/RuuviOnboard/target.yml b/Modules/RuuviOnboard/target.yml index c5f993e98..498b7e522 100644 --- a/Modules/RuuviOnboard/target.yml +++ b/Modules/RuuviOnboard/target.yml @@ -1,6 +1,9 @@ --- targets: RuuviOnboard: + sources: + - path: Sources + name: Onboard templates: - Module dependencies: diff --git a/Packages/RuuviAnalytics/target.yml b/Packages/RuuviAnalytics/target.yml index 43153def0..c10b1294f 100644 --- a/Packages/RuuviAnalytics/target.yml +++ b/Packages/RuuviAnalytics/target.yml @@ -4,6 +4,9 @@ targets: name: RuuviAnalytics templates: - Framework + sources: + - path: Sources + name: Analytics dependencies: - package: Humidity - package: Future diff --git a/Packages/RuuviCloud/target.yml b/Packages/RuuviCloud/target.yml index 6222401c9..0e5614b89 100644 --- a/Packages/RuuviCloud/target.yml +++ b/Packages/RuuviCloud/target.yml @@ -3,6 +3,9 @@ targets: RuuviCloud: templates: - Framework + sources: + - path: Sources + name: Cloud dependencies: - package: Humidity - package: BTKit diff --git a/Packages/RuuviContext/target.yml b/Packages/RuuviContext/target.yml index ecb1f1d4a..aa7d0c8fa 100644 --- a/Packages/RuuviContext/target.yml +++ b/Packages/RuuviContext/target.yml @@ -7,6 +7,9 @@ targets: MERGEABLE_LIBRARY: false templates: - Framework + sources: + - path: Sources + name: Context dependencies: - package: Realm - package: Realm diff --git a/Packages/RuuviCore/target.yml b/Packages/RuuviCore/target.yml index d8c385aea..cb24ba24e 100644 --- a/Packages/RuuviCore/target.yml +++ b/Packages/RuuviCore/target.yml @@ -3,5 +3,8 @@ targets: RuuviCore: templates: - Framework + sources: + - path: Sources + name: Core dependencies: - package: Future diff --git a/Packages/RuuviDFU/target.yml b/Packages/RuuviDFU/target.yml index 6398a54b6..20cd7d52d 100644 --- a/Packages/RuuviDFU/target.yml +++ b/Packages/RuuviDFU/target.yml @@ -3,5 +3,8 @@ targets: RuuviDFU: templates: - Framework + sources: + - path: Sources + name: DFU dependencies: - package: NordicDFU diff --git a/Packages/RuuviDaemon/target.yml b/Packages/RuuviDaemon/target.yml index 57e3fcd05..2a7ade556 100644 --- a/Packages/RuuviDaemon/target.yml +++ b/Packages/RuuviDaemon/target.yml @@ -3,6 +3,9 @@ targets: RuuviDaemon: templates: - Framework + sources: + - path: Sources + name: Daemon dependencies: - package: BTKit - package: Future diff --git a/Packages/RuuviLocal/target.yml b/Packages/RuuviLocal/target.yml index e6b4115be..dec929954 100644 --- a/Packages/RuuviLocal/target.yml +++ b/Packages/RuuviLocal/target.yml @@ -3,6 +3,9 @@ targets: RuuviLocal: templates: - Framework + sources: + - path: Sources + name: Local dependencies: - package: Future - target: RuuviOntology diff --git a/Packages/RuuviMigration/target.yml b/Packages/RuuviMigration/target.yml index 232783118..b41702b76 100644 --- a/Packages/RuuviMigration/target.yml +++ b/Packages/RuuviMigration/target.yml @@ -3,6 +3,9 @@ targets: RuuviMigration: templates: - Framework + sources: + - path: Sources + name: Migration dependencies: - package: Humidity - package: Future diff --git a/Packages/RuuviNotification/target.yml b/Packages/RuuviNotification/target.yml index c16aefe28..f8530b012 100644 --- a/Packages/RuuviNotification/target.yml +++ b/Packages/RuuviNotification/target.yml @@ -3,6 +3,9 @@ targets: RuuviNotification: templates: - Framework + sources: + - path: Sources + name: Notification dependencies: - package: Future - package: Humidity diff --git a/Packages/RuuviNotifier/target.yml b/Packages/RuuviNotifier/target.yml index be981bd4d..5035c111a 100644 --- a/Packages/RuuviNotifier/target.yml +++ b/Packages/RuuviNotifier/target.yml @@ -3,6 +3,9 @@ targets: RuuviNotifier: templates: - Framework + sources: + - path: Sources + name: Notifier dependencies: - package: Humidity - target: RuuviOntology diff --git a/Packages/RuuviOntology/target.yml b/Packages/RuuviOntology/target.yml index c080d36b3..52fc3e669 100644 --- a/Packages/RuuviOntology/target.yml +++ b/Packages/RuuviOntology/target.yml @@ -7,6 +7,9 @@ targets: MERGEABLE_LIBRARY: false templates: - Framework + sources: + - path: Sources + name: Ontology dependencies: - package: Humidity - package: BTKit diff --git a/Packages/RuuviPersistence/target.yml b/Packages/RuuviPersistence/target.yml index 19cff3adc..12a583477 100644 --- a/Packages/RuuviPersistence/target.yml +++ b/Packages/RuuviPersistence/target.yml @@ -7,6 +7,9 @@ targets: MERGEABLE_LIBRARY: false templates: - Framework + sources: + - path: Sources + name: Persistence dependencies: - package: Humidity - package: Future diff --git a/Packages/RuuviPool/target.yml b/Packages/RuuviPool/target.yml index 7c4cac248..e1275fbff 100644 --- a/Packages/RuuviPool/target.yml +++ b/Packages/RuuviPool/target.yml @@ -3,6 +3,9 @@ targets: RuuviPool: templates: - Framework + sources: + - path: Sources + name: Pool dependencies: - package: Future - target: RuuviOntology diff --git a/Packages/RuuviReactor/target.yml b/Packages/RuuviReactor/target.yml index a30ebde46..409ac880d 100644 --- a/Packages/RuuviReactor/target.yml +++ b/Packages/RuuviReactor/target.yml @@ -7,6 +7,9 @@ targets: MERGEABLE_LIBRARY: false templates: - Framework + sources: + - path: Sources + name: Reactor dependencies: - package: Humidity - package: Future diff --git a/Packages/RuuviRepository/target.yml b/Packages/RuuviRepository/target.yml index 748bef85e..009aa9741 100644 --- a/Packages/RuuviRepository/target.yml +++ b/Packages/RuuviRepository/target.yml @@ -3,6 +3,9 @@ targets: RuuviRepository: templates: - Framework + sources: + - path: Sources + name: Repository dependencies: - package: Future - target: RuuviOntology diff --git a/Packages/RuuviService/target.yml b/Packages/RuuviService/target.yml index 115a14c07..afd71611d 100644 --- a/Packages/RuuviService/target.yml +++ b/Packages/RuuviService/target.yml @@ -3,6 +3,9 @@ targets: RuuviService: templates: - Framework + sources: + - path: Sources + name: Service dependencies: - package: Future - package: Humidity diff --git a/Packages/RuuviStorage/target.yml b/Packages/RuuviStorage/target.yml index c071f6683..e39b450bb 100644 --- a/Packages/RuuviStorage/target.yml +++ b/Packages/RuuviStorage/target.yml @@ -3,6 +3,9 @@ targets: RuuviStorage: templates: - Framework + sources: + - path: Sources + name: Storage dependencies: - package: Future - target: RuuviOntology diff --git a/Packages/RuuviUser/target.yml b/Packages/RuuviUser/target.yml index bec36bf60..bb1df5782 100644 --- a/Packages/RuuviUser/target.yml +++ b/Packages/RuuviUser/target.yml @@ -3,5 +3,8 @@ targets: RuuviUser: templates: - Framework + sources: + - path: Sources + name: User dependencies: - package: KeychainAccess diff --git a/README.md b/README.md index fe51a3401..b29cd7282 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # Ruuvi Station [![Swift Version][swift-image]][swift-url] -[![Build Status](https://travis-ci.org/ruuvi/com.ruuvi.station.ios.svg?branch=master)](https://travis-ci.org/ruuvi/com.ruuvi.station.ios) [![License][license-image]][license-url] [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) @@ -65,10 +64,8 @@ xed Ruuvi.xcodeproj

Optionally - -1. Obtain [OpenWeatherMap](https://openweathermap.org) API Key and put it into ```/station/Classes/Networking/Assembly/Networking.plist``` -2. Setup your [Firebase](https://firebase.google.com) project and replace ```station/Resources/Plists/GoogleService-Info.plist``` +Setup your [Firebase](https://firebase.google.com) project and replace ```station/Resources/Plists/GoogleService-Info.plist```
diff --git a/project.yml b/project.yml index 61c286b08..f40535fbd 100644 --- a/project.yml +++ b/project.yml @@ -1,6 +1,6 @@ BUILD_NUMBER: &BUILD_NUMBER 1 APP_VERSION: &APP_VERSION 2.5.2 -APP_NAME: &APP_NAME Ruuvi +PROJECT_NAME: &PROJECT_NAME Ruuvi DEVELOPMENT_TEAM: &DEVELOPMENT_TEAM 4MUYJ4YYH4 BUNDLE_ID_PREFIX: &BUNDLE_ID_PREFIX com.ruuvi @@ -13,7 +13,7 @@ settings: MARKETING_VERSION: *APP_VERSION DEVELOPMENT_TEAM: *DEVELOPMENT_TEAM -name: *APP_NAME +name: *PROJECT_NAME options: bundleIdPrefix: *BUNDLE_ID_PREFIX @@ -30,20 +30,6 @@ targetTemplates: path: Packages/${target_name}/Info.plist properties: CFBundleShortVersionString: "$(MARKETING_VERSION)" - sources: - - path: Packages/${target_name} - excludes: - - "*.stencil" - - target.yml - - Info.plist - - .swiftpm - - Package.swift - - Package.resolved - - .gitignore - - README.md - - "*.podspec" - - Tests - - Templates settings: base: DEVELOPMENT_TEAM: *DEVELOPMENT_TEAM @@ -66,20 +52,6 @@ targetTemplates: path: Modules/${target_name}/Info.plist properties: CFBundleShortVersionString: "$(MARKETING_VERSION)" - sources: - - path: Modules/${target_name} - excludes: - - "*.stencil" - - target.yml - - Info.plist - - .swiftpm - - Package.swift - - Package.resolved - - .gitignore - - README.md - - "*.podspec" - - Tests - - Templates settings: base: DEVELOPMENT_TEAM: *DEVELOPMENT_TEAM @@ -102,20 +74,6 @@ targetTemplates: path: Common/${target_name}/Info.plist properties: CFBundleShortVersionString: "$(MARKETING_VERSION)" - sources: - - path: Common/${target_name} - excludes: - - "*.stencil" - - target.yml - - Info.plist - - .swiftpm - - Package.swift - - Package.resolved - - .gitignore - - README.md - - "*.podspec" - - Tests - - Templates settings: base: DEVELOPMENT_TEAM: *DEVELOPMENT_TEAM @@ -199,143 +157,12 @@ include: - Modules/RuuviDiscover/target.yml - Modules/RuuviOnboard/target.yml - Modules/RuuviFirmware/target.yml -- widget.yml -- pnservice.yml -- intents.yml +- Apps/RuuviStation/target.yml +- Apps/RuuviStation/Widgets/target.yml +- Apps/RuuviStation/NotificationService/target.yml +- Apps/RuuviStation/Intents/target.yml configs: Alpha: debug Debug: debug - Release: release - -targets: - station: - type: application - platform: iOS - sources: - - path: station - - path: ruuvi_widgets.entitlements - - path: station_intents.entitlements - - path: pnservice.entitlements - dependencies: - - target: "station.widgets" - - target: "station.intents" - - target: "station.pnservice" - - package: BTKit - - package: Charts - - package: GRDB - - package: LightRoute - - package: Swinject - - package: RangeSeekSlider - - package: NordicDFU - - package: GestureInstructions - - package: Firebase - product: FirebaseMessaging - - package: Firebase - product: FirebaseRemoteConfig - - package: KeychainAccess - - package: Humidity - - package: Future - - package: Realm - - package: Realm - product: RealmSwift - - package: FLEX - - target: RuuviAnalytics - - target: RuuviCloud - - target: RuuviContext - - target: RuuviCore - - target: RuuviDaemon - - target: RuuviDFU - - target: RuuviLocal - - target: RuuviMigration - - target: RuuviNotification - - target: RuuviNotifier - - target: RuuviOntology - - target: RuuviPersistence - - target: RuuviPool - - target: RuuviReactor - - target: RuuviRepository - - target: RuuviService - - target: RuuviStorage - - target: RuuviUser - - target: RuuviPresenters - - target: RuuviDiscover - - target: RuuviOnboard - - target: RuuviFirmware - - target: RuuviLocalization - info: - path: station/Resources/Plists/Info.plist - properties: - CFBundleDisplayName: Ruuvi Station - CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString: "$(MARKETING_VERSION)" - CFBundleVersion: $(CURRENT_PROJECT_VERSION) - UISupportedInterfaceOrientations: [UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight, UIInterfaceOrientationPortrait] - UILaunchStoryboardName: LaunchScreen - BGTaskSchedulerPermittedIdentifiers: [com.ruuvi.station.BackgroundProcessServiceiOS13.dataPruning] - FirebaseMessagingAutoInitEnabled: false - LSApplicationQueriesSchemes: [https, http, mailto] - LSRequiresIPhoneOS: true - NFCReaderUsageDescription: Allows user to claim a RuuviTag using NFC when the user has physical access to the sensor - NSBluetoothAlwaysUsageDescription: The app uses Bluetooth LE to read data from Ruuvi Sensors - NSBluetoothPeripheralUsageDescription: The app uses Bluetooth LE to read data from RuuviTag sensors. - NSCameraUsageDescription: Ruuvi Station needs to access your camera in order to be able to capture photos and use them as sensor background. - NSLocationAlwaysAndWhenInUseUsageDescription: Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. - NSLocationAlwaysUsageDescription: Ruuvi Station needs to access your location while being in background in order to pull data for Virtual Sensors for your current location and display alerts. - NSLocationUsageDescription: Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. - NSLocationWhenInUseUsageDescription: Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. - NSPhotoLibraryUsageDescription: Ruuvi Station needs to access your camera roll to enable selecting the background for the sensor. - NSUserActivityTypes: [RuuviTagSelectionIntent] - UIAppFonts: [Oswald-Bold.ttf,Oswald-ExtraLight.ttf,Muli-Regular.ttf,Muli-Bold.ttf,Muli-SemiBoldItalic.ttf,Muli-ExtraBold.ttf,Montserrat-Bold.ttf,Montserrat-Regular.ttf,Montserrat-ExtraBold.ttf] - UIBackgroundModes: [bluetooth-central, processing, remote-notification] - UIRequiredDeviceCapabilities: [armv7] - UIRequiresFullScreen: true - UIStatusBarStyle: UIStatusBarStyleLightContent - UISupportedInterfaceOrientations~ipad: [UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight,UIInterfaceOrientationPortrait, UIInterfaceOrientationPortraitUpsideDown] - UIViewControllerBasedStatusBarAppearance: true - settings: - base: - MERGED_BINARY_TYPE: "manual" - TARGETED_DEVICE_FAMILY: 1,2 - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD: true - CODE_SIGN_ENTITLEMENTS: station/station.entitlements - configs: - Alpha: - CODE_SIGN_IDENTITY: "iPhone Distribution" - PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station" - Debug: - CODE_SIGN_STYLE: Automatic - OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries - Release: - EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" - CODE_SIGN_IDENTITY: "iPhone Distribution" - PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station" - preBuildScripts: - - path: scripts/build/generate_l10n.sh - name: Generate L10N - inputFiles: - - $(SRCROOT)/station.localization/station.localization.json - outputFiles: - - $(SRCROOT)/station/Resources/Strings/en.lproj/Localizable.strings - - $(SRCROOT)/station/Resources/Strings/sv.lproj/Localizable.strings - - $(SRCROOT)/station/Resources/Strings/ru.lproj/Localizable.strings - - $(SRCROOT)/station/Resources/Strings/fi.lproj/Localizable.strings - - $(SRCROOT)/station/Resources/Strings/fr.lproj/Localizable.strings - - $(SRCROOT)/station/Resources/Strings/de.lproj/Localizable.strings - postCompileScripts: - - path: scripts/build/lint.sh - name: Lint - basedOnDependencyAnalysis: false - postBuildScripts: - - path: scripts/build/load_keystore.sh - name: Load Keystore - inputFiles: - - $(SRCROOT)/station/Classes/Networking/Assembly/Networking.plist - - $(SRCROOT)/station/Resources/Plists/GoogleService-Info.plist - runOnlyWhenInstalling: true - basedOnDependencyAnalysis: false -schemes: - station: - build: - targets: - station: all \ No newline at end of file + Release: release \ No newline at end of file diff --git a/station/Resources/Plists/DevInfo.plist b/station/Resources/Plists/DevInfo.plist deleted file mode 100644 index 727293828..000000000 --- a/station/Resources/Plists/DevInfo.plist +++ /dev/null @@ -1,97 +0,0 @@ - - - - - BGTaskSchedulerPermittedIdentifiers - - com.ruuvi.station.BackgroundProcessServiceiOS13.dataPruning - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Ruuvi Station - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 421 - FirebaseMessagingAutoInitEnabled - - LSRequiresIPhoneOS - - NFCReaderUsageDescription - Allows user to claim a RuuviTag using NFC when the user has physical access to the sensor - NSBluetoothAlwaysUsageDescription - The app uses Bluetooth LE to read data from RuuviTag sensors. - NSBluetoothPeripheralUsageDescription - The app uses Bluetooth LE to read data from RuuviTag sensors. - NSCameraUsageDescription - Ruuvi Station needs to access your camera in order to be able to capture photos and use them as tag background. - NSLocationAlwaysAndWhenInUseUsageDescription - Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. - NSLocationAlwaysUsageDescription - Ruuvi Station needs to access your location while being in background in order to pull data for Virtual Sensors for your current location and display alerts. - NSLocationUsageDescription - Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. - NSLocationWhenInUseUsageDescription - Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. - NSPhotoLibraryUsageDescription - Ruuvi Station needs to access your camera roll to enable selecting the background for the tag. - NSUserActivityTypes - - RuuviTagSelectionIntent - - UIAppFonts - - Oswald-Bold.ttf - Oswald-ExtraLight.ttf - Muli-Regular.ttf - Muli-Bold.ttf - Muli-SemiBoldItalic.ttf - Muli-ExtraBold.ttf - Montserrat-Bold.ttf - Montserrat-Regular.ttf - Montserrat-ExtraBold.ttf - - UIBackgroundModes - - bluetooth-central - processing - remote-notification - - UILaunchStoryboardName - LaunchScreen - UIRequiredDeviceCapabilities - - armv7 - - UIRequiresFullScreen - - UIStatusBarStyle - UIStatusBarStyleLightContent - UISupportedInterfaceOrientations - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - UIInterfaceOrientationPortrait - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/stationUITests/Info.plist b/stationUITests/Info.plist deleted file mode 100644 index 6c40a6cd0..000000000 --- a/stationUITests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/stationUITests/StationUITests.swift b/stationUITests/StationUITests.swift deleted file mode 100644 index 5734f1de0..000000000 --- a/stationUITests/StationUITests.swift +++ /dev/null @@ -1,9 +0,0 @@ -import XCTest - -class StationUITests: XCTestCase { - override func setUp() { - super.setUp() - continueAfterFailure = false - XCUIApplication().launch() - } -} From c146f8b9059bb4f631126d63465507f98f479de4 Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Wed, 13 Dec 2023 17:51:26 +0100 Subject: [PATCH 43/84] fix: Incorrect icon for failed events on sensor settings #1600 (#1774) --- .../Modules/TagSettings/Presenter/TagSettingsPresenter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift index b3bb33f7c..aed1174be 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift @@ -1813,7 +1813,7 @@ extension TagSettingsPresenter { ) case .failed: activityPresenter.update( - with: .success( + with: .failed( message: RuuviLocalization.activitySavingFail ) ) From 58128dc150164d4b0350553ac77ffd503c9f56b4 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Wed, 13 Dec 2023 19:10:04 +0200 Subject: [PATCH 44/84] Fix Intents (#1775) Fixes intents, as RuuviLocalization framework must be explicitly used. --- Apps/RuuviStation/Intents/target.yml | 4 + .../AccentColor.colorset/Contents.json | 11 -- .../AppIcon.appiconset/Contents.json | 98 ------------------ .../BackgroundColor.colorset/Contents.json | 0 .../BodyTextColor.colorset/Contents.json | 0 .../Assets.xcassets/Colors/Contents.json | 0 .../Colors/LogoColor.colorset/Contents.json | 0 .../SensorNameColor1.colorset/Contents.json | 0 .../SensorNameColor2.colorset/Contents.json | 0 .../UnitTextColor.colorset/Contents.json | 0 .../Assets.xcassets/Contents.json | 0 .../eye_circle.imageset/Contents.json | 0 .../web-ruuvi-eye-nega.png | Bin .../ruuvi_logo.imageset/Contents.json | 0 .../ruuvi_logo.imageset/ruuvi_logo.png | Bin Apps/RuuviStation/Widgets/target.yml | 1 + 16 files changed, 5 insertions(+), 109 deletions(-) delete mode 100644 Apps/RuuviStation/Widgets/Sources/Assets.xcassets/AccentColor.colorset/Contents.json delete mode 100644 Apps/RuuviStation/Widgets/Sources/Assets.xcassets/AppIcon.appiconset/Contents.json rename Apps/RuuviStation/Widgets/Sources/{ => Resources}/Assets.xcassets/Colors/BackgroundColor.colorset/Contents.json (100%) rename Apps/RuuviStation/Widgets/Sources/{ => Resources}/Assets.xcassets/Colors/BodyTextColor.colorset/Contents.json (100%) rename Apps/RuuviStation/Widgets/Sources/{ => Resources}/Assets.xcassets/Colors/Contents.json (100%) rename Apps/RuuviStation/Widgets/Sources/{ => Resources}/Assets.xcassets/Colors/LogoColor.colorset/Contents.json (100%) rename Apps/RuuviStation/Widgets/Sources/{ => Resources}/Assets.xcassets/Colors/SensorNameColor1.colorset/Contents.json (100%) rename Apps/RuuviStation/Widgets/Sources/{ => Resources}/Assets.xcassets/Colors/SensorNameColor2.colorset/Contents.json (100%) rename Apps/RuuviStation/Widgets/Sources/{ => Resources}/Assets.xcassets/Colors/UnitTextColor.colorset/Contents.json (100%) rename Apps/RuuviStation/Widgets/Sources/{ => Resources}/Assets.xcassets/Contents.json (100%) rename Apps/RuuviStation/Widgets/Sources/{ => Resources}/Assets.xcassets/eye_circle.imageset/Contents.json (100%) rename Apps/RuuviStation/Widgets/Sources/{ => Resources}/Assets.xcassets/eye_circle.imageset/web-ruuvi-eye-nega.png (100%) rename Apps/RuuviStation/Widgets/Sources/{ => Resources}/Assets.xcassets/ruuvi_logo.imageset/Contents.json (100%) rename Apps/RuuviStation/Widgets/Sources/{ => Resources}/Assets.xcassets/ruuvi_logo.imageset/ruuvi_logo.png (100%) diff --git a/Apps/RuuviStation/Intents/target.yml b/Apps/RuuviStation/Intents/target.yml index e7fb5fd84..b9118f41b 100644 --- a/Apps/RuuviStation/Intents/target.yml +++ b/Apps/RuuviStation/Intents/target.yml @@ -42,6 +42,8 @@ targets: excludes: - "*.entitlements" - Info.plist + resources: + - path: ../Widgets/Sources/Resources/ dependencies: - package: Swinject - package: BTKit @@ -65,4 +67,6 @@ targets: - target: RuuviPersistence embed: true - target: RuuviContext + embed: true + - target: RuuviLocalization embed: true \ No newline at end of file diff --git a/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/AccentColor.colorset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb8789700..000000000 --- a/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 9221b9bb1..000000000 --- a/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "20x20" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "40x40" - }, - { - "idiom" : "ipad", - "scale" : "1x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "76x76" - }, - { - "idiom" : "ipad", - "scale" : "2x", - "size" : "83.5x83.5" - }, - { - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/BackgroundColor.colorset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/Colors/BackgroundColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/BackgroundColor.colorset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/Colors/BackgroundColor.colorset/Contents.json diff --git a/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/BodyTextColor.colorset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/Colors/BodyTextColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/BodyTextColor.colorset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/Colors/BodyTextColor.colorset/Contents.json diff --git a/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/Contents.json b/Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/Colors/Contents.json similarity index 100% rename from Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/Colors/Contents.json diff --git a/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/LogoColor.colorset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/Colors/LogoColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/LogoColor.colorset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/Colors/LogoColor.colorset/Contents.json diff --git a/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/SensorNameColor1.colorset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/Colors/SensorNameColor1.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/SensorNameColor1.colorset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/Colors/SensorNameColor1.colorset/Contents.json diff --git a/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/SensorNameColor2.colorset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/Colors/SensorNameColor2.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/SensorNameColor2.colorset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/Colors/SensorNameColor2.colorset/Contents.json diff --git a/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/UnitTextColor.colorset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/Colors/UnitTextColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Colors/UnitTextColor.colorset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/Colors/UnitTextColor.colorset/Contents.json diff --git a/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Contents.json b/Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/Contents.json similarity index 100% rename from Apps/RuuviStation/Widgets/Sources/Assets.xcassets/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/Contents.json diff --git a/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/eye_circle.imageset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/eye_circle.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Widgets/Sources/Assets.xcassets/eye_circle.imageset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/eye_circle.imageset/Contents.json diff --git a/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/eye_circle.imageset/web-ruuvi-eye-nega.png b/Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/eye_circle.imageset/web-ruuvi-eye-nega.png similarity index 100% rename from Apps/RuuviStation/Widgets/Sources/Assets.xcassets/eye_circle.imageset/web-ruuvi-eye-nega.png rename to Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/eye_circle.imageset/web-ruuvi-eye-nega.png diff --git a/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/ruuvi_logo.imageset/Contents.json b/Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/ruuvi_logo.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Widgets/Sources/Assets.xcassets/ruuvi_logo.imageset/Contents.json rename to Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/ruuvi_logo.imageset/Contents.json diff --git a/Apps/RuuviStation/Widgets/Sources/Assets.xcassets/ruuvi_logo.imageset/ruuvi_logo.png b/Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/ruuvi_logo.imageset/ruuvi_logo.png similarity index 100% rename from Apps/RuuviStation/Widgets/Sources/Assets.xcassets/ruuvi_logo.imageset/ruuvi_logo.png rename to Apps/RuuviStation/Widgets/Sources/Resources/Assets.xcassets/ruuvi_logo.imageset/ruuvi_logo.png diff --git a/Apps/RuuviStation/Widgets/target.yml b/Apps/RuuviStation/Widgets/target.yml index 28fb675e5..e4a7f3b6a 100644 --- a/Apps/RuuviStation/Widgets/target.yml +++ b/Apps/RuuviStation/Widgets/target.yml @@ -35,6 +35,7 @@ targets: - "*.entitlements" - Info.plist resources: + - path: Sources/Resources/ - path: ../Sources/Resources/Strings/ dependencies: - package: Swinject From dbe8fe02dfd0ccad196818751cc51c4bc88d1934 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Wed, 13 Dec 2023 19:26:43 +0200 Subject: [PATCH 45/84] Remove #if canImport() (#1777) Motivation: no need for project without dev pods --- .../Classes/Application/AppAssembly.swift | 100 +----------------- .../AppState/Impl/AppStateServiceImpl.swift | 20 ++-- .../Home/Interactor/DashboardInteractor.swift | 3 - .../Presenter/TagSettingsPresenter.swift | 3 - .../OffsetCorrectionAppleViewController.swift | 3 - .../Sources/Assembly/WidgetAssembly.swift | 6 -- .../SQLiteContextGRDB.swift | 3 - .../toSQLite/MigrationManagerToSQLite.swift | 3 - .../toVIPER/MigrationManagerToVIPER.swift | 3 - .../RuuviPersistenceRealm.swift | 8 +- .../RuuviPersistenceSQLite.swift | 6 -- .../RuuviTagLastRecordSubjectCombine.swift | 6 -- .../RuuviTagLatestRecordSubjectCombine.swift | 6 -- .../RuuviTagRecordSubjectCombine.swift | 6 -- .../RuuviTagSubjectCombine.swift | 6 -- .../SensorSettingsCombine.swift | 6 -- .../RuuviReactorImpl/RuuviReactorImpl.swift | 6 -- .../RuuviServiceCloudNotificationImpl.swift | 3 - .../RuuviServiceFactory.swift | 27 ----- 19 files changed, 12 insertions(+), 212 deletions(-) diff --git a/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift b/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift index b257c2cbf..841ff4376 100644 --- a/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift +++ b/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift @@ -1,5 +1,7 @@ +// swiftlint:disable file_length import BTKit import Foundation +import RuuviAnalytics import RuuviCloud import RuuviContext import RuuviCore @@ -20,101 +22,7 @@ import RuuviRepository import RuuviService import RuuviStorage import RuuviUser -// swiftlint:disable file_length import Swinject -#if canImport(RuuviCloudPure) - import RuuviCloudPure -#endif -#if canImport(RuuviContextRealm) - import RuuviContextRealm -#endif -#if canImport(RuuviContextSQLite) - import RuuviContextSQLite -#endif -#if canImport(RuuviPersistenceRealm) - import RuuviPersistenceRealm -#endif -#if canImport(RuuviPersistenceSQLite) - import RuuviPersistenceSQLite -#endif -#if canImport(RuuviStorageCoordinator) - import RuuviStorageCoordinator -#endif -#if canImport(RuuviPoolCoordinator) - import RuuviPoolCoordinator -#endif -#if canImport(RuuviLocalUserDefaults) - import RuuviLocalUserDefaults -#endif -#if canImport(RuuviPoolCoordinator) - import RuuviPoolCoordinator -#endif -#if canImport(RuuviReactorImpl) - import RuuviReactorImpl -#endif -#if canImport(RuuviDFUImpl) - import RuuviDFUImpl -#endif -#if canImport(RuuviMigrationImpl) - import RuuviMigrationImpl -#endif -#if canImport(RuuviDaemonOperation) - import RuuviDaemonOperation -#endif -#if canImport(RuuviDaemonBackground) - import RuuviDaemonBackground -#endif -#if canImport(RuuviDaemonRuuviTag) - import RuuviDaemonRuuviTag -#endif -#if canImport(RuuviServiceGATT) - import RuuviServiceGATT -#endif -#if canImport(RuuviAnalytics) - import RuuviAnalytics -#endif -#if canImport(RuuviAnalyticsImpl) - import RuuviAnalyticsImpl -#endif -#if canImport(RuuviServiceExport) - import RuuviServiceExport -#endif -#if canImport(RuuviNotifierImpl) - import RuuviNotifierImpl -#endif -#if canImport(RuuviServiceFactory) - import RuuviServiceFactory -#endif -#if canImport(RuuviDaemonCloudSync) - import RuuviDaemonCloudSync -#endif -#if canImport(RuuviRepositoryCoordinator) - import RuuviRepositoryCoordinator -#endif -#if canImport(RuuviUserCoordinator) - import RuuviUserCoordinator -#endif -#if canImport(RuuviCoreLocation) - import RuuviCoreLocation -#endif -#if canImport(RuuviNotificationLocal) - import RuuviNotificationLocal -#endif -#if canImport(RuuviCoreImage) - import RuuviCoreImage -#endif -#if canImport(RuuviCoreLocation) - import RuuviCoreLocation -#endif -#if canImport(RuuviCorePN) - import RuuviCorePN -#endif -#if canImport(RuuviCorePermission) - import RuuviCorePermission -#endif -#if canImport(RuuviServiceMeasurement) - import RuuviServiceMeasurement -#endif final class AppAssembly { static let shared = AppAssembly() @@ -428,9 +336,7 @@ private final class BusinessAssembly: Assembly { service.heartbeatDaemon = r.resolve(RuuviTagHeartbeatDaemon.self) service.ruuviUser = r.resolve(RuuviUser.self) service.backgroundProcessService = r.resolve(BackgroundProcessService.self) - #if canImport(RuuviAnalytics) - service.userPropertiesService = r.resolve(RuuviAnalytics.self) - #endif + service.userPropertiesService = r.resolve(RuuviAnalytics.self) service.universalLinkCoordinator = r.resolve(UniversalLinkCoordinator.self) return service }.inObjectScope(.container) diff --git a/Apps/RuuviStation/Sources/Classes/Application/AppState/Impl/AppStateServiceImpl.swift b/Apps/RuuviStation/Sources/Classes/Application/AppState/Impl/AppStateServiceImpl.swift index 476e31d7f..12ff12bdb 100644 --- a/Apps/RuuviStation/Sources/Classes/Application/AppState/Impl/AppStateServiceImpl.swift +++ b/Apps/RuuviStation/Sources/Classes/Application/AppState/Impl/AppStateServiceImpl.swift @@ -1,11 +1,9 @@ +import RuuviAnalytics import RuuviDaemon import RuuviLocal import RuuviOntology import RuuviUser import UIKit -#if canImport(RuuviAnalytics) - import RuuviAnalytics -#endif #if canImport(WidgetKit) import WidgetKit #endif @@ -18,9 +16,7 @@ class AppStateServiceImpl: AppStateService { var propertiesDaemon: RuuviTagPropertiesDaemon! var cloudSyncDaemon: RuuviDaemonCloudSync! var settings: RuuviLocalSettings! - #if canImport(RuuviAnalytics) - var userPropertiesService: RuuviAnalytics! - #endif + var userPropertiesService: RuuviAnalytics! var universalLinkCoordinator: UniversalLinkCoordinator! func application( @@ -44,12 +40,10 @@ class AppStateServiceImpl: AppStateService { backgroundProcessService.register() settings.appIsOnForeground = true observeWidgetKind() - #if canImport(RuuviAnalytics) - DispatchQueue.main.async { - self.userPropertiesService.update() - } - settings.appOpenedCount += 1 - #endif + DispatchQueue.main.async { + self.userPropertiesService.update() + } + settings.appOpenedCount += 1 } func applicationWillResignActive(_: UIApplication) { @@ -66,7 +60,9 @@ class AppStateServiceImpl: AppStateService { } if ruuviUser.isAuthorized { cloudSyncDaemon.stop() +#if canImport(WidgetKit) WidgetCenter.shared.reloadTimelines(ofKind: AppAssemblyConstants.simpleWidgetKindId) +#endif } propertiesDaemon.stop() backgroundProcessService.schedule() diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift index 34f927ea4..7d322b8cc 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Interactor/DashboardInteractor.swift @@ -5,9 +5,6 @@ import RuuviLocal import RuuviOntology import RuuviPool import RuuviService -#if canImport(RuuviServiceOwnership) - import RuuviServiceOwnership -#endif import RuuviUser class DashboardInteractor { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift index aed1174be..5d4065012 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift @@ -9,9 +9,6 @@ import RuuviReactor import RuuviService import RuuviStorage import UIKit -#if canImport(RuuviServiceOwnership) - import RuuviServiceOwnership -#endif import RuuviCore import RuuviDaemon import RuuviNotifier diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift index e52e2a165..e7d9f9ee9 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift @@ -2,9 +2,6 @@ import RuuviLocalization import RuuviOntology import RuuviService import UIKit -#if canImport(RuuviServiceMeasurement) - import RuuviServiceMeasurement -#endif class OffsetCorrectionAppleViewController: UIViewController { var output: OffsetCorrectionViewOutput! diff --git a/Apps/RuuviStation/Widgets/Sources/Assembly/WidgetAssembly.swift b/Apps/RuuviStation/Widgets/Sources/Assembly/WidgetAssembly.swift index ec266fbde..9896defe6 100644 --- a/Apps/RuuviStation/Widgets/Sources/Assembly/WidgetAssembly.swift +++ b/Apps/RuuviStation/Widgets/Sources/Assembly/WidgetAssembly.swift @@ -2,12 +2,6 @@ import Foundation import RuuviCloud import RuuviUser import Swinject -#if canImport(RuuviCloudPure) - import RuuviCloudPure -#endif -#if canImport(RuuviUserCoordinator) - import RuuviUserCoordinator -#endif final class WidgetAssembly { static let shared = WidgetAssembly() diff --git a/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextGRDB.swift b/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextGRDB.swift index 7fc1254c1..d327392fc 100644 --- a/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextGRDB.swift +++ b/Packages/RuuviContext/Sources/RuuviContextSQLite/SQLiteContextGRDB.swift @@ -1,9 +1,6 @@ import Foundation import GRDB import RuuviOntology -#if canImport(RuuviOntologySQLite) - import RuuviOntologySQLite -#endif class SQLiteContextGRDB: SQLiteContext { let database: GRDBDatabase = SQLiteGRDBDatabase.shared diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift index 0633be772..4d66b3df0 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift @@ -4,9 +4,6 @@ import RuuviContext import RuuviLocal import RuuviOntology import RuuviPool -#if canImport(RuuviOntologyRealm) - import RuuviOntologyRealm -#endif extension Notification.Name { static let MigrationManagerToSQLiteDidFinish = Notification.Name("MigrationManagerToSQLite.DidFinish") diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift index d257a81e2..46c065c55 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift @@ -2,9 +2,6 @@ import Foundation import RealmSwift import RuuviLocal import RuuviOntology -#if canImport(RuuviOntologyRealm) - import RuuviOntologyRealm -#endif public final class MigrationManagerToVIPER: RuuviMigration { private let localImages: RuuviLocalImages diff --git a/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift b/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift index 1f49b26b7..3ec363bc3 100644 --- a/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift +++ b/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift @@ -1,19 +1,13 @@ +// swiftlint:disable file_length import BTKit import Foundation import Future -// swiftlint:disable file_length import RealmSwift import RuuviContext import RuuviOntology #if canImport(FirebaseCrashlytics) // TODO: @rinat eliminate import FirebaseCrashlytics #endif -#if canImport(RuuviOntologyRealm) - import RuuviOntologyRealm -#endif -#if canImport(RuuviContextRealm) - import RuuviContextRealm -#endif // swiftlint:disable type_body_length public class RuuviPersistenceRealm: RuuviPersistence { diff --git a/Packages/RuuviPersistence/Sources/RuuviPersistenceSQLite/RuuviPersistenceSQLite.swift b/Packages/RuuviPersistence/Sources/RuuviPersistenceSQLite/RuuviPersistenceSQLite.swift index 6aad4eaac..09e9754e4 100644 --- a/Packages/RuuviPersistence/Sources/RuuviPersistenceSQLite/RuuviPersistenceSQLite.swift +++ b/Packages/RuuviPersistence/Sources/RuuviPersistenceSQLite/RuuviPersistenceSQLite.swift @@ -8,12 +8,6 @@ import RuuviOntology #if canImport(FirebaseCrashlytics) import FirebaseCrashlytics #endif -#if canImport(RuuviOntologySQLite) - import RuuviOntologySQLite -#endif -#if canImport(RuuviContextSQLite) - import RuuviContextSQLite -#endif // swiftlint:disable type_body_length public class RuuviPersistenceSQLite: RuuviPersistence, DatabaseService { diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLastRecordSubjectCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLastRecordSubjectCombine.swift index c1c6ff646..337ebac55 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLastRecordSubjectCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLastRecordSubjectCombine.swift @@ -4,12 +4,6 @@ import GRDB import RealmSwift import RuuviContext import RuuviOntology -#if canImport(RuuviOntologyRealm) - import RuuviOntologyRealm -#endif -#if canImport(RuuviOntologySQLite) - import RuuviOntologySQLite -#endif final class RuuviTagLastRecordSubjectCombine { var isServing: Bool = false diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLatestRecordSubjectCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLatestRecordSubjectCombine.swift index 90c927418..a31ef4622 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLatestRecordSubjectCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLatestRecordSubjectCombine.swift @@ -4,12 +4,6 @@ import GRDB import RealmSwift import RuuviContext import RuuviOntology -#if canImport(RuuviOntologyRealm) - import RuuviOntologyRealm -#endif -#if canImport(RuuviOntologySQLite) - import RuuviOntologySQLite -#endif final class RuuviTagLatestRecordSubjectCombine { var isServing: Bool = false diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagRecordSubjectCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagRecordSubjectCombine.swift index d12dab71c..93d7f8c72 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagRecordSubjectCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagRecordSubjectCombine.swift @@ -4,12 +4,6 @@ import GRDB import RealmSwift import RuuviContext import RuuviOntology -#if canImport(RuuviOntologyRealm) - import RuuviOntologyRealm -#endif -#if canImport(RuuviOntologySQLite) - import RuuviOntologySQLite -#endif final class RuuviTagRecordSubjectCombine { var isServing: Bool = false diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagSubjectCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagSubjectCombine.swift index b44e7b730..f5ae07566 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagSubjectCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagSubjectCombine.swift @@ -4,12 +4,6 @@ import GRDB import RealmSwift import RuuviContext import RuuviOntology -#if canImport(RuuviOntologyRealm) - import RuuviOntologyRealm -#endif -#if canImport(RuuviOntologySQLite) - import RuuviOntologySQLite -#endif final class RuuviTagSubjectCombine { var sqlite: SQLiteContext diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/SensorSettingsCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/SensorSettingsCombine.swift index 4e1fccba0..6fa2d6ab8 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/SensorSettingsCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/SensorSettingsCombine.swift @@ -4,12 +4,6 @@ import GRDB import RealmSwift import RuuviContext import RuuviOntology -#if canImport(RuuviOntologyRealm) - import RuuviOntologyRealm -#endif -#if canImport(RuuviOntologySQLite) - import RuuviOntologySQLite -#endif final class SensorSettingsCombine { var luid: LocalIdentifier? diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift index 0df62d43a..9d3cf3ec8 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift @@ -4,12 +4,6 @@ import GRDB import RuuviContext import RuuviOntology import RuuviPersistence -#if canImport(RuuviOntologyRealm) - import RuuviOntologyRealm -#endif -#if canImport(RuuviOntologySQLite) - import RuuviOntologySQLite -#endif class RuuviReactorImpl: RuuviReactor { typealias SQLiteEntity = RuuviTagSQLite diff --git a/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift b/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift index 8aa448d15..4072e0d4c 100644 --- a/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceCloudNotification/RuuviServiceCloudNotificationImpl.swift @@ -7,9 +7,6 @@ import RuuviOntology import RuuviPool import RuuviStorage import RuuviUser -#if canImport(RuuviCloudApi) - import RuuviCloudApi -#endif public final class RuuviServiceCloudNotificationImpl: RuuviServiceCloudNotification { private let cloud: RuuviCloud diff --git a/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift b/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift index fb77e0d8d..82850f0ee 100644 --- a/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift +++ b/Packages/RuuviService/Sources/RuuviServiceFactory/RuuviServiceFactory.swift @@ -6,33 +6,6 @@ import RuuviPool import RuuviRepository import RuuviStorage import RuuviUser -#if canImport(RuuviServiceCloudSync) - import RuuviServiceCloudSync -#endif -#if canImport(RuuviServiceOwnership) - import RuuviServiceOwnership -#endif -#if canImport(RuuviServiceSensorProperties) - import RuuviServiceSensorProperties -#endif -#if canImport(RuuviServiceSensorRecords) - import RuuviServiceSensorRecords -#endif -#if canImport(RuuviServiceAppSettings) - import RuuviServiceAppSettings -#endif -#if canImport(RuuviServiceOffsetCalibration) - import RuuviServiceOffsetCalibration -#endif -#if canImport(RuuviServiceAlert) - import RuuviServiceAlert -#endif -#if canImport(RuuviServiceAuth) - import RuuviServiceAuth -#endif -#if canImport(RuuviServiceCloudNotification) - import RuuviServiceCloudNotification -#endif public protocol RuuviServiceFactory { // swiftlint:disable:next function_parameter_count From c061f2019a6113e3d5b45aba461f7d03d55fe087 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Thu, 14 Dec 2023 00:15:08 +0200 Subject: [PATCH 46/84] RuuviColor generated enum (#1778) * Remove RuuviLocalization file from repo Codegenerate it on the fly * add colors to generated code * remove localizable * gitignore files * use new colors * fix crash on not debug mode --- .swiftgen.assets.yml | 19 + .swiftgen.localizable.yml | 25 + .../Presentation/Colors/RuuviColor.swift | 42 - .../FLEX/FeatureTogglesViewController.swift | 11 +- .../About/Presenter/AboutPresenter.swift | 4 +- .../About/View/AboutViewController.swift | 4 +- .../UI/BackgroundSelectionButtonView.swift | 7 +- ...ackgroundSelectionUploadProgressView.swift | 5 +- .../BackgroundSelectionViewController.swift | 2 +- .../UI/BackgroundSelectionViewHeader.swift | 6 +- .../Cards/View/UI/CardsViewController.swift | 6 +- .../Charts/Helpers/TagChartsHelper.swift | 7 +- .../Charts/View/UI/TagChartsMarkerView.swift | 3 +- .../View/UI/TagChartsViewController.swift | 2 +- .../Home/View/DashboardImageCell.swift | 24 +- .../Home/View/DashboardIndicatorView.swift | 13 +- .../Home/View/DashboardPlainCell.swift | 16 +- .../Home/View/DashboardViewController.swift | 14 +- .../Dashboard/Home/View/LowBatteryView.swift | 4 +- .../Dashboard/Home/View/NoSensorView.swift | 8 +- .../View/UI/ASSelectionTableViewCell.swift | 9 +- .../UI/ASSelectionTableViewController.swift | 3 +- ...AppearanceSettingsTableViewBasicCell.swift | 5 +- ...ppearanceSettingsTableViewController.swift | 3 +- .../ChartSettingsTableViewController.swift | 2 +- .../View/UI/DevicesTableViewCell.swift | 8 +- .../View/UI/DevicesTableViewController.swift | 2 +- .../Table/HeartbeatTableViewController.swift | 2 +- ...PushAlertSoundSelectionTableViewCell.swift | 9 +- ...ertSoundSelectionTableViewController.swift | 3 +- .../UI/NotificationsSettingsSwitchCell.swift | 5 +- ...ficationsSettingsTableViewController.swift | 2 +- .../UI/NotificationsSettingsTextCell.swift | 7 +- .../View/UI/RuuviCloudTableViewCell.swift | 3 +- .../UI/RuuviCloudTableViewController.swift | 4 +- .../Table/SelectionTableViewController.swift | 4 +- .../ViewController/ShareViewController.swift | 5 +- .../View/SignInBenefitsViewController.swift | 6 +- .../SignIn/View/UI/Helper/SignInView.swift | 2 +- .../SignIn/View/UI/SignInViewController.swift | 2 +- .../DFU/View/SwiftUI/DFUUIView.swift | 89 +- .../UI/SensorForceClaimViewController.swift | 14 +- .../OffsetCorrectionAppleViewController.swift | 4 +- .../Owner/View/OwnerViewController.swift | 4 +- .../View/UI/SensorRemovalViewController.swift | 10 +- .../RUAlertDetailsCellChildView.swift | 3 +- .../RUAlertExpandButton.swift | 3 +- .../View/UI/TagSettingsAlertConfigCell.swift | 12 +- .../TagSettingsBackgroundSelectionView.swift | 2 +- .../View/UI/TagSettingsBasicCell.swift | 9 +- .../TagSettingsExpandableSectionHeader.swift | 24 +- .../View/UI/TagSettingsPlainCell.swift | 5 +- .../UI/TagSettingsSimpleSectionHeader.swift | 7 +- .../View/UI/TagSettingsSwitchCell.swift | 7 +- .../View/UI/TagSettingsViewController.swift | 12 +- .../Classess/RuuviLinkTextView.swift | 9 +- .../Extensions/Classess/RuuviUISwitch.swift | 6 +- .../Sources/Extensions/Color+Ruuvi.swift | 16 - Apps/RuuviStation/target.yml | 17 - Common/RuuviLocalization/.gitignore | 3 + .../RuuviColors.xcassets}/Contents.json | 0 .../DashboardBG.colorset}/Contents.json | 0 .../DashboardCardBG.colorset}/Contents.json | 0 .../Contents.json | 0 .../Contents.json | 0 .../DustyBlue.colorset}/Contents.json | 0 .../GraphBGColor.colorset}/Contents.json | 0 .../GraphFillColor.colorset}/Contents.json | 0 .../GraphLineColor.colorset}/Contents.json | 0 .../GraphMarkerColor.colorset}/Contents.json | 0 .../Green.colorset}/Contents.json | 0 .../LineColor.colorset}/Contents.json | 0 .../LogoTintColor.colorset}/Contents.json | 0 .../MenuTextColor.colorset}/Contents.json | 0 .../MenuTintColor.colorset}/Contents.json | 0 .../OrangeColor.colorset}/Contents.json | 0 .../Primary.colorset}/Contents.json | 0 .../Purple.colorset}/Contents.json | 0 .../Secondary.colorset}/Contents.json | 0 .../Contents.json | 0 .../Contents.json | 0 .../SwitchEnabledTint.colorset}/Contents.json | 0 .../Contents.json | 0 .../Contents.json | 0 .../TextColor.colorset}/Contents.json | 0 .../TintColor.colorset}/Contents.json | 0 .../Resources/de.lproj/Localizable.strings | 772 ----- .../Resources/en.lproj/Localizable.strings | 767 ----- .../Resources/fi.lproj/Localizable.strings | 767 ----- .../Resources/fr.lproj/Localizable.strings | 769 ----- .../Resources/ru.lproj/Localizable.strings | 767 ----- .../Resources/sv.lproj/Localizable.strings | 767 ----- .../RuuviLocalization/RuuviLocalization.swift | 2659 ----------------- ...-swift5.stencil => strings-swift5.stencil} | 0 .../Templates/xcassets-swift5.stencil | 438 +++ Common/RuuviLocalization/target.yml | 22 + Makefile | 2 +- .../View/Table/DiscoverTableHeaderView.swift | 3 +- .../RuuviFirmware/Common/ProgressBar.swift | 5 +- .../RuuviMenuTextColor.colorset/Contents.json | 38 - .../RuuviTextColor.colorset/Contents.json | 38 - .../RuuviTintColor.colorset/Contents.json | 20 - .../RuuviFirmware/SwiftUI/FirmwareView.swift | 87 +- .../RuuviFirmware/Util/RuuviColor.swift | 8 - Modules/RuuviFirmware/target.yml | 1 + .../Pages/Assests/RuuviAssets.swift | 3 - .../RuuviOnboardGatewayFeaturesCell.swift | 3 +- .../Pages/RuuviOnboardSignInCell.swift | 3 +- .../RuuviTintColor.colorset/Contents.json | 20 - ...generate_l10n.sh => generate_resources.sh} | 3 +- scripts/generate_project.sh | 26 + swiftgen.yml | 34 - 112 files changed, 823 insertions(+), 7763 deletions(-) create mode 100644 .swiftgen.assets.yml create mode 100644 .swiftgen.localizable.yml delete mode 100644 Apps/RuuviStation/Sources/Classes/Presentation/Colors/RuuviColor.swift delete mode 100644 Apps/RuuviStation/Sources/Extensions/Color+Ruuvi.swift rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardBG.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/DashboardBG.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardCardBG.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/DashboardCardBG.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardIndicator.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/DashboardIndicator.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardIndicatorBig.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/DashboardIndicatorBig.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDustyBlue.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/DustyBlue.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphBGColor.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/GraphBGColor.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphFillColor.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/GraphFillColor.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphLineColor.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/GraphLineColor.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphMarkerColor.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/GraphMarkerColor.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGreen.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/Green.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviLineColor.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/LineColor.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviLogoTintColor.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/LogoTintColor.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviMenuTextColor.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/MenuTextColor.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviMenuTintColor.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/MenuTintColor.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviOrangeColor.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/OrangeColor.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviPrimary.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/Primary.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviPurple.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/Purple.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSecondary.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/Secondary.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSwitchDisabledThumbTint.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/SwitchDisabledThumbTint.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSwitchDisabledTint.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/SwitchDisabledTint.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSwitchEnabledTint.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/SwitchEnabledTint.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets}/TagSettingsItemHeaderColor.colorset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets}/TagSettingsSectionHeaderColor.colorset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviTextColor.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/TextColor.colorset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviTintColor.colorset => Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/TintColor.colorset}/Contents.json (100%) delete mode 100644 Common/RuuviLocalization/Sources/RuuviLocalization/Resources/de.lproj/Localizable.strings delete mode 100644 Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings delete mode 100644 Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fi.lproj/Localizable.strings delete mode 100644 Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fr.lproj/Localizable.strings delete mode 100644 Common/RuuviLocalization/Sources/RuuviLocalization/Resources/ru.lproj/Localizable.strings delete mode 100644 Common/RuuviLocalization/Sources/RuuviLocalization/Resources/sv.lproj/Localizable.strings delete mode 100644 Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift rename Common/RuuviLocalization/Templates/{structured-swift5.stencil => strings-swift5.stencil} (100%) create mode 100644 Common/RuuviLocalization/Templates/xcassets-swift5.stencil delete mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviMenuTextColor.colorset/Contents.json delete mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviTextColor.colorset/Contents.json delete mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviTintColor.colorset/Contents.json delete mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviColor.swift delete mode 100644 Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/RuuviTintColor.colorset/Contents.json rename scripts/build/{generate_l10n.sh => generate_resources.sh} (57%) create mode 100755 scripts/generate_project.sh delete mode 100644 swiftgen.yml diff --git a/.swiftgen.assets.yml b/.swiftgen.assets.yml new file mode 100644 index 000000000..f38d655cd --- /dev/null +++ b/.swiftgen.assets.yml @@ -0,0 +1,19 @@ +xcassets: + - inputs: ./Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets + outputs: + - templatePath: ./Common/RuuviLocalization/Templates/xcassets-swift5.stencil + output: ./Common/RuuviLocalization/Sources/RuuviColor.swift + params: + forceProvidesNamespaces: true + publicAccess: true + enumName: RuuviColor + +strings: + - inputs: ./Common/RuuviLocalization/Sources/Resources/en.lproj/Localizable.strings + outputs: + - templatePath: ./Common/RuuviLocalization/Templates/strings-swift5.stencil + output: ./Common/RuuviLocalization/Sources/RuuviLocalization.swift + params: + forceProvidesNamespaces: true + publicAccess: true + enumName: RuuviLocalization \ No newline at end of file diff --git a/.swiftgen.localizable.yml b/.swiftgen.localizable.yml new file mode 100644 index 000000000..dcb738514 --- /dev/null +++ b/.swiftgen.localizable.yml @@ -0,0 +1,25 @@ +json: + - inputs: ./station.localization/station.localization.json + outputs: + - templatePath: ./Common/RuuviLocalization/Templates/Localizable_en.strings.stencil + output: ./Common/RuuviLocalization/Sources/Resources/en.lproj/Localizable.strings + - inputs: ./station.localization/station.localization.json + outputs: + - templatePath: ./Common/RuuviLocalization/Templates/Localizable_sv.strings.stencil + output: ./Common/RuuviLocalization/Sources/Resources/sv.lproj/Localizable.strings + - inputs: ./station.localization/station.localization.json + outputs: + - templatePath: ./Common/RuuviLocalization/Templates/Localizable_ru.strings.stencil + output: ./Common/RuuviLocalization/Sources/Resources/ru.lproj/Localizable.strings + - inputs: ./station.localization/station.localization.json + outputs: + - templatePath: ./Common/RuuviLocalization/Templates/Localizable_fi.strings.stencil + output: ./Common/RuuviLocalization/Sources/Resources/fi.lproj/Localizable.strings + - inputs: ./station.localization/station.localization.json + outputs: + - templatePath: ./Common/RuuviLocalization/Templates/Localizable_fr.strings.stencil + output: ./Common/RuuviLocalization/Sources/Resources/fr.lproj/Localizable.strings + - inputs: ./station.localization/station.localization.json + outputs: + - templatePath: ./Common/RuuviLocalization/Templates/Localizable_de.strings.stencil + output: ./Common/RuuviLocalization/Sources/Resources/de.lproj/Localizable.strings \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Colors/RuuviColor.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Colors/RuuviColor.swift deleted file mode 100644 index 75c0ca8a3..000000000 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Colors/RuuviColor.swift +++ /dev/null @@ -1,42 +0,0 @@ -import SwiftUI - -enum RuuviColor { - static let purple = Color("RuuviPurple") - static let green = Color("RuuviGreen") - static let dustyBlue = Color("RuuviDustyBlue") - static let ruuviPrimarySUI = UIColor(named: "RuuviPrimary") - static let ruuviTintColorSUI = Color("RuuviTintColor") - static let ruuviTextColorSUI = Color("RuuviTextColor") - static let ruuviTitleTextColorSUI = Color("RuuviMenuTextColor") - static let dashboardBGColor = UIColor(named: "RuuviDashboardBG") - static let dashboardCardBGColor = UIColor(named: "RuuviDashboardCardBG") - static let menuButtonTintColor = UIColor(named: "RuuviMenuTintColor") - static let logoTintColor = UIColor(named: "RuuviLogoTintColor") - static let dashboardIndicatorTextColor = UIColor(named: "RuuviDashboardIndicator") - static let dashboardIndicatorBigTextColor = UIColor(named: "RuuviDashboardIndicatorBig") - static let ruuviOrangeColor = UIColor(named: "RuuviOrangeColor") - static let ruuviGraphBGColor = UIColor(named: "RuuviGraphBGColor") - static let ruuviGraphFillColor = UIColor(named: "RuuviGraphFillColor") - static let ruuviGraphLineColor = UIColor(named: "RuuviGraphFillColor") - static let ruuviGraphMarkerColor = UIColor(named: "RuuviGraphMarkerColor") - static let ruuviPrimary = UIColor(named: "RuuviPrimary") - static let ruuviSecondary = UIColor(named: "RuuviSecondary") - static let ruuviTintColor = UIColor(named: "RuuviTintColor") - static let ruuviTextColor = UIColor(named: "RuuviTextColor") - static let ruuviMenuTextColor = UIColor(named: "RuuviMenuTextColor") - static let ruuviLineColor = UIColor(named: "RuuviLineColor") - static let ruuviSwitchDisabledTint = - UIColor(named: "RuuviSwitchDisabledTint") - static let ruuviSwitchEnabledTint = - UIColor(named: "RuuviSwitchEnabledTint") - static let ruuviSwitchDisabledThumbTint = UIColor(named: "RuuviSwitchDisabledThumbTint") - - // Tag settings - static let tagSettingsSectionHeaderColor = UIColor(named: "TagSettingsSectionHeaderColor") - static let tagSettingsItemHeaderColor = UIColor(named: "TagSettingsItemHeaderColor") -} - -extension RuuviColor { - static let fallbackGraphLineColor = UIColor(hexString: "34ad9f") - static let fallbackGraphFillColor = UIColor(hexString: "46cab9", alpha: 0.3) -} diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/FLEX/FeatureTogglesViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/FLEX/FeatureTogglesViewController.swift index 732492390..ae969e479 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/FLEX/FeatureTogglesViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/FLEX/FeatureTogglesViewController.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit final class FeatureTogglesViewController: UITableViewController { @@ -22,7 +23,7 @@ final class FeatureTogglesViewController: UITableViewController { private static let featureCellReuseIdentifier = "FeatureCellReuseIdentifier" private func setupViews() { - view.backgroundColor = RuuviColor.ruuviPrimary + view.backgroundColor = RuuviColor.primary.color headerView.addSubview(sourceSwitch) headerView.addSubview(sourceLabel) tableView.tableHeaderView = headerView @@ -44,7 +45,7 @@ final class FeatureTogglesViewController: UITableViewController { let sourceSwitch = sourceSwitch sourceSwitch.onTintColor = .clear - sourceSwitch.thumbTintColor = RuuviColor.ruuviTintColor + sourceSwitch.thumbTintColor = RuuviColor.tintColor.color let sourceLabel = sourceLabel headerView.translatesAutoresizingMaskIntoConstraints = false @@ -106,10 +107,10 @@ extension FeatureTogglesViewController { let feature = features[indexPath.row] cell.textLabel?.text = Self.title(for: feature) cell.textLabel?.font = UIFont.Muli(.bold, size: 16) - cell.textLabel?.textColor = RuuviColor.ruuviMenuTextColor + cell.textLabel?.textColor = RuuviColor.menuTextColor.color if featureToggleService.isEnabled(feature) { cell.accessoryType = .checkmark - cell.tintColor = RuuviColor.ruuviTintColor + cell.tintColor = RuuviColor.tintColor.color } else { cell.accessoryType = .none } @@ -136,7 +137,7 @@ extension FeatureTogglesViewController { label.text = "Use local feature toggles" label.textAlignment = .right label.font = UIFont.Muli(.bold, size: 16) - label.textColor = RuuviColor.ruuviMenuTextColor + label.textColor = RuuviColor.menuTextColor.color return label } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift index 5c3a391af..0a4d77cea 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift @@ -71,7 +71,7 @@ extension AboutPresenter { ) attrString.addAttribute( .foregroundColor, - value: RuuviColor.ruuviTintColor ?? UIColor.blue, + value: RuuviColor.tintColor.color, range: changelogRange ) @@ -80,7 +80,7 @@ extension AboutPresenter { .range(of: versionText) attrString.addAttribute( .foregroundColor, - value: RuuviColor.dashboardIndicatorTextColor ?? UIColor.label, + value: RuuviColor.dashboardIndicator.color, range: regularRange ) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/View/AboutViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/View/AboutViewController.swift index 303ce0a26..8dbc4ac93 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/View/AboutViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/View/AboutViewController.swift @@ -155,12 +155,12 @@ extension AboutViewController { // make text color white attrString.addAttribute( .foregroundColor, - value: RuuviColor.ruuviTextColor ?? UIColor.label, + value: RuuviColor.textColor.color, range: NSRange(location: 0, length: attrString.length) ) aboutTextView.attributedText = attrString - aboutTextView.textColor = RuuviColor.ruuviTextColor + aboutTextView.textColor = RuuviColor.textColor.color } private func setUpChangelogTapGesture() { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift index 9843f9aac..c2d39604f 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionButtonView.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit protocol BackgroundSelectionButtonViewDelegate: NSObjectProtocol { @@ -10,7 +11,7 @@ class BackgroundSelectionButtonView: UIView { // UI private lazy var titleLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Muli(.bold, size: 16) @@ -21,11 +22,11 @@ class BackgroundSelectionButtonView: UIView { let iv = UIImageView() iv.contentMode = .scaleAspectFit iv.backgroundColor = .clear - iv.tintColor = RuuviColor.ruuviTintColor + iv.tintColor = RuuviColor.tintColor.color return iv }() - lazy var seprator = UIView(color: RuuviColor.ruuviLineColor) + lazy var seprator = UIView(color: RuuviColor.lineColor.color) override init(frame: CGRect) { super.init(frame: frame) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift index 2aae72c97..670c004a4 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionUploadProgressView.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit // swiftlint:disable:next type_name @@ -21,7 +22,7 @@ class BackgroundSelectionUploadProgressView: UIView { let iv = UIImageView() iv.contentMode = .scaleAspectFit iv.backgroundColor = .clear - iv.tintColor = RuuviColor.ruuviTintColor + iv.tintColor = RuuviColor.tintColor.color iv.isUserInteractionEnabled = true iv.image = UIImage(systemName: "xmark.circle.fill") let tap = UITapGestureRecognizer(target: self, action: #selector(handleCancelTap)) @@ -42,7 +43,7 @@ class BackgroundSelectionUploadProgressView: UIView { private extension BackgroundSelectionUploadProgressView { func setUpUI() { - backgroundColor = RuuviColor.ruuviGraphBGColor + backgroundColor = RuuviColor.graphBGColor.color layer.cornerRadius = 4 clipsToBounds = true diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift index 6ec8d7cdf..67b28d3ec 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift @@ -81,7 +81,7 @@ private extension BackgroundSelectionViewController { } func setUpBaseView() { - view.backgroundColor = RuuviColor.dashboardBGColor + view.backgroundColor = RuuviColor.dashboardBG.color } func setUpHeaderView() { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift index 626e872c8..6992074a3 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewHeader.swift @@ -15,7 +15,7 @@ class BackgroundSelectionViewHeader: UICollectionReusableView { private lazy var descriptionLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Muli(.regular, size: 16) @@ -23,7 +23,7 @@ class BackgroundSelectionViewHeader: UICollectionReusableView { return label }() - lazy var seprator = UIView(color: RuuviColor.ruuviLineColor) + lazy var seprator = UIView(color: RuuviColor.lineColor.color) lazy var takePhotoButton = BackgroundSelectionButtonView( title: RuuviLocalization.takePhoto, icon: "camera.fill", @@ -37,7 +37,7 @@ class BackgroundSelectionViewHeader: UICollectionReusableView { private lazy var selectFromDefaultLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Muli(.bold, size: 16) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift index 9143b34d5..cbf95aaad 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift @@ -1,9 +1,9 @@ +// swiftlint:disable file_length import Humidity import RuuviLocal import RuuviLocalization import RuuviOntology import RuuviService -// swiftlint:disable file_length import UIKit class CardsViewController: UIViewController { @@ -56,7 +56,7 @@ class CardsViewController: UIViewController { // Base private lazy var cardBackgroundView = CardsBackgroundView() - private lazy var chartViewBackground = UIView(color: RuuviColor.ruuviGraphBGColor) + private lazy var chartViewBackground = UIView(color: RuuviColor.graphBGColor.color) // Header View // Ruuvi Logo @@ -261,7 +261,7 @@ private extension CardsViewController { } func setUpBaseView() { - view.backgroundColor = RuuviColor.ruuviPrimary + view.backgroundColor = RuuviColor.primary.color view.addSubview(cardBackgroundView) cardBackgroundView.fillSuperview() diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift index 9ff1ac9f7..4d8ed7e3c 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift @@ -1,18 +1,19 @@ import Charts import Foundation +import RuuviLocalization enum TagChartsHelper { static func newDataSet(entries: [ChartDataEntry] = []) -> LineChartDataSet { let lineChartDataSet = LineChartDataSet(entries: entries) lineChartDataSet.axisDependency = .left - lineChartDataSet.setColor(RuuviColor.ruuviGraphLineColor ?? RuuviColor.fallbackGraphLineColor) + lineChartDataSet.setColor(RuuviColor.graphLineColor.color) lineChartDataSet.lineWidth = 1.5 lineChartDataSet.drawCirclesEnabled = false lineChartDataSet.circleRadius = 0.8 lineChartDataSet.drawValuesEnabled = false lineChartDataSet.fillAlpha = 1 - lineChartDataSet.fillColor = RuuviColor.ruuviGraphFillColor ?? RuuviColor.fallbackGraphFillColor - lineChartDataSet.highlightColor = RuuviColor.ruuviGraphFillColor ?? RuuviColor.fallbackGraphFillColor + lineChartDataSet.fillColor = RuuviColor.graphFillColor.color + lineChartDataSet.highlightColor = RuuviColor.graphFillColor.color lineChartDataSet.highlightLineDashLengths = [2, 1, 0] lineChartDataSet.highlightLineWidth = 1 lineChartDataSet.drawCircleHoleEnabled = false diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift index ee362a0f7..1aacac812 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift @@ -1,4 +1,5 @@ import Charts +import RuuviLocalization import RuuviService import UIKit @@ -21,7 +22,7 @@ class TagChartsMarkerView: MarkerImage { private let yBottomPadding: CGFloat = 32.0 init( - color: UIColor? = RuuviColor.ruuviGraphMarkerColor, + color: UIColor? = RuuviColor.graphMarkerColor.color, font: UIFont = UIFont.Muli(.regular, size: 8), textColor: UIColor = .white ) { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift index b67a3bac8..b53c01d7b 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift @@ -84,7 +84,7 @@ class TagChartsViewController: UIViewController { titleColor: .white, title: RuuviLocalization.day1, icon: RuuviAssets.dropDownArrowImage, - iconTintColor: RuuviColor.logoTintColor, + iconTintColor: RuuviColor.logoTintColor.color, iconSize: .init(width: 14, height: 14), preccedingIcon: false ) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift index f17a92cc7..f118dda09 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift @@ -12,7 +12,7 @@ class DashboardImageCell: UICollectionViewCell { private lazy var ruuviTagNameLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.dashboardIndicatorBigTextColor + label.textColor = RuuviColor.dashboardIndicatorBig.color label.textAlignment = .left label.numberOfLines = 2 label.font = UIFont.Montserrat(.bold, size: 14) @@ -23,7 +23,7 @@ class DashboardImageCell: UICollectionViewCell { let iv = UIImageView() iv.contentMode = .scaleAspectFit iv.backgroundColor = .clear - iv.tintColor = RuuviColor.dashboardIndicatorBigTextColor + iv.tintColor = RuuviColor.dashboardIndicatorBig.color iv.alpha = 0 return iv }() @@ -42,7 +42,7 @@ class DashboardImageCell: UICollectionViewCell { iv.contentMode = .scaleAspectFit iv.backgroundColor = .clear iv.image = RuuviAssets.threeDotMoreImage - iv.tintColor = RuuviColor.dashboardIndicatorBigTextColor + iv.tintColor = RuuviColor.dashboardIndicatorBig.color return iv }() @@ -57,7 +57,7 @@ class DashboardImageCell: UICollectionViewCell { private lazy var temperatureLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.dashboardIndicatorBigTextColor + label.textColor = RuuviColor.dashboardIndicatorBig.color label.textAlignment = .left label.numberOfLines = 1 label.font = UIFont.Oswald(.bold, size: 30) @@ -66,7 +66,7 @@ class DashboardImageCell: UICollectionViewCell { private lazy var temperatureUnitLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.dashboardIndicatorBigTextColor + label.textColor = RuuviColor.dashboardIndicatorBig.color label.textAlignment = .left label.numberOfLines = 1 label.font = UIFont.Oswald(.extraLight, size: 16) @@ -83,7 +83,7 @@ class DashboardImageCell: UICollectionViewCell { iv.backgroundColor = .clear iv.alpha = 0.7 iv.tintColor = RuuviColor - .dashboardIndicatorTextColor? + .dashboardIndicator.color .withAlphaComponent(0.8) return iv }() @@ -91,7 +91,7 @@ class DashboardImageCell: UICollectionViewCell { private lazy var updatedAtLabel: UILabel = { let label = UILabel() label.textColor = RuuviColor - .dashboardIndicatorTextColor? + .dashboardIndicator.color .withAlphaComponent(0.8) label.textAlignment = .left label.numberOfLines = 0 @@ -128,7 +128,7 @@ class DashboardImageCell: UICollectionViewCell { // swiftlint:disable:next function_body_length fileprivate func setUpUI() { let container = UIView( - color: RuuviColor.dashboardCardBGColor, + color: RuuviColor.dashboardCardBG.color, cornerRadius: 8 ) contentView.addSubview(container) @@ -530,11 +530,11 @@ extension DashboardImageCell { alertIcon.image = RuuviAssets.alertOnImage removeAlertAnimations() } - alertIcon.tintColor = RuuviColor.logoTintColor + alertIcon.tintColor = RuuviColor.logoTintColor.color case .firing: alertButton.isUserInteractionEnabled = true alertIcon.alpha = 1.0 - alertIcon.tintColor = RuuviColor.ruuviOrangeColor + alertIcon.tintColor = RuuviColor.orangeColor.color if alertIcon.image != RuuviAssets.alertActiveImage { alertIcon.image = RuuviAssets.alertActiveImage } @@ -629,8 +629,8 @@ extension DashboardImageCell { private func highlightTemperatureValues(highlight: Bool) { temperatureLabel.textColor = - highlight ? RuuviColor.ruuviOrangeColor : RuuviColor.dashboardIndicatorBigTextColor + highlight ? RuuviColor.orangeColor.color : RuuviColor.dashboardIndicatorBig.color temperatureUnitLabel.textColor = - highlight ? RuuviColor.ruuviOrangeColor : RuuviColor.dashboardIndicatorBigTextColor + highlight ? RuuviColor.orangeColor.color : RuuviColor.dashboardIndicatorBig.color } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift index fd974bed6..75fece86e 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardIndicatorView.swift @@ -1,9 +1,10 @@ +import RuuviLocalization import UIKit class DashboardIndicatorView: UIView { private lazy var indicatorValueLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.dashboardIndicatorTextColor + label.textColor = RuuviColor.dashboardIndicator.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Montserrat(.bold, size: 14) @@ -13,7 +14,7 @@ class DashboardIndicatorView: UIView { private lazy var indicatorUnitLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.dashboardIndicatorTextColor + label.textColor = RuuviColor.dashboardIndicator.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Muli(.regular, size: 12) @@ -78,15 +79,15 @@ extension DashboardIndicatorView { func changeColor(highlight: Bool) { indicatorValueLabel.textColor = - highlight ? RuuviColor.ruuviOrangeColor : RuuviColor.dashboardIndicatorTextColor + highlight ? RuuviColor.orangeColor.color : RuuviColor.dashboardIndicator.color indicatorUnitLabel.textColor = - highlight ? RuuviColor.ruuviOrangeColor : RuuviColor.dashboardIndicatorTextColor + highlight ? RuuviColor.orangeColor.color : RuuviColor.dashboardIndicator.color } func clearValues() { indicatorValueLabel.text = nil indicatorUnitLabel.text = nil - indicatorValueLabel.textColor = RuuviColor.dashboardIndicatorTextColor - indicatorUnitLabel.textColor = RuuviColor.dashboardIndicatorTextColor + indicatorValueLabel.textColor = RuuviColor.dashboardIndicator.color + indicatorUnitLabel.textColor = RuuviColor.dashboardIndicator.color } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift index 226bd8784..a909756d5 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift @@ -8,7 +8,7 @@ import UIKit class DashboardPlainCell: UICollectionViewCell { private lazy var ruuviTagNameLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.dashboardIndicatorBigTextColor + label.textColor = RuuviColor.dashboardIndicatorBig.color label.textAlignment = .left label.numberOfLines = 1 label.font = UIFont.Montserrat(.bold, size: 14) @@ -19,7 +19,7 @@ class DashboardPlainCell: UICollectionViewCell { let iv = UIImageView() iv.contentMode = .scaleAspectFit iv.backgroundColor = .clear - iv.tintColor = RuuviColor.dashboardIndicatorBigTextColor + iv.tintColor = RuuviColor.dashboardIndicatorBig.color iv.alpha = 0 return iv }() @@ -38,7 +38,7 @@ class DashboardPlainCell: UICollectionViewCell { iv.contentMode = .scaleAspectFit iv.backgroundColor = .clear iv.image = RuuviAssets.threeDotMoreImage - iv.tintColor = RuuviColor.dashboardIndicatorBigTextColor + iv.tintColor = RuuviColor.dashboardIndicatorBig.color return iv }() @@ -62,7 +62,7 @@ class DashboardPlainCell: UICollectionViewCell { iv.backgroundColor = .clear iv.alpha = 0.7 iv.tintColor = RuuviColor - .dashboardIndicatorTextColor? + .dashboardIndicator.color .withAlphaComponent(0.8) return iv }() @@ -70,7 +70,7 @@ class DashboardPlainCell: UICollectionViewCell { private lazy var updatedAtLabel: UILabel = { let label = UILabel() label.textColor = RuuviColor - .dashboardIndicatorTextColor? + .dashboardIndicator.color .withAlphaComponent(0.8) label.textAlignment = .left label.numberOfLines = 0 @@ -107,7 +107,7 @@ class DashboardPlainCell: UICollectionViewCell { // swiftlint:disable:next function_body_length fileprivate func setUpUI() { let container = UIView( - color: RuuviColor.dashboardCardBGColor, + color: RuuviColor.dashboardCardBG.color, cornerRadius: 8 ) contentView.addSubview(container) @@ -482,11 +482,11 @@ extension DashboardPlainCell { alertIcon.image = RuuviAssets.alertOnImage removeAlertAnimations() } - alertIcon.tintColor = RuuviColor.logoTintColor + alertIcon.tintColor = RuuviColor.logoTintColor.color case .firing: alertButton.isUserInteractionEnabled = true alertIcon.alpha = 1.0 - alertIcon.tintColor = RuuviColor.ruuviOrangeColor + alertIcon.tintColor = RuuviColor.orangeColor.color if alertIcon.image != RuuviAssets.alertActiveImage { alertIcon.image = RuuviAssets.alertActiveImage } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift index a920b3106..4302bdc5c 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift @@ -76,7 +76,7 @@ class DashboardViewController: UIViewController { // UI private lazy var noSensorView: NoSensorView = { let view = NoSensorView() - view.backgroundColor = RuuviColor.dashboardCardBGColor + view.backgroundColor = RuuviColor.dashboardCardBG.color view.layer.cornerRadius = 12 view.clipsToBounds = true view.delegate = self @@ -92,14 +92,14 @@ class DashboardViewController: UIViewController { contentMode: .scaleAspectFit ) iv.backgroundColor = .clear - iv.tintColor = RuuviColor.logoTintColor + iv.tintColor = RuuviColor.logoTintColor.color return iv }() // Action Buttons private lazy var menuButton: UIButton = { let button = UIButton() - button.tintColor = RuuviColor.menuButtonTintColor + button.tintColor = RuuviColor.menuTintColor.color let menuImage = UIImage(named: "baseline_menu_white_48pt") button.setImage(menuImage, for: .normal) button.setImage(menuImage, for: .highlighted) @@ -115,10 +115,10 @@ class DashboardViewController: UIViewController { private lazy var viewButton: RuuviContextMenuButton = .init( menu: viewToggleMenuOptions(), - titleColor: RuuviColor.dashboardIndicatorTextColor, + titleColor: RuuviColor.dashboardIndicator.color, title: RuuviLocalization.view, icon: RuuviAssets.dropDownArrowImage, - iconTintColor: RuuviColor.logoTintColor, + iconTintColor: RuuviColor.logoTintColor.color, iconSize: .init(width: 14, height: 14), preccedingIcon: false ) @@ -140,7 +140,7 @@ class DashboardViewController: UIViewController { private lazy var refresher: UIRefreshControl = { let rc = UIRefreshControl() - rc.tintColor = RuuviColor.ruuviTintColor + rc.tintColor = RuuviColor.tintColor.color rc.layer.zPosition = -1 rc.alpha = 0 rc.addTarget(self, action: #selector(didPullToRefresh), for: .valueChanged) @@ -382,7 +382,7 @@ private extension DashboardViewController { } func setUpBaseView() { - view.backgroundColor = RuuviColor.dashboardBGColor + view.backgroundColor = RuuviColor.dashboardBG.color view.addSubview(noSensorView) noSensorView.anchor( diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift index 7bc284348..1708e9f93 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/LowBatteryView.swift @@ -5,7 +5,7 @@ class BatteryLevelView: UIView { private lazy var batteryLevelLabel: UILabel = { let label = UILabel() label.textColor = RuuviColor - .dashboardIndicatorTextColor? + .dashboardIndicator.color .withAlphaComponent(0.5) label.textAlignment = .right label.numberOfLines = 0 @@ -19,7 +19,7 @@ class BatteryLevelView: UIView { iv.contentMode = .scaleAspectFit iv.backgroundColor = .clear iv.image = UIImage(systemName: "battery.25") - iv.tintColor = RuuviColor.ruuviOrangeColor + iv.tintColor = RuuviColor.orangeColor.color return iv }() diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift index ce9c82765..e5c58ffa4 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift @@ -31,7 +31,7 @@ class NoSensorView: UIView { private lazy var messageLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .center label.numberOfLines = 0 label.font = UIFont.Muli(.semiBoldItalic, size: UIDevice.isiPhoneSE() ? 16 : 20) @@ -48,7 +48,7 @@ class NoSensorView: UIView { private lazy var signInButton: UIButton = { let button = UIButton( - color: RuuviColor.ruuviTintColor, + color: RuuviColor.tintColor.color, cornerRadius: UIDevice.isiPhoneSE() ? 20 : 25 ) button.setTitle( @@ -70,7 +70,7 @@ class NoSensorView: UIView { private lazy var addSensorButton: UIButton = { let button = UIButton( - color: RuuviColor.ruuviTintColor, + color: RuuviColor.tintColor.color, cornerRadius: UIDevice.isiPhoneSE() ? 20 : 25 ) button.setTitle( @@ -92,7 +92,7 @@ class NoSensorView: UIView { private lazy var buySensorButton: UIButton = { let button = UIButton() - button.setTitleColor(RuuviColor.ruuviTextColor, for: .normal) + button.setTitleColor(RuuviColor.textColor.color, for: .normal) button.setTitle( RuuviLocalization.DiscoverTable.GetMoreSensors.Button.title, for: .normal diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift index 71401485b..4b8ac6ba7 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewCell.swift @@ -1,9 +1,10 @@ +import RuuviLocalization import UIKit class ASSelectionTableViewCell: UITableViewCell { private lazy var titleLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .left label.numberOfLines = 1 label.font = UIFont.Muli(.regular, size: 16) @@ -28,7 +29,7 @@ class ASSelectionTableViewCell: UITableViewCell { fileprivate func setUpUI() { backgroundColor = .clear - tintColor = RuuviColor.ruuviTintColor + tintColor = RuuviColor.tintColor.color addSubview(titleLabel) titleLabel.anchor( @@ -52,8 +53,8 @@ extension ASSelectionTableViewCell { UIFont.Muli(.bold, size: 16) : UIFont.Muli(.regular, size: 16) titleLabel.textColor = isSelected ? - RuuviColor.ruuviMenuTextColor : - RuuviColor.ruuviTextColor + RuuviColor.menuTextColor.color : + RuuviColor.textColor.color accessoryType = isSelected ? .checkmark : .none } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift index c53442d60..26f0a1734 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/Selection/View/UI/ASSelectionTableViewController.swift @@ -1,4 +1,5 @@ import Foundation +import RuuviLocalization import UIKit class ASSelectionTableViewController: UITableViewController { @@ -41,7 +42,7 @@ extension ASSelectionTableViewController: ASSelectionViewInput { private extension ASSelectionTableViewController { func setUpUI() { - view.backgroundColor = RuuviColor.ruuviPrimary + view.backgroundColor = RuuviColor.primary.color setUpTableView() } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift index e344ce6af..c66f8bbf2 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewBasicCell.swift @@ -1,9 +1,10 @@ +import RuuviLocalization import UIKit class AppearanceSettingsTableViewBasicCell: UITableViewCell { private lazy var titleLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviMenuTextColor + label.textColor = RuuviColor.menuTextColor.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Muli(.bold, size: 16) @@ -12,7 +13,7 @@ class AppearanceSettingsTableViewBasicCell: UITableViewCell { private lazy var valueLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviMenuTextColor + label.textColor = RuuviColor.menuTextColor.color label.textAlignment = .right label.numberOfLines = 0 label.font = UIFont.Muli(.regular, size: 16) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift index 3c7882c9a..3cbd88277 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Appearance/View/UI/AppearanceSettingsTableViewController.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import Foundation import UIKit @@ -41,7 +42,7 @@ extension AppearanceSettingsTableViewController: AppearanceSettingsViewInput { private extension AppearanceSettingsTableViewController { func setUpUI() { - view.backgroundColor = RuuviColor.ruuviPrimary + view.backgroundColor = RuuviColor.primary.color setUpTableView() } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift index 135f15728..127314a5d 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift @@ -85,7 +85,7 @@ extension ChartSettingsTableViewController { override func tableView(_: UITableView, viewForFooterInSection section: Int) -> UIView? { let footerView = UIView() let footerLabel = UILabel() - footerLabel.textColor = RuuviColor.ruuviTextColor + footerLabel.textColor = RuuviColor.textColor.color footerLabel.font = UIFont.Muli(.regular, size: 13) footerLabel.numberOfLines = 0 footerLabel.text = viewModel.sections[section].note diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift index 6286107b7..344fc3229 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewCell.swift @@ -15,7 +15,7 @@ class DevicesTableViewCell: UITableViewCell { // UI private lazy var deviceNameLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.dashboardIndicatorBigTextColor + label.textColor = RuuviColor.dashboardIndicatorBig.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Montserrat(.bold, size: 14) @@ -24,7 +24,7 @@ class DevicesTableViewCell: UITableViewCell { private lazy var tokenIdLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.dashboardIndicatorTextColor + label.textColor = RuuviColor.dashboardIndicator.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Montserrat(.regular, size: 12) @@ -33,7 +33,7 @@ class DevicesTableViewCell: UITableViewCell { private lazy var lastAccessedLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.dashboardIndicatorTextColor + label.textColor = RuuviColor.dashboardIndicator.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Montserrat(.regular, size: 12) @@ -56,7 +56,7 @@ private extension DevicesTableViewCell { selectionStyle = .none let container = UIView( - color: RuuviColor.dashboardCardBGColor, + color: RuuviColor.dashboardCardBG.color, cornerRadius: 8 ) contentView.addSubview(container) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift index 67c160e24..db3860190 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Devices/View/UI/DevicesTableViewController.swift @@ -90,7 +90,7 @@ private extension DevicesTableViewController { } func setUpTableView() { - view.backgroundColor = RuuviColor.ruuviPrimary + view.backgroundColor = RuuviColor.primary.color tableView.showsVerticalScrollIndicator = false tableView.tableFooterView = UIView() tableView.estimatedRowHeight = UITableView.automaticDimension diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift index 4aad330ad..2e74ef82c 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift @@ -66,7 +66,7 @@ extension HeartbeatTableViewController { override func tableView(_: UITableView, viewForFooterInSection _: Int) -> UIView? { let footerView = UIView() let footerLabel = UILabel() - footerLabel.textColor = RuuviColor.ruuviTextColor + footerLabel.textColor = RuuviColor.textColor.color footerLabel.font = UIFont.Muli(.regular, size: 13) footerLabel.numberOfLines = 0 footerLabel.text = RuuviLocalization.Settings.BackgroundScanning.Footer.message diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift index 775ff356e..e90df097d 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewCell.swift @@ -1,9 +1,10 @@ +import RuuviLocalization import UIKit class PushAlertSelectionTableViewCell: UITableViewCell { private lazy var titleLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .left label.numberOfLines = 1 label.font = UIFont.Muli(.regular, size: 16) @@ -28,7 +29,7 @@ class PushAlertSelectionTableViewCell: UITableViewCell { fileprivate func setUpUI() { backgroundColor = .clear - tintColor = RuuviColor.ruuviTintColor + tintColor = RuuviColor.tintColor.color addSubview(titleLabel) titleLabel.anchor( @@ -52,8 +53,8 @@ extension PushAlertSelectionTableViewCell { UIFont.Muli(.bold, size: 16) : UIFont.Muli(.regular, size: 16) titleLabel.textColor = isSelected ? - RuuviColor.ruuviMenuTextColor : - RuuviColor.ruuviTextColor + RuuviColor.menuTextColor.color : + RuuviColor.textColor.color accessoryType = isSelected ? .checkmark : .none } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift index b7ada4f69..bd1fa978f 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/Selection/View/UI/PushAlertSoundSelectionTableViewController.swift @@ -1,5 +1,6 @@ import AVFoundation import Foundation +import RuuviLocalization import RuuviOntology import UIKit @@ -60,7 +61,7 @@ extension PushAlertSoundSelectionTableViewController: PushAlertSoundSelectionVie private extension PushAlertSoundSelectionTableViewController { func setUpUI() { - view.backgroundColor = RuuviColor.ruuviPrimary + view.backgroundColor = RuuviColor.primary.color setUpTableView() } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift index e0131e90a..336eb67fe 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsSwitchCell.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit protocol NotificationsSettingsSwitchCellDelegate: NSObjectProtocol { @@ -9,7 +10,7 @@ class NotificationsSettingsSwitchCell: UITableViewCell { private lazy var titleLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviMenuTextColor + label.textColor = RuuviColor.menuTextColor.color label.textAlignment = .left label.numberOfLines = 1 label.font = UIFont.Muli(.bold, size: 16) @@ -19,7 +20,7 @@ class NotificationsSettingsSwitchCell: UITableViewCell { private lazy var subtitleLabel: UILabel = { let label = UILabel() label.textColor = RuuviColor - .dashboardIndicatorTextColor? + .dashboardIndicator.color .withAlphaComponent(0.6) label.textAlignment = .left label.numberOfLines = 0 diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift index 300c701e3..92a80a0bd 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTableViewController.swift @@ -43,7 +43,7 @@ extension NotificationsSettingsTableViewController: NotificationsSettingsViewInp private extension NotificationsSettingsTableViewController { func setUpUI() { - view.backgroundColor = RuuviColor.ruuviPrimary + view.backgroundColor = RuuviColor.primary.color setUpTableView() } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift index 4b8fc5a53..7cd1fb1a9 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Notifications/View/UI/NotificationsSettingsTextCell.swift @@ -1,9 +1,10 @@ +import RuuviLocalization import UIKit class NotificationsSettingsTextCell: UITableViewCell { private lazy var titleLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviMenuTextColor + label.textColor = RuuviColor.menuTextColor.color label.textAlignment = .left label.numberOfLines = 1 label.font = UIFont.Muli(.bold, size: 16) @@ -13,7 +14,7 @@ class NotificationsSettingsTextCell: UITableViewCell { private lazy var subtitleLabel: UILabel = { let label = UILabel() label.textColor = RuuviColor - .dashboardIndicatorTextColor? + .dashboardIndicator.color .withAlphaComponent(0.6) label.textAlignment = .left label.numberOfLines = 0 @@ -23,7 +24,7 @@ class NotificationsSettingsTextCell: UITableViewCell { private lazy var valueLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviMenuTextColor + label.textColor = RuuviColor.menuTextColor.color label.textAlignment = .right label.numberOfLines = 1 label.font = UIFont.Muli(.regular, size: 16) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift index 7b1b8acd6..9d8399590 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewCell.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit protocol RuuviCloudTableViewCellDelegate: NSObjectProtocol { @@ -9,7 +10,7 @@ class RuuviCloudTableViewCell: UITableViewCell { private lazy var titleLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .left label.numberOfLines = 1 label.font = UIFont.Muli(.bold, size: 16) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift index 99188f8c1..9e860e057 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Ruuvi Cloud/View/UI/RuuviCloudTableViewController.swift @@ -46,7 +46,7 @@ extension RuuviCloudTableViewController: RuuviCloudViewInput { private extension RuuviCloudTableViewController { func setUpUI() { - view.backgroundColor = RuuviColor.ruuviPrimary + view.backgroundColor = RuuviColor.primary.color setUpTableView() } @@ -98,7 +98,7 @@ extension RuuviCloudTableViewController { override func tableView(_: UITableView, viewForFooterInSection _: Int) -> UIView? { let footerView = UIView() let footerLabel = UILabel() - footerLabel.textColor = RuuviColor.ruuviTextColor + footerLabel.textColor = RuuviColor.textColor.color footerLabel.font = UIFont.Muli(.regular, size: 13) footerLabel.numberOfLines = 0 footerLabel.text = RuuviLocalization.Settings.Label.CloudMode.description diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift index 3e7bcbd6b..8218c875f 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift @@ -136,11 +136,11 @@ extension SelectionTableViewController { ) { if title == viewModel?.selection { cell.accessoryType = .checkmark - cell.nameLabel.textColor = RuuviColor.ruuviMenuTextColor + cell.nameLabel.textColor = RuuviColor.menuTextColor.color cell.nameLabel.font = UIFont.Muli(.bold, size: 16) } else { cell.accessoryType = .none - cell.nameLabel.textColor = RuuviColor.ruuviTextColor + cell.nameLabel.textColor = RuuviColor.textColor.color cell.nameLabel.font = UIFont.Muli(.regular, size: 16) } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift index ee90bde01..4d5b14476 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift @@ -1,5 +1,6 @@ import RuuviLocalization import UIKit + extension ShareViewController { enum Section: Int { case addFriend = 0 @@ -88,7 +89,7 @@ class ShareViewController: UITableViewController { let section = Section(value: section) let headerView = UIView(color: .clear) let titleLabel = UILabel() - titleLabel.textColor = RuuviColor.ruuviMenuTextColor + titleLabel.textColor = RuuviColor.menuTextColor.color titleLabel.font = UIFont.Muli(.bold, size: 16) titleLabel.numberOfLines = 0 switch section { @@ -210,7 +211,7 @@ extension ShareViewController { let description = RuuviLocalization.ShareViewController.description cell.descriptionLabel.text = description.trimmingCharacters(in: .whitespacesAndNewlines) - cell.descriptionLabel.textColor = RuuviColor.ruuviTextColor + cell.descriptionLabel.textColor = RuuviColor.textColor.color return cell } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift index 14911f47f..107accc9c 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift @@ -75,7 +75,7 @@ class SignInBenefitsViewController: UIViewController, SignInBenefitsViewInput { private lazy var continueButton: UIButton = { let button = UIButton( - color: RuuviColor.ruuviTintColor, + color: RuuviColor.tintColor.color, cornerRadius: 25 ) button.setTitle( @@ -148,7 +148,7 @@ extension SignInBenefitsViewController { } private func setUpBase() { - view.backgroundColor = RuuviColor.ruuviPrimary + view.backgroundColor = RuuviColor.primary.color view.addSubview(bgLayer) bgLayer.fillSuperview() @@ -284,7 +284,7 @@ extension SignInBenefitsViewController { ) attrString.addAttribute( .foregroundColor, - value: RuuviColor.ruuviOrangeColor ?? UIColor.systemOrange, + value: RuuviColor.orangeColor.color, range: boldRange ) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift index fdd764b40..f633582a7 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInView.swift @@ -64,7 +64,7 @@ class SignInView: UIView { private lazy var requestCodeButton: UIButton = { let button = UIButton( - color: RuuviColor.ruuviTintColor, + color: RuuviColor.tintColor.color, cornerRadius: 25 ) button.setTitle( diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift index f352547b1..bda968102 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift @@ -186,7 +186,7 @@ extension SignInViewController { } private func setUpBase() { - view.backgroundColor = RuuviColor.ruuviPrimary + view.backgroundColor = RuuviColor.primary.color view.addSubview(bgLayer) bgLayer.fillSuperview() diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift index e897bf587..abea5d4e1 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift @@ -50,7 +50,8 @@ struct DFUUIView: View { ) } } - .background(Color(RuuviColor.ruuviPrimarySUI!).edgesIgnoringSafeArea(.all)) + .background(RuuviColor.primary.swiftUIColor) + .edgesIgnoringSafeArea(.all) .navigationBarTitle( texts.navigationTitle ) @@ -78,7 +79,7 @@ struct DFUUIView: View { return VStack(alignment: .leading, spacing: 16) { Text(texts.latestTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Spinner(isAnimating: true, style: .medium).eraseToAnyView() } .frame( @@ -96,13 +97,13 @@ struct DFUUIView: View { return VStack(alignment: .leading, spacing: 16) { Text(texts.latestTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) Text(latestRelease.version) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.currentTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) Spinner(isAnimating: true, style: .medium).eraseToAnyView() } .frame( @@ -117,13 +118,13 @@ struct DFUUIView: View { return VStack(alignment: .leading, spacing: 16) { Text(texts.latestTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) Text(latestRelease.version) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.currentTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) Spinner(isAnimating: true, style: .medium).eraseToAnyView() } .frame( @@ -137,21 +138,21 @@ struct DFUUIView: View { return VStack(alignment: .leading, spacing: 16) { Text(texts.latestTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) Text(latestRelease.version) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.currentTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) if let currentVersion = currentRelease?.version { Text(currentVersion) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) } else { Text(texts.notReportingDescription) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) } } .frame( @@ -165,7 +166,7 @@ struct DFUUIView: View { case let .noNeedToUpgrade(_, currentRelease): return Text(texts.alreadyOnLatest) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) .frame( maxWidth: .infinity, maxHeight: .infinity, @@ -179,21 +180,21 @@ struct DFUUIView: View { VStack(alignment: .leading, spacing: 16) { Text(texts.latestTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) Text(latestRelease.version) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.currentTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) if let currentVersion = currentRelease?.version { Text(currentVersion) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) } else { Text(texts.notReportingDescription) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) } Button( action: { @@ -210,7 +211,7 @@ struct DFUUIView: View { ) .buttonStyle( LargeButtonStyle( - backgroundColor: RuuviColor.ruuviTintColorSUI, + backgroundColor: RuuviColor.tintColor.swiftUIColor, foregroundColor: Color.white, isDisabled: false ) @@ -246,13 +247,13 @@ struct DFUUIView: View { return VStack(alignment: .center, spacing: 16) { Text(texts.downloadingTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) ProgressBar(value: $viewModel.downloadProgress) .frame(height: 16) .padding() Text("\(Int(viewModel.downloadProgress * 100))%") .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) } .frame( maxWidth: .infinity, @@ -269,25 +270,25 @@ struct DFUUIView: View { VStack(alignment: .leading, spacing: 16) { Text(texts.prepareTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) Text(texts.openCoverTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.localBootButtonTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.setUpdatingModeTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.toBootModeTwoButtonsDescription) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.toBootModeOneButtonDescription) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.toBootModeSuccessTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) } Button( action: {}, @@ -302,7 +303,7 @@ struct DFUUIView: View { ) .buttonStyle( LargeButtonStyle( - backgroundColor: RuuviColor.ruuviTintColorSUI, + backgroundColor: RuuviColor.tintColor.swiftUIColor, foregroundColor: Color.white, isDisabled: true ) @@ -328,25 +329,25 @@ struct DFUUIView: View { VStack(alignment: .leading, spacing: 16) { Text(texts.prepareTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) Text(texts.openCoverTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.localBootButtonTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.setUpdatingModeTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.toBootModeTwoButtonsDescription) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.toBootModeOneButtonDescription) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.toBootModeSuccessTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) } Button( action: { @@ -368,7 +369,7 @@ struct DFUUIView: View { ) .buttonStyle( LargeButtonStyle( - backgroundColor: RuuviColor.ruuviTintColorSUI, + backgroundColor: RuuviColor.tintColor.swiftUIColor, foregroundColor: Color.white, isDisabled: false ) @@ -389,17 +390,17 @@ struct DFUUIView: View { return VStack(alignment: .center, spacing: 24) { Text(texts.updatingTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) ProgressBar(value: $viewModel.flashProgress) .frame(height: 16) Text("\(Int(viewModel.flashProgress * 100))%") .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.doNotCloseTitle) .font(muliBold16) .bold() .multilineTextAlignment(.center) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) } .frame( maxWidth: .infinity, @@ -411,7 +412,7 @@ struct DFUUIView: View { case .successfulyFlashed: return Text(texts.updatingTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) .frame( maxWidth: .infinity, maxHeight: .infinity, @@ -422,7 +423,7 @@ struct DFUUIView: View { case .servingAfterUpdate: return Text(texts.updatingTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) .frame( maxWidth: .infinity, maxHeight: .infinity, @@ -434,7 +435,7 @@ struct DFUUIView: View { viewModel.storeUpdatedFirmware(currentRelease: currentRelease) return Text(texts.successfulTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) .frame( maxWidth: .infinity, maxHeight: .infinity, diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift index 44d9d3b19..9036507f8 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift @@ -18,7 +18,7 @@ class SensorForceClaimViewController: UIViewController { private lazy var messageLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .left label.numberOfLines = 0 label.text = RuuviLocalization.forceClaimSensorDescription1 @@ -28,7 +28,7 @@ class SensorForceClaimViewController: UIViewController { private lazy var claimSensorButton: UIButton = { let button = UIButton( - color: RuuviColor.ruuviTintColor, + color: RuuviColor.tintColor.color, cornerRadius: 25 ) button.setTitle(RuuviLocalization.forceClaim, for: .normal) @@ -43,7 +43,7 @@ class SensorForceClaimViewController: UIViewController { }() private lazy var sensorClaimNotesViewContainer: UIView = .init( - color: RuuviColor.ruuviPrimary + color: RuuviColor.primary.color ) private lazy var sensorClaimNotesView: UITextView = { let tv = UITextView() @@ -51,7 +51,7 @@ class SensorForceClaimViewController: UIViewController { tv.isEditable = false tv.textAlignment = .left tv.text = RuuviLocalization.forceClaimSensorDescription2 - tv.textColor = RuuviColor.ruuviTextColor + tv.textColor = RuuviColor.textColor.color tv.backgroundColor = .clear tv.font = UIFont.Muli(.regular, size: 16) tv.isScrollEnabled = true @@ -60,7 +60,7 @@ class SensorForceClaimViewController: UIViewController { private lazy var useNFCButton: UIButton = { let button = UIButton( - color: RuuviColor.ruuviTintColor, + color: RuuviColor.tintColor.color, cornerRadius: 25 ) button.setTitle( @@ -79,7 +79,7 @@ class SensorForceClaimViewController: UIViewController { private lazy var useBluetoothButton: UIButton = { let button = UIButton( - color: RuuviColor.ruuviTintColor, + color: RuuviColor.tintColor.color, cornerRadius: 25 ) button.setTitle( @@ -173,7 +173,7 @@ extension SensorForceClaimViewController { private func setUpBase() { title = RuuviLocalization.forceClaimSensor - view.backgroundColor = RuuviColor.ruuviPrimary + view.backgroundColor = RuuviColor.primary.color let backBarButtonItemView = UIView() backBarButtonItemView.addSubview(backButton) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift index e7d9f9ee9..8c9a6afb8 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift @@ -164,12 +164,12 @@ extension OffsetCorrectionAppleViewController: OffsetCorrectionViewInput { // make text color gray attrString.addAttribute( .foregroundColor, - value: RuuviColor.ruuviTextColor ?? UIColor.secondaryLabel, + value: RuuviColor.textColor.color, range: NSRange(location: 0, length: attrString.length) ) descriptionTextView.attributedText = attrString - descriptionTextView.textColor = RuuviColor.ruuviTextColor + descriptionTextView.textColor = RuuviColor.textColor.color } func showCalibrateDialog() { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift index a9009d4d8..ac7068648 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift @@ -13,7 +13,7 @@ final class OwnerViewController: UIViewController { private lazy var removeCloudHistoryTitleLabel: UILabel = { let label = UILabel() label.text = RuuviLocalization.removeCloudHistoryTitle - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Muli(.bold, size: 14) @@ -23,7 +23,7 @@ final class OwnerViewController: UIViewController { private lazy var removeCloudHistoryDescriptionLabel: UILabel = { let label = UILabel() label.text = RuuviLocalization.removeCloudHistoryDescription - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Muli(.regular, size: 14) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift index 12514a7c4..35b947ae6 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift @@ -18,7 +18,7 @@ class SensorRemovalViewController: UIViewController { private lazy var messageLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Muli(.regular, size: 16) @@ -29,7 +29,7 @@ class SensorRemovalViewController: UIViewController { private lazy var removeCloudHistoryTitleLabel: UILabel = { let label = UILabel() label.text = RuuviLocalization.removeCloudHistoryTitle - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Muli(.bold, size: 14) @@ -39,7 +39,7 @@ class SensorRemovalViewController: UIViewController { private lazy var removeCloudHistoryDescriptionLabel: UILabel = { let label = UILabel() label.text = RuuviLocalization.removeCloudHistoryDescription - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Muli(.regular, size: 14) @@ -54,7 +54,7 @@ class SensorRemovalViewController: UIViewController { private lazy var removeButton: UIButton = { let button = UIButton( - color: RuuviColor.ruuviTintColor, + color: RuuviColor.tintColor.color, cornerRadius: 25 ) button.setTitle(RuuviLocalization.remove, for: .normal) @@ -142,7 +142,7 @@ extension SensorRemovalViewController { private func setUpBase() { title = RuuviLocalization.TagSettings.ConfirmTagRemovalDialog.title - view.backgroundColor = RuuviColor.ruuviPrimary + view.backgroundColor = RuuviColor.primary.color let backBarButtonItemView = UIView() backBarButtonItemView.addSubview(backButton) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift index 7639fe97a..74dc3dc19 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit protocol RUAlertDetailsCellChildViewDelegate: NSObjectProtocol { @@ -22,7 +23,7 @@ class RUAlertDetailsCellChildView: UIView { let iv = UIImageView() iv.backgroundColor = .clear iv.image = RuuviAssets.editPenImage - iv.tintColor = RuuviColor.ruuviTintColor + iv.tintColor = RuuviColor.tintColor.color iv.contentMode = .scaleAspectFit return iv }() diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift index fa6b50c4e..d0095de03 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit protocol RUAlertExpandButtonDelegate: NSObjectProtocol { @@ -15,7 +16,7 @@ class RUAlertExpandButton: UIView { let iv = UIImageView() iv.backgroundColor = .clear iv.image = UIImage(named: "chevron.down") - iv.tintColor = RuuviColor.ruuviTintColor + iv.tintColor = RuuviColor.tintColor.color iv.contentMode = .scaleAspectFit return iv }() diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift index 1991de466..7cbefda37 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift @@ -75,10 +75,10 @@ class TagSettingsAlertConfigCell: UITableViewCell { slider.handleDiameter = 18 slider.enableStep = true slider.minDistance = 1 - slider.colorBetweenHandles = RuuviColor.ruuviTintColor - slider.handleColor = RuuviColor.ruuviTintColor + slider.colorBetweenHandles = RuuviColor.tintColor.color + slider.handleColor = RuuviColor.tintColor.color slider.backgroundColor = .clear - slider.tintColor = RuuviColor.ruuviTintColor?.withAlphaComponent(0.2) + slider.tintColor = RuuviColor.tintColor.color.withAlphaComponent(0.2) slider.hideLabels = true return slider }() @@ -134,7 +134,7 @@ extension TagSettingsAlertConfigCell { private func setUpUI() { contentView.isUserInteractionEnabled = true - backgroundColor = RuuviColor.ruuviPrimary + backgroundColor = RuuviColor.primary.color addSubview(noticeView) noticeView.anchor( @@ -191,7 +191,7 @@ extension TagSettingsAlertConfigCell { statusSwitch.centerYInSuperview() let statusSeparator = UIView() - statusSeparator.backgroundColor = RuuviColor.ruuviLineColor + statusSeparator.backgroundColor = RuuviColor.lineColor.color addSubview(statusSeparator) statusSeparator.anchor( top: statusContainerView.bottomAnchor, @@ -212,7 +212,7 @@ extension TagSettingsAlertConfigCell { ) let customDescriptionSeparator = UIView() - customDescriptionSeparator.backgroundColor = RuuviColor.ruuviLineColor + customDescriptionSeparator.backgroundColor = RuuviColor.lineColor.color addSubview(customDescriptionSeparator) customDescriptionSeparator.anchor( top: setCustomDescriptionView.bottomAnchor, diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift index c6810a81f..e43dadf1c 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBackgroundSelectionView.swift @@ -22,7 +22,7 @@ class TagSettingsBackgroundSelectionView: UIView { private lazy var cameraIconContainer: UIView = { let container = UIView( - color: RuuviColor.ruuviTintColor, + color: RuuviColor.tintColor.color, cornerRadius: 30 ) let cameraIconView = UIImageView() diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift index 1ef4b1a80..081c166c7 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit enum TagSettingsBasicAccessory { @@ -11,7 +12,7 @@ enum TagSettingsBasicAccessory { class TagSettingsBasicCell: UITableViewCell { lazy var titleLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .left label.numberOfLines = 1 label.font = UIFont.Muli(.bold, size: 14) @@ -20,7 +21,7 @@ class TagSettingsBasicCell: UITableViewCell { private lazy var valueLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .right label.numberOfLines = 1 label.font = UIFont.Muli(.regular, size: 14) @@ -35,7 +36,7 @@ class TagSettingsBasicCell: UITableViewCell { private var iconHiddenWidthConstraints: [NSLayoutConstraint] = [] - private lazy var separator = UIView(color: RuuviColor.ruuviLineColor) + private lazy var separator = UIView(color: RuuviColor.lineColor.color) override init( style: UITableViewCell.CellStyle, @@ -113,7 +114,7 @@ class TagSettingsBasicCell: UITableViewCell { switch type { case .pencil: iconView.image = RuuviAssets.editPenImage - iconView.tintColor = RuuviColor.ruuviTintColor + iconView.tintColor = RuuviColor.tintColor.color iconHiddenWidthConstraints.forEach { anchor in anchor.isActive = false } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift index 475eb6dd1..02096b71b 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift @@ -17,7 +17,7 @@ class TagSettingsExpandableSectionHeader: UIView { private lazy var titleLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.dashboardIndicatorTextColor + label.textColor = RuuviColor.dashboardIndicator.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Muli(.bold, size: 16) @@ -35,7 +35,7 @@ class TagSettingsExpandableSectionHeader: UIView { let label = UILabel() label.textAlignment = .center label.numberOfLines = 0 - label.textColor = RuuviColor.ruuviTextColor?.withAlphaComponent(0.7) + label.textColor = RuuviColor.textColor.color.withAlphaComponent(0.7) label.font = UIFont.Muli(.regular, size: 14) return label }() @@ -44,7 +44,7 @@ class TagSettingsExpandableSectionHeader: UIView { let iv = UIImageView() iv.backgroundColor = .clear iv.image = RuuviAssets.dropDownArrowImage - iv.tintColor = RuuviColor.ruuviTintColor + iv.tintColor = RuuviColor.tintColor.color iv.contentMode = .scaleAspectFit return iv }() @@ -53,7 +53,7 @@ class TagSettingsExpandableSectionHeader: UIView { private lazy var noValueLabel: UILabel = { let label = UILabel() label.text = RuuviLocalization.TagSettings.Label.NoValues.text - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .right label.numberOfLines = 0 label.font = UIFont.Muli(.regular, size: 12) @@ -63,11 +63,11 @@ class TagSettingsExpandableSectionHeader: UIView { private lazy var iconView: UIImageView = { let iv = UIImageView() iv.image = UIImage(systemName: "info.circle") - iv.tintColor = RuuviColor.ruuviTintColor + iv.tintColor = RuuviColor.tintColor.color return iv }() - lazy var seprator = UIView(color: RuuviColor.ruuviPrimary) + lazy var seprator = UIView(color: RuuviColor.primary.color) override init(frame: CGRect) { super.init(frame: frame) @@ -81,7 +81,7 @@ class TagSettingsExpandableSectionHeader: UIView { // swiftlint:disable:next function_body_length private func setUpUI() { - backgroundColor = RuuviColor.tagSettingsSectionHeaderColor + backgroundColor = RuuviColor.tagSettingsSectionHeaderColor.color addSubview(titleLabel) titleLabel.anchor( top: topAnchor, @@ -200,7 +200,7 @@ extension TagSettingsExpandableSectionHeader { if let color = backgroundColor { self.backgroundColor = color } else { - self.backgroundColor = RuuviColor.tagSettingsItemHeaderColor + self.backgroundColor = RuuviColor.tagSettingsItemHeaderColor.color } if let font { titleLabel.font = font @@ -250,12 +250,12 @@ extension TagSettingsExpandableSectionHeader { .shared .shortTimeString(from: date) alertIcon.image = RuuviAssets.alertOffImage - alertIcon.tintColor = RuuviColor.logoTintColor + alertIcon.tintColor = RuuviColor.logoTintColor.color return } else { mutedTillLabel.isHidden = true alertIcon.image = isOn ? RuuviAssets.alertOnImage : nil - alertIcon.tintColor = RuuviColor.logoTintColor + alertIcon.tintColor = RuuviColor.logoTintColor.color removeAlertAnimations() } @@ -267,11 +267,11 @@ extension TagSettingsExpandableSectionHeader { switch state { case .registered: alertIcon.image = RuuviAssets.alertOnImage - alertIcon.tintColor = RuuviColor.logoTintColor + alertIcon.tintColor = RuuviColor.logoTintColor.color removeAlertAnimations() case .firing: alertIcon.alpha = 1.0 - alertIcon.tintColor = RuuviColor.ruuviOrangeColor + alertIcon.tintColor = RuuviColor.orangeColor.color alertIcon.image = RuuviAssets.alertActiveImage DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { UIView.animate( diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift index 546217cd1..e998114c5 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsPlainCell.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit /// Leading title label and trailing aligned value label @@ -6,7 +7,7 @@ import UIKit class TagSettingsPlainCell: UITableViewCell { private lazy var titleLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .left label.numberOfLines = 1 label.font = UIFont.Muli(.regular, size: 14) @@ -15,7 +16,7 @@ class TagSettingsPlainCell: UITableViewCell { private lazy var valueLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .right label.numberOfLines = 1 label.font = UIFont.Muli(.regular, size: 14) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift index f19011c3f..d7e20e54c 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSimpleSectionHeader.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit protocol TagSettingsSimpleSectionHeaderDelegate: NSObjectProtocol {} @@ -8,7 +9,7 @@ class TagSettingsSimpleSectionHeader: UIView { private lazy var titleLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.dashboardIndicatorTextColor + label.textColor = RuuviColor.dashboardIndicator.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Muli(.bold, size: 18) @@ -26,7 +27,7 @@ class TagSettingsSimpleSectionHeader: UIView { } private func setUpUI() { - backgroundColor = RuuviColor.tagSettingsSectionHeaderColor + backgroundColor = RuuviColor.tagSettingsSectionHeaderColor.color addSubview(titleLabel) titleLabel.fillSuperviewToSafeArea( padding: .init(top: 8, left: 8, bottom: 8, right: 8)) @@ -42,7 +43,7 @@ class TagSettingsSimpleSectionHeader: UIView { if let color = backgroundColor { self.backgroundColor = color } else { - self.backgroundColor = RuuviColor.tagSettingsSectionHeaderColor + self.backgroundColor = RuuviColor.tagSettingsSectionHeaderColor.color } } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift index ebcf00450..df2a77933 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsSwitchCell.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit protocol TagSettingsSwitchCellDelegate: NSObjectProtocol { @@ -9,7 +10,7 @@ class TagSettingsSwitchCell: UITableViewCell { private lazy var titleLabel: UILabel = { let label = UILabel() - label.textColor = RuuviColor.ruuviTextColor + label.textColor = RuuviColor.textColor.color label.textAlignment = .left label.numberOfLines = 0 label.font = UIFont.Muli(.bold, size: 14) @@ -18,7 +19,7 @@ class TagSettingsSwitchCell: UITableViewCell { private lazy var pairingAnimationView: UIActivityIndicatorView = { let activityIndicator = UIActivityIndicatorView(style: .medium) - activityIndicator.tintColor = RuuviColor.ruuviTintColor + activityIndicator.tintColor = RuuviColor.tintColor.color return activityIndicator }() @@ -29,7 +30,7 @@ class TagSettingsSwitchCell: UITableViewCell { return toggle }() - lazy var seprator = UIView(color: RuuviColor.ruuviLineColor) + lazy var seprator = UIView(color: RuuviColor.lineColor.color) override init( style: UITableViewCell.CellStyle, diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift index 763ce9153..d7ac9ae34 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift @@ -2607,7 +2607,7 @@ extension TagSettingsViewController { cells: offsetCorrectionItems, collapsed: true, headerType: .expandable, - backgroundColor: RuuviColor.tagSettingsSectionHeaderColor, + backgroundColor: RuuviColor.tagSettingsSectionHeaderColor.color, font: UIFont.Muli(.bold, size: 18) ) return section @@ -2847,7 +2847,7 @@ extension TagSettingsViewController { ], collapsed: true, headerType: .expandable, - backgroundColor: RuuviColor.tagSettingsSectionHeaderColor, + backgroundColor: RuuviColor.tagSettingsSectionHeaderColor.color, font: UIFont.Muli(.bold, size: 18) ) return section @@ -3045,7 +3045,7 @@ extension TagSettingsViewController { if let batteryLow { // swiftlint:disable:next line_length let batteryStatus = batteryLow ? "(\(RuuviLocalization.TagSettings.BatteryStatusLabel.Replace.message))" : "(\(RuuviLocalization.TagSettings.BatteryStatusLabel.Ok.message))" - let indicatorColor = batteryLow ? .red : RuuviColor.ruuviTintColor + let indicatorColor = batteryLow ? .red : RuuviColor.tintColor.color return (status: batteryStatus, color: indicatorColor) } else { return (status: nil, color: nil) @@ -3095,7 +3095,7 @@ extension TagSettingsViewController { ], collapsed: true, headerType: .expandable, - backgroundColor: RuuviColor.tagSettingsSectionHeaderColor, + backgroundColor: RuuviColor.tagSettingsSectionHeaderColor.color, font: UIFont.Muli(.bold, size: 18) ) return section @@ -3149,7 +3149,7 @@ extension TagSettingsViewController { ], collapsed: true, headerType: .expandable, - backgroundColor: RuuviColor.tagSettingsSectionHeaderColor, + backgroundColor: RuuviColor.tagSettingsSectionHeaderColor.color, font: UIFont.Muli(.bold, size: 18) ) return section @@ -3524,7 +3524,7 @@ private extension TagSettingsViewController { func setUpUI() { title = RuuviLocalization.TagSettings.NavigationItem.title - view.backgroundColor = RuuviColor.ruuviPrimary + view.backgroundColor = RuuviColor.primary.color let backBarButtonItemView = UIView() backBarButtonItemView.addSubview(backButton) diff --git a/Apps/RuuviStation/Sources/Extensions/Classess/RuuviLinkTextView.swift b/Apps/RuuviStation/Sources/Extensions/Classess/RuuviLinkTextView.swift index 4b02184d5..7f09b9670 100644 --- a/Apps/RuuviStation/Sources/Extensions/Classess/RuuviLinkTextView.swift +++ b/Apps/RuuviStation/Sources/Extensions/Classess/RuuviLinkTextView.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit protocol RuuviLinkTextViewDelegate: NSObjectProtocol { @@ -6,9 +7,9 @@ protocol RuuviLinkTextViewDelegate: NSObjectProtocol { class RuuviLinkTextView: UITextView { private var textRegularColor: UIColor? = RuuviColor - .dashboardIndicatorTextColor? + .dashboardIndicator.color .withAlphaComponent(0.6) - private var textLinkColor: UIColor? = RuuviColor.ruuviTextColor + private var textLinkColor: UIColor? = RuuviColor.textColor.color private var fullTextString: String? private var linkString: String? private var link: String? @@ -16,8 +17,8 @@ class RuuviLinkTextView: UITextView { weak var linkDelegate: RuuviLinkTextViewDelegate? convenience init( - textColor: UIColor? = RuuviColor.dashboardIndicatorTextColor?.withAlphaComponent(0.6), - linkColor: UIColor? = RuuviColor.ruuviTextColor, + textColor: UIColor? = RuuviColor.dashboardIndicator.color.withAlphaComponent(0.6), + linkColor: UIColor? = RuuviColor.textColor.color, fullTextString: String?, linkString: String?, link: String? diff --git a/Apps/RuuviStation/Sources/Extensions/Classess/RuuviUISwitch.swift b/Apps/RuuviStation/Sources/Extensions/Classess/RuuviUISwitch.swift index b4864ee02..3f561699d 100644 --- a/Apps/RuuviStation/Sources/Extensions/Classess/RuuviUISwitch.swift +++ b/Apps/RuuviStation/Sources/Extensions/Classess/RuuviUISwitch.swift @@ -1,9 +1,9 @@ +import RuuviLocalization import UIKit class RuuviUISwitch: UISwitch { - private let activeThumbColor: UIColor? = - RuuviColor.ruuviTintColor - private let inactiveThumbColor: UIColor? = RuuviColor.ruuviSwitchDisabledThumbTint + private let activeThumbColor: UIColor? = RuuviColor.tintColor.color + private let inactiveThumbColor: UIColor? = RuuviColor.switchDisabledThumbTint.color override init(frame: CGRect) { super.init(frame: frame) diff --git a/Apps/RuuviStation/Sources/Extensions/Color+Ruuvi.swift b/Apps/RuuviStation/Sources/Extensions/Color+Ruuvi.swift deleted file mode 100644 index 2b2e19a89..000000000 --- a/Apps/RuuviStation/Sources/Extensions/Color+Ruuvi.swift +++ /dev/null @@ -1,16 +0,0 @@ -import UIKit - -extension UIColor { - static var normalButtonBackground: UIColor { - UIColor( - red: 21.0 / 255, - green: 141.0 / 255, - blue: 165.0 / 255, - alpha: 1 - ) - } - - static var disableButtonBackground: UIColor { - UIColor.darkGray - } -} diff --git a/Apps/RuuviStation/target.yml b/Apps/RuuviStation/target.yml index d897952f5..c1a2e69df 100644 --- a/Apps/RuuviStation/target.yml +++ b/Apps/RuuviStation/target.yml @@ -9,11 +9,6 @@ targets: excludes: - "*.entitlements" - Info.plist - # - path: Widgets/Sources/Widgets.entitlements - # name: Widgets - # - path: Intents/Sources/Intents.entitlements - # name: Intents - # - path: NotificationService/Sources/NotificationService.entitlements dependencies: - target: "station.widgets" - target: "station.intents" @@ -107,18 +102,6 @@ targets: EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" CODE_SIGN_IDENTITY: "iPhone Distribution" PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station" - preBuildScripts: - - path: ../../scripts/build/generate_l10n.sh - name: Generate L10N - inputFiles: - - $(SRCROOT)/station.localization/station.localization.json - outputFiles: - - $(SRCROOT)/Apps/RuuviStation/Sources/Resources/Strings/en.lproj/Localizable.strings - - $(SRCROOT)/Apps/RuuviStation/Sources/Resources/Strings/sv.lproj/Localizable.strings - - $(SRCROOT)/Apps/RuuviStation/Sources/Resources/Strings/ru.lproj/Localizable.strings - - $(SRCROOT)/Apps/RuuviStation/Sources/Resources/Strings/fi.lproj/Localizable.strings - - $(SRCROOT)/Apps/RuuviStation/Sources/Resources/Strings/fr.lproj/Localizable.strings - - $(SRCROOT)/Apps/RuuviStation/Sources/Resources/Strings/de.lproj/Localizable.strings postCompileScripts: - path: ../../scripts/build/lint.sh name: Lint diff --git a/Common/RuuviLocalization/.gitignore b/Common/RuuviLocalization/.gitignore index bb460e7be..1eacdd81b 100644 --- a/Common/RuuviLocalization/.gitignore +++ b/Common/RuuviLocalization/.gitignore @@ -5,3 +5,6 @@ xcuserdata/ DerivedData/ .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +RuuviLocalization.swift +RuuviColor.swift +Localizable.strings \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardBG.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/DashboardBG.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardBG.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/DashboardBG.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardCardBG.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/DashboardCardBG.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardCardBG.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/DashboardCardBG.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardIndicator.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/DashboardIndicator.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardIndicator.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/DashboardIndicator.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardIndicatorBig.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/DashboardIndicatorBig.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDashboardIndicatorBig.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/DashboardIndicatorBig.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDustyBlue.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/DustyBlue.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviDustyBlue.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/DustyBlue.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphBGColor.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/GraphBGColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphBGColor.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/GraphBGColor.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphFillColor.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/GraphFillColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphFillColor.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/GraphFillColor.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphLineColor.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/GraphLineColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphLineColor.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/GraphLineColor.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphMarkerColor.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/GraphMarkerColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGraphMarkerColor.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/GraphMarkerColor.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGreen.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/Green.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviGreen.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/Green.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviLineColor.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/LineColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviLineColor.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/LineColor.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviLogoTintColor.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/LogoTintColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviLogoTintColor.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/LogoTintColor.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviMenuTextColor.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/MenuTextColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviMenuTextColor.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/MenuTextColor.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviMenuTintColor.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/MenuTintColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviMenuTintColor.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/MenuTintColor.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviOrangeColor.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/OrangeColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviOrangeColor.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/OrangeColor.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviPrimary.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/Primary.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviPrimary.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/Primary.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviPurple.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/Purple.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviPurple.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/Purple.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSecondary.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/Secondary.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSecondary.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/Secondary.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSwitchDisabledThumbTint.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/SwitchDisabledThumbTint.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSwitchDisabledThumbTint.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/SwitchDisabledThumbTint.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSwitchDisabledTint.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/SwitchDisabledTint.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSwitchDisabledTint.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/SwitchDisabledTint.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSwitchEnabledTint.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/SwitchEnabledTint.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviSwitchEnabledTint.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/SwitchEnabledTint.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/TagSettingsItemHeaderColor.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/TagSettingsItemHeaderColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/TagSettingsItemHeaderColor.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/TagSettingsItemHeaderColor.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/TagSettingsSectionHeaderColor.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/TagSettingsSectionHeaderColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/TagSettingsSectionHeaderColor.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/TagSettingsSectionHeaderColor.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviTextColor.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/TextColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviTextColor.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/TextColor.colorset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviTintColor.colorset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/TintColor.colorset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Colors/Colors.xcassets/RuuviTintColor.colorset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets/TintColor.colorset/Contents.json diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/de.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/de.lproj/Localizable.strings deleted file mode 100644 index 3be9a37ef..000000000 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/de.lproj/Localizable.strings +++ /dev/null @@ -1,772 +0,0 @@ -// swiftlint:disable all -// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen -"Done" = "Fertig"; -"Copy" = "Kopieren"; -"Confirm" = "Bestätige"; -"Remove" = "Löschen"; -"N/A" = "-"; -"g" = "g"; -"About.Version.text" = "Version"; -"Background.PresentNotifications.title" = "Zeige Benachrichtigungen"; -"Background.KeepConnection.title" = " Verbindung behalten"; -"Background.Interval.Every.string" = "Jeder"; -"Background.Interval.Min.string" = "min"; -"Background.readRSSITitle.title" = "Lese RSSI"; -"BluetoothError.disconnected" = "Getrennt"; -"Cards.BluetoothDisabledAlert.title" = "Bluetooth ist nicht aktiviert"; -"Cards.BluetoothDisabledAlert.message" = "Ruuvi Station benötigt Bluetooth, um Sensoren zu verbinden. Gehe zu Einstellungen und schalte Bluetooth ein."; -"Cards.WebTagAPILimitExcededError.Alert.title" = "Zu viele Anfragen"; -"Cards.WebTagAPILimitExcededError.Alert.message" = "Versuche es in 5 minuten nochmal"; -"Cards.KeepConnectionDialog.message" = "Scheint, als ob Sie eine verbindbare Firmware auf Ihrem Ruuvi-Gerät ausführen. Möchten Sie die Verbindung zu diesem Ruuvi-Gerät im Hintergrund offen halten? Dadurch können Histogramme und Warnungen auch dann angezeigt werden, wenn die Anwendung minimiert ist."; -"Cards.KeepConnectionDialog.Dismiss.title" = "Abbrechen"; -"Cards.KeepConnectionDialog.KeepConnection.title" = "Verbindung aufrecht erhalten"; -"Cards.LegacyFirmwareUpdateDialog.message" = "Scheint, dass Ihr Sensor eine alte Firmware-Softwareversion verwendet. Um auf neue Funktionen wie Verlaufsdiagramme, Warnungen und Cloud-Dienste zugreifen zu können, ist eine Aktualisierung obligatorisch."; -"Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message" = "Bist du sicher? Ohne Aktualisierung können Sie den Besitz des Sensors nicht beanspruchen, Verlaufsdiagramme herunterladen und Warnungen einstellen. Das Update enthält auch Fehlerbehebungen. Wenn Sie jetzt abbrechen, können Sie den Update-Vorgang erneut von der Einstellungsseite des Sensors starten."; -"Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title" = "Überprüfe auf Updates"; -"Cards.Connected.title" = "Verbunden"; -"Cards.Error.ReverseGeocodingFailed.message" = "Fehler beim Laden der Daten für den virtuellen Sensor. Das Betriebslimit für umgekehrte Geokodierung wurde überschritten."; -"Cards.UpdatedLabel.NoData.message" = "Keine Daten in den letzten 10 Tagen"; -"CoreError.failedToGetPngRepresentation" = "PNG-Darstellung konnte nicht abgerufen werden"; -"CoreError.failedToGetDocumentsDirectory" = "Fehler beim Abrufen des Hintergrundverzeichnisses"; -"CoreError.failedToGetCurrentLocation" = "Fehler beim Abrufen des aktuellen Standorts"; -"CoreError.failedToGetDataFromResponse" = "Fehler beim Abrufen der Daten"; -"CoreError.locationPermissionDenied" = "Fehlende Berechtigung für Ortungsdienste"; -"CoreError.locationPermissionNotDetermined" = "Autorisierungsstatus der Standortberechtigung ist unbestimmt"; -"CoreError.objectNotFound" = "Objekt nicht gefunden"; -"CoreError.objectInvalidated" = "Objekt ungültig"; -"CoreError.unableToSendEmail" = "Email kann nicht gesendet werden"; -"Defaults.navigationItem.title" = "Standardeinstellungen"; -"Defaults.WelcomeShown.title" = "Willkommen angezeigt"; -"Defaults.ChartsSwipeInstructionWasShown.title" = "Charts-Swipe-Hinweis wurde angezeigt"; -"Defaults.Interval.Sec.string" = "sek"; -"Defaults.Interval.Min.string" = "min"; -"Defaults.ConnectionTimeout.title" = "Verbindungszeitüberschreitung"; -"Defaults.ServiceTimeout.title" = "Service Unterbrechung"; -"Defaults.CardsSwipeHint.title" = "Karten-Swipe-Hinweis wurde angezeigt"; -"Defaults.AlertsRepeatInterval.title" = "Benachrichtigungsintervall"; -"Defaults.WebPullInterval.title" = "Intervall für Web-Benachrichtigungen"; -"Defaults.PruningOffsetHours.title" = "Versatzstunden beschneiden"; -"Defaults.Interval.Hour.string" = "h"; -"Defaults.ChartDurationHours.title" = "Diagrammdauer"; -"Defaults.AppLaunchRequiredForReview.Count.title" = "Anzahl der App-Starts, um zum ersten Mal eine Überprüfung anzufordern"; -"Defaults.AskReviewIfLaunchDivisibleBy.Count.title" = "Überprüfung fragen, ob App-Start teilbar durch"; -"DiscoverTable.SectionTitle.WebTags" = "Virtuelle Sensoren"; -"DiscoverTable.BluetoothDisabledAlert.title" = "Bluetooth ist nicht aktiviert"; -"DiscoverTable.BluetoothDisabledAlert.message" = "Die Ruuvi Station benötigt Bluetooth, um die Sensoren zu verbinden. Gehen Sie zu Einstellungen und schalten Sie Bluetooth ein."; -"DiscoverTable.NavigationItem.title" = "Neuen Sensor hinzufügen"; -"DiscoverTable.GetMoreSensors.button.title" = "Ruuvi Sensoren kaufen"; -"DiscoverTable.NoDevicesSection.NotFound.text" = "(Keine Sensoren in Bluetooth-Reichweite)"; -"DiscoverTable.NoDevicesSection.BluetoothDisabled.text" = "(Bluetooth ist deaktiviert)"; -"DiscoverTable.WebTagsInfoDialog.message" = "Virtuelle Sensoren zeigen öffentliche Wetterdaten an, die von lokalen Wetterstationen bereitgestellt werden."; -"DiscoverTable.RuuviDevice.prefix" = "Ruuvi"; -"ErrorPresenterAlert.Error" = "Fehler"; -"ErrorPresenterAlert.OK" = "OK"; -"ExpectedError.missingOpenWeatherMapAPIKey" = "Fehlender OpenWeatherMap-API-Schlüssel. Bitte holen Sie einen von openweathermap.org und fügen Sie sie diesen in die Datei station/Classes/Networking/Assembly/Networking.plist ein"; -"ExpectedError.isAlreadySyncingLogsWithThisTag" = "Die App ist bereits dabei, Protokolle mit diesem Sensor zu synchronisieren"; -"ExpectedError.failedToDeleteTag" = "Das nicht erreichbare Gerät kann nicht entfernt werden. Bitte überprüfen Sie Ihre Bluetooth-Verbindung."; -"ExportService.Date" = "Datum"; -"ExportService.ISO8601" = "ISO8601"; -"ExportService.Temperature" = "Temperatur (%@)"; -"ExportService.Humidity" = "Feuchtigkeit (%@)"; -"ExportService.DewPoint" = "Taupunkt (%@)"; -"ExportService.Pressure" = "Druck (%@)"; -"ExportService.Voltage" = "Spannung (V)"; -"ExportService.MovementCounter" = "Bewegungszähler"; -"ExportService.MeasurementSequenceNumber" = "Messsequenznummer"; -"ExportService.TXPower" = "TX-Leistung"; -"ForegroundRow.advertisement.section" = "ANZEIGE"; -"ForegroundRow.advertisement.title" = "Werbung speichern"; -"ForegroundRow.connection.section" = "PROTOKOLL"; -"ForegroundRow.connection.title" = "Protokolle verbinden und synchronisieren"; -"Foreground.navigationItem.title" = "Vordergrund"; -"Foreground.Interval.Every.string" = "Jeder"; -"Foreground.Interval.Min.string" = "min"; -"ForegroundRow.webTags.title" = "Laden und speichern aus dem Web"; -"ForegroundRow.webTags.section" = "VIRTUELLE SENSOREN"; -"Foreground.Interval.All.string" = "Alle"; -"Heartbeat.Interval.Every.string" = "jeder"; -"Heartbeat.Interval.Min.string" = "min"; -"Heartbeat.readRSSITitle.title" = "Lese RSSI"; -"Heartbeat.Interval.Sec.string" = "sek"; -"Heartbeat.Interval.All.string" = "Alle"; -"HumidityCalibration.ClearCalibrationConfirmationAlert.title" = "Sind Sie sicher?"; -"HumidityCalibration.ClearCalibrationConfirmationAlert.message" = "Feuchtigkeits-Offset wird gelöscht. Dies kann nicht rückgängig gemacht werden. Tippen Sie auf \"Bestätigen\", um fortzufahren."; -"HumidityCalibration.CalibrationConfirmationAlert.title" = "Sind Sie sicher?"; -"HumidityCalibration.CalibrationConfirmationAlert.message" = "Feuchtigkeits-Offset wird kalibriert. Tippen Sie auf \"Bestätigen\", um fortzufahren."; -"Language.English" = "Englisch"; -"Language.Finnish" = "Suomi"; -"Language.Russian" = "Русский"; -"Language.Swedish" = "Svenska"; -"Language.French" = "Français"; -"Language.German" = "Deutsch"; -"LocalNotificationsManager.DidConnect.title" = "Verbunden"; -"LocalNotificationsManager.DidDisconnect.title" = "Unterbrochen"; -"LocalNotificationsManager.Disable.button" = "Ausschalten"; -"LocalNotificationsManager.LowDewPoint.title" = "Taupunkt ist zu niedrig!"; -"LocalNotificationsManager.HighDewPoint.title" = "Taupunkt ist zu hoch!,"; -"PermissionPresenter.NoPhotoLibraryAccess.message" = "Ruuvi Station muss auf Ihre Kamera zugreifen, um diese Funktion zu aktivieren."; -"PermissionPresenter.NoCameraAccess.message" = "Ruuvi Station muss auf Ihre Kamera zugreifen, um diese Funktion zu aktivieren."; -"PermissionPresenter.NoLocationAccess.message" = "Ruuvi Station muss auf Ihren Standort zugreifen, um diese Funktion zu aktivieren."; -"PermissionPresenter.settings" = "Einstellungen"; -"PermissionPresenter.NoPushNotificationsPermission.message" = "Ruuvi Station benötigt die Berechtigung für Push-Benachrichtigungen, um diese Funktion zu aktivieren."; -"PhotoPicker.Sheet.message" = "Wähle ein Foto"; -"PhotoPicker.Sheet.library" = "Aus der Bibliothek auswählen"; -"PhotoPicker.Sheet.camera" = "Foto aufnehmen"; -"Settings.SegmentedControl.Humidity.Relative.title" = "Rel"; -"Settings.SegmentedControl.Humidity.Absolute.title" = "Abs"; -"Settings.SegmentedControl.Humidity.DewPoint.title" = "Tau"; -"Settings.Label.Language.text" = "Sprache"; -"Settings.Language.Dialog.title" = "Sprache auswählen"; -"Settings.Language.Dialog.message" = "Öffnen Sie die Einstellungen und tippen Sie auf Sprache, um die Sprache der App zu ändern. Wenn Sie die Option Sprache in den Einstellungen nicht sehen können, stellen Sie sicher, dass Sie mindestens eine bevorzugte Sprache in den Systemeinstellungen hinzugefügt haben: Einstellungen -> Allgemein -> Sprache & Region."; -"Settings.Label.Foreground" = "Vordergrund"; -"Settings.Label.Defaults" = "Standardeinstellungen"; -"OWMError.failedToParseOpenWeatherMapResponse" = "Fehler beim Parsen der Open Weather Map-Antwort"; -"OWMError.apiLimitExceeded" = "API-Limit überschritten"; -"OWMError.notAHttpResponse" = "Keine HTTP-Antwort"; -"OWMError.invalidApiKey" = "Ungültiger API-Schlüssel"; -"TagCharts.NoChartData.text" = "Keine Kartendaten verfügbar"; -"TagCharts.BluetoothDisabledAlert.title" = "Bluetooth ist nicht aktiviert"; -"TagCharts.BluetoothDisabledAlert.message" = "Die Ruuvi Station benötigt Bluetooth, um Sensoren zu verbinden. Gehen Sie zu Einstellungen und schalten Sie Bluetooth ein."; -"TagCharts.Clear.title" = "Löschen"; -"TagCharts.SyncConfirmationDialog.title" = "Sind Sie sicher?"; -"TagCharts.DeleteHistoryConfirmationDialog.button.delete.title" = "Löschen"; -"TagCharts.DeleteHistoryConfirmationDialog.title" = "Sind Sie sicher?"; -"TagCharts.Status.Disconnecting" = "Trennen..."; -"TagCharts.Status.Success" = "Erfolgreich"; -"TagCharts.Status.Error" = "Fehler"; -"TagSettings.UUID.Alert.title" = "UUID"; -"TagSettings.UpdateFirmware.Alert.title" = "RAWv2-Modus ist erforderlich"; -"TagSettings.UpdateFirmware.Alert.message" = "Um fehlende Werte anzuzeigen:\n Wenn Sie die neueste Firmware verwenden, stellen Sie den RAWv2-Modus ein, indem Sie auf einem Sensor \"B\" drücken.\ oder aktualisieren Sie Ihren Sensor mit der neuesten Firmware."; -"TagSettings.UpdateFirmware.Alert.Buttons.LearnMore.title" = "Mehr erfahren"; -"TagCharts.Dismiss.Alert.message" = "Der Download des Protokolls über die Bluetooth-Verbindung wird gerade durchgeführt. Bitte warten Sie."; -"TagCharts.AbortSync.Alert.message" = "Manchmal ist der Download des Protokolls aufgrund der Bluetooth-Verbindung langsam. Bitte warten Sie einen Moment."; -"TagCharts.AbortSync.Button.title" = "Download abbrechen"; -"TagSettings.EmptyValue.sign" = "-"; -"TagSettings.HumidityIsClipped.Alert.title" = "Luftfeuchtigkeit wird angepasst"; -"TagSettings.HumidityIsClipped.Alert.message" = "Der Feuchtigkeitswert ist nach der Kalibrierung größer als 100 %. Dieser Wert ist nicht sinnvoll, daher wird der Wert auf 100 % angepasst."; -"TagSettings.HumidityIsClipped.Alert.Fix.button" = "Reparieren"; -"TagSettings.navigationItem.title" = "Sensoreinstellungen"; -"TagSettings.tagNameTitleLabel.text" = "Name"; -"TagSettings.humidityTitleLabel.text" = "Feuchtigkeit"; -"TagSettings.uuidTitleLabel.text" = "UUID"; -"TagSettings.macAddressTitleLabel.text" = "MAC-Adresse"; -"TagSettings.dataFormatTitleLabel.text" = "Datei Format"; -"TagSettings.accelerationXTitleLabel.text" = "Beschleunigung X"; -"TagSettings.accelerationYTitleLabel.text" = "Beschleunigung Y"; -"TagSettings.accelerationZTitleLabel.text" = "Beschleunigung Z"; -"TagSettings.txPowerTitleLabel.text" = "Sendeleistung"; -"TagSettings.mcTitleLabel.text" = "Bewegungszähler"; -"TagSettings.msnTitleLabel.text" = "Messsequenznummer"; -"TagSettings.SectionHeader.Remove.title" = "LÖSCHEN"; -"TagSettings.Label.noValues.text" = "KEINE WERTE?"; -"TagSettings.SectionHeader.Calibration.title" = "KALIBRIERUNG"; -"TagSettings.SectionHeader.BTConnection.title" = "BLUETOOTH VERBINDUNG"; -"TagSettings.PairAndBackgroundScan.Unpaired.title" = "Koppeln und Hintergrundsuche verwenden"; -"TagSettings.PairAndBackgroundScan.Pairing.title" = "Anschließen an den Sensor"; -"TagSettings.PairAndBackgroundScan.Paired.title" = "Gekoppelt und aktiviert"; -"TagSettings.PairAndBackgroundScan.description" = "Warnungen sind über die Bluetooth-Verbindung nicht verfügbar, wenn die Hintergrundsuche nicht aktiviert ist. Es kann jeweils nur ein iOS-Gerät mit einem Ruuvi-Sensor gekoppelt werden."; -"TagSettings.PairError.CloudMode.description" = "Der Sensor kann nicht über Bluetooth verbunden werden, wenn der Cloud-Modus aktiv ist. Sie können die Bluetooth-Verbindung für die Cloud-Sensoren wieder aktivieren, indem Sie den Cloud-Modus in den App-Einstellungen deaktivieren."; -"TagSettings.PairError.Timeout.description" = "Die Verbindung wurde unterbrochen. Das Pairing war nicht erfolgreich. Bitte versuchen Sie es erneut."; -"TagSettings.dataSourceTitleLabel.text" = "Daten empfangen über"; -"TagSettings.DataSource.Heartbeat.title" = "Herzschlag"; -"TagSettings.DataSource.Advertisement.title" = "Advertisement"; -"TagSettings.DataSource.Network.title" = "Cloud"; -"TagSettings.Label.disabled.text" = "AUSGESCHALTEN?"; -"TagSettings.AlertsAreDisabled.Dialog.BothNotConnectedAndNoPNPermission.message" = "Warnungen sind deaktiviert, weil das Gerät nicht verbunden ist und die Berechtigung für Push-Benachrichtigungen fehlt. Bitte verbinden Sie sich zuerst mit dem Gerät."; -"TagSettings.AlertsAreDisabled.Dialog.Connect.title" = "Verbinden"; -"TagSettings.AlertsAreDisabled.Dialog.NotConnected.message" = "Warnungen sind deaktiviert, weil Sie nicht mit dem Gerät verbunden sind."; -"TagSettings.Alert.CustomDescription.placeholder" = "Benutzerdefinierte Beschreibung festlegen..."; -"TagSettings.Alert.CustomDescription.title" = "Benutzerdefinierte Beschreibung des Alarms"; -"TagSettings.Alerts.Humidity.description" = "Warnung bei weniger als %.0f oder mehr als %.0f"; -"TagSettings.Alerts.DewPoint.description" = "Warnung bei weniger als %.0f oder mehr als %.0f"; -"TagSettings.dewPointAlertTitleLabel.text" = "Taupunkt"; -"TagSettings.Alerts.Pressure.description" = "Warnung bei weniger als %.0f oder mehr als %.0f"; -"TagSettings.Alerts.Connection.description" = "Warnung, wenn verbunden/getrennt"; -"TagSettings.ConnectionAlert.title" = "Verbindung"; -"TagSettings.SectionHeader.Firmware.title" = "Firmware"; -"TagSettings.Firmware.CurrentVersion" = "Aktuelle Version"; -"TagSettings.Firmware.CurrentVersion.VeryOld" = "Sehr alt"; -"TagSettings.Firmware.UpdateFirmware" = "Aktualisiere"; -"UnexpectedError.callbackErrorAndResultAreNil" = "Sowohl das Rückrufergebnis als auch der Fehler sind null"; -"UnexpectedError.callerDeinitedDuringOperation" = "Anrufer wurde während des Betriebs freigegeben"; -"UnexpectedError.failedToReverseGeocodeCoordinate" = "Fehler beim Umkehren der Geokodierung des Standorts"; -"UnexpectedError.failedToFindRuuviTag" = "Sensor konnte nicht gefunden werden"; -"UnexpectedError.failedToFindLogsForTheTag" = "Protokolle für den Sensor konnten nicht gefunden werden"; -"UnexpectedError.viewModelUUIDIsNil" = "Modell-UUID Anzeige ist null"; -"UnexpectedError.attemptToReadDataFromRealmWithoutLUID" = "Versuch, Daten aus Realm ohne LUID zu lesen"; -"UnexpectedError.failedToFindVirtualTag" = "Virtueller Sensor konnte nicht gefunden werden"; -"HumidityUnit.Dew.title" = "Taupunkt (%@)"; -"WebTagLocationSource.current" = "Ihr Standort"; -"WebTagLocationSource.manual" = "Wählen Sie aus der Karte"; -"WebTagSettings.confirmTagRemovalDialog.title" = "Virtuellen Sensor entfernen"; -"WebTagSettings.confirmTagRemovalDialog.message" = "Möchten Sie diesen virtuellen Sensor wirklich entfernen?"; -"WebTagSettings.Location.Current" = "Ihr Standort"; -"WebTagSettings.confirmClearLocationDialog.title" = "Standort löschen"; -"WebTagSettings.confirmClearLocationDialog.message" = "Möchten Sie den Standort dieses virtuellen Sensors wirklich löschen? Stattdessen wird der aktuelle Standort verwendet."; -"WebTagSettings.navigationItem.title" = "Virtuelle Sensoreinstellungen"; -"WebTagSettings.Label.BackgroundImage.text" = "HINTERGRUND BILD"; -"WebTagSettings.Label.Location.text" = "Standort"; -"WebTagSettings.Button.Remove.title" = "ENTFERNEN SIE DIESEN VIRTUELLEN SENSOR"; -"WebTagSettings.SectionHeader.Name.title" = "NAME"; -"WebTagSettings.SectionHeader.MoreInfo.title" = "MEHR INFO"; -"WebTagSettings.Alerts.Temperature.description" = "Warnung bei weniger als %.0f oder mehr als %.0f"; -"WebTagSettings.Alerts.Off" = "Aus"; -"WebTagSettings.temperatureAlertTitleLabel.text" = "Temperatur"; -"WebTagSettings.Label.disabled.text" = "AUSGESCHALTET?"; -"WebTagSettings.Label.alerts.text" = "WARNUNGEN"; -"WebTagSettings.AlertsAreDisabled.Dialog.BothNoPNPermissionAndNoLocationPermission.message" = "Um virtuelle Sensorwarnungen zu aktivieren, erteilen Sie bitte immer Standort- und Benachrichtigungsberechtigungen in den Einstellungen."; -"WebTagSettings.AlertsAreDisabled.Dialog.Settings.title" = "Einstellungen"; -"WebTagSettings.AirHumidityAlert.title" = "Luftfeuchtigkeit"; -"WebTagSettings.Alerts.Humidity.description" = "Warnung bei weniger als %.0f oder mehr als %.0f"; -"WebTagSettings.Alerts.DewPoint.description" = "Warnung bei weniger als %.0f oder mehr als %.0f"; -"WebTagSettings.dewPointAlertTitleLabel.text" = "Taupunkt"; -"WebTagSettings.PressureAlert.title" = "Luftdruck"; -"WebTagSettings.Alerts.Pressure.description" = "Warnung bei weniger als %.0f oder mehr als %.0f"; -"Welcome.description.text" = "Um Sensoren in der Nähe zu finden und Live-Sensordaten zu empfangen, drücken Sie Scannen."; -"ExportService.AccelerationX" = "Beschleunigung X"; -"ExportService.AccelerationY" = "Beschleunigung Y"; -"ExportService.AccelerationZ" = "Beschleunigung Z"; -"DiscoverTable.SectionTitle.Devices" = "Ruuvi-Sensoren in der Nähe"; -"ago" = "vor"; -"TagSettings.MovementAlert.title" = "Bewegung"; -"TagSettings.Alerts.Movement.description" = "Warnung, wenn der Sensor bewegt wird"; -"LocalNotificationsManager.HighHumidity.title" = "Luftfeuchtigkeit ist zu hoch!"; -"LocalNotificationsManager.LowHumidity.title" = "Luftfeuchtigkeit ist zu niedrig!"; -"LocalNotificationsManager.DidMove.title" = "Bewegung erkannt!"; -"LocalNotificationsManager.HighPressure.title" = "Luftdruck ist zu hoch!"; -"LocalNotificationsManager.LowPressure.title" = "Luftdruck ist zu niedrig!"; -"LocalNotificationsManager.HighSignal.title" = "Signalstärke ist zu hoch!"; -"LocalNotificationsManager.LowSignal.title" = "Signalstärke ist zu gering!"; -"LocalNotificationsManager.HighTemperature.title" = "Temperatur ist zu hoch!"; -"LocalNotificationsManager.LowTemperature.title" = "Temperatur zu niedrig!"; -"TagSettings.Alerts.Off" = "Aus"; -"TagSettings.Alerts.Temperature.description" = "Warnung bei weniger als %.0f oder mehr als %.0f"; -"TagSettings.Label.alerts.text" = "Warnungen"; -"TagSettings.backgroundImageLabel.text" = "Hintergrund bild"; -"TagSettings.batteryVoltageTitleLabel.text" = "Batteriespannung"; -"HumidityCalibration.Button.Calibrate.title" = "Kalibrieren"; -"HumidityCalibration.lastCalibrationDate.format" = "Kalibriert: %@"; -"HumidityCalibration.Description.text" = "Um die relative Luftfeuchtigkeit so genau wie möglich zu messen, wird eine Natriumchlorid-(Salz-)Kalibrierung empfohlen. Sehen Sie sich Video-Tutorials an, wie Sie dies ganz einfach zu Hause tun können."; -"HumidityCalibration.Label.note.text" = "Beachten Sie, dass die Kalibrierungsdaten lokal auf Ihrem Mobilgerät gespeichert werden. Nach der Deinstallation und Installation von Ruuvi Station müssen Sie möglicherweise eine Neukalibrierung durchführen."; -"HumidityCalibration.VideoTutorials.link" = "Videoanleitungen"; -"Cancel" = "Abbrechen"; -"HumidityCalibration.Button.Clear.title" = "Löschen"; -"TagCharts.DeleteHistoryConfirmationDialog.message" = "Die lokalen historischen Daten aus der App löschen?"; -"HumidityCalibration.Button.Close.title" = "Schließen"; -"TagCharts.Status.Serving" = "Synchronisieren..."; -"TagCharts.Status.Connecting" = "Verbinden..."; -"TagSettings.ConnectStatus.Disconnected" = "Getrennt"; -"TagCharts.Export.title" = "EXPORT"; -"h" = "h"; -"About.AboutHelp.contents" = "Ruuvi Station ist eine benutzerfreundliche Anwendung, mit der Sie die Messdaten von Ruuvi-Sensoren überwachen können."; -"About.AboutHelp.header" = "Über / Hilfe"; -"About.TagsCount.text" = "Sensoren hinzugefügt: %d"; -"About.MeasurementsCount.text" = "Anzahl lokal gespeicherter Messungen: %d"; -"About.DatabaseSize.text" = "Datenbankgröße: %@"; -"About.More.contents" = "Ruuvi-Website: ruuvi.com\nRuuvi-Forum: f.ruuvi.com\nRuuvi-Blog: ruuvi.com/blog\nRuuvi auf Twitter: twitter.com/ruuvicom"; -"About.More.header" = "Mehr erfahren"; -"About.OpenSource.contents" = "Genau wie Ruuvi-Sensoren sind auch die Ruuvi Station-Apps Open Source. Verfolgen Sie die Entwicklung und leisten Sie einen Beitrag unter: github.com/ruuvi"; -"About.OpenSource.header" = "Open-source"; -"About.OperationsManual.contents" = "Beginnen Sie mit der Nutzung der mobilen Anwendung Ruuvi Station mit unseren Online-Anleitungen: ruuvi.com/support/station-mobile"; -"About.OperationsManual.header" = "Anleitung"; -"About.Privacy.contents" = "Durch die Nutzung der Anwendung akzeptieren Sie die allgemeinen Geschäftsbedingungen von Ruuvi: ruuvi.com/terms"; -"About.Privacy.header" = "Datenschutz-bestimmungen"; -"About.Troubleshooting.contents" = "Hilfe bei der Verwendung der Ruuvi Station-Apps, Ruuvi-Produkte und des Ruuvi Cloud-Dienstes finden Sie in unserem Support-Center: ruuvi.com/support"; -"About.Troubleshooting.header" = "Fehlerbehebung"; -"hours" = "Stunden"; -"Interval.Days.string" = "Tage"; -"TagSettings.AirHumidityAlert.title" = "Luftfeuchtigkeit (%@)"; -"HumidityUnit.gm3.title" = "Absolut (g/m³)"; -"g/m³" = "g/m³"; -"HumidityUnit.Percent.title" = "Relative (%)"; -"TagSettings.Mac.Alert.title" = "MAC-Adresse"; -"Menu.Label.AboutHelp.text" = "Über / Hilfe"; -"Menu.Label.AddAnNewSensor.text" = "Neuen Sensor hinzufügen"; -"Menu.Label.AppSettings.text" = "App Einstellungen"; -"Menu.Label.GetMoreSensors.text" = "Sensoren kaufen"; -"Ruuvi.BuySensors.URL.IOS" = "https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Ruuvi.BuySensors.Menu.URL.IOS" = "https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios"; -"Menu.Label.BuyRuuviGateway.text" = "Ruuvi Gateway kaufen"; -"Menu.BuyGateway.URL.IOS" = "https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Menu.Label.WhatToMeasure.text" = "Was mit Ruuvi messen?"; -"Menu.Measure.URL.IOS" = "https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Menu.Label.Feedback.text" = "Feedback schicken"; -"Menu.Label.MyRuuviAccount.text" = "Mein Ruuvi Konto"; -"min" = "min"; -"minutes" = "Minuten"; -"TagSettings.Label.moreInfo.text" = "Mehr info"; -"TagSettings.SectionHeader.Name.title" = "NAME"; -"No" = "Nein"; -"OK" = "OK"; -"Cards.NoSensors.title" = "Keine Sensoren hinzugefügt\nKlicken Sie hier, um Sensoren hinzuzufügen"; -"TagSettings.PressureAlert.title" = "Luftdruck (%@)"; -"UnitPressure.hectopascal.title" = "Hektopascal (hPa)"; -"hPa" = "hPa"; -"UnitPressure.inchOfMercury.title" = "Zoll Quecksilber (inHg)"; -"UnitPressure.millimetreOfMercury.title" = "Millimeter Quecksilbersäule (mmHg)"; -"TagCharts.Status.ReadingHistory" = "History wird gelesen"; -"TagSettings.rssiTitleLabel.text" = "Signalstärke (RSSI)"; -"signal_strength_dbm" = "Signalstärke (dBm)"; -"s" = "s"; -"Welcome.scan.title" = "SCANNEN"; -"Background.Interval.Sec.string" = "sek"; -"Settings.navigationItem.title" = "Einstellungen"; -"Settings.BackgroundScanning.title" = "Scannen im Hintergrund"; -"Settings.BackgroundScanning.Footer.message" = "Wichtiger Hinweis: Die Bluetooth-Hintergrundprotokollierung und Bluetooth-Warnungen funktionieren nur, wenn die Hintergrundsuche aktiviert ist. Wenn Sie die Hintergrundabtastung deaktivieren, werden alle gekoppelten Ruuvi-Sensoren automatisch entkoppelt und Sie müssen sie auf ihren Einstellungsseiten erneut koppeln."; -"Settings.BackgroundScanning.interval" = "Datenprotokollierungsintervall"; -"Settings.Label.Chart" = "Diagramm Einstellungen"; -"ChartSettings.AllPoints.title" = "Alle Messungen anzeigen"; -"ChartSettings.AllPoints.description" = "Die Aktivierung kann dazu führen, dass Diagramme langsam aktualisiert werden."; -"ChartSettings.DrawDots.title" = "Datenpunkte anzeigen"; -"ChartSettings.DrawDots.description" = "Kleine Punkte helfen zu verstehen, wann Messungen erfasst wurden."; -"Defaults.ChartIntervalSeconds.title" = "Diagrammintervall"; -"ChartSettings.Duration.title" = "Anzeigezeitraum des Diagrammverlaufs"; -"ChartSettings.Duration.description" = "Konfigurieren Sie den Zeitraum, der im Diagramm angezeigt werden soll, von 1 bis 10 Tagen."; -"Settings.Label.HumidityUnit.text" = "Feuchtigkeitseinheit"; -"Settings.Label.Temperature" = "Temperatur"; -"Settings.Label.Humidity" = "Feuchtigkeit"; -"Settings.Label.Pressure" = "Druck"; -"Settings.ChooseHumidityUnit.text" = "Wählen Sie die Luftfeuchtigkeitseinheit aus, die angezeigt werden soll."; -"Settings.Label.PressureUnit.text" = "Druckeinheit"; -"Settings.ChoosePressureUnit.text" = "Wählen Sie die Druckeinheit, die angezeigt werden soll."; -"Settings.Label.TemperatureUnit.text" = "Temperatureinheit"; -"Settings.ChooseTemperatureUnit.text" = "Wählen Sie die Temperatureinheit, die angezeigt werden soll."; -"dBm" = "dBm"; -"TagCharts.Sync.title" = "Sync"; -"TagCharts.SyncConfirmationDialog.message" = "Daten vom Sensor herunterladen?"; -"WebTagSettings.Label.TagName.text" = "Sensor Name"; -"TagSettings.confirmTagRemovalDialog.title" = "Sensor entfernen"; -"TagSettings.confirmTagRemovalDialog.message" = "Möchten Sie den Sensor entfernen? Sie können ihn später bei Bedarf wieder hinzufügen."; -"TagSettings.temperatureAlertTitleLabel.text" = "Temperatur (%@)"; -"TemperatureUnit.Celsius.title" = "Celsius (℃)"; -"ºC" = "°C"; -"TemperatureUnit.Fahrenheit.title" = "Fahrenheit (℉)"; -"ºF" = "°F"; -"TemperatureUnit.Kelvin.title" = "Kelvin (K)"; -"Updated" = "Aktuaisiert"; -"V" = "V"; -"RuuviOnboard.Welcome.title" = "Wischen Sie, um zu sehen, was Ruuvi Station für Sie tun kann."; -"RuuviOnboard.Measure.title" = "Umweltdaten messen: Temperatur, relative Luftfeuchtigkeit und Luftdruck."; -"RuuviOnboard.Access.title" = "Greifen Sie in Echtzeit auf Daten für jeden verknüpften Sensor zu und erkunden Sie Verlaufsdiagramme."; -"RuuviOnboard.Alerts.title" = "Legen Sie Benachrichtigungen fest und lassen Sie sich benachrichtigen, wenn Ihre Grenzen erreicht sind."; -"RuuviOnboard.Cloud.title" = "Melden Sie sich an, um das volle Potenzial der App zu nutzen."; -"RuuviOnboard.Cloud.subtitle" = "Beanspruchen Sie das Eigentum an Ihren Sensoren mit einem kostenlosen Ruuvi Cloud-Konto."; -"RuuviOnboard.Cloud.subtitle.signed" = "Super! Sie haben sich bereits angemeldet!"; -"RuuviOnboard.Start.title" = "Drücken Sie SCAN, um Sensoren in der Nähe zu finden und zu Ihrer Ruuvi Station hinzuzufügen."; -"Yes" = "Ja"; -"LocalNotificationsManager.Mute.button" = "Stumm schalten für eine Stunde"; -"Defaults.AlertsMuteInterval.title" = "Alarmstummschaltintervall"; -"SignIn.Title.text" = "Einloggen"; -"Menu.SignOut.text" = "Ausloggen"; -"RuuviOnboard.Cloud.Benefits.message" = "Vorteile:\n\n ● Sensornamen, Hintergrundbilder, Offsets und Alarmeinstellungen werden sicher in der Cloud gespeichert\n\n ● Fernzugriff auf Sensoren über das Internet (erfordert ein Ruuvi Gateway)\n\n ● Teilen Sie Sensoren mit Freunden und Familie (erfordert ein Ruuvi Gateway)\n\n ● Sehen Sie bis zu 2 Jahre Geschichtsdaten auf station.ruuvi.com (erfordert ein Ruuvi-Gateway)"; -"RuuviOnboard.Cloud.Details.title" = "Einzelheiten"; -"ruuvi_cloud" = "Ruuvi Cloud"; -"RuuviOnboard.Cloud.Skip.title" = "Sind Sie sicher, dass Sie die Anmeldung überspringen wollen?"; -"RuuviOnboard.Cloud.Skip.Yes.title" = "Ja, überspringen"; -"RuuviOnboard.Cloud.Skip.GoBack.title" = "Zurückgehen"; -"SignIn.EmailPlaceholder" = "Email"; -"SignIn.RequestCode" = "Fordern Sie einen Code an"; -"SignIn.SubmitCode" = "Abschicken"; -"SignIn.EmailSent" = "E-Mail gesendet"; -"SignIn.CheckMailbox" = "Wir haben ein Einmalpasswort an Ihre E-Mail gesendet %@. Melden Sie sich an, indem Sie es hier eingeben:"; -"SignIn.CodeHint" = "Code"; -"TagsManagerPresenter.SignOutConfirmAlert.Message" = "Wenn Sie sich abmelden, werden Sensoren, deren Eigentum Sie mit den Sensoreinstellungen bestätigt haben, automatisch aus der App entfernt. Wenn Sie sich erneut mit derselben E-Mail-Adresse anmelden, werden die Sensoren aus der Cloud zurückgegeben.\n\nMöchten Sie sich abmelden?"; -"TagSettings.ClaimTagButton.Claim" = "Inhaberschaft beanspruchen"; -"TagSettings.ShareButton" = "Teilen"; -"Syncing..." = "Synchronisierung..."; -"Synchronized" = "Synchronisiert"; -"TagChartsPresenter.NumberOfPointsSynchronizedOverNetwork" = "Synchronisiert: %@"; -"MenuTableViewController.None" = "keiner"; -"MenuTableViewController.User" = "Benutzer: %@"; -"ShareViewController.Title" = "Sensor teilen"; -"ShareViewController.Description" = "Sie können den Sensor mit Freunden und Familie teilen, wenn er sich in Reichweite eines Ruuvi Gateways befindet.\n\nDer Empfänger wird per E-Mail benachrichtigt. Wenn der Empfänger kein Ruuvi-Konto hat, wird beim ersten Anmelden automatisch ein kostenloses Ruuvi-Konto erstellt.\n\nBeachten Sie, dass der benutzerdefinierte Name und das Hintergrundbild des Sensors geteilt werden. Der Name und das Bild werden nur einmal synchronisiert und können danach vom Empfänger privat angepasst werden. Vom Besitzer eingestellte Offset-Werte (sofern vorhanden) werden automatisch synchronisiert und der Empfänger sieht immer die endgültigen korrigierten Werte."; -"ShareViewController.addFriend.Title" = "Freund hinzufügen"; -"ShareViewController.emailTextField.placeholder" = "E-Mail eingeben"; -"ShareViewController.sharedEmails.Title" = "Sie haben %d/%d der maximalen Teilungszahl für diesen Sensor verwendet. Der Sensor wird mit den folgenden Benutzern geteilt:"; -"Share.Send.button" = "Senden"; -"SharePresenter.UnshareSensor.Message" = "Möchten Sie die Freigabe des Sensors für %@ aufheben?"; -"TagSettings.SectionHeader.NetworkInfo.title" = "NETZWERK INFORMATION"; -"TagSettings.NetworkInfo.Owner" = "Eigentümer"; -"Menu.RuuviNetworkStatus.text" = "Ruuvi-Cloud-Status"; -"SignIn.TitleLabel.text" = "Login zur\nRuuvi\nStation"; -"SignIn.SubtitleLabel.text" = "Um alle Funktionen nutzen zu können, erstellen Sie ein kostenloses Konto oder melden Sie sich bei Ihrem bestehenden Ruuvi-Konto an, indem Sie Ihre E-Mail-Adresse eingeben."; -"SignIn.VerificationCodePlaceholder" = "Verifizierungscode im Format: CJSM"; -"UserApiError.ER_FORBIDDEN" = "Verboten"; -"UserApiError.ER_UNAUTHORIZED" = "Nicht autorisiert"; -"UserApiError.ER_INTERNAL" = "Interner Fehler"; -"UserApiError.ER_INVALID_FORMAT" = "Ungültiges Anfrageformat"; -"UserApiError.ER_USER_NOT_FOUND" = "Benutzer wurde nicht gefunden"; -"UserApiError.ER_SENSOR_NOT_FOUND" = "Sensor nicht gefunden"; -"UserApiError.ER_TOKEN_EXPIRED" = "Token ist abgelaufen"; -"UserApiError.ER_SUBSCRIPTION_NOT_FOUND" = "Abonnement wurde nicht gefunden"; -"UserApiError.ER_SHARE_COUNT_REACHED" = "Das Teilen Limit ist erreicht"; -"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Sensor Teilen Limit ist erreicht"; -"UserApiError.ER_NO_DATA_TO_SHARE" = "Um den Sensor zu teilen, benötigen Sie einen Ruuvi Gateway-Router in der Nähe des Sensors"; -"UserApiError.ER_SENSOR_ALREADY_SHARED" = "Dieser Sensor wurde bereits geteilt"; -"UserApiError.ER_SENSOR_ALREADY_CLAIMED" = "Sensor bereits beansprucht von %@"; -"UserApiError.ER_SENSOR_ALREADY_CLAIMED_NO_EMAIL" = "Sensor bereits beansprucht"; -"UserApiError.ER_UNABLE_TO_SEND_EMAIL" = "Die Email kann nicht gesendet werden"; -"UserApiError.ER_MISSING_ARGUMENT" = "Fehlendes Argument"; -"UserApiError.ER_INVALID_DENSITY_MODE" = "Ungültiger Dichtemodus"; -"UserApiError.ER_INVALID_SORT_MODE" = "Ungültiger Sortiermodus"; -"UserApiError.ER_INVALID_TIME_RANGE" = "Ungültiger Zeitraum"; -"UserApiError.ER_INVALID_EMAIL_ADDRESS" = "Ungültige E-Mail-Adresse"; -"UserApiError.ER_INVALID_MAC_ADDRESS" = "Ungültige MAC-Adresse"; -"UserApiError.ER_SUB_DATA_STORAGE_ERROR" = "Datenspeicherfehler"; -"UserApiError.ER_SUB_NO_USER" = "Kein Benutzer"; -"UserApiError.ER_THROTTLED" = "Zu viele Anfragen"; -"OffsetCorrection.CalibrationDescription.text" = "Bei normalem Gebrauch ist es nicht erforderlich, den Offset anzupassen.\n\nWenn Sie ein fortgeschrittener Benutzer sind und die werkseitig kalibrierten Sensoren manuell konfigurieren möchten, ist dies möglich.\n\nTipps zur Kalibrierung sind auf ruuvi.com/support verfügbar"; -"OffsetCorrection.Dialog.Calibration.ClearConfirm" = "Kalibrierungseinstellungen löschen?"; -"OffsetCorrection.Dialog.Calibration.Title" = "Kalibriereinrichtung"; -"OffsetCorrection.Dialog.Calibration.EnterTemperature" = "Geben Sie den erwarteten Temperaturwert des Sensors unter aktuellen Bedingungen ein (%@): "; -"OffsetCorrection.Dialog.Calibration.EnterPressure" = "Geben Sie den erwarteten Druckwert vom Sensor unter aktuellen Bedingungen ein (%@): "; -"OffsetCorrection.Dialog.Calibration.EnterHumidity" = "Geben Sie den erwarteten Feuchtigkeitswert des Sensors unter den aktuellen Bedingungen ein (%@): "; -"OffsetCorrection.OriginalValue.title" = "Ursprünglicher Messwert"; -"OffsetCorrection.CorrectedValue.title" = "Korrigierter Wert"; -"OffsetCorrection.Temperature.Title" = "Temperatur-Offset"; -"OffsetCorrection.Humidity.Title" = "Feuchtigkeits-Offset"; -"OffsetCorrection.Pressure.Title" = "Druckoffset"; -"OffsetCorrection.Calibrate.button" = "Offset-Korrektur"; -"TagSettings.SectionHeader.OffsetCorrection.Title" = "OFFSET-KORREKTUR"; -"TagSettings.OffsetCorrection.Temperature" = "Temperatur"; -"TagSettings.OffsetCorrection.Humidity" = "Feuchtigkeit"; -"TagSettings.OffsetCorrection.Pressure" = "Druck"; -"PhotoPicker.Sheet.files" = "Aus Dateien auswählen"; -"SignIn.EnterVerificationCode" = "Bitte Bestätigungscode eingeben"; -"UnexpectedError.failedToFindOrGenerateBackgroundImage" = "Hintergrundbild konnte nicht gefunden oder generiert werden"; -"UnexpectedError.bothLuidAndMacAreNil" = "Sowohl lokale als auch MAC-Identifikatoren sind null"; -"RuuviCloudApiError.emptyResponse" = "Leere Antwort"; -"RuuviCloudApiError.failedToGetDataFromResponse" = "Fehler beim Abrufen der Daten aus der Antwort"; -"RuuviCloudApiError.unexpectedHTTPStatusCode" = "Unerwarteter HTTP-Statuscode"; -"RuuviCloudError.NotAuthorized" = "Nicht autorisiert"; -"RuuviLocalError.failedToGetJpegRepresentation" = "Fehler beim Abrufen der JPG-Darstellung"; -"RuuviLocalError.failedToGetDocumentsDirectory" = "Fehler beim Abrufen des Hintergrundverzeichnisses"; -"RuuviPersistenceError.failedToFindRuuviTag" = "Sensor konnte nicht gefunden werden"; -"RuuviServiceError.pictureUrlIsNil" = "Bild-URL ist null"; -"RuuviServiceError.macIdIsNil" = "MAC-Kennung ist null"; -"network_sharing_disabled" = "Nur Sensoren in Reichweite Ihres Ruuvi Gateways können geteilt werden."; -"RuuviServiceError.bothLuidAndMacAreNil" = "Sowohl lokale als auch MAC-Identifikatoren sind null"; -"RuuviServiceError.failedToParseNetworkResponse" = "Fehler beim Parsen der Antwort."; -"RuuviServiceError.failedToFindOrGenerateBackgroundImage" = "Hintergrundbild konnte nicht gefunden oder generiert werden"; -"RuuviServiceError.failedToGetJpegRepresentation" = "Fehler beim Abrufen der JPG-Darstellung"; -"UpdateFirmware.Title.text" = "Firmware aktualisieren"; -"UpdateFirmware.Download.header" = "AKTUELLE FIRMWARE HERUNTERLADEN"; -"UpdateFirmware.Download.content" = "Um mit dem Update-Vorgang zu beginnen, laden Sie zuerst das neueste Softwarepaket auf das Gerät herunter, das Sie für die Aktualisierung verwenden möchten. Die neueste Version ist auf ruuvi.com/software-update verfügbar"; -"UpdateFirmware.SetDfu.header" = "RUUVI-TAG AUF DFU-MODUS EINSTELLEN"; -"UpdateFirmware.SetDfu.content" = "Öffnen Sie das Gehäuse des RuuviTag, indem Sie es mit den Fingern oder vorsichtig mit einem Flachkopfschraubendreher aufziehen.\n\nSetzen Sie den RuuviTag in den Bootloader-Modus, indem Sie die Taste B gedrückt halten und die Reset-Taste R drücken. Die rote LED-Anzeige leuchtet und bleibt An. Wenn Ihr Gerät nur über 1 Taste verfügt, halten Sie diese 10 Sekunden lang gedrückt, um den Bootloader aufzurufen."; -"UpdateFirmware.NextButton.title" = "NÄCHSTE"; -"DfuDevicesScanner.Title.text" = "Geräte"; -"DfuDevicesScanner.Description.text" = "Suchen und wählen Sie den Sensor \"RuuviBoot\"."; -"DfuDevicesScanner.NoDevice.text" = "(Keine Sensoren in Bluetooth-Reichweite)"; -"DfuDevicesScanner.BluetoothDisabled.text" = "(Bluetooth ist deaktiviert)"; -"DfuDevicesScanner.BluetoothDisabledAlert.title" = "Bluetooth ist nicht aktiviert"; -"DfuDevicesScanner.BluetoothDisabledAlert.message" = "Die Ruuvi Station benötigt Bluetooth, um Sensoren zu verbinden. Gehen Sie zu Einstellungen und schalten Sie Bluetooth ein."; -"DfuFlash.Title.text" = "DFU Flash"; -"DfuFlash.Progress.text" = "Fortschritt"; -"DfuFlash.Step.text" = "Schritt"; -"DfuFlash.Steps.PackageSelection.text" = "Paketauswahl"; -"DfuFlash.Steps.ReadyForUpload.text" = "Bereit zum Hochladen"; -"DfuFlash.Steps.Uploading.text" = "Hochladen"; -"DfuFlash.Steps.Completed.text" = "Fertig"; -"DfuFlash.OpenDocumentPicker.title" = "DOKUMENTENAUSWAHL ÖFFNEN"; -"DfuFlash.FirmwareSelectionGuide.text" = "Suchen Sie die zuvor heruntergeladene ZIP-Datei auf Ihrem Handy."; -"DfuFlash.Firmware.FileName.text" = "Dateiname"; -"DfuFlash.Firmware.Parts.text" = "Teile"; -"DfuFlash.Firmware.Size.text" = "Größe"; -"DfuFlash.Firmware.SoftDeviceSize.text" = "Größe des Soft-Geräts"; -"DfuFlash.Firmware.BootloaderSize.text" = "Bootloader-Größe"; -"DfuFlash.Cancel.text" = "ABBRECHEN"; -"DfuFlash.Start.text" = "Start"; -"DfuFlash.Finish.text" = "BEENDEN"; -"DfuFlash.FinishGuide.text" = "Der Firmware-Update-Prozess wurde erfolgreich abgeschlossen. -Ihr RuuviTag-Sensor ist einsatzbereit!"; -"DfuFlash.CancelAlert.text" = "Möchten Sie den Firmware-Aktualisierungsvorgang wirklich abbrechen?"; -"RuuviDfuError.invalidFirmwareFile" = "Ungültige Firmware-Datei"; -"DFUUIView.navigationTitle" = "Firmware Update"; -"DFUUIView.latestTitle" = "Neueste verfügbare Ruuvi Firmware-Version:"; -"DFUUIView.currentTitle" = "Aktuelle Version:"; -"DFUUIView.notReportingDescription" = "Ihr Sensor meldet seine aktuelle Firmware-Version nicht. Dies bedeutet, dass wahrscheinlich eine alte Firmware-Version ausgeführt wird und eine Aktualisierung empfohlen wird."; -"DFUUIView.alreadyOnLatest" = "Sie verwenden die neueste Firmware-Version, keine Aktualisierung erforderlich"; -"DFUUIView.startUpdateProcess" = "Update-Prozess starten"; -"DFUUIView.downloadingTitle" = "Laden Sie die neueste zu aktualisierende Firmware herunter..."; -"DFUUIView.prepareTitle" = "Bereiten Sie Ihren Sensor vor"; -"DFUUIView.openCoverTitle" = "1. Öffnen Sie den Deckel Ihres Ruuvi-Sensors"; -"DFUUIView.locateBootButtonTitle" = "2. Suchen Sie die kleinen runden schwarzen Knöpfe auf der weißen Platine; ältere Ruuvi-Sensoren haben zwei Knöpfe mit den Bezeichnungen \"R\" und \"B\", während neuere nur einen Knopf ohne Beschriftung haben."; -"DFUUIView.setUpdatingModeTitle" = "3. Stellen Sie den Sensor in den Aktualisierungsmodus:"; -"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. Wenn Ihr Sensor 2 Tasten hat: Halten Sie die Taste \"B\" gedrückt und tippen Sie gleichzeitig kurz auf die Taste \"R\". Lassen Sie die Taste \"B\" los."; -"DFUUIView.toBootModeOneButtonDescription" = "3.2. Wenn Ihr Sensor eine einzelne Taste hat: Halten Sie die Taste 10 Sekunden lang gedrückt."; -"DFUUIView.toBootModeSuccessTitle" = "4. Wenn die Einstellung erfolgreich war, leuchtet ein rotes Licht auf der Platine und die Schaltfläche in der App ändert sich in \"Start the update\"."; -"DFUUIView.updatingTitle" = "Aktualisierung..."; -"DFUUIView.searchingTitle" = "Suche nach einem Sensor"; -"DFUUIView.startTitle" = "Starten Sie die Aktualisierung"; -"DFUUIView.doNotCloseTitle" = "Schließen Sie die App nicht und schalten Sie den Sensor während des Updates nicht aus."; -"DFUUIView.successfulTitle" = "Aktualisierung erfolgreich"; -"DFUUIView.DBMigration.Error.message" = "Die Aktualisierung war erfolgreich, aber es ist ein unerwarteter Datenbankmigrationsfehler aufgetreten. Um diesen Sensor weiterhin zu verwenden, entfernen Sie ihn bitte aus der App und fügen Sie ihn dann erneut hinzu."; -"RuuviDfuError.failedToConstructUUID" = "Fehler beim Erstellen der UUID"; -"SignIn.EmailMismatch.Alert.message" = "Hoppla, Sie haben den Code für %@ angefordert, aber den Code für %@ verwendet. Bitte überprüfen Sie, ob Sie den Code für %@ verwenden."; -"SignIn.EmailMissing.Alert.message" = "Hoppla, die E-Mail, mit der Sie den Code erhalten haben, wurde nicht gespeichert. Bitte versuchen Sie erneut, sich anzumelden."; -"TagSettings.RemoveThisSensor.title" = "Entfernen Sie diesen Sensor"; -"Share.Success.message" = "Sensor erfolgreich geteilt"; -"TagSettings.SectionHeader.General.title" = "Allgemein"; -"TagSettings.Shared.title" = "Geteilt"; -"TagSettings.NotShared.title" = "Nicht geteilt"; -"Owner.title" = "Sensor beanspruchen"; -"Owner.ClaimOwnership.button" = "Inhaberschaft beanspruchen"; -"Owner.Claim.description" = "Besitzen Sie diesen Sensor? Wenn ja, beanspruchen Sie bitte den Besitz des Sensors und er wird Ihrem Ruuvi-Konto hinzugefügt. Jeder Ruuvi-Sensor kann nur einen Besitzer haben. Um Eigentum zu beanspruchen, müssen Sie angemeldet sein.\n\nVorteile:\n\n ● Sensornamen, Hintergrundbilder, Offsets und Alarmeinstellungen werden sicher in der Cloud gespeichert\n\n ● Fernzugriff auf Sensoren über das Internet (erfordert ein Ruuvi Gateway)\n\n ● Teilen Sie Sensoren mit Freunden und Familie (erfordert ein Ruuvi Gateway)\n\n ● Sehen Sie bis zu 2 Jahre Geschichtsdaten auf station.ruuvi.com (erfordert ein Ruuvi-Gateway)"; -"TagSettings.confirmTagUnclaimAndRemoveDialog.message" = "Durch das Entfernen des Sensors wird Ihr Sensor-Eigentumsstatus widerrufen. Nach dem Entfernen kann eine andere Person das Eigentum an dem Sensor beanspruchen. Jeder Ruuvi-Sensor kann nur einen Besitzer haben."; -"TagSettings.confirmSharedTagRemovalDialog.message" = "Wenn Sie den Sensor entfernen, wird der Besitzer des Sensors benachrichtigt und Sie können nicht mehr auf den Sensor zugreifen."; -"TagSettings.General.Owner.none" = "Keiner"; -"TagSettings.Share.title" = "Teilen"; -"Menu.LoggedIn.title" = "Eingeloggt:"; -"Interval.Day.string" = "Tag"; -"hour" = "Stunde"; -"TagSettings.tagNameTitleLabel.rename.text" = "Ihre Sensoren werden in alphabetischer Reihenfolge angezeigt."; -"On" = "An"; -"Off" = "Aus"; -"DFUUIView.lowBattery.warning.message" = "Die Batteriespannung des Sensors scheint zu niedrig zu sein, und der Firmware-Aktualisierungsprozess kann fehlschlagen. Wir empfehlen, die Batterie vor der Aktualisierung zu ersetzen."; -"alert_notification_humidity_high_threshold" = "Luftfeuchtigkeit liegt über %@"; -"alert_notification_humidity_low_threshold" = "Luftfeuchtigkeit liegt unter %@"; -"alert_notification_pressure_high_threshold" = "Luftdruck liegt über %@"; -"alert_notification_pressure_low_threshold" = "Luftdruck liegt unter %@"; -"alert_notification_rssi_high_threshold" = "Die Signalstärke liegt über %@"; -"alert_notification_rssi_low_threshold" = "Die Signalstärke liegt unter %@"; -"alert_notification_temperature_high_threshold" = "Die Temperatur liegt über %@"; -"alert_notification_temperature_low_threshold" = "Die Temperatur liegt unter %@"; -"Cards.Alert.AlreadyLoggedIn.message" = "Benutzer %@ ist bereits angemeldet. Wenn Sie ein anderes Konto verwenden möchten, melden Sie sich bitte zuerst ab und versuchen Sie es dann erneut."; -"Settings.Label.CloudMode" = "Cloud-Modus"; -"Settings.Label.CloudMode.description" = "Aktualisieren Sie Cloud-Sensoren in der Nähe nur aus der Cloud, indem Sie ihre Bluetooth-Nachrichten ignorieren und Warnungen nur per E-Mail erhalten. Erfordert einen Ruuvi Gateway-Router."; -"internet_connection_problem" = "Problem mit der Internetverbindung"; -"Widgets.Loading.message" = "laden..."; -"Cards.Movements.title" = "bewegungen"; -"TagSettings.BatteryStatusLabel.Replace.message" = "Schwache Batterie"; -"TagSettings.BatteryStatusLabel.Ok.message" = "Batterie OK"; -"Widgets.Description.message" = "Erstellen Sie Widgets mit Ihren bevorzugten Ruuvi-Sensoren. Widgets werden über die Ruuvi Cloud aktualisiert. Ein Ruuvi Gateway-Router ist erforderlich."; -"settings_appearance" = "Erscheinungsbild"; -"app_theme" = "App Thema"; -"follow_system_theme" = "Systemthema"; -"dark_theme" = "Dunkles Thema"; -"light_theme" = "Thema Licht"; -"Settings.Temperature.Resolution.title" = "Auflösung der Temperatur"; -"Settings.Humidity.Resolution.title" = "Auflösung der Luftfeuchtigkeit"; -"Settings.Pressure.Resolution.title" = "Auflösung des Drucks"; -"Settings.Measurement.Resolution.description" = "Wählen Sie aus, wie genau Sie die Live-Messwerte der Sensoren in der App sehen möchten. Diese Einstellung hat keinen Einfluss auf Verlaufsdiagramme oder Alarme."; -"Settings.Measurement.Unit.title" = "Einheit"; -"Settings.Measurement.Resolution.title" = "Auflösung"; -"MyRuuvi.Settings.DeleteAccount.title" = "Konto löschen"; -"MyRuuvi.Settings.DeleteAccount.Confirmation.message" = "Es wurde eine Bestätigung an Ihre E-Mail gesendet. Um mit der Löschung fortzufahren, überprüfen Sie bitte Ihren Posteingang und folgen Sie den Anweisungen."; -"TagSettings.Alert.SetTemperature.title" = "Temperaturalarm einstellen"; -"TagSettings.Alert.SetHumidity.title" = "Feuchtigkeitsalarm einstellen"; -"TagSettings.Alert.SetPressure.title" = "Druckalarm einstellen"; -"TagSettings.Alert.SetRSSI.title" = "Signalstärkealarm einstellen"; -"TagSettings.AlertSettings.Dialog.Min" = "Min (%.0f)"; -"TagSettings.AlertSettings.Dialog.Max" = "Max (%.0f)"; -"export_history" = "Verlauf exportieren (csv)"; -"clear_view" = "Klare verlaufsansicht"; -"day_1" = "1 Tag"; -"day_2" = "2 Tage"; -"day_3" = "3 Tage"; -"day_4" = "4 Tage"; -"day_5" = "5 Tage"; -"day_6" = "6 Tage"; -"day_7" = "7 Tage"; -"day_8" = "8 Tage"; -"day_9" = "9 Tage"; -"day_10" = "10 Tage"; -"day_x" = "%.0f Tage"; -"more" = "Mehr..."; -"all" = "Alle"; -"longer_history_title" = "Längere Geschichte"; -"longer_history_message" = "Die Ruuvi Station Mobile App unterstützt maximal 10 Tage Historie. Ruuvi-Cloud-Abonnenten können mit der Web-App unter ruuvi.com/station (erfordert Ruuvi-Gateway-Router) bis zu 2 Jahre historische Daten anzeigen."; -"reading_history_x" = "Bluetooth-Sync: %.0f"; -"rssi_alert_description" = "Die Verwendung dieses Alarms setzt voraus, dass Sie in der App angemeldet sind und dass Sie den Sensor für sich beansprucht haben und dass er sich in der Reichweite des Ruuvi Gateway Routers befindet. iOS-Geräte können keine Informationen zur Signalstärke der vom Ruuvi-Sensor gesendeten Daten anzeigen, wenn der Sensor gekoppelt ist und Messungen im Hintergrund empfangen werden. Die Echtzeit-Bluetooth-Signalstärke wird in der App angezeigt, hat aber keinen Einfluss auf diesen Alarm."; -"bluetooth_download" = "Bluetooth-Download"; -"bluetooth_download_description" = "Lokale Sensordaten können heruntergeladen werden, wenn Sie sich in Bluetooth-Reichweite befinden."; -"download" = "Download"; -"clear_local_history" = "Lokaler Verlauf löschen"; -"clear_local_history_description" = "Möchten Sie lokal gespeicherte historische Daten aus der App löschen? Dies löscht nicht den intern gespeicherten Verlauf des Sensors oder die im Ruuvi Cloud-Dienst gespeicherten historischen Daten."; -"TagCharts.FailedToSyncDialog.title" = "Herunterladen fehlgeschlagen"; -"TagCharts.FailedToSyncDialog.message" = "Download der Bluetooth-Historie fehlgeschlagen. Stellen Sie sicher, dass Sie sich in Bluetooth-Reichweite befinden, dass Ihr Sensor über eine Firmware verfügt, die das Herunterladen unterstützt, und dass der Sensor nicht gleichzeitig mit einem anderen iOS-Gerät verbunden ist. Die Sensorverbindung ist für die Ruuvi Station reserviert, wenn der Verbindungsmodus in iOS verwendet wird."; -"TagCharts.TryAgain.title" = "Erneut versuchen"; -"support" = "Unterstützung"; -"full_image_view" = "Vollbildansicht"; -"history_view" = "Ansicht Verlauf"; -"settings_and_alerts" = "Einstellungen & Benachrichtigungen"; -"change_background" = "Einstellungen und Warnungen"; -"check_claim_state" = "Prüfung des Antragsstatus"; -"claim_in_progress" = "Anspruchserhebung läuft"; -"force_claim_sensor" = "Antragstellung in Bearbeitung"; -"force_claim_sensor_description1" = "Dieser Sensor wurde von einem anderen Benutzer beansprucht. Sie können die Eigentümerschaft für Ihr Konto erzwingen, wenn Sie physischen Zugang zu diesem Sensor haben. Jeder Ruuvi-Sensor kann nur einen Besitzer haben."; -"force_claim_sensor_description2" = "Die Zwangsanforderung erfolgt über die Nahfeldkommunikation (NFC). Vergewissern Sie sich, dass NFC auf Ihrem Mobilgerät aktiviert ist.\ - 1. Berühren Sie Ihren Ruuvi-Sensor mit Ihrem Mobilgerät, um den Beanspruchungsprozess zu starten.\n - 2. Nach erfolgreicher Beanspruchung werden Sie zu den Sensoreinstellungen zurückgeschickt.\ -\ -Wenn die Beanspruchung nicht erfolgreich war oder NFC auf Ihrem Gerät nicht verfügbar ist:\n\n 1. Öffnen Sie die Abdeckung Ihres Ruuvi-Sensors.\ - 2. Suchen Sie die runde schwarze Taste (oder die Taste \"B\", falls Ihr Sensor 2 Tasten hat) auf der weißen Platine und drücken Sie sie kurz, und tippen Sie dann auf die Schaltfläche „Verwenden Sie BT“, um den Beanspruchungsprozess zu starten.\ -\n\t3. Nach erfolgreicher Beanspruchung werden Sie zu den Sensoreinstellungen zurückgeschickt."; -"force_claim" = "Kraft-Anspruch"; -"claim_wrong_sensor_scanned" = "Sie scannen gerade verschiedene RuuviTag"; -"view" = "Siehe"; -"card_type" = "Speicherkarten-Typ"; -"image_cards" = "Bildkarten"; -"simple_cards" = "Einfache Karten"; -"card_action" = "Kartenaktion"; -"open_sensor_view" = "Sensoransicht öffnen"; -"open_history_view" = "Verlaufsansicht öffnen"; -"change_background_message" = "Wählen Sie das Hintergrundbild. Wenn Sie nicht angemeldet sind, verlieren Sie das Bild bei einer Neuinstallation der App."; -"take_photo" = "Ein Foto machen"; -"select_from_gallery" = "Aus der Handy-Galerie auswählen"; -"select_default_image" = "Aus Standardbildern auswählen"; -"export_csv_feature_location" = "Sie können den Verlauf eines Sensors von seiner Verlaufsgrafikseite aus exportieren. Tippen Sie auf das Drei-Punkte-Menüsymbol in der oberen rechten Ecke und wählen Sie dann \"Verlauf exportieren (csv)\"."; -"low_battery" = "Schwache Batterie"; -"change_background_image" = "Hintergrundbild ändern"; -"SignIn.Sync.message" = "Herunterladen von Inhalten aus der Cloud. Bitte warten Sie."; -"uploading_progress" = "Hochladen: %.0f"; -"Widgets.Unauthorized.Regular.message" = "Melden Sie sich an, um das Widget zu verwenden."; -"Widgets.Unauthorized.Inline.message" = "Anmeldung bei Ruuvi Station"; -"Widgets.Unconfigured.Simple.message" = "Erzwingen Sie das Tippen, um das Widget zu bearbeiten."; -"Widgets.Unconfigured.Rectangular.message" = "Tippen Sie auf , um das Widget zu bearbeiten."; -"Widgets.Unconfigured.Inline.message" = "Sensor hinzufügen, um Ruuvi Widget zu verwenden"; -"Widgets.Unconfigured.Circular.message" = "+Hinzufügen"; -"Widgets.Select.Sensor.title" = "Ausgewählter Ruuvi-Sensor"; -"Widgets.Sensor.Type.title" = "Ausgewählter Sensortyp"; -"Settings.SectionHeader.General.title" = "ALLGEMEINES"; -"Settings.SectionHeader.Application.title" = "ANWENDUNG"; -"empty_chart_message" = "Im gewählten Verlaufsfenster sind keine Daten verfügbar."; -"onboarding_measure_your_world" = "Measure Your World"; -"onboarding_with_ruuvi_sensors" = "Lernen Sie Ihre Ruuvi Station -App kennen."; -"onboarding_swipe_to_continue" = "Wischen Sie zum Fortfahren →"; -"onboarding_read_sensors_data" = "Lesen Sie Ihre Ruuvi-Sensoren"; -"onboarding_via_bluetooth_or_cloud" = "mit Bluetooth oder Ruuvi Cloud"; -"onboarding_follow_measurement" = "Sehen Sie alle Sensoren auf einen Blick auf Ihrem"; -"onboarding_dashboard" = "Dashboard"; -"onboarding_personalise" = "Personalisieren"; -"onboarding_your_sensors" = "Sie Ihre App mit benutzerdefinierten Namen und Hintergründen."; -"onboarding_explore_detailed" = "Erkunden Sie Ihren"; -"onboarding_history" = "Messverlauf"; -"onboarding_set_custom" = "Einstellen und anpassen"; -"onboarding_alerts" = "Alarme"; -"onboarding_share_your_sensors" = "zum Messen mit Ihren Freunden und Ihrer Familie."; -"onboarding_sharees_can_use" = "Teilen Sie Sensoren"; -"onboarding_handy_widgets" = "Widgets hinzu"; -"onboarding_access_widgets" = "Fügen Sie Ihre bevorzugten Sensoren als"; -"onboarding_station_web" = "Ruuvi Web App"; -"onboarding_web_pros" = "Großes Dashboard, mehrjähriger Verlauf, E-Mail-Benachrichtigungen und mehr in der"; -"onboarding_gateway_required" = "Ein Ruuvi Gateway -Router ist erforderlich."; -"onboarding_skip" = "Überspringen"; -"onboarding_thats_it" = "Fast dort!"; -"onboarding_thats_it_already_signed_in" = "Lass uns anfangen!"; -"onboarding_go_to_sign_in" = "Ruuvi ist besser, wenn Sie angemeldet sind. Machen Sie es jetzt oder fahren Sie ohne Cloud-Funktionen fort."; -"onboarding_go_to_sign_in_already_signed_in" = "Fangen wir an zu messen!"; -"onboarding_continue" = "Nächste"; -"sign_in_or_create_free_account" = "Logge dich ein oder erstelle ein kostenloses Ruuvi-Konto"; -"to_use_all_app_features" = "Kein Passwort erforderlich."; -"type_your_email" = "Geben Sie Ihre E-Mail ein.."; -"request_code" = "Anfrage Code"; -"no_password_needed" = "Für diese E-Mail wird ein kostenloses Konto erstellt, falls Sie noch keines haben. Es ist nur eine E-Mail-Adresse erforderlich. Wir bewahren Ihre Informationen sicher auf."; -"benefits_sign_in" = "Lesen Sie mehr über die Vorteile des Ruuvi-Kontos oder melden Sie sich später an"; -"use_without_account" = "Nein danke, überspringen"; -"why_should_sign_in" = "Vorteile"; -"sensors_ownership_and_settings_stored_in_cloud" = "Die Anmeldung bei der App hat viele Vorteile. Einstellungen werden sicher in deinem Konto gespeichert:"; -"cloud_stored_ownerships" = "● Sensorbesitz"; -"cloud_stored_names" = "● Sensornamen"; -"cloud_stored_alerts" = "● Hintergrundbilder"; -"cloud_stored_backgrounds" = "● Alert-Einstellungen"; -"cloud_stored_calibration" = "● Kalibrierungseinstellungen"; -"cloud_stored_sharing" = "● App Einstellungen"; -"note" = "Notiz!"; -"claim_warning" = "Sichern Sie die Eigentumsinformationen Ihrer Sensoren, indem Sie ihre Eigentumsrechte in der App beanspruchen."; -"lets_do_it" = "Gehen Sie zum Anmelden"; -"enter_code" = "Code eingeben"; -"dashboard_no_sensors_message" = "Scheint, als hätten Sie noch keine Ruuvi-Sensoren hinzugefügt."; -"dashboard_no_sensors_message_signed_out" = "Sie sind nicht angemeldet.\n\nWenn Sie ein Konto haben und diesem bereits Ruuvi-Sensoren hinzugefügt haben, werden diese automatisch mit der mobilen Ruuvi Station-App synchronisiert, wenn Sie sich anmelden."; -"add_a_sensor" = "Fügen Sie einen Sensor hinzu"; -"changelog" = "(änderungsprotokoll)"; -"changelog_ios_url" = "https://f.ruuvi.com/t/3192"; -"chart_stat_min" = "Min"; -"chart_stat_max" = "Max"; -"chart_stat_avg" = "Durchschnitt"; -"shared_to_x" = "Freigegebene %d/%d"; -"settings_alert_notifications" = "Alarmbenachrichtigungen"; -"settings_alert_sound" = "Alarmton"; -"settings_alert_sound_description" = "Wählen Sie den Push-Benachrichtigungston aus."; -"settings_alerts_footer_description" = "Sie können die Benachrichtigungseinstellungen auch unter iOS-Einstellungen -> Benachrichtigungen anpassen"; -"settings_alerts_footer_description_link_mask" = "iOS-Einstellungen -> Benachrichtigungen"; -"settings_email_alerts" = "E-Mail-Benachrichtigungen"; -"settings_email_alerts_description" = "Wenn Sie Ruuvi Cloud und Ruuvi Gateway verwenden, können Sie durch Aktivieren dieser Funktion E-Mail-Benachrichtigungen erhalten."; -"settings_push_alerts" = "Push-Benachrichtigungen"; -"settings_push_alerts_description" = "Wenn Sie Ruuvi Cloud und Ruuvi Gateway verwenden, können Sie Push-Benachrichtigungen erhalten, indem Sie diese aktivieren."; -"synchronisation" = "Synchronisation"; -"gatt_sync_description" = "Ruuvi Station lädt den internen Verlauf des Sensors für die letzten 10 Tage herunter, wenn der Messverlauf verfügbar ist.\n\nDer Verlauf wird über eine Bluetooth-Verbindung heruntergeladen. Stellen Sie sicher, dass Sie sich in der Nähe des Sensors befinden."; -"do_not_show_again" = "Zeige das nicht noch einmal"; -"sign_in_continue" = "Weitermachen"; -"signing_in_is_optional" = "(Die Anmeldung ist optional)"; -"Defaults.UserAuthorized.title" = "Benutzerautorisiert"; -"Defaults.DashboardTapActionChart.title" = "Tippen Sie auf die Dashboard-Karte, um das Diagramm anzuzeigen"; -"Defaults.DevServer.title" = "Verwenden Sie einen Entwicklungsserver"; -"Defaults.DevServer.message" = "Um den Ruuvi Cloud-Endpunkt zu ändern, müssen Sie sich von der aktuellen Sitzung abmelden und die App neu starten. Bist du dir sicher?"; -"Defaults.ShowEmailAlertsSettings.title" = "Einstellungen für E-Mail-Benachrichtigungen anzeigen"; -"Defaults.ShowPushAlertsSettings.title" = "Einstellungen für Push-Benachrichtigungen anzeigen"; -"use_nfc" = "Verwenden Sie NFC"; -"use_bluetooth" = "Verwenden Sie BT"; -"sensor_not_found_error" = "Sensor nicht gefunden. Versuchen Sie es erneut."; -"Defaults.HideNFC.title" = "Verstecken Sie die NFC-Option vor einem erzwungenen Eigentümerwechsel"; -"settings_alert_sound_default" = "Systemfehler"; -"settings_alert_sound_ruuvi_speak" = "Ruuvi Alarm"; -"add_with_nfc" = "Mit NFC hinzufügen"; -"sensor_details" = "Sensordetails"; -"add_sensor" = "Sensor hinzufügen"; -"copy_mac_address" = "MAC-Adresse kopieren"; -"copy_unique_id" = "Eindeutige ID kopieren"; -"name" = "Name:"; -"mac_address" = "MAC-Adresse:"; -"go_to_sensor" = "Gehen Sie zur Sensorkarte"; -"unique_id" = "Eindeutige ID:"; -"firmware_version" = "Firmware Version:"; -"Close" = "Schließen"; -"add_sensor_nfc_df3_error" = "Dieser Sensor kann aufgrund der alten Firmware nicht mit NFC hinzugefügt werden. Bitte fügen Sie den Sensor über Bluetooth hinzu und aktualisieren Sie die Firmware."; -"add_sensor_description" = "Auf dieser Seite werden Ruuvi-Sensoren in der Nähe angezeigt, die der App noch nicht hinzugefügt wurden. Tippen Sie auf einen Sensor, um ihn hinzuzufügen."; -"add_sensor_via_nfc" = "Alternativ können Sie einen Sensor über NFC hinzufügen, indem Sie Mit NFC hinzufügen auswählen und ihn mit Ihrem Telefon berühren."; -"unclaim_sensor" = "Anspruch auf Eigentum zurückziehen"; -"unclaim" = "Anspruch aufheben"; -"unclaim_sensor_description" = "Das Eigentum an diesem Sensor wurde Ihrem Ruuvi-Konto zugeordnet. Klicken Sie auf „Anspruch aufheben“, um die Einstellungen dieses Sensors und die zugehörigen Daten aus Ihrem Ruuvi-Konto zu entfernen."; -"claim_sensor_ownership" = "Beanspruchen Sie den Besitz des Sensors"; -"do_you_own_sensor" = "Besitzen Sie diesen Sensor?"; -"owners_plan" = "Ruuvi-Plan des Eigentümers"; -"alert_cloud_connection_title" = "Cloud-Verbindung"; -"alert_cloud_connection_description" = "Warnung, wenn Sensordaten länger als %d Minuten nicht in der Cloud aktualisiert wurden."; -"alert_cloud_connection_dialog_description" = "Geben Sie die gewünschte Verzögerung in Minuten ein, bevor die Warnung ausgelöst wird. Der Mindestwert beträgt 2 Minuten."; -"alert_cloud_connection_dialog_title" = "Cloud-Verbindungsalarm einstellen"; -"rename" = "Umbenennen"; -"chart_stat_show" = "Min./Max./Durchschnitt anzeigen"; -"chart_stat_hide" = "Min./Max./Durchschnitt ausblenden"; -"settings_alert_limit_notification" = "Beschränken Sie Warnmeldungen"; -"settings_alert_limit_notification_description" = "Lösen Sie die Bluetooth-Benachrichtigung nur einmal pro Stunde aus, auch wenn die Warnung erneut ausgelöst wurde."; -"share_pending" = "Freigabe ausstehend"; -"share_pending_message" = "Erfolgreich geteilt! Diese E-Mail-Adresse ist noch nicht mit einem Ruuvi-Konto verknüpft. Eine Einladung zur Erstellung eines kostenlosen Kontos wurde gesendet. Nach der Erstellung werden Sie es in der Freigabeliste sehen."; -"dialog_are_you_sure" = "Sind Sie sicher?"; -"dialog_operation_undone" = "Dieser Vorgang kann nicht rückgängig gemacht werden."; -"remove_cloud_history_title" = "Cloud-Historie entfernen"; -"remove_cloud_history_description" = "Ich möchte auch die Sensorverlaufsdaten aus Ruuvi Cloud entfernen."; -"remove_claimed_sensor_description" = "Durch das Entfernen des Sensors wird Ihr Sensor-Eigentumsstatus aufgehoben, und Sensor-Einstellungen wie Name, Hintergrundbild, Kalibrierungseinstellungen und Alarmeinstellungen werden entfernt. Nach der Entfernung kann jemand anderes das Eigentum am Sensor beanspruchen. Jeder Ruuvi-Sensor kann nur einen Besitzer haben."; -"remove_shared_sensor_description" = "Wenn Sie diesen freigegebenen Sensor entfernen, wird der Eigentümer des Sensors benachrichtigt und Sie können nicht mehr auf den Sensor zugreifen.\n\nSie verlieren außerdem alle zugehörigen Sensoreinstellungen wie Name, Hintergrundbild und Alarmkonfigurationen ."; -"remove_local_sensor_description" = "Wenn Sie diesen Sensor entfernen, führt dies zur Löschung Ihres lokal gespeicherten Messverlaufs sowie zur Entfernung aller zugehörigen Sensoreinstellungen wie Name, Hintergrundbild, Kalibrierung und Alarmkonfigurationen.\n\nSie können hinzufügen diesen Sensor später bei Bedarf erneut."; -"activity_saving_to_cloud" = "Speichern in der Cloud...bitte warten."; -"activity_saving_success" = "Erfolgreich gespeichert."; -"activity_saving_fail" = "Die Änderungen konnten nicht in der Cloud gespeichert werden."; -"activity_ongoing_generic" = "Bitte warten..."; -"activity_success_generic" = "Operation erfolgreich."; -"activity_failed_generic" = "Operation fehlgeschlagen."; -"Devices.tokenId" = "Token Id"; -"UserApiError.ER_GATEWAY_NOT_FOUND" = "Gateway not found"; -"UserApiError.ER_GATEWAY_ALREADY_WHITELISTED" = "Gateway already whitelisted"; -"UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED" = "Gateway status report failed"; -"UserApiError.ER_CONFLICT" = "Data already exists, cannot update"; -"UserApiError.ER_CLAIM_COUNT_REACHED" = "Maximum claim count for the user reached"; -"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Maximum share count for the sensor reached"; -"UserApiError.ER_NO_DATA_TO_SHARE" = "In order to share a sensor, it must have data"; -"UserApiError.ER_SENSOR_ALREADY_REGISTERED" = "The sensor has already been registered"; -"UserApiError.ER_SUBSCRIPTION_CODE_EXISTS" = "Tried to add duplicate subscription to a code"; -"UserApiError.ER_SUBSCRIPTION_CODE_USED" = "Tried to claim already used code"; -"UserApiError.ER_OLD_ENTRY" = "Newer data already exists, cannot update"; -"UserApiError.ER_INVALID_ENUM_VALUE" = "Invalid ENUM value given"; -"UserApiError.OK" = "Operation was successful"; diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings deleted file mode 100644 index df8b7ce15..000000000 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings +++ /dev/null @@ -1,767 +0,0 @@ -// swiftlint:disable all -// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen -"Done" = "Done"; -"Copy" = "Copy"; -"Confirm" = "Confirm"; -"Remove" = "Remove"; -"N/A" = "-"; -"g" = "g"; -"About.Version.text" = "Version"; -"Background.PresentNotifications.title" = "Show Notifications"; -"Background.KeepConnection.title" = "Keep the Connection"; -"Background.Interval.Every.string" = "every"; -"Background.Interval.Min.string" = "min"; -"Background.readRSSITitle.title" = "Read RSSI"; -"BluetoothError.disconnected" = "Disconnected"; -"Cards.BluetoothDisabledAlert.title" = "Bluetooth is not enabled"; -"Cards.BluetoothDisabledAlert.message" = "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on."; -"Cards.WebTagAPILimitExcededError.Alert.title" = "Too many requests"; -"Cards.WebTagAPILimitExcededError.Alert.message" = "Please try again in 5 minutes"; -"Cards.KeepConnectionDialog.message" = "Seems like you are running a connectable firmware on your Ruuvi device. Would you like to keep the connection open to this Ruuvi device in the background? This will allow histograms and alerts to work even when the application is minimised."; -"Cards.KeepConnectionDialog.Dismiss.title" = "Cancel"; -"Cards.KeepConnectionDialog.KeepConnection.title" = "Keep the Connection"; -"Cards.LegacyFirmwareUpdateDialog.message" = "Looks like your sensor is using an old firmware software version. To access new features such as history graphs, alerts and cloud services, updating is mandatory."; -"Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message" = "Are you sure? Without updating, you won't be able to claim ownership of the sensor, download history graphs and set alerts. The update also includes bug fixes. If you cancel now, you can start the update process again from the sensor's settings page."; -"Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title" = "Check for update"; -"Cards.Connected.title" = "Connected"; -"Cards.Error.ReverseGeocodingFailed.message" = "Failed to load data for Virtual Sensor. Reverse geocode operation limit exceeded."; -"Cards.UpdatedLabel.NoData.message" = "No data during the last 10 days"; -"CoreError.failedToGetPngRepresentation" = "Failed to get PNG representation"; -"CoreError.failedToGetDocumentsDirectory" = "Failed to get background directory"; -"CoreError.failedToGetCurrentLocation" = "Failed to get current location"; -"CoreError.failedToGetDataFromResponse" = "Failed to get data from response"; -"CoreError.locationPermissionDenied" = "Missing permission for Location Services"; -"CoreError.locationPermissionNotDetermined" = "Location permission authorisation status is not determined"; -"CoreError.objectNotFound" = "Object not found"; -"CoreError.objectInvalidated" = "Object invalidated"; -"CoreError.unableToSendEmail" = "Unable to send email"; -"Defaults.navigationItem.title" = "Defaults"; -"Defaults.WelcomeShown.title" = "Welcome Displayed"; -"Defaults.ChartsSwipeInstructionWasShown.title" = "Charts Swipe Hint Was Shown"; -"Defaults.Interval.Sec.string" = "sec"; -"Defaults.Interval.Min.string" = "min"; -"Defaults.ConnectionTimeout.title" = "Connection Timeout"; -"Defaults.ServiceTimeout.title" = "Service Timeout"; -"Defaults.CardsSwipeHint.title" = "Cards Swipe Hint Was Shown"; -"Defaults.AlertsRepeatInterval.title" = "Alerts Interval"; -"Defaults.WebPullInterval.title" = "Web Alerts Interval"; -"Defaults.PruningOffsetHours.title" = "Pruning Offset Hours"; -"Defaults.Interval.Hour.string" = "h"; -"Defaults.ChartDurationHours.title" = "Chart Duration"; -"Defaults.AppLaunchRequiredForReview.Count.title" = "App launch count to ask for review for the first time"; -"Defaults.AskReviewIfLaunchDivisibleBy.Count.title" = "Ask review if app launch divisible by"; -"DiscoverTable.SectionTitle.WebTags" = "Virtual sensors"; -"DiscoverTable.BluetoothDisabledAlert.title" = "Bluetooth is not enabled"; -"DiscoverTable.BluetoothDisabledAlert.message" = "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on."; -"DiscoverTable.NavigationItem.title" = "Add a New Sensor"; -"DiscoverTable.GetMoreSensors.button.title" = "Buy Ruuvi Sensors"; -"DiscoverTable.NoDevicesSection.NotFound.text" = "(No sensors in Bluetooth range)"; -"DiscoverTable.NoDevicesSection.BluetoothDisabled.text" = "(Bluetooth is disabled)"; -"DiscoverTable.WebTagsInfoDialog.message" = "Virtual Sensors show public weather data provided by local weather stations."; -"DiscoverTable.RuuviDevice.prefix" = "Ruuvi"; -"ErrorPresenterAlert.Error" = "Error"; -"ErrorPresenterAlert.OK" = "OK"; -"ExpectedError.missingOpenWeatherMapAPIKey" = "Missing OpenWeatherMap API Key. Please get one from openweathermap.org website and enter it in the station/Classes/Networking/Assembly/Networking.plist file"; -"ExpectedError.isAlreadySyncingLogsWithThisTag" = "App is already in the process of syncing logs with this sensor"; -"ExpectedError.failedToDeleteTag" = "Unable to remove a connected device that is not reachable. Please check your Bluetooth connection."; -"ExportService.Date" = "Date"; -"ExportService.ISO8601" = "ISO8601"; -"ExportService.Temperature" = "Temperature (%@)"; -"ExportService.Humidity" = "Humidity (%@)"; -"ExportService.DewPoint" = "Dew point (%@)"; -"ExportService.Pressure" = "Pressure (%@)"; -"ExportService.Voltage" = "Voltage (V)"; -"ExportService.MovementCounter" = "Movement Counter"; -"ExportService.MeasurementSequenceNumber" = "Measurement Sequence Number"; -"ExportService.TXPower" = "TX Power"; -"ForegroundRow.advertisement.section" = "ADVERTISEMENTS"; -"ForegroundRow.advertisement.title" = "Save advertisements"; -"ForegroundRow.connection.section" = "LOGS"; -"ForegroundRow.connection.title" = "Connect and sync logs"; -"Foreground.navigationItem.title" = "Foreground"; -"Foreground.Interval.Every.string" = "Every"; -"Foreground.Interval.Min.string" = "min"; -"ForegroundRow.webTags.title" = "Load and save from web"; -"ForegroundRow.webTags.section" = "VIRTUAL SENSORS"; -"Foreground.Interval.All.string" = "All"; -"Heartbeat.Interval.Every.string" = "every"; -"Heartbeat.Interval.Min.string" = "min"; -"Heartbeat.readRSSITitle.title" = "Read RSSI"; -"Heartbeat.Interval.Sec.string" = "sec"; -"Heartbeat.Interval.All.string" = "All"; -"HumidityCalibration.ClearCalibrationConfirmationAlert.title" = "Are you sure?"; -"HumidityCalibration.ClearCalibrationConfirmationAlert.message" = "You are going to clear humidity offset. This can't be undone. Tap \"Confirm\" to continue."; -"HumidityCalibration.CalibrationConfirmationAlert.title" = "Are you sure?"; -"HumidityCalibration.CalibrationConfirmationAlert.message" = "You are going to calibrate humidity offset. Tap \"Confirm\" to continue"; -"Language.English" = "English"; -"Language.Finnish" = "Suomi"; -"Language.Russian" = "Русский"; -"Language.Swedish" = "Svenska"; -"Language.French" = "Français"; -"Language.German" = "Deutsch"; -"LocalNotificationsManager.DidConnect.title" = "Connected"; -"LocalNotificationsManager.DidDisconnect.title" = "Disconnected"; -"LocalNotificationsManager.Disable.button" = "Turn off"; -"LocalNotificationsManager.LowDewPoint.title" = "Dew Point is too low!"; -"LocalNotificationsManager.HighDewPoint.title" = "Dew Point is too high!"; -"PermissionPresenter.NoPhotoLibraryAccess.message" = "Ruuvi Station needs to access your camera library to enable this feature."; -"PermissionPresenter.NoCameraAccess.message" = "Ruuvi Station needs to access your camera to enable this feature."; -"PermissionPresenter.NoLocationAccess.message" = "Ruuvi Station needs to access your location to enable this feature."; -"PermissionPresenter.settings" = "Settings"; -"PermissionPresenter.NoPushNotificationsPermission.message" = "Ruuvi Station needs push notifications permission to enable this feature"; -"PhotoPicker.Sheet.message" = "Pick a photo"; -"PhotoPicker.Sheet.library" = "Choose from the library"; -"PhotoPicker.Sheet.camera" = "Take photo"; -"Settings.SegmentedControl.Humidity.Relative.title" = "Rel"; -"Settings.SegmentedControl.Humidity.Absolute.title" = "Abs"; -"Settings.SegmentedControl.Humidity.DewPoint.title" = "Dew"; -"Settings.Label.Language.text" = "Language"; -"Settings.Language.Dialog.title" = "Select Language"; -"Settings.Language.Dialog.message" = "Open settings and tap Language to change language of the app. -If you cannot see the Language option in the settings, make sure that you have at least one preferred language added in system settings: Settings -> General -> Language & Region."; -"Settings.Label.Foreground" = "Foreground"; -"Settings.Label.Defaults" = "Defaults"; -"OWMError.failedToParseOpenWeatherMapResponse" = "Failed to parse Open Weather Map response"; -"OWMError.apiLimitExceeded" = "API limit exceeded"; -"OWMError.notAHttpResponse" = "Not an HTTP response"; -"OWMError.invalidApiKey" = "Invalid API Key"; -"TagCharts.NoChartData.text" = "No chart data available"; -"TagCharts.BluetoothDisabledAlert.title" = "Bluetooth is not enabled"; -"TagCharts.BluetoothDisabledAlert.message" = "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on."; -"TagCharts.Clear.title" = "Clear"; -"TagCharts.SyncConfirmationDialog.title" = "Are you sure?"; -"TagCharts.DeleteHistoryConfirmationDialog.button.delete.title" = "Delete"; -"TagCharts.DeleteHistoryConfirmationDialog.title" = "Are you sure?"; -"TagCharts.Status.Disconnecting" = "Disconnecting..."; -"TagCharts.Status.Success" = "Success"; -"TagCharts.Status.Error" = "Error"; -"TagSettings.UUID.Alert.title" = "UUID"; -"TagSettings.UpdateFirmware.Alert.title" = "RAWv2 mode is required"; -"TagSettings.UpdateFirmware.Alert.message" = "In order to see missing values:\nIf you are using the latest firmware, set RAWv2 mode by pressing \"B\" on a sensor.\nOr update your sensor with the latest firmware."; -"TagSettings.UpdateFirmware.Alert.Buttons.LearnMore.title" = "Learn more"; -"TagCharts.Dismiss.Alert.message" = "The history download via Bluetooth connection is in progress. Please wait."; -"TagCharts.AbortSync.Alert.message" = "Sometimes the history download is slow due to the Bluetooth connectivity. Please wait a moment."; -"TagCharts.AbortSync.Button.title" = "Abort download"; -"TagSettings.EmptyValue.sign" = "-"; -"TagSettings.HumidityIsClipped.Alert.title" = "Humidity is adjusted"; -"TagSettings.HumidityIsClipped.Alert.message" = "Humidity value is greater than 100% after calibration. This value doesn't make sense, so the value has been adjusted to 100%."; -"TagSettings.HumidityIsClipped.Alert.Fix.button" = "Fix"; -"TagSettings.navigationItem.title" = "Sensor Settings"; -"TagSettings.tagNameTitleLabel.text" = "Name"; -"TagSettings.humidityTitleLabel.text" = "Humidity"; -"TagSettings.uuidTitleLabel.text" = "UUID"; -"TagSettings.macAddressTitleLabel.text" = "MAC Address"; -"TagSettings.dataFormatTitleLabel.text" = "Data Format"; -"TagSettings.accelerationXTitleLabel.text" = "Acceleration X"; -"TagSettings.accelerationYTitleLabel.text" = "Acceleration Y"; -"TagSettings.accelerationZTitleLabel.text" = "Acceleration Z"; -"TagSettings.txPowerTitleLabel.text" = "Tx Power"; -"TagSettings.mcTitleLabel.text" = "Movement Counter"; -"TagSettings.msnTitleLabel.text" = "Measurement Sequence Number"; -"TagSettings.SectionHeader.Remove.title" = "REMOVE"; -"TagSettings.Label.noValues.text" = "NO VALUES?"; -"TagSettings.SectionHeader.Calibration.title" = "CALIBRATION"; -"TagSettings.SectionHeader.BTConnection.title" = "BLUETOOTH CONNECTION"; -"TagSettings.PairAndBackgroundScan.Unpaired.title" = "Pair and use background scan"; -"TagSettings.PairAndBackgroundScan.Pairing.title" = "Connecting to the sensor"; -"TagSettings.PairAndBackgroundScan.Paired.title" = "Paired and background scan is on"; -"TagSettings.PairAndBackgroundScan.description" = "Alerts are not available over Bluetooth connection if background scanning is not enabled. Only one iOS device can be paired to a Ruuvi sensor at a time."; -"TagSettings.PairError.CloudMode.description" = "The sensor cannot be connected to via Bluetooth when the cloud mode is active. You can re-enable the Bluetooth connection for the cloud sensors by disabling cloud mode in the app settings."; -"TagSettings.PairError.Timeout.description" = "Connection timed out. Pairing was unsuccessful. Please try again."; -"TagSettings.dataSourceTitleLabel.text" = "Data Received Via"; -"TagSettings.DataSource.Heartbeat.title" = "Heartbeat"; -"TagSettings.DataSource.Advertisement.title" = "Advertisement"; -"TagSettings.DataSource.Network.title" = "Cloud"; -"TagSettings.Label.disabled.text" = "DISABLED?"; -"TagSettings.AlertsAreDisabled.Dialog.BothNotConnectedAndNoPNPermission.message" = "Alerts are disabled because the device is not connected and missing push notification permission. Please connect to the device first."; -"TagSettings.AlertsAreDisabled.Dialog.Connect.title" = "Connect"; -"TagSettings.AlertsAreDisabled.Dialog.NotConnected.message" = "Alerts are disabled because you are not connected to the device."; -"TagSettings.Alert.CustomDescription.placeholder" = "Set custom description..."; -"TagSettings.Alert.CustomDescription.title" = "Alert custom description"; -"TagSettings.Alerts.Humidity.description" = "Alert when less than %.0f or more than %.0f"; -"TagSettings.Alerts.DewPoint.description" = "Alert when less than %.0f or more than %.0f"; -"TagSettings.dewPointAlertTitleLabel.text" = "Dew Point"; -"TagSettings.Alerts.Pressure.description" = "Alert when less than %.0f or more than %.0f"; -"TagSettings.Alerts.Connection.description" = "Alert when connected/disconnected"; -"TagSettings.ConnectionAlert.title" = "Connection"; -"TagSettings.SectionHeader.Firmware.title" = "Firmware"; -"TagSettings.Firmware.CurrentVersion" = "Current version"; -"TagSettings.Firmware.CurrentVersion.VeryOld" = "Very old"; -"TagSettings.Firmware.UpdateFirmware" = "Update"; -"UnexpectedError.callbackErrorAndResultAreNil" = "Both callback result and error are nil"; -"UnexpectedError.callerDeinitedDuringOperation" = "Caller was deallocated during operation"; -"UnexpectedError.failedToReverseGeocodeCoordinate" = "Failed to reverse geocode location"; -"UnexpectedError.failedToFindRuuviTag" = "Failed to find sensor"; -"UnexpectedError.failedToFindLogsForTheTag" = "Failed to find logs for the sensor"; -"UnexpectedError.viewModelUUIDIsNil" = "View Model UUID is nil"; -"UnexpectedError.attemptToReadDataFromRealmWithoutLUID" = "Attempt to read data from Realm without LUID"; -"UnexpectedError.failedToFindVirtualTag" = "Failed to find virtual sensor"; -"HumidityUnit.Dew.title" = "Dew point (%@)"; -"WebTagLocationSource.current" = "Your location"; -"WebTagLocationSource.manual" = "Pick from the map"; -"WebTagSettings.confirmTagRemovalDialog.title" = "Remove virtual sensor"; -"WebTagSettings.confirmTagRemovalDialog.message" = "Are you sure you want to remove this virtual sensor?"; -"WebTagSettings.Location.Current" = "Your location"; -"WebTagSettings.confirmClearLocationDialog.title" = "Clear Location"; -"WebTagSettings.confirmClearLocationDialog.message" = "Are you sure you want to clear location for this virtual sensor? Current location will be used instead."; -"WebTagSettings.navigationItem.title" = "Virtual Sensor Settings"; -"WebTagSettings.Label.BackgroundImage.text" = "BACKGROUND\nIMAGE"; -"WebTagSettings.Label.Location.text" = "Location"; -"WebTagSettings.Button.Remove.title" = "REMOVE THIS VIRTUAL SENSOR"; -"WebTagSettings.SectionHeader.Name.title" = "NAME"; -"WebTagSettings.SectionHeader.MoreInfo.title" = "MORE INFO"; -"WebTagSettings.Alerts.Temperature.description" = "Alert when less than %.0f or more than %.0f"; -"WebTagSettings.Alerts.Off" = "Off"; -"WebTagSettings.temperatureAlertTitleLabel.text" = "Temperature"; -"WebTagSettings.Label.disabled.text" = "DISABLED?"; -"WebTagSettings.Label.alerts.text" = "ALERTS"; -"WebTagSettings.AlertsAreDisabled.Dialog.BothNoPNPermissionAndNoLocationPermission.message" = "In order to enable virtual sensor alerts please always grant location and notification permissions in Settings."; -"WebTagSettings.AlertsAreDisabled.Dialog.Settings.title" = "Settings"; -"WebTagSettings.AirHumidityAlert.title" = "Air Humidity"; -"WebTagSettings.Alerts.Humidity.description" = "Alert when less than %.0f or more than %.0f"; -"WebTagSettings.Alerts.DewPoint.description" = "Alert when less than %.0f or more than %.0f"; -"WebTagSettings.dewPointAlertTitleLabel.text" = "Dew Point"; -"WebTagSettings.PressureAlert.title" = "Air Pressure"; -"WebTagSettings.Alerts.Pressure.description" = "Alert when less than %.0f or more than %.0f"; -"Welcome.description.text" = "To find nearby sensors and receive live sensor data, press 'scan'."; -"ExportService.AccelerationX" = "Acceleration X"; -"ExportService.AccelerationY" = "Acceleration Y"; -"ExportService.AccelerationZ" = "Acceleration Z"; -"DiscoverTable.SectionTitle.Devices" = "Nearby Ruuvi sensors"; -"ago" = "ago"; -"TagSettings.MovementAlert.title" = "Movement"; -"TagSettings.Alerts.Movement.description" = "Alert when sensor is moved"; -"LocalNotificationsManager.HighHumidity.title" = "Air Humidity is too high!"; -"LocalNotificationsManager.LowHumidity.title" = "Air Humidity is too low!"; -"LocalNotificationsManager.DidMove.title" = "Movement detected!"; -"LocalNotificationsManager.HighPressure.title" = "Air Pressure is too high!"; -"LocalNotificationsManager.LowPressure.title" = "Air Pressure is too low!"; -"LocalNotificationsManager.HighSignal.title" = "Signal strength is too high!"; -"LocalNotificationsManager.LowSignal.title" = "Signal strength is too low!"; -"LocalNotificationsManager.HighTemperature.title" = "Temperature is too high!"; -"LocalNotificationsManager.LowTemperature.title" = "Temperature is too low!"; -"TagSettings.Alerts.Off" = "Off"; -"TagSettings.Alerts.Temperature.description" = "Alert when less than %.0f or more than %.0f"; -"TagSettings.Label.alerts.text" = "Alerts"; -"TagSettings.backgroundImageLabel.text" = "Background image"; -"TagSettings.batteryVoltageTitleLabel.text" = "Battery Voltage"; -"HumidityCalibration.Button.Calibrate.title" = "Calibrate"; -"HumidityCalibration.lastCalibrationDate.format" = "Calibrated: %@"; -"HumidityCalibration.Description.text" = "In order to measure relative humidity as accurately as possible, a sodium chloride (salt) calibration is recommended. See video tutorials on how to easily do this at home."; -"HumidityCalibration.Label.note.text" = "Note that calibration data will be stored locally in your mobile device. After Ruuvi Station uninstall and install, you may need to recalibrate."; -"HumidityCalibration.VideoTutorials.link" = "video tutorials"; -"Cancel" = "Cancel"; -"HumidityCalibration.Button.Clear.title" = "Clear"; -"TagCharts.DeleteHistoryConfirmationDialog.message" = "Clear the local history data from the app?"; -"HumidityCalibration.Button.Close.title" = "Close"; -"TagCharts.Status.Serving" = "Synchronising..."; -"TagCharts.Status.Connecting" = "Connecting..."; -"TagSettings.ConnectStatus.Disconnected" = "Disconnected"; -"TagCharts.Export.title" = "EXPORT"; -"h" = "h"; -"About.AboutHelp.contents" = "Ruuvi Station is an easy-to-use application that allows you to monitor the measurement data of Ruuvi sensors."; -"About.AboutHelp.header" = "About / Help"; -"About.TagsCount.text" = "Added sensors: %d"; -"About.MeasurementsCount.text" = "Number of locally stored measurements: %d"; -"About.DatabaseSize.text" = "Database size: %@"; -"About.More.contents" = "Ruuvi's website: ruuvi.com\nRuuvi Forum: f.ruuvi.com\nRuuvi Blog: ruuvi.com/blog\nRuuvi on Twitter: twitter.com/ruuvicom"; -"About.More.header" = "More to read"; -"About.OpenSource.contents" = "Just like Ruuvi sensors, Ruuvi Station apps are open source. Follow the development and contribute at: github.com/ruuvi"; -"About.OpenSource.header" = "Open-source"; -"About.OperationsManual.contents" = "Get started using the Ruuvi Station mobile application with our online guides: ruuvi.com/support/station-mobile"; -"About.OperationsManual.header" = "Operations manual"; -"About.Privacy.contents" = "By using the application, you accept Ruuvi's standard terms and conditions: ruuvi.com/terms"; -"About.Privacy.header" = "Privacy policy"; -"About.Troubleshooting.contents" = "Find help using the Ruuvi Station apps, Ruuvi products and Ruuvi Cloud service from our support center: ruuvi.com/support"; -"About.Troubleshooting.header" = "Troubleshooting"; -"hours" = "Hours"; -"Interval.Days.string" = "Days"; -"TagSettings.AirHumidityAlert.title" = "Air Humidity (%@)"; -"HumidityUnit.gm3.title" = "Absolute (g/m³)"; -"g/m³" = "g/m³"; -"HumidityUnit.Percent.title" = "Relative (%)"; -"TagSettings.Mac.Alert.title" = "MAC Address"; -"Menu.Label.AboutHelp.text" = "About / Help"; -"Menu.Label.AddAnNewSensor.text" = "Add a New Sensor"; -"Menu.Label.AppSettings.text" = "App Settings"; -"Menu.Label.GetMoreSensors.text" = "Buy Ruuvi Sensors"; -"Ruuvi.BuySensors.URL.IOS" = "https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Ruuvi.BuySensors.Menu.URL.IOS" = "https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios"; -"Menu.Label.BuyRuuviGateway.text" = "Buy Ruuvi Gateway"; -"Menu.BuyGateway.URL.IOS" = "https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Menu.Label.WhatToMeasure.text" = "What to measure with Ruuvi?"; -"Menu.Measure.URL.IOS" = "https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Menu.Label.Feedback.text" = "Send Feedback"; -"Menu.Label.MyRuuviAccount.text" = "My Ruuvi Account"; -"min" = "min"; -"minutes" = "Minutes"; -"TagSettings.Label.moreInfo.text" = "More info"; -"TagSettings.SectionHeader.Name.title" = "NAME"; -"No" = "No"; -"OK" = "OK"; -"Cards.NoSensors.title" = "No sensors added\nPress here to add sensors"; -"TagSettings.PressureAlert.title" = "Air Pressure (%@)"; -"UnitPressure.hectopascal.title" = "Hectopascal (hPa)"; -"hPa" = "hPa"; -"UnitPressure.inchOfMercury.title" = "Inch of mercury (inHg)"; -"UnitPressure.millimetreOfMercury.title" = "Millimetre of mercury (mmHg)"; -"TagCharts.Status.ReadingHistory" = "Reading history"; -"TagSettings.rssiTitleLabel.text" = "Signal Strength (RSSI)"; -"signal_strength_dbm" = "Signal Strength (dBm)"; -"s" = "s"; -"Welcome.scan.title" = "SCAN"; -"Background.Interval.Sec.string" = "sec"; -"Settings.navigationItem.title" = "Settings"; -"Settings.BackgroundScanning.title" = "Background Scanning"; -"Settings.BackgroundScanning.Footer.message" = "Important note: Bluetooth background history logging and Bluetooth alerts work only when background scanning is enabled. If you disable the background scanning, all paired Ruuvi sensors will be automatically unpaired and you need to pair them again from their settings pages."; -"Settings.BackgroundScanning.interval" = "Data logging interval"; -"Settings.Label.Chart" = "Chart Settings"; -"ChartSettings.AllPoints.title" = "Show all measurements"; -"ChartSettings.AllPoints.description" = "Charts may be updated slowly when enabled."; -"ChartSettings.DrawDots.title" = "Show datapoints"; -"ChartSettings.DrawDots.description" = "Small dots will help to understand when measurements were collected."; -"Defaults.ChartIntervalSeconds.title" = "Chart Interval"; -"ChartSettings.Duration.title" = "Chart History View Period"; -"ChartSettings.Duration.description" = "Configure the period of history to be shown on chart from 1 to 10 days."; -"Settings.Label.HumidityUnit.text" = "Humidity Unit"; -"Settings.Label.Temperature" = "Temperature"; -"Settings.Label.Humidity" = "Humidity"; -"Settings.Label.Pressure" = "Pressure"; -"Settings.ChooseHumidityUnit.text" = "Choose the humidity unit you want to be displayed."; -"Settings.Label.PressureUnit.text" = "Pressure Unit"; -"Settings.ChoosePressureUnit.text" = "Choose the pressure unit you want to be displayed."; -"Settings.Label.TemperatureUnit.text" = "Temperature Unit"; -"Settings.ChooseTemperatureUnit.text" = "Choose the temperature unit you want to be displayed."; -"dBm" = "dBm"; -"TagCharts.Sync.title" = "Sync"; -"TagCharts.SyncConfirmationDialog.message" = "Download history data from the sensor?"; -"WebTagSettings.Label.TagName.text" = "Sensor Name"; -"TagSettings.confirmTagRemovalDialog.title" = "Remove sensor"; -"TagSettings.confirmTagRemovalDialog.message" = "Do you want to remove the sensor? You can add it again later, if needed."; -"TagSettings.temperatureAlertTitleLabel.text" = "Temperature (%@)"; -"TemperatureUnit.Celsius.title" = "Celsius (℃)"; -"ºC" = "°C"; -"TemperatureUnit.Fahrenheit.title" = "Fahrenheit (℉)"; -"ºF" = "°F"; -"TemperatureUnit.Kelvin.title" = "Kelvin (K)"; -"Updated" = "Updated"; -"V" = "V"; -"RuuviOnboard.Welcome.title" = "Swipe to see what Ruuvi Station can do for you."; -"RuuviOnboard.Measure.title" = "Measure environmental data: temperature, relative humidity and air pressure."; -"RuuviOnboard.Access.title" = "Access data for each linked sensor in real time and explore history graphs."; -"RuuviOnboard.Alerts.title" = "Set alerts and get notified whenever your limits are hit."; -"RuuviOnboard.Cloud.title" = "Sign in to use the full potential of the app."; -"RuuviOnboard.Cloud.subtitle" = "Claim ownership of your sensors with a free Ruuvi Cloud account."; -"RuuviOnboard.Cloud.subtitle.signed" = "Great! You already signed in!"; -"RuuviOnboard.Start.title" = "Press SCAN to find and add nearby sensors to your Ruuvi Station."; -"Yes" = "Yes"; -"LocalNotificationsManager.Mute.button" = "Mute for an hour"; -"Defaults.AlertsMuteInterval.title" = "Alerts Mute Interval"; -"SignIn.Title.text" = "Sign in"; -"Menu.SignOut.text" = "Sign out"; -"RuuviOnboard.Cloud.Benefits.message" = "Benefits:\n\n ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud\n\n ● Access sensors remotely over the Internet (requires a Ruuvi Gateway)\n\n ● Share sensors with friends and family (requires a Ruuvi Gateway)\n\n ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway)"; -"RuuviOnboard.Cloud.Details.title" = "Details"; -"ruuvi_cloud" = "Ruuvi Cloud"; -"RuuviOnboard.Cloud.Skip.title" = "Are you sure you want to skip sign in?"; -"RuuviOnboard.Cloud.Skip.Yes.title" = "Yes, skip"; -"RuuviOnboard.Cloud.Skip.GoBack.title" = "Go back"; -"SignIn.EmailPlaceholder" = "Email"; -"SignIn.RequestCode" = "Request a code"; -"SignIn.SubmitCode" = "Submit"; -"SignIn.EmailSent" = "Email sent"; -"SignIn.CheckMailbox" = "We've sent a one-time password to your email %@. Sign in by entering it here:"; -"SignIn.CodeHint" = "Code"; -"TagsManagerPresenter.SignOutConfirmAlert.Message" = "When you sign out, sensors the ownerships of which you've claimed on the sensor Settings page will be automatically removed from the app. When you sign in again using the same email address, the sensors will be returned from the cloud.\n\nDo you want to sign out?"; -"TagSettings.ClaimTagButton.Claim" = "Claim ownership"; -"TagSettings.ShareButton" = "Share"; -"Syncing..." = "Loading history from the cloud..."; -"Synchronized" = "Synchronised"; -"TagChartsPresenter.NumberOfPointsSynchronizedOverNetwork" = "Synchronised: %@"; -"MenuTableViewController.None" = "none"; -"MenuTableViewController.User" = "User: %@"; -"ShareViewController.Title" = "Share sensor"; -"ShareViewController.Description" = "You can share the sensor with friends and family if it's in range of a Ruuvi Gateway.\n\nReceiver will be notified by email. If the receiver doesn't have a Ruuvi account, a free Ruuvi account will automatically be created at first log in.\n\nNote that the sensor's custom name and background image will be shared. The name and image sync is one time only, and after this, they can be privately customised by the receiver. Offset values (if any) set by the owner, will be automatically synced, and the receiver will always see the final corrected values."; -"ShareViewController.addFriend.Title" = "Add friend"; -"ShareViewController.emailTextField.placeholder" = "Type email"; -"ShareViewController.sharedEmails.Title" = "You have used %d/%d of maximum shares of this sensor. The sensor has been shared to following users:"; -"Share.Send.button" = "Send"; -"SharePresenter.UnshareSensor.Message" = "Do you want to unshare sensor for %@?"; -"TagSettings.SectionHeader.NetworkInfo.title" = "NETWORK INFO"; -"TagSettings.NetworkInfo.Owner" = "Owner"; -"Menu.RuuviNetworkStatus.text" = "Ruuvi Cloud status"; -"SignIn.TitleLabel.text" = "Sign in to\nRuuvi\nStation"; -"SignIn.SubtitleLabel.text" = "To enjoy all the features, create a free account or sign in to your existing Ruuvi account by entering your email address."; -"SignIn.VerificationCodePlaceholder" = "verification code in format: CJSM"; -"UserApiError.ER_FORBIDDEN" = "Forbidden"; -"UserApiError.ER_UNAUTHORIZED" = "Unauthorised"; -"UserApiError.ER_INTERNAL" = "Internal error"; -"UserApiError.ER_INVALID_FORMAT" = "Invalid request format"; -"UserApiError.ER_USER_NOT_FOUND" = "User not found"; -"UserApiError.ER_SENSOR_NOT_FOUND" = "Sensor not found"; -"UserApiError.ER_TOKEN_EXPIRED" = "Token is expired"; -"UserApiError.ER_SUBSCRIPTION_NOT_FOUND" = "Subscription is not found"; -"UserApiError.ER_SHARE_COUNT_REACHED" = "The share limit is reached"; -"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Sensor share limit is reached"; -"UserApiError.ER_NO_DATA_TO_SHARE" = "In order to share the sensor, you need to have a Ruuvi Gateway router nearby the sensor"; -"UserApiError.ER_SENSOR_ALREADY_SHARED" = "This sensor is already shared"; -"UserApiError.ER_SENSOR_ALREADY_CLAIMED" = "Sensor already claimed by %@"; -"UserApiError.ER_SENSOR_ALREADY_CLAIMED_NO_EMAIL" = "Sensor already claimed"; -"UserApiError.ER_UNABLE_TO_SEND_EMAIL" = "Unable to send email"; -"UserApiError.ER_MISSING_ARGUMENT" = "Missing argument"; -"UserApiError.ER_INVALID_DENSITY_MODE" = "Invalid density mode"; -"UserApiError.ER_INVALID_SORT_MODE" = "Invalid sort mode"; -"UserApiError.ER_INVALID_TIME_RANGE" = "Invalid time range"; -"UserApiError.ER_INVALID_EMAIL_ADDRESS" = "Invalid email address"; -"UserApiError.ER_INVALID_MAC_ADDRESS" = "Invalid MAC-address"; -"UserApiError.ER_SUB_DATA_STORAGE_ERROR" = "Data storage error"; -"UserApiError.ER_SUB_NO_USER" = "No user"; -"UserApiError.ER_THROTTLED" = "Too many requests"; -"OffsetCorrection.CalibrationDescription.text" = "In normal use, it's not necessary to adjust the offset.\n\nIf you're an advanced user and you'd like to manually configure the factory calibrated sensors, it's possible to do so.\n\nCalibration tips are available on ruuvi.com/support"; -"OffsetCorrection.Dialog.Calibration.ClearConfirm" = "Clear calibration settings?"; -"OffsetCorrection.Dialog.Calibration.Title" = "Calibration setup"; -"OffsetCorrection.Dialog.Calibration.EnterTemperature" = "Enter the expected temperature value from sensor under current conditions (%@): "; -"OffsetCorrection.Dialog.Calibration.EnterPressure" = "Enter the expected pressure value from sensor under current conditions (%@): "; -"OffsetCorrection.Dialog.Calibration.EnterHumidity" = "Enter the expected humidity value from sensor under current conditions (%@): "; -"OffsetCorrection.OriginalValue.title" = "Original measured value"; -"OffsetCorrection.CorrectedValue.title" = "Corrected value"; -"OffsetCorrection.Temperature.Title" = "Temperature offset"; -"OffsetCorrection.Humidity.Title" = "Humidity offset"; -"OffsetCorrection.Pressure.Title" = "Pressure offset"; -"OffsetCorrection.Calibrate.button" = "Offset correction"; -"TagSettings.SectionHeader.OffsetCorrection.Title" = "OFFSET CORRECTION"; -"TagSettings.OffsetCorrection.Temperature" = "Temperature"; -"TagSettings.OffsetCorrection.Humidity" = "Humidity"; -"TagSettings.OffsetCorrection.Pressure" = "Pressure"; -"PhotoPicker.Sheet.files" = "Choose from files"; -"SignIn.EnterVerificationCode" = "Please enter verification code"; -"UnexpectedError.failedToFindOrGenerateBackgroundImage" = "Failed to find or generate background image"; -"UnexpectedError.bothLuidAndMacAreNil" = "Both local and MAC identifiers are nil"; -"RuuviCloudApiError.emptyResponse" = "Empty response"; -"RuuviCloudApiError.failedToGetDataFromResponse" = "Failed to get data from response"; -"RuuviCloudApiError.unexpectedHTTPStatusCode" = "Unexpected HTTP status code"; -"RuuviCloudError.NotAuthorized" = "Not authorised"; -"RuuviLocalError.failedToGetJpegRepresentation" = "Failed to get JPG representation"; -"RuuviLocalError.failedToGetDocumentsDirectory" = "Failed to get background directory"; -"RuuviPersistenceError.failedToFindRuuviTag" = "Failed to find sensor"; -"RuuviServiceError.pictureUrlIsNil" = "Photo URL is nil"; -"RuuviServiceError.macIdIsNil" = "MAC identifier is nil"; -"network_sharing_disabled" = "Only sensors within range of your Ruuvi Gateway can be shared."; -"RuuviServiceError.bothLuidAndMacAreNil" = "Both local and MAC identifiers are nil"; -"RuuviServiceError.failedToParseNetworkResponse" = "Failed to parse response."; -"RuuviServiceError.failedToFindOrGenerateBackgroundImage" = "Failed to find or generate background image"; -"RuuviServiceError.failedToGetJpegRepresentation" = "Failed to get JPG representation"; -"UpdateFirmware.Title.text" = "Update Firmware"; -"UpdateFirmware.Download.header" = "DOWNLOAD LATEST FIRMWARE"; -"UpdateFirmware.Download.content" = "To start with the update process, first download the latest software package on the device you're going to use for updates. Latest version is available on ruuvi.com/software-update"; -"UpdateFirmware.SetDfu.header" = "SET RUUVI TAG TO DFU MODE"; -"UpdateFirmware.SetDfu.content" = "Open the RuuviTag's enclosure by pulling it open with your fingers or gently with a flat head screw driver.\n\nSet RuuviTag to bootloader mode by holding down button B and pressing reset button R. Red indicator LED light will light up and stay on. If your device has only 1 button, keep it pressed 10 seconds to enter the bootloader."; -"UpdateFirmware.NextButton.title" = "NEXT"; -"DfuDevicesScanner.Title.text" = "Devices"; -"DfuDevicesScanner.Description.text" = "Find and select sensor \"RuuviBoot\"."; -"DfuDevicesScanner.NoDevice.text" = "(No sensors in Bluetooth range)"; -"DfuDevicesScanner.BluetoothDisabled.text" = "(Bluetooth is disabled)"; -"DfuDevicesScanner.BluetoothDisabledAlert.title" = "Bluetooth is not enabled"; -"DfuDevicesScanner.BluetoothDisabledAlert.message" = "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on."; -"DfuFlash.Title.text" = "DFU Flash"; -"DfuFlash.Progress.text" = "Progress"; -"DfuFlash.Step.text" = "Step"; -"DfuFlash.Steps.PackageSelection.text" = "Package selection"; -"DfuFlash.Steps.ReadyForUpload.text" = "Ready For upload"; -"DfuFlash.Steps.Uploading.text" = "Uploading"; -"DfuFlash.Steps.Completed.text" = "Completed"; -"DfuFlash.OpenDocumentPicker.title" = "OPEN DOCUMENT PICKER"; -"DfuFlash.FirmwareSelectionGuide.text" = "Locate the previously downloaded ZIP file on your mobile device."; -"DfuFlash.Firmware.FileName.text" = "File name"; -"DfuFlash.Firmware.Parts.text" = "Parts"; -"DfuFlash.Firmware.Size.text" = "Size"; -"DfuFlash.Firmware.SoftDeviceSize.text" = "Soft Device size"; -"DfuFlash.Firmware.BootloaderSize.text" = "Bootloader size"; -"DfuFlash.Cancel.text" = "CANCEL"; -"DfuFlash.Start.text" = "Start"; -"DfuFlash.Finish.text" = "FINISH"; -"DfuFlash.FinishGuide.text" = "Firmware update process has been completed successfully. -Your RuuviTag sensor is ready for use!"; -"DfuFlash.CancelAlert.text" = "Are you sure you want to cancel the firmware update process?"; -"RuuviDfuError.invalidFirmwareFile" = "Invalid firmware file"; -"DFUUIView.navigationTitle" = "Firmware Update"; -"DFUUIView.latestTitle" = "Latest available Ruuvi Firmware version:"; -"DFUUIView.currentTitle" = "Current version:"; -"DFUUIView.notReportingDescription" = "Your sensor doesn't report its current firmware version. Either you're not in its Bluetooth range, it's connected to another phone, or it's running a very old firmware version."; -"DFUUIView.alreadyOnLatest" = "You are running the latest firmware version, no need to update"; -"DFUUIView.startUpdateProcess" = "Start update process"; -"DFUUIView.downloadingTitle" = "Downloading the latest firmware to be updated..."; -"DFUUIView.prepareTitle" = "Prepare your sensor"; -"DFUUIView.openCoverTitle" = "1. Open the cover of your Ruuvi sensor"; -"DFUUIView.locateBootButtonTitle" = "2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label."; -"DFUUIView.setUpdatingModeTitle" = "3. Set the sensor to updating mode:"; -"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”."; -"DFUUIView.toBootModeOneButtonDescription" = "3.2. If your sensor has a single button: keep the button pressed for 10 seconds."; -"DFUUIView.toBootModeSuccessTitle" = "4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”."; -"DFUUIView.updatingTitle" = "Updating..."; -"DFUUIView.searchingTitle" = "Searching for a sensor"; -"DFUUIView.startTitle" = "Start the update"; -"DFUUIView.doNotCloseTitle" = "Do not close the app or power off the sensor during the update."; -"DFUUIView.successfulTitle" = "Update successful"; -"DFUUIView.DBMigration.Error.message" = "The update was successful, but an unexpected database migration error occurred. To continue using this sensor, please remove it from the app and then add it again."; -"RuuviDfuError.failedToConstructUUID" = "Failed to construct UUID"; -"SignIn.EmailMismatch.Alert.message" = "Oops, you've requested the code for %@, but used the code for %@. Please double check that you are using the code for %@"; -"SignIn.EmailMissing.Alert.message" = "Oops, the email you've used to get the code was not saved. Please try to sign in again."; -"TagSettings.RemoveThisSensor.title" = "Remove this sensor"; -"Share.Success.message" = "Successfully shared sensor"; -"TagSettings.SectionHeader.General.title" = "General"; -"TagSettings.Shared.title" = "Shared"; -"TagSettings.NotShared.title" = "Not shared"; -"Owner.title" = "Claim sensor"; -"Owner.ClaimOwnership.button" = "Claim ownership"; -"Owner.Claim.description" = "Do you own this sensor? If yes, please claim ownership of the sensor and it'll be added to your Ruuvi account. Each Ruuvi sensor can have only one owner. To claim ownership, you need to be signed in.\n\nBenefits:\n\n ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud\n\n ● Access sensors remotely over the Internet (requires a Ruuvi Gateway)\n\n ● Share sensors with friends and family (requires a Ruuvi Gateway)\n\n ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway)"; -"TagSettings.confirmTagUnclaimAndRemoveDialog.message" = "By removing the sensor, your sensor ownership status will be revoked. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner."; -"TagSettings.confirmSharedTagRemovalDialog.message" = "If you remove the sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore."; -"TagSettings.General.Owner.none" = "No owner"; -"TagSettings.Share.title" = "Share"; -"Menu.LoggedIn.title" = "Signed in:"; -"Interval.Day.string" = "Day"; -"hour" = "Hour"; -"TagSettings.tagNameTitleLabel.rename.text" = "Your sensors are displayed in alphabetical order."; -"On" = "On"; -"Off" = "Off"; -"DFUUIView.lowBattery.warning.message" = "Sensor's battery voltage seems to be low and the firmware update process may fail. We recommend to replace the battery before updating."; -"alert_notification_humidity_high_threshold" = "Air Humidity is above %@"; -"alert_notification_humidity_low_threshold" = "Air Humidity is below %@"; -"alert_notification_pressure_high_threshold" = "Air Pressure is above %@"; -"alert_notification_pressure_low_threshold" = "Air Pressure is below %@"; -"alert_notification_rssi_high_threshold" = "Signal strength is above %@"; -"alert_notification_rssi_low_threshold" = "Signal strength is below %@"; -"alert_notification_temperature_high_threshold" = "Temperature is above %@"; -"alert_notification_temperature_low_threshold" = "Temperature is below %@"; -"Cards.Alert.AlreadyLoggedIn.message" = "User %@ is already signed in. If you'd like to use a different account, please sign out first and then try again."; -"Settings.Label.CloudMode" = "Cloud mode"; -"Settings.Label.CloudMode.description" = "Refresh nearby cloud sensors only from the cloud by ignoring their Bluetooth messages and receiving alerts only by email. Requires a Ruuvi Gateway router."; -"internet_connection_problem" = "Internet connection problem"; -"Widgets.Loading.message" = "loading..."; -"Cards.Movements.title" = "movements"; -"TagSettings.BatteryStatusLabel.Replace.message" = "Low battery"; -"TagSettings.BatteryStatusLabel.Ok.message" = "Battery OK"; -"Widgets.Description.message" = "Create widgets of your favourite Ruuvi sensors. Widgets update from the Ruuvi Cloud. A Ruuvi Gateway router is required."; -"settings_appearance" = "Appearance"; -"app_theme" = "App Theme"; -"follow_system_theme" = "System theme"; -"dark_theme" = "Dark theme"; -"light_theme" = "Light theme"; -"Settings.Temperature.Resolution.title" = "Temperature Resolution"; -"Settings.Humidity.Resolution.title" = "Humidity Resolution"; -"Settings.Pressure.Resolution.title" = "Pressure Resolution"; -"Settings.Measurement.Resolution.description" = "Select how accurately you'd like to see the sensors' live measurement values in the app. This setting doesn't affect history charts or alerts."; -"Settings.Measurement.Unit.title" = "Unit"; -"Settings.Measurement.Resolution.title" = "Resolution"; -"MyRuuvi.Settings.DeleteAccount.title" = "Delete Account"; -"MyRuuvi.Settings.DeleteAccount.Confirmation.message" = "A confirmation has been sent to your email. To proceed with the deletion, please check your inbox and follow the instructions."; -"TagSettings.Alert.SetTemperature.title" = "Set temperature alert"; -"TagSettings.Alert.SetHumidity.title" = "Set humidity alert"; -"TagSettings.Alert.SetPressure.title" = "Set pressure alert"; -"TagSettings.Alert.SetRSSI.title" = "Set signal strength alert"; -"TagSettings.AlertSettings.Dialog.Min" = "Min (%.0f)"; -"TagSettings.AlertSettings.Dialog.Max" = "Max (%.0f)"; -"export_history" = "Export history (csv)"; -"clear_view" = "Clear history view"; -"day_1" = "1 day"; -"day_2" = "2 days"; -"day_3" = "3 days"; -"day_4" = "4 days"; -"day_5" = "5 days"; -"day_6" = "6 days"; -"day_7" = "7 days"; -"day_8" = "8 days"; -"day_9" = "9 days"; -"day_10" = "10 days"; -"day_x" = "%.0f days"; -"more" = "More..."; -"all" = "All"; -"longer_history_title" = "Longer history"; -"longer_history_message" = "Ruuvi Station mobile app supports maximum 10 days of history. Ruuvi Cloud subscribers are able to view up to 2 years of historical data using web app at ruuvi.com/station (requires Ruuvi Gateway router)."; -"reading_history_x" = "Reading Bluetooth: %.0f"; -"rssi_alert_description" = "Using this alert requires you to be signed in to the app, and that you have claimed the ownership of this sensor and it's in the range of Ruuvi Gateway router. iOS devices are unable to indicate signal strength information of received data sent by Ruuvi sensor when sensor is paired and measurements are being received in the background. Realtime Bluetooth signal strength is shown in the app but doesn't affect this alert."; -"bluetooth_download" = "Bluetooth download"; -"bluetooth_download_description" = "Local sensor data can be downloaded, when you're within its Bluetooth range."; -"download" = "Download"; -"clear_local_history" = "Clear local history"; -"clear_local_history_description" = "Do you want to clear locally stored history data from the app? This won't clear internally stored history from the sensor or history data stored on the Ruuvi Cloud service."; -"TagCharts.FailedToSyncDialog.title" = "Download failed"; -"TagCharts.FailedToSyncDialog.message" = "Bluetooth history download failed. Check that you're within Bluetooth range, your sensor has firmware that supports downloading and that the sensor is not simultaneously connected to another iOS device. Sensor connection is reserved for Ruuvi Station when using connected mode in iOS."; -"TagCharts.TryAgain.title" = "Try again"; -"support" = "Support"; -"full_image_view" = "Full image view"; -"history_view" = "History view"; -"settings_and_alerts" = "Settings & alerts"; -"change_background" = "Change background"; -"check_claim_state" = "Checking claim state"; -"claim_in_progress" = "Claiming in progress"; -"force_claim_sensor" = "Force Claim Sensor"; -"force_claim_sensor_description1" = "This sensor has been claimed by another user. You can force the ownership to your account if you have physical access to this sensor. Each Ruuvi sensor can have only one owner."; -"force_claim_sensor_description2" = "Force Claim is done by using Near-Field Communication (NFC). Make sure NFC is enabled on your mobile device.\n\n\t1. Touch your Ruuvi sensor with your mobile device to start the claiming process.\n\n\t2. When successfully claimed, you will be sent back to Sensor Settings.\n\nIf claiming was unsuccessful or NFC is not available on your device:\n\n\t1. Open the cover of your Ruuvi sensor.\n\n\t2. Locate the round black button (or button \"B\" in case your sensor has 2 buttons) on the white circuit board and press it briefly, then tap on Use BT button to start the claiming process.\n\n\t3. When successfully claimed you will be sent back to Sensor Settings."; -"force_claim" = "Force Claim"; -"claim_wrong_sensor_scanned" = "You are scanning different RuuviTag"; -"view" = "View"; -"card_type" = "Card type"; -"image_cards" = "Image cards"; -"simple_cards" = "Simple cards"; -"card_action" = "Card action"; -"open_sensor_view" = "Open sensor view"; -"open_history_view" = "Open history view"; -"change_background_message" = "Select background image. If you're not signed in, you'll lose the image in case of app reinstall."; -"take_photo" = "Take a photo"; -"select_from_gallery" = "Select from phone gallery"; -"select_default_image" = "Select from default images"; -"export_csv_feature_location" = "You can export a sensor's history from its history graph page. Tap the three dots menu icon in the top right corner, and then select \"Export history (csv)\"."; -"low_battery" = "Low battery"; -"change_background_image" = "Change background image"; -"SignIn.Sync.message" = "Downloading content from the cloud. Please wait."; -"uploading_progress" = "Uploading: %.0f"; -"Widgets.Unauthorized.Regular.message" = "Sign in to use the widget."; -"Widgets.Unauthorized.Inline.message" = "Sign in to Ruuvi Station"; -"Widgets.Unconfigured.Simple.message" = "Force tap to edit the widget."; -"Widgets.Unconfigured.Rectangular.message" = "Add sensor to use Ruuvi Widget"; -"Widgets.Unconfigured.Inline.message" = "Add sensor to use Ruuvi Widget"; -"Widgets.Unconfigured.Circular.message" = "+Add"; -"Widgets.Select.Sensor.title" = "Selected Ruuvi sensor"; -"Widgets.Sensor.Type.title" = "Selected sensor type"; -"Settings.SectionHeader.General.title" = "GENERAL"; -"Settings.SectionHeader.Application.title" = "APPLICATION"; -"empty_chart_message" = "No data available \nin the selected history window."; -"onboarding_measure_your_world" = "Measure Your World"; -"onboarding_with_ruuvi_sensors" = "Let's get to know your Ruuvi Station app."; -"onboarding_swipe_to_continue" = "Swipe to continue →"; -"onboarding_read_sensors_data" = "Read Your Ruuvi Sensors"; -"onboarding_via_bluetooth_or_cloud" = "using Bluetooth or Ruuvi Cloud"; -"onboarding_follow_measurement" = "View all sensors at a glance on your"; -"onboarding_dashboard" = "Dashboard"; -"onboarding_personalise" = "Personalise"; -"onboarding_your_sensors" = "your app with custom names and backgrounds."; -"onboarding_explore_detailed" = "Explore your measurement"; -"onboarding_history" = "History"; -"onboarding_set_custom" = "Set and customise your"; -"onboarding_alerts" = "Alerts"; -"onboarding_share_your_sensors" = "to measure together with your friends and family."; -"onboarding_sharees_can_use" = "Share Sensors"; -"onboarding_handy_widgets" = "Widgets"; -"onboarding_access_widgets" = "Bring your favorite sensors to your Home Screen and Lock Screen as"; -"onboarding_station_web" = "Ruuvi Web App"; -"onboarding_web_pros" = "Large dashboard, multi-year history, email alerts and more on"; -"onboarding_gateway_required" = "A Ruuvi Gateway router is required."; -"onboarding_skip" = "Skip"; -"onboarding_thats_it" = "Almost there!"; -"onboarding_thats_it_already_signed_in" = "Let's get started!"; -"onboarding_go_to_sign_in" = "Ruuvi experience is better when you're signed in. Do it now or continue without cloud features."; -"onboarding_go_to_sign_in_already_signed_in" = "Let's start measuring!"; -"onboarding_continue" = "Next"; -"sign_in_or_create_free_account" = "Sign in or create a free Ruuvi account"; -"to_use_all_app_features" = "No password needed."; -"type_your_email" = "Type your email.."; -"request_code" = "Request Code"; -"no_password_needed" = "A free account will be created for this email if you don't already have one. Only email address is required. We keep your information safe."; -"benefits_sign_in" = "Read more about Ruuvi account benefits or sign in later"; -"use_without_account" = "No thanks, skip"; -"why_should_sign_in" = "Benefits"; -"sensors_ownership_and_settings_stored_in_cloud" = "Signing in to the app has many advantages. Settings will be safely stored to your account:"; -"cloud_stored_ownerships" = "● Sensor ownerships"; -"cloud_stored_names" = "● Custom names"; -"cloud_stored_alerts" = "● Background images"; -"cloud_stored_backgrounds" = "● Alert settings"; -"cloud_stored_calibration" = "● Calibration settings"; -"cloud_stored_sharing" = "● App settings"; -"note" = "Note!"; -"claim_warning" = "Secure the ownership information of your sensors by claiming their ownerships in the app."; -"lets_do_it" = "Let's Sign In"; -"enter_code" = "Enter Code"; -"dashboard_no_sensors_message" = "Seems that you don't have any Ruuvi sensors added yet."; -"dashboard_no_sensors_message_signed_out" = "You are not signed in.\n\nIf you have an account and have already added Ruuvi sensors to it, they will automatically synchronise with Ruuvi Station mobile app when you sign in."; -"add_a_sensor" = "Add a Sensor"; -"changelog" = "(changelog)"; -"changelog_ios_url" = "https://f.ruuvi.com/t/3192"; -"chart_stat_min" = "Min"; -"chart_stat_max" = "Max"; -"chart_stat_avg" = "Average"; -"shared_to_x" = "Shared to %d/%d"; -"settings_alert_notifications" = "Alert Notifications"; -"settings_alert_sound" = "Alert Sound"; -"settings_alert_sound_description" = "Select push notification alert sound."; -"settings_alerts_footer_description" = "You can also adjust Notification settings under iOS Settings -> Notifications"; -"settings_alerts_footer_description_link_mask" = "iOS Settings -> Notifications"; -"settings_email_alerts" = "Email Alerts"; -"settings_email_alerts_description" = "If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive email alerts by enabling this."; -"settings_push_alerts" = "Push Alerts"; -"settings_push_alerts_description" = "If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive push alerts by enabling this."; -"synchronisation" = "Synchronisation"; -"gatt_sync_description" = "Ruuvi Station downloads the internal history of the sensor for the last 10 days if the measurement history is available.\n\nThe history is downloaded using a Bluetooth connection. Make sure you are near the sensor."; -"do_not_show_again" = "Don't show this again"; -"sign_in_continue" = "Continue"; -"signing_in_is_optional" = "(Signing in is optional)"; -"Defaults.UserAuthorized.title" = "User Authorized"; -"Defaults.DashboardTapActionChart.title" = "Show Chart on Dashboard Card Tap"; -"Defaults.DevServer.title" = "Use Dev Server"; -"Defaults.DevServer.message" = "Changing Ruuvi Cloud endpoint requires signing out from current session and restart the app. Are you sure?"; -"Defaults.ShowEmailAlertsSettings.title" = "Show email alerts settings"; -"Defaults.ShowPushAlertsSettings.title" = "Show push alerts settings"; -"use_nfc" = "Use NFC"; -"use_bluetooth" = "Use BT"; -"sensor_not_found_error" = "Sensor not found. Try again."; -"Defaults.HideNFC.title" = "Hide NFC Option for sensor contest"; -"settings_alert_sound_default" = "System Default"; -"settings_alert_sound_ruuvi_speak" = "Ruuvi Alert"; -"add_with_nfc" = "Add with NFC"; -"sensor_details" = "Sensor Details"; -"add_sensor" = "Add Sensor"; -"copy_mac_address" = "Copy MAC Address"; -"copy_unique_id" = "Copy Unique ID"; -"name" = "Name:"; -"mac_address" = "Mac Address:"; -"go_to_sensor" = "Go to sensor card"; -"unique_id" = "Unique ID:"; -"firmware_version" = "Firmware Version:"; -"Close" = "Close"; -"add_sensor_nfc_df3_error" = "This sensor cannot be added with NFC due to old firmware. Please add the sensor with Bluetooth and update firmware."; -"add_sensor_description" = "This page shows nearby Ruuvi sensors not yet added to the app. Tap a sensor to add it."; -"add_sensor_via_nfc" = "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone."; -"unclaim_sensor" = "Unclaim sensor"; -"unclaim" = "Unclaim"; -"unclaim_sensor_description" = "Ownership of this sensor has been claimed to your Ruuvi account. Press Unclaim to remove this sensor's settings and related data from your Ruuvi account."; -"claim_sensor_ownership" = "Claim sensor ownership"; -"do_you_own_sensor" = "Do you own this sensor?"; -"owners_plan" = "Owner's Ruuvi Plan"; -"alert_cloud_connection_title" = "Cloud Connection"; -"alert_cloud_connection_description" = "Alert if sensor data hasn't been updated to the cloud for longer than %d minutes."; -"alert_cloud_connection_dialog_description" = "Enter the desired delay to be used in minutes before alert is triggered. Minimum value is 2 minutes."; -"alert_cloud_connection_dialog_title" = "Set cloud connection alert"; -"rename" = "Rename"; -"chart_stat_show" = "Show min/max/avg"; -"chart_stat_hide" = "Hide min/max/avg"; -"settings_alert_limit_notification" = "Limit alert notifications"; -"settings_alert_limit_notification_description" = "Trigger Bluetooth alert notification only once per hour even if alert was retriggered."; -"share_pending" = "Share pending"; -"share_pending_message" = "Shared successfully! This email address isn't linked to a Ruuvi account yet. An invite to create a free account has been sent. Once created, you'll see it in the sharee listing."; -"dialog_are_you_sure" = "Are you sure?"; -"dialog_operation_undone" = "This operation cannot be undone."; -"remove_cloud_history_title" = "Remove cloud history"; -"remove_cloud_history_description" = "I also want to remove sensor history data from Ruuvi Cloud."; -"remove_claimed_sensor_description" = "By removing the sensor, your sensor ownership status will be revoked and sensor settings, such as name, background image, calibration settings and alert settings will be removed. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner."; -"remove_shared_sensor_description" = "If you choose to remove this shared sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore.\n\nYou will also lose any related sensor settings like name, background image and alert configurations."; -"remove_local_sensor_description" = "If you choose to remove this sensor, it will result in the deletion of your locally stored measurement history, along with the removal of any related sensor settings like name, background image, calibration, and alert configurations.\n\nYou can add this sensor later again, if needed."; -"activity_saving_to_cloud" = "Saving to cloud...please wait."; -"activity_saving_success" = "Saved successfully."; -"activity_saving_fail" = "Couldn't save changes to cloud."; -"activity_ongoing_generic" = "Please wait..."; -"activity_success_generic" = "Operation successful."; -"activity_failed_generic" = "Operation failed."; -"Devices.tokenId" = "Token Id"; -"UserApiError.ER_GATEWAY_NOT_FOUND" = "Gateway not found"; -"UserApiError.ER_GATEWAY_ALREADY_WHITELISTED" = "Gateway already whitelisted"; -"UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED" = "Gateway status report failed"; -"UserApiError.ER_CONFLICT" = "Data already exists, cannot update"; -"UserApiError.ER_CLAIM_COUNT_REACHED" = "Maximum claim count for the user reached"; -"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Maximum share count for the sensor reached"; -"UserApiError.ER_NO_DATA_TO_SHARE" = "In order to share a sensor, it must have data"; -"UserApiError.ER_SENSOR_ALREADY_REGISTERED" = "The sensor has already been registered"; -"UserApiError.ER_SUBSCRIPTION_CODE_EXISTS" = "Tried to add duplicate subscription to a code"; -"UserApiError.ER_SUBSCRIPTION_CODE_USED" = "Tried to claim already used code"; -"UserApiError.ER_OLD_ENTRY" = "Newer data already exists, cannot update"; -"UserApiError.ER_INVALID_ENUM_VALUE" = "Invalid ENUM value given"; -"UserApiError.OK" = "Operation was successful"; diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fi.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fi.lproj/Localizable.strings deleted file mode 100644 index 50b4daa2e..000000000 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fi.lproj/Localizable.strings +++ /dev/null @@ -1,767 +0,0 @@ -// swiftlint:disable all -// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen -"Done" = "Valmis"; -"Copy" = "Kopioi"; -"Confirm" = "Vahvista"; -"Remove" = "Poista"; -"N/A" = "-"; -"g" = "g"; -"About.Version.text" = "Versio"; -"Background.PresentNotifications.title" = "Näytä ilmoituksia"; -"Background.KeepConnection.title" = "Säilytä yhteys"; -"Background.Interval.Every.string" = "joka"; -"Background.Interval.Min.string" = "min"; -"Background.readRSSITitle.title" = "Lue RSSI"; -"BluetoothError.disconnected" = "Yhteys katkaistu"; -"Cards.BluetoothDisabledAlert.title" = "Bluetooth ei ole käytössä"; -"Cards.BluetoothDisabledAlert.message" = "Ruuvi Station tarvitsee Bluetooth-yhteyden toimiakseen. Ota Bluetooth käyttöön laitteen asetuksista."; -"Cards.WebTagAPILimitExcededError.Alert.title" = "Liian monta pyyntöä"; -"Cards.WebTagAPILimitExcededError.Alert.message" = "Yritä uudelleen viiden minuutin kuluttua"; -"Cards.KeepConnectionDialog.message" = "Laitteessasi on yhteyden säilyttämiseen pystyvä laiteohjelmisto. Haluatko pitää yhteyden avoinna tähän Ruuvi-laitteeseen ohjelman ollessa taustalla? Tämä mahdollistaa historian ja hälytysten toiminnan ohjelman ollessa pienennettynä."; -"Cards.KeepConnectionDialog.Dismiss.title" = "Hylkää"; -"Cards.KeepConnectionDialog.KeepConnection.title" = "Säilytä yhteys"; -"Cards.LegacyFirmwareUpdateDialog.message" = "Näyttää siltä, että anturisi laiteohjelmistoversio on vanha. Käyttääksesi uusia ominaisuuksia kuten historiakuvaajia, hälytyksiä ja pilvipalvelua, päivitys on pakollinen."; -"Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message" = "Oletko varma? Ilman päivittämistä et voi vahvistaa anturin omistajuutta, ladata sen sisäistä historiaa etkä asettaa hälytyksiä. Päivitys sisältää myös bugikorjauksia. Mikäli peruutat nyt, voit aloittaa päivityksen uudelleen anturin asetussivulta käsin."; -"Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title" = "Tarkista päivitykset"; -"Cards.Connected.title" = "Yhdistetty"; -"Cards.Error.ReverseGeocodingFailed.message" = "Virtuaalisen anturin tietojen lataaminen epäonnistui. Maantieteellisten koordinaattien käänteishaun toimintaraja ylittyi."; -"Cards.UpdatedLabel.NoData.message" = "Ei tietoja viimeiseltä 10 päivältä"; -"CoreError.failedToGetPngRepresentation" = "PNG-muunnosta ei voida tehdä"; -"CoreError.failedToGetDocumentsDirectory" = "Taustakuvahakemistoa ei löydy"; -"CoreError.failedToGetCurrentLocation" = "Nykyistä paikkaa ei löydy"; -"CoreError.failedToGetDataFromResponse" = "Vastaus ei sisällä tietoa"; -"CoreError.locationPermissionDenied" = "Oikeus paikkatietoon puuttuu"; -"CoreError.locationPermissionNotDetermined" = "Sijainnin käyttöoikeuden tilaa ei ole päätetty"; -"CoreError.objectNotFound" = "Kohdetta ei löydy"; -"CoreError.objectInvalidated" = "Kohde mitätöity"; -"CoreError.unableToSendEmail" = "Sähköpostin lähetys epäonnistui"; -"Defaults.navigationItem.title" = "Oletusasetukset"; -"Defaults.WelcomeShown.title" = "Esittely näytetään"; -"Defaults.ChartsSwipeInstructionWasShown.title" = "Histogrammin selite vaakanäytöllä"; -"Defaults.Interval.Sec.string" = "sek"; -"Defaults.Interval.Min.string" = "min"; -"Defaults.ConnectionTimeout.title" = "Yhteyden aikakatkaisu"; -"Defaults.ServiceTimeout.title" = "Palvelun aikakatkaisu"; -"Defaults.CardsSwipeHint.title" = "Pyyhkäisyvinkki"; -"Defaults.AlertsRepeatInterval.title" = "Hälytysväli"; -"Defaults.WebPullInterval.title" = "Virtuaalisten antureiden hälytysväli"; -"Defaults.PruningOffsetHours.title" = "Poistojen tuntisiirtymä"; -"Defaults.Interval.Hour.string" = "t"; -"Defaults.ChartDurationHours.title" = "Historian kesto"; -"Defaults.AppLaunchRequiredForReview.Count.title" = "Sovelluksen käynnistyskerrat, kun pyydetään tarkistusta ensimmäistä kertaa"; -"Defaults.AskReviewIfLaunchDivisibleBy.Count.title" = "Pyydä tarkistusta, onko sovelluksen käynnistys jaettavissa"; -"DiscoverTable.SectionTitle.WebTags" = "Paikkaan perustuvat virtuaaliset anturit"; -"DiscoverTable.BluetoothDisabledAlert.title" = "Bluetooth ei ole käytössä"; -"DiscoverTable.BluetoothDisabledAlert.message" = "Ruuvi Station tarvitsee Bluetooth-yhteyden toimiakseen. Ota Bluetooth käyttöön laitteen asetuksista."; -"DiscoverTable.NavigationItem.title" = "Lisää uusi anturi"; -"DiscoverTable.GetMoreSensors.button.title" = "Osta Ruuvi-antureita"; -"DiscoverTable.NoDevicesSection.NotFound.text" = "(Ei havaittuja antureita Bluetooth-verkon alueella)"; -"DiscoverTable.NoDevicesSection.BluetoothDisabled.text" = "(Bluetooth ei ole käytössä)"; -"DiscoverTable.WebTagsInfoDialog.message" = "Virtuaalisten antureiden avulla voidaan esittää paikallisilta sääasemilta kerättyjä säätietoja."; -"DiscoverTable.RuuviDevice.prefix" = "Ruuvi"; -"ErrorPresenterAlert.Error" = "Virhe"; -"ErrorPresenterAlert.OK" = "OK"; -"ExpectedError.missingOpenWeatherMapAPIKey" = "OpenWeatherMap API-avain puuttuu. Hanki avain openweathermap.org -sivustolta ja lisää saamasi avain station/Classes/Networking/Assembly/Networking.plist -tiedostoon"; -"ExpectedError.isAlreadySyncingLogsWithThisTag" = "Sovellus on jo määritetty synkronoimaan lokitietoja tämän anturin kanssa"; -"ExpectedError.failedToDeleteTag" = "Aiemmin yhdistettyä laitetta ei voida poistaa ilman Bluetooth-yhteyttä. Tarkasta Bluetooth-yhteyden tila."; -"ExportService.Date" = "Päivämäärä"; -"ExportService.ISO8601" = "ISO8601"; -"ExportService.Temperature" = "Lämpötila (%@)"; -"ExportService.Humidity" = "Kosteus (%@)"; -"ExportService.DewPoint" = "Kastepiste (%@)"; -"ExportService.Pressure" = "Ilmanpaine (%@)"; -"ExportService.Voltage" = "Jännite (V)"; -"ExportService.MovementCounter" = "Liikelaskuri"; -"ExportService.MeasurementSequenceNumber" = "Mittausjärjestysnumero"; -"ExportService.TXPower" = "Lähetysteho"; -"ForegroundRow.advertisement.section" = "LAITEILMOITUKSET"; -"ForegroundRow.advertisement.title" = "Tallenna laiteilmoitukset"; -"ForegroundRow.connection.section" = "LOKITIEDOT"; -"ForegroundRow.connection.title" = "Yhdistä ja tallenna lokitiedot"; -"Foreground.navigationItem.title" = "Prosessit"; -"Foreground.Interval.Every.string" = "Joka"; -"Foreground.Interval.Min.string" = "min"; -"ForegroundRow.webTags.title" = "Lataa ja tallenna verkkopalvelusta"; -"ForegroundRow.webTags.section" = "VIRTUAALISET ANTURIT"; -"Foreground.Interval.All.string" = "Kaikki"; -"Heartbeat.Interval.Every.string" = "joka"; -"Heartbeat.Interval.Min.string" = "min"; -"Heartbeat.readRSSITitle.title" = "Lue RSSI"; -"Heartbeat.Interval.Sec.string" = "sek"; -"Heartbeat.Interval.All.string" = "Kaikki"; -"HumidityCalibration.ClearCalibrationConfirmationAlert.title" = "Oletko varma?"; -"HumidityCalibration.ClearCalibrationConfirmationAlert.message" = "Olet nollaamassa kalibrointia. Tätä ei voida peruuttaa. Jatka napauttamalla \"Vahvista\" ."; -"HumidityCalibration.CalibrationConfirmationAlert.title" = "Oletko varma?"; -"HumidityCalibration.CalibrationConfirmationAlert.message" = "Olet kalibroimassa kosteusanturia. Jatka napauttamalla \"Vahvista\" ."; -"Language.English" = "English"; -"Language.Finnish" = "Suomi"; -"Language.Russian" = "Русский"; -"Language.Swedish" = "Svenska"; -"Language.French" = "Français"; -"Language.German" = "Deutsch"; -"LocalNotificationsManager.DidConnect.title" = "Yhdistetty"; -"LocalNotificationsManager.DidDisconnect.title" = "Yhteys katkaistu"; -"LocalNotificationsManager.Disable.button" = "Poista käytöstä"; -"LocalNotificationsManager.LowDewPoint.title" = "Kastepiste liian alhainen!"; -"LocalNotificationsManager.HighDewPoint.title" = "Kastepiste liian korkea!"; -"PermissionPresenter.NoPhotoLibraryAccess.message" = "Tämä ominaisuus vaatii oikeuden gallerian käyttöön."; -"PermissionPresenter.NoCameraAccess.message" = "Tämä ominaisuus vaatii oikeuden kameran käyttöön."; -"PermissionPresenter.NoLocationAccess.message" = "Tämä ominaisuus vaatii oikeuden paikkatiedon käyttöön."; -"PermissionPresenter.settings" = "Asetukset"; -"PermissionPresenter.NoPushNotificationsPermission.message" = "Tämä ominaisuus vaatii oikeuden palveluilmoitusten näyttämiseen."; -"PhotoPicker.Sheet.message" = "Valitse kuva"; -"PhotoPicker.Sheet.library" = "Valitse kirjastosta"; -"PhotoPicker.Sheet.camera" = "Ota kuva"; -"Settings.SegmentedControl.Humidity.Relative.title" = "Suht."; -"Settings.SegmentedControl.Humidity.Absolute.title" = "Abs."; -"Settings.SegmentedControl.Humidity.DewPoint.title" = "Kast."; -"Settings.Label.Language.text" = "Kieli"; -"Settings.Language.Dialog.title" = "Valitse kieli"; -"Settings.Language.Dialog.message" = "Avaa asetukset ja napauta Kieli vaihtaaksesi sovelluksen kieltä. -Mikäli et näe Kieli-valintaa asetuksissa, varmista, että sinulla on vähintään yksi ensisijainen kieli on valittuna järjestelmäasetuksissa: Asetukset -> Yleiset -> Kieli ja alue."; -"Settings.Label.Foreground" = "Prosessit"; -"Settings.Label.Defaults" = "Oletusasetukset"; -"OWMError.failedToParseOpenWeatherMapResponse" = "Open Weather Map -vastauksen jäsentäminen epäonnistui"; -"OWMError.apiLimitExceeded" = "API-raja ylittyi"; -"OWMError.notAHttpResponse" = "Vastaus ei ole HTTP-muodossa"; -"OWMError.invalidApiKey" = "API-avain ei kelpaa"; -"TagCharts.NoChartData.text" = "Tietoja ei ole saatavilla"; -"TagCharts.BluetoothDisabledAlert.title" = "Bluetooth ei ole päällä"; -"TagCharts.BluetoothDisabledAlert.message" = "Ruuvi Station tarvitsee Bluetooth-yhteyden toimiakseen. Ota Bluetooth käyttöön laitteen asetuksista."; -"TagCharts.Clear.title" = "Pyyhi"; -"TagCharts.SyncConfirmationDialog.title" = "Oletko varma?"; -"TagCharts.DeleteHistoryConfirmationDialog.button.delete.title" = "Poista"; -"TagCharts.DeleteHistoryConfirmationDialog.title" = "Oletko varma?"; -"TagCharts.Status.Disconnecting" = "Katkaistaan yhteyttä..."; -"TagCharts.Status.Success" = "Onnistui"; -"TagCharts.Status.Error" = "Virhe"; -"TagSettings.UUID.Alert.title" = "UUID"; -"TagSettings.UpdateFirmware.Alert.title" = "RAWv2-formaatti vaaditaan"; -"TagSettings.UpdateFirmware.Alert.message" = "Puuttuvat arvot voidaan näyttää ainoastaan uudemmalla laiteohjelmistoversiolla."; -"TagSettings.UpdateFirmware.Alert.Buttons.LearnMore.title" = "Lue lisää"; -"TagCharts.Dismiss.Alert.message" = "Historian lataaminen Bluetooth-yhteydellä on käynnissä. Odota hetki."; -"TagCharts.AbortSync.Alert.message" = "Historian lataaminen voi kestää pitkään Bluetooth-yhteyden laadusta riippuen. Odota hetki."; -"TagCharts.AbortSync.Button.title" = "Peruuta lataaminen"; -"TagSettings.EmptyValue.sign" = "-"; -"TagSettings.HumidityIsClipped.Alert.title" = "Kosteus on säädetty"; -"TagSettings.HumidityIsClipped.Alert.message" = "Kalibroinnin jälkeinen kosteusarvo on suurempi kuin 100%. Tämä ei käy järkeen, joten maksimiarvona näytetään 100%."; -"TagSettings.HumidityIsClipped.Alert.Fix.button" = "Korjaa"; -"TagSettings.navigationItem.title" = "Asetukset"; -"TagSettings.tagNameTitleLabel.text" = "Anturin nimi"; -"TagSettings.humidityTitleLabel.text" = "Kosteus"; -"TagSettings.uuidTitleLabel.text" = "UUID"; -"TagSettings.macAddressTitleLabel.text" = "MAC-osoite"; -"TagSettings.dataFormatTitleLabel.text" = "Dataformaatti"; -"TagSettings.accelerationXTitleLabel.text" = "Kiihtyvyys X"; -"TagSettings.accelerationYTitleLabel.text" = "Kiihtyvyys Y"; -"TagSettings.accelerationZTitleLabel.text" = "Kiihtyvyys Z"; -"TagSettings.txPowerTitleLabel.text" = "Lähetysteho"; -"TagSettings.mcTitleLabel.text" = "Liikelaskuri"; -"TagSettings.msnTitleLabel.text" = "Mittausjärjestysnumero"; -"TagSettings.SectionHeader.Remove.title" = "POISTA"; -"TagSettings.Label.noValues.text" = "EI ARVOJA?"; -"TagSettings.SectionHeader.Calibration.title" = "KALIBROINTI"; -"TagSettings.SectionHeader.BTConnection.title" = "BLUETOOTH YHTEYS"; -"TagSettings.PairAndBackgroundScan.Unpaired.title" = "Parita ja käytä taustaskannausta"; -"TagSettings.PairAndBackgroundScan.Pairing.title" = "Yhdistetään anturiin"; -"TagSettings.PairAndBackgroundScan.Paired.title" = "Paritettu ja taustaskannaus päällä"; -"TagSettings.PairAndBackgroundScan.description" = "Bluetooth-yhteyttä käyttävät hälytykset eivät ole käytettävissä silloin kun taustaskannausta ei ole otettu käyttöön. Ruuvi-anturi voidaan parittaa vain yhteen iOS-laitteeseen kerrallaan."; -"TagSettings.PairError.CloudMode.description" = "Anturiin ei voida yhdistää Bluetoothilla sovelluksen pilvitilan ollessa aktiivinen. Voit ottaa pilvianturiesi Bluetoothin takaisin käyttöön sammuttamalla pilvitilan sovelluksen asetussivulta."; -"TagSettings.PairError.Timeout.description" = "Yhteys aikakatkaistiin. Laiteparin muodostaminen epäonnistui. Yritä uudelleen."; -"TagSettings.dataSourceTitleLabel.text" = "Datalähde"; -"TagSettings.DataSource.Heartbeat.title" = "Syke"; -"TagSettings.DataSource.Advertisement.title" = "Laiteilmoitus"; -"TagSettings.DataSource.Network.title" = "Pilvi"; -"TagSettings.Label.disabled.text" = "POIS KÄYTÖSTÄ?"; -"TagSettings.AlertsAreDisabled.Dialog.BothNotConnectedAndNoPNPermission.message" = "Hälytykset ovat poissa käytöstä, sillä yhteyttä laitteeseen ei ole muodostettu ja lupa palveluviestien näyttämiseen puuttuu. Yhdistä laitteeseen ensin."; -"TagSettings.AlertsAreDisabled.Dialog.Connect.title" = "Yhdistä"; -"TagSettings.AlertsAreDisabled.Dialog.NotConnected.message" = "Hälytykset ovat poissa käytöstä, sillä yhteyttä laitteeseen ei ole muodostettu."; -"TagSettings.Alert.CustomDescription.placeholder" = "Muokkaa kuvausta..."; -"TagSettings.Alert.CustomDescription.title" = "Aseta hälytysviesti"; -"TagSettings.Alerts.Humidity.description" = "Hälytä, mikäli alle %.0f tai yli %.0f"; -"TagSettings.Alerts.DewPoint.description" = "Hälytä, mikäli kastepiste alle %.0f tai yli %.0f"; -"TagSettings.dewPointAlertTitleLabel.text" = "Kastepiste"; -"TagSettings.Alerts.Pressure.description" = "Hälytä, mikäli ilmanpaine %.0f tai yli %.0f"; -"TagSettings.Alerts.Connection.description" = "Hälytä, mikäli yhteys muodostettu/yhteys menetetty"; -"TagSettings.ConnectionAlert.title" = "Yhteys"; -"TagSettings.SectionHeader.Firmware.title" = "Laiteohjelmisto"; -"TagSettings.Firmware.CurrentVersion" = "Nykyinen versio"; -"TagSettings.Firmware.CurrentVersion.VeryOld" = "Hyvin vanha"; -"TagSettings.Firmware.UpdateFirmware" = "Päivitä"; -"UnexpectedError.callbackErrorAndResultAreNil" = "Vastakutsun ja virheen tulos on nolla"; -"UnexpectedError.callerDeinitedDuringOperation" = "Kutsuja deallokoitiin toiminnon aikana"; -"UnexpectedError.failedToReverseGeocodeCoordinate" = "Maantieteellisen sijainnin peruutus epäonnistui"; -"UnexpectedError.failedToFindRuuviTag" = "Anturia ei löydetty"; -"UnexpectedError.failedToFindLogsForTheTag" = "Anturin lokitietoja ei löydetty"; -"UnexpectedError.viewModelUUIDIsNil" = "UUID:n näyttömalli on nolla"; -"UnexpectedError.attemptToReadDataFromRealmWithoutLUID" = "Realmin tietoja yritettiin lukea ilman LUID:tä"; -"UnexpectedError.failedToFindVirtualTag" = "Virtuaalisen anturin haku epäonnistui"; -"HumidityUnit.Dew.title" = "Kastepiste (%@)"; -"WebTagLocationSource.current" = "Nykyinen sijaintisi"; -"WebTagLocationSource.manual" = "Valitse kartalta"; -"WebTagSettings.confirmTagRemovalDialog.title" = "Poista"; -"WebTagSettings.confirmTagRemovalDialog.message" = "Haluatko varmasti poistaa?"; -"WebTagSettings.Location.Current" = "Nykyinen sijaintisi"; -"WebTagSettings.confirmClearLocationDialog.title" = "Poista sijainti"; -"WebTagSettings.confirmClearLocationDialog.message" = "Oletko varma, että haluat poistaa tämän sijainnin ja käyttää nykyistä sijaintiasi?"; -"WebTagSettings.navigationItem.title" = "Asetukset"; -"WebTagSettings.Label.BackgroundImage.text" = "TAUSTAKUVA"; -"WebTagSettings.Label.Location.text" = "Paikka"; -"WebTagSettings.Button.Remove.title" = "POISTA"; -"WebTagSettings.SectionHeader.Name.title" = "NIMI"; -"WebTagSettings.SectionHeader.MoreInfo.title" = "LISÄTIETOJA"; -"WebTagSettings.Alerts.Temperature.description" = "Hälytä, mikäli lämpötila alle %.0f tai yli %.0f"; -"WebTagSettings.Alerts.Off" = "Pois käytöstä"; -"WebTagSettings.temperatureAlertTitleLabel.text" = "Lämpötila"; -"WebTagSettings.Label.disabled.text" = "POIS KÄYTÖSTÄ?"; -"WebTagSettings.Label.alerts.text" = "HÄLYTYKSET"; -"WebTagSettings.AlertsAreDisabled.Dialog.BothNoPNPermissionAndNoLocationPermission.message" = "Virtuaalisten antureiden hälytysominaisuus tarvitsee oikeuden sekä paikkatiedon että palveluilmoitusten näyttämiseen. Tarkasta sovellusasetukset."; -"WebTagSettings.AlertsAreDisabled.Dialog.Settings.title" = "Asetukset"; -"WebTagSettings.AirHumidityAlert.title" = "Ilmankosteus"; -"WebTagSettings.Alerts.Humidity.description" = "Hälytä, mikäli alle %.0f tai yli %.0f"; -"WebTagSettings.Alerts.DewPoint.description" = "Hälytä, mikäli kastepiste alle %.0f tai yli %.0f"; -"WebTagSettings.dewPointAlertTitleLabel.text" = "Kastepiste"; -"WebTagSettings.PressureAlert.title" = "Ilmanpaine"; -"WebTagSettings.Alerts.Pressure.description" = "Hälytä, mikäli ilmanpaine alle %.0f tai yli %.0f"; -"Welcome.description.text" = "Etsi lähistöllä olevia antureita napauttamalla Skannaa."; -"ExportService.AccelerationX" = "Kiihtyvyys X"; -"ExportService.AccelerationY" = "Kiihtyvyys Y"; -"ExportService.AccelerationZ" = "Kiihtyvyys Z"; -"DiscoverTable.SectionTitle.Devices" = "Lähellä olevat Ruuvi-laitteet"; -"ago" = "sitten"; -"TagSettings.MovementAlert.title" = "Liike"; -"TagSettings.Alerts.Movement.description" = "Hälytä, mikäli liike havaittu"; -"LocalNotificationsManager.HighHumidity.title" = "Suhteellinen ilmankosteus liian korkea!"; -"LocalNotificationsManager.LowHumidity.title" = "Suhteellinen ilmankosteus liian alhainen!"; -"LocalNotificationsManager.DidMove.title" = "Liike havaittu!"; -"LocalNotificationsManager.HighPressure.title" = "Ilmanpaine liian korkea!"; -"LocalNotificationsManager.LowPressure.title" = "Ilmanpaine liian alhainen!"; -"LocalNotificationsManager.HighSignal.title" = "Signaalin voimakkuus liian korkea!"; -"LocalNotificationsManager.LowSignal.title" = "Signaalin voimakkuus liian alhainen!"; -"LocalNotificationsManager.HighTemperature.title" = "Lämpötila liian korkea!"; -"LocalNotificationsManager.LowTemperature.title" = "Lämpötila liian alhainen!"; -"TagSettings.Alerts.Off" = "Pois käytöstä"; -"TagSettings.Alerts.Temperature.description" = "Hälytä, mikäli alle %.0f tai yli %.0f"; -"TagSettings.Label.alerts.text" = "Hälytykset"; -"TagSettings.backgroundImageLabel.text" = "Taustakuva"; -"TagSettings.batteryVoltageTitleLabel.text" = "Paristojännite"; -"HumidityCalibration.Button.Calibrate.title" = "Kalibroi"; -"HumidityCalibration.lastCalibrationDate.format" = "Kalibroitu: %@"; -"HumidityCalibration.Description.text" = "Suosittelemme kalibrointia suolaliuoksen avulla mahdollisimman tarkkojen ilmankosteusmittausten saamiseksi. Video-ohje."; -"HumidityCalibration.Label.note.text" = "Huomaathan, että kalibrointitieto tallennetaan paikallisesti mobiililaitteeseesi. Kalibrointi joudutaan suorittamaan uudelleen sovelluksen poistamisen ja uudelleenasennuksen jälkeen."; -"HumidityCalibration.VideoTutorials.link" = "Video-ohje."; -"Cancel" = "Peruuta"; -"HumidityCalibration.Button.Clear.title" = "Pyyhi"; -"TagCharts.DeleteHistoryConfirmationDialog.message" = "Tyhjennetäänkö sovellukseen paikallisesti tallennetut historiatiedot?"; -"HumidityCalibration.Button.Close.title" = "Sulje"; -"TagCharts.Status.Serving" = "Synkronoidaan..."; -"TagCharts.Status.Connecting" = "Yhdistetään..."; -"TagSettings.ConnectStatus.Disconnected" = "Ei yhteyttä"; -"TagCharts.Export.title" = "LATAA"; -"h" = "t"; -"About.AboutHelp.contents" = "Ruuvi Station on kätevä ja helppokäyttöinen sovellus, jonka avulla voit seurata Ruuvin anturien mittaustietoja."; -"About.AboutHelp.header" = "Tietoa / Apua"; -"About.TagsCount.text" = "Lisätyt anturit: %d"; -"About.MeasurementsCount.text" = "Paikallisesti tallennettujen mittausten lukumäärä: %d"; -"About.DatabaseSize.text" = "Tietokannan koko: %@"; -"About.More.contents" = "Ruuvin kotisivu: ruuvi.com\nRuuvi Forum: f.ruuvi.com\nRuuvi Blog: ruuvi.com/fi/blogi\nRuuvi Twitter: twitter.com/ruuvicom"; -"About.More.header" = "Lue lisää"; -"About.OpenSource.contents" = "Kuten Ruuvi-anturit, Ruuvi Station -sovellukset perustuvat avoimeen lähdekoodiin. Seuraa kehitystä ja osallistu osoitteessa: github.com/ruuvi"; -"About.OpenSource.header" = "Avoin lähdekoodi"; -"About.OperationsManual.contents" = "Aloita Ruuvi Station -mobiilisovelluksen käyttö ohjeidemme avulla: ruuvi.com/fi/tuki/station-mobile-fi"; -"About.OperationsManual.header" = "Käyttöohje"; -"About.Privacy.contents" = "Sovelluksen käyttäminen vaatii Ruuvin käyttöehtojen hyväksymisen: ruuvi.com/terms"; -"About.Privacy.header" = "Tietosuojakäytäntö"; -"About.Troubleshooting.contents" = "Löydä apua Ruuvi Station -sovellusten, Ruuvi-tuotteiden ja Ruuvi Cloud -palvelun käyttöön tukikeskuksestamme: ruuvi.com/fi/tuki"; -"About.Troubleshooting.header" = "Vianetsintä"; -"hours" = "tuntia"; -"Interval.Days.string" = "päivää"; -"TagSettings.AirHumidityAlert.title" = "Ilmankosteus (%@)"; -"HumidityUnit.gm3.title" = "Absoluuttinen (g/m³)"; -"g/m³" = "g/m³"; -"HumidityUnit.Percent.title" = "Suhteellinen (%)"; -"TagSettings.Mac.Alert.title" = "MAC-osoite"; -"Menu.Label.AboutHelp.text" = "Tietoa / Apua"; -"Menu.Label.AddAnNewSensor.text" = "Lisää uusi anturi"; -"Menu.Label.AppSettings.text" = "Asetukset"; -"Menu.Label.GetMoreSensors.text" = "Osta Ruuvi-antureita"; -"Ruuvi.BuySensors.URL.IOS" = "https://ruuvi.com/fi/tuotteet?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Ruuvi.BuySensors.Menu.URL.IOS" = "https://ruuvi.com/fi/tuotteet?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios"; -"Menu.Label.BuyRuuviGateway.text" = "Osta Ruuvi Gateway"; -"Menu.BuyGateway.URL.IOS" = "https://ruuvi.com/fi/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Menu.Label.WhatToMeasure.text" = "Mitä mitata Ruuvilla?"; -"Menu.Measure.URL.IOS" = "https://ruuvi.com/fi/ideat?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Menu.Label.Feedback.text" = "Lähetä palautetta"; -"Menu.Label.MyRuuviAccount.text" = "Minun Ruuvi-tilini"; -"min" = "min"; -"minutes" = "Minuuttia"; -"TagSettings.Label.moreInfo.text" = "Lisätietoa"; -"TagSettings.SectionHeader.Name.title" = "NIMI"; -"No" = "Ei"; -"OK" = "OK"; -"Cards.NoSensors.title" = "Ei antureita\nLisää antureita napauttamalla tästä"; -"TagSettings.PressureAlert.title" = "Ilmanpaine (%@)"; -"UnitPressure.hectopascal.title" = "Hehtopascal (hPa)"; -"hPa" = "hPa"; -"UnitPressure.inchOfMercury.title" = "Elohopeatuuma (inHg)"; -"UnitPressure.millimetreOfMercury.title" = "Elohopeamillimetri (mmHg)"; -"TagCharts.Status.ReadingHistory" = "Historiatietoja luetaan"; -"TagSettings.rssiTitleLabel.text" = "Signaalin voimakkuus (RSSI)"; -"signal_strength_dbm" = "Signaalin voimakkuus (dBm)"; -"s" = "s"; -"Welcome.scan.title" = "SKANNAA"; -"Background.Interval.Sec.string" = "sek"; -"Settings.navigationItem.title" = "Asetukset"; -"Settings.BackgroundScanning.title" = "Taustaskannaus"; -"Settings.BackgroundScanning.Footer.message" = "Tärkeitä huomioita: Historian Bluetooth-taustatallennus ja Bluetooth-hälytykset toimivat ainoastaan sovelluksen taustaskannauksen ollessa käytössä. Mikäli poistat taustaskannauksen käytöstä, kaikkien yhdistettyjen Ruuvi-anturien paritukset poistetaan ja joudut parittamaan ne uudelleen niiden asetussivuilta käsin."; -"Settings.BackgroundScanning.interval" = "Historiatietojen tallennusväli"; -"Settings.Label.Chart" = "Historiatietojen asetukset"; -"ChartSettings.AllPoints.title" = "Näytä kaikki kerätyt mittaukset"; -"ChartSettings.AllPoints.description" = "Ominaisuuden käyttäminen saattaa hidastaa historiatietojen päivittymistä."; -"ChartSettings.DrawDots.title" = "Näytä tietopisteet"; -"ChartSettings.DrawDots.description" = "Tietopisteiden näyttäminen helpottaa tallennetun historiatiedon tutkimista."; -"Defaults.ChartIntervalSeconds.title" = "Historian tarkkuus"; -"ChartSettings.Duration.title" = "Historian tarkastelujakso"; -"ChartSettings.Duration.description" = "Määritä historian tarkastelujakso 1 - 10 päivää."; -"Settings.Label.HumidityUnit.text" = "Kosteusyksikkö"; -"Settings.Label.Temperature" = "Lämpötila"; -"Settings.Label.Humidity" = "Kosteus"; -"Settings.Label.Pressure" = "Paine"; -"Settings.ChooseHumidityUnit.text" = "Valitse sovelluksessa käytettävä kosteusyksikkö."; -"Settings.Label.PressureUnit.text" = "Paineyksikkö"; -"Settings.ChoosePressureUnit.text" = "Valitse sovelluksessa käytettävä paineyksikkö."; -"Settings.Label.TemperatureUnit.text" = "Lämpötilayksikkö"; -"Settings.ChooseTemperatureUnit.text" = "Valitse sovelluksessa käytettävä lämpötilayksikkö."; -"dBm" = "dBm"; -"TagCharts.Sync.title" = "Synkronoi"; -"TagCharts.SyncConfirmationDialog.message" = "Ladataanko historiatiedot anturista?"; -"WebTagSettings.Label.TagName.text" = "Anturin nimi"; -"TagSettings.confirmTagRemovalDialog.title" = "Poista"; -"TagSettings.confirmTagRemovalDialog.message" = "Haluatko varmasti poistaa tämän anturin?"; -"TagSettings.temperatureAlertTitleLabel.text" = "Lämpötila (%@)"; -"TemperatureUnit.Celsius.title" = "Celsius (℃)"; -"ºC" = "°C"; -"TemperatureUnit.Fahrenheit.title" = "Fahrenheit (℉)"; -"ºF" = "°F"; -"TemperatureUnit.Kelvin.title" = "Kelvin (K)"; -"Updated" = "Päivitetty"; -"V" = "V"; -"RuuviOnboard.Welcome.title" = "Tutustu Ruuvi Station -sovellukseen."; -"RuuviOnboard.Measure.title" = "Mittaa ympäristösi olosuhteita: lämpötilaa, ilmankosteutta ja ilmanpainetta."; -"RuuviOnboard.Access.title" = "Tarkastele anturitietoja reaaliaikaisesti tai tutki laitteelle tallennettuja historiatietoja."; -"RuuviOnboard.Alerts.title" = "Aseta hälytyksiä ja ilmoituksia haluamallasi tavalla."; -"RuuviOnboard.Cloud.title" = "Kirjaudu sisään käyttääksesi kaikkia sovelluksen ominaisuuksia."; -"RuuviOnboard.Cloud.subtitle" = "Vahvista anturiesi omistajuudet ilmaisen Ruuvi Cloud -tilin avulla."; -"RuuviOnboard.Cloud.subtitle.signed" = "Hienoa, olet jo kirjautunut sisään!"; -"RuuviOnboard.Start.title" = "Näytä lähietäisyydellä olevat anturit napauttamalla SKANNAA."; -"Yes" = "Kyllä"; -"LocalNotificationsManager.Mute.button" = "Mykistä tunniksi"; -"Defaults.AlertsMuteInterval.title" = "Hälytysten mykistysväli"; -"SignIn.Title.text" = "Kirjaudu sisään"; -"Menu.SignOut.text" = "Kirjaudu ulos"; -"RuuviOnboard.Cloud.Benefits.message" = "Hyödyt:\n\n ● Anturien nimet, taustakuvat sekä kalibrointi- ja hälytysasetukset tallentuvat turvallisesti tilillesi pilvipalveluun\n\n ● Lue anturitiedot etänä verkossa (vaatii Ruuvi Gateway -reitittimen)\n\n ● Jaa antureita ystävien ja perheen kesken (vaatii Ruuvi Gateway -reitittimen)\n\n ● Selaa jopa 2 vuoden historiatietoja osoitteessa station.ruuvi.com (vaatii Ruuvi Gateway -reitittimen)"; -"RuuviOnboard.Cloud.Details.title" = "Tiedot"; -"ruuvi_cloud" = "Ruuvi Cloud"; -"RuuviOnboard.Cloud.Skip.title" = "Haluatko varmasti ohittaa sisäänkirjautumisen?"; -"RuuviOnboard.Cloud.Skip.Yes.title" = "Kyllä, ohita"; -"RuuviOnboard.Cloud.Skip.GoBack.title" = "Takaisin"; -"SignIn.EmailPlaceholder" = "Sähköposti"; -"SignIn.RequestCode" = "Pyydä kirjautumiskoodi"; -"SignIn.SubmitCode" = "Lähetä"; -"SignIn.EmailSent" = "Sähköposti lähetetty"; -"SignIn.CheckMailbox" = "Olemme lähettäneet sähköpostiisi kertakäyttöisen salasanan %@. Kirjaudu syöttämällä se tähän:"; -"SignIn.CodeHint" = "Koodi"; -"TagsManagerPresenter.SignOutConfirmAlert.Message" = "Anturit, joiden omistajuuden olet vahvistanut asetussivulla poistetaan sovelluksesta automaattisesti uloskirjauduttaessa. Anturitiedot palautetaan pilvipalvelusta samalla sähköpostiosoitteella uudelleenkirjauduttaessa.\n\nHaluatko varmasti kirjautua ulos?"; -"TagSettings.ClaimTagButton.Claim" = "Vahvista omistajuus"; -"TagSettings.ShareButton" = "Jaa"; -"Syncing..." = "Ladataan historiaa pilvestä..."; -"Synchronized" = "Synkronoitu"; -"TagChartsPresenter.NumberOfPointsSynchronizedOverNetwork" = "Synkronoitu: %@"; -"MenuTableViewController.None" = "ei kirjautunut"; -"MenuTableViewController.User" = "Käyttäjä: %@"; -"ShareViewController.Title" = "Jaa anturi"; -"ShareViewController.Description" = "Voit jakaa tämän anturin ystäville tai perheenjäsenille, mikäli laite on Ruuvi Gateway -reitittimen kuuluvuusalueella.\n\nVastaanottaja saa jakamisesta ilmoituksen sähköpostilla. Ilmainen Ruuvi-tili luodaan ensimmäisen sisäänkirjautumisen yhteydessä, mikäli vastaanottajalla ei ole vielä Ruuvi-tiliä.\n\nAnturin nimi ja taustakuva jaetaan vastaanottajalle vain kertaalleen. Sen jälkeen kumpikin voivat muokata vain omia anturiasetuksiaan. Kalibrointiarvot (mikäli käytössä) synkronoidaan automaattisesti jaetuille antureille ja vastaanottaja näkee vain lopulliset korjatut arvot."; -"ShareViewController.addFriend.Title" = "Lisää ystävä"; -"ShareViewController.emailTextField.placeholder" = "Anna sähköpostiosoite"; -"ShareViewController.sharedEmails.Title" = "Olet käyttänyt %d/%d tämän anturin enimmäisjakomäärästä. Anturi on jaettu seuraaville käyttäjille:"; -"Share.Send.button" = "Lähetä"; -"SharePresenter.UnshareSensor.Message" = "Haluatko lopettaa anturin jakamisen käyttäjälle %@?"; -"TagSettings.SectionHeader.NetworkInfo.title" = "VERKON TIEDOT"; -"TagSettings.NetworkInfo.Owner" = "Omistaja"; -"Menu.RuuviNetworkStatus.text" = "Ruuvin pilven tila"; -"SignIn.TitleLabel.text" = "Kirjaudu\nRuuvi\nStationiin"; -"SignIn.SubtitleLabel.text" = "Hyödyntääksesi kaikkia sovelluksen ominaisuuksia, kirjaudu sisään tai luo uusi ilmainen Ruuvi-käyttäjätili antamalla sähköpostiosoitteesi."; -"SignIn.VerificationCodePlaceholder" = "vahvistuskoodi muodossa: CJSM"; -"UserApiError.ER_FORBIDDEN" = "Kielletty"; -"UserApiError.ER_UNAUTHORIZED" = "Ei sallittu"; -"UserApiError.ER_INTERNAL" = "Sisäinen virhe"; -"UserApiError.ER_INVALID_FORMAT" = "Virheellinen pyynnön muoto"; -"UserApiError.ER_USER_NOT_FOUND" = "Käyttäjää ei löydy"; -"UserApiError.ER_SENSOR_NOT_FOUND" = "Anturia ei löydy"; -"UserApiError.ER_TOKEN_EXPIRED" = "Avain on vanhentunut"; -"UserApiError.ER_SUBSCRIPTION_NOT_FOUND" = "Tilausta ei löydy"; -"UserApiError.ER_SHARE_COUNT_REACHED" = "Jakojen enimmäismäärä on ylitetty"; -"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Et voi jakaa anturia useammalle käyttäjälle"; -"UserApiError.ER_NO_DATA_TO_SHARE" = "Jotta voit jakaa anturin, sen täytyy olla Ruuvi Gateway -reitittimen kuuluvuusalueella"; -"UserApiError.ER_SENSOR_ALREADY_SHARED" = "Tämä anturi on jo jaettu"; -"UserApiError.ER_SENSOR_ALREADY_CLAIMED" = "Anturilla on jo toinen omistaja: %@"; -"UserApiError.ER_SENSOR_ALREADY_CLAIMED_NO_EMAIL" = "Anturilla on jo toinen omistaja"; -"UserApiError.ER_UNABLE_TO_SEND_EMAIL" = "Sähköpostin lähetys epäonnistui"; -"UserApiError.ER_MISSING_ARGUMENT" = "Argumentti puuttuu"; -"UserApiError.ER_INVALID_DENSITY_MODE" = "Virheellinen tiheuden tila"; -"UserApiError.ER_INVALID_SORT_MODE" = "Virheellinen lajittelun tila"; -"UserApiError.ER_INVALID_TIME_RANGE" = "Virheellinen aikaväli"; -"UserApiError.ER_INVALID_EMAIL_ADDRESS" = "Virheellinen sähköpostiosoite"; -"UserApiError.ER_INVALID_MAC_ADDRESS" = "Virheellinen MAC-osoite"; -"UserApiError.ER_SUB_DATA_STORAGE_ERROR" = "Tallennusvirhe"; -"UserApiError.ER_SUB_NO_USER" = "Ei käyttäjää"; -"UserApiError.ER_THROTTLED" = "Liian monta pyyntöä"; -"OffsetCorrection.CalibrationDescription.text" = "Anturin kalibrointi ei ole tarpeellista normaalissa käytössä.\n\nTämä ominaisuus on tarkoitettu edistyneille käyttäjille.\n\nKalibroinnin lisäohjeet löytyvät osoitteesta ruuvi.com/fi/tuki"; -"OffsetCorrection.Dialog.Calibration.ClearConfirm" = "Poista kalibrointiasetukset?"; -"OffsetCorrection.Dialog.Calibration.Title" = "Kalibrointi"; -"OffsetCorrection.Dialog.Calibration.EnterTemperature" = "Syötä anturin oletettu lämpötila tämänhetkisissä olosuhteissa (%@): "; -"OffsetCorrection.Dialog.Calibration.EnterPressure" = "Syötä anturin oletettu paine tämänhetkisissä olosuhteissa (%@): "; -"OffsetCorrection.Dialog.Calibration.EnterHumidity" = "Syötä anturin oletettu kosteus tämänhetkisissä olosuhteissa (%@): "; -"OffsetCorrection.OriginalValue.title" = "Alkuperäinen arvo"; -"OffsetCorrection.CorrectedValue.title" = "Korjattu arvo"; -"OffsetCorrection.Temperature.Title" = "Lämpötilapoikkeama"; -"OffsetCorrection.Humidity.Title" = "Kosteuspoikkeama"; -"OffsetCorrection.Pressure.Title" = "Painepoikkeama"; -"OffsetCorrection.Calibrate.button" = "Kalibrointi"; -"TagSettings.SectionHeader.OffsetCorrection.Title" = "KALIBROINTI"; -"TagSettings.OffsetCorrection.Temperature" = "Lämpötila"; -"TagSettings.OffsetCorrection.Humidity" = "Kosteus"; -"TagSettings.OffsetCorrection.Pressure" = "Paine"; -"PhotoPicker.Sheet.files" = "Valitse tiedostoista"; -"SignIn.EnterVerificationCode" = "Syötä vahvistuskoodi"; -"UnexpectedError.failedToFindOrGenerateBackgroundImage" = "Taustakuvaa ei löydy tai sen luominen epäonnistui"; -"UnexpectedError.bothLuidAndMacAreNil" = "Sekä paikallinen että MAC-tunniste puuttuu"; -"RuuviCloudApiError.emptyResponse" = "Tyhjä vastaus"; -"RuuviCloudApiError.failedToGetDataFromResponse" = "Vastaus ei sisällä tietoa"; -"RuuviCloudApiError.unexpectedHTTPStatusCode" = "Odottamaton HTTP-tilakoodi"; -"RuuviCloudError.NotAuthorized" = "Ei valtuutusta"; -"RuuviLocalError.failedToGetJpegRepresentation" = "JPG-muunnosta ei voida tehdä"; -"RuuviLocalError.failedToGetDocumentsDirectory" = "Taustakuvahakemistoa ei löydy"; -"RuuviPersistenceError.failedToFindRuuviTag" = "Anturia ei löydetty"; -"RuuviServiceError.pictureUrlIsNil" = "Kuvan URL puuttuu"; -"RuuviServiceError.macIdIsNil" = "MAC-tunniste puuttuu"; -"network_sharing_disabled" = "Voit jakaa vain Ruuvi Gateway -reitittimen läheisyydessä olevia antureita."; -"RuuviServiceError.bothLuidAndMacAreNil" = "Sekä paikallinen että MAC-tunniste puuttuu"; -"RuuviServiceError.failedToParseNetworkResponse" = "Vastauksen jäsentäminen epäonnistui"; -"RuuviServiceError.failedToFindOrGenerateBackgroundImage" = "Taustakuvaa ei löydy tai sen luominen epäonnistui"; -"RuuviServiceError.failedToGetJpegRepresentation" = "JPG-muunnosta ei voida tehdä"; -"UpdateFirmware.Title.text" = "Päivitä laiteohjelmisto"; -"UpdateFirmware.Download.header" = "LATAA UUSIN LAITEOHJELMISTO"; -"UpdateFirmware.Download.content" = "Lataa uusin saatavilla oleva ohjelmistopaketti ennen päivityksen aloittamista. Uusin versio on ladattavissa osoitteesta ruuvi.com/fi/ohjelmistopaivitys"; -"UpdateFirmware.SetDfu.header" = "ASETA RUUVI-ANTURI DFU-TILAAN"; -"UpdateFirmware.SetDfu.content" = "Avaa anturin suojakotelo vetämällä kansiosa erilleen kotelon pohjasta sormin tai tasapäisen ruuvimeisselin avulla.\n\nAseta RuuviTag päivitystilaan pitämällä painiketta B alaspainettuna ja painamalla samalla nollauspainiketta R. Punainen LED-valo on aktiivinen laitteen ollessa bootloader-tilassa. Pidä painiketta alaspainettuna 10 sekunnin ajan, mikäli laitteessa on vain yksi painike."; -"UpdateFirmware.NextButton.title" = "SEURAAVA"; -"DfuDevicesScanner.Title.text" = "Laitteet"; -"DfuDevicesScanner.Description.text" = "Etsi ja valitse päivitettävä anturi \"RuuviBoot\"."; -"DfuDevicesScanner.NoDevice.text" = "(Ei havaittuja antureita Bluetooth-verkon alueella)"; -"DfuDevicesScanner.BluetoothDisabled.text" = "(Bluetooth ei ole käytössä)"; -"DfuDevicesScanner.BluetoothDisabledAlert.title" = "Bluetooth ei ole käytössä"; -"DfuDevicesScanner.BluetoothDisabledAlert.message" = "Ruuvi Station tarvitsee Bluetooth-yhteyden toimiakseen. Ota Bluetooth käyttöön laitteen asetuksista."; -"DfuFlash.Title.text" = "DFU-päivitys"; -"DfuFlash.Progress.text" = "Edistyminen"; -"DfuFlash.Step.text" = "Vaihe"; -"DfuFlash.Steps.PackageSelection.text" = "Valitse päivityspaketti"; -"DfuFlash.Steps.ReadyForUpload.text" = "Valmis ladattavaksi"; -"DfuFlash.Steps.Uploading.text" = "Ladataan"; -"DfuFlash.Steps.Completed.text" = "Valmis"; -"DfuFlash.OpenDocumentPicker.title" = "AVAA TIEDOSTOVALITSIN"; -"DfuFlash.FirmwareSelectionGuide.text" = "Etsi aiemmin mobiililaitteelle tallentamasi ZIP-tiedosto."; -"DfuFlash.Firmware.FileName.text" = "Tiedostonimi"; -"DfuFlash.Firmware.Parts.text" = "Osat"; -"DfuFlash.Firmware.Size.text" = "Koko"; -"DfuFlash.Firmware.SoftDeviceSize.text" = "Soft Device koko"; -"DfuFlash.Firmware.BootloaderSize.text" = "Bootloader koko"; -"DfuFlash.Cancel.text" = "PERUUTA"; -"DfuFlash.Start.text" = "Aloita"; -"DfuFlash.Finish.text" = "VALMIS"; -"DfuFlash.FinishGuide.text" = "Laiteohjelmiston päivitys onnistui. -RuuviTag on valmis käyttöön!"; -"DfuFlash.CancelAlert.text" = "Haluatko varmasti peruuttaa laiteohjelmistopäivityksen?"; -"RuuviDfuError.invalidFirmwareFile" = "Tiedosto ei sisällä sopivaa laiteohjelmistoa"; -"DFUUIView.navigationTitle" = "Laiteohjelmiston päivitys"; -"DFUUIView.latestTitle" = "Uusin saatavilla oleva Ruuvi-laiteohjelmisto:"; -"DFUUIView.currentTitle" = "Nykyinen versio:"; -"DFUUIView.notReportingDescription" = "Laitteessa oleva laiteohjelmisto ei ilmoita nykyistä versiota. Joko et ole sen Bluetooth-kuuluvuusalueella, se on samanaikaisesti yhteydessä toiseen puhelimeen tai kyseessä on hyvin vanha laiteohjelmisto."; -"DFUUIView.alreadyOnLatest" = "Laitteessa on jo viimeisin saatavilla oleva laiteohjelmisto"; -"DFUUIView.startUpdateProcess" = "Siirry päivittämään"; -"DFUUIView.downloadingTitle" = "Ladataan viimeisin laiteohjelmisto päivitystä varten..."; -"DFUUIView.prepareTitle" = "Laitteen asettaminen päivitystilaan"; -"DFUUIView.openCoverTitle" = "1. Avaa Ruuvi-anturin suojakotelo"; -"DFUUIView.locateBootButtonTitle" = "2. Paikanna valkoisella piirilevyllä olevat pienet pyöreät mustat painikkeet; vanhemmissa Ruuvi-antureissa on 2 painiketta “R” ja “B”, kun taas uudemmissa on vain yksi nimeämätön painike."; -"DFUUIView.setUpdatingModeTitle" = "3. Aseta anturi päivitystilaan:"; -"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. Anturissasi on kaksi painiketta: pidä painike “B” alaspainettuna ja napauta samalla painiketta “R”. Vapauta painike “B”."; -"DFUUIView.toBootModeOneButtonDescription" = "3.2. Anturissasi on yksi painike: pidä painiketta alaspainettuna 10 sekunnin ajan."; -"DFUUIView.toBootModeSuccessTitle" = "4. Päivitystilaan siirtyminen onnistui, mikäli piirilevyllä oleva punainen LED-valo on nyt aktiivinen ja sovelluksen painikkeen nimeksi on vaihtunut “Aloita päivitys”."; -"DFUUIView.updatingTitle" = "Päivitetään..."; -"DFUUIView.searchingTitle" = "Laitetta etsitään"; -"DFUUIView.startTitle" = "Aloita päivitys"; -"DFUUIView.doNotCloseTitle" = "Älä sulje sovellusta tai poista paristoa laitteesta päivityksen aikana."; -"DFUUIView.successfulTitle" = "Päivitys onnistui"; -"DFUUIView.DBMigration.Error.message" = "Päivitys onnistui, mutta sovelluksen tietokannassa tapahtui odottamaton virhe. Jatkaaksesi tämän anturin käyttöä, poista se sovelluksesta ja lisää se sitten uudelleen."; -"RuuviDfuError.failedToConstructUUID" = "UUID:n muodostaminen epäonnistui"; -"SignIn.EmailMismatch.Alert.message" = "Hupsis, olet pyytänyt kirjautumiskoodia käyttäjälle %@ mutta käytettävä koodi on tarkoitettu käyttäjälle %@. Tarkasta, että saamasi koodi on käyttäjälle %@"; -"SignIn.EmailMissing.Alert.message" = "Hupsis, kirjautumiskoodin saamiseksi antamaasi sähköpostia ei voitu tallentaa. Yritä kirjautumista uudelleen."; -"TagSettings.RemoveThisSensor.title" = "Poista tämä anturi"; -"Share.Success.message" = "Anturi jaettu onnistuneesti"; -"TagSettings.SectionHeader.General.title" = "Yleisasetukset"; -"TagSettings.Shared.title" = "Jaettu"; -"TagSettings.NotShared.title" = "Ei jaettu"; -"Owner.title" = "Vahvista omistajuus"; -"Owner.ClaimOwnership.button" = "Vahvista Omistajuus"; -"Owner.Claim.description" = "Omistatko tämän anturin? Vahvista omistajuus ja anturi lisätään Ruuvi-tilillesi. Jokaisella Ruuvi-anturilla voi olla vain yksi omistaja. Vahvistaaksesi omistajuuden, sinun täytyy olla kirjautuneena sisälle.\n\nHyödyt:\n\n ● Anturien nimet, taustakuvat sekä kalibrointi- ja hälytysasetukset tallentuvat turvallisesti tilillesi pilvipalveluun\n\n ● Lue anturitiedot etänä verkossa (vaatii Ruuvi Gateway -reitittimen)\n\n ● Jaa antureita ystävien ja perheen kesken (vaatii Ruuvi Gateway -reitittimen)\n\n ● Selaa jopa 2 vuoden historiatietoja osoitteessa station.ruuvi.com (vaatii Ruuvi Gateway -reitittimen)"; -"TagSettings.confirmTagUnclaimAndRemoveDialog.message" = "Anturin poistaminen mitätöi omistajuuden. Kuka tahansa voi vaatia anturin omistajuutta poistamisen jälkeen. Jokaisella Ruuvi-anturilla voi olla vain yksi omistaja."; -"TagSettings.confirmSharedTagRemovalDialog.message" = "Poistamisesta ilmoitetaan anturin omistajalle ja anturin tietojen lukuoikeus päättyy."; -"TagSettings.General.Owner.none" = "Ei omistajaa"; -"TagSettings.Share.title" = "Jaa"; -"Menu.LoggedIn.title" = "Kirjautunut:"; -"Interval.Day.string" = "päivä"; -"hour" = "tunti"; -"TagSettings.tagNameTitleLabel.rename.text" = "Anturisi asettuvat automaattisesti aakkosjärjestykseen."; -"On" = "Päällä"; -"Off" = "Pois"; -"DFUUIView.lowBattery.warning.message" = "Anturin paristojännite on alhainen ja päivitysprosessi voi epäonnistua. Suosittelemme vaihtamaan pariston ennen ohjelmiston päivittämistä."; -"alert_notification_humidity_high_threshold" = "Ilmankosteus on yli %@"; -"alert_notification_humidity_low_threshold" = "Ilmankosteus on alle %@"; -"alert_notification_pressure_high_threshold" = "Ilmanpaine on yli %@"; -"alert_notification_pressure_low_threshold" = "Ilmanpaine on alle %@"; -"alert_notification_rssi_high_threshold" = "Signaalinvoimakkuus on yli %@"; -"alert_notification_rssi_low_threshold" = "Signaalinvoimakkuus on alle %@"; -"alert_notification_temperature_high_threshold" = "Lämpötila on yli %@"; -"alert_notification_temperature_low_threshold" = "Lämpötila on alle %@"; -"Cards.Alert.AlreadyLoggedIn.message" = "Käyttäjä %@ on jo kirjautuneena sisälle. Mikäli haluat käyttää toista tiliä, kirjaudu ensin ulos ja yritä sitten uudelleen."; -"Settings.Label.CloudMode" = "Pilvitila"; -"Settings.Label.CloudMode.description" = "Päivitä lähellä olevat pilveen rekisteröidyt anturit ainoastaan pilvestä ja vastaanota ainoastaan sähköpostihälytyksiä hylkäämällä niiden Bluetooth-viestit. Vaatii Ruuvi Gateway -reitittimen."; -"internet_connection_problem" = "Ongelma internet-yhteydessä"; -"Widgets.Loading.message" = "ladataan..."; -"Cards.Movements.title" = "liikettä"; -"TagSettings.BatteryStatusLabel.Replace.message" = "Paristo vähissä"; -"TagSettings.BatteryStatusLabel.Ok.message" = "Paristo OK"; -"Widgets.Description.message" = "Luo widgettejä Ruuvi-antureistasi. Widgetit päivittyvät Ruuvin pilvipalvelun kautta ja vaativat toimiakseen Ruuvi Gateway -reitittimen."; -"settings_appearance" = "Sovelluksen ulkoasuasetukset"; -"app_theme" = "Sovelluksen teema"; -"follow_system_theme" = "Järjestelmä"; -"dark_theme" = "Tumma teema"; -"light_theme" = "Vaalea teema"; -"Settings.Temperature.Resolution.title" = "Lämpötilan resoluutio"; -"Settings.Humidity.Resolution.title" = "Kosteuden resoluutio"; -"Settings.Pressure.Resolution.title" = "Paineen resoluutio"; -"Settings.Measurement.Resolution.description" = "Valitse kuinka suurella tarkkuudella haluat mittaustietojen näkyvän sovelluksessa. Tämä asetus ei vaikuta historiatietoihin tai hälytyksiin."; -"Settings.Measurement.Unit.title" = "Yksikkö"; -"Settings.Measurement.Resolution.title" = "Resoluutio"; -"MyRuuvi.Settings.DeleteAccount.title" = "Poista tili"; -"MyRuuvi.Settings.DeleteAccount.Confirmation.message" = "Vahvistussähköposti lähetetty. Poista tili noudattamalla sähköpostissa annettuja ohjeita."; -"TagSettings.Alert.SetTemperature.title" = "Aseta lämpötilahälytys"; -"TagSettings.Alert.SetHumidity.title" = "Aseta kosteushälytys"; -"TagSettings.Alert.SetPressure.title" = "Aseta painehälytys"; -"TagSettings.Alert.SetRSSI.title" = "Aseta signaalinvoimakkuushälytys"; -"TagSettings.AlertSettings.Dialog.Min" = "Min (%.0f)"; -"TagSettings.AlertSettings.Dialog.Max" = "Max (%.0f)"; -"export_history" = "Lataa historia (csv)"; -"clear_view" = "Tyhjennä kaavionäkymä"; -"day_1" = "1 päivä"; -"day_2" = "2 päivää"; -"day_3" = "3 päivää"; -"day_4" = "4 päivää"; -"day_5" = "5 päivää"; -"day_6" = "6 päivää"; -"day_7" = "7 päivää"; -"day_8" = "8 päivää"; -"day_9" = "9 päivää"; -"day_10" = "10 päivää"; -"day_x" = "%.0f päivää"; -"more" = "Lisää..."; -"all" = "Kaikki"; -"longer_history_title" = "Pidempi historia"; -"longer_history_message" = "Ruuvi Station -mobiilisovellus tukee maksimissaan 10 päivän historiaa. Ruuvi Cloud -tilaajat voivat tarkastella historiatietoja jopa 2 vuoden ajalta web-sovelluksessa osoitteessa ruuvi.com/fi/station (vaatii Ruuvi Gateway -reitittimen)."; -"reading_history_x" = "Bluetooth-lataus: %.0f"; -"rssi_alert_description" = "Tämän hälytyksen käyttö vaatii, että olet sisäänkirjautunut sovellukseen, sinut on merkitty anturin omistajaksi ja anturi on Ruuvi Gateway -reitittimen kuuluvuusalueella. iOS-päätelaitteet eivät pysty näyttämään Ruuvin anturien lähettämien viestien signaalinvoimakkuustietoja anturin ollessa paritettuna ja kun mittauksia luetaan taustalla. Reaaliaikainen Bluetooth-signaalinvoimakkuus näytetään sovelluksessa, mutta sitä ei käytetä tässä hälytyksessä."; -"bluetooth_download" = "Bluetooth-lataus"; -"bluetooth_download_description" = "Voit ladata anturin sisäisen historian ollessasi Bluetooth-kantaman sisällä."; -"download" = "Lataa"; -"clear_local_history" = "Tyhjennä paikallinen historia"; -"clear_local_history_description" = "Haluatko tyhjentää sovelluksen muistiin tallennetun mittaushistorian? Tämä ei tyhjennä anturin sisäistä historiaa eikä Ruuvi Cloud -pilvipalveluun tallennettua historiaa."; -"TagCharts.FailedToSyncDialog.title" = "Lataus epäonnistui"; -"TagCharts.FailedToSyncDialog.message" = "Bluetooth-historian lataus epäonnistui. Tarkasta, että olet Bluetooth-kantaman sisällä, että anturissa on latausta tukeva laiteohjelmisto ja ettei anturi ole yhteydessä toiseen iOS-laitteeseen samanaikaisesti. Ruuvi Stationin iOS-versio varaa anturin yhteyden käyttöönsä jatkuvaa yhteystilaa käytettäessä."; -"TagCharts.TryAgain.title" = "Yritä uudelleen"; -"support" = "Tuki"; -"full_image_view" = "Anturikortti"; -"history_view" = "Historianäkymä"; -"settings_and_alerts" = "Asetukset & hälytykset"; -"change_background" = "Vaihda taustakuva"; -"check_claim_state" = "Omistajuuden tilaa haetaan"; -"claim_in_progress" = "Omistajuutta vaihdetaan"; -"force_claim_sensor" = "Vaihda omistajuus"; -"force_claim_sensor_description1" = "Tällä anturilla on jo toinen omistaja. Omistajuus voidaan vaihtaa pakotetusti, mikäli anturi on lähettyvilläsi. Jokaisella Ruuvi-anturilla voi olla vain yksi omistaja."; -"force_claim_sensor_description2" = "Omistajuuden pakotettu vaihtaminen tapahtuu Near-Field Communication (NFC) ominaisuutta käyttämällä. Varmista, että NFC on käytössä mobiililaitteessasi.\n\n\t1. Aloita omistajuuden pakotettu vaihto koskettamalla Ruuvi-anturia mobiililaitteellasi.\n\n\t2. Sinut siirretään takaisin Asetukset-sivulle onnistuneen vaihdon päätteeksi.\n\nMikäli pakotettu vaihto epäonnistui tai NFC-ominaisuutta ei ole saatavilla mobiililaitteessasi:\n\n\t1. Avaa Ruuvi-anturin suojakotelo.\n\n\t2. Paikanna valkoisella piirilevyllä oleva pieni musta painike (tai painike \"B\", mikäli anturissasi on 2 painiketta), napauta painiketta ensin lyhyesti ja paina tämän jälkeen sivulla olevaa Käytä BT -nappia pakotetun vaihdon aloittamiseksi.\n\n\t3. Sinut siirretään takaisin Asetukset-sivulle onnistuneen vaihdon päätteeksi."; -"force_claim" = "Vaadi omistajuutta"; -"claim_wrong_sensor_scanned" = "Olet lukemassa väärää RuuviTagia"; -"view" = "Näkymä"; -"card_type" = "Korttityyppi"; -"image_cards" = "Kuvakortit"; -"simple_cards" = "Yksinkertaiset kortit"; -"card_action" = "Siirry kortista"; -"open_sensor_view" = "Anturinäkymään"; -"open_history_view" = "Historianäkymään"; -"change_background_message" = "Valitse taustakuva. Taustakuva menetetään uudelleenasennuksen yhteydessä, mikäli et ole sisäänkirjautunut sovellukseen."; -"take_photo" = "Ota kuva"; -"select_from_gallery" = "Valitse kuvagalleriasta"; -"select_default_image" = "Valitse oletuskuva"; -"export_csv_feature_location" = "Anturihistoria voidaan viedä tiedostoon anturin historiasivulla. Napauta oikeassa yläkulmassa olevaa kolmipistevalikkoa ja valitse sitten \"Lataa historia (csv)\"."; -"low_battery" = "Paristo vähissä"; -"change_background_image" = "Vaihda taustakuva"; -"SignIn.Sync.message" = "Ladataan tietoja pilvestä. Odota hetki."; -"uploading_progress" = "Ladataan: %.0f"; -"Widgets.Unauthorized.Regular.message" = "Kirjaudu sisään käyttääksesi widgettiä."; -"Widgets.Unauthorized.Inline.message" = "Kirjaudu Ruuvi Stationiin"; -"Widgets.Unconfigured.Simple.message" = "Paina pitkään muokataksesi widgettiä."; -"Widgets.Unconfigured.Rectangular.message" = "Lisää Ruuvi widgetissä näytettävä anturi"; -"Widgets.Unconfigured.Inline.message" = "Lisää Ruuvi widgetissä näytettävä anturi"; -"Widgets.Unconfigured.Circular.message" = "+Lisää"; -"Widgets.Select.Sensor.title" = "Valittu anturi"; -"Widgets.Sensor.Type.title" = "Valitse anturin tyyppi"; -"Settings.SectionHeader.General.title" = "YLEISET"; -"Settings.SectionHeader.Application.title" = "OHJELMA"; -"empty_chart_message" = "Ei tallennettuja mittauksia \nvalitulla aikajaksolla."; -"onboarding_measure_your_world" = "Measure Your World"; -"onboarding_with_ruuvi_sensors" = "Tutustu Ruuvi Station -sovellukseesi."; -"onboarding_swipe_to_continue" = "Jatka pyyhkäisemällä →"; -"onboarding_read_sensors_data" = "Lue Ruuvi-antureitasi"; -"onboarding_via_bluetooth_or_cloud" = "Bluetoothilla tai Ruuvi Cloudilla"; -"onboarding_follow_measurement" = "Seuraa kaikkia antureitasi"; -"onboarding_dashboard" = "koontinäytöltä"; -"onboarding_personalise" = "Personoi"; -"onboarding_your_sensors" = "sovelluksesi omilla nimillä ja taustakuvilla."; -"onboarding_explore_detailed" = "Tarkastele anturiesi"; -"onboarding_history" = "mittaushistoriaa"; -"onboarding_set_custom" = "Aseta ja säädä omat"; -"onboarding_alerts" = "hälytyksesi"; -"onboarding_share_your_sensors" = "ja mittaa yhdessä ystävien sekä perheen kesken."; -"onboarding_sharees_can_use" = "Jaa anturisi"; -"onboarding_handy_widgets" = "widgeteillä"; -"onboarding_access_widgets" = "Tuo suosikkianturisi kotinäytölle ja lukitusnäytölle"; -"onboarding_station_web" = "Ruuvin web-sovelluksessa"; -"onboarding_web_pros" = "Koontinäyttö, usean vuoden historia, sähköpostihälytykset ja paljon muuta"; -"onboarding_gateway_required" = "Vaatii Ruuvi Gateway -reitittimen."; -"onboarding_skip" = "Ohita"; -"onboarding_thats_it" = "Melkein valmista!"; -"onboarding_thats_it_already_signed_in" = "Aloitetaan!"; -"onboarding_go_to_sign_in" = "Kirjautumalla sisään saat parhaan Ruuvi-käyttökokemuksen. Tee se nyt tai jatka ilman pilviominaisuuksia."; -"onboarding_go_to_sign_in_already_signed_in" = "Lähdetään mittaamaan!"; -"onboarding_continue" = "Seuraava"; -"sign_in_or_create_free_account" = "Kirjaudu tai luo ilmainen Ruuvi-tili"; -"to_use_all_app_features" = "Kirjautuminen ei vaadi salasanaa."; -"type_your_email" = "Anna sähköpostiosoite..."; -"request_code" = "Pyydä kirjautumiskoodi"; -"no_password_needed" = "Tälle osoitteelle luodaan ilmainen tili, jos sinulla ei vielä ole tiliä. Tarvitset kirjautumiseen ainoastaan sähköpostiosoitteen. Pidämme tietosi turvassa."; -"benefits_sign_in" = "Lue lisää Ruuvi-tilin hyödyistä tai kirjaudu sisään myöhemmin"; -"use_without_account" = "Ei kiitos, ohita"; -"why_should_sign_in" = "Hyödyt"; -"sensors_ownership_and_settings_stored_in_cloud" = "Sisäänkirjautumalla saat useita etuja. Asetukset tallennetaan turvallisesti tilillesi:"; -"cloud_stored_ownerships" = "● Anturien omistajuustiedot"; -"cloud_stored_names" = "● Anturinimet"; -"cloud_stored_alerts" = "● Taustakuvat"; -"cloud_stored_backgrounds" = "● Hälytysasetukset"; -"cloud_stored_calibration" = "● Kalibrointiasetukset"; -"cloud_stored_sharing" = "● Sovellusasetukset"; -"note" = "Huomaa!"; -"claim_warning" = "Turvaa anturiesi omistajuustiedot merkitsemällä niiden omistajuudet sovelluksessa."; -"lets_do_it" = "Siirry kirjautumaan"; -"enter_code" = "Syötä koodi"; -"dashboard_no_sensors_message" = "Sinulla ei ole vielä Ruuvi-antureita sovelluksessa."; -"dashboard_no_sensors_message_signed_out" = "Et ole kirjautunut sisään.\n\nJos sinulla on tili ja olet jo lisännyt tilille Ruuvi-antureita, ne synkronoituvat automaattisesti Ruuvi Station -mobiilisovellukseen kirjautuessasi sisään."; -"add_a_sensor" = "Lisää anturi"; -"changelog" = "(muutosloki)"; -"changelog_ios_url" = "https://f.ruuvi.com/t/3192"; -"chart_stat_min" = "Min"; -"chart_stat_max" = "Max"; -"chart_stat_avg" = "Keskiarvo"; -"shared_to_x" = "Jaettu %d/%d"; -"settings_alert_notifications" = "Hälytysilmoitukset"; -"settings_alert_sound" = "Hälytysääni"; -"settings_alert_sound_description" = "Valitse push-viestin hälytysääni."; -"settings_alerts_footer_description" = "Voit myös muokata ilmoitusasetuksia kohdassa iOS-asetukset -> Ilmoitukset"; -"settings_alerts_footer_description_link_mask" = "iOS-asetukset -> Ilmoitukset"; -"settings_email_alerts" = "Sähköpostihälytykset"; -"settings_email_alerts_description" = "Jos olet Ruuvi Cloud ja Ruuvi Gateway -käyttäjä, voit vastaanottaa sähköpostihälytyksiä ottamalla tämän käyttöön."; -"settings_push_alerts" = "Push-hälytykset"; -"settings_push_alerts_description" = "Jos olet Ruuvi Cloud ja Ruuvi Gateway -käyttäjä, voit vastaanottaa push-hälytyksiä ottamalla tämän käyttöön."; -"synchronisation" = "Synkronointi"; -"gatt_sync_description" = "Ruuvi Station lataa anturin sisäisen historian viimeiseltä 10 päivältä, jos historia on saatavilla.\n\nMittaushistoria ladataan Bluetooth-yhteydellä. Varmista, että olet anturin läheisyydessä."; -"do_not_show_again" = "Älä näytä tätä uudestaan"; -"sign_in_continue" = "Jatka"; -"signing_in_is_optional" = "(Kirjautuminen ei ole pakollista)"; -"Defaults.UserAuthorized.title" = "Käyttäjä autorisoitu"; -"Defaults.DashboardTapActionChart.title" = "Näytä kuvaaja napauttamalla koontinäytön korttia"; -"Defaults.DevServer.title" = "Käytä dev-palvelinta"; -"Defaults.DevServer.message" = "Ruuvi Cloud -päätepisteen muuttaminen vaatii kirjautumisen ulos nykyisestä istunnosta ja käynnistämään sovelluksen uudelleen. Oletko varma?"; -"Defaults.ShowEmailAlertsSettings.title" = "Näytä sähköpostihälytysasetukset"; -"Defaults.ShowPushAlertsSettings.title" = "Näytä push-hälytysasetukset"; -"use_nfc" = "Käytä NFC:tä"; -"use_bluetooth" = "Käytä BT:tä"; -"sensor_not_found_error" = "Anturia ei löytynyt. Yritä uudelleen."; -"Defaults.HideNFC.title" = "Piilota NFC-vaihtoehto pakotetusta omistajuudenvaihdosta"; -"settings_alert_sound_default" = "Järjestelmän oletus"; -"settings_alert_sound_ruuvi_speak" = "Ruuvi hälytys"; -"add_with_nfc" = "Lisää NFC:llä"; -"sensor_details" = "Anturin tiedot"; -"add_sensor" = "Lisää anturi"; -"copy_mac_address" = "Kopioi MAC-osoite"; -"copy_unique_id" = "Kopioi yksilöivä tunniste"; -"name" = "Nimi:"; -"mac_address" = "MAC-osoite:"; -"go_to_sensor" = "Siirry anturikortille"; -"unique_id" = "Yksilöivä tunniste:"; -"firmware_version" = "Laiteohjelmistoversio:"; -"Close" = "Sulje"; -"add_sensor_nfc_df3_error" = "Vanha laiteohjelmisto ei salli anturin lisäämistä NFC:llä. Lisää anturi Bluetooth-yhteydellä ja päivitä laiteohjelmisto."; -"add_sensor_description" = "Tällä sivulla näet lähelläsi olevat Ruuvi-anturit, joita ei ole vielä lisätty sovellukseen. Lisää listattu anturi napauttamalla."; -"add_sensor_via_nfc" = "Voit vaihtoehtoisesti lisätä anturin sovellukseen NFC:llä napauttamalla Lisää NFC:llä painiketta ja koskettamalla sitä."; -"unclaim_sensor" = "Poista omistajuus"; -"unclaim" = "Poista omistajuus"; -"unclaim_sensor_description" = "Tämän anturin omistajuus on merkitty Ruuvi-tilillesi. Poista anturin asetukset ja anturin tiedot Ruuvi-tililtä valitsemalla Poista omistajuus."; -"claim_sensor_ownership" = "Vaadi anturin omistajuutta"; -"do_you_own_sensor" = "Omistatko tämän anturin?"; -"owners_plan" = "Omistajan Ruuvi-tilaus"; -"alert_cloud_connection_title" = "Yhteys pilveen"; -"alert_cloud_connection_description" = "Hälytä, jos anturitietoja ei ole päivitetty pilveen yli %d minuuttiin."; -"alert_cloud_connection_dialog_description" = "Syötä haluttu viive minuutteina, jonka jälkeen hälytys laukaistaan. Lyhyin valittava arvo on 2 minuuttia."; -"alert_cloud_connection_dialog_title" = "Aseta pilviyhteyden hälytys"; -"rename" = "Nimeä uudelleen"; -"chart_stat_show" = "Näytä min/maks/ka"; -"chart_stat_hide" = "Piilota min/maks/ka"; -"settings_alert_limit_notification" = "Rajoita hälytysilmoituksia"; -"settings_alert_limit_notification_description" = "Näytä Bluetooth-hälytysilmoitus vain kerran tunnissa, vaikka hälytys laukeaisi useammin."; -"share_pending" = "Jakamista odotetaan"; -"share_pending_message" = "Jako onnistui! Tämä sähköpostiosoite ei ole vielä liitetty Ruuvi-tiliin. Kutsu ilmaisen tilin luomiseen on lähetetty. Kun tili on luotu, näet sen jakolistanäkymässä."; -"dialog_are_you_sure" = "Oletko varma?"; -"dialog_operation_undone" = "Tätä toimenpidettä ei voi perua."; -"remove_cloud_history_title" = "Poista pilvihistoria"; -"remove_cloud_history_description" = "Haluan myös poistaa anturihistoriatiedot Ruuvi Cloudista."; -"remove_claimed_sensor_description" = "Poistamalla anturin omistusoikeutesi peruutetaan, ja anturin asetukset, kuten nimi, taustakuva, kalibrointiasetukset ja hälytysasetukset poistetaan. Poiston jälkeen joku toinen voi ottaa anturin omistukseensa. Jokaisella Ruuvi-anturilla voi olla vain yksi omistaja."; -"remove_shared_sensor_description" = "Jos poistat tämän jaetun anturin, anturin omistajalle lähetetään ilmoitus poistosta, etkä voi enää käyttää anturia.\n\nMenetät myös kaikki tähän anturiin liittyvät anturin asetukset, kuten nimen, taustakuvan ja asetetut hälytykset."; -"remove_local_sensor_description" = "Jos poistat tämän anturin, paikallisesti tallennettu mittaushistoria ja kaikki tähän anturiin liittyvät asetukset, kuten nimi, taustakuva, kalibrointiasetukset ja hälytysasetukset poistetaan.\n\nVoit lisätä tämän anturin myöhemmin uudelleen tarvittaessa."; -"activity_saving_to_cloud" = "Tallennetaan pilveen...odota hetki."; -"activity_saving_success" = "Tallennus onnistui."; -"activity_saving_fail" = "Muutoksia ei voitu tallentaa pilveen."; -"activity_ongoing_generic" = "Odota..."; -"activity_success_generic" = "Toiminto onnistui."; -"activity_failed_generic" = "Toiminto epäonnistui."; -"Devices.tokenId" = "Token Id"; -"UserApiError.ER_GATEWAY_NOT_FOUND" = "Gateway not found"; -"UserApiError.ER_GATEWAY_ALREADY_WHITELISTED" = "Gateway already whitelisted"; -"UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED" = "Gateway status report failed"; -"UserApiError.ER_CONFLICT" = "Data already exists, cannot update"; -"UserApiError.ER_CLAIM_COUNT_REACHED" = "Maximum claim count for the user reached"; -"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Maximum share count for the sensor reached"; -"UserApiError.ER_NO_DATA_TO_SHARE" = "In order to share a sensor, it must have data"; -"UserApiError.ER_SENSOR_ALREADY_REGISTERED" = "The sensor has already been registered"; -"UserApiError.ER_SUBSCRIPTION_CODE_EXISTS" = "Tried to add duplicate subscription to a code"; -"UserApiError.ER_SUBSCRIPTION_CODE_USED" = "Tried to claim already used code"; -"UserApiError.ER_OLD_ENTRY" = "Newer data already exists, cannot update"; -"UserApiError.ER_INVALID_ENUM_VALUE" = "Invalid ENUM value given"; -"UserApiError.OK" = "Operation was successful"; diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fr.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fr.lproj/Localizable.strings deleted file mode 100644 index 10f7618e3..000000000 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fr.lproj/Localizable.strings +++ /dev/null @@ -1,769 +0,0 @@ -// swiftlint:disable all -// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen -"Done" = "Prêt"; -"Copy" = "Copier"; -"Confirm" = "Confirmer"; -"Remove" = "Supprimer"; -"N/A" = "-"; -"g" = "g"; -"About.Version.text" = "Version"; -"Background.PresentNotifications.title" = "Voir les notifications"; -"Background.KeepConnection.title" = "Maintenir la connexion"; -"Background.Interval.Every.string" = "Chaque"; -"Background.Interval.Min.string" = "min"; -"Background.readRSSITitle.title" = "Lire RSSI"; -"BluetoothError.disconnected" = "Déconnecté"; -"Cards.BluetoothDisabledAlert.title" = "Bluetooth désactivé"; -"Cards.BluetoothDisabledAlert.message" = "Ruuvi Station a besoin du Bluetooth pour fonctionner. Activez-le dans les paramètres de votre téléphone."; -"Cards.WebTagAPILimitExcededError.Alert.title" = "Trop de demandes simultanées"; -"Cards.WebTagAPILimitExcededError.Alert.message" = "Réessayez dans 5 minutes"; -"Cards.KeepConnectionDialog.message" = "Votre appareil est programmé pour rester connecté. Souhaitez-vous maintenir la connexion en arrière plan? Cela permettra de tracer les histogrammes et de recevoir les alertes même lorsque l'application est fermée."; -"Cards.KeepConnectionDialog.Dismiss.title" = "Supprimer"; -"Cards.KeepConnectionDialog.KeepConnection.title" = "Maintenir la connexion"; -"Cards.LegacyFirmwareUpdateDialog.message" = "Il semble que votre capteur utilise une ancienne version du micrologiciel. Une mise à jour est obligatoire pour avoir accès à de nouvelles fonctions telles que les graphiques d'historique, les alertes et les services cloud."; -"Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message" = "Tu es sûr ? Sans mise à jour, vous ne pouvez pas revendiquer la propriété du capteur, télécharger des graphiques d'historique et définir des alertes. La mise à jour contient également des corrections de bugs. Si vous annulez maintenant, vous pouvez relancer le processus de mise à jour à partir de la page de configuration du capteur."; -"Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title" = "Vérifie les mises à jour"; -"Cards.Connected.title" = "Connecté"; -"Cards.Error.ReverseGeocodingFailed.message" = "Echec du téléchargement des données de l'appareil."; -"Cards.UpdatedLabel.NoData.message" = "Aucune donnée au cours des 10 derniers jours"; -"CoreError.failedToGetPngRepresentation" = "Echec de la représentation PNG"; -"CoreError.failedToGetDocumentsDirectory" = "Répertoire d'arrière-plan introuvable"; -"CoreError.failedToGetCurrentLocation" = "Position introuvable"; -"CoreError.failedToGetDataFromResponse" = "La réponse ne contient pas de données"; -"CoreError.locationPermissionDenied" = "L'accès aux données de géolocalisation n'est pas accordé"; -"CoreError.locationPermissionNotDetermined" = "L'accès aux données de géolocalisation n'est pas déterminé"; -"CoreError.objectNotFound" = "Objet introuvable"; -"CoreError.objectInvalidated" = "Objet invalide"; -"CoreError.unableToSendEmail" = "Echec de l'envoi du mail"; -"Defaults.navigationItem.title" = "Paramètres d'usine"; -"Defaults.WelcomeShown.title" = "La présentation est affichée"; -"Defaults.ChartsSwipeInstructionWasShown.title" = "Détails de l'histogramme en mode paysage"; -"Defaults.Interval.Sec.string" = "sec"; -"Defaults.Interval.Min.string" = "min"; -"Defaults.ConnectionTimeout.title" = "Temporisation de la connexion"; -"Defaults.ServiceTimeout.title" = "Temporisation du service"; -"Defaults.CardsSwipeHint.title" = "Conseil d'essuyage"; -"Defaults.AlertsRepeatInterval.title" = "Intervalle d'alerte"; -"Defaults.WebPullInterval.title" = "Intervalle d'alerte des capteurs virtuels"; -"Defaults.PruningOffsetHours.title" = "Décalage"; -"Defaults.Interval.Hour.string" = "h"; -"Defaults.ChartDurationHours.title" = "Durée de l'historique"; -"Defaults.AppLaunchRequiredForReview.Count.title" = "Nombre de lancements d'applications pour demander un examen pour la première fois"; -"Defaults.AskReviewIfLaunchDivisibleBy.Count.title" = "Demander un avis si le lancement de l'application est divisible par"; -"DiscoverTable.SectionTitle.WebTags" = "Capteurs virtuels"; -"DiscoverTable.BluetoothDisabledAlert.title" = "Bluetooth désactivé"; -"DiscoverTable.BluetoothDisabledAlert.message" = "Ruuvi Station a besoin du Bluetooth pour fonctionner. Activez-le dans les paramètres de votre appareil."; -"DiscoverTable.NavigationItem.title" = "Ajouter un capteur"; -"DiscoverTable.GetMoreSensors.button.title" = "Acheter des capteurs Ruuvi"; -"DiscoverTable.NoDevicesSection.NotFound.text" = "(Pas de capteurs à portée du Bluetooth)"; -"DiscoverTable.NoDevicesSection.BluetoothDisabled.text" = "(Bluetooth désactivé)"; -"DiscoverTable.WebTagsInfoDialog.message" = "Les capteurs virtuels permettent d'afficher des données recueillies à partir de stations météorologiques locales."; -"DiscoverTable.RuuviDevice.prefix" = "Ruuvi"; -"ErrorPresenterAlert.Error" = "Erreur"; -"ErrorPresenterAlert.OK" = "OK"; -"ExpectedError.missingOpenWeatherMapAPIKey" = "Clé API OpenWeatherMap manquante. Obtenez une clé sur openweathermap.org et ajoutez-la dans le fichier station/Classes/Networking/Assembly/Networking.plist"; -"ExpectedError.isAlreadySyncingLogsWithThisTag" = "L'application a été paramétrée pour être synchronisée avec ce capteur"; -"ExpectedError.failedToDeleteTag" = "Un capteur enregistré ne peut être supprimé sans connexion Bluetooth. Vérifiez la connexion."; -"ExportService.Date" = "Date"; -"ExportService.ISO8601" = "ISO8601"; -"ExportService.Temperature" = "Température (%@)"; -"ExportService.Humidity" = "Humidité (%@)"; -"ExportService.DewPoint" = "Point de rosée (%@)"; -"ExportService.Pressure" = "Pression (%@)"; -"ExportService.Voltage" = "Tension (V)"; -"ExportService.MovementCounter" = "Compteur de mouvements"; -"ExportService.MeasurementSequenceNumber" = "Numéro de séquence"; -"ExportService.TXPower" = "Puissance d'émission"; -"ForegroundRow.advertisement.section" = "MESSAGES DES CAPTEURS"; -"ForegroundRow.advertisement.title" = "Enregistrer les messages des capteurs"; -"ForegroundRow.connection.section" = "HISTORIQUE"; -"ForegroundRow.connection.title" = "Connecter et enregistrer l'historique"; -"Foreground.navigationItem.title" = "Tâches actives en premier plan"; -"Foreground.Interval.Every.string" = "Chaque"; -"Foreground.Interval.Min.string" = "min"; -"ForegroundRow.webTags.title" = "Télécharger et enregistrer depuis internet"; -"ForegroundRow.webTags.section" = "CAPTEURS VIRTUELS"; -"Foreground.Interval.All.string" = "Tous"; -"Heartbeat.Interval.Every.string" = "toutes les"; -"Heartbeat.Interval.Min.string" = "min"; -"Heartbeat.readRSSITitle.title" = "Lire RSSI"; -"Heartbeat.Interval.Sec.string" = "sec"; -"Heartbeat.Interval.All.string" = "Tous"; -"HumidityCalibration.ClearCalibrationConfirmationAlert.title" = "Êtes-vous sûr ?"; -"HumidityCalibration.ClearCalibrationConfirmationAlert.message" = "Vous allez réinitialiser le calibrage de l'hygromètre. Cette action est irréversible. Appuyez sur \"confirmer\" pour continuer."; -"HumidityCalibration.CalibrationConfirmationAlert.title" = "Êtes-vous sûr ?"; -"HumidityCalibration.CalibrationConfirmationAlert.message" = "Vous allez calibrer l'hygromètre. Appuyez sur \"confirmer\" pour continuer."; -"Language.English" = "English"; -"Language.Finnish" = "Suomi"; -"Language.Russian" = "Русский"; -"Language.Swedish" = "Svenska"; -"Language.French" = "Français"; -"Language.German" = "Deutsch"; -"LocalNotificationsManager.DidConnect.title" = "Connecté"; -"LocalNotificationsManager.DidDisconnect.title" = "Déconnecté"; -"LocalNotificationsManager.Disable.button" = "Supprimer"; -"LocalNotificationsManager.LowDewPoint.title" = "Point de rosée trop bas !"; -"LocalNotificationsManager.HighDewPoint.title" = "Point de rosée trop haut !"; -"PermissionPresenter.NoPhotoLibraryAccess.message" = "Veuillez autoriser l'accès aux fichiers multimédias de votre appareil."; -"PermissionPresenter.NoCameraAccess.message" = "Veuillez autoriser l'accès à l'appareil photo."; -"PermissionPresenter.NoLocationAccess.message" = "Veuillez autoriser l'accès aux services de géolocalisation."; -"PermissionPresenter.settings" = "Réglages"; -"PermissionPresenter.NoPushNotificationsPermission.message" = "Veuillez autoriser les notifications dans les réglages de l'appareil."; -"PhotoPicker.Sheet.message" = "Choisissez une photo"; -"PhotoPicker.Sheet.library" = "Choisir dans la bibliothèque"; -"PhotoPicker.Sheet.camera" = "Prendre une photo"; -"Settings.SegmentedControl.Humidity.Relative.title" = "Rel"; -"Settings.SegmentedControl.Humidity.Absolute.title" = "Abs"; -"Settings.SegmentedControl.Humidity.DewPoint.title" = "Rosée"; -"Settings.Label.Language.text" = "Langue"; -"Settings.Language.Dialog.title" = "Choisissez une Langue"; -"Settings.Language.Dialog.message" = "Ouvrez les paramètres et appuyez sur Langue pour changer la langue de l'application. Si vous ne voyez pas l'option Langue dans les paramètres, assurez-vous que vous avez ajouté au moins une langue préférée dans les paramètres système : Paramètres -> Général -> Langue et région."; -"Settings.Label.Foreground" = "Premier plan"; -"Settings.Label.Defaults" = "Paramètres d'usine"; -"OWMError.failedToParseOpenWeatherMapResponse" = "Echec lors de l'ajout de la réponse Weather Map"; -"OWMError.apiLimitExceeded" = "Limite API dépassée"; -"OWMError.notAHttpResponse" = "La réponse n'est pas au format HTTP"; -"OWMError.invalidApiKey" = "Clé API invalide"; -"TagCharts.NoChartData.text" = "Informations indisponibles"; -"TagCharts.BluetoothDisabledAlert.title" = "Le Bluetooth n'est pas activé"; -"TagCharts.BluetoothDisabledAlert.message" = "Ruuvi Station a besoin du Bluetooth pour fonctionner. Veuillez l'activer dans les paramètres de votre appareil."; -"TagCharts.Clear.title" = "Effacer"; -"TagCharts.SyncConfirmationDialog.title" = "Êtes-vous sûr ?"; -"TagCharts.DeleteHistoryConfirmationDialog.button.delete.title" = "Supprimer"; -"TagCharts.DeleteHistoryConfirmationDialog.title" = "Êtes-vous sûr ?"; -"TagCharts.Status.Disconnecting" = "Déconnexion..."; -"TagCharts.Status.Success" = "Succès"; -"TagCharts.Status.Error" = "Erreur"; -"TagSettings.UUID.Alert.title" = "UUID"; -"TagSettings.UpdateFirmware.Alert.title" = "Format RAWv2 nécessaire"; -"TagSettings.UpdateFirmware.Alert.message" = "L'affichage des informations manquantes n'est possible qu'avec la nouvelle version système."; -"TagSettings.UpdateFirmware.Alert.Buttons.LearnMore.title" = "Plus d'infos"; -"TagCharts.Dismiss.Alert.message" = "Le téléchargement de l'historique via la connexion Bluetooth est en cours. Veuillez patienter."; -"TagCharts.AbortSync.Alert.message" = "Parfois, le téléchargement de l'historique est lent en raison de la connectivité Bluetooth. Veuillez patienter un moment."; -"TagCharts.AbortSync.Button.title" = "Abandonner le téléchargement"; -"TagSettings.EmptyValue.sign" = "-"; -"TagSettings.HumidityIsClipped.Alert.title" = "L'hygromètre est calibré"; -"TagSettings.HumidityIsClipped.Alert.message" = "L'humidité est supérieure à 100 % après calibrage. Cela n'a pas de sens, donc la valeur max affichée est 100 %."; -"TagSettings.HumidityIsClipped.Alert.Fix.button" = "Réparer"; -"TagSettings.navigationItem.title" = "Réglages"; -"TagSettings.tagNameTitleLabel.text" = "Nom du capteur"; -"TagSettings.humidityTitleLabel.text" = "Humidité"; -"TagSettings.uuidTitleLabel.text" = "UUID"; -"TagSettings.macAddressTitleLabel.text" = "Adresse MAC"; -"TagSettings.dataFormatTitleLabel.text" = "Format des données"; -"TagSettings.accelerationXTitleLabel.text" = "Accélération en X"; -"TagSettings.accelerationYTitleLabel.text" = "Accélération en Y"; -"TagSettings.accelerationZTitleLabel.text" = "Accélération en Z"; -"TagSettings.txPowerTitleLabel.text" = "Puissance d'émission"; -"TagSettings.mcTitleLabel.text" = "Compteur de mouvements"; -"TagSettings.msnTitleLabel.text" = "Numéro de séquence"; -"TagSettings.SectionHeader.Remove.title" = "SUPPRIMER"; -"TagSettings.Label.noValues.text" = "PAS DE VALEURS ?"; -"TagSettings.SectionHeader.Calibration.title" = "CALIBRAGE"; -"TagSettings.SectionHeader.BTConnection.title" = "BLUETOOTH CONNEXION"; -"TagSettings.PairAndBackgroundScan.Unpaired.title" = "Jumelage et utilisation de l'analyse d'arrière-plan"; -"TagSettings.PairAndBackgroundScan.Pairing.title" = "Connexion au capteur"; -"TagSettings.PairAndBackgroundScan.Paired.title" = "Pairé et le scan de fond est activé"; -"TagSettings.PairAndBackgroundScan.description" = "Les alertes ne sont pas disponibles via la connexion Bluetooth si le balayage en arrière-plan n'est pas activé. Un seul appareil iOS peut être apparié à un capteur Ruuvi à la fois."; -"TagSettings.PairError.CloudMode.description" = "Impossible de se connecter au capteur tant que le statut du cloud est actif. Vous pouvez modifier le statut dans les paramètres de l'application."; -"TagSettings.PairError.Timeout.description" = "La connexion a expiré. Le jumelage n'a pas réussi. Veuillez réessayer."; -"TagSettings.dataSourceTitleLabel.text" = "Données reçues via"; -"TagSettings.DataSource.Heartbeat.title" = "Cadence"; -"TagSettings.DataSource.Advertisement.title" = "Messages des capteurs"; -"TagSettings.DataSource.Network.title" = "Cloud"; -"TagSettings.Label.disabled.text" = "HORS SERVICE ?"; -"TagSettings.AlertsAreDisabled.Dialog.BothNotConnectedAndNoPNPermission.message" = "Les notifications sont désactivées car l'appareil n'est pas connecté et les notifications ne sont autorisées. Veuillez d'abord vous connecter à l'appareil."; -"TagSettings.AlertsAreDisabled.Dialog.Connect.title" = "Se connecter"; -"TagSettings.AlertsAreDisabled.Dialog.NotConnected.message" = "Les notifications sont désactivées car l'appreil n'est pas connecté."; -"TagSettings.Alert.CustomDescription.placeholder" = "Modifier la description..."; -"TagSettings.Alert.CustomDescription.title" = "Description personnalisée de l'alerte"; -"TagSettings.Alerts.Humidity.description" = "Notifier si la valeur est inférieure à %.0f ou supérieure à %.0f"; -"TagSettings.Alerts.DewPoint.description" = "Notifier si le point de rosée est inférieur à %.0f ou supérieur à %.0f"; -"TagSettings.dewPointAlertTitleLabel.text" = "Point de rosée"; -"TagSettings.Alerts.Pressure.description" = "Notifier si la pression de l'air est inférieure à %.0f ou supérieure à %.0f"; -"TagSettings.Alerts.Connection.description" = "Notifier lorsque l'appareil est connecté/déconnecté"; -"TagSettings.ConnectionAlert.title" = "Connexion"; -"TagSettings.SectionHeader.Firmware.title" = "Firmware"; -"TagSettings.Firmware.CurrentVersion" = "Version actuelle"; -"TagSettings.Firmware.CurrentVersion.VeryOld" = "Très vieux"; -"TagSettings.Firmware.UpdateFirmware" = "Mettre à jour"; -"UnexpectedError.callbackErrorAndResultAreNil" = "Le résultat est nul"; -"UnexpectedError.callerDeinitedDuringOperation" = "Les invitations ont été délocalisées"; -"UnexpectedError.failedToReverseGeocodeCoordinate" = "Echec de l'annulation de la géolocalisation"; -"UnexpectedError.failedToFindRuuviTag" = "Echec de jumelage"; -"UnexpectedError.failedToFindLogsForTheTag" = "Historique du capteur introuvable"; -"UnexpectedError.viewModelUUIDIsNil" = "Le modèle d'affichage UUID est nul"; -"UnexpectedError.attemptToReadDataFromRealmWithoutLUID" = "Tentative de lecture des données de Realm sans LUID"; -"UnexpectedError.failedToFindVirtualTag" = "Echec de jumelage du capteur virtuel"; -"HumidityUnit.Dew.title" = "Point de rosée (%@)"; -"WebTagLocationSource.current" = "Localisation actuelle"; -"WebTagLocationSource.manual" = "Choisir sur la carte"; -"WebTagSettings.confirmTagRemovalDialog.title" = "Supprimer"; -"WebTagSettings.confirmTagRemovalDialog.message" = "Êtes-vous certain de vouloir supprimer ?"; -"WebTagSettings.Location.Current" = "Localisation actuelle"; -"WebTagSettings.confirmClearLocationDialog.title" = "Supprimer la localisation"; -"WebTagSettings.confirmClearLocationDialog.message" = "Êtes-vous certain de vouloir supprimer cette position et d'utiliser votre position actuelle ?"; -"WebTagSettings.navigationItem.title" = "Réglages"; -"WebTagSettings.Label.BackgroundImage.text" = "FOND D'ÉCRAN"; -"WebTagSettings.Label.Location.text" = "Position"; -"WebTagSettings.Button.Remove.title" = "SUPPRIMER CE CAPTEUR VIRTUEL"; -"WebTagSettings.SectionHeader.Name.title" = "NOM"; -"WebTagSettings.SectionHeader.MoreInfo.title" = "PLUS D'INFOS"; -"WebTagSettings.Alerts.Temperature.description" = "Notifier si la température est inférieure à %.0f ou supérieure à %.0f"; -"WebTagSettings.Alerts.Off" = "Désactivé"; -"WebTagSettings.temperatureAlertTitleLabel.text" = "Température"; -"WebTagSettings.Label.disabled.text" = "DÉSACTIVÉ ?"; -"WebTagSettings.Label.alerts.text" = "NOTIFICATIONS"; -"WebTagSettings.AlertsAreDisabled.Dialog.BothNoPNPermissionAndNoLocationPermission.message" = "Pour activer les notifications, veuillez autoriser la géolocalisation ainsi que l'affichage des notifications dans les réglages de votre appareil."; -"WebTagSettings.AlertsAreDisabled.Dialog.Settings.title" = "Réglages"; -"WebTagSettings.AirHumidityAlert.title" = "Humidité de l'air"; -"WebTagSettings.Alerts.Humidity.description" = "Notifier si la valeur est inférieure à %.0f ou supérieure à %.0f"; -"WebTagSettings.Alerts.DewPoint.description" = "Notifier si le point de rosée est inférieur à %.0f ou supérieur à %.0f"; -"WebTagSettings.dewPointAlertTitleLabel.text" = "Point de rosée"; -"WebTagSettings.PressureAlert.title" = "Pression de l'air"; -"WebTagSettings.Alerts.Pressure.description" = "Notifier si la pression de l'air est inférieure à %.0f ou supérieure à %.0f"; -"Welcome.description.text" = "Appuyer sur scanner pour trouver des capteurs."; -"ExportService.AccelerationX" = "Accélération en X"; -"ExportService.AccelerationY" = "Accélération en Y"; -"ExportService.AccelerationZ" = "Accélération en Z"; -"DiscoverTable.SectionTitle.Devices" = "Capteurs Ruuvi à proximité"; -"ago" = "avant"; -"TagSettings.MovementAlert.title" = "Mouvement"; -"TagSettings.Alerts.Movement.description" = "Notifier quand le capteur est déplacé"; -"LocalNotificationsManager.HighHumidity.title" = "L'humidité de l'air est trop haute !"; -"LocalNotificationsManager.LowHumidity.title" = "L'humidité de l'air est trop basse !"; -"LocalNotificationsManager.DidMove.title" = "Mouvement détecté !"; -"LocalNotificationsManager.HighPressure.title" = "La pression de l'air est trop haute !"; -"LocalNotificationsManager.LowPressure.title" = "La pression de l'air est trop basse !"; -"LocalNotificationsManager.HighSignal.title" = "Puissance du signal trop importante !"; -"LocalNotificationsManager.LowSignal.title" = "Puissance du signal trop faible !"; -"LocalNotificationsManager.HighTemperature.title" = "Température trop haute !"; -"LocalNotificationsManager.LowTemperature.title" = "Température trop basse !"; -"TagSettings.Alerts.Off" = "Désactivé"; -"TagSettings.Alerts.Temperature.description" = "Notifier si la valeur est inférieure à %.0f ou supérieure à %.0f"; -"TagSettings.Label.alerts.text" = "Notifications"; -"TagSettings.backgroundImageLabel.text" = "Fond d'écran"; -"TagSettings.batteryVoltageTitleLabel.text" = "Tension de la pile"; -"HumidityCalibration.Button.Calibrate.title" = "Calibrer"; -"HumidityCalibration.lastCalibrationDate.format" = "Calibré : %@"; -"HumidityCalibration.Description.text" = "Nous recommandons le calibrage avec une solution saline pour de meilleurs résultats. Tutoriel vidéo."; -"HumidityCalibration.Label.note.text" = "Le calibrage s'effectue sur la mémoire de votre appareil. Vous devrez répeter l'opération si vous supprimez/installez à nouveau l'application."; -"HumidityCalibration.VideoTutorials.link" = "Tutoriel vidéo."; -"Cancel" = "Annuler"; -"HumidityCalibration.Button.Clear.title" = "Effacer"; -"TagCharts.DeleteHistoryConfirmationDialog.message" = "Supprimer l'historique de l'application ?"; -"HumidityCalibration.Button.Close.title" = "Fermer"; -"TagCharts.Status.Serving" = "Synchronisation..."; -"TagCharts.Status.Connecting" = "Connexion..."; -"TagSettings.ConnectStatus.Disconnected" = "Déconnecté"; -"TagCharts.Export.title" = "EXPORTER"; -"h" = "h"; -"About.AboutHelp.contents" = "Ruuvi Station est une application facile à utiliser qui vous permet de surveiller les données de mesure des capteurs Ruuvi."; -"About.AboutHelp.header" = "Infos / Aide"; -"About.TagsCount.text" = "Capteurs jumelés : %d"; -"About.MeasurementsCount.text" = "Données enregistrées : %d"; -"About.DatabaseSize.text" = "Taille de la base de données : %@"; -"About.More.contents" = "Site officiel de Ruuvi : ruuvi.com\nRuuvi Forum : f.ruuvi.com\nRuuvi Blog : ruuvi.com/blog\nRuuvi Twitter : twitter.com/ruuvicom"; -"About.More.header" = "Plus d'infos"; -"About.OpenSource.contents" = "Tout comme les capteurs Ruuvi, les applications Ruuvi Station sont open source. Suivez le développement et contribuez sur : github.com/ruuvi"; -"About.OpenSource.header" = "Open-source"; -"About.OperationsManual.contents" = "Commencez à utiliser l'application mobile Ruuvi Station avec nos guides en ligne : ruuvi.com/support/station-mobile"; -"About.OperationsManual.header" = "Notice d'utilisation"; -"About.Privacy.contents" = "L'utilisation de l'application nécessite l'approbation des conditions générales de Ruuvi : ruuvi.com/terms"; -"About.Privacy.header" = "Protection des données personnelles"; -"About.Troubleshooting.contents" = "Trouvez de l'aide en utilisant les applications Ruuvi Station, les produits Ruuvi et le service Ruuvi Cloud depuis notre centre d'assistance : ruuvi.com/support"; -"About.Troubleshooting.header" = "Dépannage technique"; -"hours" = "Heures"; -"Interval.Days.string" = "Jours"; -"TagSettings.AirHumidityAlert.title" = "Humidité de l'air (%@)"; -"HumidityUnit.gm3.title" = "Absolue (g/m³)"; -"g/m³" = "g/m³"; -"HumidityUnit.Percent.title" = "Relative (%)"; -"TagSettings.Mac.Alert.title" = "Adresse MAC"; -"Menu.Label.AboutHelp.text" = "Infos/Aide"; -"Menu.Label.AddAnNewSensor.text" = "Ajouter un capteur"; -"Menu.Label.AppSettings.text" = "Réglages"; -"Menu.Label.GetMoreSensors.text" = "Acheter des capteurs"; -"Ruuvi.BuySensors.URL.IOS" = "https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Ruuvi.BuySensors.Menu.URL.IOS" = "https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios"; -"Menu.Label.BuyRuuviGateway.text" = "Acheter le routeur Ruuvi Gateway"; -"Menu.BuyGateway.URL.IOS" = "https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Menu.Label.WhatToMeasure.text" = "Que mesurer avec Ruuvi?"; -"Menu.Measure.URL.IOS" = "https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Menu.Label.Feedback.text" = "Donnez-nous votre avis!"; -"Menu.Label.MyRuuviAccount.text" = "Mon compte Ruuvi"; -"min" = "min"; -"minutes" = "Minutes"; -"TagSettings.Label.moreInfo.text" = "Plus d'infos"; -"TagSettings.SectionHeader.Name.title" = "NOM"; -"No" = "Non"; -"OK" = "OK"; -"Cards.NoSensors.title" = "Pas de capteurs\nAjoutez-en en cliquant ici"; -"TagSettings.PressureAlert.title" = "Pression de l'air (%@)"; -"UnitPressure.hectopascal.title" = "Hectopascal (hPa)"; -"hPa" = "hPa"; -"UnitPressure.inchOfMercury.title" = "Pouce de mercure (inHg)"; -"UnitPressure.millimetreOfMercury.title" = "Millimètre de mercure (mmHg)"; -"TagCharts.Status.ReadingHistory" = "Analyse de l'historique"; -"TagSettings.rssiTitleLabel.text" = "Puissance du signal (RSSI)"; -"signal_strength_dbm" = "Puissance du signal (dBm)"; -"s" = "s"; -"Welcome.scan.title" = "BALAYAGE EN COURS"; -"Background.Interval.Sec.string" = "sec"; -"Settings.navigationItem.title" = "Réglages"; -"Settings.BackgroundScanning.title" = "Réglages du balayage en arrière-plan"; -"Settings.BackgroundScanning.Footer.message" = "Remarque importante : L'enregistrement de l'historique et les alertes Bluetooth ne fonctionnent que lorsque le balayage en arrière-plan est activé. Si vous désactivez l'analyse en arrière-plan, tous les capteurs Ruuvi appariés seront automatiquement désappariés et vous devrez les appairer à nouveau à partir de leurs pages de paramètres."; -"Settings.BackgroundScanning.interval" = "Intervalle d'acquisition des données"; -"Settings.Label.Chart" = "Paramètres de l'histogramme"; -"ChartSettings.AllPoints.title" = "Afficher toutes les mesures"; -"ChartSettings.AllPoints.description" = "L'utilisation de cette fonction peut ralentir la mise à jour de l'histogramme."; -"ChartSettings.DrawDots.title" = "Afficher les points de données"; -"ChartSettings.DrawDots.description" = "L'affichage des points facilite l'analyse de l'histogramme."; -"Defaults.ChartIntervalSeconds.title" = "Précision de l'histogramme"; -"ChartSettings.Duration.title" = "Période de l'histogramme"; -"ChartSettings.Duration.description" = "Définir la période de l'histogramme 1 - 10 jours"; -"Settings.Label.HumidityUnit.text" = "Unité d'humidité"; -"Settings.Label.Temperature" = "Température"; -"Settings.Label.Humidity" = "Humidité"; -"Settings.Label.Pressure" = "Pression"; -"Settings.ChooseHumidityUnit.text" = "Choisissez l'unité souhaitée pour l'humidité."; -"Settings.Label.PressureUnit.text" = "Unité de pression"; -"Settings.ChoosePressureUnit.text" = "Choisissez l'unité souhaitée pour la pression."; -"Settings.Label.TemperatureUnit.text" = "Unité de température"; -"Settings.ChooseTemperatureUnit.text" = "Choisissez l'unité souhaitée pour la température."; -"dBm" = "dBm"; -"TagCharts.Sync.title" = "Synchroniser"; -"TagCharts.SyncConfirmationDialog.message" = "Souhaitez vous importer les données du capteur ?"; -"WebTagSettings.Label.TagName.text" = "Nom du capteur"; -"TagSettings.confirmTagRemovalDialog.title" = "Supprimer le capteur"; -"TagSettings.confirmTagRemovalDialog.message" = "Êtes-vous certain de vouloir supprimer ce capteur ?"; -"TagSettings.temperatureAlertTitleLabel.text" = "Température (%@)"; -"TemperatureUnit.Celsius.title" = "Celsius (℃)"; -"ºC" = "°C"; -"TemperatureUnit.Fahrenheit.title" = "Fahrenheit (℉)"; -"ºF" = "°F"; -"TemperatureUnit.Kelvin.title" = "Kelvin (K)"; -"Updated" = "Mis à jour il y'a"; -"V" = "V"; -"RuuviOnboard.Welcome.title" = "Découvrez l'application Ruuvi Station."; -"RuuviOnboard.Measure.title" = "Mesurer votre environnement : température, humidité, et pression de l'air."; -"RuuviOnboard.Access.title" = "Vérifier les données en temps réels ou consultez les histogrammes."; -"RuuviOnboard.Alerts.title" = "Définir des alarmes et des notifications comme vous le souhaitez."; -"RuuviOnboard.Cloud.title" = "Connectez-vous pour utiliser tout le potentiel de l'application."; -"RuuviOnboard.Cloud.subtitle" = "Réclamez la propriété de vos capteurs avec un compte Ruuvi Cloud gratuit."; -"RuuviOnboard.Cloud.subtitle.signed" = "Super ! Vous vous êtes déjà connecté !"; -"RuuviOnboard.Start.title" = "Afficher les capteurs à proximité en appuyant sur BALAYAGE."; -"Yes" = "Oui"; -"LocalNotificationsManager.Mute.button" = "Désactiver les notifications pendant une heure"; -"Defaults.AlertsMuteInterval.title" = "Espacement entre deux alarmes"; -"SignIn.Title.text" = "Connexion"; -"Menu.SignOut.text" = "Déconnexion"; -"RuuviOnboard.Cloud.Benefits.message" = "Avantages :\n\n ● Les noms, fonds d'écrans, les réglages de calibration, ainsi que les alertes sont enregistrés de façon sécurisée dans notre cloud\n\n ● Consultez les données à distance depuis n'importe quel navigateur (routeur Ruuvi Gateway requis)\n\n ● Partager les capteurs avec votre famille ou des amis (routeur Ruuvi Gateway requis)\n\n ● consultez jusqu'à deux ans d'historique de vos données sur le site station.ruuvi.com (routeur Ruuvi Gateway requis)"; -"RuuviOnboard.Cloud.Details.title" = "Détails"; -"ruuvi_cloud" = "Ruuvi Cloud"; -"RuuviOnboard.Cloud.Skip.title" = "Êtes-vous sûr de vouloir ignorer l'ouverture de session ?"; -"RuuviOnboard.Cloud.Skip.Yes.title" = "Oui, passez."; -"RuuviOnboard.Cloud.Skip.GoBack.title" = "Retourner"; -"SignIn.EmailPlaceholder" = "Email"; -"SignIn.RequestCode" = "Obtenir un code"; -"SignIn.SubmitCode" = "Envoyer"; -"SignIn.EmailSent" = "Email envoyé"; -"SignIn.CheckMailbox" = "Nous avons envoyé un mot de passe à usage unique à votre adresse e-mail %@. Connectez-vous en le saisissant ici:"; -"SignIn.CodeHint" = "Code"; -"TagsManagerPresenter.SignOutConfirmAlert.Message" = "Les capteurs dont vous êtes propriétaire seront suspprimés de l'application lorsque vous vous déconnectez de votre compte Ruuvi. Les données seront importées du cloud lorsque vous vous connectez à nouveau.\n\nSouhaitez vous vous déconnecter ?"; -"TagSettings.ClaimTagButton.Claim" = "Confirmer l'appropriation"; -"TagSettings.ShareButton" = "Partager"; -"Syncing..." = "Synchronisation..."; -"Synchronized" = "Synchronisé"; -"TagChartsPresenter.NumberOfPointsSynchronizedOverNetwork" = "Synchronisé : %@"; -"MenuTableViewController.None" = "non connecté"; -"MenuTableViewController.User" = "Utilisateur : %@"; -"ShareViewController.Title" = "Partager le capteur"; -"ShareViewController.Description" = "Vous pouvez partager ce capteur à des amis ou à des membres de votre famille si le capteur est à portée du routeur Ruuvi Gateway.\n\nL'utilisateur recevra une notification par mail. Le compte Ruuvi est créé en utilisant une adresse mailf si l'utilisateur n'en possède pas encore.\n\Le nom du capteur ainsi que le fond d'écran sont partgés seulement une fois. Si la fonction calibrage est utilisée, les utilisateurs verront seulement la valeur finale une fois ajustée."; -"ShareViewController.addFriend.Title" = "Ajouter un ami"; -"ShareViewController.emailTextField.placeholder" = "Adresse mail"; -"ShareViewController.sharedEmails.Title" = "Vous avez utilisé %d/%d du nombre maximum de divisions pour ce capteur. Le capteur est partagé avec les utilisateurs suivants :"; -"Share.Send.button" = "Envoyer"; -"SharePresenter.UnshareSensor.Message" = "Voulez-vous arrêter le partage du capteur avec %@ ?"; -"TagSettings.SectionHeader.NetworkInfo.title" = "RÉSEAU"; -"TagSettings.NetworkInfo.Owner" = "Propriétaire"; -"Menu.RuuviNetworkStatus.text" = "Statut du Ruuvi cloud"; -"SignIn.TitleLabel.text" = "Connexion \nRuuvi\nStation"; -"SignIn.SubtitleLabel.text" = "Profitez de tous les avantages de Ruuvi Station! Connectez-vous ou créez votre compte en entrant votre adresse mail."; -"SignIn.VerificationCodePlaceholder" = "verification du code au format CJSM"; -"UserApiError.ER_FORBIDDEN" = "Interdit"; -"UserApiError.ER_UNAUTHORIZED" = "Non permis"; -"UserApiError.ER_INTERNAL" = "Erreur interne"; -"UserApiError.ER_INVALID_FORMAT" = "Format incorrect"; -"UserApiError.ER_USER_NOT_FOUND" = "Utilisateur introuvable"; -"UserApiError.ER_SENSOR_NOT_FOUND" = "Capteur introuvable"; -"UserApiError.ER_TOKEN_EXPIRED" = "Le code est perimé"; -"UserApiError.ER_SUBSCRIPTION_NOT_FOUND" = "L'abonnement est introuvable"; -"UserApiError.ER_SHARE_COUNT_REACHED" = "Le nombre de partages maximum est atteint"; -"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Vous ne pouvez pas partager le capteur à d'avantage d'utilisateurs"; -"UserApiError.ER_NO_DATA_TO_SHARE" = "Pour partager le capteur, ce dernier doit être à portée du routeur Ruuvi Gateway"; -"UserApiError.ER_SENSOR_ALREADY_SHARED" = "Ce capteur est déjà partagé"; -"UserApiError.ER_SENSOR_ALREADY_CLAIMED" = "Capteur déjà revendiqué par %@"; -"UserApiError.ER_SENSOR_ALREADY_CLAIMED_NO_EMAIL" = "Capteur déjà revendiqué"; -"UserApiError.ER_UNABLE_TO_SEND_EMAIL" = "Impossible d'envoyer l'email"; -"UserApiError.ER_MISSING_ARGUMENT" = "Argument manquant"; -"UserApiError.ER_INVALID_DENSITY_MODE" = "Mode de densité invalide"; -"UserApiError.ER_INVALID_SORT_MODE" = "Mode de tri invalide"; -"UserApiError.ER_INVALID_TIME_RANGE" = "Intervalle invalide"; -"UserApiError.ER_INVALID_EMAIL_ADDRESS" = "Adresse email invalide"; -"UserApiError.ER_INVALID_MAC_ADDRESS" = "Adresse MAC invalide"; -"UserApiError.ER_SUB_DATA_STORAGE_ERROR" = "Erreur d'enregistrement"; -"UserApiError.ER_SUB_NO_USER" = "Pas d'utilisateur"; -"UserApiError.ER_THROTTLED" = "Trop de demandes simultanées"; -"OffsetCorrection.CalibrationDescription.text" = "En utilisation normale, il n'est pas nécessaire de calibrer le capteur.\n\nSi vous souhaitez tout de même calibrer calibrer le capteur \n\n les instructions sont trouvables ici ruuvi.com/support"; -"OffsetCorrection.Dialog.Calibration.ClearConfirm" = "Supprimer la calibration ?"; -"OffsetCorrection.Dialog.Calibration.Title" = "Calibration"; -"OffsetCorrection.Dialog.Calibration.EnterTemperature" = "Entrez la température attendue dans ces conditions (%@):"; -"OffsetCorrection.Dialog.Calibration.EnterPressure" = "Entrez la pression attendue dans ces conditions (%@):"; -"OffsetCorrection.Dialog.Calibration.EnterHumidity" = "Entrez l'humidité attendue dans ces conditions (%@):"; -"OffsetCorrection.OriginalValue.title" = "Valeur originale"; -"OffsetCorrection.CorrectedValue.title" = "Valeur corrigée"; -"OffsetCorrection.Temperature.Title" = "Correction de température"; -"OffsetCorrection.Humidity.Title" = "Correction d'humidité"; -"OffsetCorrection.Pressure.Title" = "Correction de pression"; -"OffsetCorrection.Calibrate.button" = "Correction"; -"TagSettings.SectionHeader.OffsetCorrection.Title" = "CORRECTION"; -"TagSettings.OffsetCorrection.Temperature" = "Température"; -"TagSettings.OffsetCorrection.Humidity" = "Humidité"; -"TagSettings.OffsetCorrection.Pressure" = "Pression"; -"PhotoPicker.Sheet.files" = "Choisir parmis les fichiers"; -"SignIn.EnterVerificationCode" = "Entrez le code de vérification"; -"UnexpectedError.failedToFindOrGenerateBackgroundImage" = "Echec de la mise à jour du fond d'écran"; -"UnexpectedError.bothLuidAndMacAreNil" = "Les identifiants MAC et local sont introuvables"; -"RuuviCloudApiError.emptyResponse" = "Réponse nulle"; -"RuuviCloudApiError.failedToGetDataFromResponse" = "La réponse ne contient pas de données"; -"RuuviCloudApiError.unexpectedHTTPStatusCode" = "Code HTTP innatendu"; -"RuuviCloudError.NotAuthorized" = "Non authorisé"; -"RuuviLocalError.failedToGetJpegRepresentation" = "Echec de la représentation JPG"; -"RuuviLocalError.failedToGetDocumentsDirectory" = "Répertoire d'arrière-plan introuvable"; -"RuuviPersistenceError.failedToFindRuuviTag" = "Echec de jumelage"; -"RuuviServiceError.pictureUrlIsNil" = "URL de la photo manquant"; -"RuuviServiceError.macIdIsNil" = "adresse MAC manquante"; -"network_sharing_disabled" = "Vous pouvez partager seulement des capteurs à proximité du Ruuvi Gateway."; -"RuuviServiceError.bothLuidAndMacAreNil" = "Identifiants MAC et local manquant"; -"RuuviServiceError.failedToParseNetworkResponse" = "Echec de l'enregistrement de la réponse"; -"RuuviServiceError.failedToFindOrGenerateBackgroundImage" = "Fond d'écran introuvable"; -"RuuviServiceError.failedToGetJpegRepresentation" = "Echec de la représentation JPG"; -"UpdateFirmware.Title.text" = "Mettre à jour le programme"; -"UpdateFirmware.Download.header" = "TÉLÉCHARGER LA DÉRNIÈRE VERSION"; -"UpdateFirmware.Download.content" = "Pour commencer la mise à jour, télécharger la dérnière version sur l'appareil que vous utiliserez pour mettre à jour le capteur. Fichier disponible sur ruuvi.com/software-update"; -"UpdateFirmware.SetDfu.header" = "METTRE LE CAPTEUR EN MODE DFU"; -"UpdateFirmware.SetDfu.content" = "Ouvrez le boitier du capteur, aidez-vous d'un tournevis plat si besoin.\n\nAppuyez sur le bouton B pendant quelques secondespuis sur le bouton R en gradant le bouton B enfoncé. La LED rouge doit s'allumer lorsqu'il est en mode bootloader. S'il n'y a qu'un bouton appuyez dessus pendant 10 secondes."; -"UpdateFirmware.NextButton.title" = "SUIVANT"; -"DfuDevicesScanner.Title.text" = "Appareils"; -"DfuDevicesScanner.Description.text" = "Chercher et choisir un capteur \"RuuviBoot\"."; -"DfuDevicesScanner.NoDevice.text" = "(Pas de capteurs à portée du Bluetooth)"; -"DfuDevicesScanner.BluetoothDisabled.text" = "(Bluetooth désactivé)"; -"DfuDevicesScanner.BluetoothDisabledAlert.title" = "Bluetooth désactivé"; -"DfuDevicesScanner.BluetoothDisabledAlert.message" = "Ruuvi Station a besoin du Bluetooth pour fonctionner. Activez-le dans les paramètres de votre appareil."; -"DfuFlash.Title.text" = "Mise à jour DFU"; -"DfuFlash.Progress.text" = "Avancement"; -"DfuFlash.Step.text" = "Étape"; -"DfuFlash.Steps.PackageSelection.text" = "Choisir le fichier de mise à jour"; -"DfuFlash.Steps.ReadyForUpload.text" = "Prêt pour la mise à jour"; -"DfuFlash.Steps.Uploading.text" = "Chargement"; -"DfuFlash.Steps.Completed.text" = "Prêt"; -"DfuFlash.OpenDocumentPicker.title" = "OUVRIR LE GESTIONNAIRE DE FICHIERS"; -"DfuFlash.FirmwareSelectionGuide.text" = "Chercher le fichier ZIP."; -"DfuFlash.Firmware.FileName.text" = "Nom du fichier"; -"DfuFlash.Firmware.Parts.text" = "Parties"; -"DfuFlash.Firmware.Size.text" = "Taille"; -"DfuFlash.Firmware.SoftDeviceSize.text" = "Soft Device taille"; -"DfuFlash.Firmware.BootloaderSize.text" = "Taille du bootloader"; -"DfuFlash.Cancel.text" = "ANNULER"; -"DfuFlash.Start.text" = "Commencer"; -"DfuFlash.Finish.text" = "PRÊT"; -"DfuFlash.FinishGuide.text" = "Mise à jour réussie. -RuuviTag est prêt à être utilisé !"; -"DfuFlash.CancelAlert.text" = "Voulez-vous annuler la mise à jour ?"; -"RuuviDfuError.invalidFirmwareFile" = "Fichier de mise à jour invalide"; -"DFUUIView.navigationTitle" = "Mise à jour du firmware"; -"DFUUIView.latestTitle" = "Dernière version du Ruuvi Firmware :"; -"DFUUIView.currentTitle" = "Version actuelle :"; -"DFUUIView.notReportingDescription" = "Impossible d'obtenir la version actuelle de l'appareil. La version est probablement trop ancienne et il est recommandé d'effectuer une mise à jour."; -"DFUUIView.alreadyOnLatest" = "L'appareil est à déjà à jour"; -"DFUUIView.startUpdateProcess" = "Début de la mise à jour"; -"DFUUIView.downloadingTitle" = "Téléchargement de la dernière version pour la mise à jour..."; -"DFUUIView.prepareTitle" = "Préparez votre capteur"; -"DFUUIView.openCoverTitle" = "1. Ouvrez le couvercle de votre capteur Ruuvi"; -"DFUUIView.locateBootButtonTitle" = "2. Localisez les petits boutons ronds noirs sur la carte de circuit imprimé blanche ; les anciens capteurs Ruuvi ont 2 boutons étiquetés \"R\" et \"B\" tandis que les plus récents n'ont qu'un seul bouton sans étiquette."; -"DFUUIView.setUpdatingModeTitle" = "3. Mettez le capteur en mode de mise à jour :"; -"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. Si votre capteur est équipé de 2 boutons : maintenez le bouton \"B\" enfoncé tout en appuyant momentanément sur le bouton \"R\". Relâchez le bouton \"B\"."; -"DFUUIView.toBootModeOneButtonDescription" = "3.2. Si votre capteur possède un seul bouton : maintenez le bouton enfoncé pendant 10 secondes."; -"DFUUIView.toBootModeSuccessTitle" = "4. Si le réglage est réussi, vous verrez une lumière rouge fixe s'allumer sur la carte de circuit imprimé et le bouton de l'application passera à \"Démarrer la mise à jour\"."; -"DFUUIView.updatingTitle" = "Mise à jour..."; -"DFUUIView.searchingTitle" = "Recherche d'un capteur"; -"DFUUIView.startTitle" = "Lancer la mise à jour"; -"DFUUIView.doNotCloseTitle" = "Ne pas fermer l'application ou enlever la pile du capteur pendant la mise à jour."; -"DFUUIView.successfulTitle" = "Mise à jour réussie"; -"DFUUIView.DBMigration.Error.message" = "La mise à jour a réussi, mais une erreur inattendue de migration de la base de données s'est produite. Pour continuer à utiliser ce capteur, veuillez le supprimer de l'application, puis le rajouter à nouveau."; -"RuuviDfuError.failedToConstructUUID" = "Echec de la création de l'UUID"; -"SignIn.EmailMismatch.Alert.message" = "Oups, vous avez demandé le code de connexion pour l'utilisateur %@ alors qu'il est destiné à l'utilisateur %@. Veuillez vérifier que vous utilisez bien le code pour %@"; -"SignIn.EmailMissing.Alert.message" = "Oups, l'adresse mail utilisée n'a pu être enregistrée. Veuillez réessayer."; -"TagSettings.RemoveThisSensor.title" = "Retirer le capteur"; -"Share.Success.message" = "Capteur partagé avec succès"; -"TagSettings.SectionHeader.General.title" = "Général"; -"TagSettings.Shared.title" = "Partagé"; -"TagSettings.NotShared.title" = "Non partagé"; -"Owner.title" = "Confirmer l'appropriation"; -"Owner.ClaimOwnership.button" = "Confirmer l'appropriation"; -"Owner.Claim.description" = "Êtes-vous propriétaire de ce capteur ? En devenant propriétaire, le capteur sera associé à votre compte Ruuvi. Chaque capteur ne peut avoir qu'un seul propriétaire. Pour revendiquer la propriété, vous devez être connecté.\n\nAvantages:\n\n ● Les noms, fonds d'écrans, les réglages de calibration, ainsi que les alertes sont enregistrés de façon sécurisée dans notre cloud\n\n ● Consultez les données à distance depuis n'importe quel navigateur (routeur Ruuvi Gateway requis)\n\n ● Partager les capteurs avec votre famille ou des amis (routeur Ruuvi Gateway requis)\n\n ● consultez jusqu'à deux ans d'historique de vos données sur le site station.ruuvi.com (routeur Ruuvi Gateway requis)"; -"TagSettings.confirmTagUnclaimAndRemoveDialog.message" = "Le propriétaire sera réinitialisé en supprimant le capteur. N'importe qui pourra alors s'approprier le capteur. Chaque capteur Ruuvi ne pouvant avoir qu'un propriétaire."; -"TagSettings.confirmSharedTagRemovalDialog.message" = "En supprimant le capteur vous n'aurez plus accès aux données du capteur et une notification sera envoyée au propriétaire."; -"TagSettings.General.Owner.none" = "Pas de propriétaire"; -"TagSettings.Share.title" = "Partager"; -"Menu.LoggedIn.title" = "Connecté :"; -"Interval.Day.string" = "Jour"; -"hour" = "Heure"; -"TagSettings.tagNameTitleLabel.rename.text" = "Les capteurs sont dans l'ordre alphabétique."; -"On" = "Activé"; -"Off" = "Désactivé"; -"DFUUIView.lowBattery.warning.message" = "La tension de la pile du capteur est faible et risque de faire echouer la mise à jour. Nous vous conseillons de remplacer la batterie avant la mise à jour."; -"alert_notification_humidity_high_threshold" = "L'humidité de l'air est supérieure à %@"; -"alert_notification_humidity_low_threshold" = "L'humidité de l'air est inférieure à %@"; -"alert_notification_pressure_high_threshold" = "La pression de l'air est supérieure à %@"; -"alert_notification_pressure_low_threshold" = "La pression de l'air est inférieure à %@"; -"alert_notification_rssi_high_threshold" = "La puissance du signal est supérieure à %@"; -"alert_notification_rssi_low_threshold" = "La puissance du signal est inférieure à %@"; -"alert_notification_temperature_high_threshold" = "La température est supérieure à %@"; -"alert_notification_temperature_low_threshold" = "La température est inférieure à %@"; -"Cards.Alert.AlreadyLoggedIn.message" = "L'utilisateur %@ est déjà connecté. Si vous souhaitez utiliser un autre compte veuillez vous déconnecter d'abord."; -"Settings.Label.CloudMode" = "Statut du cloud"; -"Settings.Label.CloudMode.description" = "Mettre à jour les capteurs à proximité associés au cloud seulement pour recevoir seulement des alertes par mail en rejetant les messages Bluetooth. Nécessite le routeur Ruuvi Gateway."; -"internet_connection_problem" = "Problème de connexion Internet"; -"Widgets.Loading.message" = "Chargement..."; -"Cards.Movements.title" = "mouvements"; -"TagSettings.BatteryStatusLabel.Replace.message" = "Batterie faible"; -"TagSettings.BatteryStatusLabel.Ok.message" = "Batterie OK"; -"Widgets.Description.message" = "Créez des widgets de vos capteurs Ruuvi préférés. Les widgets sont mis à jour depuis le Ruuvi Cloud. Un routeur Ruuvi Gateway est nécessaire."; -"settings_appearance" = "Apparition"; -"app_theme" = "App Theme"; -"follow_system_theme" = "Thème système"; -"dark_theme" = "Thème sombre"; -"light_theme" = "Thème de la lumière"; -"Settings.Temperature.Resolution.title" = "Résolution de la température"; -"Settings.Humidity.Resolution.title" = "Résolution de l'humidité"; -"Settings.Pressure.Resolution.title" = "Résolution de la pression"; -"Settings.Measurement.Resolution.description" = "Sélectionnez la précision avec laquelle vous souhaitez voir les valeurs de mesure en direct des capteurs dans l'application. Ce paramètre n'affecte pas les graphiques d'historique ni les alertes."; -"Settings.Measurement.Unit.title" = "Unité"; -"Settings.Measurement.Resolution.title" = "Résolution"; -"MyRuuvi.Settings.DeleteAccount.title" = "Supprimer le compte"; -"MyRuuvi.Settings.DeleteAccount.Confirmation.message" = "Une confirmation a été envoyée à votre adresse électronique. Pour procéder à la suppression, veuillez vérifier votre boîte de réception et suivre les instructions."; -"TagSettings.Alert.SetTemperature.title" = "Réglage de l'alerte de température"; -"TagSettings.Alert.SetHumidity.title" = "Réglage de l'alerte d'humidité"; -"TagSettings.Alert.SetPressure.title" = "Régler l'alerte de pression"; -"TagSettings.Alert.SetRSSI.title" = "Définir une alerte sur la puissance du signal"; -"TagSettings.AlertSettings.Dialog.Min" = "Min (%.0f)"; -"TagSettings.AlertSettings.Dialog.Max" = "Max (%.0f)"; -"export_history" = "Exportation de l'historique (csv)"; -"clear_view" = "Vue historique vide"; -"day_1" = "1 jour"; -"day_2" = "2 jours"; -"day_3" = "3 jours"; -"day_4" = "4 jours"; -"day_5" = "5 jours"; -"day_6" = "6 jours"; -"day_7" = "7 jours"; -"day_8" = "8 jours"; -"day_9" = "9 jours"; -"day_10" = "10 jours"; -"day_x" = "%.0f jours"; -"more" = "Plus..."; -"all" = "Tout"; -"longer_history_title" = "Une histoire plus longue"; -"longer_history_message" = "L'application mobile Ruuvi Station prend en charge un maximum de 10 jours d'historique. Les abonnés à Ruuvi Cloud peuvent consulter jusqu'à 2 ans d'historique en utilisant l'application web à ruuvi.com/station (nécessite le routeur Ruuvi Gateway)."; -"reading_history_x" = "Bluetooth sync: %.0f"; -"rssi_alert_description" = "L'utilisation de cette alerte nécessite que vous soyez connecté à l'application, que vous ayez revendiqué la propriété de ce capteur et qu'il se trouve dans le rayon d'action du routeur de la passerelle Ruuvi. Les appareils iOS sont incapables d'indiquer l'intensité du signal des données reçues envoyées par le capteur Ruuvi lorsque le capteur est apparié et que des mesures sont reçues en arrière-plan. La puissance du signal Bluetooth en temps réel est affichée dans l'application mais n'affecte pas cette alerte."; -"bluetooth_download" = "Téléchargement Bluetooth"; -"bluetooth_download_description" = "Les données du capteur local peuvent être téléchargées lorsque vous êtes dans sa portée Bluetooth."; -"download" = "Téléchargement"; -"clear_local_history" = "Effacer l'histoire locale"; -"clear_local_history_description" = "Voulez-vous effacer les données historiques stockées localement dans l'application ? Cela n'effacera pas l'historique stocké en interne par le capteur ou les données historiques stockées sur le service Ruuvi Cloud."; -"TagCharts.FailedToSyncDialog.title" = "Échec du téléchargement"; -"TagCharts.FailedToSyncDialog.message" = "Le téléchargement de l'historique Bluetooth a échoué. Vérifiez que vous êtes à portée Bluetooth, que votre capteur possède un micrologiciel prenant en charge le téléchargement et que le capteur n'est pas simultanément connecté à un autre appareil iOS. La connexion du capteur est réservée à la Ruuvi Station lorsque vous utilisez le mode connecté dans iOS."; -"TagCharts.TryAgain.title" = "Essayez à nouveau"; -"support" = "Soutien"; -"full_image_view" = "Vue d'ensemble de l'image"; -"history_view" = "Vue de l'histoire"; -"settings_and_alerts" = "Paramètres & alertes"; -"change_background" = "Paramètres et alertes"; -"check_claim_state" = "Vérification de l'état de la demande"; -"claim_in_progress" = "Réclamation en cours"; -"force_claim_sensor" = "Revendication en cours"; -"force_claim_sensor_description1" = "Ce capteur a été réclamé par un autre utilisateur. Vous pouvez forcer la propriété à votre compte si vous avez un accès physique à ce capteur. Chaque capteur Ruuvi ne peut avoir qu'un seul propriétaire."; -"force_claim_sensor_description2" = "La réclamation forcée est effectuée en utilisant la communication en champ proche (NFC). Assurez-vous que la NFC est activée sur votre appareil mobile. 1. Touchez le capteur de votre Ruuvi avec votre appareil mobile pour lancer le processus de réclamation. - 2. Une fois la réclamation réussie, vous serez renvoyé aux paramètres du capteur. Si la réclamation n'a pas abouti ou si la technologie NFC n'est pas disponible sur votre appareil : 1. Ouvrez le couvercle de votre capteur Ruuvi. 2. Localisez le bouton rond noir (ou le bouton \"B\" si votre capteur a 2 boutons) sur la carte de circuit imprimé blanche et appuyez dessus brièvement, puis appuyez sur le bouton Utiliser BT pour démarrer le processus de réclamation. - 3. Une fois la réclamation réussie, vous serez renvoyé aux paramètres du capteur."; -"force_claim" = "Revendication de force"; -"claim_wrong_sensor_scanned" = "Vous scannez différents RuuviTag"; -"view" = "Voir"; -"card_type" = "Type de carte"; -"image_cards" = "Cartes-images"; -"simple_cards" = "Cartes simples"; -"card_action" = "Action de la carte"; -"open_sensor_view" = "Ouvrir la vue du capteur"; -"open_history_view" = "Ouvrir la vue de l'historique"; -"change_background_message" = "Sélectionnez l'image d'arrière-plan. Si vous n'êtes pas connecté, vous perdrez l'image en cas de réinstallation de l'application."; -"take_photo" = "Prenez une photo"; -"select_from_gallery" = "Sélectionner dans la galerie du téléphone"; -"select_default_image" = "Choisir parmi les images par défaut"; -"export_csv_feature_location" = "Vous pouvez exporter l'historique d'un capteur à partir de sa page graphique d'historique. Appuyez sur l'icône de menu à trois points dans le coin supérieur droit, puis sélectionnez \"Exporter l'historique (csv)\"."; -"low_battery" = "Batterie faible"; -"change_background_image" = "Modifier l'image de fond"; -"SignIn.Sync.message" = "Téléchargement de contenu depuis le cloud. Veuillez patienter."; -"uploading_progress" = "Chargement: %.0f"; -"Widgets.Unauthorized.Regular.message" = "Connectez-vous pour utiliser le widget.Connectez-vous pour utiliser le widget."; -"Widgets.Unauthorized.Inline.message" = "Connectez-vous à la station Ruuvi"; -"Widgets.Unconfigured.Simple.message" = "Forcer l'appui pour modifier le widget."; -"Widgets.Unconfigured.Rectangular.message" = "Appuyez sur le bouton pour modifier le widget."; -"Widgets.Unconfigured.Inline.message" = "Ajouter un capteur pour utiliser le widget Ruuvi"; -"Widgets.Unconfigured.Circular.message" = "+Ajouter"; -"Widgets.Select.Sensor.title" = "Capteur Ruuvi sélectionné"; -"Widgets.Sensor.Type.title" = "Type de capteur sélectionné"; -"Settings.SectionHeader.General.title" = "GÉNÉRAL"; -"Settings.SectionHeader.Application.title" = "APPLICATION"; -"empty_chart_message" = "Aucune donnée disponible dans la fenêtre d'historique sélectionnée."; -"onboarding_measure_your_world" = "Measure Your World"; -"onboarding_with_ruuvi_sensors" = "Apprenez à connaître votre application Ruuvi Station."; -"onboarding_swipe_to_continue" = "Balayez pour continuer →"; -"onboarding_read_sensors_data" = "Lisez vos capteurs Ruuvi"; -"onboarding_via_bluetooth_or_cloud" = "en utilisant Bluetooth ou Ruuvi Cloud"; -"onboarding_follow_measurement" = "Visualisez tous les capteurs en un coup d'œil sur votre"; -"onboarding_dashboard" = "tableau de bord"; -"onboarding_personalise" = "Personnalisez"; -"onboarding_your_sensors" = "votre application avec des noms et des arrière-plans personnalisés."; -"onboarding_explore_detailed" = "Explorez votre"; -"onboarding_history" = "historique de mesure"; -"onboarding_set_custom" = "Définissez et personnalisez vos"; -"onboarding_alerts" = "alertes"; -"onboarding_share_your_sensors" = "à mesurer avec vos amis et votre famille."; -"onboarding_sharees_can_use" = "Partagez des capteurs"; -"onboarding_handy_widgets" = "de widgets"; -"onboarding_access_widgets" = "Apportez vos capteurs préférés sur votre écran d'accueil et votre écran de verrouillage sous forme"; -"onboarding_station_web" = "l'application Web Ruuvi"; -"onboarding_web_pros" = "Grand tableau de bord, historique pluriannuel, alertes par e-mail et plus encore sur"; -"onboarding_gateway_required" = "Un routeur Ruuvi Gateway est requis."; -"onboarding_skip" = "Ignorer"; -"onboarding_thats_it" = "Presque là!"; -"onboarding_thats_it_already_signed_in" = "Commençons!"; -"onboarding_go_to_sign_in" = "L'expérience Ruuvi est meilleure lorsque vous êtes connecté. Faites-le maintenant ou continuez sans les fonctionnalités cloud."; -"onboarding_go_to_sign_in_already_signed_in" = "Commençons à mesurer !"; -"onboarding_continue" = "Suivant"; -"sign_in_or_create_free_account" = "Connectez-vous ou créez un compte Ruuvi gratuit"; -"to_use_all_app_features" = "Aucun mot de passe nécessaire."; -"type_your_email" = "Tapez votre e-mail..."; -"request_code" = "Demander un code"; -"no_password_needed" = "Un compte gratuit sera créé pour cet e-mail si vous n'en avez pas déjà un. Seule l'adresse e-mail est requise. Nous gardons vos informations en toute sécurité."; -"benefits_sign_in" = "En savoir plus sur les avantages du compte Ruuvi ou connectez-vous plus tard"; -"use_without_account" = "Non merci, ignorer"; -"why_should_sign_in" = "Bénéfices"; -"sensors_ownership_and_settings_stored_in_cloud" = "La connexion à l'application présente de nombreux avantages. Les paramètres seront stockés en toute sécurité sur votre compte:"; -"cloud_stored_ownerships" = "● Propriété des capteurs"; -"cloud_stored_names" = "● Noms des capteurs"; -"cloud_stored_alerts" = "● Images d'arrière-plan"; -"cloud_stored_backgrounds" = "● Paramètres d'alerte"; -"cloud_stored_calibration" = "● Paramètres d'étalonnage"; -"cloud_stored_sharing" = "● Paramètres de l'application"; -"note" = "Note!"; -"claim_warning" = "Sécurisez les informations de propriété de vos capteurs en revendiquant leurs propriétés dans l'application."; -"lets_do_it" = "Connectez-vous"; -"enter_code" = "Entrez le code"; -"dashboard_no_sensors_message" = "Il semble que vous n'ayez pas encore ajouté de capteurs Ruuvi."; -"dashboard_no_sensors_message_signed_out" = "Vous n'êtes pas connecté.\n\nSi vous avez un compte et que vous y avez déjà ajouté des capteurs Ruuvi, ils se synchroniseront automatiquement avec l'application mobile Ruuvi Station lorsque vous vous connecterez."; -"add_a_sensor" = "Ajouter un capteur"; -"changelog" = "(journal des modifications)"; -"changelog_ios_url" = "https://f.ruuvi.com/t/3192"; -"chart_stat_min" = "Min"; -"chart_stat_max" = "Max"; -"chart_stat_avg" = "Moyenne"; -"shared_to_x" = "Partagé %d/%d"; -"settings_alert_notifications" = "Notifications d'alerte"; -"settings_alert_sound" = "Son d'alerte"; -"settings_alert_sound_description" = "Sélectionnez le son de notification push."; -"settings_alerts_footer_description" = "Vous pouvez également ajuster les paramètres de notification sous Paramètres iOS -> Notifications"; -"settings_alerts_footer_description_link_mask" = "Paramètres iOS -> Notifications"; -"settings_email_alerts" = "Alertes courrier électronique"; -"settings_email_alerts_description" = "Si vous utilisez Ruuvi Cloud et Ruuvi Gateway, vous pourrez recevoir des alertes par e-mail en activant ceci."; -"settings_push_alerts" = "Alertes push"; -"settings_push_alerts_description" = "Si vous utilisez Ruuvi Cloud et Ruuvi Gateway, vous pourrez recevoir des alertes push en activant ceci."; -"synchronisation" = "Synchronisation"; -"gatt_sync_description" = "Ruuvi Station télécharge l'historique interne du capteur pour les 10 derniers jours si l'historique des mesures est disponible.\n\nL'historique est téléchargé à l'aide d'une connexion Bluetooth. Assurez-vous d'être à proximité du capteur."; -"do_not_show_again" = "Ne plus afficher ça"; -"sign_in_continue" = "Continuer"; -"signing_in_is_optional" = "(La connexion est facultative)"; -"Defaults.UserAuthorized.title" = "Utilisateur autorisé"; -"Defaults.DashboardTapActionChart.title" = "Appuyez sur la carte du tableau de bord pour afficher le graphique"; -"Defaults.DevServer.title" = "Utiliser le serveur de développement"; -"Defaults.DevServer.message" = "La modification du point de terminaison Ruuvi Cloud nécessite de se déconnecter de la session en cours et de redémarrer l'application. Es-tu sûr?"; -"Defaults.ShowEmailAlertsSettings.title" = "Afficher les paramètres d'alertes par e-mail"; -"Defaults.ShowPushAlertsSettings.title" = "Afficher les paramètres des alertes push"; -"use_nfc" = "Utiliser NFC"; -"use_bluetooth" = "Utiliser BT"; -"sensor_not_found_error" = "Capteur introuvable. Essayer à nouveau."; -"Defaults.HideNFC.title" = "Masquer l'option NFC du changement de propriété forcé"; -"settings_alert_sound_default" = "Défaillance du système"; -"settings_alert_sound_ruuvi_speak" = "Ruuvi alarme"; -"add_with_nfc" = "Ajouter avec NFC"; -"sensor_details" = "Détails du capteur"; -"add_sensor" = "Ajouter un capteur"; -"copy_mac_address" = "Copier l'adresse MAC"; -"copy_unique_id" = "Copier l'identifiant unique"; -"name" = "Nom:"; -"mac_address" = "Adresse Mac:"; -"go_to_sensor" = "Aller à la carte du capteur"; -"unique_id" = "Identifiant unique:"; -"firmware_version" = "Version du firmware:"; -"Close" = "Fermer"; -"add_sensor_nfc_df3_error" = "Ce capteur ne peut pas être ajouté avec NFC en raison d'un ancien firmware. Veuillez ajouter le capteur avec Bluetooth et mettre à jour le firmware."; -"add_sensor_description" = "Cette page montre les capteurs Ruuvi à proximité qui n'ont pas encore été ajoutés à l'application. Appuyez sur un capteur pour l'ajouter."; -"add_sensor_via_nfc" = "Vous pouvez également ajouter un capteur via NFC en sélectionnant Ajouter avec NFC et en le touchant avec votre téléphone."; -"unclaim_sensor" = "Annuler la revendication du capteur"; -"unclaim" = "Annuler la réclamation"; -"unclaim_sensor_description" = "La propriété de ce capteur a été revendiquée sur votre compte Ruuvi. Appuyez sur Annuler la revendication pour supprimer les paramètres de ce capteur et les données associées de votre compte Ruuvi."; -"claim_sensor_ownership" = "Revendiquer la propriété du capteur"; -"do_you_own_sensor" = "Possédez-vous ce capteur ?"; -"owners_plan" = "Plan Ruuvi du propriétaire"; -"alert_cloud_connection_title" = "Connexion infonuagique"; -"alert_cloud_connection_description" = "Alerte si les données du capteur n'ont pas été mises à jour dans le cloud depuis plus de %d minutes."; -"alert_cloud_connection_dialog_description" = "Entrez le délai souhaité à utiliser en minutes avant le déclenchement de l'alerte. La valeur minimale est de 2 minutes."; -"alert_cloud_connection_dialog_title" = "Définir une alerte de connexion au cloud"; -"rename" = "Renommer"; -"chart_stat_show" = "Afficher min/max/moy"; -"chart_stat_hide" = "Masquer min/max/moy"; -"settings_alert_limit_notification" = "Limiter les notifications d'alerte"; -"settings_alert_limit_notification_description" = "Déclenchez la notification d'alerte Bluetooth une seule fois par heure, même si l'alerte a été redéclenchée."; -"share_pending" = "Partage en attente"; -"share_pending_message" = "Partagé avec succès ! Cette adresse e-mail n'est pas encore liée à un compte Ruuvi. Une invitation pour créer un compte gratuit a été envoyée. Une fois créé, vous le verrez dans la liste des partages."; -"dialog_are_you_sure" = "Êtes-vous sûr ?"; -"dialog_operation_undone" = "Cette opération ne peut pas être annulée."; -"remove_cloud_history_title" = "Supprimer l'historique cloud"; -"remove_cloud_history_description" = "Je veux également supprimer les données d'historique du capteur de Ruuvi Cloud."; -"remove_claimed_sensor_description" = "En supprimant le capteur, votre statut de propriétaire du capteur sera révoqué, et les paramètres du capteur, tels que le nom, l'image d'arrière-plan, les paramètres de calibration et les paramètres d'alerte, seront supprimés. Après la suppression, quelqu'un d'autre peut revendiquer la propriété du capteur. Chaque capteur Ruuvi ne peut avoir qu'un seul propriétaire."; -"remove_shared_sensor_description" = "Si vous choisissez de supprimer ce capteur partagé, le propriétaire du capteur sera averti et vous ne pourrez plus accéder au capteur.\n\nVous perdrez également tous les paramètres du capteur associés, tels que le nom, l'image d'arrière-plan et les configurations d'alerte. ."; -"remove_local_sensor_description" = "Si vous choisissez de supprimer ce capteur, cela entraînera la suppression de votre historique de mesures stocké localement, ainsi que la suppression de tous les paramètres du capteur associés tels que le nom, l'image d'arrière-plan, l'étalonnage et les configurations d'alerte.\n\nVous pouvez ajouter ce capteur plus tard, si nécessaire."; -"activity_saving_to_cloud" = "Enregistrement dans le cloud... veuillez patienter."; -"activity_saving_success" = "Enregistré avec succès."; -"activity_saving_fail" = "Impossible d'enregistrer les modifications dans le cloud."; -"activity_ongoing_generic" = "S'il vous plaît, attendez..."; -"activity_success_generic" = "Opération réussie."; -"activity_failed_generic" = "L'opération a échoué."; -"Devices.tokenId" = "Token Id"; -"UserApiError.ER_GATEWAY_NOT_FOUND" = "Gateway not found"; -"UserApiError.ER_GATEWAY_ALREADY_WHITELISTED" = "Gateway already whitelisted"; -"UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED" = "Gateway status report failed"; -"UserApiError.ER_CONFLICT" = "Data already exists, cannot update"; -"UserApiError.ER_CLAIM_COUNT_REACHED" = "Maximum claim count for the user reached"; -"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Maximum share count for the sensor reached"; -"UserApiError.ER_NO_DATA_TO_SHARE" = "In order to share a sensor, it must have data"; -"UserApiError.ER_SENSOR_ALREADY_REGISTERED" = "The sensor has already been registered"; -"UserApiError.ER_SUBSCRIPTION_CODE_EXISTS" = "Tried to add duplicate subscription to a code"; -"UserApiError.ER_SUBSCRIPTION_CODE_USED" = "Tried to claim already used code"; -"UserApiError.ER_OLD_ENTRY" = "Newer data already exists, cannot update"; -"UserApiError.ER_INVALID_ENUM_VALUE" = "Invalid ENUM value given"; -"UserApiError.OK" = "Operation was successful"; - diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/ru.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/ru.lproj/Localizable.strings deleted file mode 100644 index 77faef121..000000000 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/ru.lproj/Localizable.strings +++ /dev/null @@ -1,767 +0,0 @@ -// swiftlint:disable all -// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen -"Done" = "Готово"; -"Copy" = "Копировать"; -"Confirm" = "Подтвердить"; -"Remove" = "Удалить"; -"N/A" = "-"; -"g" = "g"; -"About.Version.text" = "Версия"; -"Background.PresentNotifications.title" = "Показывать Уведомления"; -"Background.KeepConnection.title" = "Держать Соединение"; -"Background.Interval.Every.string" = "каждые"; -"Background.Interval.Min.string" = "мин"; -"Background.readRSSITitle.title" = "Считывать RSSI"; -"BluetoothError.disconnected" = "Соединение разорвано"; -"Cards.BluetoothDisabledAlert.title" = "Bluetooth выключен"; -"Cards.BluetoothDisabledAlert.message" = "Ruuvi Station необходим Bluetooth чтобы слушать сенсоры. Откройте Настройки и включите Bluetooth."; -"Cards.WebTagAPILimitExcededError.Alert.title" = "Слишком много запросов"; -"Cards.WebTagAPILimitExcededError.Alert.message" = "Пожалуйста, попробуйте через 5 минут"; -"Cards.KeepConnectionDialog.message" = "На вашем устройстве установлена прошивка, поддерживающая соединение. Хотите поддерживать соединение активным для этого устройства в фоновом режиме? Это позволит использовать графики и уведомления даже когда приложение закрыто."; -"Cards.KeepConnectionDialog.Dismiss.title" = "Закрыть"; -"Cards.KeepConnectionDialog.KeepConnection.title" = "Установить Соединение"; -"Cards.LegacyFirmwareUpdateDialog.message" = "Looks like your sensor is using an old firmware software version. To access new features such as history graphs, alerts and cloud services, updating is mandatory."; -"Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message" = "Are you sure? Without updating, you won't be able to claim ownership of the sensor, download history graphs and set alerts. The update also includes bug fixes. If you cancel now, you can start the update process again from the sensor's settings page."; -"Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title" = "Check for update"; -"Cards.Connected.title" = "Соединен"; -"Cards.Error.ReverseGeocodingFailed.message" = "Не удалось загрузить данные для виртуального сенсора. Превышен лимит операций обратного геокодирования."; -"Cards.UpdatedLabel.NoData.message" = "No data during the last 10 days"; -"CoreError.failedToGetPngRepresentation" = "Не удалось получить данные в формате PNG"; -"CoreError.failedToGetDocumentsDirectory" = "Не удалось получить директорию для фоновых изображений"; -"CoreError.failedToGetCurrentLocation" = "Не удалось получить текущее месторасположение"; -"CoreError.failedToGetDataFromResponse" = "Не удалось получить данные из ответа"; -"CoreError.locationPermissionDenied" = "Не удалось получить разрешение на использование геолокации"; -"CoreError.locationPermissionNotDetermined" = "Права на использование локационных сервисов не определены"; -"CoreError.objectNotFound" = "Объект не найден"; -"CoreError.objectInvalidated" = "Объект инвалидирован"; -"CoreError.unableToSendEmail" = "Невозможно отправить электронное письмо"; -"Defaults.navigationItem.title" = "Значения"; -"Defaults.WelcomeShown.title" = "Приветствие Показано"; -"Defaults.ChartsSwipeInstructionWasShown.title" = "Свайп на Графиках"; -"Defaults.Interval.Sec.string" = "сек"; -"Defaults.Interval.Min.string" = "мин"; -"Defaults.ConnectionTimeout.title" = "Таймаут (соед.)"; -"Defaults.ServiceTimeout.title" = "Таймаут (обм.)"; -"Defaults.CardsSwipeHint.title" = "Свайп Подсказка на Графиках"; -"Defaults.AlertsRepeatInterval.title" = "Интервал Уведомлений"; -"Defaults.WebPullInterval.title" = "Интервал Уведомления для Виртуальных Сенсоров"; -"Defaults.PruningOffsetHours.title" = "Смещение Очистки в Часах"; -"Defaults.Interval.Hour.string" = "ч"; -"Defaults.ChartDurationHours.title" = "Размер Графиков"; -"Defaults.AppLaunchRequiredForReview.Count.title" = "Количество запусков приложения, чтобы запросить обзор в первый раз"; -"Defaults.AskReviewIfLaunchDivisibleBy.Count.title" = "Запросить отзыв, если запуск приложения делится на"; -"DiscoverTable.SectionTitle.WebTags" = "Виртуальные"; -"DiscoverTable.BluetoothDisabledAlert.title" = "Bluetooth выключен"; -"DiscoverTable.BluetoothDisabledAlert.message" = "Ruuvi Station необходим bluetooth чтобы слушать сенсоры. Откройте Настройки и включите Bluetooth."; -"DiscoverTable.NavigationItem.title" = "Добавить Сенсор"; -"DiscoverTable.GetMoreSensors.button.title" = "Купить датчики Ruuvi"; -"DiscoverTable.NoDevicesSection.NotFound.text" = "(Bluetooth устройства не найдены)"; -"DiscoverTable.NoDevicesSection.BluetoothDisabled.text" = "(Bluetooth отключен)"; -"DiscoverTable.WebTagsInfoDialog.message" = "Виртуальные сенсоры показывают публичную информацию о погоде, предоставленную локальными станциями."; -"DiscoverTable.RuuviDevice.prefix" = "Ruuvi"; -"ErrorPresenterAlert.Error" = "Ошибка"; -"ErrorPresenterAlert.OK" = "OK"; -"ExpectedError.missingOpenWeatherMapAPIKey" = "Не указан API-ключ для OpenWeatherMap. Пожалуйста, получите его на сайте openweathermap.org и поместите в файл station/Classes/Networking/Assembly/Networking.plist"; -"ExpectedError.isAlreadySyncingLogsWithThisTag" = "Приложение уже в процессе синхронизации логов с данным сенсором"; -"ExpectedError.failedToDeleteTag" = "Не удалось удалить подключенный сенсор, так как он недоступен. Пожалуйста, проверьте соединение по Bluetooth."; -"ExportService.Date" = "Дата"; -"ExportService.ISO8601" = "ISO8601"; -"ExportService.Temperature" = "Температура (%@)"; -"ExportService.Humidity" = "Влажность (%@)"; -"ExportService.DewPoint" = "Точка росы (%@)"; -"ExportService.Pressure" = "Давление (%@)"; -"ExportService.Voltage" = "Напряжение (В)"; -"ExportService.MovementCounter" = "Счетчик Движения"; -"ExportService.MeasurementSequenceNumber" = "Порядковый Номер Измерения"; -"ExportService.TXPower" = "Мощность Передачи"; -"ForegroundRow.advertisement.section" = "СООБЩЕНИЯ"; -"ForegroundRow.advertisement.title" = "Сохранять данные"; -"ForegroundRow.connection.section" = "ЛОГИ"; -"ForegroundRow.connection.title" = "Соединяться и сохранять логи"; -"Foreground.navigationItem.title" = "Активный Режим"; -"Foreground.Interval.Every.string" = "Каждые"; -"Foreground.Interval.Min.string" = "мин"; -"ForegroundRow.webTags.title" = "Загружать из интернета"; -"ForegroundRow.webTags.section" = "ВИРТУАЛЬНЫЕ СЕНСОРЫ"; -"Foreground.Interval.All.string" = "Все"; -"Heartbeat.Interval.Every.string" = "каждые"; -"Heartbeat.Interval.Min.string" = "мин"; -"Heartbeat.readRSSITitle.title" = "Считывать RSSI"; -"Heartbeat.Interval.Sec.string" = "сек"; -"Heartbeat.Interval.All.string" = "Все"; -"HumidityCalibration.ClearCalibrationConfirmationAlert.title" = "Вы уверены?"; -"HumidityCalibration.ClearCalibrationConfirmationAlert.message" = "Вы собираетесь очистить смещение для влажности. Вы не сможете откатить изменения. Нажмите \"Подтвердить\" для продолжения."; -"HumidityCalibration.CalibrationConfirmationAlert.title" = "Вы уверены?"; -"HumidityCalibration.CalibrationConfirmationAlert.message" = "Вы собираетесь откалибровать смещение для влажности. Нажмите \"Подтвердить\" для продолжения."; -"Language.English" = "English"; -"Language.Finnish" = "Suomi"; -"Language.Russian" = "Русский"; -"Language.Swedish" = "Svenska"; -"Language.French" = "Français"; -"Language.German" = "Deutsch"; -"LocalNotificationsManager.DidConnect.title" = "Соединился"; -"LocalNotificationsManager.DidDisconnect.title" = "Отсоединился"; -"LocalNotificationsManager.Disable.button" = "Отключить"; -"LocalNotificationsManager.LowDewPoint.title" = "Ниже Точки Росы!"; -"LocalNotificationsManager.HighDewPoint.title" = "Выше Точки Росы!"; -"PermissionPresenter.NoPhotoLibraryAccess.message" = "Ruuvi Station необходим доступ к вашей библиотеке фотографий для того, чтобы использовать эту функцию."; -"PermissionPresenter.NoCameraAccess.message" = "Ruuvi Station нужен доступ к камере для того, чтобы использовать эту функцию."; -"PermissionPresenter.NoLocationAccess.message" = "Ruuvi Station необходим доступ к геолокационным сервисам для того, чтобы использовать эту функцию."; -"PermissionPresenter.settings" = "Настройки"; -"PermissionPresenter.NoPushNotificationsPermission.message" = "Ruuvi Station необходим доступ к уведомлениям для того, чтобы использовать эту функцию."; -"PhotoPicker.Sheet.message" = "Выбрать фотографию"; -"PhotoPicker.Sheet.library" = "Выбрать из библиотеки"; -"PhotoPicker.Sheet.camera" = "Сделать фото"; -"Settings.SegmentedControl.Humidity.Relative.title" = "Отн"; -"Settings.SegmentedControl.Humidity.Absolute.title" = "Абс"; -"Settings.SegmentedControl.Humidity.DewPoint.title" = "ТР"; -"Settings.Label.Language.text" = "Язык"; -"Settings.Language.Dialog.title" = "Выберите Язык"; -"Settings.Language.Dialog.message" = "Open settings and tap Language to change language of the app. -If you cannot see the Language option in the settings, make sure that you have at least one preferred language added in system settings: Settings -> General -> Language & Region."; -"Settings.Label.Foreground" = "Активный Режим"; -"Settings.Label.Defaults" = "Значения"; -"OWMError.failedToParseOpenWeatherMapResponse" = "Не удалось распарсить ответ от OpenWeatherMap"; -"OWMError.apiLimitExceeded" = "Превышен лимит запросов к API OpenWeatherMap"; -"OWMError.notAHttpResponse" = "Не HTTP ответ"; -"OWMError.invalidApiKey" = "Некорректный API-ключ"; -"TagCharts.NoChartData.text" = "Нет данных для построения графика"; -"TagCharts.BluetoothDisabledAlert.title" = "Bluetooth выключен"; -"TagCharts.BluetoothDisabledAlert.message" = "Ruuvi Station необходим Bluetooth чтобы слушать сенсоры. Откройте Настройки и включите Bluetooth."; -"TagCharts.Clear.title" = "Очистить"; -"TagCharts.SyncConfirmationDialog.title" = "Вы уверены?"; -"TagCharts.DeleteHistoryConfirmationDialog.button.delete.title" = "Удалить"; -"TagCharts.DeleteHistoryConfirmationDialog.title" = "Вы уверены?"; -"TagCharts.Status.Disconnecting" = "Разрываю соединение..."; -"TagCharts.Status.Success" = "Успех"; -"TagCharts.Status.Error" = "Ошибка"; -"TagSettings.UUID.Alert.title" = "UUID"; -"TagSettings.UpdateFirmware.Alert.title" = "Необходим Режим RAWv2"; -"TagSettings.UpdateFirmware.Alert.message" = "Для того, чтобы увидеть отсутствующие значения:\nЕсли вы используете последнюю прошивку, включите RAWv2 режим нажатием кнопки \"B\" на вашем сенсоре.\nИли обновите ваш сенсор с последней прошивкой."; -"TagSettings.UpdateFirmware.Alert.Buttons.LearnMore.title" = "Узнать больше"; -"TagCharts.Dismiss.Alert.message" = "The history download via Bluetooth connection is in progress. Please wait."; -"TagCharts.AbortSync.Alert.message" = "Sometimes the history download is slow due to the Bluetooth connectivity. Please wait a moment."; -"TagCharts.AbortSync.Button.title" = "Abort download"; -"TagSettings.EmptyValue.sign" = "-"; -"TagSettings.HumidityIsClipped.Alert.title" = "Датчик влажности откалиброван"; -"TagSettings.HumidityIsClipped.Alert.message" = "Значение относительной влажности больше 100% после калибровки. Это значение не имеет смысла, поэтому значение откалибровано до 100%."; -"TagSettings.HumidityIsClipped.Alert.Fix.button" = "Исправить"; -"TagSettings.navigationItem.title" = "Настройки"; -"TagSettings.tagNameTitleLabel.text" = "Имя"; -"TagSettings.humidityTitleLabel.text" = "Влажность"; -"TagSettings.uuidTitleLabel.text" = "UUID"; -"TagSettings.macAddressTitleLabel.text" = "MAC Адрес"; -"TagSettings.dataFormatTitleLabel.text" = "Формат Данных"; -"TagSettings.accelerationXTitleLabel.text" = "Ускорение по X"; -"TagSettings.accelerationYTitleLabel.text" = "Ускорение по Y"; -"TagSettings.accelerationZTitleLabel.text" = "Ускорение по Z"; -"TagSettings.txPowerTitleLabel.text" = "Мощность Передачи"; -"TagSettings.mcTitleLabel.text" = "Счетчик Движения"; -"TagSettings.msnTitleLabel.text" = "Порядковый Номер Измерения"; -"TagSettings.SectionHeader.Remove.title" = "УДАЛИТЬ"; -"TagSettings.Label.noValues.text" = "НЕТ ЗНАЧЕНИЙ?"; -"TagSettings.SectionHeader.Calibration.title" = "КАЛИБРОВКА"; -"TagSettings.SectionHeader.BTConnection.title" = "BLUETOOTH СОЕДИНЕНИЕ"; -"TagSettings.PairAndBackgroundScan.Unpaired.title" = "Pair and use background scan"; -"TagSettings.PairAndBackgroundScan.Pairing.title" = "Connecting to the sensor"; -"TagSettings.PairAndBackgroundScan.Paired.title" = "Paired and background scan is on"; -"TagSettings.PairAndBackgroundScan.description" = "Alerts are not available over Bluetooth connection if background scanning is not enabled. Only one iOS device can be paired to a Ruuvi sensor at a time."; -"TagSettings.PairError.CloudMode.description" = "The sensor cannot be connected to via Bluetooth when the cloud mode is active. You can re-enable the Bluetooth connection for the cloud sensors by disabling cloud mode in the app settings."; -"TagSettings.PairError.Timeout.description" = "Connection timed out. Pairing was unsuccessful. Please try again."; -"TagSettings.dataSourceTitleLabel.text" = "Данные Получены Из"; -"TagSettings.DataSource.Heartbeat.title" = "Соединение"; -"TagSettings.DataSource.Advertisement.title" = "Вещания"; -"TagSettings.DataSource.Network.title" = "Сеть"; -"TagSettings.Label.disabled.text" = "НЕДОСТУПНО?"; -"TagSettings.AlertsAreDisabled.Dialog.BothNotConnectedAndNoPNPermission.message" = "Уведомления недоступны поскольку девайс не подсоединен и нет разрешения на показ уведомлений. Пожалуйста, сперва соединитесь с устройством."; -"TagSettings.AlertsAreDisabled.Dialog.Connect.title" = "Соединиться"; -"TagSettings.AlertsAreDisabled.Dialog.NotConnected.message" = "Уведомления недоступны поскольку вы не подсоединены к устройству."; -"TagSettings.Alert.CustomDescription.placeholder" = "Введите описание..."; -"TagSettings.Alert.CustomDescription.title" = "Описание уведомления"; -"TagSettings.Alerts.Humidity.description" = "Уведомить если меньше %.0f или больше %.0f"; -"TagSettings.Alerts.DewPoint.description" = "Уведомить если меньше %.0f или больше %.0f"; -"TagSettings.dewPointAlertTitleLabel.text" = "Точка Росы"; -"TagSettings.Alerts.Pressure.description" = "Уведомить если меньше %.0f или больше %.0f"; -"TagSettings.Alerts.Connection.description" = "Уведомить при установке/разрыве соединения"; -"TagSettings.ConnectionAlert.title" = "Соединение"; -"TagSettings.SectionHeader.Firmware.title" = "Прошивка"; -"TagSettings.Firmware.CurrentVersion" = "Текущая версия"; -"TagSettings.Firmware.CurrentVersion.VeryOld" = "Устаревшая"; -"TagSettings.Firmware.UpdateFirmware" = "Обновить"; -"UnexpectedError.callbackErrorAndResultAreNil" = "И коллбэк и ошибка nil"; -"UnexpectedError.callerDeinitedDuringOperation" = "Вызывающий объект был деаллоцирован во время операции"; -"UnexpectedError.failedToReverseGeocodeCoordinate" = "Не удалось определить локацию по координатам"; -"UnexpectedError.failedToFindRuuviTag" = "Не удалось найти сенсор"; -"UnexpectedError.failedToFindLogsForTheTag" = "Не удалось найти логи сенсора"; -"UnexpectedError.viewModelUUIDIsNil" = "UUID модели пустое"; -"UnexpectedError.attemptToReadDataFromRealmWithoutLUID" = "Attempt to read data from Realm without LUID"; -"UnexpectedError.failedToFindVirtualTag" = "Failed to find virtual sensor"; -"HumidityUnit.Dew.title" = "Точка росы (%@)"; -"WebTagLocationSource.current" = "Ваше текущее месторасположение"; -"WebTagLocationSource.manual" = "Месторасположение на карте"; -"WebTagSettings.confirmTagRemovalDialog.title" = "Удалить"; -"WebTagSettings.confirmTagRemovalDialog.message" = "Вы уверены что хотите удалить?"; -"WebTagSettings.Location.Current" = "Ваше текущее месторасположение"; -"WebTagSettings.confirmClearLocationDialog.title" = "Очистить месторасположение"; -"WebTagSettings.confirmClearLocationDialog.message" = "Вы уверены, что хотите очистить месторасположение? Будет использовано текущее месторасположение."; -"WebTagSettings.navigationItem.title" = "Настройки"; -"WebTagSettings.Label.BackgroundImage.text" = "ФОНОВОЕ\nИЗОБРАЖЕНИЕ"; -"WebTagSettings.Label.Location.text" = "Месторасположение"; -"WebTagSettings.Button.Remove.title" = "УДАЛИТЬ"; -"WebTagSettings.SectionHeader.Name.title" = "ИМЯ"; -"WebTagSettings.SectionHeader.MoreInfo.title" = "ДОПОЛНИТЕЛЬНО"; -"WebTagSettings.Alerts.Temperature.description" = "Уведомить если меньше %.0f или больше %.0f"; -"WebTagSettings.Alerts.Off" = "Отключено"; -"WebTagSettings.temperatureAlertTitleLabel.text" = "Температура"; -"WebTagSettings.Label.disabled.text" = "НЕДОСТУПНО?"; -"WebTagSettings.Label.alerts.text" = "УВЕДОМЛЕНИЯ"; -"WebTagSettings.AlertsAreDisabled.Dialog.BothNoPNPermissionAndNoLocationPermission.message" = "Чтобы включить уведомления для Виртуальных Сенсоров, пожалуйста дайте разрешение на использование геолокации в Настройках."; -"WebTagSettings.AlertsAreDisabled.Dialog.Settings.title" = "Настройки"; -"WebTagSettings.AirHumidityAlert.title" = "Относительная Влажность"; -"WebTagSettings.Alerts.Humidity.description" = "Уведомить если меньше %.0f или больше %.0f"; -"WebTagSettings.Alerts.DewPoint.description" = "Уведомить если меньше %.0f или больше %.0f"; -"WebTagSettings.dewPointAlertTitleLabel.text" = "Точка Росы"; -"WebTagSettings.PressureAlert.title" = "Атмосферное Давление"; -"WebTagSettings.Alerts.Pressure.description" = "Уведомить если меньше %.0f или больше %.0f"; -"Welcome.description.text" = "Чтобы найти сенсор рядом и получать текущие данные, нажмите сканировать."; -"ExportService.AccelerationX" = "Ускорение по X"; -"ExportService.AccelerationY" = "Ускорение по Y"; -"ExportService.AccelerationZ" = "Ускорение по Z"; -"DiscoverTable.SectionTitle.Devices" = "Ближайшие Сенсоры"; -"ago" = "назад"; -"TagSettings.MovementAlert.title" = "Движение"; -"TagSettings.Alerts.Movement.description" = "Уведомить при движении"; -"LocalNotificationsManager.HighHumidity.title" = "Высокая Влажность!"; -"LocalNotificationsManager.LowHumidity.title" = "Низкая Влажность!"; -"LocalNotificationsManager.DidMove.title" = "Сработал Датчик Движения!"; -"LocalNotificationsManager.HighPressure.title" = "Высокое Атмосферное Давление!"; -"LocalNotificationsManager.LowPressure.title" = "Низкое Атмосферное Давление!"; -"LocalNotificationsManager.HighSignal.title" = "Высокий уровень сигнала!"; -"LocalNotificationsManager.LowSignal.title" = "Низкий уровен сигнала!"; -"LocalNotificationsManager.HighTemperature.title" = "Высокая температура!"; -"LocalNotificationsManager.LowTemperature.title" = "Низкая температура!"; -"TagSettings.Alerts.Off" = "Отключено"; -"TagSettings.Alerts.Temperature.description" = "Уведомление если меньше %.0f или больше %.0f"; -"TagSettings.Label.alerts.text" = "Уведомления"; -"TagSettings.backgroundImageLabel.text" = "Фоновое изображение"; -"TagSettings.batteryVoltageTitleLabel.text" = "Напряжение Батареи"; -"HumidityCalibration.Button.Calibrate.title" = "Калибровать"; -"HumidityCalibration.lastCalibrationDate.format" = "Откалибровано: %@"; -"HumidityCalibration.Description.text" = "Чтобы измерять относительную влажность наиболее точно, рекомендуется провести тест с поваренной солью. Посмотрите обучающие видео о том, как легко сделать это дома. "; -"HumidityCalibration.Label.note.text" = "Данные для калибровки будут сохранены локально. Если вы переустановите приложение будет нужно произвести калибровку заново."; -"HumidityCalibration.VideoTutorials.link" = "обучающие видео"; -"Cancel" = "Отмена"; -"HumidityCalibration.Button.Clear.title" = "Очистить"; -"TagCharts.DeleteHistoryConfirmationDialog.message" = "Вы уверены что хотите удалить всю историю наблюдений? Данное действие невозможно отменить."; -"HumidityCalibration.Button.Close.title" = "Закрыть"; -"TagCharts.Status.Serving" = "Обмениваюсь..."; -"TagCharts.Status.Connecting" = "Соединение..."; -"TagSettings.ConnectStatus.Disconnected" = "Отсоединен"; -"TagCharts.Export.title" = "ЭКСПОРТ"; -"h" = "ч"; -"About.AboutHelp.contents" = "Ruuvi Station — это простое в использовании приложение, позволяющее отслеживать данные измерений датчиков Ruuvi."; -"About.AboutHelp.header" = "О приложении"; -"About.TagsCount.text" = "Добавленных датчиков: %d"; -"About.MeasurementsCount.text" = "Кол-во сохраненных измерений: %d"; -"About.DatabaseSize.text" = "Размер базы данных: %@"; -"About.More.contents" = "Веб-сайт: ruuvi.com\nФорум: f.ruuvi.com\nБлог: ruuvi.com\nTwitter: twitter.com/ruuvicom"; -"About.More.header" = "Почитать еще"; -"About.OpenSource.contents" = "Как и датчики Ruuvi, приложения Ruuvi Station имеют открытый исходный код. Следите за развитием и вносите свой вклад на: github.com/ruuvi"; -"About.OpenSource.header" = "Открытый исходный код"; -"About.OperationsManual.contents" = "Начните использовать мобильное приложение Ruuvi Station с помощью наших онлайн-руководств: ruuvi.com/support/station-mobile"; -"About.OperationsManual.header" = "Руководство"; -"About.Privacy.contents" = "Используя это приложение, вы соглашаетесь со стандартными условиями и положениями Ruuvi: ruuvi.com/terms"; -"About.Privacy.header" = "Политика конфиденциальности"; -"About.Troubleshooting.contents" = "Получите помощь по использованию приложений Ruuvi Station, продуктов Ruuvi и облачной службы Ruuvi в нашем центре поддержки: ruuvi.com/support"; -"About.Troubleshooting.header" = "Решение проблем"; -"hours" = "Часов"; -"Interval.Days.string" = "Дней"; -"TagSettings.AirHumidityAlert.title" = "Влажность воздуха (%@)"; -"HumidityUnit.gm3.title" = "Абсолютная влажность (г/м³)"; -"g/m³" = "г/м³"; -"HumidityUnit.Percent.title" = "Относительная влажность (%)"; -"TagSettings.Mac.Alert.title" = "MAC адрес"; -"Menu.Label.AboutHelp.text" = "О Приложении"; -"Menu.Label.AddAnNewSensor.text" = "Добавить Сенсор"; -"Menu.Label.AppSettings.text" = "Настройки"; -"Menu.Label.GetMoreSensors.text" = "Купить датчики Ruuvi"; -"Ruuvi.BuySensors.URL.IOS" = "https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Ruuvi.BuySensors.Menu.URL.IOS" = "https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios"; -"Menu.Label.BuyRuuviGateway.text" = "Купить Ruuvi Gateway"; -"Menu.BuyGateway.URL.IOS" = "https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Menu.Label.WhatToMeasure.text" = "Что измерять с помощью Ruuvi?"; -"Menu.Measure.URL.IOS" = "https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Menu.Label.Feedback.text" = "Отправить Отзыв"; -"Menu.Label.MyRuuviAccount.text" = "My Ruuvi Account"; -"min" = "мин"; -"minutes" = "Минут"; -"TagSettings.Label.moreInfo.text" = "Дополнительно"; -"TagSettings.SectionHeader.Name.title" = "ИМЯ"; -"No" = "Нет"; -"OK" = "OK"; -"Cards.NoSensors.title" = "Нет добавленных датчиков\nнажмите чтобы добавить"; -"TagSettings.PressureAlert.title" = "Атмосферное Давление (%@)"; -"UnitPressure.hectopascal.title" = "Гектопаскаль (гПа)"; -"hPa" = "гПа"; -"UnitPressure.inchOfMercury.title" = "Дюймов ртутного столба (inHg)"; -"UnitPressure.millimetreOfMercury.title" = "Миллиметров ртутного столба (мм.рт.ст.)"; -"TagCharts.Status.ReadingHistory" = "Чтение истории"; -"TagSettings.rssiTitleLabel.text" = "Сила сигнала (RSSI)"; -"signal_strength_dbm" = "Сила сигнала (dBm)"; -"s" = "с"; -"Welcome.scan.title" = "СКАНИРОВАТЬ"; -"Background.Interval.Sec.string" = "сек"; -"Settings.navigationItem.title" = "Настройки"; -"Settings.BackgroundScanning.title" = "Сканирование в фоне"; -"Settings.BackgroundScanning.Footer.message" = "Important note: Bluetooth background history logging and Bluetooth alerts work only when background scanning is enabled. If you disable the background scanning, all paired Ruuvi sensors will be automatically unpaired and you need to pair them again from their settings pages."; -"Settings.BackgroundScanning.interval" = "Интервал сканирования"; -"Settings.Label.Chart" = "Настройки графиков"; -"ChartSettings.AllPoints.title" = "Отображать все данные"; -"ChartSettings.AllPoints.description" = "Это может привести к медленному обновлению графиков."; -"ChartSettings.DrawDots.title" = "Показывать точки на графике"; -"ChartSettings.DrawDots.description" = "Маленькие точки помогут точно понять когда были получены данные."; -"Defaults.ChartIntervalSeconds.title" = "Интервал Графиков"; -"ChartSettings.Duration.title" = "Диапазон отображения графиков"; -"ChartSettings.Duration.description" = "Установите диапазон для отображения на графиках от 1-го до 10-ти дней."; -"Settings.Label.HumidityUnit.text" = "Ед. изм. Влажности"; -"Settings.Label.Temperature" = "Температура"; -"Settings.Label.Humidity" = "Влажность"; -"Settings.Label.Pressure" = "Давление"; -"Settings.ChooseHumidityUnit.text" = "Выберите единицу измерения влажности для отображения."; -"Settings.Label.PressureUnit.text" = "Ед. изм. Давления"; -"Settings.ChoosePressureUnit.text" = "Выберите единицу измерения давления для отображения."; -"Settings.Label.TemperatureUnit.text" = "Ед. изм. Температуры"; -"Settings.ChooseTemperatureUnit.text" = "Выберите единицу измерения температуры для отображения."; -"dBm" = "дБм"; -"TagCharts.Sync.title" = "Скачать"; -"TagCharts.SyncConfirmationDialog.message" = "Вы уверены что хотите синхронизировать данные с устройством?"; -"WebTagSettings.Label.TagName.text" = "Имя"; -"TagSettings.confirmTagRemovalDialog.title" = "Удалить сенсор"; -"TagSettings.confirmTagRemovalDialog.message" = "Вы уверены что хотите удалить этот сенсор?"; -"TagSettings.temperatureAlertTitleLabel.text" = "Температура (%@)"; -"TemperatureUnit.Celsius.title" = "Цельсий (℃)"; -"ºC" = "°C"; -"TemperatureUnit.Fahrenheit.title" = "Фаренгейт (℉)"; -"ºF" = "°F"; -"TemperatureUnit.Kelvin.title" = "Кельвин (K)"; -"Updated" = "Обновлено"; -"V" = "В"; -"RuuviOnboard.Welcome.title" = "Проведите пальцем чтобы узнать, чем Ruuvi Station может помочь вам."; -"RuuviOnboard.Measure.title" = "Измеряйте параметры окружающей среды: температуру, влажность и атмосферное давление."; -"RuuviOnboard.Access.title" = "В реальном времени считывайте показатели с датчиков и просматривайте историю на графиках."; -"RuuviOnboard.Alerts.title" = "Устанавливайте лимиты значений, при превышении которых вы получите уведомление."; -"RuuviOnboard.Cloud.title" = "Sign in to use the full potential of the app."; -"RuuviOnboard.Cloud.subtitle" = "Claim ownership of your sensors with a free Ruuvi Cloud account."; -"RuuviOnboard.Cloud.subtitle.signed" = "Great! You already signed in!"; -"RuuviOnboard.Start.title" = "Нажмите СКАНИРОВАТЬ, чтобы найти и добавить датчики в Ruuvi Station."; -"Yes" = "Да"; -"LocalNotificationsManager.Mute.button" = "Отключить на час"; -"Defaults.AlertsMuteInterval.title" = "Интервал Отключения Уведомлений"; -"SignIn.Title.text" = "Войти"; -"Menu.SignOut.text" = "Выйти из сети"; -"RuuviOnboard.Cloud.Benefits.message" = "Преимущества:\n\n ● Название датчика, изображение фона, данные калибровки и настройки тревог будут безопасно храниться в облаке\n\n ● Получите доступ к датчикам через интернет (требуестся Ruuvi Gateway)\n\n ● Поделитесь данными датчиков с друзьями и членами семьи (требуется Ruuvi Gateway)\n\n ● Просматривайте до 2-х лет истории на сайте station.ruuvi.com (требуется a Ruuvi Gateway)"; -"RuuviOnboard.Cloud.Details.title" = "Подробнее"; -"ruuvi_cloud" = "Ruuvi Cloud"; -"RuuviOnboard.Cloud.Skip.title" = "Точно хотите пропустить вход?"; -"RuuviOnboard.Cloud.Skip.Yes.title" = "Пропустить"; -"RuuviOnboard.Cloud.Skip.GoBack.title" = "Назад"; -"SignIn.EmailPlaceholder" = "Email"; -"SignIn.RequestCode" = "Запросить код"; -"SignIn.SubmitCode" = "Отправить"; -"SignIn.EmailSent" = "Email отправлен"; -"SignIn.CheckMailbox" = "Мы отправили одноразовый пароль на вашу электронную почту %@. Войдите, введя его здесь:"; -"SignIn.CodeHint" = "Код для входа"; -"TagsManagerPresenter.SignOutConfirmAlert.Message" = "После выхода все датчики, которые зарегистрованы на вас, будут удалены из приложения. Если вы повторно войдете с тем же email адресом, список ваших датчиков будет загружен из облака. \n\nВы хотите выйти из сети?"; -"TagSettings.ClaimTagButton.Claim" = "Заявить о собственности"; -"TagSettings.ShareButton" = "Поделиться"; -"Syncing..." = "Синхронизация..."; -"Synchronized" = "Синхронизировано"; -"TagChartsPresenter.NumberOfPointsSynchronizedOverNetwork" = "Синхронизировано: %@"; -"MenuTableViewController.None" = "нет"; -"MenuTableViewController.User" = "Пользователь: %@"; -"ShareViewController.Title" = "Поделиться датчиком Ruuvi"; -"ShareViewController.Description" = "Вы можете поделиться измерениями этого датчика с друзьями или членами семьи, если датчик находится в радиусе действия Ruuvi Gateway.\n\nПолучатель будет извещен по электронной почте. Если у него нет аккаунта Ruuvi, то бесплатный аккаунт будет создан при первом входе.\n\nНазвание датчика и изображение использованное в качестве фона будет также доступно для пользователя. Пользователь сможет позже изменить название и изображение на удобное для себя. Данные калибровки датчика (если они были установлены владельцем) будут автоматически синхронизированы и получатель всегда будет видеть данные после калибровки."; -"ShareViewController.addFriend.Title" = "Добавить друга"; -"ShareViewController.emailTextField.placeholder" = "Введите email"; -"ShareViewController.sharedEmails.Title" = "Вы использовали %d/%d от максимального количества делений для этого датчика. Датчик используется совместно со следующими пользователями:"; -"Share.Send.button" = "Отправить"; -"SharePresenter.UnshareSensor.Message" = "Хотите перестать делиться показаниями датчика с %@?"; -"TagSettings.SectionHeader.NetworkInfo.title" = "Данные сети"; -"TagSettings.NetworkInfo.Owner" = "Владелец"; -"Menu.RuuviNetworkStatus.text" = "Статус сети Ruuvi"; -"SignIn.TitleLabel.text" = "Войти в\nRuuvi\nStation"; -"SignIn.SubtitleLabel.text" = "Чтобы воспользоваться всеми функциями, создайте аккаунт или войдите в существующий. Пожалуйста, введите ваш email."; -"SignIn.VerificationCodePlaceholder" = "код подтверждения в формате: CJSM"; -"UserApiError.ER_FORBIDDEN" = "Запрещено"; -"UserApiError.ER_UNAUTHORIZED" = "Требуется авторизация"; -"UserApiError.ER_INTERNAL" = "Внутренняя ошибка"; -"UserApiError.ER_INVALID_FORMAT" = "Неправильный формат запроса"; -"UserApiError.ER_USER_NOT_FOUND" = "Пользователь не найден"; -"UserApiError.ER_SENSOR_NOT_FOUND" = "Сенсор не найден"; -"UserApiError.ER_TOKEN_EXPIRED" = "Токен истек"; -"UserApiError.ER_SUBSCRIPTION_NOT_FOUND" = "Подписка не найдена"; -"UserApiError.ER_SHARE_COUNT_REACHED" = "Достигнут лимит количества общих сенсоров"; -"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Превышено количество общих сенсоров"; -"UserApiError.ER_NO_DATA_TO_SHARE" = "Чтобы поделиться датчиком необходимо наличие Ruuvi Gateway поблизости"; -"UserApiError.ER_SENSOR_ALREADY_SHARED" = "Вы уже делились этим сенсором"; -"UserApiError.ER_SENSOR_ALREADY_CLAIMED" = "Sensor already claimed by %@"; -"UserApiError.ER_SENSOR_ALREADY_CLAIMED_NO_EMAIL" = "Sensor already claimed"; -"UserApiError.ER_UNABLE_TO_SEND_EMAIL" = "Не удалось отправить e-mail"; -"UserApiError.ER_MISSING_ARGUMENT" = "Пропущен аргумент запроса"; -"UserApiError.ER_INVALID_DENSITY_MODE" = "Недопустимый режим плотности"; -"UserApiError.ER_INVALID_SORT_MODE" = "Выбран недопустимый метод сортировки"; -"UserApiError.ER_INVALID_TIME_RANGE" = "Выбран недопустимый промежуток времени"; -"UserApiError.ER_INVALID_EMAIL_ADDRESS" = "Недопустимый e-mail"; -"UserApiError.ER_INVALID_MAC_ADDRESS" = "Недопустимый MAC-адрес"; -"UserApiError.ER_SUB_DATA_STORAGE_ERROR" = "Ошибка сохранения данных"; -"UserApiError.ER_SUB_NO_USER" = "Нет пользователя"; -"UserApiError.ER_THROTTLED" = "Слишком много запросов"; -"OffsetCorrection.CalibrationDescription.text" = "Обычно нет необходимости калибровать датчики.\n\nОднако, если вы продивнутый пользователь и хотите вручную откалибровать настроенные на заводе сенсоры, это возможно.\n\nПодсказки и информация доступны на сайте ruuvi.com/support"; -"OffsetCorrection.Dialog.Calibration.ClearConfirm" = "Сбросить настройки калибровки?"; -"OffsetCorrection.Dialog.Calibration.Title" = "Настройка калибровок"; -"OffsetCorrection.Dialog.Calibration.EnterTemperature" = "Введите ожидаемое значение температуры в текущих условиях (%@): "; -"OffsetCorrection.Dialog.Calibration.EnterPressure" = "Введите ожидаемое значение давления в текущих условиях (%@): "; -"OffsetCorrection.Dialog.Calibration.EnterHumidity" = "Введите ожидаемое значение влажности в текущих условиях (%@): "; -"OffsetCorrection.OriginalValue.title" = "Измеренное значение"; -"OffsetCorrection.CorrectedValue.title" = "Откалиброванное значение"; -"OffsetCorrection.Temperature.Title" = "Калибровка по температуре"; -"OffsetCorrection.Humidity.Title" = "Калибровка по влажности"; -"OffsetCorrection.Pressure.Title" = "Калибровка по давлению"; -"OffsetCorrection.Calibrate.button" = "Калибровка"; -"TagSettings.SectionHeader.OffsetCorrection.Title" = "КАЛИБРОВКИ"; -"TagSettings.OffsetCorrection.Temperature" = "Температура"; -"TagSettings.OffsetCorrection.Humidity" = "Влажность"; -"TagSettings.OffsetCorrection.Pressure" = "Давление"; -"PhotoPicker.Sheet.files" = "Выбрать из файлов"; -"SignIn.EnterVerificationCode" = "Пожалуйста, введите код подтверждения"; -"UnexpectedError.failedToFindOrGenerateBackgroundImage" = "Не удалось найти или сгенерировать фоновое изображение"; -"UnexpectedError.bothLuidAndMacAreNil" = "Локальный индентификатор и MAC-адрес не определены"; -"RuuviCloudApiError.emptyResponse" = "Пустой ответ"; -"RuuviCloudApiError.failedToGetDataFromResponse" = "Не удалось получить данные из ответа"; -"RuuviCloudApiError.unexpectedHTTPStatusCode" = "Неожиданный код статуса HTTP"; -"RuuviCloudError.NotAuthorized" = "Не авторизован"; -"RuuviLocalError.failedToGetJpegRepresentation" = "Не удалось получить данные в формате JPG"; -"RuuviLocalError.failedToGetDocumentsDirectory" = "Не удалось получить директорию для фоновых изображений"; -"RuuviPersistenceError.failedToFindRuuviTag" = "Не удалось найти сенсор"; -"RuuviServiceError.pictureUrlIsNil" = "Пустой URL картинки"; -"RuuviServiceError.macIdIsNil" = "Пустой MAC-адрес"; -"network_sharing_disabled" = "Вы можете поделиться сенсорами только из зоны покрытия Ruuvi Gateway."; -"RuuviServiceError.bothLuidAndMacAreNil" = "Локальный идентификатор и MAC-адрес пустые"; -"RuuviServiceError.failedToParseNetworkResponse" = "Не удалось распарсить ответ"; -"RuuviServiceError.failedToFindOrGenerateBackgroundImage" = "Не удалось найти или сгенерировать фоновое изображение"; -"RuuviServiceError.failedToGetJpegRepresentation" = "Не удалось получить данные в формате JPG"; -"UpdateFirmware.Title.text" = "Обновить Прошивку"; -"UpdateFirmware.Download.header" = "СКАЧАТЬ ПОСЛЕДНЮЮ ПРОШИВКУ"; -"UpdateFirmware.Download.content" = "Чтобы начать процесс обновления, скачайте последнюю прошивку для целевого устройства. Последняя версия прошивки доступна на сайте ruuvi.com/software-update"; -"UpdateFirmware.SetDfu.header" = "ПЕРЕВЕДИТЕ RUUVI TAG В DFU-РЕЖИМ"; -"UpdateFirmware.SetDfu.content" = "Осторожно откройте RuuviTag пальцами или отверткой.\n\nВведите RuuviTag в режим обновления прошивки, зажав кнопку B и нажав на кнопку перезагрузки R. Красная лампочка загорится и будет продолжать гореть. Если на вашем устройстве только одна кнопка, зажмите ее на 10 секунд."; -"UpdateFirmware.NextButton.title" = "ДАЛЕЕ"; -"DfuDevicesScanner.Title.text" = "Устройства"; -"DfuDevicesScanner.Description.text" = "Найдите и выберите сенсор \"RuuviBoot\"."; -"DfuDevicesScanner.NoDevice.text" = "(Bluetooth устройства не найдены)"; -"DfuDevicesScanner.BluetoothDisabled.text" = "(Bluetooth отключен)"; -"DfuDevicesScanner.BluetoothDisabledAlert.title" = "Bluetooth выключен"; -"DfuDevicesScanner.BluetoothDisabledAlert.message" = "Ruuvi Station необходим bluetooth чтобы слушать сенсоры. Откройте Настройки и включите Bluetooth."; -"DfuFlash.Title.text" = "DFU"; -"DfuFlash.Progress.text" = "Прогресс"; -"DfuFlash.Step.text" = "Шаг"; -"DfuFlash.Steps.PackageSelection.text" = "Выбор Прошивки"; -"DfuFlash.Steps.ReadyForUpload.text" = "Готово к Загрузке"; -"DfuFlash.Steps.Uploading.text" = "Загружаю"; -"DfuFlash.Steps.Completed.text" = "Успешно"; -"DfuFlash.OpenDocumentPicker.title" = "ОТКРЫТЬ ФАЙЛ"; -"DfuFlash.FirmwareSelectionGuide.text" = "Выберите ранее загруженный ZIP файл."; -"DfuFlash.Firmware.FileName.text" = "Имя Файла"; -"DfuFlash.Firmware.Parts.text" = "Части"; -"DfuFlash.Firmware.Size.text" = "Размер"; -"DfuFlash.Firmware.SoftDeviceSize.text" = "Soft Device Размер"; -"DfuFlash.Firmware.BootloaderSize.text" = "Размер Загрузчика"; -"DfuFlash.Cancel.text" = "ОТМЕНА"; -"DfuFlash.Start.text" = "Начать"; -"DfuFlash.Finish.text" = "УСПЕХ"; -"DfuFlash.FinishGuide.text" = "Обновление прошивки завершилось успешно -Ваш RuuviTag готов к использованию!"; -"DfuFlash.CancelAlert.text" = "Вы уверены что хотите прервать процесс обновления прошивки?"; -"RuuviDfuError.invalidFirmwareFile" = "Некорректный файл прошивки"; -"DFUUIView.navigationTitle" = "Обновление Прошивки"; -"DFUUIView.latestTitle" = "Доступная версия прошивки Ruuvi:"; -"DFUUIView.currentTitle" = "Текущая версия:"; -"DFUUIView.notReportingDescription" = "Ваш сенсор не возвращает версию прошивки. Вероятно, на нем установлена старая версия прошивки и обновление рекомендовано."; -"DFUUIView.alreadyOnLatest" = "Последняя версия прошивки уже установлена, обновление не требуется"; -"DFUUIView.startUpdateProcess" = "Начать процесс обновления"; -"DFUUIView.downloadingTitle" = "Идет скачивание обновления прошивки..."; -"DFUUIView.prepareTitle" = "Prepare your sensor"; -"DFUUIView.openCoverTitle" = "1. Open the cover of your Ruuvi sensor"; -"DFUUIView.locateBootButtonTitle" = "2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label."; -"DFUUIView.setUpdatingModeTitle" = "3. Set the sensor to updating mode:"; -"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”."; -"DFUUIView.toBootModeOneButtonDescription" = "3.2. If your sensor has a single button: keep the button pressed for 10 seconds."; -"DFUUIView.toBootModeSuccessTitle" = "4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”."; -"DFUUIView.updatingTitle" = "Обновляю..."; -"DFUUIView.searchingTitle" = "Searching for a sensor"; -"DFUUIView.startTitle" = "Start the update"; -"DFUUIView.doNotCloseTitle" = "Не закрывайте приложение и не отключайте сенсор во время обновления."; -"DFUUIView.successfulTitle" = "Обновление успешно завершено"; -"DFUUIView.DBMigration.Error.message" = "The update was successful, but an unexpected database migration error occurred. To continue using this sensor, please remove it from the app and then add it again."; -"RuuviDfuError.failedToConstructUUID" = "Не удалось создать UUID"; -"SignIn.EmailMismatch.Alert.message" = "Вы запросили код для %@, но использовали код для %@. Пожалуйста, убадитесь в том, что вы используете код из %@"; -"SignIn.EmailMissing.Alert.message" = "Почтовый адрес, который вы использовали для входа, не был сохранен. Пожалуйста, попробуйте войти снова."; -"TagSettings.RemoveThisSensor.title" = "Удалить датчик"; -"Share.Success.message" = "Успешно поделились данными датчика"; -"TagSettings.SectionHeader.General.title" = "Основное"; -"TagSettings.Shared.title" = "Поделились"; -"TagSettings.NotShared.title" = "Не делились"; -"Owner.title" = "Заявить о собственности"; -"Owner.ClaimOwnership.button" = "Заявить о владении"; -"Owner.Claim.description" = "Это ваш датчик? Если да, то пожалуйста заявите о владении и датчик будет добавлен в ваш Ruuvi аккаунт. Каждый датчик может иметь только одного владельца. Чтобы заявить права собственности, вам необходимо войти в систему.\n\nПреимущества:\n\n ● Название датчика, изображение фона, данные калибровки и настройки тревог будут безопасно храниться в облаке\n\n ● Получите доступ к датчикам через интернет (требуестся Ruuvi Gateway)\n\n ● Поделитесь данными датчиков с друзьями и членами семьи (требуется Ruuvi Gateway)\n\n ● Просматривайте до 2-х лет истории на сайте station.ruuvi.com (требуется a Ruuvi Gateway)"; -"TagSettings.confirmTagUnclaimAndRemoveDialog.message" = "Удаляя датчик вы также отказываетесь от владения. Кто-то другой сможет заявить о владении этим датчиком. Каждый датчик может иметь только одного владельца."; -"TagSettings.confirmSharedTagRemovalDialog.message" = "Если вы удалите датчик, то владелец будет уведомлен и вы более не сможете получать данные с него."; -"TagSettings.General.Owner.none" = "Нет владельца"; -"TagSettings.Share.title" = "Поделиться"; -"Menu.LoggedIn.title" = "Пользователь:"; -"Interval.Day.string" = "день"; -"hour" = "час"; -"TagSettings.tagNameTitleLabel.rename.text" = "Датчики будут отсортированы в алфавитном порядке."; -"On" = "Вкл"; -"Off" = "Выкл"; -"DFUUIView.lowBattery.warning.message" = "Уровень заряда батареи датчика слишком низкий и обновление прошивки может завершиться неудачей. Мы рекомендуем заменить батарейку перед обновлением."; -"alert_notification_humidity_high_threshold" = "Влажность выше %@"; -"alert_notification_humidity_low_threshold" = "Влажность ниже %@"; -"alert_notification_pressure_high_threshold" = "Давление выше %@"; -"alert_notification_pressure_low_threshold" = "Давление ниже %@"; -"alert_notification_rssi_high_threshold" = "Сила сигнала выше %@"; -"alert_notification_rssi_low_threshold" = "Сила сигнала ниже %@"; -"alert_notification_temperature_high_threshold" = "Температура выше %@"; -"alert_notification_temperature_low_threshold" = "Температура ниже %@"; -"Cards.Alert.AlreadyLoggedIn.message" = "Пользователь %@ уже совершил вход. Если вы хотите войти под другим аккаунтом, пожалуйста вначале выйдите, а затем повторите попытку."; -"Settings.Label.CloudMode" = "Режим облака"; -"Settings.Label.CloudMode.description" = "Refresh nearby cloud sensors only from the cloud by ignoring their Bluetooth messages and receiving alerts only by email. Requires a Ruuvi Gateway router."; -"internet_connection_problem" = "Проблема с подключением"; -"Widgets.Loading.message" = "загрузка..."; -"Cards.Movements.title" = "движений"; -"TagSettings.BatteryStatusLabel.Replace.message" = "Low battery"; -"TagSettings.BatteryStatusLabel.Ok.message" = "Батарея OK"; -"Widgets.Description.message" = "Create widgets of your favourite Ruuvi sensors. Widgets update from the Ruuvi Cloud. A Ruuvi Gateway router is required."; -"settings_appearance" = "Внешний вид"; -"app_theme" = "Тема приложения"; -"follow_system_theme" = "Системная тема"; -"dark_theme" = "Темная тема"; -"light_theme" = "Светлая тема"; -"Settings.Temperature.Resolution.title" = "Temperature Resolution"; -"Settings.Humidity.Resolution.title" = "Humidity Resolution"; -"Settings.Pressure.Resolution.title" = "Pressure Resolution"; -"Settings.Measurement.Resolution.description" = "Select how accurately you'd like to see the sensors' live measurement values in the app. This setting doesn't affect history charts or alerts."; -"Settings.Measurement.Unit.title" = "Unit"; -"Settings.Measurement.Resolution.title" = "Resolution"; -"MyRuuvi.Settings.DeleteAccount.title" = "Delete Account"; -"MyRuuvi.Settings.DeleteAccount.Confirmation.message" = "A confirmation has been sent to your email. To proceed with the deletion, please check your inbox and follow the instructions."; -"TagSettings.Alert.SetTemperature.title" = "Set temperature alert"; -"TagSettings.Alert.SetHumidity.title" = "Set humidity alert"; -"TagSettings.Alert.SetPressure.title" = "Set pressure alert"; -"TagSettings.Alert.SetRSSI.title" = "Set signal strength alert"; -"TagSettings.AlertSettings.Dialog.Min" = "Min (%.0f)"; -"TagSettings.AlertSettings.Dialog.Max" = "Max (%.0f)"; -"export_history" = "Выгрузить историю (csv)"; -"clear_view" = "Clear history view"; -"day_1" = "1 день"; -"day_2" = "2 дня"; -"day_3" = "3 дня"; -"day_4" = "4 дня"; -"day_5" = "5 дней"; -"day_6" = "6 дней"; -"day_7" = "7 дней"; -"day_8" = "8 дней"; -"day_9" = "9 дней"; -"day_10" = "10 дней"; -"day_x" = "%.0f days"; -"more" = "Больше..."; -"all" = "All"; -"longer_history_title" = "Longer history"; -"longer_history_message" = "Ruuvi Station mobile app supports maximum 10 days of history. Ruuvi Cloud subscribers are able to view up to 2 years of historical data using web app at ruuvi.com/station (requires Ruuvi Gateway router)."; -"reading_history_x" = "Bluetooth sync: %.0f"; -"rssi_alert_description" = "Using this alert requires you to be signed in to the app, and that you have claimed the ownership of this sensor and it's in the range of Ruuvi Gateway router. iOS devices are unable to indicate signal strength information of received data sent by Ruuvi sensor when sensor is paired and measurements are being received in the background. Realtime Bluetooth signal strength is shown in the app but doesn't affect this alert."; -"bluetooth_download" = "Bluetooth download"; -"bluetooth_download_description" = "Local sensor data can be downloaded, when you're within its Bluetooth range."; -"download" = "Download"; -"clear_local_history" = "Clear local history"; -"clear_local_history_description" = "Do you want to clear locally stored history data from the app? This won't clear internally stored history from the sensor or history data stored on the Ruuvi Cloud service."; -"TagCharts.FailedToSyncDialog.title" = "Download failed"; -"TagCharts.FailedToSyncDialog.message" = "Bluetooth history download failed. Check that you're within Bluetooth range, your sensor has firmware that supports downloading and that the sensor is not simultaneously connected to another iOS device. Sensor connection is reserved for Ruuvi Station when using connected mode in iOS."; -"TagCharts.TryAgain.title" = "Try again"; -"support" = "Support"; -"full_image_view" = "Full image view"; -"history_view" = "History view"; -"settings_and_alerts" = "Settings & alerts"; -"change_background" = "Change background"; -"check_claim_state" = "Checking claim state"; -"claim_in_progress" = "Claiming in progress"; -"force_claim_sensor" = "Force Claim Sensor"; -"force_claim_sensor_description1" = "This sensor has been claimed by another user. You can force the ownership to your account if you have physical access to this sensor. Each Ruuvi sensor can have only one owner."; -"force_claim_sensor_description2" = "Force Claim is done by using Near-Field Communication (NFC). Make sure NFC is enabled on your mobile device.\n\n\t1. Touch your Ruuvi sensor with your mobile device to start the claiming process.\n\n\t2. When successfully claimed, you will be sent back to Sensor Settings.\n\nIf claiming was unsuccessful or NFC is not available on your device:\n\n\t1. Open the cover of your Ruuvi sensor.\n\n\t2. Locate the round black button (or button \"B\" in case your sensor has 2 buttons) on the white circuit board and press it briefly, then tap on Use BT button to start the claiming process.\n\n\t3. When successfully claimed you will be sent back to Sensor Settings."; -"force_claim" = "Force Claim"; -"claim_wrong_sensor_scanned" = "You are scanning different RuuviTag"; -"view" = "Вид"; -"card_type" = "Card type"; -"image_cards" = "Image cards"; -"simple_cards" = "Simple cards"; -"card_action" = "Card action"; -"open_sensor_view" = "Open sensor view"; -"open_history_view" = "Open history view"; -"change_background_message" = "Select background image. If you're not signed in, you'll lose the image in case of app reinstall."; -"take_photo" = "Take a photo"; -"select_from_gallery" = "Select from phone gallery"; -"select_default_image" = "Select from default images"; -"export_csv_feature_location" = "You can export a sensor's history from its history graph page. Tap the three dots menu icon in the top right corner, and then select \"Export history (csv)\"."; -"low_battery" = "Low battery"; -"change_background_image" = "Изменить фоновое изображение"; -"SignIn.Sync.message" = "Downloading content from the cloud. Please wait."; -"uploading_progress" = "Загружаю: %.0f"; -"Widgets.Unauthorized.Regular.message" = "Sign in to use the widget."; -"Widgets.Unauthorized.Inline.message" = "Sign in to Ruuvi Station"; -"Widgets.Unconfigured.Simple.message" = "Force tap to edit the widget."; -"Widgets.Unconfigured.Rectangular.message" = "Add sensor to use Ruuvi Widget"; -"Widgets.Unconfigured.Inline.message" = "Add sensor to use Ruuvi Widget"; -"Widgets.Unconfigured.Circular.message" = "+Add"; -"Widgets.Select.Sensor.title" = "Selected Ruuvi sensor"; -"Widgets.Sensor.Type.title" = "Selected sensor type"; -"Settings.SectionHeader.General.title" = "ОСНОВНЫЕ"; -"Settings.SectionHeader.Application.title" = "ПРИЛОЖЕНИЕ"; -"empty_chart_message" = "No data available \nin the selected history window."; -"onboarding_measure_your_world" = "Measure Your World"; -"onboarding_with_ruuvi_sensors" = "Let's get to know your Ruuvi Station app."; -"onboarding_swipe_to_continue" = "Swipe to continue →"; -"onboarding_read_sensors_data" = "Read Your Ruuvi Sensors"; -"onboarding_via_bluetooth_or_cloud" = "using Bluetooth or Ruuvi Cloud"; -"onboarding_follow_measurement" = "View all sensors at a glance on your"; -"onboarding_dashboard" = "Dashboard"; -"onboarding_personalise" = "Personalise"; -"onboarding_your_sensors" = "your app with custom names and backgrounds."; -"onboarding_explore_detailed" = "Explore your measurement"; -"onboarding_history" = "History"; -"onboarding_set_custom" = "Set and customise your"; -"onboarding_alerts" = "Alerts"; -"onboarding_share_your_sensors" = "to measure together with your friends and family."; -"onboarding_sharees_can_use" = "Share Sensors"; -"onboarding_handy_widgets" = "Widgets"; -"onboarding_access_widgets" = "Bring your favorite sensors to your Home Screen and Lock Screen as"; -"onboarding_station_web" = "Ruuvi Web App"; -"onboarding_web_pros" = "Large dashboard, multi-year history, email alerts and more on"; -"onboarding_gateway_required" = "A Ruuvi Gateway router is required."; -"onboarding_skip" = "Skip"; -"onboarding_thats_it" = "Almost there!"; -"onboarding_thats_it_already_signed_in" = "Let's get started!"; -"onboarding_go_to_sign_in" = "Ruuvi experience is better when you're signed in. Do it now or continue without cloud features."; -"onboarding_go_to_sign_in_already_signed_in" = "Let's start measuring!"; -"onboarding_continue" = "Next"; -"sign_in_or_create_free_account" = "Sign in or create a free Ruuvi account"; -"to_use_all_app_features" = "No password needed."; -"type_your_email" = "Type your email.."; -"request_code" = "Request Code"; -"no_password_needed" = "A free account will be created for this email if you don't already have one. Only email address is required. We keep your information safe."; -"benefits_sign_in" = "Read more about Ruuvi account benefits or sign in later"; -"use_without_account" = "No thanks, skip"; -"why_should_sign_in" = "Benefits"; -"sensors_ownership_and_settings_stored_in_cloud" = "Signing in to the app has many advantages. Settings will be safely stored to your account:"; -"cloud_stored_ownerships" = "● Sensor ownerships"; -"cloud_stored_names" = "● Custom names"; -"cloud_stored_alerts" = "● Background images"; -"cloud_stored_backgrounds" = "● Alert settings"; -"cloud_stored_calibration" = "● Calibration settings"; -"cloud_stored_sharing" = "● App settings"; -"note" = "Note!"; -"claim_warning" = "Secure the ownership information of your sensors by claiming their ownerships in the app."; -"lets_do_it" = "Let's Sign In"; -"enter_code" = "Enter Code"; -"dashboard_no_sensors_message" = "Seems that you don't have any Ruuvi sensors added yet."; -"dashboard_no_sensors_message_signed_out" = "Вы не вошли в аккаунт.\n\nЕсли у вас уже есть аккаунт Ruuvi и добавлены датчики в него, то они будут автоматичеки синхронизированы с мобильным приложением после того как вы войдете в свой аккаунт."; -"add_a_sensor" = "Add a Sensor"; -"changelog" = "(changelog)"; -"changelog_ios_url" = "https://f.ruuvi.com/t/3192"; -"chart_stat_min" = "Min"; -"chart_stat_max" = "Max"; -"chart_stat_avg" = "Average"; -"shared_to_x" = "Shared to %d/%d"; -"settings_alert_notifications" = "Уведомления о тревогах"; -"settings_alert_sound" = "Alert Sound"; -"settings_alert_sound_description" = "Select push notification alert sound."; -"settings_alerts_footer_description" = "You can also adjust Notification settings under iOS Settings -> Notifications"; -"settings_alerts_footer_description_link_mask" = "iOS Settings -> Notifications"; -"settings_email_alerts" = "Email Alerts"; -"settings_email_alerts_description" = "If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive email alerts by enabling this."; -"settings_push_alerts" = "Push Alerts"; -"settings_push_alerts_description" = "If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive push alerts by enabling this."; -"synchronisation" = "Синхронизация"; -"gatt_sync_description" = "Ruuvi Station downloads the internal history of the sensor for the last 10 days if the measurement history is available.\n\nThe history is downloaded using a Bluetooth connection. Make sure you are near the sensor."; -"do_not_show_again" = "Больше не показывать"; -"sign_in_continue" = "Продолжить"; -"signing_in_is_optional" = "(Авторизация не обязательна)"; -"Defaults.UserAuthorized.title" = "User Authorized"; -"Defaults.DashboardTapActionChart.title" = "Show Chart on Dashboard Card Tap"; -"Defaults.DevServer.title" = "Use Dev Server"; -"Defaults.DevServer.message" = "Changing Ruuvi Cloud endpoint requires signing out from current session and restart the app. Are you sure?"; -"Defaults.ShowEmailAlertsSettings.title" = "Show email alerts settings"; -"Defaults.ShowPushAlertsSettings.title" = "Show push alerts settings"; -"use_nfc" = "Use NFC"; -"use_bluetooth" = "Use BT"; -"sensor_not_found_error" = "Sensor not found. Try again."; -"Defaults.HideNFC.title" = "Hide NFC Option for sensor contest"; -"settings_alert_sound_default" = "System Default"; -"settings_alert_sound_ruuvi_speak" = "Ruuvi Alert"; -"add_with_nfc" = "Add with NFC"; -"sensor_details" = "Sensor Details"; -"add_sensor" = "Add Sensor"; -"copy_mac_address" = "Копировать MAC-адрес"; -"copy_unique_id" = "Скопировать уникальный идентификатор"; -"name" = "Name:"; -"mac_address" = "Mac Address:"; -"go_to_sensor" = "Go to sensor card"; -"unique_id" = "Unique ID:"; -"firmware_version" = "Firmware Version:"; -"Close" = "Закрыть"; -"add_sensor_nfc_df3_error" = "This sensor cannot be added with NFC due to old firmware. Please add the sensor with Bluetooth and update firmware."; -"add_sensor_description" = "Здесь показаны датчики Ruuvi, которые еще не были добавлены в приложение. Нажмите на сенсор, чтобы добавить его."; -"add_sensor_via_nfc" = "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone."; -"unclaim_sensor" = "Unclaim sensor"; -"unclaim" = "Unclaim"; -"unclaim_sensor_description" = "Ownership of this sensor has been claimed to your Ruuvi account. Press Unclaim to remove this sensor's settings and related data from your Ruuvi account."; -"claim_sensor_ownership" = "Заявить о собственности на датчик"; -"do_you_own_sensor" = "Это ваш датчик?"; -"owners_plan" = "Owner's Ruuvi Plan"; -"alert_cloud_connection_title" = "Cloud Connection"; -"alert_cloud_connection_description" = "Alert if sensor data hasn't been updated to the cloud for longer than %d minutes."; -"alert_cloud_connection_dialog_description" = "Enter the desired delay to be used in minutes before alert is triggered. Minimum value is 2 minutes."; -"alert_cloud_connection_dialog_title" = "Set cloud connection alert"; -"rename" = "Переименовать"; -"chart_stat_show" = "Show min/max/avg"; -"chart_stat_hide" = "Hide min/max/avg"; -"settings_alert_limit_notification" = "Ограничить количество уведомлений"; -"settings_alert_limit_notification_description" = "Показывать уведомления не чаще одного раза в час, даже если тревога сработала повторно."; -"share_pending" = "Share pending"; -"share_pending_message" = "Shared successfully! This email address isn't linked to a Ruuvi account yet. An invite to create a free account has been sent. Once created, you'll see it in the sharee listing."; -"dialog_are_you_sure" = "Вы уверены?"; -"dialog_operation_undone" = "This operation cannot be undone."; -"remove_cloud_history_title" = "Remove cloud history"; -"remove_cloud_history_description" = "I also want to remove sensor history data from Ruuvi Cloud."; -"remove_claimed_sensor_description" = "By removing the sensor, your sensor ownership status will be revoked and sensor settings, such as name, background image, calibration settings and alert settings will be removed. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner."; -"remove_shared_sensor_description" = "If you choose to remove this shared sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore.\n\nYou will also lose any related sensor settings like name, background image and alert configurations."; -"remove_local_sensor_description" = "If you choose to remove this sensor, it will result in the deletion of your locally stored measurement history, along with the removal of any related sensor settings like name, background image, calibration, and alert configurations.\n\nYou can add this sensor later again, if needed."; -"activity_saving_to_cloud" = "Saving to cloud...please wait."; -"activity_saving_success" = "Saved successfully."; -"activity_saving_fail" = "Couldn't save changes to cloud."; -"activity_ongoing_generic" = "Please wait..."; -"activity_success_generic" = "Operation successful."; -"activity_failed_generic" = "Operation failed."; -"Devices.tokenId" = "Token Id"; -"UserApiError.ER_GATEWAY_NOT_FOUND" = "Gateway not found"; -"UserApiError.ER_GATEWAY_ALREADY_WHITELISTED" = "Gateway already whitelisted"; -"UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED" = "Gateway status report failed"; -"UserApiError.ER_CONFLICT" = "Data already exists, cannot update"; -"UserApiError.ER_CLAIM_COUNT_REACHED" = "Maximum claim count for the user reached"; -"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Maximum share count for the sensor reached"; -"UserApiError.ER_NO_DATA_TO_SHARE" = "In order to share a sensor, it must have data"; -"UserApiError.ER_SENSOR_ALREADY_REGISTERED" = "The sensor has already been registered"; -"UserApiError.ER_SUBSCRIPTION_CODE_EXISTS" = "Tried to add duplicate subscription to a code"; -"UserApiError.ER_SUBSCRIPTION_CODE_USED" = "Tried to claim already used code"; -"UserApiError.ER_OLD_ENTRY" = "Newer data already exists, cannot update"; -"UserApiError.ER_INVALID_ENUM_VALUE" = "Invalid ENUM value given"; -"UserApiError.OK" = "Operation was successful"; diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/sv.lproj/Localizable.strings b/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/sv.lproj/Localizable.strings deleted file mode 100644 index a6979e528..000000000 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/Resources/sv.lproj/Localizable.strings +++ /dev/null @@ -1,767 +0,0 @@ -// swiftlint:disable all -// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen -"Done" = "Klar"; -"Copy" = "Kopiera"; -"Confirm" = "Bekräfta"; -"Remove" = "Ta bort"; -"N/A" = "-"; -"g" = "g"; -"About.Version.text" = "Version"; -"Background.PresentNotifications.title" = "Visa Notifikationer"; -"Background.KeepConnection.title" = "Håll Anslutningen"; -"Background.Interval.Every.string" = "varje"; -"Background.Interval.Min.string" = "min"; -"Background.readRSSITitle.title" = "Läs RSSI"; -"BluetoothError.disconnected" = "Frånkopplad"; -"Cards.BluetoothDisabledAlert.title" = "Bluetooth är inte aktiverat"; -"Cards.BluetoothDisabledAlert.message" = "Ruuvi Station behöver bluetooth för att fungera. Gå till Inställningar och aktivera Bluetooth."; -"Cards.WebTagAPILimitExcededError.Alert.title" = "För många förfrågningar"; -"Cards.WebTagAPILimitExcededError.Alert.message" = "Försök igen om 5 minutes"; -"Cards.KeepConnectionDialog.message" = "Det ser ut som din Ruuvi enhet har anslutningsbar firmware. Vill du att anslutningen till enheten skall hållas öppen i bakgrunden? Detta gör att histogram och alarm fungerar även om applikationen är minimerad."; -"Cards.KeepConnectionDialog.Dismiss.title" = "Avbryt"; -"Cards.KeepConnectionDialog.KeepConnection.title" = "Håll Anslutningen"; -"Cards.LegacyFirmwareUpdateDialog.message" = "Det verkar som om din sensor använder en gammal programvaruversion. För att komma åt nya funktioner som historikgrafer, alarm och molntjänster krävs en mjukvaruuppdatering."; -"Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message" = "Är du säker? Utan uppdatering kommer du inte att kunna göra anspråk på äganderätten till sensorn, ladda ner historikdiagram och ställa in alarm. Uppdateringen innehåller även buggfixar. Om du avbryter nu kan du starta uppdateringsprocessen igen från sensorns inställningssida."; -"Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title" = "Visa uppdateringsinstruktioner"; -"Cards.Connected.title" = "Ansluten"; -"Cards.Error.ReverseGeocodingFailed.message" = "Det gick inte att ladda data för Virtual Sensor. Gränsen för geokodöverföring överskriden."; -"Cards.UpdatedLabel.NoData.message" = "Ingen data under de senaste 10 dagarna"; -"CoreError.failedToGetPngRepresentation" = "Det gick inte att få PNG-representation"; -"CoreError.failedToGetDocumentsDirectory" = "Det gick inte att hämta bakgrundskatalog"; -"CoreError.failedToGetCurrentLocation" = "Det gick inte att få aktuell plats"; -"CoreError.failedToGetDataFromResponse" = "Svaret innehåller ingen information"; -"CoreError.locationPermissionDenied" = "Saknar rättigheter för Platstjänster"; -"CoreError.locationPermissionNotDetermined" = "Status för platstillstånd kunde inte fastställas"; -"CoreError.objectNotFound" = "Inget objekt hittades"; -"CoreError.objectInvalidated" = "Objekt ogiltigt"; -"CoreError.unableToSendEmail" = "Kunde inte skicka e-post"; -"Defaults.navigationItem.title" = "Standardinställningar"; -"Defaults.WelcomeShown.title" = "Välkomst Visad"; -"Defaults.ChartsSwipeInstructionWasShown.title" = "Histogram Swipe Tips Har Visats"; -"Defaults.Interval.Sec.string" = "sek"; -"Defaults.Interval.Min.string" = "min"; -"Defaults.ConnectionTimeout.title" = "Anslutningstimeout"; -"Defaults.ServiceTimeout.title" = "Service Timeout"; -"Defaults.CardsSwipeHint.title" = "Kort Swipe Tips Har Visats"; -"Defaults.AlertsRepeatInterval.title" = "Alarmintervall"; -"Defaults.WebPullInterval.title" = "Alarmintervall för Virtuella Sensorer"; -"Defaults.PruningOffsetHours.title" = "Beskärning av förskjutningstider"; -"Defaults.Interval.Hour.string" = "h"; -"Defaults.ChartDurationHours.title" = "Historikens längd"; -"Defaults.AppLaunchRequiredForReview.Count.title" = "Appstartsräkning för att be om granskning för första gången"; -"Defaults.AskReviewIfLaunchDivisibleBy.Count.title" = "Fråga granskning om appstart är delbart med"; -"DiscoverTable.SectionTitle.WebTags" = "Virtuella sensorer"; -"DiscoverTable.BluetoothDisabledAlert.title" = "Bluetooth är inte aktiverat"; -"DiscoverTable.BluetoothDisabledAlert.message" = "Ruuvi Station behöver bluetooth för att fungera. Gå till Inställningar och aktivera Bluetooth."; -"DiscoverTable.NavigationItem.title" = "Lägg till en ny sensor"; -"DiscoverTable.GetMoreSensors.button.title" = "Köp Ruuvi-sensorer"; -"DiscoverTable.NoDevicesSection.NotFound.text" = "(Inga sensorer inom Bluetooths räckvidd)"; -"DiscoverTable.NoDevicesSection.BluetoothDisabled.text" = "(Bluetooth är avaktiverat)"; -"DiscoverTable.WebTagsInfoDialog.message" = "Virtuella Sensorer visar offentlig väder data som upprätthålls av lokala väderstationer."; -"DiscoverTable.RuuviDevice.prefix" = "Ruuvi"; -"ErrorPresenterAlert.Error" = "Fel"; -"ErrorPresenterAlert.OK" = "OK"; -"ExpectedError.missingOpenWeatherMapAPIKey" = "OpenWeatherMap API Key saknas. Du kan få en från openweathermap.org website och sätt den sedan i filen station/Classes/Networking/Assembly/Networking.plist"; -"ExpectedError.isAlreadySyncingLogsWithThisTag" = "Applikationen håller redan på att synkronisera logginformation med denna sensor"; -"ExpectedError.failedToDeleteTag" = "Det går inte att ta bort en ansluten enhet som inte kan nås. Kontrollera Bluetooth-anslutningen."; -"ExportService.Date" = "Datum"; -"ExportService.ISO8601" = "ISO8601"; -"ExportService.Temperature" = "Temperatur (%@)"; -"ExportService.Humidity" = "Luftfuktighet (%@)"; -"ExportService.DewPoint" = "Daggpunkt (%@)"; -"ExportService.Pressure" = "Lufttryck (%@)"; -"ExportService.Voltage" = "Spänning (V)"; -"ExportService.MovementCounter" = "Rörelseräknare"; -"ExportService.MeasurementSequenceNumber" = "Mätningssekvensnummer"; -"ExportService.TXPower" = "Sändningseffekt"; -"ForegroundRow.advertisement.section" = "ENHETSMEDDELANDEN"; -"ForegroundRow.advertisement.title" = "Spara enhetsmeddelanden"; -"ForegroundRow.connection.section" = "LOGS"; -"ForegroundRow.connection.title" = "Anslut och synkronisera loggar"; -"Foreground.navigationItem.title" = "Processer"; -"Foreground.Interval.Every.string" = "Varje"; -"Foreground.Interval.Min.string" = "min"; -"ForegroundRow.webTags.title" = "Ladda och spara från webben"; -"ForegroundRow.webTags.section" = "VIRTUELLA SENSORER"; -"Foreground.Interval.All.string" = "Alla"; -"Heartbeat.Interval.Every.string" = "varje"; -"Heartbeat.Interval.Min.string" = "min"; -"Heartbeat.readRSSITitle.title" = "Läs RSSI"; -"Heartbeat.Interval.Sec.string" = "sek"; -"Heartbeat.Interval.All.string" = "Alla"; -"HumidityCalibration.ClearCalibrationConfirmationAlert.title" = "Är du säker?"; -"HumidityCalibration.ClearCalibrationConfirmationAlert.message" = "Du kommer att rensa luftfuktighetskalibreringen. Det går inte att ångra detta. Tryck på \"Bekräfta\" för att fortsätta."; -"HumidityCalibration.CalibrationConfirmationAlert.title" = "Är du säker?"; -"HumidityCalibration.CalibrationConfirmationAlert.message" = "Du kommer att kalibrera luftfuktighetssensorn. Tryck på \"Bekräfta\" för att fortsätta."; -"Language.English" = "English"; -"Language.Finnish" = "Suomi"; -"Language.Russian" = "Русский"; -"Language.Swedish" = "Svenska"; -"Language.French" = "Français"; -"Language.German" = "Deutsch"; -"LocalNotificationsManager.DidConnect.title" = "Ansluten"; -"LocalNotificationsManager.DidDisconnect.title" = "Frånkopplad"; -"LocalNotificationsManager.Disable.button" = "Stäng av"; -"LocalNotificationsManager.LowDewPoint.title" = "För låg Daggpunkt!"; -"LocalNotificationsManager.HighDewPoint.title" = "För hög Daggpunkt!"; -"PermissionPresenter.NoPhotoLibraryAccess.message" = "Ruuvi Station behöver tillgång till dina bilder för att använda den här funktionen."; -"PermissionPresenter.NoCameraAccess.message" = "Ruuvi Station behöver tillgång kameran för att använda den här funktionen."; -"PermissionPresenter.NoLocationAccess.message" = "Ruuvi Station behöver tillgång till din plats för att använda den här funktionen."; -"PermissionPresenter.settings" = "Inställningar"; -"PermissionPresenter.NoPushNotificationsPermission.message" = "Ruuvi Station behöver behörighett ill Push-meddelanden för att aktivera den här funktionen."; -"PhotoPicker.Sheet.message" = "Välj ett foto"; -"PhotoPicker.Sheet.library" = "Välj från bilder"; -"PhotoPicker.Sheet.camera" = "Ta ett foto"; -"Settings.SegmentedControl.Humidity.Relative.title" = "Rel"; -"Settings.SegmentedControl.Humidity.Absolute.title" = "Abs"; -"Settings.SegmentedControl.Humidity.DewPoint.title" = "Dew"; -"Settings.Label.Language.text" = "Språk"; -"Settings.Language.Dialog.title" = "Välj språk"; -"Settings.Language.Dialog.message" = "Öppna inställningar och tryck på Språk för att ändra språket i appen. -Om du inte kan se språkalternativet i inställningarna, se till att du har lagt till minst ett föredraget språk i systeminställningarna: Inställningar -> Allmänt -> Språk och region."; -"Settings.Label.Foreground" = "Processer"; -"Settings.Label.Defaults" = "Standardinställningar"; -"OWMError.failedToParseOpenWeatherMapResponse" = "Det gick inte att tolka Open Weather Map data"; -"OWMError.apiLimitExceeded" = "API gräns överskriden"; -"OWMError.notAHttpResponse" = "Ingen HTTP respons"; -"OWMError.invalidApiKey" = "Ogiltig API Key"; -"TagCharts.NoChartData.text" = "Ingen histogram data"; -"TagCharts.BluetoothDisabledAlert.title" = "Bluetooth är inte aktiverat"; -"TagCharts.BluetoothDisabledAlert.message" = "Ruuvi Station behöver Bluetooth för att lyssna efter sensorer. Gå till Inställningar och aktivera Bluetooth."; -"TagCharts.Clear.title" = "Rensa"; -"TagCharts.SyncConfirmationDialog.title" = "Är du säker?"; -"TagCharts.DeleteHistoryConfirmationDialog.button.delete.title" = "Radera"; -"TagCharts.DeleteHistoryConfirmationDialog.title" = "Är du säker?"; -"TagCharts.Status.Disconnecting" = "Avbryter anslutning..."; -"TagCharts.Status.Success" = "Lyckades"; -"TagCharts.Status.Error" = "Fel"; -"TagSettings.UUID.Alert.title" = "UUID"; -"TagSettings.UpdateFirmware.Alert.title" = "RAWv2-format krävs"; -"TagSettings.UpdateFirmware.Alert.message" = "Värden som saknas kan bara visas i nyare enhetsmjukvara med RAWv2-format."; -"TagSettings.UpdateFirmware.Alert.Buttons.LearnMore.title" = "Läs mer"; -"TagCharts.Dismiss.Alert.message" = "Nedladdning av historik via Bluetooth pågår. Vänta."; -"TagCharts.AbortSync.Alert.message" = "Ibland går nedladdningen av historik långsamt på grund av Bluetooth-anslutningen. Var god vänta ett ögonblick."; -"TagCharts.AbortSync.Button.title" = "Avbryt nedladdning"; -"TagSettings.EmptyValue.sign" = "-"; -"TagSettings.HumidityIsClipped.Alert.title" = "Luftfuktigheten är justerad"; -"TagSettings.HumidityIsClipped.Alert.message" = "Fuktighetsvärdet efter kalibreringen är större än 100%. Detta är inte rimligt, så det maximala värdet visas som 100%."; -"TagSettings.HumidityIsClipped.Alert.Fix.button" = "Fixa"; -"TagSettings.navigationItem.title" = "Inställningar"; -"TagSettings.tagNameTitleLabel.text" = "Sensornamn"; -"TagSettings.humidityTitleLabel.text" = "Luftfuktighet"; -"TagSettings.uuidTitleLabel.text" = "UUID"; -"TagSettings.macAddressTitleLabel.text" = "MAC Adress"; -"TagSettings.dataFormatTitleLabel.text" = "Dataformat"; -"TagSettings.accelerationXTitleLabel.text" = "Acceleration X"; -"TagSettings.accelerationYTitleLabel.text" = "Acceleration Y"; -"TagSettings.accelerationZTitleLabel.text" = "Acceleration Z"; -"TagSettings.txPowerTitleLabel.text" = "Sändningseffekten"; -"TagSettings.mcTitleLabel.text" = "Rörelseräknare"; -"TagSettings.msnTitleLabel.text" = "Mätningssekvensnummer"; -"TagSettings.SectionHeader.Remove.title" = "TA BORT"; -"TagSettings.Label.noValues.text" = "INGA VÄRDEN?"; -"TagSettings.SectionHeader.Calibration.title" = "KALIBRERING"; -"TagSettings.SectionHeader.BTConnection.title" = "BLUETOOTH ANSLUTNING"; -"TagSettings.PairAndBackgroundScan.Unpaired.title" = "Para ihop och använd bakgrundsskanning"; -"TagSettings.PairAndBackgroundScan.Pairing.title" = "Anslutning till sensorn"; -"TagSettings.PairAndBackgroundScan.Paired.title" = "Parat och bakgrundsskanning på"; -"TagSettings.PairAndBackgroundScan.description" = "Alarm är inte tillgängliga via Bluetooth-anslutning om bakgrundsskanning inte är aktiverad. Endast en iOS-enhet kan paras ihop med Ruuvi-sensorn åt gången."; -"TagSettings.PairError.CloudMode.description" = "Sensorn kan inte anslutas till via Bluetooth när molnläget är aktivt. Du kan återaktivera Bluetooth-anslutning för molnsensorerna genom att inaktivera molnläget i appinställningarna."; -"TagSettings.PairError.Timeout.description" = "Anslutningstimeout. Parningen misslyckades. Försök igen."; -"TagSettings.dataSourceTitleLabel.text" = "Data Mottagen Via"; -"TagSettings.DataSource.Heartbeat.title" = "Hjärtslag"; -"TagSettings.DataSource.Advertisement.title" = "Advertisement"; -"TagSettings.DataSource.Network.title" = "Moln"; -"TagSettings.Label.disabled.text" = "INAKTIVERAD?"; -"TagSettings.AlertsAreDisabled.Dialog.BothNotConnectedAndNoPNPermission.message" = "Alarm är inaktiverade eftersom enheten inte är ansluten och behörigheten att se Push-meddelanden saknas. Anslut först till enheten."; -"TagSettings.AlertsAreDisabled.Dialog.Connect.title" = "Anslut"; -"TagSettings.AlertsAreDisabled.Dialog.NotConnected.message" = "Alarm är inaktiverade eftersom du inte är ansluten till enheten."; -"TagSettings.Alert.CustomDescription.placeholder" = "Redigera beskrivningen..."; -"TagSettings.Alert.CustomDescription.title" = "Ställ in ett alarm-meddelande"; -"TagSettings.Alerts.Humidity.description" = "Alarmera om mindre än %.0f eller mer än %.0f"; -"TagSettings.Alerts.DewPoint.description" = "Alarmera om mindre än %.0f eller mer än %.0f"; -"TagSettings.dewPointAlertTitleLabel.text" = "Daggpunkt"; -"TagSettings.Alerts.Pressure.description" = "Alarmera om mindre än %.0f eller mer än %.0f"; -"TagSettings.Alerts.Connection.description" = "Alarmera vid anslutning/frånkoppling"; -"TagSettings.ConnectionAlert.title" = "Anslutning"; -"TagSettings.SectionHeader.Firmware.title" = "Programvara"; -"TagSettings.Firmware.CurrentVersion" = "Nuvarande version"; -"TagSettings.Firmware.CurrentVersion.VeryOld" = "Väldigt gammal"; -"TagSettings.Firmware.UpdateFirmware" = "Uppdatera"; -"UnexpectedError.callbackErrorAndResultAreNil" = "Både resultatet och felmeddelande är nil"; -"UnexpectedError.callerDeinitedDuringOperation" = "Uppringare avallokerad under operation"; -"UnexpectedError.failedToReverseGeocodeCoordinate" = "Det gick inte att få geokoordinaterna för platsen"; -"UnexpectedError.failedToFindRuuviTag" = "Hittade inte sensorn"; -"UnexpectedError.failedToFindLogsForTheTag" = "Ingen sensorlogginformation hittades"; -"UnexpectedError.viewModelUUIDIsNil" = "View Model UUID är nil"; -"UnexpectedError.attemptToReadDataFromRealmWithoutLUID" = "Försökte läsa data från Realm utan LUID"; -"UnexpectedError.failedToFindVirtualTag" = "Hittade inte den virtuella sensorn"; -"HumidityUnit.Dew.title" = "Daggpunkt (%@)"; -"WebTagLocationSource.current" = "Din plats"; -"WebTagLocationSource.manual" = "Välj från karta"; -"WebTagSettings.confirmTagRemovalDialog.title" = "Ta bort virtuell sensor"; -"WebTagSettings.confirmTagRemovalDialog.message" = "Är du säker på att du vill ta bort den här virtuella sensorn?"; -"WebTagSettings.Location.Current" = "Din plats"; -"WebTagSettings.confirmClearLocationDialog.title" = "Renas Plats"; -"WebTagSettings.confirmClearLocationDialog.message" = "Är du säker på att du vill rensa plats för den här virtuella sensorn? Nuvarande plats kommer att användas istället."; -"WebTagSettings.navigationItem.title" = "Inställningar"; -"WebTagSettings.Label.BackgroundImage.text" = "BAKGRUNDSBILD"; -"WebTagSettings.Label.Location.text" = "Plats"; -"WebTagSettings.Button.Remove.title" = "TA BORT"; -"WebTagSettings.SectionHeader.Name.title" = "NAMN"; -"WebTagSettings.SectionHeader.MoreInfo.title" = "MER INFO"; -"WebTagSettings.Alerts.Temperature.description" = "Alarmera om mindre än %.0f eller mer än %.0f"; -"WebTagSettings.Alerts.Off" = "Av"; -"WebTagSettings.temperatureAlertTitleLabel.text" = "Temperatur"; -"WebTagSettings.Label.disabled.text" = "INAKTIVERAD?"; -"WebTagSettings.Label.alerts.text" = "ALARM"; -"WebTagSettings.AlertsAreDisabled.Dialog.BothNoPNPermissionAndNoLocationPermission.message" = "Den virtuella sensorns alarmfunktion kräver rätt att visa både platsinformation och push-meddelanden. Kontrollera applikationsinställningarna."; -"WebTagSettings.AlertsAreDisabled.Dialog.Settings.title" = "Inställningar"; -"WebTagSettings.AirHumidityAlert.title" = "Luftfuktighet"; -"WebTagSettings.Alerts.Humidity.description" = "Alarmera om mindre än %.0f eller mer än %.0f"; -"WebTagSettings.Alerts.DewPoint.description" = "Alarmera om mindre än %.0f eller mer än %.0f"; -"WebTagSettings.dewPointAlertTitleLabel.text" = "Daggpunkt"; -"WebTagSettings.PressureAlert.title" = "Luftfuktighet"; -"WebTagSettings.Alerts.Pressure.description" = "Alarmera om mindre än %.0f eller mer än %.0f"; -"Welcome.description.text" = "Klicka på Skanna för att hitta sensorer i närheten."; -"ExportService.AccelerationX" = "Acceleration X"; -"ExportService.AccelerationY" = "Acceleration Y"; -"ExportService.AccelerationZ" = "Acceleration Z"; -"DiscoverTable.SectionTitle.Devices" = "Ruuvi sensorer i närheten"; -"ago" = "sedan"; -"TagSettings.MovementAlert.title" = "Rörelse"; -"TagSettings.Alerts.Movement.description" = "Alarmera om rörelse upptäcks"; -"LocalNotificationsManager.HighHumidity.title" = "För hög Luftfuktighet!"; -"LocalNotificationsManager.LowHumidity.title" = "För låg Luftfuktighet!"; -"LocalNotificationsManager.DidMove.title" = "Rörelse upptäckt!"; -"LocalNotificationsManager.HighPressure.title" = "För högt Lufttryck!"; -"LocalNotificationsManager.LowPressure.title" = "För lågt Lufttryck!"; -"LocalNotificationsManager.HighSignal.title" = "För hög signalstyrka!"; -"LocalNotificationsManager.LowSignal.title" = "För låg signalstyrka!"; -"LocalNotificationsManager.HighTemperature.title" = "För hög temperatur!"; -"LocalNotificationsManager.LowTemperature.title" = "För låg temperatur!"; -"TagSettings.Alerts.Off" = "Av"; -"TagSettings.Alerts.Temperature.description" = "Alarmera när mindre än %.0f eller mer än %.0f"; -"TagSettings.Label.alerts.text" = "Alarm"; -"TagSettings.backgroundImageLabel.text" = "Bakgrundsbild"; -"TagSettings.batteryVoltageTitleLabel.text" = "Batterispänning"; -"HumidityCalibration.Button.Calibrate.title" = "Kalibrera"; -"HumidityCalibration.lastCalibrationDate.format" = "Kalibrerad: %@"; -"HumidityCalibration.Description.text" = "För att mäta relativ luftfuktighet så exakt som möjligt rekommenderar vi att kalibrera sensorn med natriumklorid (salt). Se videor om hur du enkelt gör det hemma."; -"HumidityCalibration.Label.note.text" = "Observera att kalibreringsdata lagras lokalt i din mobila enhet. Om du tar bort Ruuvi Station appen och installerar den igen behöver du kalibrera på nytt."; -"HumidityCalibration.VideoTutorials.link" = "Se videor"; -"Cancel" = "Avbryt"; -"HumidityCalibration.Button.Clear.title" = "Rensa"; -"TagCharts.DeleteHistoryConfirmationDialog.message" = "Radera historisk data från appen?"; -"HumidityCalibration.Button.Close.title" = "Stäng"; -"TagCharts.Status.Serving" = "Synkroniserar..."; -"TagCharts.Status.Connecting" = "Ansluter..."; -"TagSettings.ConnectStatus.Disconnected" = "Frånkopplad"; -"TagCharts.Export.title" = "EXPORTERA"; -"h" = "h"; -"About.AboutHelp.contents" = "Ruuvi Station är en lättanvänd applikation som låter dig övervaka mätdata från Ruuvi-sensorer."; -"About.AboutHelp.header" = "Om / Hjälp"; -"About.TagsCount.text" = "Tillagda sensorer: %d"; -"About.MeasurementsCount.text" = "Sparade mätningar: %d"; -"About.DatabaseSize.text" = "Databasens storlek: %@"; -"About.More.contents" = "Ruuvis hemsida: ruuvi.com\nRuuvi Forum: f.ruuvi.com\nRuuvi Blog: ruuvi.com/blog\nRuuvi Twitter: twitter.com/ruuvicom"; -"About.More.header" = "Läs mer"; -"About.OpenSource.contents" = "Precis som Ruuvi-sensorer är Ruuvi Station-appar öppen källkod. Följ utvecklingen och bidra på: github.com/ruuvi"; -"About.OpenSource.header" = "Öppen källkod"; -"About.OperationsManual.contents" = "Kom igång med Ruuvi Stations mobilapplikation med våra onlineguider: ruuvi.com/support/station-mobile"; -"About.OperationsManual.header" = "Bruksanvisning"; -"About.Privacy.contents" = "Användning av applikationen kräver godkännande av användarvillkoren\nruuvi.com/terms"; -"About.Privacy.header" = "Integritetspolicy"; -"About.Troubleshooting.contents" = "Hitta hjälp med att använda Ruuvi Station-appar, Ruuvi-produkter och Ruuvi Cloud-tjänst från vårt supportcenter: ruuvi.com/support"; -"About.Troubleshooting.header" = "Felsökning"; -"hours" = "Timmar"; -"Interval.Days.string" = "Dagar"; -"TagSettings.AirHumidityAlert.title" = "Luftfuktighet (%@)"; -"HumidityUnit.gm3.title" = "Absolut (g/m³)"; -"g/m³" = "g/m³"; -"HumidityUnit.Percent.title" = "Relativ (%)"; -"TagSettings.Mac.Alert.title" = "MAC Adress"; -"Menu.Label.AboutHelp.text" = "Om / Hjälp"; -"Menu.Label.AddAnNewSensor.text" = "Lägg till en ny Sensor"; -"Menu.Label.AppSettings.text" = "App Inställningar"; -"Menu.Label.GetMoreSensors.text" = "Köp Ruuvi-sensorer"; -"Ruuvi.BuySensors.URL.IOS" = "https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Ruuvi.BuySensors.Menu.URL.IOS" = "https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios"; -"Menu.Label.BuyRuuviGateway.text" = "Köp Ruuvi Gateway"; -"Menu.BuyGateway.URL.IOS" = "https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Menu.Label.WhatToMeasure.text" = "Vad ska man mäta med Ruuvi?"; -"Menu.Measure.URL.IOS" = "https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"Menu.Label.Feedback.text" = "Skicka Feedback"; -"Menu.Label.MyRuuviAccount.text" = "Mitt Ruuvi-konto"; -"min" = "min"; -"minutes" = "Minuter"; -"TagSettings.Label.moreInfo.text" = "Mer info"; -"TagSettings.SectionHeader.Name.title" = "NAMN"; -"No" = "Nej"; -"OK" = "OK"; -"Cards.NoSensors.title" = "Inga sensorer har lags till\nTryck här för att lägga till sensorer"; -"TagSettings.PressureAlert.title" = "Lufttryck (%@)"; -"UnitPressure.hectopascal.title" = "Hektopascal (hPa)"; -"hPa" = "hPa"; -"UnitPressure.inchOfMercury.title" = "Tum kvicksilver (inHg)"; -"UnitPressure.millimetreOfMercury.title" = "Millimeter kvicksilver (mmHg)"; -"TagCharts.Status.ReadingHistory" = "Läser historik"; -"TagSettings.rssiTitleLabel.text" = "Signalstyrka (RSSI)"; -"signal_strength_dbm" = "Signalstyrka (dBm)"; -"s" = "s"; -"Welcome.scan.title" = "SKANNA"; -"Background.Interval.Sec.string" = "sek"; -"Settings.navigationItem.title" = "Inställningar"; -"Settings.BackgroundScanning.title" = "Bakgrundsskanning"; -"Settings.BackgroundScanning.Footer.message" = "Viktiga anteckningar: Loggning av Bluetooth-bakgrundshistorik och Bluetooth-alarm fungerar endast när bakgrundsskanning är aktiverad. Om du inaktiverar bakgrundsskanning kommer alla parade Ruuvi-sensorer att automatiskt avparas och du måste para dem igen från deras inställningssidor."; -"Settings.BackgroundScanning.interval" = "Dataloggningsintervall"; -"Settings.Label.Chart" = "Historik"; -"ChartSettings.AllPoints.title" = "Visa alla mätningar"; -"ChartSettings.AllPoints.description" = "Den här funktionen kan göra appen laddar historik långsammare."; -"ChartSettings.DrawDots.title" = "Visa datapunkter"; -"ChartSettings.DrawDots.description" = "Datapunkter gör det lättare att utforska lagrad historikinformation."; -"Defaults.ChartIntervalSeconds.title" = "Historikens noggrannhet"; -"ChartSettings.Duration.title" = "Historik"; -"ChartSettings.Duration.description" = "Ange hur långt bak historiken skall visas, mellan 1 - 10 dagar."; -"Settings.Label.HumidityUnit.text" = "Luftfuktighetsenhet"; -"Settings.Label.Temperature" = "Temperatur"; -"Settings.Label.Humidity" = "Fuktighet"; -"Settings.Label.Pressure" = "Lufttryck"; -"Settings.ChooseHumidityUnit.text" = "Välj den fuktighetsenhet som du vill ska visas."; -"Settings.Label.PressureUnit.text" = "Tryckenhet"; -"Settings.ChoosePressureUnit.text" = "Välj den tryckenhet du vill ska visas."; -"Settings.Label.TemperatureUnit.text" = "Temperaturenhet"; -"Settings.ChooseTemperatureUnit.text" = "Välj den temperaturenhet som du vill ska visas."; -"dBm" = "dBm"; -"TagCharts.Sync.title" = "Synk"; -"TagCharts.SyncConfirmationDialog.message" = "Ladda ner historik-data från sensorn?"; -"WebTagSettings.Label.TagName.text" = "Sensornamn"; -"TagSettings.confirmTagRemovalDialog.title" = "Ta bort sensor"; -"TagSettings.confirmTagRemovalDialog.message" = "Är du säker på att du vill ta bort den här sensorn?"; -"TagSettings.temperatureAlertTitleLabel.text" = "Temperatur (%@)"; -"TemperatureUnit.Celsius.title" = "Celsius (℃)"; -"ºC" = "°C"; -"TemperatureUnit.Fahrenheit.title" = "Fahrenheit (℉)"; -"ºF" = "°F"; -"TemperatureUnit.Kelvin.title" = "Kelvin (K)"; -"Updated" = "Uppdaterad"; -"V" = "V"; -"RuuviOnboard.Welcome.title" = "Det här kan Ruuvi Station göra för dig."; -"RuuviOnboard.Measure.title" = "Mät förhållandena i din miljö: temperatur, luftfuktighet och lufttryck."; -"RuuviOnboard.Access.title" = "Visa sensordata i realtid eller granska historisk data som är lagrad på enheten."; -"RuuviOnboard.Alerts.title" = "Ställ in alarm och få notiser om dem."; -"RuuviOnboard.Cloud.title" = "Logga in för att få tillgång till alla appens funktioner."; -"RuuviOnboard.Cloud.subtitle" = "Verifiera ditt sensorägande med ett gratis Ruuvi Cloud-konto."; -"RuuviOnboard.Cloud.subtitle.signed" = "Bra! Du är redan inloggad!"; -"RuuviOnboard.Start.title" = "Tryck på SCAN för att se sensorerna i närheten."; -"Yes" = "Ja"; -"LocalNotificationsManager.Mute.button" = "Pausa alarmet i en timme"; -"Defaults.AlertsMuteInterval.title" = "Alarmavstängningsintervall"; -"SignIn.Title.text" = "Logga in"; -"Menu.SignOut.text" = "Logga ut"; -"RuuviOnboard.Cloud.Benefits.message" = "Fördelar:\n\n ● Sensornamn, bakgrundsbilder, kalibrering och larminformation från en säker molntjänst\n\n ● Läs sensorinformation på distans online ( kräver Ruuvi Gateway-router)\n\n ● Dela sensorer med vänner och familj (kräver Ruuvi Gateway)\n\n ● Upp till 2 års historik från station.ruuvi.com (kräver Ruuvi Gateway)"; -"RuuviOnboard.Cloud.Details.title" = "Info"; -"ruuvi_cloud" = "Ruuvi Cloud"; -"RuuviOnboard.Cloud.Skip.title" = "Är du säker på att du vill hoppa över inloggningen?"; -"RuuviOnboard.Cloud.Skip.Yes.title" = "Ja, hoppa över"; -"RuuviOnboard.Cloud.Skip.GoBack.title" = "Gå tillbaka"; -"SignIn.EmailPlaceholder" = "E-post"; -"SignIn.RequestCode" = "Begär en inloggningskod"; -"SignIn.SubmitCode" = "Skicka"; -"SignIn.EmailSent" = "E-post skickat"; -"SignIn.CheckMailbox" = "Vi har skickat ett engångslösenord till din e-post %@. Logga in genom att ange den här:"; -"SignIn.CodeHint" = "Kod"; -"TagsManagerPresenter.SignOutConfirmAlert.Message" = "Sensorer som du har verifierat äganderätten till på inställningssidan tas automatiskt bort från appen när du loggar ut. Sensordata hämtas från molnet igen om du loggar in med samma e-postadress.\n\nÄr du säker på att du vill logga ut? "; -"TagSettings.ClaimTagButton.Claim" = "Bekräfta ägandet"; -"TagSettings.ShareButton" = "Dela"; -"Syncing..." = "Synkroniserar..."; -"Synchronized" = "Synkronisering klar"; -"TagChartsPresenter.NumberOfPointsSynchronizedOverNetwork" = "Synkroniserat: %@"; -"MenuTableViewController.None" = "ingen"; -"MenuTableViewController.User" = "Användare: %@"; -"ShareViewController.Title" = "Dela sensor"; -"ShareViewController.Description" = "Du kan dela sensorn med vänner och familj om den är inom räckhåll för en Ruuvi Gateway.\n\nMottagaren meddelas via e-post. Om mottagaren inte har ett Ruuvi-konto skapas ett gratis Ruuvi-konto automatiskt vid första inloggningen.\n\nObservera att sensorns anpassade namn och bakgrundsbild delas. Namnet och bildsynkroniseringen sker endast vid en gång, efteråt kan det anpassas av mottagaren. Kalibreringsvärden (om sådana finns) synkroniseras automatiskt och mottagaren ser alltid de korrigerade värdena."; -"ShareViewController.addFriend.Title" = "Lägg till vän"; -"ShareViewController.emailTextField.placeholder" = "Ange e-postadress"; -"ShareViewController.sharedEmails.Title" = "Du har använt %d/%d av det maximala antalet delningar för denna sensor. Sensorn delas med följande användare:"; -"Share.Send.button" = "Skicka"; -"SharePresenter.UnshareSensor.Message" = "Vill du sluta dela sensorn med %@?"; -"TagSettings.SectionHeader.NetworkInfo.title" = "NÄTVERKSINFO"; -"TagSettings.NetworkInfo.Owner" = "Ägare"; -"Menu.RuuviNetworkStatus.text" = "Ruuvi cloud status"; -"SignIn.TitleLabel.text" = "Logga in till\nRuuvi\nStation"; -"SignIn.SubtitleLabel.text" = "Dra full nytta av Ruuvi Station! Logga in eller skapa ett nytt Ruuvi-konto genom att ange din e-postadress."; -"SignIn.VerificationCodePlaceholder" = "verifieringskod i format CJSM"; -"UserApiError.ER_FORBIDDEN" = "Förbjuden"; -"UserApiError.ER_UNAUTHORIZED" = "Obehörig"; -"UserApiError.ER_INTERNAL" = "Internt fel"; -"UserApiError.ER_INVALID_FORMAT" = "Ogiltigt förfrågningsformat"; -"UserApiError.ER_USER_NOT_FOUND" = "Användaren hittades inte"; -"UserApiError.ER_SENSOR_NOT_FOUND" = "Sensorn hittades inte"; -"UserApiError.ER_TOKEN_EXPIRED" = "Nyckeln har upphört att gälla"; -"UserApiError.ER_SUBSCRIPTION_NOT_FOUND" = "Prenumerationen hittades inte"; -"UserApiError.ER_SHARE_COUNT_REACHED" = "Maximal delning har överskridits"; -"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Du kan inte dela sensorn med flera användare"; -"UserApiError.ER_NO_DATA_TO_SHARE" = "För att dela sensorn måste du ha en Ruuvi Gateway router i närheten av sensorn"; -"UserApiError.ER_SENSOR_ALREADY_SHARED" = "Sensorn är redan delad"; -"UserApiError.ER_SENSOR_ALREADY_CLAIMED" = "Sensorn ägs redan av %@"; -"UserApiError.ER_SENSOR_ALREADY_CLAIMED_NO_EMAIL" = "Sensorn har redan en ägare"; -"UserApiError.ER_UNABLE_TO_SEND_EMAIL" = "Kunde inte skicka e-post"; -"UserApiError.ER_MISSING_ARGUMENT" = "Argument saknas"; -"UserApiError.ER_INVALID_DENSITY_MODE" = "Ogiltig densitet"; -"UserApiError.ER_INVALID_SORT_MODE" = "Ogiltig sortering"; -"UserApiError.ER_INVALID_TIME_RANGE" = "Ogiltigt intervall"; -"UserApiError.ER_INVALID_EMAIL_ADDRESS" = "Ogiltig e-postaddress"; -"UserApiError.ER_INVALID_MAC_ADDRESS" = "Ogiltig MAC-address"; -"UserApiError.ER_SUB_DATA_STORAGE_ERROR" = "Datalagringsfel"; -"UserApiError.ER_SUB_NO_USER" = "Ingen användare"; -"UserApiError.ER_THROTTLED" = "För många förfrågningar"; -"OffsetCorrection.CalibrationDescription.text" = "Vid normal användning är det inte nödvändigt att kalibrera sensorerna.\n\nOm du är en avancerad användare och vill kalibrera manuellt är det möjligt att göra det.\n\nKalibreringstips finns på ruuvi.com/support"; -"OffsetCorrection.Dialog.Calibration.ClearConfirm" = "Renas kalibereringsinställningar?"; -"OffsetCorrection.Dialog.Calibration.Title" = "Kalibreringsinställningar"; -"OffsetCorrection.Dialog.Calibration.EnterTemperature" = "Ange temperaturen som förväntas av sensorn just nu (%@): "; -"OffsetCorrection.Dialog.Calibration.EnterPressure" = "Ange lufttrycket som förväntas av sensorn just nu (%@): "; -"OffsetCorrection.Dialog.Calibration.EnterHumidity" = "Ange fuktigheten som förväntas av sensorn just nu (%@): "; -"OffsetCorrection.OriginalValue.title" = "Ursprungligt värde"; -"OffsetCorrection.CorrectedValue.title" = "Korrigerat värde"; -"OffsetCorrection.Temperature.Title" = "Temperatur offset"; -"OffsetCorrection.Humidity.Title" = "Fuktighet offset"; -"OffsetCorrection.Pressure.Title" = "Lufttryck offset"; -"OffsetCorrection.Calibrate.button" = "Kalibrering"; -"TagSettings.SectionHeader.OffsetCorrection.Title" = "KALIBRERING"; -"TagSettings.OffsetCorrection.Temperature" = "Temperatur"; -"TagSettings.OffsetCorrection.Humidity" = "Fuktighet"; -"TagSettings.OffsetCorrection.Pressure" = "Lufttryck"; -"PhotoPicker.Sheet.files" = "Välj från filer"; -"SignIn.EnterVerificationCode" = "Ange verifieringskod"; -"UnexpectedError.failedToFindOrGenerateBackgroundImage" = "Det gick inte att hitta eller skapa bakgrundsbild"; -"UnexpectedError.bothLuidAndMacAreNil" = "Både lokal och MAC-ID saknas"; -"RuuviCloudApiError.emptyResponse" = "Tomt svar"; -"RuuviCloudApiError.failedToGetDataFromResponse" = "Svaret innehåller ingen information"; -"RuuviCloudApiError.unexpectedHTTPStatusCode" = "Oväntad HTTP-statuskod"; -"RuuviCloudError.NotAuthorized" = "Inte behörig"; -"RuuviLocalError.failedToGetJpegRepresentation" = "Det gick inte att få JPG-representation"; -"RuuviLocalError.failedToGetDocumentsDirectory" = "Det gick inte att hämta bakgrundskatalog"; -"RuuviPersistenceError.failedToFindRuuviTag" = "Hittade inte sensorn"; -"RuuviServiceError.pictureUrlIsNil" = "Bild URL saknas"; -"RuuviServiceError.macIdIsNil" = "MAC-id saknas"; -"network_sharing_disabled" = "Endast sensorer inom räckhåll av din Ruuvi Gateway kan delas."; -"RuuviServiceError.bothLuidAndMacAreNil" = "Både lokal och MAC-ID saknas"; -"RuuviServiceError.failedToParseNetworkResponse" = "Det gick inte att tolka svaret."; -"RuuviServiceError.failedToFindOrGenerateBackgroundImage" = "Det gick inte att hitta eller skapa bakgrundsbild"; -"RuuviServiceError.failedToGetJpegRepresentation" = "Det gick inte att få JPG-representation"; -"UpdateFirmware.Title.text" = "Uppdatera programvara"; -"UpdateFirmware.Download.header" = "LADDA NER NYASTE PROGRAMVARA"; -"UpdateFirmware.Download.content" = "Ladda ner det senaste tillgängliga programvarupaketet innan du startar uppgraderingen. Den senaste versionen kan laddas ner från ruuvi.com/software-update"; -"UpdateFirmware.SetDfu.header" = "STÄLL IN RUUVI TAG I DFU-LÄGE"; -"UpdateFirmware.SetDfu.content" = "Öppna sensorn genom att dra upp den med fingrarna eller försiktigt med en platt skruvmejsel.\n\nStäll RuuviTag i uppdateringsläge genom att hålla ned knappen B och trycka på återställningsknappen R. Den röda indikatorlampan tänds och fortsätter att lysa. Om din enhet bara har en knapp, håll den intryckt i 10 sekunder för att komma in i uppdateringsläge."; -"UpdateFirmware.NextButton.title" = "NÄSTA"; -"DfuDevicesScanner.Title.text" = "Enheter"; -"DfuDevicesScanner.Description.text" = "Hitta ock välj sensor \"RuuviBoot\""; -"DfuDevicesScanner.NoDevice.text" = "(Inga sensorer inom Bluetooths räckvidd)"; -"DfuDevicesScanner.BluetoothDisabled.text" = "(Bluetooth är avaktiverat)"; -"DfuDevicesScanner.BluetoothDisabledAlert.title" = "Bluetooth är inte aktiverat"; -"DfuDevicesScanner.BluetoothDisabledAlert.message" = "Ruuvi Station behöver bluetooth för att fungera. Gå till Inställningar och aktivera Bluetooth."; -"DfuFlash.Title.text" = "DFU-uppdatering"; -"DfuFlash.Progress.text" = "Framsteg"; -"DfuFlash.Step.text" = "Steg"; -"DfuFlash.Steps.PackageSelection.text" = "Välj uppdateringspaket"; -"DfuFlash.Steps.ReadyForUpload.text" = "Redo för uppladdning"; -"DfuFlash.Steps.Uploading.text" = "Uppladdning"; -"DfuFlash.Steps.Completed.text" = "Klar"; -"DfuFlash.OpenDocumentPicker.title" = "ÖPPET DOKUMENTVÄLJARE"; -"DfuFlash.FirmwareSelectionGuide.text" = "Hitta ZIP-filen som du laddade ner."; -"DfuFlash.Firmware.FileName.text" = "Filnamn"; -"DfuFlash.Firmware.Parts.text" = "Delar"; -"DfuFlash.Firmware.Size.text" = "Storlek"; -"DfuFlash.Firmware.SoftDeviceSize.text" = "Soft Device storlek"; -"DfuFlash.Firmware.BootloaderSize.text" = "Bootloader storlek"; -"DfuFlash.Cancel.text" = "AVBRYT"; -"DfuFlash.Start.text" = "Börja"; -"DfuFlash.Finish.text" = "KLAR"; -"DfuFlash.FinishGuide.text" = "Uppdateringsprocessen har slutförts. -RuuviTag-sensorn är redo att användas!"; -"DfuFlash.CancelAlert.text" = "Är du säker på att du vill avbryta uppdateringsprocessen?"; -"RuuviDfuError.invalidFirmwareFile" = "Ogiltig programvaruuppdateringsfil"; -"DFUUIView.navigationTitle" = "Firmware Uppdatering"; -"DFUUIView.latestTitle" = "Senast tillgängliga Ruuvi firmwareversion:"; -"DFUUIView.currentTitle" = "Nuvarande version:"; -"DFUUIView.notReportingDescription" = "Din sensor rapporterar inte sin nuvarande firmwareversion. Det betyder att den förmodligen har en gammal firmwareversion och uppdatering rekommenderas."; -"DFUUIView.alreadyOnLatest" = "Du har redan den senaste firmwareversionen, ingen uppdatering behövs"; -"DFUUIView.startUpdateProcess" = "Starta uppdateringsprocessen"; -"DFUUIView.downloadingTitle" = "Hämtar senaste firmware.."; -"DFUUIView.prepareTitle" = "Förbered din sensor"; -"DFUUIView.openCoverTitle" = "1. Öppna locket på din Ruuvi sensor"; -"DFUUIView.locateBootButtonTitle" = "2. Leta reda på små runda svarta knappar på det vita kretskortet; äldre Ruuvi-sensorer har 2 knappar märkta “R“ och “B“ medan nyare har bara en knapp utan etikett."; -"DFUUIView.setUpdatingModeTitle" = "3. Lägg sensorn i uppdateringsläge"; -"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. Om din sensor har två knappar: håll knappen “B” intryckt medan du trycker en gång på “R”. Släpp knapp “B”."; -"DFUUIView.toBootModeOneButtonDescription" = "3.2. Om din sensor har en knapp, håll knappen intryckt i 10 sekunder."; -"DFUUIView.toBootModeSuccessTitle" = "4. Uppgraderingsläget lyckades om den röda lysdioden på kretskortet lyser och knappens text i appen har bytts till “Starta uppdatering“."; -"DFUUIView.updatingTitle" = "Uppdaterar..."; -"DFUUIView.searchingTitle" = "Söker efter en sensor"; -"DFUUIView.startTitle" = "Starta uppdatering"; -"DFUUIView.doNotCloseTitle" = "Stäng inte appen eller stäng av sensorn under uppdateringen."; -"DFUUIView.successfulTitle" = "Uppdateringen lyckades"; -"DFUUIView.DBMigration.Error.message" = "Uppdateringen lyckades, men ett oväntat databasmigreringsfel inträffade. För att fortsätta använda den här sensorn, ta bort den från appen och lägg sedan till den igen."; -"RuuviDfuError.failedToConstructUUID" = "Det gick inte att skapa UUID"; -"SignIn.EmailMismatch.Alert.message" = "Oj, du har begärt koden för %@, men använde koden för %@. Kontrollera att du använder koden för %@"; -"SignIn.EmailMissing.Alert.message" = "Oj, e-postadressen du har använt för att få koden sparades inte. Försök att logga in igen."; -"TagSettings.RemoveThisSensor.title" = "Ta bort sensorn"; -"Share.Success.message" = "Delningen lyckades"; -"TagSettings.SectionHeader.General.title" = "Allmänt"; -"TagSettings.Shared.title" = "Delad"; -"TagSettings.NotShared.title" = "Inte delad"; -"Owner.title" = "Bekräfta ägandet"; -"Owner.ClaimOwnership.button" = "Bekräfta Ägandet"; -"Owner.Claim.description" = "Äger du den här sensorn? Bekräfta ägandet och så läggs sensorn till på ditt Ruuvi-konto. Varje Ruuvi-sensor kan bara ha en ägare. För att göra anspråk på äganderätt måste du vara inloggad.\n\nFördelar:\n\n ● Sensornamn, bakgrundsbilder, kalibrering och larminformation från en säker molntjänst\n\n ● Läs sensorinformation på distans online ( kräver Ruuvi Gateway-router)\n\n ● Dela sensorer med vänner och familj (kräver Ruuvi Gateway)\n\n ● Upp till 2 års historik från station.ruuvi.com (kräver Ruuvi Gateway)"; -"TagSettings.confirmTagUnclaimAndRemoveDialog.message" = "Om du tar bort sensorn upphör ägarskapet. Vem som helst kan göra anspråk på ägandet av sensorn efter borttagning. Varje Ruuvi-sensor kan bara ha en ägare."; -"TagSettings.confirmSharedTagRemovalDialog.message" = "Om du tar bort sensorn så meddelas ägaren till sensorn och du kan inte komma åt den längre."; -"TagSettings.General.Owner.none" = "Ingen"; -"TagSettings.Share.title" = "Dela"; -"Menu.LoggedIn.title" = "Inloggad:"; -"Interval.Day.string" = "Dag"; -"hour" = "Timme"; -"TagSettings.tagNameTitleLabel.rename.text" = "Dina sensorer kommer att vara i alfabetisk ordning."; -"On" = "På"; -"Off" = "Av"; -"DFUUIView.lowBattery.warning.message" = "Sensorns batterispänning är låg och uppgraderingsprocessen kan misslyckas. Vi rekommenderar att du byter ut batteriet innan du uppdaterar programvaran."; -"alert_notification_humidity_high_threshold" = "Luftfuktigheten är över %@"; -"alert_notification_humidity_low_threshold" = "Luftfuktigheten är under %@"; -"alert_notification_pressure_high_threshold" = "Lufttrycket är över %@"; -"alert_notification_pressure_low_threshold" = "Lufttrycket är under %@"; -"alert_notification_rssi_high_threshold" = "Signalstyrkan är över %@"; -"alert_notification_rssi_low_threshold" = "Signalstyrkan är under %@"; -"alert_notification_temperature_high_threshold" = "Temperaturen är över %@"; -"alert_notification_temperature_low_threshold" = "Temperaturen är under %@"; -"Cards.Alert.AlreadyLoggedIn.message" = "Användare %@ är redan inloggad. Om du vill använda ett annat konto, logga ut först och försök sedan igen."; -"Settings.Label.CloudMode" = "Molnläge"; -"Settings.Label.CloudMode.description" = "Uppdatera närliggande molnregistrerade sensorer endast från molnet genom att inte lyssna på deras Bluetooth-meddelanden och endast ta emot varningar via e-post. Kräver en Ruuvi Gateway."; -"internet_connection_problem" = "Internetanslutningsproblem"; -"Widgets.Loading.message" = "laddar..."; -"Cards.Movements.title" = "rörelser"; -"TagSettings.BatteryStatusLabel.Replace.message" = "Låg batterinivå"; -"TagSettings.BatteryStatusLabel.Ok.message" = "Batteri OK"; -"Widgets.Description.message" = "Skapa widgets av dina favorit Ruuvi-sensorer. Widgetdatan kommer från Ruuvi Cloud och kräver en Ruuvi Gateway-router."; -"settings_appearance" = "Utseende"; -"app_theme" = "App tema"; -"follow_system_theme" = "Systemtema"; -"dark_theme" = "Mörkt tema"; -"light_theme" = "Ljust tema"; -"Settings.Temperature.Resolution.title" = "Temperaturupplösning"; -"Settings.Humidity.Resolution.title" = "Fuktighetsupplösning"; -"Settings.Pressure.Resolution.title" = "Tryckupplösning"; -"Settings.Measurement.Resolution.description" = "Välj hur exakt du vill se sensorernas livemätvärden i appen. Den här inställningen påverkar inte histogram eller varningar."; -"Settings.Measurement.Unit.title" = "Enhet"; -"Settings.Measurement.Resolution.title" = "Upplösning"; -"MyRuuvi.Settings.DeleteAccount.title" = "Radera konto"; -"MyRuuvi.Settings.DeleteAccount.Confirmation.message" = "En bekräftelse skickas till din e-post. För att fortsätta med raderingen, kontrollera din inkorg och följ instruktionerna."; -"TagSettings.Alert.SetTemperature.title" = "Ställ in temperaturalarm"; -"TagSettings.Alert.SetHumidity.title" = "Ställ in fuktighetsalarm"; -"TagSettings.Alert.SetPressure.title" = "Ställ in lufttryckssalarm"; -"TagSettings.Alert.SetRSSI.title" = "Ställ in signalstyrkealarm"; -"TagSettings.AlertSettings.Dialog.Min" = "Min (%.0f)"; -"TagSettings.AlertSettings.Dialog.Max" = "Max (%.0f)"; -"export_history" = "Exportera historik (csv)"; -"clear_view" = "Töm historikvy"; -"day_1" = "1 dag"; -"day_2" = "2 dagar"; -"day_3" = "3 dagar"; -"day_4" = "4 dagar"; -"day_5" = "5 dagar"; -"day_6" = "6 dagar"; -"day_7" = "7 dagar"; -"day_8" = "8 dagar"; -"day_9" = "9 dagar"; -"day_10" = "10 dagar"; -"day_x" = "%.0f dagar"; -"more" = "Mer..."; -"all" = "Allt"; -"longer_history_title" = "Längre historik"; -"longer_history_message" = "Ruuvi Station mobilapp stöder högst 10 dagars historik. Ruuvi Cloud-prenumeranter kan se upp till 2 års historisk data med hjälp av webbappen på ruuvi.com/station (kräver Ruuvi Gateway-router)."; -"reading_history_x" = "Läser Bluetooth: %.0f"; -"rssi_alert_description" = "För att använda denna avisering måste du vara inloggad i appen, att du har tagit ägandeskap av den här sensorn och att den är inom räckhåll för Ruuvi Gateway-routern. IOS-enheter kan inte visa signalstyrka för mottagna data som skickas av Ruuvi-sensorn när sensorn är parat och mätningar mottas i bakgrunden. Realtids Bluetooth-signalstyrka visas i appen men påverkar inte denna avisering."; -"bluetooth_download" = "Bluetooth-nedladdning"; -"bluetooth_download_description" = "Lokal sensordata kan laddas ner när du är inom Bluetooth-räckvidd."; -"download" = "Ladda ner"; -"clear_local_history" = "Rensa lokal historik"; -"clear_local_history_description" = "Vill du rensa lokalt lagrad historisk data från appen? Detta kommer inte att rensa internt lagrad historik i sensorer eller historisk data lagrad i Ruuvi Cloud-tjänst."; -"TagCharts.FailedToSyncDialog.title" = "Nedladdning misslyckad"; -"TagCharts.FailedToSyncDialog.message" = "Nedladdning av Bluetooth-historik misslyckades. Kontrollera att du är inom Bluetooth-räckvidd, att din sensor har firmware som stöder nedladdning och att sensorn inte samtidigt är ansluten till en annan iOS-enhet. Sensoranslutning är reserverad för Ruuvi Station vid användning av anslutet läge i iOS."; -"TagCharts.TryAgain.title" = "Försök igen"; -"support" = "Support"; -"full_image_view" = "Bildvy"; -"history_view" = "Historikvy"; -"settings_and_alerts" = "Inställningar & alarm"; -"change_background" = "Byt bakgrund"; -"check_claim_state" = "Kontrollerar anspråkstillstånd"; -"claim_in_progress" = "Anspråk pågår"; -"force_claim_sensor" = "Tvinga fram anspråk"; -"force_claim_sensor_description1" = "Den här sensorn ägs av en annan användare. Du kan tvinga ägandeskap till ditt konto om du har fysisk tillgång till den här sensorn. Varje Ruuvi-sensor kan bara ha en ägare."; -"force_claim_sensor_description2" = "Tvingat anspråk görs genom att använda närfältskommunikation (NFC). Se till att NFC är aktiverat på din mobil.\n\n\t1. Rör din Ruuvi-givare med din mobila enhet för att starta kravprocessen.\n\n\t2. När det lyckats förs du tillbaka till sensorinställningar.\n\nOm det misslyckades eller om NFC inte är tillgängligt på din enhet:\n\n\t1. Öppna locket på sensorn. Leta upp den runda svarta knappen (eller knapp B om din sensor har två knappar)på det vita kretskortet, tryck först kort på knappen och tryck sedan på knappen Använd BT på sidan för att starta processen.\n\n\t3. När det har gått igenom framgångsrikt förs du tillbaka till sensorinställningar."; -"force_claim" = "Tvinga fram anspråk"; -"claim_wrong_sensor_scanned" = "Du skannar fel RuuviTag"; -"view" = "Vy"; -"card_type" = "Kort typ"; -"image_cards" = "Bildkort"; -"simple_cards" = "Enkla kort"; -"card_action" = "Kortåtgärd"; -"open_sensor_view" = "Öppna sensorvy"; -"open_history_view" = "Öppna historikvy"; -"change_background_message" = "Välj bakgrundsbild. Om du inte är inloggad kommer du att förlora bilden vid appominstallation."; -"take_photo" = "Ta ett foto"; -"select_from_gallery" = "Välj från telefonens galleri"; -"select_default_image" = "Välj bland standardbilder"; -"export_csv_feature_location" = "Du kan exportera sensorns historik från dess historiagramsida. Tryck på tre punkters menyikon i övre högra hörnet, och välj sedan \"Exportera historik (csv)\"."; -"low_battery" = "Låg batterinivå"; -"change_background_image" = "Ändra bakgrundsbild"; -"SignIn.Sync.message" = "Laddar ner data från molnet. Vänta en stund."; -"uploading_progress" = "Uppladdning: %.0f"; -"Widgets.Unauthorized.Regular.message" = "Logga in för att använda widgeten."; -"Widgets.Unauthorized.Inline.message" = "Logga in till Ruuvi Station"; -"Widgets.Unconfigured.Simple.message" = "Tryck och håll ned för att redigera widgeten."; -"Widgets.Unconfigured.Rectangular.message" = "Välj sensorn som ska visas i Ruuvi widgeten"; -"Widgets.Unconfigured.Inline.message" = "Välj sensorn som ska visas i Ruuvi widgeten"; -"Widgets.Unconfigured.Circular.message" = "+Lägg till"; -"Widgets.Select.Sensor.title" = "Vald Ruuvi sensor"; -"Widgets.Sensor.Type.title" = "Vald sensortyp"; -"Settings.SectionHeader.General.title" = "ALLMÄNT"; -"Settings.SectionHeader.Application.title" = "APPLIKATION"; -"empty_chart_message" = "Ingen data tillgänglig \ni det valda historikfönstret."; -"onboarding_measure_your_world" = "Measure Your World"; -"onboarding_with_ruuvi_sensors" = "Lär känna din Ruuvi Station -applikation."; -"onboarding_swipe_to_continue" = "Dra för att fortsätta →"; -"onboarding_read_sensors_data" = "Läs dina Ruuvi-sensorer"; -"onboarding_via_bluetooth_or_cloud" = "med Bluetooth eller Ruuvi Cloud"; -"onboarding_follow_measurement" = "Se alla sensorer med en blick på din"; -"onboarding_dashboard" = "instrumentpanel"; -"onboarding_personalise" = "Anpassa"; -"onboarding_your_sensors" = "din app med anpassade namn och bakgrunder."; -"onboarding_explore_detailed" = "Utforska din"; -"onboarding_history" = "mäthistorik"; -"onboarding_set_custom" = "Ställ in och anpassa dina"; -"onboarding_alerts" = "varningar"; -"onboarding_share_your_sensors" = "för att mäta tillsammans med dina vänner och familj."; -"onboarding_sharees_can_use" = "Dela sensorer"; -"onboarding_handy_widgets" = "widgets"; -"onboarding_access_widgets" = "Ta med dina favoritsensorer till din startskärm och låsskärm som"; -"onboarding_station_web" = "Ruuvi webbappen"; -"onboarding_web_pros" = "Stor instrumentpanel, flerårig historik, e-postvarningar och mer på"; -"onboarding_gateway_required" = "En Ruuvi Gateway -router krävs."; -"onboarding_skip" = "Hoppa över"; -"onboarding_thats_it" = "Nästan där!"; -"onboarding_thats_it_already_signed_in" = "Låt oss börja!"; -"onboarding_go_to_sign_in" = "Ruuvi-upplevelsen är bättre när du är inloggad. Gör det nu eller fortsätt utan molnfunktioner."; -"onboarding_go_to_sign_in_already_signed_in" = "Låt oss börja mäta!"; -"onboarding_continue" = "Nästa"; -"sign_in_or_create_free_account" = "Logga in eller skapa ett gratis Ruuvi-konto"; -"to_use_all_app_features" = "Inget lösenord behövs."; -"type_your_email" = "Skriv in din e-postadress..."; -"request_code" = "Begär en inloggningskod"; -"no_password_needed" = "Ett gratiskonto kommer att skapas för denna e-post om du inte redan har ett. Endast e-postadress krävs. Vi håller din information säker."; -"benefits_sign_in" = "Läs mer om Ruuvi-kontoförmåner eller logga in senare"; -"use_without_account" = "Nej tack, hoppa över"; -"why_should_sign_in" = "Fördelar"; -"sensors_ownership_and_settings_stored_in_cloud" = "Att logga in på appen har många fördelar. Inställningarna kommer att lagras säkert på ditt konto:"; -"cloud_stored_ownerships" = "● Sensorns ägarskap"; -"cloud_stored_names" = "● Sensornamn"; -"cloud_stored_alerts" = "● Bakgrundsbilder"; -"cloud_stored_backgrounds" = "● Varningsinställningar"; -"cloud_stored_calibration" = "● Kalibreringsinställningar"; -"cloud_stored_sharing" = "● App inställningar"; -"note" = "Obs!"; -"claim_warning" = "Säkra ägarinformationen för dina sensorer genom att göra anspråk på deras äganderätt i appen."; -"lets_do_it" = "Gå till inloggning"; -"enter_code" = "Ange kod"; -"dashboard_no_sensors_message" = "Det verkar som om du inte har några Ruuvi-sensorer tillagda ännu."; -"dashboard_no_sensors_message_signed_out" = "Du är inte inloggad.\n\nOm du har ett konto och redan har lagt till Ruuvi-sensorer till det, synkroniseras de automatiskt med Ruuvi Stations mobilapp när du loggar in."; -"add_a_sensor" = "Lägg till en sensor"; -"changelog" = "(ändringslogg)"; -"changelog_ios_url" = "https://f.ruuvi.com/t/3192"; -"chart_stat_min" = "Min"; -"chart_stat_max" = "Max"; -"chart_stat_avg" = "Medelvärde"; -"shared_to_x" = "Delad %d/%d"; -"settings_alert_notifications" = "Varningsmeddelanden"; -"settings_alert_sound" = "Varningsljud"; -"settings_alert_sound_description" = "Välj varningsljudet för push-meddelandet."; -"settings_alerts_footer_description" = "Du kan även justera Aviseringsinställningar under iOS-inställningar -> Aviseringar"; -"settings_alerts_footer_description_link_mask" = "iOS-inställningar -> Aviseringar"; -"settings_email_alerts" = "E-postvarningar"; -"settings_email_alerts_description" = "Om du använder Ruuvi Cloud och Ruuvi Gateway kommer du att kunna ta emot e-postvarningar genom att aktivera detta."; -"settings_push_alerts" = "Push-varningar"; -"settings_push_alerts_description" = "Om du använder Ruuvi Cloud och Ruuvi Gateway kommer du att kunna ta emot push-varningar genom att aktivera detta."; -"synchronisation" = "Synkronisering"; -"gatt_sync_description" = "Ruuvi Station laddar ner sensorns interna historik för de senaste 10 dagarna om mäthistoriken är tillgänglig.\n\nHistorien laddas ner med en Bluetooth-anslutning. Se till att du är nära sensorn."; -"do_not_show_again" = "Visa inte detta igen"; -"sign_in_continue" = "Fortsätta"; -"signing_in_is_optional" = "(Inloggning är inte obligatoriskt)"; -"Defaults.UserAuthorized.title" = "Användare auktoriserad"; -"Defaults.DashboardTapActionChart.title" = "Tryck på instrumentpanelskortet för att visa diagrammet"; -"Defaults.DevServer.title" = "Använd dev-server"; -"Defaults.DevServer.message" = "För att ändra Ruuvi Cloud -slutpunkt måste du logga ut från den aktuella sessionen och starta om appen. Är du säker?"; -"Defaults.ShowEmailAlertsSettings.title" = "Visa inställningar för e-postvarningar"; -"Defaults.ShowPushAlertsSettings.title" = "Visa push-varningsinställningar"; -"use_nfc" = "Använd NFC"; -"use_bluetooth" = "Använd BT"; -"sensor_not_found_error" = "Sensorn hittades inte. Försök igen."; -"Defaults.HideNFC.title" = "Dölj NFC-alternativet från påtvingat ägarbyte"; -"settings_alert_sound_default" = "Systemfel"; -"settings_alert_sound_ruuvi_speak" = "Ruuvi larm"; -"add_with_nfc" = "Lägg till med NFC"; -"sensor_details" = "Sensordetaljer"; -"add_sensor" = "Lägg till sensor"; -"copy_mac_address" = "Kopiera MAC-adress"; -"copy_unique_id" = "Kopiera unikt ID"; -"name" = "Namn:"; -"mac_address" = "MAC-adress:"; -"go_to_sensor" = "Gå till sensorkortet"; -"unique_id" = "Unikt ID:"; -"firmware_version" = "Firmwareversion:"; -"Close" = "Stäng"; -"add_sensor_nfc_df3_error" = "Denna sensor kan inte läggas till med NFC på grund av gammal firmware. Lägg till sensorn med Bluetooth och uppdatera firmware."; -"add_sensor_description" = "Den här sidan visar närliggande Ruuvi-sensorer som ännu inte har lagts till i appen. Tryck på en sensor för att lägga till den."; -"add_sensor_via_nfc" = "Alternativt kan du lägga till en sensor med NFC genom att välja Lägg till med NFC och trycka på den med din telefon."; -"unclaim_sensor" = "Ta bort äganderätten"; -"unclaim" = "Ta bort anspråk"; -"unclaim_sensor_description" = "Äganderätten till denna sensor har gjorts anspråk på ditt Ruuvi-konto. Tryck på Unclaim för att ta bort sensorns inställningar och relaterade data från ditt Ruuvi-konto."; -"claim_sensor_ownership" = "Gör anspråk på sensorägande"; -"do_you_own_sensor" = "Äger du denna sensor?"; -"owners_plan" = "Ägarens Ruuvi-plan"; -"alert_cloud_connection_title" = "Molnuppkoppling"; -"alert_cloud_connection_description" = "Varning om sensordata inte har uppdaterats till molnet på mer än %d minuter."; -"alert_cloud_connection_dialog_description" = "Ange önskad fördröjning som ska användas i minuter innan larmet utlöses. Minsta värde är 2 minuter."; -"alert_cloud_connection_dialog_title" = "Ställ in molnanslutningsvarning"; -"rename" = "Döp om"; -"chart_stat_show" = "Visa min/max/genomsnitt"; -"chart_stat_hide" = "Dölj min/max/genomsnitt"; -"settings_alert_limit_notification" = "Begränsa varningsmeddelanden"; -"settings_alert_limit_notification_description" = "Utlös Bluetooth-varningsavisering endast en gång i timmen även om varningen återutlöstes."; -"share_pending" = "Delning pågår"; -"share_pending_message" = "Delat framgångsrikt! Den här e-postadressen är ännu inte kopplad till ett Ruuvi-konto. En inbjudan att skapa ett gratis konto har skickats. När kontot har skapats kommer du att se det i delningslistan."; -"dialog_are_you_sure" = "Är du säker?"; -"dialog_operation_undone" = "Denna åtgärd kan inte ångras."; -"remove_cloud_history_title" = "Ta bort molnhistorik"; -"remove_cloud_history_description" = "Jag vill också ta bort sensorhistorikdata från Ruuvi Cloud."; -"remove_claimed_sensor_description" = "Genom att ta bort sensorn kommer den inte längre synas i ditt konto och sensorinställningar som namn, bakgrundsbild, kalibreringsinställningar och larminställningar kommer att tas bort. Efter borttagning kan någon annan ta ägande om sensorn. Varje Ruuvi-sensor kan bara ha en ägare."; -"remove_shared_sensor_description" = "Om du tar bort den här delade sensorn kommer sensorns ägare att meddelas om borttagningen och du kommer inte längre att kunna använda sensorn.\n\nDu kommer också att förlora alla sensorinställningar som är kopplade till denna sensor, t.ex. namn, bakgrundsbild och ställ in alarm."; -"remove_local_sensor_description" = "Om du väljer att ta bort den här sensorn kommer det att resultera i radering av din lokalt lagrade mäthistorik, tillsammans med att eventuella relaterade sensorinställningar som namn, bakgrundsbild, kalibrering och varningskonfigurationer tas bort.\n\nDu kan lägga till denna sensor senare igen, om det behövs."; -"activity_saving_to_cloud" = "Sparar till molnet... vänligen vänta."; -"activity_saving_success" = "Sparad."; -"activity_saving_fail" = "Det gick inte att spara ändringar i molnet."; -"activity_ongoing_generic" = "Vänta..."; -"activity_success_generic" = "Operationen lyckades."; -"activity_failed_generic" = "Operationen misslyckades."; -"Devices.tokenId" = "Token Id"; -"UserApiError.ER_GATEWAY_NOT_FOUND" = "Gateway not found"; -"UserApiError.ER_GATEWAY_ALREADY_WHITELISTED" = "Gateway already whitelisted"; -"UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED" = "Gateway status report failed"; -"UserApiError.ER_CONFLICT" = "Data already exists, cannot update"; -"UserApiError.ER_CLAIM_COUNT_REACHED" = "Maximum claim count for the user reached"; -"UserApiError.ER_SENSOR_SHARE_COUNT_REACHED" = "Maximum share count for the sensor reached"; -"UserApiError.ER_NO_DATA_TO_SHARE" = "In order to share a sensor, it must have data"; -"UserApiError.ER_SENSOR_ALREADY_REGISTERED" = "The sensor has already been registered"; -"UserApiError.ER_SUBSCRIPTION_CODE_EXISTS" = "Tried to add duplicate subscription to a code"; -"UserApiError.ER_SUBSCRIPTION_CODE_USED" = "Tried to claim already used code"; -"UserApiError.ER_OLD_ENTRY" = "Newer data already exists, cannot update"; -"UserApiError.ER_INVALID_ENUM_VALUE" = "Invalid ENUM value given"; -"UserApiError.OK" = "Operation was successful"; diff --git a/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift b/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift deleted file mode 100644 index 3d3ae71ea..000000000 --- a/Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift +++ /dev/null @@ -1,2659 +0,0 @@ -// swiftlint:disable all -// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen - -import Foundation - -// swiftlint:disable superfluous_disable_command file_length implicit_return prefer_self_in_static_references - -// MARK: - Strings - -// swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length -// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces -public enum RuuviLocalization { - /// Operation failed. - public static let activityFailedGeneric = RuuviLocalization.tr("Localizable", "activity_failed_generic", fallback: "Operation failed.") - /// Please wait... - public static let activityOngoingGeneric = RuuviLocalization.tr("Localizable", "activity_ongoing_generic", fallback: "Please wait...") - /// Couldn't save changes to cloud. - public static let activitySavingFail = RuuviLocalization.tr("Localizable", "activity_saving_fail", fallback: "Couldn't save changes to cloud.") - /// Saved successfully. - public static let activitySavingSuccess = RuuviLocalization.tr("Localizable", "activity_saving_success", fallback: "Saved successfully.") - /// Saving to cloud...please wait. - public static let activitySavingToCloud = RuuviLocalization.tr("Localizable", "activity_saving_to_cloud", fallback: "Saving to cloud...please wait.") - /// Operation successful. - public static let activitySuccessGeneric = RuuviLocalization.tr("Localizable", "activity_success_generic", fallback: "Operation successful.") - /// Add a Sensor - public static let addASensor = RuuviLocalization.tr("Localizable", "add_a_sensor", fallback: "Add a Sensor") - /// Add Sensor - public static let addSensor = RuuviLocalization.tr("Localizable", "add_sensor", fallback: "Add Sensor") - /// This page shows nearby Ruuvi sensors not yet added to the app. Tap a sensor to add it. - public static let addSensorDescription = RuuviLocalization.tr("Localizable", "add_sensor_description", fallback: "This page shows nearby Ruuvi sensors not yet added to the app. Tap a sensor to add it.") - /// This sensor cannot be added with NFC due to old firmware. Please add the sensor with Bluetooth and update firmware. - public static let addSensorNfcDf3Error = RuuviLocalization.tr("Localizable", "add_sensor_nfc_df3_error", fallback: "This sensor cannot be added with NFC due to old firmware. Please add the sensor with Bluetooth and update firmware.") - /// Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone. - public static let addSensorViaNfc = RuuviLocalization.tr("Localizable", "add_sensor_via_nfc", fallback: "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone.") - /// Add with NFC - public static let addWithNfc = RuuviLocalization.tr("Localizable", "add_with_nfc", fallback: "Add with NFC") - /// ago - public static let ago = RuuviLocalization.tr("Localizable", "ago", fallback: "ago") - /// Alert if sensor data hasn't been updated to the cloud for longer than %d minutes. - public static func alertCloudConnectionDescription(_ p1: Int) -> String { - RuuviLocalization.tr("Localizable", "alert_cloud_connection_description", p1, fallback: "Alert if sensor data hasn't been updated to the cloud for longer than %d minutes.") - } - /// Enter the desired delay to be used in minutes before alert is triggered. Minimum value is 2 minutes. - public static let alertCloudConnectionDialogDescription = RuuviLocalization.tr("Localizable", "alert_cloud_connection_dialog_description", fallback: "Enter the desired delay to be used in minutes before alert is triggered. Minimum value is 2 minutes.") - /// Set cloud connection alert - public static let alertCloudConnectionDialogTitle = RuuviLocalization.tr("Localizable", "alert_cloud_connection_dialog_title", fallback: "Set cloud connection alert") - /// Cloud Connection - public static let alertCloudConnectionTitle = RuuviLocalization.tr("Localizable", "alert_cloud_connection_title", fallback: "Cloud Connection") - /// Air Humidity is above %@ - public static func alertNotificationHumidityHighThreshold(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "alert_notification_humidity_high_threshold", String(describing: p1), fallback: "Air Humidity is above %@") - } - /// Air Humidity is below %@ - public static func alertNotificationHumidityLowThreshold(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "alert_notification_humidity_low_threshold", String(describing: p1), fallback: "Air Humidity is below %@") - } - /// Air Pressure is above %@ - public static func alertNotificationPressureHighThreshold(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "alert_notification_pressure_high_threshold", String(describing: p1), fallback: "Air Pressure is above %@") - } - /// Air Pressure is below %@ - public static func alertNotificationPressureLowThreshold(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "alert_notification_pressure_low_threshold", String(describing: p1), fallback: "Air Pressure is below %@") - } - /// Signal strength is above %@ - public static func alertNotificationRssiHighThreshold(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "alert_notification_rssi_high_threshold", String(describing: p1), fallback: "Signal strength is above %@") - } - /// Signal strength is below %@ - public static func alertNotificationRssiLowThreshold(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "alert_notification_rssi_low_threshold", String(describing: p1), fallback: "Signal strength is below %@") - } - /// Temperature is above %@ - public static func alertNotificationTemperatureHighThreshold(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "alert_notification_temperature_high_threshold", String(describing: p1), fallback: "Temperature is above %@") - } - /// Temperature is below %@ - public static func alertNotificationTemperatureLowThreshold(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "alert_notification_temperature_low_threshold", String(describing: p1), fallback: "Temperature is below %@") - } - /// All - public static let all = RuuviLocalization.tr("Localizable", "all", fallback: "All") - /// App Theme - public static let appTheme = RuuviLocalization.tr("Localizable", "app_theme", fallback: "App Theme") - /// Read more about Ruuvi account benefits or sign in later - public static let benefitsSignIn = RuuviLocalization.tr("Localizable", "benefits_sign_in", fallback: "Read more about Ruuvi account benefits or sign in later") - /// Bluetooth download - public static let bluetoothDownload = RuuviLocalization.tr("Localizable", "bluetooth_download", fallback: "Bluetooth download") - /// Local sensor data can be downloaded, when you're within its Bluetooth range. - public static let bluetoothDownloadDescription = RuuviLocalization.tr("Localizable", "bluetooth_download_description", fallback: "Local sensor data can be downloaded, when you're within its Bluetooth range.") - /// Cancel - public static let cancel = RuuviLocalization.tr("Localizable", "Cancel", fallback: "Cancel") - /// Card action - public static let cardAction = RuuviLocalization.tr("Localizable", "card_action", fallback: "Card action") - /// Card type - public static let cardType = RuuviLocalization.tr("Localizable", "card_type", fallback: "Card type") - /// Change background - public static let changeBackground = RuuviLocalization.tr("Localizable", "change_background", fallback: "Change background") - /// Change background image - public static let changeBackgroundImage = RuuviLocalization.tr("Localizable", "change_background_image", fallback: "Change background image") - /// Select background image. If you're not signed in, you'll lose the image in case of app reinstall. - public static let changeBackgroundMessage = RuuviLocalization.tr("Localizable", "change_background_message", fallback: "Select background image. If you're not signed in, you'll lose the image in case of app reinstall.") - /// (changelog) - public static let changelog = RuuviLocalization.tr("Localizable", "changelog", fallback: "(changelog)") - /// https://f.ruuvi.com/t/3192 - public static let changelogIosUrl = RuuviLocalization.tr("Localizable", "changelog_ios_url", fallback: "https://f.ruuvi.com/t/3192") - /// Average - public static let chartStatAvg = RuuviLocalization.tr("Localizable", "chart_stat_avg", fallback: "Average") - /// Hide min/max/avg - public static let chartStatHide = RuuviLocalization.tr("Localizable", "chart_stat_hide", fallback: "Hide min/max/avg") - /// Max - public static let chartStatMax = RuuviLocalization.tr("Localizable", "chart_stat_max", fallback: "Max") - /// Min - public static let chartStatMin = RuuviLocalization.tr("Localizable", "chart_stat_min", fallback: "Min") - /// Show min/max/avg - public static let chartStatShow = RuuviLocalization.tr("Localizable", "chart_stat_show", fallback: "Show min/max/avg") - /// Checking claim state - public static let checkClaimState = RuuviLocalization.tr("Localizable", "check_claim_state", fallback: "Checking claim state") - /// Claiming in progress - public static let claimInProgress = RuuviLocalization.tr("Localizable", "claim_in_progress", fallback: "Claiming in progress") - /// Claim sensor ownership - public static let claimSensorOwnership = RuuviLocalization.tr("Localizable", "claim_sensor_ownership", fallback: "Claim sensor ownership") - /// Secure the ownership information of your sensors by claiming their ownerships in the app. - public static let claimWarning = RuuviLocalization.tr("Localizable", "claim_warning", fallback: "Secure the ownership information of your sensors by claiming their ownerships in the app.") - /// You are scanning different RuuviTag - public static let claimWrongSensorScanned = RuuviLocalization.tr("Localizable", "claim_wrong_sensor_scanned", fallback: "You are scanning different RuuviTag") - /// Clear local history - public static let clearLocalHistory = RuuviLocalization.tr("Localizable", "clear_local_history", fallback: "Clear local history") - /// Do you want to clear locally stored history data from the app? This won't clear internally stored history from the sensor or history data stored on the Ruuvi Cloud service. - public static let clearLocalHistoryDescription = RuuviLocalization.tr("Localizable", "clear_local_history_description", fallback: "Do you want to clear locally stored history data from the app? This won't clear internally stored history from the sensor or history data stored on the Ruuvi Cloud service.") - /// Clear history view - public static let clearView = RuuviLocalization.tr("Localizable", "clear_view", fallback: "Clear history view") - /// Close - public static let close = RuuviLocalization.tr("Localizable", "Close", fallback: "Close") - /// ● Background images - public static let cloudStoredAlerts = RuuviLocalization.tr("Localizable", "cloud_stored_alerts", fallback: "● Background images") - /// ● Alert settings - public static let cloudStoredBackgrounds = RuuviLocalization.tr("Localizable", "cloud_stored_backgrounds", fallback: "● Alert settings") - /// ● Calibration settings - public static let cloudStoredCalibration = RuuviLocalization.tr("Localizable", "cloud_stored_calibration", fallback: "● Calibration settings") - /// ● Custom names - public static let cloudStoredNames = RuuviLocalization.tr("Localizable", "cloud_stored_names", fallback: "● Custom names") - /// ● Sensor ownerships - public static let cloudStoredOwnerships = RuuviLocalization.tr("Localizable", "cloud_stored_ownerships", fallback: "● Sensor ownerships") - /// ● App settings - public static let cloudStoredSharing = RuuviLocalization.tr("Localizable", "cloud_stored_sharing", fallback: "● App settings") - /// Confirm - public static let confirm = RuuviLocalization.tr("Localizable", "Confirm", fallback: "Confirm") - /// Copy - public static let copy = RuuviLocalization.tr("Localizable", "Copy", fallback: "Copy") - /// Copy MAC Address - public static let copyMacAddress = RuuviLocalization.tr("Localizable", "copy_mac_address", fallback: "Copy MAC Address") - /// Copy Unique ID - public static let copyUniqueId = RuuviLocalization.tr("Localizable", "copy_unique_id", fallback: "Copy Unique ID") - /// Dark theme - public static let darkTheme = RuuviLocalization.tr("Localizable", "dark_theme", fallback: "Dark theme") - /// Seems that you don't have any Ruuvi sensors added yet. - public static let dashboardNoSensorsMessage = RuuviLocalization.tr("Localizable", "dashboard_no_sensors_message", fallback: "Seems that you don't have any Ruuvi sensors added yet.") - /// You are not signed in. - /// - /// If you have an account and have already added Ruuvi sensors to it, they will automatically synchronise with Ruuvi Station mobile app when you sign in. - public static let dashboardNoSensorsMessageSignedOut = RuuviLocalization.tr("Localizable", "dashboard_no_sensors_message_signed_out", fallback: "You are not signed in.\n\nIf you have an account and have already added Ruuvi sensors to it, they will automatically synchronise with Ruuvi Station mobile app when you sign in.") - /// 1 day - public static let day1 = RuuviLocalization.tr("Localizable", "day_1", fallback: "1 day") - /// 10 days - public static let day10 = RuuviLocalization.tr("Localizable", "day_10", fallback: "10 days") - /// 2 days - public static let day2 = RuuviLocalization.tr("Localizable", "day_2", fallback: "2 days") - /// 3 days - public static let day3 = RuuviLocalization.tr("Localizable", "day_3", fallback: "3 days") - /// 4 days - public static let day4 = RuuviLocalization.tr("Localizable", "day_4", fallback: "4 days") - /// 5 days - public static let day5 = RuuviLocalization.tr("Localizable", "day_5", fallback: "5 days") - /// 6 days - public static let day6 = RuuviLocalization.tr("Localizable", "day_6", fallback: "6 days") - /// 7 days - public static let day7 = RuuviLocalization.tr("Localizable", "day_7", fallback: "7 days") - /// 8 days - public static let day8 = RuuviLocalization.tr("Localizable", "day_8", fallback: "8 days") - /// 9 days - public static let day9 = RuuviLocalization.tr("Localizable", "day_9", fallback: "9 days") - /// %.0f days - public static func dayX(_ p1: Float) -> String { - RuuviLocalization.tr("Localizable", "day_x", p1, fallback: "%.0f days") - } - /// dBm - public static let dBm = RuuviLocalization.tr("Localizable", "dBm", fallback: "dBm") - /// Are you sure? - public static let dialogAreYouSure = RuuviLocalization.tr("Localizable", "dialog_are_you_sure", fallback: "Are you sure?") - /// This operation cannot be undone. - public static let dialogOperationUndone = RuuviLocalization.tr("Localizable", "dialog_operation_undone", fallback: "This operation cannot be undone.") - /// Don't show this again - public static let doNotShowAgain = RuuviLocalization.tr("Localizable", "do_not_show_again", fallback: "Don't show this again") - /// Do you own this sensor? - public static let doYouOwnSensor = RuuviLocalization.tr("Localizable", "do_you_own_sensor", fallback: "Do you own this sensor?") - /// Done - public static let done = RuuviLocalization.tr("Localizable", "Done", fallback: "Done") - /// Download - public static let download = RuuviLocalization.tr("Localizable", "download", fallback: "Download") - /// No data available - /// in the selected history window. - public static let emptyChartMessage = RuuviLocalization.tr("Localizable", "empty_chart_message", fallback: "No data available \nin the selected history window.") - /// Enter Code - public static let enterCode = RuuviLocalization.tr("Localizable", "enter_code", fallback: "Enter Code") - /// You can export a sensor's history from its history graph page. Tap the three dots menu icon in the top right corner, and then select "Export history (csv)". - public static let exportCsvFeatureLocation = RuuviLocalization.tr("Localizable", "export_csv_feature_location", fallback: "You can export a sensor's history from its history graph page. Tap the three dots menu icon in the top right corner, and then select \"Export history (csv)\".") - /// Export history (csv) - public static let exportHistory = RuuviLocalization.tr("Localizable", "export_history", fallback: "Export history (csv)") - /// Firmware Version: - public static let firmwareVersion = RuuviLocalization.tr("Localizable", "firmware_version", fallback: "Firmware Version:") - /// System theme - public static let followSystemTheme = RuuviLocalization.tr("Localizable", "follow_system_theme", fallback: "System theme") - /// Force Claim - public static let forceClaim = RuuviLocalization.tr("Localizable", "force_claim", fallback: "Force Claim") - /// Force Claim Sensor - public static let forceClaimSensor = RuuviLocalization.tr("Localizable", "force_claim_sensor", fallback: "Force Claim Sensor") - /// This sensor has been claimed by another user. You can force the ownership to your account if you have physical access to this sensor. Each Ruuvi sensor can have only one owner. - public static let forceClaimSensorDescription1 = RuuviLocalization.tr("Localizable", "force_claim_sensor_description1", fallback: "This sensor has been claimed by another user. You can force the ownership to your account if you have physical access to this sensor. Each Ruuvi sensor can have only one owner.") - /// Force Claim is done by using Near-Field Communication (NFC). Make sure NFC is enabled on your mobile device. - /// - /// 1. Touch your Ruuvi sensor with your mobile device to start the claiming process. - /// - /// 2. When successfully claimed, you will be sent back to Sensor Settings. - /// - /// If claiming was unsuccessful or NFC is not available on your device: - /// - /// 1. Open the cover of your Ruuvi sensor. - /// - /// 2. Locate the round black button (or button "B" in case your sensor has 2 buttons) on the white circuit board and press it briefly, then tap on Use BT button to start the claiming process. - /// - /// 3. When successfully claimed you will be sent back to Sensor Settings. - public static let forceClaimSensorDescription2 = RuuviLocalization.tr("Localizable", "force_claim_sensor_description2", fallback: "Force Claim is done by using Near-Field Communication (NFC). Make sure NFC is enabled on your mobile device.\n\n\t1. Touch your Ruuvi sensor with your mobile device to start the claiming process.\n\n\t2. When successfully claimed, you will be sent back to Sensor Settings.\n\nIf claiming was unsuccessful or NFC is not available on your device:\n\n\t1. Open the cover of your Ruuvi sensor.\n\n\t2. Locate the round black button (or button \"B\" in case your sensor has 2 buttons) on the white circuit board and press it briefly, then tap on Use BT button to start the claiming process.\n\n\t3. When successfully claimed you will be sent back to Sensor Settings.") - /// Full image view - public static let fullImageView = RuuviLocalization.tr("Localizable", "full_image_view", fallback: "Full image view") - /// g - public static let g = RuuviLocalization.tr("Localizable", "g", fallback: "g") - /// g/m³ - public static let gm³ = RuuviLocalization.tr("Localizable", "g/m³", fallback: "g/m³") - /// Ruuvi Station downloads the internal history of the sensor for the last 10 days if the measurement history is available. - /// - /// The history is downloaded using a Bluetooth connection. Make sure you are near the sensor. - public static let gattSyncDescription = RuuviLocalization.tr("Localizable", "gatt_sync_description", fallback: "Ruuvi Station downloads the internal history of the sensor for the last 10 days if the measurement history is available.\n\nThe history is downloaded using a Bluetooth connection. Make sure you are near the sensor.") - /// Go to sensor card - public static let goToSensor = RuuviLocalization.tr("Localizable", "go_to_sensor", fallback: "Go to sensor card") - /// h - public static let h = RuuviLocalization.tr("Localizable", "h", fallback: "h") - /// History view - public static let historyView = RuuviLocalization.tr("Localizable", "history_view", fallback: "History view") - /// Hour - public static let hour = RuuviLocalization.tr("Localizable", "hour", fallback: "Hour") - /// Hours - public static let hours = RuuviLocalization.tr("Localizable", "hours", fallback: "Hours") - /// hPa - public static let hPa = RuuviLocalization.tr("Localizable", "hPa", fallback: "hPa") - /// Image cards - public static let imageCards = RuuviLocalization.tr("Localizable", "image_cards", fallback: "Image cards") - /// Internet connection problem - public static let internetConnectionProblem = RuuviLocalization.tr("Localizable", "internet_connection_problem", fallback: "Internet connection problem") - /// Let's Sign In - public static let letsDoIt = RuuviLocalization.tr("Localizable", "lets_do_it", fallback: "Let's Sign In") - /// Light theme - public static let lightTheme = RuuviLocalization.tr("Localizable", "light_theme", fallback: "Light theme") - /// Ruuvi Station mobile app supports maximum 10 days of history. Ruuvi Cloud subscribers are able to view up to 2 years of historical data using web app at ruuvi.com/station (requires Ruuvi Gateway router). - public static let longerHistoryMessage = RuuviLocalization.tr("Localizable", "longer_history_message", fallback: "Ruuvi Station mobile app supports maximum 10 days of history. Ruuvi Cloud subscribers are able to view up to 2 years of historical data using web app at ruuvi.com/station (requires Ruuvi Gateway router).") - /// Longer history - public static let longerHistoryTitle = RuuviLocalization.tr("Localizable", "longer_history_title", fallback: "Longer history") - /// Low battery - public static let lowBattery = RuuviLocalization.tr("Localizable", "low_battery", fallback: "Low battery") - /// Mac Address: - public static let macAddress = RuuviLocalization.tr("Localizable", "mac_address", fallback: "Mac Address:") - /// min - public static let min = RuuviLocalization.tr("Localizable", "min", fallback: "min") - /// Minutes - public static let minutes = RuuviLocalization.tr("Localizable", "minutes", fallback: "Minutes") - /// More... - public static let more = RuuviLocalization.tr("Localizable", "more", fallback: "More...") - /// - - public static let na = RuuviLocalization.tr("Localizable", "N/A", fallback: "-") - /// Name: - public static let name = RuuviLocalization.tr("Localizable", "name", fallback: "Name:") - /// Only sensors within range of your Ruuvi Gateway can be shared. - public static let networkSharingDisabled = RuuviLocalization.tr("Localizable", "network_sharing_disabled", fallback: "Only sensors within range of your Ruuvi Gateway can be shared.") - /// No - public static let no = RuuviLocalization.tr("Localizable", "No", fallback: "No") - /// A free account will be created for this email if you don't already have one. Only email address is required. We keep your information safe. - public static let noPasswordNeeded = RuuviLocalization.tr("Localizable", "no_password_needed", fallback: "A free account will be created for this email if you don't already have one. Only email address is required. We keep your information safe.") - /// Note! - public static let note = RuuviLocalization.tr("Localizable", "note", fallback: "Note!") - /// Off - public static let off = RuuviLocalization.tr("Localizable", "Off", fallback: "Off") - /// OK - public static let ok = RuuviLocalization.tr("Localizable", "OK", fallback: "OK") - /// On - public static let on = RuuviLocalization.tr("Localizable", "On", fallback: "On") - /// Bring your favorite sensors to your Home Screen and Lock Screen as - public static let onboardingAccessWidgets = RuuviLocalization.tr("Localizable", "onboarding_access_widgets", fallback: "Bring your favorite sensors to your Home Screen and Lock Screen as") - /// Alerts - public static let onboardingAlerts = RuuviLocalization.tr("Localizable", "onboarding_alerts", fallback: "Alerts") - /// Next - public static let onboardingContinue = RuuviLocalization.tr("Localizable", "onboarding_continue", fallback: "Next") - /// Dashboard - public static let onboardingDashboard = RuuviLocalization.tr("Localizable", "onboarding_dashboard", fallback: "Dashboard") - /// Explore your measurement - public static let onboardingExploreDetailed = RuuviLocalization.tr("Localizable", "onboarding_explore_detailed", fallback: "Explore your measurement") - /// View all sensors at a glance on your - public static let onboardingFollowMeasurement = RuuviLocalization.tr("Localizable", "onboarding_follow_measurement", fallback: "View all sensors at a glance on your") - /// A Ruuvi Gateway router is required. - public static let onboardingGatewayRequired = RuuviLocalization.tr("Localizable", "onboarding_gateway_required", fallback: "A Ruuvi Gateway router is required.") - /// Ruuvi experience is better when you're signed in. Do it now or continue without cloud features. - public static let onboardingGoToSignIn = RuuviLocalization.tr("Localizable", "onboarding_go_to_sign_in", fallback: "Ruuvi experience is better when you're signed in. Do it now or continue without cloud features.") - /// Let's start measuring! - public static let onboardingGoToSignInAlreadySignedIn = RuuviLocalization.tr("Localizable", "onboarding_go_to_sign_in_already_signed_in", fallback: "Let's start measuring!") - /// Widgets - public static let onboardingHandyWidgets = RuuviLocalization.tr("Localizable", "onboarding_handy_widgets", fallback: "Widgets") - /// History - public static let onboardingHistory = RuuviLocalization.tr("Localizable", "onboarding_history", fallback: "History") - /// Measure Your World - public static let onboardingMeasureYourWorld = RuuviLocalization.tr("Localizable", "onboarding_measure_your_world", fallback: "Measure Your World") - /// Personalise - public static let onboardingPersonalise = RuuviLocalization.tr("Localizable", "onboarding_personalise", fallback: "Personalise") - /// Read Your Ruuvi Sensors - public static let onboardingReadSensorsData = RuuviLocalization.tr("Localizable", "onboarding_read_sensors_data", fallback: "Read Your Ruuvi Sensors") - /// Set and customise your - public static let onboardingSetCustom = RuuviLocalization.tr("Localizable", "onboarding_set_custom", fallback: "Set and customise your") - /// to measure together with your friends and family. - public static let onboardingShareYourSensors = RuuviLocalization.tr("Localizable", "onboarding_share_your_sensors", fallback: "to measure together with your friends and family.") - /// Share Sensors - public static let onboardingShareesCanUse = RuuviLocalization.tr("Localizable", "onboarding_sharees_can_use", fallback: "Share Sensors") - /// Skip - public static let onboardingSkip = RuuviLocalization.tr("Localizable", "onboarding_skip", fallback: "Skip") - /// Ruuvi Web App - public static let onboardingStationWeb = RuuviLocalization.tr("Localizable", "onboarding_station_web", fallback: "Ruuvi Web App") - /// Swipe to continue → - public static let onboardingSwipeToContinue = RuuviLocalization.tr("Localizable", "onboarding_swipe_to_continue", fallback: "Swipe to continue →") - /// Almost there! - public static let onboardingThatsIt = RuuviLocalization.tr("Localizable", "onboarding_thats_it", fallback: "Almost there!") - /// Let's get started! - public static let onboardingThatsItAlreadySignedIn = RuuviLocalization.tr("Localizable", "onboarding_thats_it_already_signed_in", fallback: "Let's get started!") - /// using Bluetooth or Ruuvi Cloud - public static let onboardingViaBluetoothOrCloud = RuuviLocalization.tr("Localizable", "onboarding_via_bluetooth_or_cloud", fallback: "using Bluetooth or Ruuvi Cloud") - /// Large dashboard, multi-year history, email alerts and more on - public static let onboardingWebPros = RuuviLocalization.tr("Localizable", "onboarding_web_pros", fallback: "Large dashboard, multi-year history, email alerts and more on") - /// Let's get to know your Ruuvi Station app. - public static let onboardingWithRuuviSensors = RuuviLocalization.tr("Localizable", "onboarding_with_ruuvi_sensors", fallback: "Let's get to know your Ruuvi Station app.") - /// your app with custom names and backgrounds. - public static let onboardingYourSensors = RuuviLocalization.tr("Localizable", "onboarding_your_sensors", fallback: "your app with custom names and backgrounds.") - /// Open history view - public static let openHistoryView = RuuviLocalization.tr("Localizable", "open_history_view", fallback: "Open history view") - /// Open sensor view - public static let openSensorView = RuuviLocalization.tr("Localizable", "open_sensor_view", fallback: "Open sensor view") - /// Owner's Ruuvi Plan - public static let ownersPlan = RuuviLocalization.tr("Localizable", "owners_plan", fallback: "Owner's Ruuvi Plan") - /// Reading Bluetooth: %.0f - public static func readingHistoryX(_ p1: Float) -> String { - RuuviLocalization.tr("Localizable", "reading_history_x", p1, fallback: "Reading Bluetooth: %.0f") - } - /// Remove - public static let remove = RuuviLocalization.tr("Localizable", "Remove", fallback: "Remove") - /// By removing the sensor, your sensor ownership status will be revoked and sensor settings, such as name, background image, calibration settings and alert settings will be removed. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner. - public static let removeClaimedSensorDescription = RuuviLocalization.tr("Localizable", "remove_claimed_sensor_description", fallback: "By removing the sensor, your sensor ownership status will be revoked and sensor settings, such as name, background image, calibration settings and alert settings will be removed. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner.") - /// I also want to remove sensor history data from Ruuvi Cloud. - public static let removeCloudHistoryDescription = RuuviLocalization.tr("Localizable", "remove_cloud_history_description", fallback: "I also want to remove sensor history data from Ruuvi Cloud.") - /// Remove cloud history - public static let removeCloudHistoryTitle = RuuviLocalization.tr("Localizable", "remove_cloud_history_title", fallback: "Remove cloud history") - /// If you choose to remove this sensor, it will result in the deletion of your locally stored measurement history, along with the removal of any related sensor settings like name, background image, calibration, and alert configurations. - /// - /// You can add this sensor later again, if needed. - public static let removeLocalSensorDescription = RuuviLocalization.tr("Localizable", "remove_local_sensor_description", fallback: "If you choose to remove this sensor, it will result in the deletion of your locally stored measurement history, along with the removal of any related sensor settings like name, background image, calibration, and alert configurations.\n\nYou can add this sensor later again, if needed.") - /// If you choose to remove this shared sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore. - /// - /// You will also lose any related sensor settings like name, background image and alert configurations. - public static let removeSharedSensorDescription = RuuviLocalization.tr("Localizable", "remove_shared_sensor_description", fallback: "If you choose to remove this shared sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore.\n\nYou will also lose any related sensor settings like name, background image and alert configurations.") - /// Rename - public static let rename = RuuviLocalization.tr("Localizable", "rename", fallback: "Rename") - /// Request Code - public static let requestCode = RuuviLocalization.tr("Localizable", "request_code", fallback: "Request Code") - /// Using this alert requires you to be signed in to the app, and that you have claimed the ownership of this sensor and it's in the range of Ruuvi Gateway router. iOS devices are unable to indicate signal strength information of received data sent by Ruuvi sensor when sensor is paired and measurements are being received in the background. Realtime Bluetooth signal strength is shown in the app but doesn't affect this alert. - public static let rssiAlertDescription = RuuviLocalization.tr("Localizable", "rssi_alert_description", fallback: "Using this alert requires you to be signed in to the app, and that you have claimed the ownership of this sensor and it's in the range of Ruuvi Gateway router. iOS devices are unable to indicate signal strength information of received data sent by Ruuvi sensor when sensor is paired and measurements are being received in the background. Realtime Bluetooth signal strength is shown in the app but doesn't affect this alert.") - /// Ruuvi Cloud - public static let ruuviCloud = RuuviLocalization.tr("Localizable", "ruuvi_cloud", fallback: "Ruuvi Cloud") - /// s - public static let s = RuuviLocalization.tr("Localizable", "s", fallback: "s") - /// Select from default images - public static let selectDefaultImage = RuuviLocalization.tr("Localizable", "select_default_image", fallback: "Select from default images") - /// Select from phone gallery - public static let selectFromGallery = RuuviLocalization.tr("Localizable", "select_from_gallery", fallback: "Select from phone gallery") - /// Sensor Details - public static let sensorDetails = RuuviLocalization.tr("Localizable", "sensor_details", fallback: "Sensor Details") - /// Sensor not found. Try again. - public static let sensorNotFoundError = RuuviLocalization.tr("Localizable", "sensor_not_found_error", fallback: "Sensor not found. Try again.") - /// Signing in to the app has many advantages. Settings will be safely stored to your account: - public static let sensorsOwnershipAndSettingsStoredInCloud = RuuviLocalization.tr("Localizable", "sensors_ownership_and_settings_stored_in_cloud", fallback: "Signing in to the app has many advantages. Settings will be safely stored to your account:") - /// Limit alert notifications - public static let settingsAlertLimitNotification = RuuviLocalization.tr("Localizable", "settings_alert_limit_notification", fallback: "Limit alert notifications") - /// Trigger Bluetooth alert notification only once per hour even if alert was retriggered. - public static let settingsAlertLimitNotificationDescription = RuuviLocalization.tr("Localizable", "settings_alert_limit_notification_description", fallback: "Trigger Bluetooth alert notification only once per hour even if alert was retriggered.") - /// Alert Notifications - public static let settingsAlertNotifications = RuuviLocalization.tr("Localizable", "settings_alert_notifications", fallback: "Alert Notifications") - /// Alert Sound - public static let settingsAlertSound = RuuviLocalization.tr("Localizable", "settings_alert_sound", fallback: "Alert Sound") - /// System Default - public static let settingsAlertSoundDefault = RuuviLocalization.tr("Localizable", "settings_alert_sound_default", fallback: "System Default") - /// Select push notification alert sound. - public static let settingsAlertSoundDescription = RuuviLocalization.tr("Localizable", "settings_alert_sound_description", fallback: "Select push notification alert sound.") - /// Ruuvi Alert - public static let settingsAlertSoundRuuviSpeak = RuuviLocalization.tr("Localizable", "settings_alert_sound_ruuvi_speak", fallback: "Ruuvi Alert") - /// You can also adjust Notification settings under iOS Settings -> Notifications - public static let settingsAlertsFooterDescription = RuuviLocalization.tr("Localizable", "settings_alerts_footer_description", fallback: "You can also adjust Notification settings under iOS Settings -> Notifications") - /// iOS Settings -> Notifications - public static let settingsAlertsFooterDescriptionLinkMask = RuuviLocalization.tr("Localizable", "settings_alerts_footer_description_link_mask", fallback: "iOS Settings -> Notifications") - /// Settings & alerts - public static let settingsAndAlerts = RuuviLocalization.tr("Localizable", "settings_and_alerts", fallback: "Settings & alerts") - /// Appearance - public static let settingsAppearance = RuuviLocalization.tr("Localizable", "settings_appearance", fallback: "Appearance") - /// Email Alerts - public static let settingsEmailAlerts = RuuviLocalization.tr("Localizable", "settings_email_alerts", fallback: "Email Alerts") - /// If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive email alerts by enabling this. - public static let settingsEmailAlertsDescription = RuuviLocalization.tr("Localizable", "settings_email_alerts_description", fallback: "If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive email alerts by enabling this.") - /// Push Alerts - public static let settingsPushAlerts = RuuviLocalization.tr("Localizable", "settings_push_alerts", fallback: "Push Alerts") - /// If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive push alerts by enabling this. - public static let settingsPushAlertsDescription = RuuviLocalization.tr("Localizable", "settings_push_alerts_description", fallback: "If you are using Ruuvi Cloud and Ruuvi Gateway, you will be able to receive push alerts by enabling this.") - /// Share pending - public static let sharePending = RuuviLocalization.tr("Localizable", "share_pending", fallback: "Share pending") - /// Shared successfully! This email address isn't linked to a Ruuvi account yet. An invite to create a free account has been sent. Once created, you'll see it in the sharee listing. - public static let sharePendingMessage = RuuviLocalization.tr("Localizable", "share_pending_message", fallback: "Shared successfully! This email address isn't linked to a Ruuvi account yet. An invite to create a free account has been sent. Once created, you'll see it in the sharee listing.") - /// Shared to %d/%d - public static func sharedToX(_ p1: Int, _ p2: Int) -> String { - RuuviLocalization.tr("Localizable", "shared_to_x", p1, p2, fallback: "Shared to %d/%d") - } - /// Continue - public static let signInContinue = RuuviLocalization.tr("Localizable", "sign_in_continue", fallback: "Continue") - /// Sign in or create a free Ruuvi account - public static let signInOrCreateFreeAccount = RuuviLocalization.tr("Localizable", "sign_in_or_create_free_account", fallback: "Sign in or create a free Ruuvi account") - /// Signal Strength (dBm) - public static let signalStrengthDbm = RuuviLocalization.tr("Localizable", "signal_strength_dbm", fallback: "Signal Strength (dBm)") - /// (Signing in is optional) - public static let signingInIsOptional = RuuviLocalization.tr("Localizable", "signing_in_is_optional", fallback: "(Signing in is optional)") - /// Simple cards - public static let simpleCards = RuuviLocalization.tr("Localizable", "simple_cards", fallback: "Simple cards") - /// Support - public static let support = RuuviLocalization.tr("Localizable", "support", fallback: "Support") - /// Synchronisation - public static let synchronisation = RuuviLocalization.tr("Localizable", "synchronisation", fallback: "Synchronisation") - /// Synchronised - public static let synchronized = RuuviLocalization.tr("Localizable", "Synchronized", fallback: "Synchronised") - /// Loading history from the cloud... - public static let syncing = RuuviLocalization.tr("Localizable", "Syncing...", fallback: "Loading history from the cloud...") - /// Take a photo - public static let takePhoto = RuuviLocalization.tr("Localizable", "take_photo", fallback: "Take a photo") - /// No password needed. - public static let toUseAllAppFeatures = RuuviLocalization.tr("Localizable", "to_use_all_app_features", fallback: "No password needed.") - /// Type your email.. - public static let typeYourEmail = RuuviLocalization.tr("Localizable", "type_your_email", fallback: "Type your email..") - /// Unclaim - public static let unclaim = RuuviLocalization.tr("Localizable", "unclaim", fallback: "Unclaim") - /// Unclaim sensor - public static let unclaimSensor = RuuviLocalization.tr("Localizable", "unclaim_sensor", fallback: "Unclaim sensor") - /// Ownership of this sensor has been claimed to your Ruuvi account. Press Unclaim to remove this sensor's settings and related data from your Ruuvi account. - public static let unclaimSensorDescription = RuuviLocalization.tr("Localizable", "unclaim_sensor_description", fallback: "Ownership of this sensor has been claimed to your Ruuvi account. Press Unclaim to remove this sensor's settings and related data from your Ruuvi account.") - /// Unique ID: - public static let uniqueId = RuuviLocalization.tr("Localizable", "unique_id", fallback: "Unique ID:") - /// Updated - public static let updated = RuuviLocalization.tr("Localizable", "Updated", fallback: "Updated") - /// Uploading: %.0f - public static func uploadingProgress(_ p1: Float) -> String { - RuuviLocalization.tr("Localizable", "uploading_progress", p1, fallback: "Uploading: %.0f") - } - /// Use BT - public static let useBluetooth = RuuviLocalization.tr("Localizable", "use_bluetooth", fallback: "Use BT") - /// Use NFC - public static let useNfc = RuuviLocalization.tr("Localizable", "use_nfc", fallback: "Use NFC") - /// No thanks, skip - public static let useWithoutAccount = RuuviLocalization.tr("Localizable", "use_without_account", fallback: "No thanks, skip") - /// V - public static let v = RuuviLocalization.tr("Localizable", "V", fallback: "V") - /// View - public static let view = RuuviLocalization.tr("Localizable", "view", fallback: "View") - /// Benefits - public static let whyShouldSignIn = RuuviLocalization.tr("Localizable", "why_should_sign_in", fallback: "Benefits") - /// Yes - public static let yes = RuuviLocalization.tr("Localizable", "Yes", fallback: "Yes") - /// °C - public static let ºC = RuuviLocalization.tr("Localizable", "ºC", fallback: "°C") - /// °F - public static let ºF = RuuviLocalization.tr("Localizable", "ºF", fallback: "°F") - public enum About { - public enum AboutHelp { - /// Ruuvi Station is an easy-to-use application that allows you to monitor the measurement data of Ruuvi sensors. - public static let contents = RuuviLocalization.tr("Localizable", "About.AboutHelp.contents", fallback: "Ruuvi Station is an easy-to-use application that allows you to monitor the measurement data of Ruuvi sensors.") - /// About / Help - public static let header = RuuviLocalization.tr("Localizable", "About.AboutHelp.header", fallback: "About / Help") - } - public enum DatabaseSize { - /// Database size: %@ - public static func text(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "About.DatabaseSize.text", String(describing: p1), fallback: "Database size: %@") - } - } - public enum MeasurementsCount { - /// Number of locally stored measurements: %d - public static func text(_ p1: Int) -> String { - RuuviLocalization.tr("Localizable", "About.MeasurementsCount.text", p1, fallback: "Number of locally stored measurements: %d") - } - } - public enum More { - /// Ruuvi's website: ruuvi.com - /// Ruuvi Forum: f.ruuvi.com - /// Ruuvi Blog: ruuvi.com/blog - /// Ruuvi on Twitter: twitter.com/ruuvicom - public static let contents = RuuviLocalization.tr("Localizable", "About.More.contents", fallback: "Ruuvi's website: ruuvi.com\nRuuvi Forum: f.ruuvi.com\nRuuvi Blog: ruuvi.com/blog\nRuuvi on Twitter: twitter.com/ruuvicom") - /// More to read - public static let header = RuuviLocalization.tr("Localizable", "About.More.header", fallback: "More to read") - } - public enum OpenSource { - /// Just like Ruuvi sensors, Ruuvi Station apps are open source. Follow the development and contribute at: github.com/ruuvi - public static let contents = RuuviLocalization.tr("Localizable", "About.OpenSource.contents", fallback: "Just like Ruuvi sensors, Ruuvi Station apps are open source. Follow the development and contribute at: github.com/ruuvi") - /// Open-source - public static let header = RuuviLocalization.tr("Localizable", "About.OpenSource.header", fallback: "Open-source") - } - public enum OperationsManual { - /// Get started using the Ruuvi Station mobile application with our online guides: ruuvi.com/support/station-mobile - public static let contents = RuuviLocalization.tr("Localizable", "About.OperationsManual.contents", fallback: "Get started using the Ruuvi Station mobile application with our online guides: ruuvi.com/support/station-mobile") - /// Operations manual - public static let header = RuuviLocalization.tr("Localizable", "About.OperationsManual.header", fallback: "Operations manual") - } - public enum Privacy { - /// By using the application, you accept Ruuvi's standard terms and conditions: ruuvi.com/terms - public static let contents = RuuviLocalization.tr("Localizable", "About.Privacy.contents", fallback: "By using the application, you accept Ruuvi's standard terms and conditions: ruuvi.com/terms") - /// Privacy policy - public static let header = RuuviLocalization.tr("Localizable", "About.Privacy.header", fallback: "Privacy policy") - } - public enum TagsCount { - /// Added sensors: %d - public static func text(_ p1: Int) -> String { - RuuviLocalization.tr("Localizable", "About.TagsCount.text", p1, fallback: "Added sensors: %d") - } - } - public enum Troubleshooting { - /// Find help using the Ruuvi Station apps, Ruuvi products and Ruuvi Cloud service from our support center: ruuvi.com/support - public static let contents = RuuviLocalization.tr("Localizable", "About.Troubleshooting.contents", fallback: "Find help using the Ruuvi Station apps, Ruuvi products and Ruuvi Cloud service from our support center: ruuvi.com/support") - /// Troubleshooting - public static let header = RuuviLocalization.tr("Localizable", "About.Troubleshooting.header", fallback: "Troubleshooting") - } - public enum Version { - /// Version - public static let text = RuuviLocalization.tr("Localizable", "About.Version.text", fallback: "Version") - } - } - public enum Background { - public enum Interval { - public enum Every { - /// every - public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Every.string", fallback: "every") - } - public enum Min { - /// min - public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Min.string", fallback: "min") - } - public enum Sec { - /// sec - public static let string = RuuviLocalization.tr("Localizable", "Background.Interval.Sec.string", fallback: "sec") - } - } - public enum KeepConnection { - /// Keep the Connection - public static let title = RuuviLocalization.tr("Localizable", "Background.KeepConnection.title", fallback: "Keep the Connection") - } - public enum PresentNotifications { - /// Show Notifications - public static let title = RuuviLocalization.tr("Localizable", "Background.PresentNotifications.title", fallback: "Show Notifications") - } - public enum ReadRSSITitle { - /// Read RSSI - public static let title = RuuviLocalization.tr("Localizable", "Background.readRSSITitle.title", fallback: "Read RSSI") - } - } - public enum BluetoothError { - /// Disconnected - public static let disconnected = RuuviLocalization.tr("Localizable", "BluetoothError.disconnected", fallback: "Disconnected") - } - public enum Cards { - public enum Alert { - public enum AlreadyLoggedIn { - /// User %@ is already signed in. If you'd like to use a different account, please sign out first and then try again. - public static func message(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "Cards.Alert.AlreadyLoggedIn.message", String(describing: p1), fallback: "User %@ is already signed in. If you'd like to use a different account, please sign out first and then try again.") - } - } - } - public enum BluetoothDisabledAlert { - /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. - public static let message = RuuviLocalization.tr("Localizable", "Cards.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") - /// Bluetooth is not enabled - public static let title = RuuviLocalization.tr("Localizable", "Cards.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") - } - public enum Connected { - /// Connected - public static let title = RuuviLocalization.tr("Localizable", "Cards.Connected.title", fallback: "Connected") - } - public enum Error { - public enum ReverseGeocodingFailed { - /// Failed to load data for Virtual Sensor. Reverse geocode operation limit exceeded. - public static let message = RuuviLocalization.tr("Localizable", "Cards.Error.ReverseGeocodingFailed.message", fallback: "Failed to load data for Virtual Sensor. Reverse geocode operation limit exceeded.") - } - } - public enum KeepConnectionDialog { - /// Seems like you are running a connectable firmware on your Ruuvi device. Would you like to keep the connection open to this Ruuvi device in the background? This will allow histograms and alerts to work even when the application is minimised. - public static let message = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.message", fallback: "Seems like you are running a connectable firmware on your Ruuvi device. Would you like to keep the connection open to this Ruuvi device in the background? This will allow histograms and alerts to work even when the application is minimised.") - public enum Dismiss { - /// Cancel - public static let title = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.Dismiss.title", fallback: "Cancel") - } - public enum KeepConnection { - /// Keep the Connection - public static let title = RuuviLocalization.tr("Localizable", "Cards.KeepConnectionDialog.KeepConnection.title", fallback: "Keep the Connection") - } - } - public enum LegacyFirmwareUpdateDialog { - /// Looks like your sensor is using an old firmware software version. To access new features such as history graphs, alerts and cloud services, updating is mandatory. - public static let message = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.message", fallback: "Looks like your sensor is using an old firmware software version. To access new features such as history graphs, alerts and cloud services, updating is mandatory.") - public enum CancelConfirmation { - /// Are you sure? Without updating, you won't be able to claim ownership of the sensor, download history graphs and set alerts. The update also includes bug fixes. If you cancel now, you can start the update process again from the sensor's settings page. - public static let message = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.CancelConfirmation.message", fallback: "Are you sure? Without updating, you won't be able to claim ownership of the sensor, download history graphs and set alerts. The update also includes bug fixes. If you cancel now, you can start the update process again from the sensor's settings page.") - } - public enum CheckForUpdate { - /// Check for update - public static let title = RuuviLocalization.tr("Localizable", "Cards.LegacyFirmwareUpdateDialog.CheckForUpdate.title", fallback: "Check for update") - } - } - public enum Movements { - /// movements - public static let title = RuuviLocalization.tr("Localizable", "Cards.Movements.title", fallback: "movements") - } - public enum NoSensors { - /// No sensors added - /// Press here to add sensors - public static let title = RuuviLocalization.tr("Localizable", "Cards.NoSensors.title", fallback: "No sensors added\nPress here to add sensors") - } - public enum UpdatedLabel { - public enum NoData { - /// No data during the last 10 days - public static let message = RuuviLocalization.tr("Localizable", "Cards.UpdatedLabel.NoData.message", fallback: "No data during the last 10 days") - } - } - public enum WebTagAPILimitExcededError { - public enum Alert { - /// Please try again in 5 minutes - public static let message = RuuviLocalization.tr("Localizable", "Cards.WebTagAPILimitExcededError.Alert.message", fallback: "Please try again in 5 minutes") - /// Too many requests - public static let title = RuuviLocalization.tr("Localizable", "Cards.WebTagAPILimitExcededError.Alert.title", fallback: "Too many requests") - } - } - } - public enum ChartSettings { - public enum AllPoints { - /// Charts may be updated slowly when enabled. - public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.AllPoints.description", fallback: "Charts may be updated slowly when enabled.") - /// Show all measurements - public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.AllPoints.title", fallback: "Show all measurements") - } - public enum DrawDots { - /// Small dots will help to understand when measurements were collected. - public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.DrawDots.description", fallback: "Small dots will help to understand when measurements were collected.") - /// Show datapoints - public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.DrawDots.title", fallback: "Show datapoints") - } - public enum Duration { - /// Configure the period of history to be shown on chart from 1 to 10 days. - public static let description = RuuviLocalization.tr("Localizable", "ChartSettings.Duration.description", fallback: "Configure the period of history to be shown on chart from 1 to 10 days.") - /// Chart History View Period - public static let title = RuuviLocalization.tr("Localizable", "ChartSettings.Duration.title", fallback: "Chart History View Period") - } - } - public enum CoreError { - /// Failed to get current location - public static let failedToGetCurrentLocation = RuuviLocalization.tr("Localizable", "CoreError.failedToGetCurrentLocation", fallback: "Failed to get current location") - /// Failed to get data from response - public static let failedToGetDataFromResponse = RuuviLocalization.tr("Localizable", "CoreError.failedToGetDataFromResponse", fallback: "Failed to get data from response") - /// Failed to get background directory - public static let failedToGetDocumentsDirectory = RuuviLocalization.tr("Localizable", "CoreError.failedToGetDocumentsDirectory", fallback: "Failed to get background directory") - /// Failed to get PNG representation - public static let failedToGetPngRepresentation = RuuviLocalization.tr("Localizable", "CoreError.failedToGetPngRepresentation", fallback: "Failed to get PNG representation") - /// Missing permission for Location Services - public static let locationPermissionDenied = RuuviLocalization.tr("Localizable", "CoreError.locationPermissionDenied", fallback: "Missing permission for Location Services") - /// Location permission authorisation status is not determined - public static let locationPermissionNotDetermined = RuuviLocalization.tr("Localizable", "CoreError.locationPermissionNotDetermined", fallback: "Location permission authorisation status is not determined") - /// Object invalidated - public static let objectInvalidated = RuuviLocalization.tr("Localizable", "CoreError.objectInvalidated", fallback: "Object invalidated") - /// Object not found - public static let objectNotFound = RuuviLocalization.tr("Localizable", "CoreError.objectNotFound", fallback: "Object not found") - /// Unable to send email - public static let unableToSendEmail = RuuviLocalization.tr("Localizable", "CoreError.unableToSendEmail", fallback: "Unable to send email") - } - public enum DFUUIView { - /// You are running the latest firmware version, no need to update - public static let alreadyOnLatest = RuuviLocalization.tr("Localizable", "DFUUIView.alreadyOnLatest", fallback: "You are running the latest firmware version, no need to update") - /// Current version: - public static let currentTitle = RuuviLocalization.tr("Localizable", "DFUUIView.currentTitle", fallback: "Current version:") - /// Do not close the app or power off the sensor during the update. - public static let doNotCloseTitle = RuuviLocalization.tr("Localizable", "DFUUIView.doNotCloseTitle", fallback: "Do not close the app or power off the sensor during the update.") - /// Downloading the latest firmware to be updated... - public static let downloadingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.downloadingTitle", fallback: "Downloading the latest firmware to be updated...") - /// Latest available Ruuvi Firmware version: - public static let latestTitle = RuuviLocalization.tr("Localizable", "DFUUIView.latestTitle", fallback: "Latest available Ruuvi Firmware version:") - /// 2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label. - public static let locateBootButtonTitle = RuuviLocalization.tr("Localizable", "DFUUIView.locateBootButtonTitle", fallback: "2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label.") - /// Firmware Update - public static let navigationTitle = RuuviLocalization.tr("Localizable", "DFUUIView.navigationTitle", fallback: "Firmware Update") - /// Your sensor doesn't report its current firmware version. Either you're not in its Bluetooth range, it's connected to another phone, or it's running a very old firmware version. - public static let notReportingDescription = RuuviLocalization.tr("Localizable", "DFUUIView.notReportingDescription", fallback: "Your sensor doesn't report its current firmware version. Either you're not in its Bluetooth range, it's connected to another phone, or it's running a very old firmware version.") - /// 1. Open the cover of your Ruuvi sensor - public static let openCoverTitle = RuuviLocalization.tr("Localizable", "DFUUIView.openCoverTitle", fallback: "1. Open the cover of your Ruuvi sensor") - /// Prepare your sensor - public static let prepareTitle = RuuviLocalization.tr("Localizable", "DFUUIView.prepareTitle", fallback: "Prepare your sensor") - /// Searching for a sensor - public static let searchingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.searchingTitle", fallback: "Searching for a sensor") - /// 3. Set the sensor to updating mode: - public static let setUpdatingModeTitle = RuuviLocalization.tr("Localizable", "DFUUIView.setUpdatingModeTitle", fallback: "3. Set the sensor to updating mode:") - /// Start the update - public static let startTitle = RuuviLocalization.tr("Localizable", "DFUUIView.startTitle", fallback: "Start the update") - /// Start update process - public static let startUpdateProcess = RuuviLocalization.tr("Localizable", "DFUUIView.startUpdateProcess", fallback: "Start update process") - /// Update successful - public static let successfulTitle = RuuviLocalization.tr("Localizable", "DFUUIView.successfulTitle", fallback: "Update successful") - /// 3.2. If your sensor has a single button: keep the button pressed for 10 seconds. - public static let toBootModeOneButtonDescription = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeOneButtonDescription", fallback: "3.2. If your sensor has a single button: keep the button pressed for 10 seconds.") - /// 4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”. - public static let toBootModeSuccessTitle = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeSuccessTitle", fallback: "4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”.") - /// 3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”. - public static let toBootModeTwoButtonsDescription = RuuviLocalization.tr("Localizable", "DFUUIView.toBootModeTwoButtonsDescription", fallback: "3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”.") - /// Updating... - public static let updatingTitle = RuuviLocalization.tr("Localizable", "DFUUIView.updatingTitle", fallback: "Updating...") - public enum DBMigration { - public enum Error { - /// The update was successful, but an unexpected database migration error occurred. To continue using this sensor, please remove it from the app and then add it again. - public static let message = RuuviLocalization.tr("Localizable", "DFUUIView.DBMigration.Error.message", fallback: "The update was successful, but an unexpected database migration error occurred. To continue using this sensor, please remove it from the app and then add it again.") - } - } - public enum LowBattery { - public enum Warning { - /// Sensor's battery voltage seems to be low and the firmware update process may fail. We recommend to replace the battery before updating. - public static let message = RuuviLocalization.tr("Localizable", "DFUUIView.lowBattery.warning.message", fallback: "Sensor's battery voltage seems to be low and the firmware update process may fail. We recommend to replace the battery before updating.") - } - } - } - public enum Defaults { - public enum AlertsMuteInterval { - /// Alerts Mute Interval - public static let title = RuuviLocalization.tr("Localizable", "Defaults.AlertsMuteInterval.title", fallback: "Alerts Mute Interval") - } - public enum AlertsRepeatInterval { - /// Alerts Interval - public static let title = RuuviLocalization.tr("Localizable", "Defaults.AlertsRepeatInterval.title", fallback: "Alerts Interval") - } - public enum AppLaunchRequiredForReview { - public enum Count { - /// App launch count to ask for review for the first time - public static let title = RuuviLocalization.tr("Localizable", "Defaults.AppLaunchRequiredForReview.Count.title", fallback: "App launch count to ask for review for the first time") - } - } - public enum AskReviewIfLaunchDivisibleBy { - public enum Count { - /// Ask review if app launch divisible by - public static let title = RuuviLocalization.tr("Localizable", "Defaults.AskReviewIfLaunchDivisibleBy.Count.title", fallback: "Ask review if app launch divisible by") - } - } - public enum CardsSwipeHint { - /// Cards Swipe Hint Was Shown - public static let title = RuuviLocalization.tr("Localizable", "Defaults.CardsSwipeHint.title", fallback: "Cards Swipe Hint Was Shown") - } - public enum ChartDurationHours { - /// Chart Duration - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartDurationHours.title", fallback: "Chart Duration") - } - public enum ChartIntervalSeconds { - /// Chart Interval - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartIntervalSeconds.title", fallback: "Chart Interval") - } - public enum ChartsSwipeInstructionWasShown { - /// Charts Swipe Hint Was Shown - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ChartsSwipeInstructionWasShown.title", fallback: "Charts Swipe Hint Was Shown") - } - public enum ConnectionTimeout { - /// Connection Timeout - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ConnectionTimeout.title", fallback: "Connection Timeout") - } - public enum DashboardTapActionChart { - /// Show Chart on Dashboard Card Tap - public static let title = RuuviLocalization.tr("Localizable", "Defaults.DashboardTapActionChart.title", fallback: "Show Chart on Dashboard Card Tap") - } - public enum DevServer { - /// Changing Ruuvi Cloud endpoint requires signing out from current session and restart the app. Are you sure? - public static let message = RuuviLocalization.tr("Localizable", "Defaults.DevServer.message", fallback: "Changing Ruuvi Cloud endpoint requires signing out from current session and restart the app. Are you sure?") - /// Use Dev Server - public static let title = RuuviLocalization.tr("Localizable", "Defaults.DevServer.title", fallback: "Use Dev Server") - } - public enum HideNFC { - /// Hide NFC Option for sensor contest - public static let title = RuuviLocalization.tr("Localizable", "Defaults.HideNFC.title", fallback: "Hide NFC Option for sensor contest") - } - public enum Interval { - public enum Hour { - /// h - public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Hour.string", fallback: "h") - } - public enum Min { - /// min - public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Min.string", fallback: "min") - } - public enum Sec { - /// sec - public static let string = RuuviLocalization.tr("Localizable", "Defaults.Interval.Sec.string", fallback: "sec") - } - } - public enum PruningOffsetHours { - /// Pruning Offset Hours - public static let title = RuuviLocalization.tr("Localizable", "Defaults.PruningOffsetHours.title", fallback: "Pruning Offset Hours") - } - public enum ServiceTimeout { - /// Service Timeout - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ServiceTimeout.title", fallback: "Service Timeout") - } - public enum ShowEmailAlertsSettings { - /// Show email alerts settings - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ShowEmailAlertsSettings.title", fallback: "Show email alerts settings") - } - public enum ShowPushAlertsSettings { - /// Show push alerts settings - public static let title = RuuviLocalization.tr("Localizable", "Defaults.ShowPushAlertsSettings.title", fallback: "Show push alerts settings") - } - public enum UserAuthorized { - /// User Authorized - public static let title = RuuviLocalization.tr("Localizable", "Defaults.UserAuthorized.title", fallback: "User Authorized") - } - public enum WebPullInterval { - /// Web Alerts Interval - public static let title = RuuviLocalization.tr("Localizable", "Defaults.WebPullInterval.title", fallback: "Web Alerts Interval") - } - public enum WelcomeShown { - /// Welcome Displayed - public static let title = RuuviLocalization.tr("Localizable", "Defaults.WelcomeShown.title", fallback: "Welcome Displayed") - } - public enum NavigationItem { - /// Defaults - public static let title = RuuviLocalization.tr("Localizable", "Defaults.navigationItem.title", fallback: "Defaults") - } - } - public enum Devices { - /// Token Id - public static let tokenId = RuuviLocalization.tr("Localizable", "Devices.tokenId", fallback: "Token Id") - } - public enum DfuDevicesScanner { - public enum BluetoothDisabled { - /// (Bluetooth is disabled) - public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabled.text", fallback: "(Bluetooth is disabled)") - } - public enum BluetoothDisabledAlert { - /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. - public static let message = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") - /// Bluetooth is not enabled - public static let title = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") - } - public enum Description { - /// Find and select sensor "RuuviBoot". - public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.Description.text", fallback: "Find and select sensor \"RuuviBoot\".") - } - public enum NoDevice { - /// (No sensors in Bluetooth range) - public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.NoDevice.text", fallback: "(No sensors in Bluetooth range)") - } - public enum Title { - /// Devices - public static let text = RuuviLocalization.tr("Localizable", "DfuDevicesScanner.Title.text", fallback: "Devices") - } - } - public enum DfuFlash { - public enum Cancel { - /// CANCEL - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Cancel.text", fallback: "CANCEL") - } - public enum CancelAlert { - /// Are you sure you want to cancel the firmware update process? - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.CancelAlert.text", fallback: "Are you sure you want to cancel the firmware update process?") - } - public enum Finish { - /// FINISH - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Finish.text", fallback: "FINISH") - } - public enum FinishGuide { - /// Firmware update process has been completed successfully. - /// Your RuuviTag sensor is ready for use! - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.FinishGuide.text", fallback: "Firmware update process has been completed successfully.\nYour RuuviTag sensor is ready for use!") - } - public enum Firmware { - public enum BootloaderSize { - /// Bootloader size - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.BootloaderSize.text", fallback: "Bootloader size") - } - public enum FileName { - /// File name - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.FileName.text", fallback: "File name") - } - public enum Parts { - /// Parts - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.Parts.text", fallback: "Parts") - } - public enum Size { - /// Size - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.Size.text", fallback: "Size") - } - public enum SoftDeviceSize { - /// Soft Device size - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Firmware.SoftDeviceSize.text", fallback: "Soft Device size") - } - } - public enum FirmwareSelectionGuide { - /// Locate the previously downloaded ZIP file on your mobile device. - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.FirmwareSelectionGuide.text", fallback: "Locate the previously downloaded ZIP file on your mobile device.") - } - public enum OpenDocumentPicker { - /// OPEN DOCUMENT PICKER - public static let title = RuuviLocalization.tr("Localizable", "DfuFlash.OpenDocumentPicker.title", fallback: "OPEN DOCUMENT PICKER") - } - public enum Progress { - /// Progress - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Progress.text", fallback: "Progress") - } - public enum Start { - /// Start - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Start.text", fallback: "Start") - } - public enum Step { - /// Step - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Step.text", fallback: "Step") - } - public enum Steps { - public enum Completed { - /// Completed - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.Completed.text", fallback: "Completed") - } - public enum PackageSelection { - /// Package selection - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.PackageSelection.text", fallback: "Package selection") - } - public enum ReadyForUpload { - /// Ready For upload - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.ReadyForUpload.text", fallback: "Ready For upload") - } - public enum Uploading { - /// Uploading - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Steps.Uploading.text", fallback: "Uploading") - } - } - public enum Title { - /// DFU Flash - public static let text = RuuviLocalization.tr("Localizable", "DfuFlash.Title.text", fallback: "DFU Flash") - } - } - public enum DiscoverTable { - public enum BluetoothDisabledAlert { - /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. - public static let message = RuuviLocalization.tr("Localizable", "DiscoverTable.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") - /// Bluetooth is not enabled - public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") - } - public enum GetMoreSensors { - public enum Button { - /// Buy Ruuvi Sensors - public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.GetMoreSensors.button.title", fallback: "Buy Ruuvi Sensors") - } - } - public enum NavigationItem { - /// Add a New Sensor - public static let title = RuuviLocalization.tr("Localizable", "DiscoverTable.NavigationItem.title", fallback: "Add a New Sensor") - } - public enum NoDevicesSection { - public enum BluetoothDisabled { - /// (Bluetooth is disabled) - public static let text = RuuviLocalization.tr("Localizable", "DiscoverTable.NoDevicesSection.BluetoothDisabled.text", fallback: "(Bluetooth is disabled)") - } - public enum NotFound { - /// (No sensors in Bluetooth range) - public static let text = RuuviLocalization.tr("Localizable", "DiscoverTable.NoDevicesSection.NotFound.text", fallback: "(No sensors in Bluetooth range)") - } - } - public enum RuuviDevice { - /// Ruuvi - public static let `prefix` = RuuviLocalization.tr("Localizable", "DiscoverTable.RuuviDevice.prefix", fallback: "Ruuvi") - } - public enum SectionTitle { - /// Nearby Ruuvi sensors - public static let devices = RuuviLocalization.tr("Localizable", "DiscoverTable.SectionTitle.Devices", fallback: "Nearby Ruuvi sensors") - /// Virtual sensors - public static let webTags = RuuviLocalization.tr("Localizable", "DiscoverTable.SectionTitle.WebTags", fallback: "Virtual sensors") - } - public enum WebTagsInfoDialog { - /// Virtual Sensors show public weather data provided by local weather stations. - public static let message = RuuviLocalization.tr("Localizable", "DiscoverTable.WebTagsInfoDialog.message", fallback: "Virtual Sensors show public weather data provided by local weather stations.") - } - } - public enum ErrorPresenterAlert { - /// Error - public static let error = RuuviLocalization.tr("Localizable", "ErrorPresenterAlert.Error", fallback: "Error") - /// OK - public static let ok = RuuviLocalization.tr("Localizable", "ErrorPresenterAlert.OK", fallback: "OK") - } - public enum ExpectedError { - /// Unable to remove a connected device that is not reachable. Please check your Bluetooth connection. - public static let failedToDeleteTag = RuuviLocalization.tr("Localizable", "ExpectedError.failedToDeleteTag", fallback: "Unable to remove a connected device that is not reachable. Please check your Bluetooth connection.") - /// App is already in the process of syncing logs with this sensor - public static let isAlreadySyncingLogsWithThisTag = RuuviLocalization.tr("Localizable", "ExpectedError.isAlreadySyncingLogsWithThisTag", fallback: "App is already in the process of syncing logs with this sensor") - /// Missing OpenWeatherMap API Key. Please get one from openweathermap.org website and enter it in the station/Classes/Networking/Assembly/Networking.plist file - public static let missingOpenWeatherMapAPIKey = RuuviLocalization.tr("Localizable", "ExpectedError.missingOpenWeatherMapAPIKey", fallback: "Missing OpenWeatherMap API Key. Please get one from openweathermap.org website and enter it in the station/Classes/Networking/Assembly/Networking.plist file") - } - public enum ExportService { - /// Acceleration X - public static let accelerationX = RuuviLocalization.tr("Localizable", "ExportService.AccelerationX", fallback: "Acceleration X") - /// Acceleration Y - public static let accelerationY = RuuviLocalization.tr("Localizable", "ExportService.AccelerationY", fallback: "Acceleration Y") - /// Acceleration Z - public static let accelerationZ = RuuviLocalization.tr("Localizable", "ExportService.AccelerationZ", fallback: "Acceleration Z") - /// Date - public static let date = RuuviLocalization.tr("Localizable", "ExportService.Date", fallback: "Date") - /// Dew point (%@) - public static func dewPoint(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "ExportService.DewPoint", String(describing: p1), fallback: "Dew point (%@)") - } - /// Humidity (%@) - public static func humidity(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "ExportService.Humidity", String(describing: p1), fallback: "Humidity (%@)") - } - /// ISO8601 - public static let iso8601 = RuuviLocalization.tr("Localizable", "ExportService.ISO8601", fallback: "ISO8601") - /// Measurement Sequence Number - public static let measurementSequenceNumber = RuuviLocalization.tr("Localizable", "ExportService.MeasurementSequenceNumber", fallback: "Measurement Sequence Number") - /// Movement Counter - public static let movementCounter = RuuviLocalization.tr("Localizable", "ExportService.MovementCounter", fallback: "Movement Counter") - /// Pressure (%@) - public static func pressure(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "ExportService.Pressure", String(describing: p1), fallback: "Pressure (%@)") - } - /// Temperature (%@) - public static func temperature(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "ExportService.Temperature", String(describing: p1), fallback: "Temperature (%@)") - } - /// TX Power - public static let txPower = RuuviLocalization.tr("Localizable", "ExportService.TXPower", fallback: "TX Power") - /// Voltage (V) - public static let voltage = RuuviLocalization.tr("Localizable", "ExportService.Voltage", fallback: "Voltage (V)") - } - public enum Foreground { - public enum Interval { - public enum All { - /// All - public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.All.string", fallback: "All") - } - public enum Every { - /// Every - public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.Every.string", fallback: "Every") - } - public enum Min { - /// min - public static let string = RuuviLocalization.tr("Localizable", "Foreground.Interval.Min.string", fallback: "min") - } - } - public enum NavigationItem { - /// Foreground - public static let title = RuuviLocalization.tr("Localizable", "Foreground.navigationItem.title", fallback: "Foreground") - } - } - public enum ForegroundRow { - public enum Advertisement { - /// ADVERTISEMENTS - public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.advertisement.section", fallback: "ADVERTISEMENTS") - /// Save advertisements - public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.advertisement.title", fallback: "Save advertisements") - } - public enum Connection { - /// LOGS - public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.connection.section", fallback: "LOGS") - /// Connect and sync logs - public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.connection.title", fallback: "Connect and sync logs") - } - public enum WebTags { - /// VIRTUAL SENSORS - public static let section = RuuviLocalization.tr("Localizable", "ForegroundRow.webTags.section", fallback: "VIRTUAL SENSORS") - /// Load and save from web - public static let title = RuuviLocalization.tr("Localizable", "ForegroundRow.webTags.title", fallback: "Load and save from web") - } - } - public enum Heartbeat { - public enum Interval { - public enum All { - /// All - public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.All.string", fallback: "All") - } - public enum Every { - /// every - public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Every.string", fallback: "every") - } - public enum Min { - /// min - public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Min.string", fallback: "min") - } - public enum Sec { - /// sec - public static let string = RuuviLocalization.tr("Localizable", "Heartbeat.Interval.Sec.string", fallback: "sec") - } - } - public enum ReadRSSITitle { - /// Read RSSI - public static let title = RuuviLocalization.tr("Localizable", "Heartbeat.readRSSITitle.title", fallback: "Read RSSI") - } - } - public enum HumidityCalibration { - public enum Button { - public enum Calibrate { - /// Calibrate - public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Calibrate.title", fallback: "Calibrate") - } - public enum Clear { - /// Clear - public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Clear.title", fallback: "Clear") - } - public enum Close { - /// Close - public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.Button.Close.title", fallback: "Close") - } - } - public enum CalibrationConfirmationAlert { - /// You are going to calibrate humidity offset. Tap "Confirm" to continue - public static let message = RuuviLocalization.tr("Localizable", "HumidityCalibration.CalibrationConfirmationAlert.message", fallback: "You are going to calibrate humidity offset. Tap \"Confirm\" to continue") - /// Are you sure? - public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.CalibrationConfirmationAlert.title", fallback: "Are you sure?") - } - public enum ClearCalibrationConfirmationAlert { - /// You are going to clear humidity offset. This can't be undone. Tap "Confirm" to continue. - public static let message = RuuviLocalization.tr("Localizable", "HumidityCalibration.ClearCalibrationConfirmationAlert.message", fallback: "You are going to clear humidity offset. This can't be undone. Tap \"Confirm\" to continue.") - /// Are you sure? - public static let title = RuuviLocalization.tr("Localizable", "HumidityCalibration.ClearCalibrationConfirmationAlert.title", fallback: "Are you sure?") - } - public enum Description { - /// In order to measure relative humidity as accurately as possible, a sodium chloride (salt) calibration is recommended. See video tutorials on how to easily do this at home. - public static let text = RuuviLocalization.tr("Localizable", "HumidityCalibration.Description.text", fallback: "In order to measure relative humidity as accurately as possible, a sodium chloride (salt) calibration is recommended. See video tutorials on how to easily do this at home.") - } - public enum Label { - public enum Note { - /// Note that calibration data will be stored locally in your mobile device. After Ruuvi Station uninstall and install, you may need to recalibrate. - public static let text = RuuviLocalization.tr("Localizable", "HumidityCalibration.Label.note.text", fallback: "Note that calibration data will be stored locally in your mobile device. After Ruuvi Station uninstall and install, you may need to recalibrate.") - } - } - public enum VideoTutorials { - /// video tutorials - public static let link = RuuviLocalization.tr("Localizable", "HumidityCalibration.VideoTutorials.link", fallback: "video tutorials") - } - public enum LastCalibrationDate { - /// Calibrated: %@ - public static func format(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "HumidityCalibration.lastCalibrationDate.format", String(describing: p1), fallback: "Calibrated: %@") - } - } - } - public enum HumidityUnit { - public enum Dew { - /// Dew point (%@) - public static func title(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "HumidityUnit.Dew.title", String(describing: p1), fallback: "Dew point (%@)") - } - } - public enum Percent { - /// Relative (%) - public static let title = RuuviLocalization.tr("Localizable", "HumidityUnit.Percent.title", fallback: "Relative (%)") - } - public enum Gm3 { - /// Absolute (g/m³) - public static let title = RuuviLocalization.tr("Localizable", "HumidityUnit.gm3.title", fallback: "Absolute (g/m³)") - } - } - public enum Interval { - public enum Day { - /// Day - public static let string = RuuviLocalization.tr("Localizable", "Interval.Day.string", fallback: "Day") - } - public enum Days { - /// Days - public static let string = RuuviLocalization.tr("Localizable", "Interval.Days.string", fallback: "Days") - } - } - public enum Language { - /// English - public static let english = RuuviLocalization.tr("Localizable", "Language.English", fallback: "English") - /// Suomi - public static let finnish = RuuviLocalization.tr("Localizable", "Language.Finnish", fallback: "Suomi") - /// Français - public static let french = RuuviLocalization.tr("Localizable", "Language.French", fallback: "Français") - /// Deutsch - public static let german = RuuviLocalization.tr("Localizable", "Language.German", fallback: "Deutsch") - /// Русский - public static let russian = RuuviLocalization.tr("Localizable", "Language.Russian", fallback: "Русский") - /// Svenska - public static let swedish = RuuviLocalization.tr("Localizable", "Language.Swedish", fallback: "Svenska") - } - public enum LocalNotificationsManager { - public enum DidConnect { - /// Connected - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidConnect.title", fallback: "Connected") - } - public enum DidDisconnect { - /// Disconnected - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidDisconnect.title", fallback: "Disconnected") - } - public enum DidMove { - /// Movement detected! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.DidMove.title", fallback: "Movement detected!") - } - public enum Disable { - /// Turn off - public static let button = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.Disable.button", fallback: "Turn off") - } - public enum HighDewPoint { - /// Dew Point is too high! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighDewPoint.title", fallback: "Dew Point is too high!") - } - public enum HighHumidity { - /// Air Humidity is too high! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighHumidity.title", fallback: "Air Humidity is too high!") - } - public enum HighPressure { - /// Air Pressure is too high! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighPressure.title", fallback: "Air Pressure is too high!") - } - public enum HighSignal { - /// Signal strength is too high! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighSignal.title", fallback: "Signal strength is too high!") - } - public enum HighTemperature { - /// Temperature is too high! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.HighTemperature.title", fallback: "Temperature is too high!") - } - public enum LowDewPoint { - /// Dew Point is too low! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowDewPoint.title", fallback: "Dew Point is too low!") - } - public enum LowHumidity { - /// Air Humidity is too low! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowHumidity.title", fallback: "Air Humidity is too low!") - } - public enum LowPressure { - /// Air Pressure is too low! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowPressure.title", fallback: "Air Pressure is too low!") - } - public enum LowSignal { - /// Signal strength is too low! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowSignal.title", fallback: "Signal strength is too low!") - } - public enum LowTemperature { - /// Temperature is too low! - public static let title = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.LowTemperature.title", fallback: "Temperature is too low!") - } - public enum Mute { - /// Mute for an hour - public static let button = RuuviLocalization.tr("Localizable", "LocalNotificationsManager.Mute.button", fallback: "Mute for an hour") - } - } - public enum Menu { - public enum BuyGateway { - public enum Url { - /// https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios - public static let ios = RuuviLocalization.tr("Localizable", "Menu.BuyGateway.URL.IOS", fallback: "https://ruuvi.com/gateway?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") - } - } - public enum Label { - public enum AboutHelp { - /// About / Help - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AboutHelp.text", fallback: "About / Help") - } - public enum AddAnNewSensor { - /// Add a New Sensor - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AddAnNewSensor.text", fallback: "Add a New Sensor") - } - public enum AppSettings { - /// App Settings - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.AppSettings.text", fallback: "App Settings") - } - public enum BuyRuuviGateway { - /// Buy Ruuvi Gateway - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.BuyRuuviGateway.text", fallback: "Buy Ruuvi Gateway") - } - public enum Feedback { - /// Send Feedback - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.Feedback.text", fallback: "Send Feedback") - } - public enum GetMoreSensors { - /// Buy Ruuvi Sensors - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.GetMoreSensors.text", fallback: "Buy Ruuvi Sensors") - } - public enum MyRuuviAccount { - /// My Ruuvi Account - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.MyRuuviAccount.text", fallback: "My Ruuvi Account") - } - public enum WhatToMeasure { - /// What to measure with Ruuvi? - public static let text = RuuviLocalization.tr("Localizable", "Menu.Label.WhatToMeasure.text", fallback: "What to measure with Ruuvi?") - } - } - public enum LoggedIn { - /// Signed in: - public static let title = RuuviLocalization.tr("Localizable", "Menu.LoggedIn.title", fallback: "Signed in:") - } - public enum Measure { - public enum Url { - /// https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios - public static let ios = RuuviLocalization.tr("Localizable", "Menu.Measure.URL.IOS", fallback: "https://ruuvi.com/ideas?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") - } - } - public enum RuuviNetworkStatus { - /// Ruuvi Cloud status - public static let text = RuuviLocalization.tr("Localizable", "Menu.RuuviNetworkStatus.text", fallback: "Ruuvi Cloud status") - } - public enum SignOut { - /// Sign out - public static let text = RuuviLocalization.tr("Localizable", "Menu.SignOut.text", fallback: "Sign out") - } - } - public enum MenuTableViewController { - /// none - public static let `none` = RuuviLocalization.tr("Localizable", "MenuTableViewController.None", fallback: "none") - /// User: %@ - public static func user(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "MenuTableViewController.User", String(describing: p1), fallback: "User: %@") - } - } - public enum MyRuuvi { - public enum Settings { - public enum DeleteAccount { - /// Delete Account - public static let title = RuuviLocalization.tr("Localizable", "MyRuuvi.Settings.DeleteAccount.title", fallback: "Delete Account") - public enum Confirmation { - /// A confirmation has been sent to your email. To proceed with the deletion, please check your inbox and follow the instructions. - public static let message = RuuviLocalization.tr("Localizable", "MyRuuvi.Settings.DeleteAccount.Confirmation.message", fallback: "A confirmation has been sent to your email. To proceed with the deletion, please check your inbox and follow the instructions.") - } - } - } - } - public enum OWMError { - /// API limit exceeded - public static let apiLimitExceeded = RuuviLocalization.tr("Localizable", "OWMError.apiLimitExceeded", fallback: "API limit exceeded") - /// Failed to parse Open Weather Map response - public static let failedToParseOpenWeatherMapResponse = RuuviLocalization.tr("Localizable", "OWMError.failedToParseOpenWeatherMapResponse", fallback: "Failed to parse Open Weather Map response") - /// Invalid API Key - public static let invalidApiKey = RuuviLocalization.tr("Localizable", "OWMError.invalidApiKey", fallback: "Invalid API Key") - /// Not an HTTP response - public static let notAHttpResponse = RuuviLocalization.tr("Localizable", "OWMError.notAHttpResponse", fallback: "Not an HTTP response") - } - public enum OffsetCorrection { - public enum Calibrate { - /// Offset correction - public static let button = RuuviLocalization.tr("Localizable", "OffsetCorrection.Calibrate.button", fallback: "Offset correction") - } - public enum CalibrationDescription { - /// In normal use, it's not necessary to adjust the offset. - /// - /// If you're an advanced user and you'd like to manually configure the factory calibrated sensors, it's possible to do so. - /// - /// Calibration tips are available on ruuvi.com/support - public static let text = RuuviLocalization.tr("Localizable", "OffsetCorrection.CalibrationDescription.text", fallback: "In normal use, it's not necessary to adjust the offset.\n\nIf you're an advanced user and you'd like to manually configure the factory calibrated sensors, it's possible to do so.\n\nCalibration tips are available on ruuvi.com/support") - } - public enum CorrectedValue { - /// Corrected value - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.CorrectedValue.title", fallback: "Corrected value") - } - public enum Dialog { - public enum Calibration { - /// Clear calibration settings? - public static let clearConfirm = RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.ClearConfirm", fallback: "Clear calibration settings?") - /// Enter the expected humidity value from sensor under current conditions (%@): - public static func enterHumidity(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterHumidity", String(describing: p1), fallback: "Enter the expected humidity value from sensor under current conditions (%@): ") - } - /// Enter the expected pressure value from sensor under current conditions (%@): - public static func enterPressure(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterPressure", String(describing: p1), fallback: "Enter the expected pressure value from sensor under current conditions (%@): ") - } - /// Enter the expected temperature value from sensor under current conditions (%@): - public static func enterTemperature(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.EnterTemperature", String(describing: p1), fallback: "Enter the expected temperature value from sensor under current conditions (%@): ") - } - /// Calibration setup - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Dialog.Calibration.Title", fallback: "Calibration setup") - } - } - public enum Humidity { - /// Humidity offset - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Humidity.Title", fallback: "Humidity offset") - } - public enum OriginalValue { - /// Original measured value - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.OriginalValue.title", fallback: "Original measured value") - } - public enum Pressure { - /// Pressure offset - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Pressure.Title", fallback: "Pressure offset") - } - public enum Temperature { - /// Temperature offset - public static let title = RuuviLocalization.tr("Localizable", "OffsetCorrection.Temperature.Title", fallback: "Temperature offset") - } - } - public enum Owner { - /// Claim sensor - public static let title = RuuviLocalization.tr("Localizable", "Owner.title", fallback: "Claim sensor") - public enum Claim { - /// Do you own this sensor? If yes, please claim ownership of the sensor and it'll be added to your Ruuvi account. Each Ruuvi sensor can have only one owner. To claim ownership, you need to be signed in. - /// - /// Benefits: - /// - /// ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud - /// - /// ● Access sensors remotely over the Internet (requires a Ruuvi Gateway) - /// - /// ● Share sensors with friends and family (requires a Ruuvi Gateway) - /// - /// ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway) - public static let description = RuuviLocalization.tr("Localizable", "Owner.Claim.description", fallback: "Do you own this sensor? If yes, please claim ownership of the sensor and it'll be added to your Ruuvi account. Each Ruuvi sensor can have only one owner. To claim ownership, you need to be signed in.\n\nBenefits:\n\n ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud\n\n ● Access sensors remotely over the Internet (requires a Ruuvi Gateway)\n\n ● Share sensors with friends and family (requires a Ruuvi Gateway)\n\n ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway)") - } - public enum ClaimOwnership { - /// Claim ownership - public static let button = RuuviLocalization.tr("Localizable", "Owner.ClaimOwnership.button", fallback: "Claim ownership") - } - } - public enum PermissionPresenter { - /// Settings - public static let settings = RuuviLocalization.tr("Localizable", "PermissionPresenter.settings", fallback: "Settings") - public enum NoCameraAccess { - /// Ruuvi Station needs to access your camera to enable this feature. - public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoCameraAccess.message", fallback: "Ruuvi Station needs to access your camera to enable this feature.") - } - public enum NoLocationAccess { - /// Ruuvi Station needs to access your location to enable this feature. - public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoLocationAccess.message", fallback: "Ruuvi Station needs to access your location to enable this feature.") - } - public enum NoPhotoLibraryAccess { - /// Ruuvi Station needs to access your camera library to enable this feature. - public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoPhotoLibraryAccess.message", fallback: "Ruuvi Station needs to access your camera library to enable this feature.") - } - public enum NoPushNotificationsPermission { - /// Ruuvi Station needs push notifications permission to enable this feature - public static let message = RuuviLocalization.tr("Localizable", "PermissionPresenter.NoPushNotificationsPermission.message", fallback: "Ruuvi Station needs push notifications permission to enable this feature") - } - } - public enum PhotoPicker { - public enum Sheet { - /// Take photo - public static let camera = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.camera", fallback: "Take photo") - /// Choose from files - public static let files = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.files", fallback: "Choose from files") - /// Choose from the library - public static let library = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.library", fallback: "Choose from the library") - /// Pick a photo - public static let message = RuuviLocalization.tr("Localizable", "PhotoPicker.Sheet.message", fallback: "Pick a photo") - } - } - public enum Ruuvi { - public enum BuySensors { - public enum Menu { - public enum Url { - /// https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios - public static let ios = RuuviLocalization.tr("Localizable", "Ruuvi.BuySensors.Menu.URL.IOS", fallback: "https://ruuvi.com/products?utm_campaign=app_ua_nav&utm_medium=referral&utm_source=ios") - } - } - public enum Url { - /// https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios - public static let ios = RuuviLocalization.tr("Localizable", "Ruuvi.BuySensors.URL.IOS", fallback: "https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios") - } - } - } - public enum RuuviCloudApiError { - /// Empty response - public static let emptyResponse = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.emptyResponse", fallback: "Empty response") - /// Failed to get data from response - public static let failedToGetDataFromResponse = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.failedToGetDataFromResponse", fallback: "Failed to get data from response") - /// Unexpected HTTP status code - public static let unexpectedHTTPStatusCode = RuuviLocalization.tr("Localizable", "RuuviCloudApiError.unexpectedHTTPStatusCode", fallback: "Unexpected HTTP status code") - } - public enum RuuviCloudError { - /// Not authorised - public static let notAuthorized = RuuviLocalization.tr("Localizable", "RuuviCloudError.NotAuthorized", fallback: "Not authorised") - } - public enum RuuviDfuError { - /// Failed to construct UUID - public static let failedToConstructUUID = RuuviLocalization.tr("Localizable", "RuuviDfuError.failedToConstructUUID", fallback: "Failed to construct UUID") - /// Invalid firmware file - public static let invalidFirmwareFile = RuuviLocalization.tr("Localizable", "RuuviDfuError.invalidFirmwareFile", fallback: "Invalid firmware file") - } - public enum RuuviLocalError { - /// Failed to get background directory - public static let failedToGetDocumentsDirectory = RuuviLocalization.tr("Localizable", "RuuviLocalError.failedToGetDocumentsDirectory", fallback: "Failed to get background directory") - /// Failed to get JPG representation - public static let failedToGetJpegRepresentation = RuuviLocalization.tr("Localizable", "RuuviLocalError.failedToGetJpegRepresentation", fallback: "Failed to get JPG representation") - } - public enum RuuviOnboard { - public enum Access { - /// Access data for each linked sensor in real time and explore history graphs. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Access.title", fallback: "Access data for each linked sensor in real time and explore history graphs.") - } - public enum Alerts { - /// Set alerts and get notified whenever your limits are hit. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Alerts.title", fallback: "Set alerts and get notified whenever your limits are hit.") - } - public enum Cloud { - /// Claim ownership of your sensors with a free Ruuvi Cloud account. - public static let subtitle = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.subtitle", fallback: "Claim ownership of your sensors with a free Ruuvi Cloud account.") - /// Sign in to use the full potential of the app. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.title", fallback: "Sign in to use the full potential of the app.") - public enum Benefits { - /// Benefits: - /// - /// ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud - /// - /// ● Access sensors remotely over the Internet (requires a Ruuvi Gateway) - /// - /// ● Share sensors with friends and family (requires a Ruuvi Gateway) - /// - /// ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway) - public static let message = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Benefits.message", fallback: "Benefits:\n\n ● Sensor names, background images, offsets and alert settings will be securely stored on the cloud\n\n ● Access sensors remotely over the Internet (requires a Ruuvi Gateway)\n\n ● Share sensors with friends and family (requires a Ruuvi Gateway)\n\n ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway)") - } - public enum Details { - /// Details - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Details.title", fallback: "Details") - } - public enum Skip { - /// Are you sure you want to skip sign in? - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.title", fallback: "Are you sure you want to skip sign in?") - public enum GoBack { - /// Go back - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.GoBack.title", fallback: "Go back") - } - public enum Yes { - /// Yes, skip - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.Skip.Yes.title", fallback: "Yes, skip") - } - } - public enum Subtitle { - /// Great! You already signed in! - public static let signed = RuuviLocalization.tr("Localizable", "RuuviOnboard.Cloud.subtitle.signed", fallback: "Great! You already signed in!") - } - } - public enum Measure { - /// Measure environmental data: temperature, relative humidity and air pressure. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Measure.title", fallback: "Measure environmental data: temperature, relative humidity and air pressure.") - } - public enum Start { - /// Press SCAN to find and add nearby sensors to your Ruuvi Station. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Start.title", fallback: "Press SCAN to find and add nearby sensors to your Ruuvi Station.") - } - public enum Welcome { - /// Swipe to see what Ruuvi Station can do for you. - public static let title = RuuviLocalization.tr("Localizable", "RuuviOnboard.Welcome.title", fallback: "Swipe to see what Ruuvi Station can do for you.") - } - } - public enum RuuviPersistenceError { - /// Failed to find sensor - public static let failedToFindRuuviTag = RuuviLocalization.tr("Localizable", "RuuviPersistenceError.failedToFindRuuviTag", fallback: "Failed to find sensor") - } - public enum RuuviServiceError { - /// Both local and MAC identifiers are nil - public static let bothLuidAndMacAreNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.bothLuidAndMacAreNil", fallback: "Both local and MAC identifiers are nil") - /// Failed to find or generate background image - public static let failedToFindOrGenerateBackgroundImage = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToFindOrGenerateBackgroundImage", fallback: "Failed to find or generate background image") - /// Failed to get JPG representation - public static let failedToGetJpegRepresentation = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToGetJpegRepresentation", fallback: "Failed to get JPG representation") - /// Failed to parse response. - public static let failedToParseNetworkResponse = RuuviLocalization.tr("Localizable", "RuuviServiceError.failedToParseNetworkResponse", fallback: "Failed to parse response.") - /// MAC identifier is nil - public static let macIdIsNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.macIdIsNil", fallback: "MAC identifier is nil") - /// Photo URL is nil - public static let pictureUrlIsNil = RuuviLocalization.tr("Localizable", "RuuviServiceError.pictureUrlIsNil", fallback: "Photo URL is nil") - } - public enum Settings { - public enum BackgroundScanning { - /// Data logging interval - public static let interval = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.interval", fallback: "Data logging interval") - /// Background Scanning - public static let title = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.title", fallback: "Background Scanning") - public enum Footer { - /// Important note: Bluetooth background history logging and Bluetooth alerts work only when background scanning is enabled. If you disable the background scanning, all paired Ruuvi sensors will be automatically unpaired and you need to pair them again from their settings pages. - public static let message = RuuviLocalization.tr("Localizable", "Settings.BackgroundScanning.Footer.message", fallback: "Important note: Bluetooth background history logging and Bluetooth alerts work only when background scanning is enabled. If you disable the background scanning, all paired Ruuvi sensors will be automatically unpaired and you need to pair them again from their settings pages.") - } - } - public enum ChooseHumidityUnit { - /// Choose the humidity unit you want to be displayed. - public static let text = RuuviLocalization.tr("Localizable", "Settings.ChooseHumidityUnit.text", fallback: "Choose the humidity unit you want to be displayed.") - } - public enum ChoosePressureUnit { - /// Choose the pressure unit you want to be displayed. - public static let text = RuuviLocalization.tr("Localizable", "Settings.ChoosePressureUnit.text", fallback: "Choose the pressure unit you want to be displayed.") - } - public enum ChooseTemperatureUnit { - /// Choose the temperature unit you want to be displayed. - public static let text = RuuviLocalization.tr("Localizable", "Settings.ChooseTemperatureUnit.text", fallback: "Choose the temperature unit you want to be displayed.") - } - public enum Humidity { - public enum Resolution { - /// Humidity Resolution - public static let title = RuuviLocalization.tr("Localizable", "Settings.Humidity.Resolution.title", fallback: "Humidity Resolution") - } - } - public enum Label { - /// Chart Settings - public static let chart = RuuviLocalization.tr("Localizable", "Settings.Label.Chart", fallback: "Chart Settings") - /// Cloud mode - public static let cloudMode = RuuviLocalization.tr("Localizable", "Settings.Label.CloudMode", fallback: "Cloud mode") - /// Defaults - public static let defaults = RuuviLocalization.tr("Localizable", "Settings.Label.Defaults", fallback: "Defaults") - /// Foreground - public static let foreground = RuuviLocalization.tr("Localizable", "Settings.Label.Foreground", fallback: "Foreground") - /// Humidity - public static let humidity = RuuviLocalization.tr("Localizable", "Settings.Label.Humidity", fallback: "Humidity") - /// Pressure - public static let pressure = RuuviLocalization.tr("Localizable", "Settings.Label.Pressure", fallback: "Pressure") - /// Temperature - public static let temperature = RuuviLocalization.tr("Localizable", "Settings.Label.Temperature", fallback: "Temperature") - public enum CloudMode { - /// Refresh nearby cloud sensors only from the cloud by ignoring their Bluetooth messages and receiving alerts only by email. Requires a Ruuvi Gateway router. - public static let description = RuuviLocalization.tr("Localizable", "Settings.Label.CloudMode.description", fallback: "Refresh nearby cloud sensors only from the cloud by ignoring their Bluetooth messages and receiving alerts only by email. Requires a Ruuvi Gateway router.") - } - public enum HumidityUnit { - /// Humidity Unit - public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.HumidityUnit.text", fallback: "Humidity Unit") - } - public enum Language { - /// Language - public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.Language.text", fallback: "Language") - } - public enum PressureUnit { - /// Pressure Unit - public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.PressureUnit.text", fallback: "Pressure Unit") - } - public enum TemperatureUnit { - /// Temperature Unit - public static let text = RuuviLocalization.tr("Localizable", "Settings.Label.TemperatureUnit.text", fallback: "Temperature Unit") - } - } - public enum Language { - public enum Dialog { - /// Open settings and tap Language to change language of the app. - /// If you cannot see the Language option in the settings, make sure that you have at least one preferred language added in system settings: Settings -> General -> Language & Region. - public static let message = RuuviLocalization.tr("Localizable", "Settings.Language.Dialog.message", fallback: "Open settings and tap Language to change language of the app.\nIf you cannot see the Language option in the settings, make sure that you have at least one preferred language added in system settings: Settings -> General -> Language & Region.") - /// Select Language - public static let title = RuuviLocalization.tr("Localizable", "Settings.Language.Dialog.title", fallback: "Select Language") - } - } - public enum Measurement { - public enum Resolution { - /// Select how accurately you'd like to see the sensors' live measurement values in the app. This setting doesn't affect history charts or alerts. - public static let description = RuuviLocalization.tr("Localizable", "Settings.Measurement.Resolution.description", fallback: "Select how accurately you'd like to see the sensors' live measurement values in the app. This setting doesn't affect history charts or alerts.") - /// Resolution - public static let title = RuuviLocalization.tr("Localizable", "Settings.Measurement.Resolution.title", fallback: "Resolution") - } - public enum Unit { - /// Unit - public static let title = RuuviLocalization.tr("Localizable", "Settings.Measurement.Unit.title", fallback: "Unit") - } - } - public enum Pressure { - public enum Resolution { - /// Pressure Resolution - public static let title = RuuviLocalization.tr("Localizable", "Settings.Pressure.Resolution.title", fallback: "Pressure Resolution") - } - } - public enum SectionHeader { - public enum Application { - /// APPLICATION - public static let title = RuuviLocalization.tr("Localizable", "Settings.SectionHeader.Application.title", fallback: "APPLICATION") - } - public enum General { - /// GENERAL - public static let title = RuuviLocalization.tr("Localizable", "Settings.SectionHeader.General.title", fallback: "GENERAL") - } - } - public enum SegmentedControl { - public enum Humidity { - public enum Absolute { - /// Abs - public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.Absolute.title", fallback: "Abs") - } - public enum DewPoint { - /// Dew - public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.DewPoint.title", fallback: "Dew") - } - public enum Relative { - /// Rel - public static let title = RuuviLocalization.tr("Localizable", "Settings.SegmentedControl.Humidity.Relative.title", fallback: "Rel") - } - } - } - public enum Temperature { - public enum Resolution { - /// Temperature Resolution - public static let title = RuuviLocalization.tr("Localizable", "Settings.Temperature.Resolution.title", fallback: "Temperature Resolution") - } - } - public enum NavigationItem { - /// Settings - public static let title = RuuviLocalization.tr("Localizable", "Settings.navigationItem.title", fallback: "Settings") - } - } - public enum Share { - public enum Send { - /// Send - public static let button = RuuviLocalization.tr("Localizable", "Share.Send.button", fallback: "Send") - } - public enum Success { - /// Successfully shared sensor - public static let message = RuuviLocalization.tr("Localizable", "Share.Success.message", fallback: "Successfully shared sensor") - } - } - public enum SharePresenter { - public enum UnshareSensor { - /// Do you want to unshare sensor for %@? - public static func message(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "SharePresenter.UnshareSensor.Message", String(describing: p1), fallback: "Do you want to unshare sensor for %@?") - } - } - } - public enum ShareViewController { - /// You can share the sensor with friends and family if it's in range of a Ruuvi Gateway. - /// - /// Receiver will be notified by email. If the receiver doesn't have a Ruuvi account, a free Ruuvi account will automatically be created at first log in. - /// - /// Note that the sensor's custom name and background image will be shared. The name and image sync is one time only, and after this, they can be privately customised by the receiver. Offset values (if any) set by the owner, will be automatically synced, and the receiver will always see the final corrected values. - public static let description = RuuviLocalization.tr("Localizable", "ShareViewController.Description", fallback: "You can share the sensor with friends and family if it's in range of a Ruuvi Gateway.\n\nReceiver will be notified by email. If the receiver doesn't have a Ruuvi account, a free Ruuvi account will automatically be created at first log in.\n\nNote that the sensor's custom name and background image will be shared. The name and image sync is one time only, and after this, they can be privately customised by the receiver. Offset values (if any) set by the owner, will be automatically synced, and the receiver will always see the final corrected values.") - /// Share sensor - public static let title = RuuviLocalization.tr("Localizable", "ShareViewController.Title", fallback: "Share sensor") - public enum AddFriend { - /// Add friend - public static let title = RuuviLocalization.tr("Localizable", "ShareViewController.addFriend.Title", fallback: "Add friend") - } - public enum EmailTextField { - /// Type email - public static let placeholder = RuuviLocalization.tr("Localizable", "ShareViewController.emailTextField.placeholder", fallback: "Type email") - } - public enum SharedEmails { - /// You have used %d/%d of maximum shares of this sensor. The sensor has been shared to following users: - public static func title(_ p1: Int, _ p2: Int) -> String { - RuuviLocalization.tr("Localizable", "ShareViewController.sharedEmails.Title", p1, p2, fallback: "You have used %d/%d of maximum shares of this sensor. The sensor has been shared to following users:") - } - } - } - public enum SignIn { - /// We've sent a one-time password to your email %@. Sign in by entering it here: - public static func checkMailbox(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "SignIn.CheckMailbox", String(describing: p1), fallback: "We've sent a one-time password to your email %@. Sign in by entering it here:") - } - /// Code - public static let codeHint = RuuviLocalization.tr("Localizable", "SignIn.CodeHint", fallback: "Code") - /// Email - public static let emailPlaceholder = RuuviLocalization.tr("Localizable", "SignIn.EmailPlaceholder", fallback: "Email") - /// Email sent - public static let emailSent = RuuviLocalization.tr("Localizable", "SignIn.EmailSent", fallback: "Email sent") - /// Please enter verification code - public static let enterVerificationCode = RuuviLocalization.tr("Localizable", "SignIn.EnterVerificationCode", fallback: "Please enter verification code") - /// Request a code - public static let requestCode = RuuviLocalization.tr("Localizable", "SignIn.RequestCode", fallback: "Request a code") - /// Submit - public static let submitCode = RuuviLocalization.tr("Localizable", "SignIn.SubmitCode", fallback: "Submit") - /// verification code in format: CJSM - public static let verificationCodePlaceholder = RuuviLocalization.tr("Localizable", "SignIn.VerificationCodePlaceholder", fallback: "verification code in format: CJSM") - public enum EmailMismatch { - public enum Alert { - /// Oops, you've requested the code for %@, but used the code for %@. Please double check that you are using the code for %@ - public static func message(_ p1: Any, _ p2: Any, _ p3: Any) -> String { - RuuviLocalization.tr("Localizable", "SignIn.EmailMismatch.Alert.message", String(describing: p1), String(describing: p2), String(describing: p3), fallback: "Oops, you've requested the code for %@, but used the code for %@. Please double check that you are using the code for %@") - } - } - } - public enum EmailMissing { - public enum Alert { - /// Oops, the email you've used to get the code was not saved. Please try to sign in again. - public static let message = RuuviLocalization.tr("Localizable", "SignIn.EmailMissing.Alert.message", fallback: "Oops, the email you've used to get the code was not saved. Please try to sign in again.") - } - } - public enum SubtitleLabel { - /// To enjoy all the features, create a free account or sign in to your existing Ruuvi account by entering your email address. - public static let text = RuuviLocalization.tr("Localizable", "SignIn.SubtitleLabel.text", fallback: "To enjoy all the features, create a free account or sign in to your existing Ruuvi account by entering your email address.") - } - public enum Sync { - /// Downloading content from the cloud. Please wait. - public static let message = RuuviLocalization.tr("Localizable", "SignIn.Sync.message", fallback: "Downloading content from the cloud. Please wait.") - } - public enum Title { - /// Sign in - public static let text = RuuviLocalization.tr("Localizable", "SignIn.Title.text", fallback: "Sign in") - } - public enum TitleLabel { - /// Sign in to - /// Ruuvi - /// Station - public static let text = RuuviLocalization.tr("Localizable", "SignIn.TitleLabel.text", fallback: "Sign in to\nRuuvi\nStation") - } - } - public enum TagCharts { - public enum AbortSync { - public enum Alert { - /// Sometimes the history download is slow due to the Bluetooth connectivity. Please wait a moment. - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.AbortSync.Alert.message", fallback: "Sometimes the history download is slow due to the Bluetooth connectivity. Please wait a moment.") - } - public enum Button { - /// Abort download - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.AbortSync.Button.title", fallback: "Abort download") - } - } - public enum BluetoothDisabledAlert { - /// Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on. - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.BluetoothDisabledAlert.message", fallback: "Ruuvi Station needs Bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on.") - /// Bluetooth is not enabled - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.BluetoothDisabledAlert.title", fallback: "Bluetooth is not enabled") - } - public enum Clear { - /// Clear - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Clear.title", fallback: "Clear") - } - public enum DeleteHistoryConfirmationDialog { - /// Clear the local history data from the app? - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.message", fallback: "Clear the local history data from the app?") - /// Are you sure? - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.title", fallback: "Are you sure?") - public enum Button { - public enum Delete { - /// Delete - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.DeleteHistoryConfirmationDialog.button.delete.title", fallback: "Delete") - } - } - } - public enum Dismiss { - public enum Alert { - /// The history download via Bluetooth connection is in progress. Please wait. - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.Dismiss.Alert.message", fallback: "The history download via Bluetooth connection is in progress. Please wait.") - } - } - public enum Export { - /// EXPORT - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Export.title", fallback: "EXPORT") - } - public enum FailedToSyncDialog { - /// Bluetooth history download failed. Check that you're within Bluetooth range, your sensor has firmware that supports downloading and that the sensor is not simultaneously connected to another iOS device. Sensor connection is reserved for Ruuvi Station when using connected mode in iOS. - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.FailedToSyncDialog.message", fallback: "Bluetooth history download failed. Check that you're within Bluetooth range, your sensor has firmware that supports downloading and that the sensor is not simultaneously connected to another iOS device. Sensor connection is reserved for Ruuvi Station when using connected mode in iOS.") - /// Download failed - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.FailedToSyncDialog.title", fallback: "Download failed") - } - public enum NoChartData { - /// No chart data available - public static let text = RuuviLocalization.tr("Localizable", "TagCharts.NoChartData.text", fallback: "No chart data available") - } - public enum Status { - /// Connecting... - public static let connecting = RuuviLocalization.tr("Localizable", "TagCharts.Status.Connecting", fallback: "Connecting...") - /// Disconnecting... - public static let disconnecting = RuuviLocalization.tr("Localizable", "TagCharts.Status.Disconnecting", fallback: "Disconnecting...") - /// Error - public static let error = RuuviLocalization.tr("Localizable", "TagCharts.Status.Error", fallback: "Error") - /// Reading history - public static let readingHistory = RuuviLocalization.tr("Localizable", "TagCharts.Status.ReadingHistory", fallback: "Reading history") - /// Synchronising... - public static let serving = RuuviLocalization.tr("Localizable", "TagCharts.Status.Serving", fallback: "Synchronising...") - /// Success - public static let success = RuuviLocalization.tr("Localizable", "TagCharts.Status.Success", fallback: "Success") - } - public enum Sync { - /// Sync - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.Sync.title", fallback: "Sync") - } - public enum SyncConfirmationDialog { - /// Download history data from the sensor? - public static let message = RuuviLocalization.tr("Localizable", "TagCharts.SyncConfirmationDialog.message", fallback: "Download history data from the sensor?") - /// Are you sure? - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.SyncConfirmationDialog.title", fallback: "Are you sure?") - } - public enum TryAgain { - /// Try again - public static let title = RuuviLocalization.tr("Localizable", "TagCharts.TryAgain.title", fallback: "Try again") - } - } - public enum TagChartsPresenter { - /// Synchronised: %@ - public static func numberOfPointsSynchronizedOverNetwork(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "TagChartsPresenter.NumberOfPointsSynchronizedOverNetwork", String(describing: p1), fallback: "Synchronised: %@") - } - } - public enum TagSettings { - /// Share - public static let shareButton = RuuviLocalization.tr("Localizable", "TagSettings.ShareButton", fallback: "Share") - public enum AirHumidityAlert { - /// Air Humidity (%@) - public static func title(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.AirHumidityAlert.title", String(describing: p1), fallback: "Air Humidity (%@)") - } - } - public enum Alert { - public enum CustomDescription { - /// Set custom description... - public static let placeholder = RuuviLocalization.tr("Localizable", "TagSettings.Alert.CustomDescription.placeholder", fallback: "Set custom description...") - /// Alert custom description - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.CustomDescription.title", fallback: "Alert custom description") - } - public enum SetHumidity { - /// Set humidity alert - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetHumidity.title", fallback: "Set humidity alert") - } - public enum SetPressure { - /// Set pressure alert - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetPressure.title", fallback: "Set pressure alert") - } - public enum SetRSSI { - /// Set signal strength alert - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetRSSI.title", fallback: "Set signal strength alert") - } - public enum SetTemperature { - /// Set temperature alert - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Alert.SetTemperature.title", fallback: "Set temperature alert") - } - } - public enum AlertSettings { - public enum Dialog { - /// Max (%.0f) - public static func max(_ p1: Float) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.AlertSettings.Dialog.Max", p1, fallback: "Max (%.0f)") - } - /// Min (%.0f) - public static func min(_ p1: Float) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.AlertSettings.Dialog.Min", p1, fallback: "Min (%.0f)") - } - } - } - public enum Alerts { - /// Off - public static let off = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Off", fallback: "Off") - public enum Connection { - /// Alert when connected/disconnected - public static let description = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Connection.description", fallback: "Alert when connected/disconnected") - } - public enum DewPoint { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.Alerts.DewPoint.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - public enum Humidity { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Humidity.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - public enum Movement { - /// Alert when sensor is moved - public static let description = RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Movement.description", fallback: "Alert when sensor is moved") - } - public enum Pressure { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Pressure.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - public enum Temperature { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.Alerts.Temperature.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - } - public enum AlertsAreDisabled { - public enum Dialog { - public enum BothNotConnectedAndNoPNPermission { - /// Alerts are disabled because the device is not connected and missing push notification permission. Please connect to the device first. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.BothNotConnectedAndNoPNPermission.message", fallback: "Alerts are disabled because the device is not connected and missing push notification permission. Please connect to the device first.") - } - public enum Connect { - /// Connect - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.Connect.title", fallback: "Connect") - } - public enum NotConnected { - /// Alerts are disabled because you are not connected to the device. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.AlertsAreDisabled.Dialog.NotConnected.message", fallback: "Alerts are disabled because you are not connected to the device.") - } - } - } - public enum BatteryStatusLabel { - public enum Ok { - /// Battery OK - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.BatteryStatusLabel.Ok.message", fallback: "Battery OK") - } - public enum Replace { - /// Low battery - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.BatteryStatusLabel.Replace.message", fallback: "Low battery") - } - } - public enum ClaimTagButton { - /// Claim ownership - public static let claim = RuuviLocalization.tr("Localizable", "TagSettings.ClaimTagButton.Claim", fallback: "Claim ownership") - } - public enum ConnectStatus { - /// Disconnected - public static let disconnected = RuuviLocalization.tr("Localizable", "TagSettings.ConnectStatus.Disconnected", fallback: "Disconnected") - } - public enum ConnectionAlert { - /// Connection - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.ConnectionAlert.title", fallback: "Connection") - } - public enum DataSource { - public enum Advertisement { - /// Advertisement - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Advertisement.title", fallback: "Advertisement") - } - public enum Heartbeat { - /// Heartbeat - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Heartbeat.title", fallback: "Heartbeat") - } - public enum Network { - /// Cloud - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.DataSource.Network.title", fallback: "Cloud") - } - } - public enum EmptyValue { - /// - - public static let sign = RuuviLocalization.tr("Localizable", "TagSettings.EmptyValue.sign", fallback: "-") - } - public enum Firmware { - /// Current version - public static let currentVersion = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.CurrentVersion", fallback: "Current version") - /// Update - public static let updateFirmware = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.UpdateFirmware", fallback: "Update") - public enum CurrentVersion { - /// Very old - public static let veryOld = RuuviLocalization.tr("Localizable", "TagSettings.Firmware.CurrentVersion.VeryOld", fallback: "Very old") - } - } - public enum General { - public enum Owner { - /// No owner - public static let `none` = RuuviLocalization.tr("Localizable", "TagSettings.General.Owner.none", fallback: "No owner") - } - } - public enum HumidityIsClipped { - public enum Alert { - /// Humidity value is greater than 100% after calibration. This value doesn't make sense, so the value has been adjusted to 100%. - public static func message(_ p1: Float) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.message", p1, fallback: "Humidity value is greater than 100% after calibration. This value doesn't make sense, so the value has been adjusted to 100%.") - } - /// Humidity is adjusted - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.title", fallback: "Humidity is adjusted") - public enum Fix { - /// Fix - public static let button = RuuviLocalization.tr("Localizable", "TagSettings.HumidityIsClipped.Alert.Fix.button", fallback: "Fix") - } - } - } - public enum Label { - public enum Alerts { - /// Alerts - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.alerts.text", fallback: "Alerts") - } - public enum Disabled { - /// DISABLED? - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.disabled.text", fallback: "DISABLED?") - } - public enum MoreInfo { - /// More info - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.moreInfo.text", fallback: "More info") - } - public enum NoValues { - /// NO VALUES? - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.Label.noValues.text", fallback: "NO VALUES?") - } - } - public enum Mac { - public enum Alert { - /// MAC Address - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Mac.Alert.title", fallback: "MAC Address") - } - } - public enum MovementAlert { - /// Movement - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.MovementAlert.title", fallback: "Movement") - } - public enum NetworkInfo { - /// Owner - public static let owner = RuuviLocalization.tr("Localizable", "TagSettings.NetworkInfo.Owner", fallback: "Owner") - } - public enum NotShared { - /// Not shared - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.NotShared.title", fallback: "Not shared") - } - public enum OffsetCorrection { - /// Humidity - public static let humidity = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Humidity", fallback: "Humidity") - /// Pressure - public static let pressure = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Pressure", fallback: "Pressure") - /// Temperature - public static let temperature = RuuviLocalization.tr("Localizable", "TagSettings.OffsetCorrection.Temperature", fallback: "Temperature") - } - public enum PairAndBackgroundScan { - /// Alerts are not available over Bluetooth connection if background scanning is not enabled. Only one iOS device can be paired to a Ruuvi sensor at a time. - public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.description", fallback: "Alerts are not available over Bluetooth connection if background scanning is not enabled. Only one iOS device can be paired to a Ruuvi sensor at a time.") - public enum Paired { - /// Paired and background scan is on - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Paired.title", fallback: "Paired and background scan is on") - } - public enum Pairing { - /// Connecting to the sensor - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Pairing.title", fallback: "Connecting to the sensor") - } - public enum Unpaired { - /// Pair and use background scan - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.PairAndBackgroundScan.Unpaired.title", fallback: "Pair and use background scan") - } - } - public enum PairError { - public enum CloudMode { - /// The sensor cannot be connected to via Bluetooth when the cloud mode is active. You can re-enable the Bluetooth connection for the cloud sensors by disabling cloud mode in the app settings. - public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairError.CloudMode.description", fallback: "The sensor cannot be connected to via Bluetooth when the cloud mode is active. You can re-enable the Bluetooth connection for the cloud sensors by disabling cloud mode in the app settings.") - } - public enum Timeout { - /// Connection timed out. Pairing was unsuccessful. Please try again. - public static let description = RuuviLocalization.tr("Localizable", "TagSettings.PairError.Timeout.description", fallback: "Connection timed out. Pairing was unsuccessful. Please try again.") - } - } - public enum PressureAlert { - /// Air Pressure (%@) - public static func title(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.PressureAlert.title", String(describing: p1), fallback: "Air Pressure (%@)") - } - } - public enum RemoveThisSensor { - /// Remove this sensor - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.RemoveThisSensor.title", fallback: "Remove this sensor") - } - public enum SectionHeader { - public enum BTConnection { - /// BLUETOOTH CONNECTION - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.BTConnection.title", fallback: "BLUETOOTH CONNECTION") - } - public enum Calibration { - /// CALIBRATION - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Calibration.title", fallback: "CALIBRATION") - } - public enum Firmware { - /// Firmware - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Firmware.title", fallback: "Firmware") - } - public enum General { - /// General - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.General.title", fallback: "General") - } - public enum Name { - /// NAME - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Name.title", fallback: "NAME") - } - public enum NetworkInfo { - /// NETWORK INFO - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.NetworkInfo.title", fallback: "NETWORK INFO") - } - public enum OffsetCorrection { - /// OFFSET CORRECTION - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.OffsetCorrection.Title", fallback: "OFFSET CORRECTION") - } - public enum Remove { - /// REMOVE - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.SectionHeader.Remove.title", fallback: "REMOVE") - } - } - public enum Share { - /// Share - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Share.title", fallback: "Share") - } - public enum Shared { - /// Shared - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.Shared.title", fallback: "Shared") - } - public enum Uuid { - public enum Alert { - /// UUID - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UUID.Alert.title", fallback: "UUID") - } - } - public enum UpdateFirmware { - public enum Alert { - /// In order to see missing values: - /// If you are using the latest firmware, set RAWv2 mode by pressing "B" on a sensor. - /// Or update your sensor with the latest firmware. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.message", fallback: "In order to see missing values:\nIf you are using the latest firmware, set RAWv2 mode by pressing \"B\" on a sensor.\nOr update your sensor with the latest firmware.") - /// RAWv2 mode is required - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.title", fallback: "RAWv2 mode is required") - public enum Buttons { - public enum LearnMore { - /// Learn more - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.UpdateFirmware.Alert.Buttons.LearnMore.title", fallback: "Learn more") - } - } - } - } - public enum AccelerationXTitleLabel { - /// Acceleration X - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationXTitleLabel.text", fallback: "Acceleration X") - } - public enum AccelerationYTitleLabel { - /// Acceleration Y - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationYTitleLabel.text", fallback: "Acceleration Y") - } - public enum AccelerationZTitleLabel { - /// Acceleration Z - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.accelerationZTitleLabel.text", fallback: "Acceleration Z") - } - public enum BackgroundImageLabel { - /// Background image - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.backgroundImageLabel.text", fallback: "Background image") - } - public enum BatteryVoltageTitleLabel { - /// Battery Voltage - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.batteryVoltageTitleLabel.text", fallback: "Battery Voltage") - } - public enum ConfirmSharedTagRemovalDialog { - /// If you remove the sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmSharedTagRemovalDialog.message", fallback: "If you remove the sensor, the owner of the sensor will be notified and you will not be able to access the sensor anymore.") - } - public enum ConfirmTagRemovalDialog { - /// Do you want to remove the sensor? You can add it again later, if needed. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagRemovalDialog.message", fallback: "Do you want to remove the sensor? You can add it again later, if needed.") - /// Remove sensor - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagRemovalDialog.title", fallback: "Remove sensor") - } - public enum ConfirmTagUnclaimAndRemoveDialog { - /// By removing the sensor, your sensor ownership status will be revoked. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner. - public static let message = RuuviLocalization.tr("Localizable", "TagSettings.confirmTagUnclaimAndRemoveDialog.message", fallback: "By removing the sensor, your sensor ownership status will be revoked. After removal, someone else can claim ownership of the sensor. Each Ruuvi sensor can have only one owner.") - } - public enum DataFormatTitleLabel { - /// Data Format - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dataFormatTitleLabel.text", fallback: "Data Format") - } - public enum DataSourceTitleLabel { - /// Data Received Via - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dataSourceTitleLabel.text", fallback: "Data Received Via") - } - public enum DewPointAlertTitleLabel { - /// Dew Point - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.dewPointAlertTitleLabel.text", fallback: "Dew Point") - } - public enum HumidityTitleLabel { - /// Humidity - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.humidityTitleLabel.text", fallback: "Humidity") - } - public enum MacAddressTitleLabel { - /// MAC Address - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.macAddressTitleLabel.text", fallback: "MAC Address") - } - public enum McTitleLabel { - /// Movement Counter - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.mcTitleLabel.text", fallback: "Movement Counter") - } - public enum MsnTitleLabel { - /// Measurement Sequence Number - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.msnTitleLabel.text", fallback: "Measurement Sequence Number") - } - public enum NavigationItem { - /// Sensor Settings - public static let title = RuuviLocalization.tr("Localizable", "TagSettings.navigationItem.title", fallback: "Sensor Settings") - } - public enum RssiTitleLabel { - /// Signal Strength (RSSI) - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.rssiTitleLabel.text", fallback: "Signal Strength (RSSI)") - } - public enum TagNameTitleLabel { - /// Name - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.tagNameTitleLabel.text", fallback: "Name") - public enum Rename { - /// Your sensors are displayed in alphabetical order. - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.tagNameTitleLabel.rename.text", fallback: "Your sensors are displayed in alphabetical order.") - } - } - public enum TemperatureAlertTitleLabel { - /// Temperature (%@) - public static func text(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "TagSettings.temperatureAlertTitleLabel.text", String(describing: p1), fallback: "Temperature (%@)") - } - } - public enum TxPowerTitleLabel { - /// Tx Power - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.txPowerTitleLabel.text", fallback: "Tx Power") - } - public enum UuidTitleLabel { - /// UUID - public static let text = RuuviLocalization.tr("Localizable", "TagSettings.uuidTitleLabel.text", fallback: "UUID") - } - } - public enum TagsManagerPresenter { - public enum SignOutConfirmAlert { - /// When you sign out, sensors the ownerships of which you've claimed on the sensor Settings page will be automatically removed from the app. When you sign in again using the same email address, the sensors will be returned from the cloud. - /// - /// Do you want to sign out? - public static let message = RuuviLocalization.tr("Localizable", "TagsManagerPresenter.SignOutConfirmAlert.Message", fallback: "When you sign out, sensors the ownerships of which you've claimed on the sensor Settings page will be automatically removed from the app. When you sign in again using the same email address, the sensors will be returned from the cloud.\n\nDo you want to sign out?") - } - } - public enum TemperatureUnit { - public enum Celsius { - /// Celsius (℃) - public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Celsius.title", fallback: "Celsius (℃)") - } - public enum Fahrenheit { - /// Fahrenheit (℉) - public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Fahrenheit.title", fallback: "Fahrenheit (℉)") - } - public enum Kelvin { - /// Kelvin (K) - public static let title = RuuviLocalization.tr("Localizable", "TemperatureUnit.Kelvin.title", fallback: "Kelvin (K)") - } - } - public enum UnexpectedError { - /// Attempt to read data from Realm without LUID - public static let attemptToReadDataFromRealmWithoutLUID = RuuviLocalization.tr("Localizable", "UnexpectedError.attemptToReadDataFromRealmWithoutLUID", fallback: "Attempt to read data from Realm without LUID") - /// Both local and MAC identifiers are nil - public static let bothLuidAndMacAreNil = RuuviLocalization.tr("Localizable", "UnexpectedError.bothLuidAndMacAreNil", fallback: "Both local and MAC identifiers are nil") - /// Both callback result and error are nil - public static let callbackErrorAndResultAreNil = RuuviLocalization.tr("Localizable", "UnexpectedError.callbackErrorAndResultAreNil", fallback: "Both callback result and error are nil") - /// Caller was deallocated during operation - public static let callerDeinitedDuringOperation = RuuviLocalization.tr("Localizable", "UnexpectedError.callerDeinitedDuringOperation", fallback: "Caller was deallocated during operation") - /// Failed to find logs for the sensor - public static let failedToFindLogsForTheTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindLogsForTheTag", fallback: "Failed to find logs for the sensor") - /// Failed to find or generate background image - public static let failedToFindOrGenerateBackgroundImage = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindOrGenerateBackgroundImage", fallback: "Failed to find or generate background image") - /// Failed to find sensor - public static let failedToFindRuuviTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindRuuviTag", fallback: "Failed to find sensor") - /// Failed to find virtual sensor - public static let failedToFindVirtualTag = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToFindVirtualTag", fallback: "Failed to find virtual sensor") - /// Failed to reverse geocode location - public static let failedToReverseGeocodeCoordinate = RuuviLocalization.tr("Localizable", "UnexpectedError.failedToReverseGeocodeCoordinate", fallback: "Failed to reverse geocode location") - /// View Model UUID is nil - public static let viewModelUUIDIsNil = RuuviLocalization.tr("Localizable", "UnexpectedError.viewModelUUIDIsNil", fallback: "View Model UUID is nil") - } - public enum UnitPressure { - public enum Hectopascal { - /// Hectopascal (hPa) - public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.hectopascal.title", fallback: "Hectopascal (hPa)") - } - public enum InchOfMercury { - /// Inch of mercury (inHg) - public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.inchOfMercury.title", fallback: "Inch of mercury (inHg)") - } - public enum MillimetreOfMercury { - /// Millimetre of mercury (mmHg) - public static let title = RuuviLocalization.tr("Localizable", "UnitPressure.millimetreOfMercury.title", fallback: "Millimetre of mercury (mmHg)") - } - } - public enum UpdateFirmware { - public enum Download { - /// To start with the update process, first download the latest software package on the device you're going to use for updates. Latest version is available on ruuvi.com/software-update - public static let content = RuuviLocalization.tr("Localizable", "UpdateFirmware.Download.content", fallback: "To start with the update process, first download the latest software package on the device you're going to use for updates. Latest version is available on ruuvi.com/software-update") - /// DOWNLOAD LATEST FIRMWARE - public static let header = RuuviLocalization.tr("Localizable", "UpdateFirmware.Download.header", fallback: "DOWNLOAD LATEST FIRMWARE") - } - public enum NextButton { - /// NEXT - public static let title = RuuviLocalization.tr("Localizable", "UpdateFirmware.NextButton.title", fallback: "NEXT") - } - public enum SetDfu { - /// Open the RuuviTag's enclosure by pulling it open with your fingers or gently with a flat head screw driver. - /// - /// Set RuuviTag to bootloader mode by holding down button B and pressing reset button R. Red indicator LED light will light up and stay on. If your device has only 1 button, keep it pressed 10 seconds to enter the bootloader. - public static let content = RuuviLocalization.tr("Localizable", "UpdateFirmware.SetDfu.content", fallback: "Open the RuuviTag's enclosure by pulling it open with your fingers or gently with a flat head screw driver.\n\nSet RuuviTag to bootloader mode by holding down button B and pressing reset button R. Red indicator LED light will light up and stay on. If your device has only 1 button, keep it pressed 10 seconds to enter the bootloader.") - /// SET RUUVI TAG TO DFU MODE - public static let header = RuuviLocalization.tr("Localizable", "UpdateFirmware.SetDfu.header", fallback: "SET RUUVI TAG TO DFU MODE") - } - public enum Title { - /// Update Firmware - public static let text = RuuviLocalization.tr("Localizable", "UpdateFirmware.Title.text", fallback: "Update Firmware") - } - } - public enum UserApiError { - /// Maximum claim count for the user reached - public static let erClaimCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_CLAIM_COUNT_REACHED", fallback: "Maximum claim count for the user reached") - /// Data already exists, cannot update - public static let erConflict = RuuviLocalization.tr("Localizable", "UserApiError.ER_CONFLICT", fallback: "Data already exists, cannot update") - /// Forbidden - public static let erForbidden = RuuviLocalization.tr("Localizable", "UserApiError.ER_FORBIDDEN", fallback: "Forbidden") - /// Gateway already whitelisted - public static let erGatewayAlreadyWhitelisted = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_ALREADY_WHITELISTED", fallback: "Gateway already whitelisted") - /// Gateway not found - public static let erGatewayNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_NOT_FOUND", fallback: "Gateway not found") - /// Gateway status report failed - public static let erGatewayStatusReportFailed = RuuviLocalization.tr("Localizable", "UserApiError.ER_GATEWAY_STATUS_REPORT_FAILED", fallback: "Gateway status report failed") - /// Internal error - public static let erInternal = RuuviLocalization.tr("Localizable", "UserApiError.ER_INTERNAL", fallback: "Internal error") - /// Invalid density mode - public static let erInvalidDensityMode = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_DENSITY_MODE", fallback: "Invalid density mode") - /// Invalid email address - public static let erInvalidEmailAddress = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_EMAIL_ADDRESS", fallback: "Invalid email address") - /// Invalid ENUM value given - public static let erInvalidEnumValue = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_ENUM_VALUE", fallback: "Invalid ENUM value given") - /// Invalid request format - public static let erInvalidFormat = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_FORMAT", fallback: "Invalid request format") - /// Invalid MAC-address - public static let erInvalidMacAddress = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_MAC_ADDRESS", fallback: "Invalid MAC-address") - /// Invalid sort mode - public static let erInvalidSortMode = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_SORT_MODE", fallback: "Invalid sort mode") - /// Invalid time range - public static let erInvalidTimeRange = RuuviLocalization.tr("Localizable", "UserApiError.ER_INVALID_TIME_RANGE", fallback: "Invalid time range") - /// Missing argument - public static let erMissingArgument = RuuviLocalization.tr("Localizable", "UserApiError.ER_MISSING_ARGUMENT", fallback: "Missing argument") - /// In order to share a sensor, it must have data - public static let erNoDataToShare = RuuviLocalization.tr("Localizable", "UserApiError.ER_NO_DATA_TO_SHARE", fallback: "In order to share a sensor, it must have data") - /// Newer data already exists, cannot update - public static let erOldEntry = RuuviLocalization.tr("Localizable", "UserApiError.ER_OLD_ENTRY", fallback: "Newer data already exists, cannot update") - /// Sensor already claimed by %@ - public static func erSensorAlreadyClaimed(_ p1: Any) -> String { - RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_CLAIMED", String(describing: p1), fallback: "Sensor already claimed by %@") - } - /// Sensor already claimed - public static let erSensorAlreadyClaimedNoEmail = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_CLAIMED_NO_EMAIL", fallback: "Sensor already claimed") - /// The sensor has already been registered - public static let erSensorAlreadyRegistered = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_REGISTERED", fallback: "The sensor has already been registered") - /// This sensor is already shared - public static let erSensorAlreadyShared = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_ALREADY_SHARED", fallback: "This sensor is already shared") - /// Sensor not found - public static let erSensorNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_NOT_FOUND", fallback: "Sensor not found") - /// Maximum share count for the sensor reached - public static let erSensorShareCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_SENSOR_SHARE_COUNT_REACHED", fallback: "Maximum share count for the sensor reached") - /// The share limit is reached - public static let erShareCountReached = RuuviLocalization.tr("Localizable", "UserApiError.ER_SHARE_COUNT_REACHED", fallback: "The share limit is reached") - /// Data storage error - public static let erSubDataStorageError = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUB_DATA_STORAGE_ERROR", fallback: "Data storage error") - /// No user - public static let erSubNoUser = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUB_NO_USER", fallback: "No user") - /// Tried to add duplicate subscription to a code - public static let erSubscriptionCodeExists = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_CODE_EXISTS", fallback: "Tried to add duplicate subscription to a code") - /// Tried to claim already used code - public static let erSubscriptionCodeUsed = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_CODE_USED", fallback: "Tried to claim already used code") - /// Subscription is not found - public static let erSubscriptionNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_SUBSCRIPTION_NOT_FOUND", fallback: "Subscription is not found") - /// Too many requests - public static let erThrottled = RuuviLocalization.tr("Localizable", "UserApiError.ER_THROTTLED", fallback: "Too many requests") - /// Token is expired - public static let erTokenExpired = RuuviLocalization.tr("Localizable", "UserApiError.ER_TOKEN_EXPIRED", fallback: "Token is expired") - /// Unable to send email - public static let erUnableToSendEmail = RuuviLocalization.tr("Localizable", "UserApiError.ER_UNABLE_TO_SEND_EMAIL", fallback: "Unable to send email") - /// Unauthorised - public static let erUnauthorized = RuuviLocalization.tr("Localizable", "UserApiError.ER_UNAUTHORIZED", fallback: "Unauthorised") - /// User not found - public static let erUserNotFound = RuuviLocalization.tr("Localizable", "UserApiError.ER_USER_NOT_FOUND", fallback: "User not found") - /// Operation was successful - public static let ok = RuuviLocalization.tr("Localizable", "UserApiError.OK", fallback: "Operation was successful") - } - public enum WebTagLocationSource { - /// Your location - public static let current = RuuviLocalization.tr("Localizable", "WebTagLocationSource.current", fallback: "Your location") - /// Pick from the map - public static let manual = RuuviLocalization.tr("Localizable", "WebTagLocationSource.manual", fallback: "Pick from the map") - } - public enum WebTagSettings { - public enum AirHumidityAlert { - /// Air Humidity - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.AirHumidityAlert.title", fallback: "Air Humidity") - } - public enum Alerts { - /// Off - public static let off = RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Off", fallback: "Off") - public enum DewPoint { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.DewPoint.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - public enum Humidity { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Humidity.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - public enum Pressure { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Pressure.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - public enum Temperature { - /// Alert when less than %.0f or more than %.0f - public static func description(_ p1: Float, _ p2: Float) -> String { - RuuviLocalization.tr("Localizable", "WebTagSettings.Alerts.Temperature.description", p1, p2, fallback: "Alert when less than %.0f or more than %.0f") - } - } - } - public enum AlertsAreDisabled { - public enum Dialog { - public enum BothNoPNPermissionAndNoLocationPermission { - /// In order to enable virtual sensor alerts please always grant location and notification permissions in Settings. - public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.AlertsAreDisabled.Dialog.BothNoPNPermissionAndNoLocationPermission.message", fallback: "In order to enable virtual sensor alerts please always grant location and notification permissions in Settings.") - } - public enum Settings { - /// Settings - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.AlertsAreDisabled.Dialog.Settings.title", fallback: "Settings") - } - } - } - public enum Button { - public enum Remove { - /// REMOVE THIS VIRTUAL SENSOR - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.Button.Remove.title", fallback: "REMOVE THIS VIRTUAL SENSOR") - } - } - public enum Label { - public enum BackgroundImage { - /// BACKGROUND - /// IMAGE - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.BackgroundImage.text", fallback: "BACKGROUND\nIMAGE") - } - public enum Location { - /// Location - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.Location.text", fallback: "Location") - } - public enum TagName { - /// Sensor Name - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.TagName.text", fallback: "Sensor Name") - } - public enum Alerts { - /// ALERTS - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.alerts.text", fallback: "ALERTS") - } - public enum Disabled { - /// DISABLED? - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.Label.disabled.text", fallback: "DISABLED?") - } - } - public enum Location { - /// Your location - public static let current = RuuviLocalization.tr("Localizable", "WebTagSettings.Location.Current", fallback: "Your location") - } - public enum PressureAlert { - /// Air Pressure - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.PressureAlert.title", fallback: "Air Pressure") - } - public enum SectionHeader { - public enum MoreInfo { - /// MORE INFO - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.SectionHeader.MoreInfo.title", fallback: "MORE INFO") - } - public enum Name { - /// NAME - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.SectionHeader.Name.title", fallback: "NAME") - } - } - public enum ConfirmClearLocationDialog { - /// Are you sure you want to clear location for this virtual sensor? Current location will be used instead. - public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmClearLocationDialog.message", fallback: "Are you sure you want to clear location for this virtual sensor? Current location will be used instead.") - /// Clear Location - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmClearLocationDialog.title", fallback: "Clear Location") - } - public enum ConfirmTagRemovalDialog { - /// Are you sure you want to remove this virtual sensor? - public static let message = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmTagRemovalDialog.message", fallback: "Are you sure you want to remove this virtual sensor?") - /// Remove virtual sensor - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.confirmTagRemovalDialog.title", fallback: "Remove virtual sensor") - } - public enum DewPointAlertTitleLabel { - /// Dew Point - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.dewPointAlertTitleLabel.text", fallback: "Dew Point") - } - public enum NavigationItem { - /// Virtual Sensor Settings - public static let title = RuuviLocalization.tr("Localizable", "WebTagSettings.navigationItem.title", fallback: "Virtual Sensor Settings") - } - public enum TemperatureAlertTitleLabel { - /// Temperature - public static let text = RuuviLocalization.tr("Localizable", "WebTagSettings.temperatureAlertTitleLabel.text", fallback: "Temperature") - } - } - public enum Welcome { - public enum Description { - /// To find nearby sensors and receive live sensor data, press 'scan'. - public static let text = RuuviLocalization.tr("Localizable", "Welcome.description.text", fallback: "To find nearby sensors and receive live sensor data, press 'scan'.") - } - public enum Scan { - /// SCAN - public static let title = RuuviLocalization.tr("Localizable", "Welcome.scan.title", fallback: "SCAN") - } - } - public enum Widgets { - public enum Description { - /// Create widgets of your favourite Ruuvi sensors. Widgets update from the Ruuvi Cloud. A Ruuvi Gateway router is required. - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Description.message", fallback: "Create widgets of your favourite Ruuvi sensors. Widgets update from the Ruuvi Cloud. A Ruuvi Gateway router is required.") - } - public enum Loading { - /// loading... - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Loading.message", fallback: "loading...") - } - public enum Select { - public enum Sensor { - /// Selected Ruuvi sensor - public static let title = RuuviLocalization.tr("Localizable", "Widgets.Select.Sensor.title", fallback: "Selected Ruuvi sensor") - } - } - public enum Sensor { - public enum `Type` { - /// Selected sensor type - public static let title = RuuviLocalization.tr("Localizable", "Widgets.Sensor.Type.title", fallback: "Selected sensor type") - } - } - public enum Unauthorized { - public enum Inline { - /// Sign in to Ruuvi Station - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unauthorized.Inline.message", fallback: "Sign in to Ruuvi Station") - } - public enum Regular { - /// Sign in to use the widget. - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unauthorized.Regular.message", fallback: "Sign in to use the widget.") - } - } - public enum Unconfigured { - public enum Circular { - /// +Add - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Circular.message", fallback: "+Add") - } - public enum Inline { - /// Add sensor to use Ruuvi Widget - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Inline.message", fallback: "Add sensor to use Ruuvi Widget") - } - public enum Rectangular { - /// Add sensor to use Ruuvi Widget - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Rectangular.message", fallback: "Add sensor to use Ruuvi Widget") - } - public enum Simple { - /// Force tap to edit the widget. - public static let message = RuuviLocalization.tr("Localizable", "Widgets.Unconfigured.Simple.message", fallback: "Force tap to edit the widget.") - } - } - } -} -// swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length -// swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces - -// MARK: - Implementation Details - -extension RuuviLocalization { - private static func tr(_ table: String, _ key: String, _ args: CVarArg..., fallback value: String) -> String { - let format = BundleToken.bundle.localizedString(forKey: key, value: value, table: table) - return String(format: format, locale: Locale.current, arguments: args) - } -} - -// swiftlint:disable convenience_type -private final class BundleToken { - static let bundle: Bundle = { - #if SWIFT_PACKAGE - return Bundle.module - #else - return Bundle(for: BundleToken.self) - #endif - }() -} -// swiftlint:enable convenience_type -// swiftlint:enable all diff --git a/Common/RuuviLocalization/Templates/structured-swift5.stencil b/Common/RuuviLocalization/Templates/strings-swift5.stencil similarity index 100% rename from Common/RuuviLocalization/Templates/structured-swift5.stencil rename to Common/RuuviLocalization/Templates/strings-swift5.stencil diff --git a/Common/RuuviLocalization/Templates/xcassets-swift5.stencil b/Common/RuuviLocalization/Templates/xcassets-swift5.stencil new file mode 100644 index 000000000..5fa01e074 --- /dev/null +++ b/Common/RuuviLocalization/Templates/xcassets-swift5.stencil @@ -0,0 +1,438 @@ +// swiftlint:disable all +// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen + +{% if catalogs %} +{% macro hasValuesBlock assets filter %} + {%- for asset in assets -%} + {%- if asset.type == filter -%} + 1 + {%- elif asset.items -%} + {% call hasValuesBlock asset.items filter %} + {%- endif -%} + {%- endfor -%} +{% endmacro %} +{% set enumName %}{{param.enumName|default:"Asset"}}{% endset %} +{% set arResourceGroupType %}{{param.arResourceGroupTypeName|default:"ARResourceGroupAsset"}}{% endset %} +{% set colorType %}{{param.colorTypeName|default:"ColorAsset"}}{% endset %} +{% set dataType %}{{param.dataTypeName|default:"DataAsset"}}{% endset %} +{% set imageType %}{{param.imageTypeName|default:"ImageAsset"}}{% endset %} +{% set symbolType %}{{param.symbolTypeName|default:"SymbolAsset"}}{% endset %} +{% set forceNamespaces %}{{param.forceProvidesNamespaces|default:"false"}}{% endset %} +{% set accessModifier %}{% if param.publicAccess %}public{% else %}internal{% endif %}{% endset %} +{% set hasARResourceGroup %}{% for catalog in catalogs %}{% call hasValuesBlock catalog.assets "arresourcegroup" %}{% endfor %}{% endset %} +{% set hasColor %}{% for catalog in catalogs %}{% call hasValuesBlock catalog.assets "color" %}{% endfor %}{% endset %} +{% set hasData %}{% for catalog in catalogs %}{% call hasValuesBlock catalog.assets "data" %}{% endfor %}{% endset %} +{% set hasImage %}{% for catalog in catalogs %}{% call hasValuesBlock catalog.assets "image" %}{% endfor %}{% endset %} +{% set hasSymbol %}{% for catalog in catalogs %}{% call hasValuesBlock catalog.assets "symbol" %}{% endfor %}{% endset %} +#if os(macOS) + import AppKit +#elseif os(iOS) +{% if hasARResourceGroup %} + import ARKit +{% endif %} + import UIKit +#elseif os(tvOS) || os(watchOS) + import UIKit +#endif +#if canImport(SwiftUI) + import SwiftUI +#endif + +// Deprecated typealiases +{% if hasColor %} +@available(*, deprecated, renamed: "{{colorType}}.Color", message: "This typealias will be removed in SwiftGen 7.0") +{{accessModifier}} typealias {{param.colorAliasName|default:"AssetColorTypeAlias"}} = {{colorType}}.Color +{% endif %} +{% if hasImage %} +@available(*, deprecated, renamed: "{{imageType}}.Image", message: "This typealias will be removed in SwiftGen 7.0") +{{accessModifier}} typealias {{param.imageAliasName|default:"AssetImageTypeAlias"}} = {{imageType}}.Image +{% endif %} + +// swiftlint:disable superfluous_disable_command file_length implicit_return + +// MARK: - Asset Catalogs + +{% macro enumBlock assets %} + {% call casesBlock assets %} + {% if param.allValues %} + + // swiftlint:disable trailing_comma + {% set hasItems %}{% call hasValuesBlock assets "arresourcegroup" %}{% endset %} + {% if hasItems %} + @available(*, deprecated, message: "All values properties are now deprecated") + {{accessModifier}} static let allResourceGroups: [{{arResourceGroupType}}] = [ + {% filter indent:2," ",true %}{% call allValuesBlock assets "arresourcegroup" "" %}{% endfilter %} + ] + {% endif %} + {% set hasItems %}{% call hasValuesBlock assets "color" %}{% endset %} + {% if hasItems %} + @available(*, deprecated, message: "All values properties are now deprecated") + {{accessModifier}} static let allColors: [{{colorType}}] = [ + {% filter indent:2," ",true %}{% call allValuesBlock assets "color" "" %}{% endfilter %} + ] + {% endif %} + {% set hasItems %}{% call hasValuesBlock assets "data" %}{% endset %} + {% if hasItems %} + @available(*, deprecated, message: "All values properties are now deprecated") + {{accessModifier}} static let allDataAssets: [{{dataType}}] = [ + {% filter indent:2," ",true %}{% call allValuesBlock assets "data" "" %}{% endfilter %} + ] + {% endif %} + {% set hasItems %}{% call hasValuesBlock assets "image" %}{% endset %} + {% if hasItems %} + @available(*, deprecated, message: "All values properties are now deprecated") + {{accessModifier}} static let allImages: [{{imageType}}] = [ + {% filter indent:2," ",true %}{% call allValuesBlock assets "image" "" %}{% endfilter %} + ] + {% endif %} + {% set hasItems %}{% call hasValuesBlock assets "symbol" %}{% endset %} + {% if hasItems %} + @available(*, deprecated, message: "All values properties are now deprecated") + {{accessModifier}} static let allSymbols: [{{symbolType}}] = [ + {% filter indent:2," ",true %}{% call allValuesBlock assets "symbol" "" %}{% endfilter %} + ] + {% endif %} + // swiftlint:enable trailing_comma + {% endif %} +{% endmacro %} +{% macro casesBlock assets %} + {% for asset in assets %} + {% if asset.type == "arresourcegroup" %} + {{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{arResourceGroupType}}(name: "{{asset.value}}") + {% elif asset.type == "color" %} + {{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{colorType}}(name: "{{asset.value}}") + {% elif asset.type == "data" %} + {{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{dataType}}(name: "{{asset.value}}") + {% elif asset.type == "image" %} + {{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{imageType}}(name: "{{asset.value}}") + {% elif asset.type == "symbol" %} + {{accessModifier}} static let {{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{symbolType}}(name: "{{asset.value}}") + {% elif asset.items and ( forceNamespaces == "true" or asset.isNamespaced == "true" ) %} + {{accessModifier}} enum {{asset.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} { + {% filter indent:2," ",true %}{% call casesBlock asset.items %}{% endfilter %} + } + {% elif asset.items %} + {% call casesBlock asset.items %} + {% endif %} + {% endfor %} +{% endmacro %} +{% macro allValuesBlock assets filter prefix %} + {% for asset in assets %} + {% if asset.type == filter %} + {{prefix}}{{asset.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}, + {% elif asset.items and ( forceNamespaces == "true" or asset.isNamespaced == "true" ) %} + {% set prefix2 %}{{prefix}}{{asset.name|swiftIdentifier:"pretty"|escapeReservedKeywords}}.{% endset %} + {% call allValuesBlock asset.items filter prefix2 %} + {% elif asset.items %} + {% call allValuesBlock asset.items filter prefix %} + {% endif %} + {% endfor %} +{% endmacro %} +// swiftlint:disable identifier_name line_length nesting type_body_length type_name +{{accessModifier}} enum {{enumName}} { + {% if catalogs.count > 1 or param.forceFileNameEnum %} + {% for catalog in catalogs %} + {{accessModifier}} enum {{catalog.name|swiftIdentifier:"pretty"|escapeReservedKeywords}} { + {% if catalog.assets %} + {% filter indent:2," ",true %}{% call enumBlock catalog.assets %}{% endfilter %} + {% endif %} + } + {% endfor %} + {% else %} + {% call enumBlock catalogs.first.assets %} + {% endif %} +} +// swiftlint:enable identifier_name line_length nesting type_body_length type_name + +// MARK: - Implementation Details +{% if hasARResourceGroup %} + +{{accessModifier}} struct {{arResourceGroupType}} { + {{accessModifier}} fileprivate(set) var name: String + + #if os(iOS) + @available(iOS 11.3, *) + {{accessModifier}} var referenceImages: Set { + return ARReferenceImage.referenceImages(in: self) + } + + @available(iOS 12.0, *) + {{accessModifier}} var referenceObjects: Set { + return ARReferenceObject.referenceObjects(in: self) + } + #endif +} + +#if os(iOS) +@available(iOS 11.3, *) +{{accessModifier}} extension ARReferenceImage { + static func referenceImages(in asset: {{arResourceGroupType}}) -> Set { + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + return referenceImages(inGroupNamed: asset.name, bundle: bundle) ?? Set() + } +} + +@available(iOS 12.0, *) +{{accessModifier}} extension ARReferenceObject { + static func referenceObjects(in asset: {{arResourceGroupType}}) -> Set { + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + return referenceObjects(inGroupNamed: asset.name, bundle: bundle) ?? Set() + } +} +#endif +{% endif %} +{% if hasColor %} + +{{accessModifier}} final class {{colorType}} { + {{accessModifier}} fileprivate(set) var name: String + + #if os(macOS) + {{accessModifier}} typealias Color = NSColor + #elseif os(iOS) || os(tvOS) || os(watchOS) + {{accessModifier}} typealias Color = UIColor + #endif + + @available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *) + {{accessModifier}} private(set) lazy var color: Color = { + guard let color = Color(asset: self) else { + fatalError("Unable to load color asset named \(name).") + } + return color + }() + + #if os(iOS) || os(tvOS) + @available(iOS 11.0, tvOS 11.0, *) + {{accessModifier}} func color(compatibleWith traitCollection: UITraitCollection) -> Color { + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + guard let color = Color(named: name, in: bundle, compatibleWith: traitCollection) else { + fatalError("Unable to load color asset named \(name).") + } + return color + } + #endif + + #if canImport(SwiftUI) + @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) + {{accessModifier}} private(set) lazy var swiftUIColor: SwiftUI.Color = { + SwiftUI.Color(asset: self) + }() + #endif + + fileprivate init(name: String) { + self.name = name + } +} + +{{accessModifier}} extension {{colorType}}.Color { + @available(iOS 11.0, tvOS 11.0, watchOS 4.0, macOS 10.13, *) + convenience init?(asset: {{colorType}}) { + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + #if os(iOS) || os(tvOS) + self.init(named: asset.name, in: bundle, compatibleWith: nil) + #elseif os(macOS) + self.init(named: NSColor.Name(asset.name), bundle: bundle) + #elseif os(watchOS) + self.init(named: asset.name) + #endif + } +} + +#if canImport(SwiftUI) +@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) +{{accessModifier}} extension SwiftUI.Color { + init(asset: {{colorType}}) { + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + self.init(asset.name, bundle: bundle) + } +} +#endif +{% endif %} +{% if hasData %} + +{{accessModifier}} struct {{dataType}} { + {{accessModifier}} fileprivate(set) var name: String + + @available(iOS 9.0, tvOS 9.0, watchOS 6.0, macOS 10.11, *) + {{accessModifier}} var data: NSDataAsset { + guard let data = NSDataAsset(asset: self) else { + fatalError("Unable to load data asset named \(name).") + } + return data + } +} + +@available(iOS 9.0, tvOS 9.0, watchOS 6.0, macOS 10.11, *) +{{accessModifier}} extension NSDataAsset { + convenience init?(asset: {{dataType}}) { + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + #if os(iOS) || os(tvOS) || os(watchOS) + self.init(name: asset.name, bundle: bundle) + #elseif os(macOS) + self.init(name: NSDataAsset.Name(asset.name), bundle: bundle) + #endif + } +} +{% endif %} +{% if hasImage %} + +{{accessModifier}} struct {{imageType}} { + {{accessModifier}} fileprivate(set) var name: String + + #if os(macOS) + {{accessModifier}} typealias Image = NSImage + #elseif os(iOS) || os(tvOS) || os(watchOS) + {{accessModifier}} typealias Image = UIImage + #endif + + @available(iOS 8.0, tvOS 9.0, watchOS 2.0, macOS 10.7, *) + {{accessModifier}} var image: Image { + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + #if os(iOS) || os(tvOS) + let image = Image(named: name, in: bundle, compatibleWith: nil) + #elseif os(macOS) + let name = NSImage.Name(self.name) + let image = (bundle == .main) ? NSImage(named: name) : bundle.image(forResource: name) + #elseif os(watchOS) + let image = Image(named: name) + #endif + guard let result = image else { + fatalError("Unable to load image asset named \(name).") + } + return result + } + + #if os(iOS) || os(tvOS) + @available(iOS 8.0, tvOS 9.0, *) + {{accessModifier}} func image(compatibleWith traitCollection: UITraitCollection) -> Image { + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + guard let result = Image(named: name, in: bundle, compatibleWith: traitCollection) else { + fatalError("Unable to load image asset named \(name).") + } + return result + } + #endif + + #if canImport(SwiftUI) + @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) + {{accessModifier}} var swiftUIImage: SwiftUI.Image { + SwiftUI.Image(asset: self) + } + #endif +} + +{{accessModifier}} extension {{imageType}}.Image { + @available(iOS 8.0, tvOS 9.0, watchOS 2.0, *) + @available(macOS, deprecated, + message: "This initializer is unsafe on macOS, please use the {{imageType}}.image property") + convenience init?(asset: {{imageType}}) { + #if os(iOS) || os(tvOS) + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + self.init(named: asset.name, in: bundle, compatibleWith: nil) + #elseif os(macOS) + self.init(named: NSImage.Name(asset.name)) + #elseif os(watchOS) + self.init(named: asset.name) + #endif + } +} + +#if canImport(SwiftUI) +@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) +{{accessModifier}} extension SwiftUI.Image { + init(asset: {{imageType}}) { + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + self.init(asset.name, bundle: bundle) + } + + init(asset: {{imageType}}, label: Text) { + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + self.init(asset.name, bundle: bundle, label: label) + } + + init(decorative asset: {{imageType}}) { + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + self.init(decorative: asset.name, bundle: bundle) + } +} +#endif +{% endif %} +{% if hasSymbol %} + +{{accessModifier}} struct {{symbolType}} { + {{accessModifier}} fileprivate(set) var name: String + + #if os(iOS) || os(tvOS) || os(watchOS) + @available(iOS 13.0, tvOS 13.0, watchOS 6.0, *) + {{accessModifier}} typealias Configuration = UIImage.SymbolConfiguration + {{accessModifier}} typealias Image = UIImage + + @available(iOS 12.0, tvOS 12.0, watchOS 5.0, *) + {{accessModifier}} var image: Image { + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + #if os(iOS) || os(tvOS) + let image = Image(named: name, in: bundle, compatibleWith: nil) + #elseif os(watchOS) + let image = Image(named: name) + #endif + guard let result = image else { + fatalError("Unable to load symbol asset named \(name).") + } + return result + } + + @available(iOS 13.0, tvOS 13.0, watchOS 6.0, *) + {{accessModifier}} func image(with configuration: Configuration) -> Image { + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + guard let result = Image(named: name, in: bundle, with: configuration) else { + fatalError("Unable to load symbol asset named \(name).") + } + return result + } + #endif + + #if canImport(SwiftUI) + @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) + {{accessModifier}} var swiftUIImage: SwiftUI.Image { + SwiftUI.Image(asset: self) + } + #endif +} + +#if canImport(SwiftUI) +@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) +{{accessModifier}} extension SwiftUI.Image { + init(asset: {{symbolType}}) { + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + self.init(asset.name, bundle: bundle) + } + + init(asset: {{symbolType}}, label: Text) { + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + self.init(asset.name, bundle: bundle, label: label) + } + + init(decorative asset: {{symbolType}}) { + let bundle = {{param.bundle|default:"BundleToken.bundle"}} + self.init(decorative: asset.name, bundle: bundle) + } +} +#endif +{% endif %} +{% if not param.bundle %} + +// swiftlint:disable convenience_type +private final class BundleToken { + static let bundle: Bundle = { + #if SWIFT_PACKAGE + return Bundle.module + #else + return Bundle(for: BundleToken.self) + #endif + }() +} +// swiftlint:enable convenience_type +{% endif %} +{% else %} +// No assets found +{% endif %} +// swiftlint:enable all \ No newline at end of file diff --git a/Common/RuuviLocalization/target.yml b/Common/RuuviLocalization/target.yml index 0dab3ce6f..452f2cc84 100644 --- a/Common/RuuviLocalization/target.yml +++ b/Common/RuuviLocalization/target.yml @@ -1,8 +1,30 @@ --- targets: RuuviLocalization: + settings: + base: + MERGEABLE_LIBRARY: false templates: - CommonFramework sources: - path: Sources name: Localization + - path: Sources/RuuviLocalization.swift + optional: true + - path: Sources/RuuviColor.swift + optional: true + preBuildScripts: + - path: ../../scripts/build/generate_resources.sh + name: Generate Resources + inputFiles: + - $(SRCROOT)/station.localization/station.localization.json + - $(SRCROOT)/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets + outputFiles: + - $(SRCROOT)/Common/RuuviLocalization/Sources/Resources/en.lproj/Localizable.strings + - $(SRCROOT)/Common/RuuviLocalization/Sources/Resources/sv.lproj/Localizable.strings + - $(SRCROOT)/Common/RuuviLocalization/Sources/Resources/ru.lproj/Localizable.strings + - $(SRCROOT)/Common/RuuviLocalization/Sources/Resources/fi.lproj/Localizable.strings + - $(SRCROOT)/Common/RuuviLocalization/Sources/Resources/fr.lproj/Localizable.strings + - $(SRCROOT)/Common/RuuviLocalization/Sources/Resources/de.lproj/Localizable.strings + - $(SRCROOT)/Common/RuuviLocalization/Sources/RuuviLocalization.swift + - $(SRCROOT)/Common/RuuviLocalization/Sources/RuuviColor.swift \ No newline at end of file diff --git a/Makefile b/Makefile index bd7da8519..3b3bd98e2 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ # generates xcodeproj for frameworks build configuration xcodeproj: installed_xcodegen installed_swiftgen installed_swiftlint - .tools/xcodegen/bin/xcodegen -s project.yml + scripts/generate_project.sh # install firebase installed_firebase: .tools/firebase/firebase diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift index 771e1956d..0c9b0162e 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift @@ -1,5 +1,6 @@ import CoreBluetooth import CoreNFC +import RuuviLocalization import UIKit protocol DiscoverTableHeaderViewDelegate: NSObjectProtocol { @@ -93,7 +94,7 @@ class DiscoverTableHeaderView: UIView { if let font = UIFont(name: "Muli-Regular", size: 16) { button.titleLabel?.font = font } - button.tintColor = UIColor(named: "RuuviTintColor") + button.tintColor = RuuviColor.tintColor.color button.addTarget( self, action: #selector(handleButtonTap), diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/ProgressBar.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/ProgressBar.swift index f0fc2ad45..1fbafd850 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/ProgressBar.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/ProgressBar.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import SwiftUI public struct ProgressBar: View { @@ -16,14 +17,14 @@ public struct ProgressBar: View { height: geometry.size.height ) .opacity(0.3) - .foregroundColor(RuuviColor.green) + .foregroundColor(RuuviColor.green.swiftUIColor) Rectangle() .frame( width: min(CGFloat(value) * geometry.size.width, geometry.size.width), height: geometry.size.height ) - .foregroundColor(RuuviColor.green) + .foregroundColor(RuuviColor.green.swiftUIColor) .animation(.linear) }.cornerRadius(6) } diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviMenuTextColor.colorset/Contents.json b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviMenuTextColor.colorset/Contents.json deleted file mode 100644 index 4f4b48058..000000000 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviMenuTextColor.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "1.000", - "blue" : "0.239", - "green" : "0.235", - "red" : "0.031" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "1.000", - "blue" : "1.000", - "green" : "1.000", - "red" : "1.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviTextColor.colorset/Contents.json b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviTextColor.colorset/Contents.json deleted file mode 100644 index efe8a9b96..000000000 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviTextColor.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "1.000", - "blue" : "0.239", - "green" : "0.235", - "red" : "0.031" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "0.800", - "blue" : "0xFF", - "green" : "0xFF", - "red" : "0xFF" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviTintColor.colorset/Contents.json b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviTintColor.colorset/Contents.json deleted file mode 100644 index 67e2f95b3..000000000 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/RuuviTintColor.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "1.000", - "blue" : "0.624", - "green" : "0.677", - "red" : "0.209" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift index 8b5bfeba8..f3784967b 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift @@ -1,4 +1,5 @@ // swiftlint:disable file_length +import RuuviLocalization import SwiftUI // swiftlint:disable:next type_body_length @@ -51,7 +52,7 @@ struct FirmwareView: View { VStack(alignment: .leading, spacing: 16) { Text(texts.latestTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Spinner(isAnimating: true, style: .medium).eraseToAnyView() } .frame( @@ -69,13 +70,13 @@ struct FirmwareView: View { VStack(alignment: .leading, spacing: 16) { Text(texts.latestTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) Text(latestRelease.version) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.currentTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) Spinner(isAnimating: true, style: .medium).eraseToAnyView() } .frame( @@ -90,13 +91,13 @@ struct FirmwareView: View { VStack(alignment: .leading, spacing: 16) { Text(texts.latestTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) Text(latestRelease.version) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.currentTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) Spinner(isAnimating: true, style: .medium).eraseToAnyView() } .frame( @@ -110,21 +111,21 @@ struct FirmwareView: View { VStack(alignment: .leading, spacing: 16) { Text(texts.latestTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) Text(latestRelease.version) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.currentTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) if let currentVersion = currentRelease?.version { Text(currentVersion) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) } else { Text(texts.notReportingDescription) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) } } .frame( @@ -139,7 +140,7 @@ struct FirmwareView: View { VStack { Text(texts.alreadyOnLatest) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) .frame( maxWidth: .infinity, maxHeight: .infinity, @@ -158,7 +159,7 @@ struct FirmwareView: View { ) .buttonStyle( LargeButtonStyle( - backgroundColor: RuuviColor.ruuviTintColorSUI, + backgroundColor: RuuviColor.tintColor.swiftUIColor, foregroundColor: Color.white, isDisabled: false ) @@ -172,21 +173,21 @@ struct FirmwareView: View { VStack(alignment: .leading, spacing: 16) { Text(texts.latestTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) Text(latestRelease.version) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.currentTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) if let currentVersion = currentRelease?.version { Text(currentVersion) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) } else { Text(texts.notReportingDescription) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) } Button( action: { @@ -203,7 +204,7 @@ struct FirmwareView: View { ) .buttonStyle( LargeButtonStyle( - backgroundColor: RuuviColor.ruuviTintColorSUI, + backgroundColor: RuuviColor.tintColor.swiftUIColor, foregroundColor: Color.white, isDisabled: false ) @@ -227,13 +228,13 @@ struct FirmwareView: View { VStack(alignment: .center, spacing: 16) { Text(texts.downloadingTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) ProgressBar(value: $viewModel.downloadProgress) .frame(height: 16) .padding() Text("\(Int(viewModel.downloadProgress * 100))%") .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) } .frame( maxWidth: .infinity, @@ -250,25 +251,25 @@ struct FirmwareView: View { VStack(alignment: .leading, spacing: 16) { Text(texts.prepareTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) Text(texts.openCoverTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.localBootButtonTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.setUpdatingModeTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.toBootModeTwoButtonsDescription) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.toBootModeOneButtonDescription) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.toBootModeSuccessTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) } Button( action: {}, @@ -283,7 +284,7 @@ struct FirmwareView: View { ) .buttonStyle( LargeButtonStyle( - backgroundColor: RuuviColor.ruuviTintColorSUI, + backgroundColor: RuuviColor.tintColor.swiftUIColor, foregroundColor: Color.white, isDisabled: true ) @@ -309,25 +310,25 @@ struct FirmwareView: View { VStack(alignment: .leading, spacing: 16) { Text(texts.prepareTitle).bold() .font(muliBold16) - .foregroundColor(RuuviColor.ruuviTitleTextColorSUI) + .foregroundColor(RuuviColor.menuTextColor.swiftUIColor) Text(texts.openCoverTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.localBootButtonTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.setUpdatingModeTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.toBootModeTwoButtonsDescription) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.toBootModeOneButtonDescription) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.toBootModeSuccessTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) } Button( action: { @@ -349,7 +350,7 @@ struct FirmwareView: View { ) .buttonStyle( LargeButtonStyle( - backgroundColor: RuuviColor.ruuviTintColorSUI, + backgroundColor: RuuviColor.tintColor.swiftUIColor, foregroundColor: Color.white, isDisabled: false ) @@ -370,17 +371,17 @@ struct FirmwareView: View { VStack(alignment: .center, spacing: 24) { Text(texts.updatingTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) ProgressBar(value: $viewModel.flashProgress) .frame(height: 16) Text("\(Int(viewModel.flashProgress * 100))%") .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) Text(texts.doNotCloseTitle) .font(muliBold16) .bold() .multilineTextAlignment(.center) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) } .frame( maxWidth: .infinity, @@ -393,7 +394,7 @@ struct FirmwareView: View { VStack { Text(texts.successfulTitle) .font(muliRegular16) - .foregroundColor(RuuviColor.ruuviTextColorSUI) + .foregroundColor(RuuviColor.textColor.swiftUIColor) .frame( maxWidth: .infinity, maxHeight: .infinity, @@ -412,7 +413,7 @@ struct FirmwareView: View { ) .buttonStyle( LargeButtonStyle( - backgroundColor: RuuviColor.ruuviTintColorSUI, + backgroundColor: RuuviColor.tintColor.swiftUIColor, foregroundColor: Color.white, isDisabled: false ) diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviColor.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviColor.swift deleted file mode 100644 index 9a01acf6e..000000000 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviColor.swift +++ /dev/null @@ -1,8 +0,0 @@ -import SwiftUI - -enum RuuviColor { - static let green = Color("RuuviGreen") - static let ruuviTintColorSUI = Color("RuuviTintColor") - static let ruuviTextColorSUI = Color("RuuviTextColor") - static let ruuviTitleTextColorSUI = Color("RuuviMenuTextColor") -} diff --git a/Modules/RuuviFirmware/target.yml b/Modules/RuuviFirmware/target.yml index 58c77d97e..8b0f80002 100644 --- a/Modules/RuuviFirmware/target.yml +++ b/Modules/RuuviFirmware/target.yml @@ -12,3 +12,4 @@ targets: dependencies: - package: BTKit - target: RuuviDFU + - target: RuuviLocalization diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Assests/RuuviAssets.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Assests/RuuviAssets.swift index 880d25bda..989ad260d 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Assests/RuuviAssets.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Assests/RuuviAssets.swift @@ -12,7 +12,4 @@ enum RuuviAssets { static let web = "onboarding_web" static let beaver_sign_in = "onboarding_beaver_sign_in" static let gateway = "gateway" - - // Color - static let ruuviTintColor = UIColor(named: "RuuviTintColor") } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift index 891407685..c8d864bcf 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit class RuuviOnboardGatewayFeaturesCell: UICollectionViewCell { @@ -105,7 +106,7 @@ private extension RuuviOnboardGatewayFeaturesCell { appImageView.fillSuperview(padding: .init(top: 30, left: 30, bottom: 30, right: 30)) } - let footerView = UIView(color: RuuviAssets.ruuviTintColor) + let footerView = UIView(color: RuuviColor.tintColor.color) container.addSubview(footerView) footerView.anchor( top: appImageViewContainer.bottomAnchor, diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift index cbded7754..8fe141cdc 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit protocol RuuviOnboardSignInCellDelegate: NSObjectProtocol { @@ -38,7 +39,7 @@ class RuuviOnboardSignInCell: UICollectionViewCell { }() private lazy var continueButton: UIButton = { - let button = UIButton(color: RuuviAssets.ruuviTintColor, cornerRadius: 22) + let button = UIButton(color: RuuviColor.tintColor.color, cornerRadius: 22) button.setTitle( "onboarding_continue".localized(for: Self.self), for: .normal diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/RuuviTintColor.colorset/Contents.json b/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/RuuviTintColor.colorset/Contents.json deleted file mode 100644 index 986f01823..000000000 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/RuuviTintColor.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "1.000", - "blue" : "0.624", - "green" : "0.678", - "red" : "0.208" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/scripts/build/generate_l10n.sh b/scripts/build/generate_resources.sh similarity index 57% rename from scripts/build/generate_l10n.sh rename to scripts/build/generate_resources.sh index 55a53e187..5ec2fc6fd 100755 --- a/scripts/build/generate_l10n.sh +++ b/scripts/build/generate_resources.sh @@ -7,4 +7,5 @@ if [ ! -f "$PROJECT_DIR"/.tools/swiftgen/bin/swiftgen ]; then fi # execute swiftgen -"$PROJECT_DIR"/.tools/swiftgen/bin/swiftgen \ No newline at end of file +"$PROJECT_DIR"/.tools/swiftgen/bin/swiftgen --config "$PROJECT_DIR"/.swiftgen.localizable.yml +"$PROJECT_DIR"/.tools/swiftgen/bin/swiftgen --config "$PROJECT_DIR"/.swiftgen.assets.yml \ No newline at end of file diff --git a/scripts/generate_project.sh b/scripts/generate_project.sh new file mode 100755 index 000000000..5b8f485d9 --- /dev/null +++ b/scripts/generate_project.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +# Check if the resources exists and if not - touch them +if [ ! -f "Common/RuuviLocalization/Sources/Resources/en.lproj/Localizable.strings" ]; then + echo "Creating $localizableStrings because it does not exist." + + mkdir -p "./Common/RuuviLocalization/Sources/Resources/de.lproj" + touch "./Common/RuuviLocalization/Sources/Resources/de.lproj/Localizable.strings" + + mkdir -p "./Common/RuuviLocalization/Sources/Resources/en.lproj" + touch "./Common/RuuviLocalization/Sources/Resources/en.lproj/Localizable.strings" + + mkdir -p "./Common/RuuviLocalization/Sources/Resources/fi.lproj" + touch "./Common/RuuviLocalization/Sources/Resources/fi.lproj/Localizable.strings" + + mkdir -p "./Common/RuuviLocalization/Sources/Resources/fr.lproj" + touch "./Common/RuuviLocalization/Sources/Resources/fr.lproj/Localizable.strings" + + mkdir -p "./Common/RuuviLocalization/Sources/Resources/ru.lproj" + touch "./Common/RuuviLocalization/Sources/Resources/ru.lproj/Localizable.strings" + + mkdir -p "./Common/RuuviLocalization/Sources/Resources/sv.lproj" + touch "./Common/RuuviLocalization/Sources/Resources/sv.lproj/Localizable.strings" +fi + +.tools/xcodegen/bin/xcodegen -s project.yml diff --git a/swiftgen.yml b/swiftgen.yml deleted file mode 100644 index 826a8779c..000000000 --- a/swiftgen.yml +++ /dev/null @@ -1,34 +0,0 @@ -json: - - inputs: ./station.localization/station.localization.json - outputs: - - templatePath: ./Common/RuuviLocalization/Templates/Localizable_en.strings.stencil - output: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings - - inputs: ./station.localization/station.localization.json - outputs: - - templatePath: ./Common/RuuviLocalization/Templates/Localizable_sv.strings.stencil - output: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/sv.lproj/Localizable.strings - - inputs: ./station.localization/station.localization.json - outputs: - - templatePath: ./Common/RuuviLocalization/Templates/Localizable_ru.strings.stencil - output: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/ru.lproj/Localizable.strings - - inputs: ./station.localization/station.localization.json - outputs: - - templatePath: ./Common/RuuviLocalization/Templates/Localizable_fi.strings.stencil - output: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fi.lproj/Localizable.strings - - inputs: ./station.localization/station.localization.json - outputs: - - templatePath: ./Common/RuuviLocalization/Templates/Localizable_fr.strings.stencil - output: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/fr.lproj/Localizable.strings - - inputs: ./station.localization/station.localization.json - outputs: - - templatePath: ./Common/RuuviLocalization/Templates/Localizable_de.strings.stencil - output: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/de.lproj/Localizable.strings -strings: - - inputs: ./Common/RuuviLocalization/Sources/RuuviLocalization/Resources/en.lproj/Localizable.strings - outputs: - - templatePath: ./Common/RuuviLocalization/Templates/structured-swift5.stencil - output: ./Common/RuuviLocalization/Sources/RuuviLocalization/RuuviLocalization.swift - params: - forceProvidesNamespaces: true - publicAccess: true - enumName: RuuviLocalization \ No newline at end of file From eeb3a90097a5dfa8cb725814a71ca45d7ecbeb33 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Fri, 15 Dec 2023 19:44:14 +0200 Subject: [PATCH 47/84] Remvoe all custom localization from Frameworks (#1782) Fixes issue with localizations on onboarding --- .../View/ActivityPresenterView.swift | 20 +++---- .../Error/Alert/ErrorPresenterAlert.swift | 7 ++- .../Alert/PermissionPresenterAlert.swift | 13 +++-- .../de.lproj/RuuviPresenters.strings | 11 ---- .../en.lproj/RuuviPresenters.strings | 11 ---- .../fi.lproj/RuuviPresenters.strings | 11 ---- .../fr.lproj/RuuviPresenters.strings | 11 ---- .../ru.lproj/RuuviPresenters.strings | 11 ---- .../sv.lproj/RuuviPresenters.strings | 11 ---- .../Util/RuuviBundleUtils.swift | 34 ----------- .../Resources/de.lproj/RuuviDiscover.strings | 31 ---------- .../Resources/en.lproj/RuuviDiscover.strings | 33 ----------- .../Resources/fi.lproj/RuuviDiscover.strings | 31 ---------- .../Resources/fr.lproj/RuuviDiscover.strings | 31 ---------- .../Resources/ru.lproj/RuuviDiscover.strings | 31 ---------- .../Resources/sv.lproj/RuuviDiscover.strings | 31 ---------- .../RuuviDiscover/Util/RuuviBundleUtils.swift | 34 ----------- .../Util/UIViewController+Alert.swift | 3 +- .../VMP/Presenter/DiscoverPresenter.swift | 17 +++--- .../View/Table/DiscoverTableHeaderView.swift | 13 ++--- .../Table/DiscoverTableViewController.swift | 56 +++++++++---------- .../Resources/de.lproj/RuuviFirmware.strings | 20 ------- .../Resources/en.lproj/RuuviFirmware.strings | 20 ------- .../Resources/fi.lproj/RuuviFirmware.strings | 20 ------- .../Resources/fr.lproj/RuuviFirmware.strings | 20 ------- .../Resources/ru.lproj/RuuviFirmware.strings | 20 ------- .../Resources/sv.lproj/RuuviFirmware.strings | 20 ------- .../RuuviFirmware/SwiftUI/FirmwareView.swift | 48 ++++++++-------- .../RuuviFirmware/Util/RuuviBundleUtils.swift | 34 ----------- .../RuuviOnboardGatewayFeaturesCell.swift | 2 +- .../Pages/RuuviOnboardSignInCell.swift | 2 +- .../Pages/RuuviOnboardViewController.swift | 45 +++++++-------- .../Pages/Util/RuuviBundleUtils.swift | 34 ----------- .../Resources/de.lproj/RuuviOnboard.strings | 45 --------------- .../Resources/en.lproj/RuuviOnboard.strings | 45 --------------- .../Resources/fi.lproj/RuuviOnboard.strings | 45 --------------- .../Resources/fr.lproj/RuuviOnboard.strings | 45 --------------- .../Resources/ru.lproj/RuuviOnboard.strings | 45 --------------- .../Resources/sv.lproj/RuuviOnboard.strings | 45 --------------- 39 files changed, 108 insertions(+), 898 deletions(-) delete mode 100644 Common/RuuviPresenters/Sources/RuuviPresenters/Resources/de.lproj/RuuviPresenters.strings delete mode 100644 Common/RuuviPresenters/Sources/RuuviPresenters/Resources/en.lproj/RuuviPresenters.strings delete mode 100644 Common/RuuviPresenters/Sources/RuuviPresenters/Resources/fi.lproj/RuuviPresenters.strings delete mode 100644 Common/RuuviPresenters/Sources/RuuviPresenters/Resources/fr.lproj/RuuviPresenters.strings delete mode 100644 Common/RuuviPresenters/Sources/RuuviPresenters/Resources/ru.lproj/RuuviPresenters.strings delete mode 100644 Common/RuuviPresenters/Sources/RuuviPresenters/Resources/sv.lproj/RuuviPresenters.strings delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/de.lproj/RuuviDiscover.strings delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/en.lproj/RuuviDiscover.strings delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/fi.lproj/RuuviDiscover.strings delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/fr.lproj/RuuviDiscover.strings delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/ru.lproj/RuuviDiscover.strings delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/sv.lproj/RuuviDiscover.strings delete mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/de.lproj/RuuviFirmware.strings delete mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/en.lproj/RuuviFirmware.strings delete mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/fi.lproj/RuuviFirmware.strings delete mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/fr.lproj/RuuviFirmware.strings delete mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/ru.lproj/RuuviFirmware.strings delete mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/sv.lproj/RuuviFirmware.strings delete mode 100644 Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/de.lproj/RuuviOnboard.strings delete mode 100644 Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/en.lproj/RuuviOnboard.strings delete mode 100644 Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/fi.lproj/RuuviOnboard.strings delete mode 100644 Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/fr.lproj/RuuviOnboard.strings delete mode 100644 Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/ru.lproj/RuuviOnboard.strings delete mode 100644 Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/sv.lproj/RuuviOnboard.strings diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift index a5430f308..16df14e25 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift @@ -1,11 +1,8 @@ +import RuuviLocalization import SwiftUI import UIKit private enum ActivityPresenterAssets { - static let activityOngoingDefault = "activity_ongoing_generic" - static let activitySuccessDefault = "activity_success_generic" - static let activityFailedDefault = "activity_failed_generic" - static let activityLogoRuuvi = "ruuvi_activity_presenter_logo" } @@ -84,25 +81,22 @@ struct ActivityPresenterContentView: View { if let message { message } else { - ActivityPresenterAssets - .activityOngoingDefault - .localized(for: ActivityPresenterViewProvider.self) + RuuviLocalization + .activityOngoingGeneric } case let .success(message): if let message { message } else { - ActivityPresenterAssets - .activitySuccessDefault - .localized(for: ActivityPresenterViewProvider.self) + RuuviLocalization + .activitySuccessGeneric } case let .failed(message): if let message { message } else { - ActivityPresenterAssets - .activityFailedDefault - .localized(for: ActivityPresenterViewProvider.self) + RuuviLocalization + .activityFailedGeneric } case .dismiss: "" // Placeholder for dismiss state diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Error/Alert/ErrorPresenterAlert.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Error/Alert/ErrorPresenterAlert.swift index 2c217c1d2..61ef977af 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Error/Alert/ErrorPresenterAlert.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Error/Alert/ErrorPresenterAlert.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit public final class ErrorPresenterAlert: ErrorPresenter { @@ -8,13 +9,13 @@ public final class ErrorPresenterAlert: ErrorPresenter { } private func presentAlert(error: Error) { - var title: String? = "ErrorPresenterAlert.Error".localized(for: Self.self) + var title: String? = RuuviLocalization.ErrorPresenterAlert.error if let localizedError = error as? LocalizedError { - title = localizedError.failureReason ?? "ErrorPresenterAlert.Error".localized(for: Self.self) + title = localizedError.failureReason ?? RuuviLocalization.ErrorPresenterAlert.error } let alert = UIAlertController(title: title, message: error.localizedDescription, preferredStyle: .alert) let action = UIAlertAction( - title: "ErrorPresenterAlert.OK".localized(for: Self.self), + title: RuuviLocalization.ErrorPresenterAlert.ok, style: .cancel, handler: nil ) diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Permission/Alert/PermissionPresenterAlert.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Permission/Alert/PermissionPresenterAlert.swift index 39665620e..15de129b0 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Permission/Alert/PermissionPresenterAlert.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Permission/Alert/PermissionPresenterAlert.swift @@ -1,33 +1,34 @@ +import RuuviLocalization import UIKit public final class PermissionPresenterAlert: PermissionPresenter { public init() {} public func presentNoPhotoLibraryPermission() { - let message = "PermissionPresenter.NoPhotoLibraryAccess.message".localized(for: Self.self) + let message = RuuviLocalization.PermissionPresenter.NoPhotoLibraryAccess.message presentAlert(with: message) } public func presentNoCameraPermission() { - let message = "PermissionPresenter.NoCameraAccess.message".localized(for: Self.self) + let message = RuuviLocalization.PermissionPresenter.NoCameraAccess.message presentAlert(with: message) } public func presentNoLocationPermission() { - let message = "PermissionPresenter.NoLocationAccess.message".localized(for: Self.self) + let message = RuuviLocalization.PermissionPresenter.NoLocationAccess.message presentAlert(with: message) } public func presentNoPushNotificationsPermission() { - let message = "PermissionPresenter.NoPushNotificationsPermission.message".localized(for: Self.self) + let message = RuuviLocalization.PermissionPresenter.NoPushNotificationsPermission.message presentAlert(with: message) } private func presentAlert(with message: String) { guard let viewController = UIApplication.shared.topViewController() else { return } let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) - let cancel = UIAlertAction(title: "Cancel".localized(for: Self.self), style: .cancel, handler: nil) - let actionTitle = "PermissionPresenter.settings".localized(for: Self.self) + let cancel = UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil) + let actionTitle = RuuviLocalization.PermissionPresenter.settings let settings = UIAlertAction(title: actionTitle, style: .default) { _ in if let settingsUrl = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.open(settingsUrl, options: [:]) diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/de.lproj/RuuviPresenters.strings b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/de.lproj/RuuviPresenters.strings deleted file mode 100644 index 8c6a6e367..000000000 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/de.lproj/RuuviPresenters.strings +++ /dev/null @@ -1,11 +0,0 @@ -"ErrorPresenterAlert.Error" = "Fehler"; -"ErrorPresenterAlert.OK" = "OK"; -"PermissionPresenter.NoPhotoLibraryAccess.message" = "Ruuvi Station muss auf Ihre Kamera zugreifen, um diese Funktion zu aktivieren."; -"PermissionPresenter.NoCameraAccess.message" = "Ruuvi Station muss auf Ihre Kamera zugreifen, um diese Funktion zu aktivieren."; -"PermissionPresenter.NoLocationAccess.message" = "Ruuvi Station muss auf Ihren Standort zugreifen, um diese Funktion zu aktivieren."; -"PermissionPresenter.settings" = "Einstellungen"; -"PermissionPresenter.NoPushNotificationsPermission.message" = "Ruuvi Station benötigt die Berechtigung für Push-Benachrichtigungen, um diese Funktion zu aktivieren"; -"Cancel" = "Abbrechen"; -"activity_ongoing_generic" = "Please wait..."; -"activity_success_generic" = "Operation successful."; -"activity_failed_generic" = "Operation failed."; diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/en.lproj/RuuviPresenters.strings b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/en.lproj/RuuviPresenters.strings deleted file mode 100644 index f06d8f267..000000000 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/en.lproj/RuuviPresenters.strings +++ /dev/null @@ -1,11 +0,0 @@ -"ErrorPresenterAlert.Error" = "Error"; -"ErrorPresenterAlert.OK" = "OK"; -"PermissionPresenter.NoPhotoLibraryAccess.message" = "Ruuvi Station needs to access your camera roll to enable this feature."; -"PermissionPresenter.NoCameraAccess.message" = "Ruuvi Station needs to access your camera to enable this feature."; -"PermissionPresenter.NoLocationAccess.message" = "Ruuvi Station needs to access your location to enable this feature."; -"PermissionPresenter.settings" = "Settings"; -"PermissionPresenter.NoPushNotificationsPermission.message" = "Ruuvi Station needs Push Notifications permission to enable this feature"; -"Cancel" = "Cancel"; -"activity_ongoing_generic" = "Please wait..."; -"activity_success_generic" = "Operation successful."; -"activity_failed_generic" = "Operation failed."; diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/fi.lproj/RuuviPresenters.strings b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/fi.lproj/RuuviPresenters.strings deleted file mode 100644 index 97a76334a..000000000 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/fi.lproj/RuuviPresenters.strings +++ /dev/null @@ -1,11 +0,0 @@ -"ErrorPresenterAlert.Error" = "Virhe"; -"ErrorPresenterAlert.OK" = "OK"; -"PermissionPresenter.NoPhotoLibraryAccess.message" = "Tämä ominaisuus vaatii oikeuden gallerian käyttöön."; -"PermissionPresenter.NoCameraAccess.message" = "Tämä ominaisuus vaatii oikeuden kameran käyttöön."; -"PermissionPresenter.NoLocationAccess.message" = "Tämä ominaisuus vaatii oikeuden paikkatiedon käyttöön."; -"PermissionPresenter.settings" = "Asetukset"; -"PermissionPresenter.NoPushNotificationsPermission.message" = "Tämä ominaisuus vaatii oikeuden palveluilmoitusten näyttämiseen."; -"Cancel" = "Peruuta"; -"activity_ongoing_generic" = "Please wait..."; -"activity_success_generic" = "Operation successful."; -"activity_failed_generic" = "Operation failed."; diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/fr.lproj/RuuviPresenters.strings b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/fr.lproj/RuuviPresenters.strings deleted file mode 100644 index af478a56a..000000000 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/fr.lproj/RuuviPresenters.strings +++ /dev/null @@ -1,11 +0,0 @@ -"ErrorPresenterAlert.Error" = "Erreur"; -"ErrorPresenterAlert.OK" = "OK"; -"PermissionPresenter.NoPhotoLibraryAccess.message" = "Veuillez autoriser l'accès aux fichiers multimédias de votre appareil."; -"PermissionPresenter.NoCameraAccess.message" = "Veuillez autoriser l'accès à l'appareil photo."; -"PermissionPresenter.NoLocationAccess.message" = "Veuillez autoriser l'accès aux services de géolocalisation."; -"PermissionPresenter.settings" = "Réglages"; -"PermissionPresenter.NoPushNotificationsPermission.message" = "Veuillez autoriser les notifications dans les réglages de l'appareil."; -"Cancel" = "Annuler"; -"activity_ongoing_generic" = "Please wait..."; -"activity_success_generic" = "Operation successful."; -"activity_failed_generic" = "Operation failed."; diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/ru.lproj/RuuviPresenters.strings b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/ru.lproj/RuuviPresenters.strings deleted file mode 100644 index f5c97052c..000000000 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/ru.lproj/RuuviPresenters.strings +++ /dev/null @@ -1,11 +0,0 @@ -"ErrorPresenterAlert.Error" = "Ошибка"; -"ErrorPresenterAlert.OK" = "OK"; -"PermissionPresenter.NoPhotoLibraryAccess.message" = "Ruuvi Station необходим доступ к вашей библиотеке фотографий для того, чтобы использовать эту функцию."; -"PermissionPresenter.NoCameraAccess.message" = "Ruuvi Station нужен доступ к камере для того, чтобы использовать эту функцию."; -"PermissionPresenter.NoLocationAccess.message" = "Ruuvi Station необходим доступ к геолокационным сервисам для того, чтобы использовать эту функцию."; -"PermissionPresenter.settings" = "Настройки"; -"PermissionPresenter.NoPushNotificationsPermission.message" = "Ruuvi Station необходим доступ к уведомлениям для того, чтобы использовать эту функцию"; -"Cancel" = "Отмена"; -"activity_ongoing_generic" = "Please wait..."; -"activity_success_generic" = "Operation successful."; -"activity_failed_generic" = "Operation failed."; diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/sv.lproj/RuuviPresenters.strings b/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/sv.lproj/RuuviPresenters.strings deleted file mode 100644 index 1fb12d7d6..000000000 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/sv.lproj/RuuviPresenters.strings +++ /dev/null @@ -1,11 +0,0 @@ -"ErrorPresenterAlert.Error" = "Fel"; -"ErrorPresenterAlert.OK" = "OK"; -"PermissionPresenter.NoPhotoLibraryAccess.message" = "Ruuvi Station behöver tillgång till dina bilder för att använda den här funktionen."; -"PermissionPresenter.NoCameraAccess.message" = "Ruuvi Station behöver tillgång kameran för att använda den här funktionen."; -"PermissionPresenter.NoLocationAccess.message" = "Ruuvi Station behöver tillgång till din plats för att använda den här funktionen."; -"PermissionPresenter.settings" = "Inställningar"; -"PermissionPresenter.NoPushNotificationsPermission.message" = "Ruuvi Station behöver behörighett ill Push-meddelanden för att aktivera den här funktionen."; -"Cancel" = "Avbryt"; -"activity_ongoing_generic" = "Please wait..."; -"activity_success_generic" = "Operation successful."; -"activity_failed_generic" = "Operation failed."; diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift index 19876bf35..d0385bb30 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift @@ -35,40 +35,6 @@ public extension UIImage { } } -extension String { - public func localized(for clazz: AnyClass) -> String { - let bundle: Bundle - #if SWIFT_PACKAGE - bundle = Bundle.module - #else - bundle = Bundle.pod(clazz) - #endif - if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { - if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), - let bundle = Bundle(path: path) { - return bundle.localizedString(forKey: self, value: nil, table: module) - } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), - let bundle = Bundle(path: path) { - return bundle.localizedString(forKey: self, value: nil, table: module) - } else { - assertionFailure() - return self - } - } else { - assertionFailure() - return self - } - } - - private func currentLanguage() -> String { - if let preferred = Bundle.main.preferredLocalizations.first { - preferred - } else { - "Base" - } - } -} - public extension UIStoryboard { static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { let bundle: Bundle diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/de.lproj/RuuviDiscover.strings b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/de.lproj/RuuviDiscover.strings deleted file mode 100644 index d98b8cfdb..000000000 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/de.lproj/RuuviDiscover.strings +++ /dev/null @@ -1,31 +0,0 @@ -"DiscoverTable.NavigationItem.title" = "Neuen Sensor hinzufügen"; -"DiscoverTable.GetMoreSensors.button.title" = "Ruuvi Sensoren kaufen"; -"DiscoverTable.BluetoothDisabledAlert.title" = "Bluetooth ist nicht aktiviert"; -"DiscoverTable.BluetoothDisabledAlert.message" = "Die Ruuvi Station benötigt Bluetooth, um die Sensoren zu verbinden. Gehen Sie zu Einstellungen und schalten Sie Bluetooth ein."; -"DiscoverTable.WebTagsInfoDialog.message" = "Virtuelle Sensoren zeigen öffentliche Wetterdaten an, die von lokalen Wetterstationen bereitgestellt werden."; -"PermissionPresenter.settings" = "Einstellungen"; -"OK" = "OK"; -"DiscoverTable.NoDevicesSection.NotFound.text" = "(Keine Sensoren in Bluetooth-Reichweite)"; -"DiscoverTable.NoDevicesSection.BluetoothDisabled.text" = "(Bluetooth ist deaktiviert)"; -"DiscoverTable.SectionTitle.Devices" = "Ruuvi-Sensoren in der Nähe"; -"dBm" = "dBm"; -"DiscoverTable.RuuviDevice.prefix" = "Ruuvi"; -"DiscoverTable.SectionTitle.WebTags" = "Virtuelle Sensoren"; -"WebTagLocationSource.current" = "Ihr Standort"; -"WebTagLocationSource.manual" = "Wählen Sie aus der Karte"; -"Ruuvi.BuySensors.URL.IOS" = "https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"add_with_nfc" = "Mit NFC hinzufügen"; -"sensor_details" = "Sensordetails"; -"add_sensor" = "Sensor hinzufügen"; -"copy_mac_address" = "MAC-Adresse kopieren"; -"copy_unique_id" = "Eindeutige ID kopieren"; -"name" = "Name:"; -"mac_address" = "MAC-Adresse:"; -"go_to_sensor" = "Gehen Sie zur Sensorkarte"; -"unique_id" = "Eindeutige ID:"; -"firmware_version" = "Firmware Version:"; -"close" = "Schließen"; -"add_sensor_nfc_df3_error" = "Dieser Sensor kann aufgrund der alten Firmware nicht mit NFC hinzugefügt werden. Bitte fügen Sie den Sensor über Bluetooth hinzu und aktualisieren Sie die Firmware."; -"add_sensor_description" = "Auf dieser Seite werden Ruuvi-Sensoren in der Nähe angezeigt, die der App noch nicht hinzugefügt wurden. Tippen Sie auf einen Sensor, um ihn hinzuzufügen."; -"add_sensor_via_nfc" = "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone."; -"upgrade_firmware" = "Firmware Update"; diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/en.lproj/RuuviDiscover.strings b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/en.lproj/RuuviDiscover.strings deleted file mode 100644 index 5e1a9399f..000000000 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/en.lproj/RuuviDiscover.strings +++ /dev/null @@ -1,33 +0,0 @@ -"DiscoverTable.NavigationItem.title" = "Add a New Sensor"; -"DiscoverTable.GetMoreSensors.button.title" = "Buy Ruuvi Sensors"; -"DiscoverTable.BluetoothDisabledAlert.title" = "Bluetooth is not enabled"; -"DiscoverTable.BluetoothDisabledAlert.message" = "Ruuvi Station needs bluetooth to be able to listen for sensors. Go to Settings and turn Bluetooth on."; -"DiscoverTable.WebTagsInfoDialog.message" = "Virtual Sensors show public weather data provided by local weather stations."; -"PermissionPresenter.settings" = "Settings"; -"OK" = "OK"; -"DiscoverTable.NoDevicesSection.NotFound.text" = "(No sensors on Bluetooth range)"; -"DiscoverTable.NoDevicesSection.BluetoothDisabled.text" = "(Bluetooth is disabled)"; -"DiscoverTable.SectionTitle.Devices" = "Nearby Ruuvi sensors"; -"dBm" = "dBm"; -"DiscoverTable.RuuviDevice.prefix" = "Ruuvi"; -"DiscoverTable.SectionTitle.WebTags" = "Virtual sensors"; -"WebTagLocationSource.current" = "Your location"; -"WebTagLocationSource.manual" = "Pick from the map"; -"Ruuvi.BuySensors.URL.IOS" = "https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"add_with_nfc" = "Add with NFC"; -"sensor_details" = "Sensor Details"; -"add_sensor" = "Add Sensor"; -"copy_mac_address" = "Copy MAC Address"; -"copy_unique_id" = "Copy Unique ID"; -"name" = "Name:"; -"mac_address" = "Mac Address:"; -"go_to_sensor" = "Go to sensor card"; -"unique_id" = "Unique ID:"; -"firmware_version" = "Firmware Version:"; -"close" = "Close"; -"add_sensor_nfc_df3_error" = "This tag cannot be added with NFC due to old firmware. Please add the tag with Bluetooth and update firmware."; -"add_sensor_description" = "This page shows nearby Ruuvi sensors not yet added to the app. Tap a sensor to add it."; -"add_sensor_via_nfc" = "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone."; -"upgrade_firmware" = "Firmware Update"; - - diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/fi.lproj/RuuviDiscover.strings b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/fi.lproj/RuuviDiscover.strings deleted file mode 100644 index 378a06592..000000000 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/fi.lproj/RuuviDiscover.strings +++ /dev/null @@ -1,31 +0,0 @@ -"DiscoverTable.NavigationItem.title" = "Lisää uusi anturi"; -"DiscoverTable.GetMoreSensors.button.title" = "Osta Ruuvi-antureita"; -"DiscoverTable.BluetoothDisabledAlert.title" = "Bluetooth ei ole käytössä"; -"DiscoverTable.BluetoothDisabledAlert.message" = "Ruuvi Station tarvitsee Bluetooth-yhteyden toimiakseen. Ota Bluetooth käyttöön laitteen asetuksista."; -"DiscoverTable.WebTagsInfoDialog.message" = "Virtuaalisten antureiden avulla voidaan esittää paikallisilta sääasemilta kerättyjä säätietoja."; -"PermissionPresenter.settings" = "Asetukset"; -"OK" = "OK"; -"DiscoverTable.NoDevicesSection.NotFound.text" = "(Ei havaittuja antureita Bluetooth-verkon alueella)"; -"DiscoverTable.NoDevicesSection.BluetoothDisabled.text" = "(Bluetooth ei ole käytössä)"; -"DiscoverTable.SectionTitle.Devices" = "Lähellä olevat Ruuvi-laitteet"; -"dBm" = "dBm"; -"DiscoverTable.RuuviDevice.prefix" = "Ruuvi"; -"DiscoverTable.SectionTitle.WebTags" = "Paikkaan perustuvat virtuaaliset anturit"; -"WebTagLocationSource.current" = "Nykyinen sijaintisi"; -"WebTagLocationSource.manual" = "Valitse kartalta"; -"Ruuvi.BuySensors.URL.IOS" = "https://ruuvi.com/fi/tuotteet?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"add_with_nfc" = "Lisää NFC:llä"; -"sensor_details" = "Anturin tiedot"; -"add_sensor" = "Lisää anturi"; -"copy_mac_address" = "Kopioi MAC-osoite"; -"copy_unique_id" = "Kopioi yksilöivä tunniste"; -"name" = "Nimi:"; -"mac_address" = "MAC-osoite:"; -"go_to_sensor" = "Siirry anturikortille"; -"unique_id" = "Yksilöivä tunniste:"; -"firmware_version" = "Laiteohjelmistoversio:"; -"close" = "Sulje"; -"add_sensor_nfc_df3_error" = "Vanha laiteohjelmisto ei salli anturin lisäämistä NFC:llä. Lisää anturi Bluetooth-yhteydellä ja päivitä laiteohjelmisto."; -"add_sensor_description" = "Tällä sivulla näet lähelläsi olevat Ruuvi-anturit, joita ei ole vielä lisätty sovellukseen. Lisää listattu anturi napauttamalla."; -"add_sensor_via_nfc" = "Voit vaihtoehtoisesti lisätä anturin sovellukseen NFC:llä napauttamalla Lisää NFC:llä painiketta ja koskettamalla sitä."; -"upgrade_firmware" = "Laiteohjelmiston päivitys"; diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/fr.lproj/RuuviDiscover.strings b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/fr.lproj/RuuviDiscover.strings deleted file mode 100644 index 0365f333a..000000000 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/fr.lproj/RuuviDiscover.strings +++ /dev/null @@ -1,31 +0,0 @@ -"DiscoverTable.NavigationItem.title" = "Ajouter un capteur"; -"DiscoverTable.GetMoreSensors.button.title" = "Acheter des capteurs Ruuvi"; -"DiscoverTable.BluetoothDisabledAlert.title" = "Bluetooth désactivé"; -"DiscoverTable.BluetoothDisabledAlert.message" = "Ruuvi Station a besoin du Bluetooth pour fonctionner. Activez-le dans les paramètres de votre appareil."; -"DiscoverTable.WebTagsInfoDialog.message" = "Les capteurs virtuels permettent d'afficher des données recueillies à partir de stations météorologiques locales."; -"PermissionPresenter.settings" = "Réglages"; -"OK" = "OK"; -"DiscoverTable.NoDevicesSection.NotFound.text" = "(Pas de capteurs à portée du Bluetooth)"; -"DiscoverTable.NoDevicesSection.BluetoothDisabled.text" = "(Bluetooth désactivé)"; -"DiscoverTable.SectionTitle.Devices" = "Capteurs Ruuvi à proximité"; -"dBm" = "dBm"; -"DiscoverTable.RuuviDevice.prefix" = "Ruuvi"; -"DiscoverTable.SectionTitle.WebTags" = "Capteurs virtuels"; -"WebTagLocationSource.current" = "Localisation actuelle"; -"WebTagLocationSource.manual" = "Choisir sur la carte"; -"Ruuvi.BuySensors.URL.IOS" = "https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"add_with_nfc" = "Ajouter avec NFC"; -"sensor_details" = "Détails du capteur"; -"add_sensor" = "Ajouter un capteur"; -"copy_mac_address" = "Copier l'adresse MAC"; -"copy_unique_id" = "Copier l'identifiant unique"; -"name" = "Nom:"; -"mac_address" = "Adresse Mac:"; -"go_to_sensor" = "Aller à la carte du capteur"; -"unique_id" = "Identifiant unique:"; -"firmware_version" = "Version du firmware:"; -"close" = "Fermer"; -"add_sensor_nfc_df3_error" = "Ce capteur ne peut pas être ajouté avec NFC en raison d'un ancien firmware. Veuillez ajouter le capteur avec Bluetooth et mettre à jour le firmware."; -"add_sensor_description" = "Cette page montre les capteurs Ruuvi à proximité qui n'ont pas encore été ajoutés à l'application. Appuyez sur un capteur pour l'ajouter."; -"add_sensor_via_nfc" = "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone."; -"upgrade_firmware" = "Mise à jour du firmware"; diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/ru.lproj/RuuviDiscover.strings b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/ru.lproj/RuuviDiscover.strings deleted file mode 100644 index dba31af33..000000000 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/ru.lproj/RuuviDiscover.strings +++ /dev/null @@ -1,31 +0,0 @@ -"DiscoverTable.NavigationItem.title" = "Добавить Сенсор"; -"DiscoverTable.GetMoreSensors.button.title" = "Купить датчики Ruuvi"; -"DiscoverTable.BluetoothDisabledAlert.title" = "Bluetooth выключен"; -"DiscoverTable.BluetoothDisabledAlert.message" = "Ruuvi Station необходим bluetooth чтобы слушать сенсоры. Откройте Настройки и включите Bluetooth."; -"DiscoverTable.WebTagsInfoDialog.message" = "Виртуальные сенсоры показывают публичную информацию о погоде, предоставленную локальными станциями."; -"PermissionPresenter.settings" = "Настройки"; -"OK" = "OK"; -"DiscoverTable.NoDevicesSection.NotFound.text" = "(Bluetooth устройства не найдены)"; -"DiscoverTable.NoDevicesSection.BluetoothDisabled.text" = "(Bluetooth отключен)"; -"DiscoverTable.SectionTitle.Devices" = "Ближайшие Сенсоры"; -"dBm" = "дБм"; -"DiscoverTable.RuuviDevice.prefix" = "Ruuvi"; -"DiscoverTable.SectionTitle.WebTags" = "Виртуальные"; -"WebTagLocationSource.current" = "Ваше текущее месторасположение"; -"WebTagLocationSource.manual" = "Месторасположение на карте"; -"Ruuvi.BuySensors.URL.IOS" = "https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"add_with_nfc" = "Add with NFC"; -"sensor_details" = "Sensor Details"; -"add_sensor" = "Add Sensor"; -"copy_mac_address" = "Копировать MAC-адрес"; -"copy_unique_id" = "Скопировать уникальный идентификатор"; -"name" = "Name:"; -"mac_address" = "Mac Address:"; -"go_to_sensor" = "Go to sensor card"; -"unique_id" = "Unique ID:"; -"firmware_version" = "Firmware Version:"; -"close" = "Close"; -"add_sensor_nfc_df3_error" = "This sensor cannot be added with NFC due to old firmware. Please add the sensor with Bluetooth and update firmware."; -"add_sensor_description" = "Здесь показаны датчики Ruuvi, которые еще не были добавлены в приложение. Нажмите на сенсор, чтобы добавить его."; -"add_sensor_via_nfc" = "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone."; -"upgrade_firmware" = "Обновление Прошивки"; diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/sv.lproj/RuuviDiscover.strings b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/sv.lproj/RuuviDiscover.strings deleted file mode 100644 index 779a30301..000000000 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/sv.lproj/RuuviDiscover.strings +++ /dev/null @@ -1,31 +0,0 @@ -"DiscoverTable.NavigationItem.title" = "Lägg till en ny sensor"; -"DiscoverTable.GetMoreSensors.button.title" = "Köp Ruuvi-sensorer"; -"DiscoverTable.BluetoothDisabledAlert.title" = "Bluetooth är inte aktiverat"; -"DiscoverTable.BluetoothDisabledAlert.message" = "Ruuvi Station behöver bluetooth för att fungera. Gå till Inställningar och aktivera Bluetooth."; -"DiscoverTable.WebTagsInfoDialog.message" = "Virtuella Sensorer visar offentlig väder data som upprätthålls av lokala väderstationer."; -"PermissionPresenter.settings" = "Inställningar"; -"OK" = "OK"; -"DiscoverTable.NoDevicesSection.NotFound.text" = "(Inga sensorer inom Bluetooths räckvidd)"; -"DiscoverTable.NoDevicesSection.BluetoothDisabled.text" = "(Bluetooth är avaktiverat)"; -"DiscoverTable.SectionTitle.Devices" = "Ruuvi sensorer i närheten"; -"dBm" = "dBm"; -"DiscoverTable.RuuviDevice.prefix" = "Ruuvi"; -"DiscoverTable.SectionTitle.WebTags" = "Virtuella sensorer"; -"WebTagLocationSource.current" = "Din plats"; -"WebTagLocationSource.manual" = "Välj från karta"; -"Ruuvi.BuySensors.URL.IOS" = "https://ruuvi.com/products?utm_campaign=app_ua&utm_medium=referral&utm_source=ios"; -"add_with_nfc" = "Lägg till med NFC"; -"sensor_details" = "Sensordetaljer"; -"add_sensor" = "Lägg till sensor"; -"copy_mac_address" = "Kopiera MAC-adress"; -"copy_unique_id" = "Kopiera unikt ID"; -"name" = "Namn:"; -"mac_address" = "MAC-adress:"; -"go_to_sensor" = "Gå till sensorkortet"; -"unique_id" = "Unikt ID:"; -"firmware_version" = "Firmwareversion:"; -"close" = "Stänga"; -"add_sensor_nfc_df3_error" = "Denna sensor kan inte läggas till med NFC på grund av gammal firmware. Lägg till sensorn med Bluetooth och uppdatera firmware."; -"add_sensor_description" = "Den här sidan visar närliggande Ruuvi-sensorer som ännu inte har lagts till i appen. Tryck på en sensor för att lägga till den."; -"add_sensor_via_nfc" = "Alternatively, you can add a sensor using NFC by selecting Add with NFC and touching it with your phone."; -"upgrade_firmware" = "Firmware Uppdatering"; diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift index 19876bf35..d0385bb30 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift @@ -35,40 +35,6 @@ public extension UIImage { } } -extension String { - public func localized(for clazz: AnyClass) -> String { - let bundle: Bundle - #if SWIFT_PACKAGE - bundle = Bundle.module - #else - bundle = Bundle.pod(clazz) - #endif - if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { - if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), - let bundle = Bundle(path: path) { - return bundle.localizedString(forKey: self, value: nil, table: module) - } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), - let bundle = Bundle(path: path) { - return bundle.localizedString(forKey: self, value: nil, table: module) - } else { - assertionFailure() - return self - } - } else { - assertionFailure() - return self - } - } - - private func currentLanguage() -> String { - if let preferred = Bundle.main.preferredLocalizations.first { - preferred - } else { - "Base" - } - } -} - public extension UIStoryboard { static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { let bundle: Bundle diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UIViewController+Alert.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UIViewController+Alert.swift index ef5362fea..5c3d7b34f 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UIViewController+Alert.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/UIViewController+Alert.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit extension UIViewController { @@ -6,7 +7,7 @@ extension UIViewController { message: String? = nil ) { let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction(title: "OK".localized(for: Self.self), style: .cancel, handler: nil)) + alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) } } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift index bc0989ce2..2b4075b2d 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift @@ -1,13 +1,14 @@ +// swiftlint:disable file_length import BTKit import CoreBluetooth import CoreNFC -// swiftlint:disable file_length import Foundation import Future import RuuviContext import RuuviCore import RuuviFirmware import RuuviLocal +import RuuviLocalization import RuuviOntology import RuuviPresenters import RuuviReactor @@ -138,7 +139,7 @@ extension DiscoverPresenter: DiscoverViewOutput { } func viewDidTriggerBuySensors() { - guard let url = URL(string: "Ruuvi.BuySensors.URL.IOS".localized(for: Self.self)) + guard let url = URL(string: RuuviLocalization.Ruuvi.BuySensors.Url.ios) else { return } UIApplication.shared.open(url, options: [:], completionHandler: nil) } @@ -425,7 +426,7 @@ extension DiscoverPresenter { else { return nil } - return "DiscoverTable.RuuviDevice.prefix".localized(for: Self.self) + return RuuviLocalization.DiscoverTable.RuuviDevice.prefix + " " + tag.macId.replacingOccurrences(of: ":", with: "").suffix(4) } @@ -436,12 +437,12 @@ extension DiscoverPresenter { return nil } - let nameString = "\("name".localized(for: Self.self))\n\(displayName)" - let macIdString = "\("mac_address".localized(for: Self.self))\n\(tag.macId)" - let uniqueIdString = "\("unique_id".localized(for: Self.self))\n\(tag.id)" - let fwString = "\("firmware_version".localized(for: Self.self))\n\(tag.firmwareVersion)" + let nameString = "\(RuuviLocalization.name)\n\(displayName)" + let macIdString = "\(RuuviLocalization.macAddress)\n\(tag.macId)" + let uniqueIdString = "\(RuuviLocalization.uniqueId)\n\(tag.id)" + let fwString = "\(RuuviLocalization.firmwareVersion)\n\(tag.firmwareVersion)" - return "\n\(nameString)\n\n\(macIdString)\n\n\(uniqueIdString)\n\n\(fwString)\n".localized(for: Self.self) + return "\n\(nameString)\n\n\(macIdString)\n\n\(uniqueIdString)\n\n\(fwString)\n" } private func addRuuviTagOwnership( diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift index 0c9b0162e..3d4cd7e0a 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableHeaderView.swift @@ -19,9 +19,6 @@ class DiscoverTableHeaderView: UIView { CBCentralManager.authorization == .allowedAlways } - private let addSensorDescriptionKey: String = "add_sensor_description" - private let addSensorViaNFCKey: String = "add_sensor_via_nfc" - // UI private lazy var descriptionLabel = createDescriptionLabel() private lazy var nfcButton = createAddWithNFCButton() @@ -70,8 +67,8 @@ class DiscoverTableHeaderView: UIView { descriptionLabel.translatesAutoresizingMaskIntoConstraints = false descriptionLabel.numberOfLines = 0 - let addSensorString: String = addSensorDescriptionKey.localized(for: Self.self) - let addSensorViaNFCString = addSensorViaNFCKey.localized(for: Self.self) + let addSensorString: String = RuuviLocalization.addSensorDescription + let addSensorViaNFCString = RuuviLocalization.addSensorViaNfc let descriptionString = (isBluetoothPermissionGranted && isNFCAvailable) ? (addSensorString + "\n\n" + addSensorViaNFCString) : addSensorString @@ -88,7 +85,7 @@ class DiscoverTableHeaderView: UIView { let button = UIButton(type: .custom) button.translatesAutoresizingMaskIntoConstraints = false button.setImage(UIImage(systemName: "plus.circle.fill"), for: .normal) - button.setTitle("add_with_nfc".localized(for: Self.self), for: .normal) + button.setTitle(RuuviLocalization.addWithNfc, for: .normal) button.setTitleColor(.label, for: .normal) button.setInsets(forContentPadding: .zero, imageTitlePadding: 8) if let font = UIFont(name: "Muli-Regular", size: 16) { @@ -157,8 +154,8 @@ extension DiscoverTableHeaderView { nfcButton.isHidden = !show } descriptionLabelBottomConstraint.isActive = !show - let addSensorString: String = addSensorDescriptionKey.localized(for: Self.self) - let addSensorViaNFCString = addSensorViaNFCKey.localized(for: Self.self) + let addSensorString: String = RuuviLocalization.addSensorDescription + let addSensorViaNFCString = RuuviLocalization.addSensorViaNfc let descriptionString = (show && isBluetoothPermissionGranted && isNFCAvailable) ? (addSensorString + "\n\n" + addSensorViaNFCString) : addSensorString diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift index 8bf10300e..339a41852 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift @@ -52,21 +52,23 @@ class DiscoverTableViewController: UIViewController { extension DiscoverTableViewController: DiscoverViewInput { func localize() { - navigationItem.title = "DiscoverTable.NavigationItem.title".localized(for: Self.self) + navigationItem.title = RuuviLocalization.DiscoverTable.NavigationItem.title } func showBluetoothDisabled(userDeclined: Bool) { - let title = "DiscoverTable.BluetoothDisabledAlert.title".localized(for: Self.self) - let message = "DiscoverTable.BluetoothDisabledAlert.message".localized(for: Self.self) + let title = RuuviLocalization.DiscoverTable.BluetoothDisabledAlert.title + let message = RuuviLocalization.DiscoverTable.BluetoothDisabledAlert.message let alertVC = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertVC.addAction(UIAlertAction( - title: "PermissionPresenter.settings".localized(for: Self.self), - style: .default, - handler: { [weak self] _ in - self?.takeUserToBTSettings(userDeclined: userDeclined) - } - )) - alertVC.addAction(UIAlertAction(title: "OK".localized(for: Self.self), style: .cancel, handler: nil)) + alertVC.addAction( + UIAlertAction( + title: RuuviLocalization.PermissionPresenter.settings, + style: .default, + handler: { [weak self] _ in + self?.takeUserToBTSettings(userDeclined: userDeclined) + } + ) + ) + alertVC.addAction(UIAlertAction(title: RuuviLocalization.ok, style: .cancel, handler: nil)) present(alertVC, animated: true) } @@ -96,15 +98,13 @@ extension DiscoverTableViewController: DiscoverViewInput { showUpgradeFirmware: Bool, isDF3: Bool ) { - let title = "sensor_details".localized(for: Self.self) + let title = RuuviLocalization.sensorDetails // Message var messageString = message // We show extra message for DF3 sensors since they can't be added with NFC. if isDF3 { - let df3ErrorMessage = "add_sensor_nfc_df3_error".localized( - for: Self.self - ) + let df3ErrorMessage = RuuviLocalization.addSensorNfcDf3Error messageString = "\n\(df3ErrorMessage)\n" + message } @@ -124,7 +124,7 @@ extension DiscoverTableViewController: DiscoverViewInput { if showAddSensor { alertVC.addAction(UIAlertAction( - title: "add_sensor".localized(for: Self.self), + title: RuuviLocalization.addSensor, style: .default, handler: { [weak self] _ in self?.output.viewDidAddDeviceWithNFC(with: tag) @@ -133,7 +133,7 @@ extension DiscoverTableViewController: DiscoverViewInput { } alertVC.addAction(UIAlertAction( - title: "copy_mac_address".localized(for: Self.self), + title: RuuviLocalization.copyMacAddress, style: .default, handler: { [weak self] _ in self?.output.viewDidACopyMacAddress(of: tag) @@ -141,7 +141,7 @@ extension DiscoverTableViewController: DiscoverViewInput { )) alertVC.addAction(UIAlertAction( - title: "copy_unique_id".localized(for: Self.self), + title: RuuviLocalization.copyUniqueId, style: .default, handler: { [weak self] _ in self?.output.viewDidACopySecret(of: tag) @@ -150,7 +150,7 @@ extension DiscoverTableViewController: DiscoverViewInput { if showGoToSensor { alertVC.addAction(UIAlertAction( - title: "go_to_sensor".localized(for: Self.self), + title: RuuviLocalization.goToSensor, style: .default, handler: { [weak self] _ in self?.output.viewDidGoToSensor(with: tag) @@ -160,7 +160,7 @@ extension DiscoverTableViewController: DiscoverViewInput { if showUpgradeFirmware { alertVC.addAction(UIAlertAction( - title: "upgrade_firmware".localized(for: Self.self), + title: RuuviLocalization.DFUUIView.navigationTitle, style: .default, handler: { [weak self] _ in self?.output.viewDidAskToUpgradeFirmware(of: tag) @@ -168,7 +168,7 @@ extension DiscoverTableViewController: DiscoverViewInput { )) } - alertVC.addAction(UIAlertAction(title: "close".localized(for: Self.self), style: .cancel, handler: nil)) + alertVC.addAction(UIAlertAction(title: RuuviLocalization.close, style: .cancel, handler: nil)) present(alertVC, animated: true) } } @@ -260,8 +260,8 @@ extension DiscoverTableViewController: UITableViewDataSource { case .noDevices: let cell = tableView.dequeueReusableCell(with: DiscoverNoDevicesTableViewCell.self, for: indexPath) cell.descriptionLabel.text = isBluetoothEnabled - ? "DiscoverTable.NoDevicesSection.NotFound.text".localized(for: Self.self) - : "DiscoverTable.NoDevicesSection.BluetoothDisabled.text".localized(for: Self.self) + ? RuuviLocalization.DiscoverTable.NoDevicesSection.NotFound.text + : RuuviLocalization.DiscoverTable.NoDevicesSection.BluetoothDisabled.text return cell } } @@ -295,7 +295,7 @@ extension DiscoverTableViewController { // RSSI if let rssi = device.rssi { - cell.rssiLabel.text = "\(rssi)" + " " + "dBm".localized(for: Self.self) + cell.rssiLabel.text = "\(rssi)" + " " + RuuviLocalization.dBm if rssi < -80 { cell.rssiImageView.image = UIImage.named("icon-connection-1", for: Self.self) } else if rssi < -50 { @@ -318,9 +318,7 @@ extension DiscoverTableViewController { navigationController?.navigationBar.titleTextAttributes = [.font: muliBold] } - actionButton.setTitle("DiscoverTable.GetMoreSensors.button.title".localized( - for: Self.self - ).capitalized, for: .normal) + actionButton.setTitle(RuuviLocalization.DiscoverTable.GetMoreSensors.Button.title.capitalized, for: .normal) configureTableView() } @@ -364,10 +362,10 @@ extension DiscoverTableViewController { private func displayName(for device: DiscoverRuuviTagViewModel) -> String { // identifier if let mac = device.mac { - "DiscoverTable.RuuviDevice.prefix".localized(for: Self.self) + RuuviLocalization.DiscoverTable.RuuviDevice.prefix + " " + mac.replacingOccurrences(of: ":", with: "").suffix(4) } else { - "DiscoverTable.RuuviDevice.prefix".localized(for: Self.self) + RuuviLocalization.DiscoverTable.RuuviDevice.prefix + " " + (device.luid?.value.prefix(4) ?? "") } } diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/de.lproj/RuuviFirmware.strings b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/de.lproj/RuuviFirmware.strings deleted file mode 100644 index 7c47df8bb..000000000 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/de.lproj/RuuviFirmware.strings +++ /dev/null @@ -1,20 +0,0 @@ -"DFUUIView.navigationTitle" = "Firmware Update"; -"DFUUIView.latestTitle" = "Neueste verfügbare Ruuvi Firmware-Version:"; -"DFUUIView.currentTitle" = "Aktuelle Version:"; -"DFUUIView.notReportingDescription" = "Ihr Sensor meldet seine aktuelle Firmware-Version nicht. Dies bedeutet, dass wahrscheinlich eine alte Firmware-Version ausgeführt wird und eine Aktualisierung empfohlen wird."; -"DFUUIView.alreadyOnLatest" = "Sie verwenden die neueste Firmware-Version, keine Aktualisierung erforderlich"; -"DFUUIView.startUpdateProcess" = "Update-Prozess starten"; -"DFUUIView.downloadingTitle" = "Laden Sie die neueste zu aktualisierende Firmware herunter..."; -"DFUUIView.prepareTitle" = "Bereiten Sie Ihren Sensor vor"; -"DFUUIView.openCoverTitle" = "1. Öffnen Sie den Deckel Ihres Ruuvi-Sensors"; -"DFUUIView.locateBootButtonTitle" = "2. Suchen Sie die kleinen runden schwarzen Knöpfe auf der weißen Platine; ältere Ruuvi-Sensoren haben zwei Knöpfe mit den Bezeichnungen \"R\" und \"B\", während neuere nur einen Knopf ohne Beschriftung haben."; -"DFUUIView.setUpdatingModeTitle" = "3. Stellen Sie den Sensor in den Aktualisierungsmodus:"; -"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. Wenn Ihr Sensor 2 Tasten hat: Halten Sie die Taste \"B\" gedrückt und tippen Sie gleichzeitig kurz auf die Taste \"R\". Lassen Sie die Taste \"B\" los."; -"DFUUIView.toBootModeOneButtonDescription" = "3.2. Wenn Ihr Sensor eine einzelne Taste hat: Halten Sie die Taste 10 Sekunden lang gedrückt."; -"DFUUIView.toBootModeSuccessTitle" = "4. Wenn die Einstellung erfolgreich war, leuchtet ein rotes Licht auf der Platine und die Schaltfläche in der App ändert sich in \"Start the update\"."; -"DFUUIView.updatingTitle" = "Aktualisierung..."; -"DFUUIView.searchingTitle" = "Suche nach einem Sensor"; -"DFUUIView.startTitle" = "Starten Sie die Aktualisierung"; -"DFUUIView.doNotCloseTitle" = "Schließen Sie die App nicht und schalten Sie den Sensor während des Updates nicht aus."; -"DFUUIView.successfulTitle" = "Aktualisierung erfolgreich"; -"DfuFlash.Finish.text" = "BEENDEN"; diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/en.lproj/RuuviFirmware.strings b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/en.lproj/RuuviFirmware.strings deleted file mode 100644 index 467ed1605..000000000 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/en.lproj/RuuviFirmware.strings +++ /dev/null @@ -1,20 +0,0 @@ -"DFUUIView.navigationTitle" = "Firmware Update"; -"DFUUIView.latestTitle" = "Latest available Ruuvi Firmware version:"; -"DFUUIView.currentTitle" = "Current version:"; -"DFUUIView.notReportingDescription" = "Your sensor doesn't report its current firmware version. Either you're not in its Bluetooth range, it's connected to another phone, or it's running a very old firmware version."; -"DFUUIView.alreadyOnLatest" = "You are running the latest firmware version, no need to update"; -"DFUUIView.startUpdateProcess" = "Start update process"; -"DFUUIView.downloadingTitle" = "Downloading the latest firmware to be updated..."; -"DFUUIView.prepareTitle" = "Prepare your sensor"; -"DFUUIView.openCoverTitle" = "1. Open the cover of your Ruuvi sensor"; -"DFUUIView.locateBootButtonTitle" = "2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label."; -"DFUUIView.setUpdatingModeTitle" = "3. Set the sensor to updating mode:"; -"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”."; -"DFUUIView.toBootModeOneButtonDescription" = "3.2. If your sensor has a single button: keep the button pressed for 10 seconds."; -"DFUUIView.toBootModeSuccessTitle" = "4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”."; -"DFUUIView.updatingTitle" = "Updating..."; -"DFUUIView.searchingTitle" = "Searching for a sensor"; -"DFUUIView.startTitle" = "Start the update"; -"DFUUIView.doNotCloseTitle" = "Do not close the app or power off the sensor during the update."; -"DFUUIView.successfulTitle" = "Update successful"; -"DfuFlash.Finish.text" = "FINISH"; diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/fi.lproj/RuuviFirmware.strings b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/fi.lproj/RuuviFirmware.strings deleted file mode 100644 index d43a87b94..000000000 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/fi.lproj/RuuviFirmware.strings +++ /dev/null @@ -1,20 +0,0 @@ -"DFUUIView.navigationTitle" = "Laiteohjelmiston päivitys"; -"DFUUIView.latestTitle" = "Uusin saatavilla oleva Ruuvi-laiteohjelmisto:"; -"DFUUIView.currentTitle" = "Nykyinen versio:"; -"DFUUIView.notReportingDescription" = "Laitteessa oleva laiteohjelmisto ei ilmoita nykyistä versiota. Joko et ole sen Bluetooth-kuuluvuusalueella, se on samanaikaisesti yhteydessä toiseen puhelimeen tai kyseessä on hyvin vanha laiteohjelmisto."; -"DFUUIView.alreadyOnLatest" = "Laitteessa on jo viimeisin saatavilla oleva laiteohjelmisto"; -"DFUUIView.startUpdateProcess" = "Siirry päivittämään"; -"DFUUIView.downloadingTitle" = "Ladataan viimeisin laiteohjelmisto päivitystä varten..."; -"DFUUIView.prepareTitle" = "Laitteen asettaminen päivitystilaan"; -"DFUUIView.openCoverTitle" = "1. Avaa Ruuvi-anturin suojakotelo"; -"DFUUIView.locateBootButtonTitle" = "2. Paikanna valkoisella piirilevyllä olevat pienet pyöreät mustat painikkeet; vanhemmissa Ruuvi-antureissa on 2 painiketta “R” ja “B”, kun taas uudemmissa on vain yksi nimeämätön painike."; -"DFUUIView.setUpdatingModeTitle" = "3. Aseta anturi päivitystilaan:"; -"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. Anturissasi on kaksi painiketta: pidä painike “B” alaspainettuna ja napauta samalla painiketta “R”. Vapauta painike “B”."; -"DFUUIView.toBootModeOneButtonDescription" = "3.2. Anturissasi on yksi painike: pidä painiketta alaspainettuna 10 sekunnin ajan."; -"DFUUIView.toBootModeSuccessTitle" = "4. Päivitystilaan siirtyminen onnistui, mikäli piirilevyllä oleva punainen LED-valo on nyt aktiivinen ja sovelluksen painikkeen nimeksi on vaihtunut “Aloita päivitys”."; -"DFUUIView.updatingTitle" = "Päivitetään..."; -"DFUUIView.searchingTitle" = "Laitetta etsitään"; -"DFUUIView.startTitle" = "Aloita päivitys"; -"DFUUIView.doNotCloseTitle" = "Älä sulje sovellusta tai poista paristoa laitteesta päivityksen aikana."; -"DFUUIView.successfulTitle" = "Päivitys onnistui"; -"DfuFlash.Finish.text" = "VALMIS"; diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/fr.lproj/RuuviFirmware.strings b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/fr.lproj/RuuviFirmware.strings deleted file mode 100644 index 5b0c767bf..000000000 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/fr.lproj/RuuviFirmware.strings +++ /dev/null @@ -1,20 +0,0 @@ -"DFUUIView.navigationTitle" = "Mise à jour du firmware"; -"DFUUIView.latestTitle" = "Dernière version du Ruuvi Firmware :"; -"DFUUIView.currentTitle" = "Version actuelle :"; -"DFUUIView.notReportingDescription" = "Impossible d'obtenir la version actuelle de l'appareil. La version est probablement trop ancienne et il est recommandé d'effectuer une mise à jour."; -"DFUUIView.alreadyOnLatest" = "L'appareil est à déjà à jour"; -"DFUUIView.startUpdateProcess" = "Début de la mise à jour"; -"DFUUIView.downloadingTitle" = "Téléchargement de la dernière version pour la mise à jour..."; -"DFUUIView.prepareTitle" = "Préparez votre capteur"; -"DFUUIView.openCoverTitle" = "1. Ouvrez le couvercle de votre capteur Ruuvi"; -"DFUUIView.locateBootButtonTitle" = "2. Localisez les petits boutons ronds noirs sur la carte de circuit imprimé blanche ; les anciens capteurs Ruuvi ont 2 boutons étiquetés \"R\" et \"B\" tandis que les plus récents n'ont qu'un seul bouton sans étiquette."; -"DFUUIView.setUpdatingModeTitle" = "3. Mettez le capteur en mode de mise à jour :"; -"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. Si votre capteur est équipé de 2 boutons : maintenez le bouton \"B\" enfoncé tout en appuyant momentanément sur le bouton \"R\". Relâchez le bouton \"B\"."; -"DFUUIView.toBootModeOneButtonDescription" = "3.2. Si votre capteur possède un seul bouton : maintenez le bouton enfoncé pendant 10 secondes."; -"DFUUIView.toBootModeSuccessTitle" = "4. Si le réglage est réussi, vous verrez une lumière rouge fixe s'allumer sur la carte de circuit imprimé et le bouton de l'application passera à \"Démarrer la mise à jour\"."; -"DFUUIView.updatingTitle" = "Mise à jour..."; -"DFUUIView.searchingTitle" = "Recherche d'un capteur"; -"DFUUIView.startTitle" = "Lancer la mise à jour"; -"DFUUIView.doNotCloseTitle" = "Ne pas fermer l'application ou enlever la pile du capteur pendant la mise à jour."; -"DFUUIView.successfulTitle" = "Mise à jour réussie"; -"DfuFlash.Finish.text" = "PRÊT"; diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/ru.lproj/RuuviFirmware.strings b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/ru.lproj/RuuviFirmware.strings deleted file mode 100644 index 7574cdef1..000000000 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/ru.lproj/RuuviFirmware.strings +++ /dev/null @@ -1,20 +0,0 @@ -"DFUUIView.navigationTitle" = "Обновление Прошивки"; -"DFUUIView.latestTitle" = "Доступная версия прошивки Ruuvi:"; -"DFUUIView.currentTitle" = "Текущая версия:"; -"DFUUIView.notReportingDescription" = "Ваш сенсор не возвращает версию прошивки. Вероятно, на нем установлена старая версия прошивки и обновление рекомендовано."; -"DFUUIView.alreadyOnLatest" = "Последняя версия прошивки уже установлена, обновление не требуется"; -"DFUUIView.startUpdateProcess" = "Начать процесс обновления"; -"DFUUIView.downloadingTitle" = "Идет скачивание обновления прошивки..."; -"DFUUIView.prepareTitle" = "Prepare your sensor"; -"DFUUIView.openCoverTitle" = "1. Open the cover of your Ruuvi sensor"; -"DFUUIView.locateBootButtonTitle" = "2. Locate the small round black buttons on the white circuit board; older Ruuvi sensors have 2 buttons labelled “R” and “B” while newer ones have only one button without a label."; -"DFUUIView.setUpdatingModeTitle" = "3. Set the sensor to updating mode:"; -"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. If your sensor has 2 buttons: keep “B” button pressed while tapping button “R” momentarily. Release button “B”."; -"DFUUIView.toBootModeOneButtonDescription" = "3.2. If your sensor has a single button: keep the button pressed for 10 seconds."; -"DFUUIView.toBootModeSuccessTitle" = "4. If set successfully, you will see a solid red light lit on the circuit board and the button in the app will change to “Start the update”."; -"DFUUIView.updatingTitle" = "Обновляю..."; -"DFUUIView.searchingTitle" = "Searching for a sensor"; -"DFUUIView.startTitle" = "Start the update"; -"DFUUIView.doNotCloseTitle" = "Не закрывайте приложение и не отключайте сенсор во время обновления."; -"DFUUIView.successfulTitle" = "Обновление успешно завершено"; -"DfuFlash.Finish.text" = "УСПЕХ"; diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/sv.lproj/RuuviFirmware.strings b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/sv.lproj/RuuviFirmware.strings deleted file mode 100644 index 4cf842198..000000000 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/sv.lproj/RuuviFirmware.strings +++ /dev/null @@ -1,20 +0,0 @@ -"DFUUIView.navigationTitle" = "Firmware Uppdatering"; -"DFUUIView.latestTitle" = "Senast tillgängliga Ruuvi firmwareversion:"; -"DFUUIView.currentTitle" = "Nuvarande version:"; -"DFUUIView.notReportingDescription" = "Din sensor rapporterar inte sin nuvarande firmwareversion. Det betyder att den förmodligen har en gammal firmwareversion och uppdatering rekommenderas."; -"DFUUIView.alreadyOnLatest" = "Du har redan den senaste firmwareversionen, ingen uppdatering behövs"; -"DFUUIView.startUpdateProcess" = "Starta uppdateringsprocessen"; -"DFUUIView.downloadingTitle" = "Hämtar senaste firmware.."; -"DFUUIView.prepareTitle" = "Förbered din sensor"; -"DFUUIView.openCoverTitle" = "1. Öppna locket på din Ruuvi sensor"; -"DFUUIView.locateBootButtonTitle" = "2. Leta reda på små runda svarta knappar på det vita kretskortet; äldre Ruuvi-sensorer har 2 knappar märkta “R“ och “B“ medan nyare har bara en knapp utan etikett."; -"DFUUIView.setUpdatingModeTitle" = "3. Lägg sensorn i uppdateringsläge"; -"DFUUIView.toBootModeTwoButtonsDescription" = "3.1. Om din sensor har två knappar: håll knappen “B” intryckt medan du trycker en gång på “R”. Släpp knapp “B”."; -"DFUUIView.toBootModeOneButtonDescription" = "3.2. Om din sensor har en knapp, håll knappen intryckt i 10 sekunder."; -"DFUUIView.toBootModeSuccessTitle" = "4. Uppgraderingsläget lyckades om den röda lysdioden på kretskortet lyser och knappens text i appen har bytts till “Starta uppdatering“."; -"DFUUIView.updatingTitle" = "Uppdaterar..."; -"DFUUIView.searchingTitle" = "Söker efter en sensor"; -"DFUUIView.startTitle" = "Starta uppdatering"; -"DFUUIView.doNotCloseTitle" = "Stäng inte appen eller stäng av sensorn under uppdateringen."; -"DFUUIView.successfulTitle" = "Uppdateringen lyckades"; -"DfuFlash.Finish.text" = "KLAR"; diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift index f3784967b..c01d4bd2a 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift @@ -7,32 +7,28 @@ struct FirmwareView: View { @ObservedObject var viewModel: FirmwareViewModel private struct Texts { - let navigationTitle = "DFUUIView.navigationTitle".localized(for: FirmwareViewModel.self) - let latestTitle = "DFUUIView.latestTitle".localized(for: FirmwareViewModel.self) - let currentTitle = "DFUUIView.currentTitle".localized(for: FirmwareViewModel.self) - let lowBatteryWarningMessage = "DFUUIView.lowBattery.warning.message".localized(for: FirmwareViewModel.self) - let okTitle = "ErrorPresenterAlert.OK".localized(for: FirmwareViewModel.self) - let notReportingDescription = "DFUUIView.notReportingDescription".localized(for: FirmwareViewModel.self) - let alreadyOnLatest = "DFUUIView.alreadyOnLatest".localized(for: FirmwareViewModel.self) - let startUpdateProcess = "DFUUIView.startUpdateProcess".localized(for: FirmwareViewModel.self) - let downloadingTitle = "DFUUIView.downloadingTitle".localized(for: FirmwareViewModel.self) - let prepareTitle = "DFUUIView.prepareTitle".localized(for: FirmwareViewModel.self) - let openCoverTitle = "DFUUIView.openCoverTitle".localized(for: FirmwareViewModel.self) - let localBootButtonTitle = "DFUUIView.locateBootButtonTitle".localized(for: FirmwareViewModel.self) - let setUpdatingModeTitle = "DFUUIView.setUpdatingModeTitle".localized(for: FirmwareViewModel.self) - let toBootModeTwoButtonsDescription = "DFUUIView.toBootModeTwoButtonsDescription".localized( - for: FirmwareViewModel.self - ) - let toBootModeOneButtonDescription = "DFUUIView.toBootModeOneButtonDescription".localized( - for: FirmwareViewModel.self - ) - let toBootModeSuccessTitle = "DFUUIView.toBootModeSuccessTitle".localized(for: FirmwareViewModel.self) - let updatingTitle = "DFUUIView.updatingTitle".localized(for: FirmwareViewModel.self) - let searchingTitle = "DFUUIView.searchingTitle".localized(for: FirmwareViewModel.self) - let startTitle = "DFUUIView.startTitle".localized(for: FirmwareViewModel.self) - let doNotCloseTitle = "DFUUIView.doNotCloseTitle".localized(for: FirmwareViewModel.self) - let successfulTitle = "DFUUIView.successfulTitle".localized(for: FirmwareViewModel.self) - let finish = "DfuFlash.Finish.text".localized(for: FirmwareViewModel.self) + let navigationTitle = RuuviLocalization.DFUUIView.navigationTitle + let latestTitle = RuuviLocalization.DFUUIView.latestTitle + let currentTitle = RuuviLocalization.DFUUIView.currentTitle + let lowBatteryWarningMessage = RuuviLocalization.DFUUIView.LowBattery.Warning.message + let okTitle = RuuviLocalization.ErrorPresenterAlert.ok + let notReportingDescription = RuuviLocalization.DFUUIView.notReportingDescription + let alreadyOnLatest = RuuviLocalization.DFUUIView.alreadyOnLatest + let startUpdateProcess = RuuviLocalization.DFUUIView.startUpdateProcess + let downloadingTitle = RuuviLocalization.DFUUIView.downloadingTitle + let prepareTitle = RuuviLocalization.DFUUIView.prepareTitle + let openCoverTitle = RuuviLocalization.DFUUIView.openCoverTitle + let localBootButtonTitle = RuuviLocalization.DFUUIView.locateBootButtonTitle + let setUpdatingModeTitle = RuuviLocalization.DFUUIView.setUpdatingModeTitle + let toBootModeTwoButtonsDescription = RuuviLocalization.DFUUIView.toBootModeTwoButtonsDescription + let toBootModeOneButtonDescription = RuuviLocalization.DFUUIView.toBootModeOneButtonDescription + let toBootModeSuccessTitle = RuuviLocalization.DFUUIView.toBootModeSuccessTitle + let updatingTitle = RuuviLocalization.DFUUIView.updatingTitle + let searchingTitle = RuuviLocalization.DFUUIView.searchingTitle + let startTitle = RuuviLocalization.DFUUIView.startTitle + let doNotCloseTitle = RuuviLocalization.DFUUIView.doNotCloseTitle + let successfulTitle = RuuviLocalization.DFUUIView.successfulTitle + let finish = RuuviLocalization.DfuFlash.Finish.text } private let texts = Texts() diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift index 19876bf35..d0385bb30 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift @@ -35,40 +35,6 @@ public extension UIImage { } } -extension String { - public func localized(for clazz: AnyClass) -> String { - let bundle: Bundle - #if SWIFT_PACKAGE - bundle = Bundle.module - #else - bundle = Bundle.pod(clazz) - #endif - if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { - if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), - let bundle = Bundle(path: path) { - return bundle.localizedString(forKey: self, value: nil, table: module) - } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), - let bundle = Bundle(path: path) { - return bundle.localizedString(forKey: self, value: nil, table: module) - } else { - assertionFailure() - return self - } - } else { - assertionFailure() - return self - } - } - - private func currentLanguage() -> String { - if let preferred = Bundle.main.preferredLocalizations.first { - preferred - } else { - "Base" - } - } -} - public extension UIStoryboard { static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { let bundle: Bundle diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift index c8d864bcf..4be61b635 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift @@ -46,7 +46,7 @@ class RuuviOnboardGatewayFeaturesCell: UICollectionViewCell { label.textColor = .white label.textAlignment = .left label.numberOfLines = 0 - label.text = "onboarding_gateway_required".localized(for: Self.self) + label.text = RuuviLocalization.onboardingGatewayRequired label.font = UIFont.Muli(.semiBoldItalic, size: 16) return label }() diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift index 8fe141cdc..11dc6eadf 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift @@ -41,7 +41,7 @@ class RuuviOnboardSignInCell: UICollectionViewCell { private lazy var continueButton: UIButton = { let button = UIButton(color: RuuviColor.tintColor.color, cornerRadius: 22) button.setTitle( - "onboarding_continue".localized(for: Self.self), + RuuviLocalization.onboardingContinue, for: .normal ) button.setTitleColor(.white, for: .normal) diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift index da863fb5e..90ab40f58 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import RuuviUser import UIKit @@ -68,7 +69,7 @@ class RuuviOnboardViewController: UIViewController { private lazy var skipButton: UIButton = { let button = UIButton() button.setTitleColor(.white, for: .normal) - button.setTitle("onboarding_skip".localized(for: Self.self), for: .normal) + button.setTitle(RuuviLocalization.onboardingSkip, for: .normal) button.titleLabel?.font = UIFont.Muli(.bold, size: 14) button.addTarget( self, @@ -371,68 +372,68 @@ private extension RuuviOnboardViewController { func constructOnboardingPages() -> [OnboardViewModel] { let meaureItem = OnboardViewModel( pageType: .measure, - title: "onboarding_measure_your_world".localized(for: Self.self), - subtitle: "onboarding_with_ruuvi_sensors".localized(for: Self.self), - sub_subtitle: "onboarding_swipe_to_continue".localized(for: Self.self) + title: RuuviLocalization.onboardingMeasureYourWorld, + subtitle: RuuviLocalization.onboardingWithRuuviSensors, + sub_subtitle: RuuviLocalization.onboardingSwipeToContinue ) let dashboardItem = OnboardViewModel( pageType: .dashboard, - title: "onboarding_dashboard".localized(for: Self.self), - subtitle: "onboarding_follow_measurement".localized(for: Self.self), + title: RuuviLocalization.onboardingDashboard, + subtitle: RuuviLocalization.onboardingFollowMeasurement, image: RuuviAssets.dashboard ) let sensorItem = OnboardViewModel( pageType: .sensors, - title: "onboarding_your_sensors".localized(for: Self.self), - subtitle: "onboarding_personalise".localized(for: Self.self), + title: RuuviLocalization.onboardingYourSensors, + subtitle: RuuviLocalization.onboardingPersonalise, image: RuuviAssets.sensors ) let historyItem = OnboardViewModel( pageType: .history, - title: "onboarding_history".localized(for: Self.self), - subtitle: "onboarding_explore_detailed".localized(for: Self.self), + title: RuuviLocalization.onboardingHistory, + subtitle: RuuviLocalization.onboardingExploreDetailed, image: RuuviAssets.history ) let alertItem = OnboardViewModel( pageType: .alerts, - title: "onboarding_alerts".localized(for: Self.self), - subtitle: "onboarding_set_custom".localized(for: Self.self), + title: RuuviLocalization.onboardingAlerts, + subtitle: RuuviLocalization.onboardingSetCustom, image: RuuviAssets.alerts ) let shareItem = OnboardViewModel( pageType: .share, - title: "onboarding_share_your_sensors".localized(for: Self.self), - subtitle: "onboarding_sharees_can_use".localized(for: Self.self), + title: RuuviLocalization.onboardingShareYourSensors, + subtitle: RuuviLocalization.onboardingShareesCanUse, image: RuuviAssets.share ) let widgetItem = OnboardViewModel( pageType: .widgets, - title: "onboarding_handy_widgets".localized(for: Self.self), - subtitle: "onboarding_access_widgets".localized(for: Self.self), + title: RuuviLocalization.onboardingHandyWidgets, + subtitle: RuuviLocalization.onboardingAccessWidgets, image: RuuviAssets.widgets ) let webItem = OnboardViewModel( pageType: .web, - title: "onboarding_station_web".localized(for: Self.self), - subtitle: "onboarding_web_pros".localized(for: Self.self), + title: RuuviLocalization.onboardingStationWeb, + subtitle: RuuviLocalization.onboardingWebPros, image: RuuviAssets.web ) let signInItem = OnboardViewModel( pageType: .signIn, title: isUserAuthorized() ? - "onboarding_thats_it_already_signed_in".localized(for: Self.self) : - "onboarding_thats_it".localized(for: Self.self), + RuuviLocalization.onboardingThatsItAlreadySignedIn : + RuuviLocalization.onboardingThatsIt, subtitle: isUserAuthorized() ? - "onboarding_go_to_sign_in_already_signed_in".localized(for: Self.self) : - "onboarding_go_to_sign_in".localized(for: Self.self) + RuuviLocalization.onboardingGoToSignInAlreadySignedIn : + RuuviLocalization.onboardingGoToSignIn ) return [ diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift index 19876bf35..d0385bb30 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift @@ -35,40 +35,6 @@ public extension UIImage { } } -extension String { - public func localized(for clazz: AnyClass) -> String { - let bundle: Bundle - #if SWIFT_PACKAGE - bundle = Bundle.module - #else - bundle = Bundle.pod(clazz) - #endif - if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { - if let path = bundle.path(forResource: currentLanguage(), ofType: "lproj"), - let bundle = Bundle(path: path) { - return bundle.localizedString(forKey: self, value: nil, table: module) - } else if let path = bundle.path(forResource: "Base", ofType: "lproj"), - let bundle = Bundle(path: path) { - return bundle.localizedString(forKey: self, value: nil, table: module) - } else { - assertionFailure() - return self - } - } else { - assertionFailure() - return self - } - } - - private func currentLanguage() -> String { - if let preferred = Bundle.main.preferredLocalizations.first { - preferred - } else { - "Base" - } - } -} - public extension UIStoryboard { static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { let bundle: Bundle diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/de.lproj/RuuviOnboard.strings b/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/de.lproj/RuuviOnboard.strings deleted file mode 100644 index a5b7645e4..000000000 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/de.lproj/RuuviOnboard.strings +++ /dev/null @@ -1,45 +0,0 @@ -"RuuviOnboard.Welcome.title" = "Wischen Sie, um zu sehen, was Ruuvi Station für Sie tun kann."; -"RuuviOnboard.Measure.title" = "Umweltdaten messen: Temperatur, relative Luftfeuchtigkeit und Luftdruck."; -"RuuviOnboard.Access.title" = "Greifen Sie in Echtzeit auf Daten für jeden verknüpften Sensor zu und erkunden Sie Verlaufsdiagramme."; -"RuuviOnboard.Alerts.title" = "Stellen Sie Benachrichtigungen ein und lassen Sie sich benachrichtigen, wenn Ihre Limits erreicht werden."; -"RuuviOnboard.Start.title" = "Drücken Sie SCAN, um Sensoren in der Nähe zu finden und Ihrer Ruuvi Station hinzuzufügen."; -"RuuviOnboard.Start.button" = "SCANNEN"; -"RuuviOnboard.Cloud.title" = "Melden Sie sich an, um das volle Potenzial der App zu nutzen."; -"RuuviOnboard.Cloud.subtitle" = "Beanspruchen Sie das Eigentum an Ihren Sensoren mit einem kostenlosen Ruuvi Cloud-Konto."; -"RuuviOnboard.Cloud.subtitle.signed" = "Super! Sie haben sich bereits angemeldet!"; -"RuuviOnboard.Cloud.SignIn.title" = "Einloggen"; -"RuuviOnboard.Cloud.Details.title" = "Einzelheiten"; -"RuuviOnboard.Cloud.Benefits.title" = "Ruuvi Cloud"; -"RuuviOnboard.Cloud.Benefits.message" = "Vorteile:\\n\\n ● Sensornamen, Hintergrundbilder, Offsets und Alarmeinstellungen werden sicher in der Cloud gespeichert\\n\\n ● Fernzugriff auf Sensoren über das Internet (erfordert ein Ruuvi Gateway)\\n\\n ● Teilen Sie Sensoren mit Freunden und Familie (erfordert ein Ruuvi Gateway)\\n\\n ● Sehen Sie bis zu 2 Jahre Geschichtsdaten auf station.ruuvi.com (erfordert ein Ruuvi-Gateway)"; -"RuuviOnboard.Cloud.Close.title" = "Schließen"; -"RuuviOnboard.Cloud.Skip.title" = "Sind Sie sicher, dass Sie die Anmeldung überspringen wollen?"; -"RuuviOnboard.Cloud.Skip.Yes.title" = "Ja, überspringen"; -"RuuviOnboard.Cloud.Skip.GoBack.title" = "Zurückgehen"; - -// New Onboarding -"onboarding_measure_your_world" = "Measure Your World"; -"onboarding_with_ruuvi_sensors" = "Lernen Sie Ihre Ruuvi Station -App kennen."; -"onboarding_swipe_to_continue" = "Wischen Sie zum Fortfahren →"; -"onboarding_read_sensors_data" = "Lesen Sie Ihre Ruuvi-Sensoren"; -"onboarding_via_bluetooth_or_cloud" = "mit Bluetooth oder Ruuvi Cloud"; -"onboarding_follow_measurement" = "Sehen Sie alle Sensoren auf einen Blick auf Ihrem"; -"onboarding_dashboard" = "Dashboard"; -"onboarding_personalise" = "Personalisieren"; -"onboarding_your_sensors" = "Sie Ihre App mit benutzerdefinierten Namen und Hintergründen."; -"onboarding_explore_detailed" = "Erkunden Sie Ihren"; -"onboarding_history" = "Messverlauf"; -"onboarding_set_custom" = "Einstellen und anpassen"; -"onboarding_alerts" = "Alarme"; -"onboarding_share_your_sensors" = "zum Messen mit Ihren Freunden und Ihrer Familie."; -"onboarding_sharees_can_use" = "Teilen Sie Sensoren"; -"onboarding_handy_widgets" = "Widgets hinzu"; -"onboarding_access_widgets" = "Fügen Sie Ihre bevorzugten Sensoren als"; -"onboarding_station_web" = "Ruuvi Web App"; -"onboarding_web_pros" = "Großes Dashboard, mehrjähriger Verlauf, E-Mail-Benachrichtigungen und mehr in der"; -"onboarding_gateway_required" = "Ein Ruuvi Gateway -Router ist erforderlich."; -"onboarding_skip" = "Überspringen"; -"onboarding_thats_it" = "Fast dort!"; -"onboarding_thats_it_already_signed_in" = "Lass uns anfangen!"; -"onboarding_go_to_sign_in" = "Ruuvi ist besser, wenn Sie angemeldet sind. Machen Sie es jetzt oder fahren Sie ohne Cloud-Funktionen fort."; -"onboarding_go_to_sign_in_already_signed_in" = "Fangen wir an zu messen!"; -"onboarding_continue" = "Nächste"; diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/en.lproj/RuuviOnboard.strings b/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/en.lproj/RuuviOnboard.strings deleted file mode 100644 index 23e521903..000000000 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/en.lproj/RuuviOnboard.strings +++ /dev/null @@ -1,45 +0,0 @@ -"RuuviOnboard.Welcome.title" = "Swipe to see what Ruuvi Station can do for you."; -"RuuviOnboard.Measure.title" = "Measure environmental data: temperature, relative humidity and air pressure."; -"RuuviOnboard.Access.title" = "Access data for each linked sensor in real time and explore history graphs."; -"RuuviOnboard.Alerts.title" = "Set alerts and get notified whenever your limits are hit."; -"RuuviOnboard.Start.title" = "Press SCAN to find and add nearby sensors to your Ruuvi Station."; -"RuuviOnboard.Start.button" = "SCAN"; -"RuuviOnboard.Cloud.title" = "Sign in to use the full potential of the app."; -"RuuviOnboard.Cloud.subtitle" = "Claim ownership of your sensors with a free Ruuvi Cloud account."; -"RuuviOnboard.Cloud.subtitle.signed" = "Great! You already signed in!"; -"RuuviOnboard.Cloud.SignIn.title" = "Sign in"; -"RuuviOnboard.Cloud.Details.title" = "Details"; -"RuuviOnboard.Cloud.Benefits.title" = "Ruuvi Cloud"; -"RuuviOnboard.Cloud.Benefits.message" = "Benefits:\\n\\n ● Sensor names, background images, offsets and alert settings will be securely stored in the cloud\\n\\n ● Access sensors remotely over the Internet (requires a Ruuvi Gateway)\\n\\n ● Share sensors with friends and family (requires a Ruuvi Gateway)\\n\\n ● Browse up to 2 years of history on station.ruuvi.com (requires a Ruuvi Gateway)"; -"RuuviOnboard.Cloud.Close.title" = "Close"; -"RuuviOnboard.Cloud.Skip.title" = "Are you sure want to skip sign in?"; -"RuuviOnboard.Cloud.Skip.Yes.title" = "Yes, skip"; -"RuuviOnboard.Cloud.Skip.GoBack.title" = "Go Back"; - -// New Onboarding -"onboarding_measure_your_world" = "Measure Your World"; -"onboarding_with_ruuvi_sensors" = "Let's get to know your Ruuvi Station app."; -"onboarding_swipe_to_continue" = "Swipe to continue →"; -"onboarding_read_sensors_data" = "Read Your Ruuvi Sensors"; -"onboarding_via_bluetooth_or_cloud" = "using Bluetooth or Ruuvi Cloud"; -"onboarding_follow_measurement" = "View all sensors at a glance on your"; -"onboarding_dashboard" = "Dashboard"; -"onboarding_personalise" = "Personalise"; -"onboarding_your_sensors" = "your app with custom names and backgrounds."; -"onboarding_explore_detailed" = "Explore your measurement"; -"onboarding_history" = "History"; -"onboarding_set_custom" = "Set and customise your"; -"onboarding_alerts" = "Alerts"; -"onboarding_share_your_sensors" = "to measure together with your friends and family."; -"onboarding_sharees_can_use" = "Share Sensors"; -"onboarding_handy_widgets" = "Widgets"; -"onboarding_access_widgets" = "Bring your favorite sensors to your Home Screen and Lock Screen as"; -"onboarding_station_web" = "Ruuvi Web App"; -"onboarding_web_pros" = "Large dashboard, multi-year history, email alerts and more on"; -"onboarding_gateway_required" = "A Ruuvi Gateway router is required."; -"onboarding_skip" = "Skip"; -"onboarding_thats_it" = "Almost there!"; -"onboarding_thats_it_already_signed_in" = "Let's get started!"; -"onboarding_go_to_sign_in" = "Ruuvi experience is better when you're signed in. Do it now or continue without cloud features."; -"onboarding_go_to_sign_in_already_signed_in" = "Let's start measuring!"; -"onboarding_continue" = "Next"; diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/fi.lproj/RuuviOnboard.strings b/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/fi.lproj/RuuviOnboard.strings deleted file mode 100644 index 29741bc95..000000000 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/fi.lproj/RuuviOnboard.strings +++ /dev/null @@ -1,45 +0,0 @@ -"RuuviOnboard.Welcome.title" = "Tutustu Ruuvi Station -sovellukseen."; -"RuuviOnboard.Measure.title" = "Mittaa ympäristösi olosuhteita: lämpötilaa, ilmankosteutta ja ilmanpainetta."; -"RuuviOnboard.Access.title" = "Tarkastele anturitietoja reaaliaikaisesti tai tutki laitteelle tallennettuja historiatietoja."; -"RuuviOnboard.Alerts.title" = "Aseta hälytyksiä ja ilmoituksia haluamallasi tavalla."; -"RuuviOnboard.Start.title" = "Näytä lähietäisyydellä olevat anturit napauttamalla SKANNAA."; -"RuuviOnboard.Start.button" = "SKANNAA"; -"RuuviOnboard.Cloud.title" = "Kirjaudu sisään käyttääksesi kaikkia sovelluksen ominaisuuksia."; -"RuuviOnboard.Cloud.subtitle" = "Vahvista anturiesi omistajuudet ilmaisen Ruuvi Cloud -tilin avulla."; -"RuuviOnboard.Cloud.subtitle.signed" = "Hienoa, olet jo kirjautunut sisään!"; -"RuuviOnboard.Cloud.SignIn.title" = "Kirjaudu"; -"RuuviOnboard.Cloud.Details.title" = "Tiedot"; -"RuuviOnboard.Cloud.Benefits.title" = "Ruuvi Cloud"; -"RuuviOnboard.Cloud.Benefits.message" = "Hyödyt:\\n\\n ● Anturien nimet, taustakuvat sekä kalibrointi- ja hälytysasetukset tallentuvat turvallisesti tilillesi pilvipalveluun\\n\\n ● Lue anturitiedot etänä verkossa (vaatii Ruuvi Gateway -reitittimen)\\n\\n ● Jaa antureita ystävien ja perheen kesken (vaatii Ruuvi Gateway -reitittimen)\\n\\n ● Selaa jopa 2 vuoden historiatietoja osoitteessa station.ruuvi.com (vaatii Ruuvi Gateway -reitittimen)"; -"RuuviOnboard.Cloud.Close.title" = "Sulje"; -"RuuviOnboard.Cloud.Skip.title" = "Haluatko varmasti ohittaa sisäänkirjautumisen?"; -"RuuviOnboard.Cloud.Skip.Yes.title" = "Kyllä, ohita"; -"RuuviOnboard.Cloud.Skip.GoBack.title" = "Takaisin"; - -// New Onboarding -"onboarding_measure_your_world" = "Measure Your World"; -"onboarding_with_ruuvi_sensors" = "Tutustu Ruuvi Station -sovellukseesi."; -"onboarding_swipe_to_continue" = "Jatka pyyhkäisemällä →"; -"onboarding_read_sensors_data" = "Lue Ruuvi-antureitasi"; -"onboarding_via_bluetooth_or_cloud" = "Bluetoothilla tai Ruuvi Cloudilla"; -"onboarding_follow_measurement" = "Seuraa kaikkia antureitasi"; -"onboarding_dashboard" = "koontinäytöltä"; -"onboarding_personalise" = "Personoi"; -"onboarding_your_sensors" = "sovelluksesi omilla nimillä ja taustakuvilla."; -"onboarding_explore_detailed" = "Tarkastele anturiesi"; -"onboarding_history" = "mittaushistoriaa"; -"onboarding_set_custom" = "Aseta ja säädä omat"; -"onboarding_alerts" = "hälytyksesi"; -"onboarding_share_your_sensors" = "ja mittaa yhdessä ystävien sekä perheen kesken."; -"onboarding_sharees_can_use" = "Jaa anturisi"; -"onboarding_handy_widgets" = "widgeteillä"; -"onboarding_access_widgets" = "Tuo suosikkianturisi kotinäytölle ja lukitusnäytölle"; -"onboarding_station_web" = "Ruuvin web-sovelluksessa"; -"onboarding_web_pros" = "Koontinäyttö, usean vuoden historia, sähköpostihälytykset ja paljon muuta"; -"onboarding_gateway_required" = "Vaatii Ruuvi Gateway -reitittimen."; -"onboarding_skip" = "Ohita"; -"onboarding_thats_it" = "Melkein valmista!"; -"onboarding_thats_it_already_signed_in" = "Aloitetaan!"; -"onboarding_go_to_sign_in" = "Kirjautumalla sisään saat parhaan Ruuvi-käyttökokemuksen. Tee se nyt tai jatka ilman pilviominaisuuksia."; -"onboarding_go_to_sign_in_already_signed_in" = "Lähdetään mittaamaan!"; -"onboarding_continue" = "Seuraava"; diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/fr.lproj/RuuviOnboard.strings b/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/fr.lproj/RuuviOnboard.strings deleted file mode 100644 index a2d500bab..000000000 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/fr.lproj/RuuviOnboard.strings +++ /dev/null @@ -1,45 +0,0 @@ -"RuuviOnboard.Welcome.title" = "Découvrez l'application Ruuvi Station."; -"RuuviOnboard.Measure.title" = "Mesurer votre environnement : température, humidité, et pression de l'air."; -"RuuviOnboard.Access.title" = "Vérifier les données en temps réels ou consultez les histogrammes."; -"RuuviOnboard.Alerts.title" = "Définir des alarmes et des notifications comme vous le souhaitez."; -"RuuviOnboard.Start.title" = "Afficher les capteurs à proximité en appuyant sur BALAYAGE."; -"RuuviOnboard.Start.button" = "BALAYAGE EN COURS"; -"RuuviOnboard.Cloud.title" = "Connectez-vous pour utiliser tout le potentiel de l'application."; -"RuuviOnboard.Cloud.subtitle" = "Réclamez la propriété de vos capteurs avec un compte Ruuvi Cloud gratuit."; -"RuuviOnboard.Cloud.subtitle.signed" = "Super ! Vous vous êtes déjà connecté !"; -"RuuviOnboard.Cloud.SignIn.title" = "Connexion"; -"RuuviOnboard.Cloud.Details.title" = "Détails"; -"RuuviOnboard.Cloud.Benefits.title" = "Ruuvi Cloud"; -"RuuviOnboard.Cloud.Benefits.message" = "Avantages :\\n\\n ● Les noms, fonds d'écrans, les réglages de calibration, ainsi que les alertes sont enregistrés de façon sécurisée dans notre cloud\\n\\n ● Consultez les données à distance depuis n'importe quel navigateur (routeur Ruuvi Gateway requis)\\n\\n ● Partager les capteurs avec votre famille ou des amis (routeur Ruuvi Gateway requis)\\n\\n ● consultez jusqu'à deux ans d'historique de vos données sur le site station.ruuvi.com (routeur Ruuvi Gateway requis)"; -"RuuviOnboard.Cloud.Close.title" = "Fermer"; -"RuuviOnboard.Cloud.Skip.title" = "Êtes-vous sûr de vouloir ignorer l'ouverture de session ?"; -"RuuviOnboard.Cloud.Skip.Yes.title" = "Oui, passez."; -"RuuviOnboard.Cloud.Skip.GoBack.title" = "Retourner"; - -// New Onboarding -"onboarding_measure_your_world" = "Measure Your World"; -"onboarding_with_ruuvi_sensors" = "Apprenez à connaître votre application Ruuvi Station."; -"onboarding_swipe_to_continue" = "Balayez pour continuer →"; -"onboarding_read_sensors_data" = "Lisez vos capteurs Ruuvi"; -"onboarding_via_bluetooth_or_cloud" = "en utilisant Bluetooth ou Ruuvi Cloud"; -"onboarding_follow_measurement" = "Visualisez tous les capteurs en un coup d'œil sur votre"; -"onboarding_dashboard" = "tableau de bord"; -"onboarding_personalise" = "Personnalisez"; -"onboarding_your_sensors" = "votre application avec des noms et des arrière-plans personnalisés."; -"onboarding_explore_detailed" = "Explorez votre"; -"onboarding_history" = "historique de mesure"; -"onboarding_set_custom" = "Définissez et personnalisez vos"; -"onboarding_alerts" = "alertes"; -"onboarding_share_your_sensors" = "à mesurer avec vos amis et votre famille."; -"onboarding_sharees_can_use" = "Partagez des capteurs"; -"onboarding_handy_widgets" = "de widgets"; -"onboarding_access_widgets" = "Apportez vos capteurs préférés sur votre écran d'accueil et votre écran de verrouillage sous forme"; -"onboarding_station_web" = "l'application Web Ruuvi"; -"onboarding_web_pros" = "Grand tableau de bord, historique pluriannuel, alertes par e-mail et plus encore sur"; -"onboarding_gateway_required" = "Un routeur Ruuvi Gateway est requis."; -"onboarding_skip" = "Ignorer"; -"onboarding_thats_it" = "Presque là!"; -"onboarding_thats_it_already_signed_in" = "Commençons!"; -"onboarding_go_to_sign_in" = "L'expérience Ruuvi est meilleure lorsque vous êtes connecté. Faites-le maintenant ou continuez sans les fonctionnalités cloud."; -"onboarding_go_to_sign_in_already_signed_in" = "Commençons à mesurer !"; -"onboarding_continue" = "Suivant"; diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/ru.lproj/RuuviOnboard.strings b/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/ru.lproj/RuuviOnboard.strings deleted file mode 100644 index df53084c8..000000000 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/ru.lproj/RuuviOnboard.strings +++ /dev/null @@ -1,45 +0,0 @@ -"RuuviOnboard.Welcome.title" = "Проведите пальцем чтобы узнать, чем Ruuvi Station может помочь вам."; -"RuuviOnboard.Measure.title" = "Измеряйте параметры окружающей среды: температуру, влажность и атмосферное давление."; -"RuuviOnboard.Access.title" = "В реальном времени считывайте показатели с датчиков и просматривайте историю на графиках."; -"RuuviOnboard.Alerts.title" = "Устанавливайте лимиты значений, при превышении которых вы получите уведомление."; -"RuuviOnboard.Start.title" = "Нажмите СКАНИРОВАТЬ, чтобы найти и добавить датчики в Ruuvi Station."; -"RuuviOnboard.Start.button" = "СКАНИРОВАТЬ"; -"RuuviOnboard.Cloud.title" = "Sign in to use the full potential of the app."; -"RuuviOnboard.Cloud.subtitle" = "Claim ownership of your sensors with a free Ruuvi Cloud account."; -"RuuviOnboard.Cloud.subtitle.signed" = "Great! You already signed in!"; -"RuuviOnboard.Cloud.SignIn.title" = "Войти"; -"RuuviOnboard.Cloud.Details.title" = "Подробнее"; -"RuuviOnboard.Cloud.Benefits.title" = "Ruuvi Cloud"; -"RuuviOnboard.Cloud.Benefits.message" = "Преимущества:\\n\\n ● Название датчика, изображение фона, данные калибровки и настройки тревог будут безопасно храниться в облаке\\n\\n ● Получите доступ к датчикам через интернет (требуестся Ruuvi Gateway)\\n\\n ● Поделитесь данными датчиков с друзьями и членами семьи (требуется Ruuvi Gateway)\\n\\n ● Просматривайте до 2-х лет истории на сайте station.ruuvi.com (требуется a Ruuvi Gateway)"; -"RuuviOnboard.Cloud.Close.title" = "Закрыть"; -"RuuviOnboard.Cloud.Skip.title" = "Точно хотите пропустить вход?"; -"RuuviOnboard.Cloud.Skip.Yes.title" = "Пропустить"; -"RuuviOnboard.Cloud.Skip.GoBack.title" = "Назад"; - -// New Onboarding -"onboarding_measure_your_world" = "Measure Your World"; -"onboarding_with_ruuvi_sensors" = "Let's get to know your Ruuvi Station app."; -"onboarding_swipe_to_continue" = "Swipe to continue →"; -"onboarding_read_sensors_data" = "Read Your Ruuvi Sensors"; -"onboarding_via_bluetooth_or_cloud" = "using Bluetooth or Ruuvi Cloud"; -"onboarding_follow_measurement" = "View all sensors at a glance on your"; -"onboarding_dashboard" = "Dashboard"; -"onboarding_personalise" = "Personalise"; -"onboarding_your_sensors" = "your app with custom names and backgrounds."; -"onboarding_explore_detailed" = "Explore your measurement"; -"onboarding_history" = "History"; -"onboarding_set_custom" = "Set and customise your"; -"onboarding_alerts" = "Alerts"; -"onboarding_share_your_sensors" = "to measure together with your friends and family."; -"onboarding_sharees_can_use" = "Share Sensors"; -"onboarding_handy_widgets" = "Widgets"; -"onboarding_access_widgets" = "Bring your favorite sensors to your Home Screen and Lock Screen as"; -"onboarding_station_web" = "Ruuvi Web App"; -"onboarding_web_pros" = "Large dashboard, multi-year history, email alerts and more on"; -"onboarding_gateway_required" = "A Ruuvi Gateway router is required."; -"onboarding_skip" = "Skip"; -"onboarding_thats_it" = "Almost there!"; -"onboarding_thats_it_already_signed_in" = "Let's get started!"; -"onboarding_go_to_sign_in" = "Ruuvi experience is better when you're signed in. Do it now or continue without cloud features."; -"onboarding_go_to_sign_in_already_signed_in" = "Let's start measuring!"; -"onboarding_continue" = "Next"; diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/sv.lproj/RuuviOnboard.strings b/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/sv.lproj/RuuviOnboard.strings deleted file mode 100644 index d496039b3..000000000 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/sv.lproj/RuuviOnboard.strings +++ /dev/null @@ -1,45 +0,0 @@ -"RuuviOnboard.Welcome.title" = "Det här kan Ruuvi Station göra för dig."; -"RuuviOnboard.Measure.title" = "Mät förhållandena i din miljö: temperatur, luftfuktighet och lufttryck."; -"RuuviOnboard.Access.title" = "Visa sensordata i realtid eller granska historisk data som är lagrad på enheten."; -"RuuviOnboard.Alerts.title" = "Ställ in alarm och få notiser om dem."; -"RuuviOnboard.Start.title" = "Tryck på SCAN för att se sensorerna i närheten."; -"RuuviOnboard.Start.button" = "SKANNA"; -"RuuviOnboard.Cloud.title" = "Logga in för att använda appens fulla potential."; -"RuuviOnboard.Cloud.subtitle" = "Gör anspråk på äganderätten till dina sensorer med ett gratis Ruuvi Cloud-konto."; -"RuuviOnboard.Cloud.subtitle.signed" = "Bra! Du har redan loggat in!"; -"RuuviOnboard.Cloud.SignIn.title" = "Logga in"; -"RuuviOnboard.Cloud.Details.title" = "Detaljer"; -"RuuviOnboard.Cloud.Benefits.title" = "Ruuvi Cloud"; -"RuuviOnboard.Cloud.Benefits.message" = "Fördelar:\\n\\n ● Sensornamn, bakgrundsbilder, kalibrering och larminformation från en säker molntjänst\\n\\n ● Läs sensorinformation på distans online ( kräver Ruuvi Gateway-router)\\n\\n ● Dela sensorer med vänner och familj (kräver Ruuvi Gateway)\\n\\n ● Upp till 2 års historik från station.ruuvi.com (kräver Ruuvi Gateway)"; -"RuuviOnboard.Cloud.Close.title" = "Stäng"; -"RuuviOnboard.Cloud.Skip.title" = "Är du säker på att du vill hoppa över inloggningen?"; -"RuuviOnboard.Cloud.Skip.Yes.title" = "Ja, hoppa över"; -"RuuviOnboard.Cloud.Skip.GoBack.title" = "Gå tillbaka"; - -// New Onboarding -"onboarding_measure_your_world" = "Measure Your World"; -"onboarding_with_ruuvi_sensors" = "Lär känna din Ruuvi Station -applikation."; -"onboarding_swipe_to_continue" = "Dra för att fortsätta →"; -"onboarding_read_sensors_data" = "Läs dina Ruuvi-sensorer"; -"onboarding_via_bluetooth_or_cloud" = "med Bluetooth eller Ruuvi Cloud"; -"onboarding_follow_measurement" = "Se alla sensorer med en blick på din"; -"onboarding_dashboard" = "instrumentpanel"; -"onboarding_personalise" = "Anpassa"; -"onboarding_your_sensors" = "din app med anpassade namn och bakgrunder."; -"onboarding_explore_detailed" = "Utforska din"; -"onboarding_history" = "mäthistorik"; -"onboarding_set_custom" = "Ställ in och anpassa dina"; -"onboarding_alerts" = "varningar"; -"onboarding_share_your_sensors" = "för att mäta tillsammans med dina vänner och familj."; -"onboarding_sharees_can_use" = "Dela sensorer"; -"onboarding_handy_widgets" = "widgets"; -"onboarding_access_widgets" = "Ta med dina favoritsensorer till din startskärm och låsskärm som"; -"onboarding_station_web" = "Ruuvi webbappen"; -"onboarding_web_pros" = "Stor instrumentpanel, flerårig historik, e-postvarningar och mer på"; -"onboarding_gateway_required" = "En Ruuvi Gateway -router krävs."; -"onboarding_skip" = "Hoppa över"; -"onboarding_thats_it" = "Nästan där!"; -"onboarding_thats_it_already_signed_in" = "Låt oss börja!"; -"onboarding_go_to_sign_in" = "Ruuvi-upplevelsen är bättre när du är inloggad. Gör det nu eller fortsätt utan molnfunktioner."; -"onboarding_go_to_sign_in_already_signed_in" = "Låt oss börja mäta!"; -"onboarding_continue" = "Nästa"; From dfb868254ce4214d7830dc0e650ec6290d04fc1d Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Fri, 15 Dec 2023 20:52:43 +0200 Subject: [PATCH 48/84] Fix colors on Storyboards (#1784) * Fix RuuviColors on Storyboards Code the colors instead of using it on storyboard * menu text color * ruuvi primary color * rest colors * call style --- .../About/View/AboutViewController.swift | 10 ++++++++++ .../MenuTableEmbededViewController.swift | 12 ++++++++++++ .../View/Table/MenuTableViewController.swift | 6 ++++++ .../View/MyRuuviAccountViewController.swift | 9 +++++++++ .../Table/SettingsTableViewController.swift | 19 ++++++++++++++++++- .../ChartSettingsTableViewController.swift | 10 ++++++++++ .../View/DefaultsViewController.swift | 5 +++++ .../Table/DefaultsTableViewController.swift | 12 ++++++++++++ .../View/HeartbeatViewController.swift | 5 +++++ .../Table/HeartbeatTableViewController.swift | 10 ++++++++++ .../Table/SelectionTableViewController.swift | 10 +++++++--- .../UnitSettingsTableViewController.swift | 8 +++++++- .../ViewController/ShareViewController.swift | 12 ++++++++++++ .../OffsetCorrectionAppleViewController.swift | 14 ++++++++++++++ .../Owner/View/OwnerViewController.swift | 7 +++++++ 15 files changed, 144 insertions(+), 5 deletions(-) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/View/AboutViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/View/AboutViewController.swift index 8dbc4ac93..89fd89091 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/View/AboutViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/View/AboutViewController.swift @@ -42,9 +42,19 @@ extension AboutViewController { configureViews() setUpChangelogTapGesture() localize() + styleViews() output.viewDidLoad() } + private func styleViews() { + view.backgroundColor = RuuviColor.primary.color + versionLabel.textColor = RuuviColor.dashboardIndicator.color + addedTagsLabel.textColor = RuuviColor.dashboardIndicator.color + storedMeasurementsLabel.textColor = RuuviColor.dashboardIndicator.color + databaseSizeLable.textColor = RuuviColor.dashboardIndicator.color + aboutTextView.tintColor = RuuviColor.tintColor.color + } + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) DispatchQueue.main.async { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift index 1a8763fdb..76ed35e8c 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/View/Table/MenuTableEmbededViewController.swift @@ -31,6 +31,17 @@ extension MenuTableEmbededViewController { getMoreSensorsLabel.text = RuuviLocalization.Menu.Label.GetMoreSensors.text feedbackLabel.text = RuuviLocalization.Menu.Label.Feedback.text } + + func styleViews() { + view.backgroundColor = RuuviColor.primary.color + addANewSensorLabel.textColor = RuuviColor.menuTextColor.color + appSettingsLabel.textColor = RuuviColor.menuTextColor.color + aboutHelpLabel.textColor = RuuviColor.menuTextColor.color + whatToMeasureLabel.textColor = RuuviColor.menuTextColor.color + getMoreSensorsLabel.textColor = RuuviColor.menuTextColor.color + feedbackLabel.textColor = RuuviColor.menuTextColor.color + accountAuthLabel.textColor = RuuviColor.menuTextColor.color + } } // MARK: - View lifecycle @@ -39,6 +50,7 @@ extension MenuTableEmbededViewController { override func viewDidLoad() { super.viewDidLoad() localize() + styleViews() } override func viewWillAppear(_ animated: Bool) { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift index 93077b07a..0a932ea20 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Menu/View/Table/MenuTableViewController.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit class MenuTableViewController: UIViewController { @@ -14,6 +15,7 @@ extension MenuTableViewController { override func viewDidLoad() { super.viewDidLoad() localize() + styleViews() configureViews() } @@ -21,6 +23,10 @@ extension MenuTableViewController { super.viewWillAppear(animated) output.viewWillAppear() } + + private func styleViews() { + view.backgroundColor = RuuviColor.primary.color + } } extension MenuTableViewController { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift index 9dd7a466d..f6cb78328 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/My Ruuvi/View/MyRuuviAccountViewController.swift @@ -19,11 +19,20 @@ class MyRuuviAccountViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() + styleViews() configureViews() localize() output.viewDidLoad() } + private func styleViews() { + view.backgroundColor = RuuviColor.primary.color + loggedInLabel.textColor = RuuviColor.textColor.color + usernameLabel.textColor = RuuviColor.textColor.color + deleteAccountButton.backgroundColor = RuuviColor.orangeColor.color + signoutButton.backgroundColor = RuuviColor.tintColor.color + } + // MARK: - Button actions @IBAction func backButtonTouchUpInside(_: Any) { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift index 42187f16b..ed1e6a0f6 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/View/Table/SettingsTableViewController.swift @@ -88,7 +88,23 @@ extension SettingsTableViewController: SettingsViewInput { appearanceTitleLabel.text = RuuviLocalization.settingsAppearance alertNotificationsTitleLabel.text = RuuviLocalization.settingsAlertNotifications updateUILanguage() - tableView.reloadData() + } + + func styleViews() { + view.backgroundColor = RuuviColor.primary.color + temperatureTitleLabel.textColor = RuuviColor.menuTextColor.color + humidityTitleLabel.textColor = RuuviColor.menuTextColor.color + pressureTitleLabel.textColor = RuuviColor.menuTextColor.color + languageTitleLabel.textColor = RuuviColor.menuTextColor.color + defaultsTitleLabel.textColor = RuuviColor.menuTextColor.color + devicesTitleLabel.textColor = RuuviColor.menuTextColor.color + heartbeatTitleLabel.textColor = RuuviColor.menuTextColor.color + chartTitleLabel.textColor = RuuviColor.menuTextColor.color + ruuviCloudTitleLabel.textColor = RuuviColor.menuTextColor.color + appearanceTitleLabel.textColor = RuuviColor.menuTextColor.color + alertNotificationsTitleLabel.textColor = RuuviColor.menuTextColor.color + experimentalFunctionsLabel.textColor = RuuviColor.menuTextColor.color + languageValueLabel.textColor = RuuviColor.menuTextColor.color } func viewDidShowLanguageChangeDialog() { @@ -125,6 +141,7 @@ extension SettingsTableViewController { updateNavBarTitleFont() updateUI() localize() + styleViews() output.viewDidLoad() becomeFirstResponder() } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift index 127314a5d..f8860635f 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Chart/View/Table/ChartSettingsTableViewController.swift @@ -16,6 +16,7 @@ class ChartSettingsTableViewController: UITableViewController { super.viewDidLoad() tableView.sectionFooterHeight = UITableView.automaticDimension localize() + styleViews() } override func viewWillDisappear(_ animated: Bool) { @@ -28,6 +29,10 @@ extension ChartSettingsTableViewController: ChartSettingsViewInput { func localize() { title = RuuviLocalization.Settings.Label.chart } + + private func styleViews() { + view.backgroundColor = RuuviColor.primary.color + } } // MARK: - View lifecycle @@ -53,7 +58,9 @@ extension ChartSettingsTableViewController { let cell = tableView .dequeueReusableCell(with: ChartSettingsSwitchTableViewCell.self, for: indexPath) cell.titleLabel.text = title + cell.titleLabel.textColor = RuuviColor.menuTextColor.color cell.isOnSwitch.isOn = value + cell.isOnSwitch.thumbTintColor = RuuviColor.tintColor.color cell.delegate = self return cell case let .stepper(title, value, unitSingular, unitPlural): @@ -67,13 +74,16 @@ extension ChartSettingsTableViewController { cell.titleLabel.text = title + " " + "(" + "\(value)" + " " + unit.unitString + ")" + cell.titleLabel.textColor = RuuviColor.menuTextColor.color cell.prefix = title cell.stepper.value = Double(value) + cell.stepper.backgroundColor = RuuviColor.tintColor.color cell.delegate = self return cell case let .disclosure(title): let cell = tableView.dequeueReusableCell(with: ChartSettingsDisclosureTableViewCell.self, for: indexPath) cell.textLabel?.text = title + cell.textLabel?.textColor = RuuviColor.menuTextColor.color return cell } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift index d9926f2b8..a49a1564e 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewController.swift @@ -54,6 +54,11 @@ extension DefaultsViewController { super.viewDidLoad() configureViews() localize() + styleViews() + } + + private func styleViews() { + view.backgroundColor = RuuviColor.primary.color } override func shouldPerformSegue(withIdentifier identifier: String, sender _: Any?) -> Bool { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift index 310337645..320ea9d3b 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/Table/DefaultsTableViewController.swift @@ -33,6 +33,11 @@ extension DefaultsTableViewController { override func viewDidLoad() { super.viewDidLoad() localize() + styleViews() + } + + private func styleViews() { + view.backgroundColor = RuuviColor.primary.color } } @@ -56,7 +61,9 @@ extension DefaultsTableViewController { ) as! DefaultsPlainTableViewCell // swiftlint:enable force_cast cell.titleLabel.text = viewModel.title + cell.titleLabel.textColor = RuuviColor.menuTextColor.color cell.valueLabel.text = viewModel.value.value ?? RuuviLocalization.na + cell.valueLabel.textColor = RuuviColor.menuTextColor.color return cell case .switcher: // swiftlint:disable force_cast @@ -67,7 +74,10 @@ extension DefaultsTableViewController { ) as! DefaultsSwitchTableViewCell // swiftlint:enable force_cast cell.titleLabel.text = viewModel.title + cell.titleLabel.textColor = RuuviColor.menuTextColor.color cell.isOnSwitch.isOn = viewModel.boolean.value ?? false + cell.isOnSwitch.onTintColor = RuuviColor.switchEnabledTint.color + cell.isOnSwitch.thumbTintColor = RuuviColor.tintColor.color cell.delegate = self return cell case .stepper: @@ -105,6 +115,8 @@ extension DefaultsTableViewController { case .decimal: cell.titleLabel.text = title + " " + "(" + "\(result)" + ")" } + cell.titleLabel.textColor = RuuviColor.menuTextColor.color + cell.stepper.backgroundColor = RuuviColor.tintColor.color cell.prefix = title cell.stepper.value = Double(viewModel.integer.value.bound) cell.delegate = self diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift index 7d4fa1dad..e67e32cb8 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/HeartbeatViewController.swift @@ -42,6 +42,11 @@ extension HeartbeatViewController { super.viewDidLoad() configureViews() localize() + styleViews() + } + + private func styleViews() { + view.backgroundColor = RuuviColor.primary.color } override func shouldPerformSegue(withIdentifier identifier: String, sender _: Any?) -> Bool { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift index 2e74ef82c..0a4377f47 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Heartbeat/View/Table/HeartbeatTableViewController.swift @@ -31,6 +31,15 @@ extension HeartbeatTableViewController: HeartbeatViewInput { bgScanningIntervalValueLabel.text = RuuviLocalization.Heartbeat.Interval.All.string } } + + func styleViews() { + view.backgroundColor = RuuviColor.primary.color + bgScanningTitleLabel.textColor = RuuviColor.menuTextColor.color + bgScanningIntervalTitleLabel.textColor = RuuviColor.menuTextColor.color + bgScanningIntervalValueLabel.textColor = RuuviColor.textColor.color + bgScanningSwitch.thumbTintColor = RuuviColor.tintColor.color + bgScanningIntervalStepper.backgroundColor = RuuviColor.tintColor.color + } } // MARK: - IBActions @@ -53,6 +62,7 @@ extension HeartbeatTableViewController { bindViewModel() updateUIComponent() localize() + styleViews() } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift index 8218c875f..a6be4b58b 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Selection/View/Table/SelectionTableViewController.swift @@ -38,8 +38,9 @@ class SelectionTableViewController: UITableViewController { // MARK: - SelectionViewInput extension SelectionTableViewController: SelectionViewInput { - func localize() { - tableView.reloadData() + func styleViews() { + view.backgroundColor = RuuviColor.primary.color + descriptionTextView.textColor = RuuviColor.textColor.color } } @@ -48,7 +49,7 @@ extension SelectionTableViewController: SelectionViewInput { extension SelectionTableViewController { override func viewDidLoad() { super.viewDidLoad() - localize() + styleViews() output.viewDidLoad() updateUI() } @@ -72,6 +73,9 @@ extension SelectionTableViewController { return .init() } + cell.nameLabel.textColor = RuuviColor.textColor.color + cell.tintColor = RuuviColor.tintColor.color + if viewModel?.unitSettingsType == .accuracy, let item = item as? MeasurementAccuracyType { let titleProvider = MeasurementAccuracyTitles() diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift index 10ee6ddd4..dc9687166 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Unit Settings/View/Table/UnitSettingsTableViewController.swift @@ -60,6 +60,10 @@ extension UnitSettingsTableViewController: UnitSettingsViewInput { func localize() { tableView.reloadData() } + + private func styleViews() { + view.backgroundColor = RuuviColor.primary.color + } } // MARK: - View lifecycle @@ -68,6 +72,7 @@ extension UnitSettingsTableViewController { override func viewDidLoad() { super.viewDidLoad() localize() + styleViews() output.viewDidLoad() updateUI() } @@ -136,7 +141,8 @@ extension UnitSettingsTableViewController { cell.valueLbl.text = RuuviLocalization.na } } - + cell.titleLbl.textColor = RuuviColor.menuTextColor.color + cell.valueLbl.textColor = RuuviColor.menuTextColor.color return cell } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift index 4d5b14476..3c13f2b2a 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift @@ -54,9 +54,14 @@ class ShareViewController: UITableViewController { configureTableView() setupCustomBackButton() localize() + styleViews() output.viewDidLoad() } + private func styleViews() { + view.backgroundColor = RuuviColor.primary.color + } + // MARK: - TableView override func numberOfSections(in _: UITableView) -> Int { @@ -208,10 +213,13 @@ extension ShareViewController { } else { cell.sharingDisabledLabel.text = RuuviLocalization.networkSharingDisabled } + cell.sharingDisabledLabel.textColor = RuuviColor.textColor.color + cell.sharingDisabledLabel.tintColor = RuuviColor.tintColor.color let description = RuuviLocalization.ShareViewController.description cell.descriptionLabel.text = description.trimmingCharacters(in: .whitespacesAndNewlines) cell.descriptionLabel.textColor = RuuviColor.textColor.color + cell.descriptionLabel.tintColor = RuuviColor.tintColor.color return cell } @@ -220,6 +228,7 @@ extension ShareViewController { cell.separatorInset = UIEdgeInsets(top: 0, left: tableView.bounds.width, bottom: 0, right: 0) cell.emailTextField.placeholder = RuuviLocalization.ShareViewController.EmailTextField.placeholder cell.emailTextField.delegate = self + cell.emailTextField.textColor = RuuviColor.textColor.color return cell } @@ -227,6 +236,7 @@ extension ShareViewController { let cell = tableView.dequeueReusableCell(with: ShareSendButtonTableViewCell.self, for: indexPath) cell.sendButton.addTarget(self, action: #selector(didTapSendButton(_:)), for: .touchUpInside) cell.sendButton.setTitle(RuuviLocalization.TagSettings.Share.title, for: .normal) + cell.sendButton.tintColor = RuuviColor.tintColor.color cell.separatorInset = UIEdgeInsets(top: 0, left: tableView.bounds.width, bottom: 0, right: 0) return cell } @@ -234,6 +244,8 @@ extension ShareViewController { private func getSharedEmailCell(_ tableView: UITableView, indexPath: IndexPath) -> ShareEmailTableViewCell { let cell = tableView.dequeueReusableCell(with: ShareEmailTableViewCell.self, for: indexPath) cell.emailLabel.text = viewModel.sharedEmails.value?[indexPath.row] + cell.emailLabel.textColor = RuuviColor.textColor.color + cell.unshareButton.tintColor = RuuviColor.textColor.color cell.delegate = self cell.separatorInset = UIEdgeInsets(top: 0, left: tableView.bounds.width, bottom: 0, right: 0) return cell diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift index 8c9a6afb8..a09096e17 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift @@ -47,6 +47,7 @@ class OffsetCorrectionAppleViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() localize() + styleViews() timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { [weak self] _ in if let updateAt = self?.updatedAt { self?.originalValueUpdateTimeLabel.text = "(\(updateAt.ruuviAgo()))" @@ -142,6 +143,19 @@ class OffsetCorrectionAppleViewController: UIViewController { } } } + + private func styleViews() { + view.backgroundColor = RuuviColor.primary.color + correctedValueTitle.textColor = RuuviColor.textColor.color + originalValueTitle.textColor = RuuviColor.textColor.color + originalValueLabel.textColor = RuuviColor.textColor.color + originalValueUpdateTimeLabel.textColor = RuuviColor.textColor.color + correctedValueLabel.textColor = RuuviColor.textColor.color + offsetValueLabel.textColor = RuuviColor.textColor.color + descriptionTextView.tintColor = RuuviColor.tintColor.color + calibrateButton.backgroundColor = RuuviColor.tintColor.color + clearButton.backgroundColor = RuuviColor.tintColor.color + } } extension OffsetCorrectionAppleViewController: OffsetCorrectionViewInput { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift index ac7068648..4379903da 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift @@ -60,8 +60,15 @@ final class OwnerViewController: UIViewController { setUpCustomBackButton() setUpCloudHistoryContentView() localize() + styleViews() output.viewDidTriggerFirmwareUpdateDialog() } + + private func styleViews() { + view.backgroundColor = RuuviColor.primary.color + claimOwnershipDescriptionLabel.textColor = RuuviColor.textColor.color + claimOwnershipButton.backgroundColor = RuuviColor.tintColor.color + } } extension OwnerViewController: OwnerViewInput { From 7872ff51fdcc3be03107339d85e8210736c28c2a Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Fri, 15 Dec 2023 21:07:50 +0200 Subject: [PATCH 49/84] Fix dependencies of RuuviPresenters (#1786) Fixes deps. --- Common/RuuviPresenters/target.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Common/RuuviPresenters/target.yml b/Common/RuuviPresenters/target.yml index ab973ecd8..211604c4c 100644 --- a/Common/RuuviPresenters/target.yml +++ b/Common/RuuviPresenters/target.yml @@ -6,3 +6,5 @@ targets: sources: - path: Sources name: Presenters + dependencies: + - target: RuuviLocalization From b34937c54bce5a9ef1bc3d718d2f4b9b4734f37d Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 16 Dec 2023 00:49:19 +0200 Subject: [PATCH 50/84] Remove Realm dependency (#1788) * Remove Realm dependency Eliminates dependency on RealmSwift * fix linker * fix warnings [linter] --- Apps/RuuviStation/Intents/target.yml | 4 - .../NotificationService/target.yml | 4 +- .../Classes/Application/AppAssembly.swift | 36 +- .../Classes/Application/AppDelegate.swift | 2 - .../About/Assembly/AboutConfigurator.swift | 1 - .../About/Presenter/AboutPresenter.swift | 12 +- .../Assembly/DashboardModuleFactory.swift | 1 - .../Home/Presenter/DashboardPresenter.swift | 1 - .../Table/SettingsTableConfigurator.swift | 1 - .../Module/Presenter/SettingsPresenter.swift | 1 - .../Submodules/DFU/DFUModuleFactory.swift | 2 - .../DFU/Presenter/DFUPresenter.swift | 4 - .../Submodules/DFU/View/DFUViewModel.swift | 163 +--- .../Sources/Extensions/Errors/RUError.swift | 3 - ...RuuviPersistenceError+LocalizedError.swift | 2 - Apps/RuuviStation/Widgets/target.yml | 4 - Apps/RuuviStation/target.yml | 7 +- Modules/RuuviOnboard/target.yml | 1 + .../Sources/RuuviContext/RealmContext.swift | 11 - .../RealmContextFactoryImpl.swift | 7 - .../RuuviContextRealm/RealmContextImpl.swift | 13 - Packages/RuuviContext/target.yml | 3 - Packages/RuuviDFU/target.yml | 1 + .../RuuviTagPropertiesDaemonBTKit.swift | 54 -- .../RuuviMigrationFactoryImpl.swift | 9 - .../toSQLite/MigrationManagerToSQLite.swift | 79 -- .../toVIPER/MigrationManagerToVIPER.swift | 161 ---- Packages/RuuviMigration/target.yml | 3 - .../RuuviTagDataRealm+Extension.swift | 90 --- ...uviTagDataRealm+RuuviTagSensorRecord.swift | 26 - .../RuuviTagDataRealm.swift | 102 --- .../RuuviTagLatestDataRealm+Extension.swift | 90 --- ...LatestDataRealm+RuuviTagSensorRecord.swift | 26 - .../RuuviTagLatestDataRealm.swift | 102 --- .../RuuviTagRealm+RuuviTagSensor.swift | 60 -- .../RuuviOntologyRealm/RuuviTagRealm.swift | 48 -- .../RuuviTagRealmProtocol.swift | 12 - .../SensorSettingsRealm.swift | 49 -- Packages/RuuviOntology/target.yml | 3 - .../RuuviPersistenceError.swift | 1 - .../RuuviPersistenceRealm.swift | 753 ------------------ Packages/RuuviPersistence/target.yml | 3 - .../Sources/RuuviPool/RuuviPoolFactory.swift | 1 - .../RuuviPoolCoordinator.swift | 68 +- .../RuuviPoolFactoryCoordinator.swift | 2 - .../RuuviReactor/RuuviReactorFactory.swift | 4 +- .../RuuviTagLastRecordSubjectCombine.swift | 28 +- .../RuuviTagLatestRecordSubjectCombine.swift | 28 +- .../RuuviTagRecordSubjectCombine.swift | 35 +- .../RuuviTagSubjectCombine.swift | 42 +- .../SensorSettingsCombine.swift | 48 +- .../RuuviReactorFactoryImpl.swift | 8 +- .../RuuviReactorImpl/RuuviReactorImpl.swift | 54 +- Packages/RuuviReactor/target.yml | 3 - .../Sources/RuuviStorage/RuuviStorage.swift | 2 +- .../RuuviStorageCoordinator.swift | 65 +- .../RuuviStorageFactoryCoordinator.swift | 4 +- project.yml | 19 +- 58 files changed, 76 insertions(+), 2290 deletions(-) delete mode 100644 Packages/RuuviContext/Sources/RuuviContext/RealmContext.swift delete mode 100644 Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextFactoryImpl.swift delete mode 100644 Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextImpl.swift delete mode 100644 Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift delete mode 100644 Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift delete mode 100644 Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+Extension.swift delete mode 100644 Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+RuuviTagSensorRecord.swift delete mode 100644 Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm.swift delete mode 100644 Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+Extension.swift delete mode 100644 Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+RuuviTagSensorRecord.swift delete mode 100644 Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm.swift delete mode 100644 Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm+RuuviTagSensor.swift delete mode 100644 Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm.swift delete mode 100644 Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealmProtocol.swift delete mode 100644 Packages/RuuviOntology/Sources/RuuviOntologyRealm/SensorSettingsRealm.swift delete mode 100644 Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift diff --git a/Apps/RuuviStation/Intents/target.yml b/Apps/RuuviStation/Intents/target.yml index b9118f41b..513f57399 100644 --- a/Apps/RuuviStation/Intents/target.yml +++ b/Apps/RuuviStation/Intents/target.yml @@ -27,7 +27,6 @@ targets: PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.intents" Debug: CODE_SIGN_STYLE: Automatic - OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries Release: EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" CODE_SIGN_IDENTITY: "iPhone Distribution" @@ -50,10 +49,7 @@ targets: - package: Future - package: GRDB - package: Humidity - - package: Realm - package: KeychainAccess - - package: Realm - product: RealmSwift - target: RuuviUser embed: true - target: RuuviCloud diff --git a/Apps/RuuviStation/NotificationService/target.yml b/Apps/RuuviStation/NotificationService/target.yml index 9e36cde40..78a600716 100644 --- a/Apps/RuuviStation/NotificationService/target.yml +++ b/Apps/RuuviStation/NotificationService/target.yml @@ -21,13 +21,15 @@ targets: Alpha: CODE_SIGN_IDENTITY: "iPhone Distribution" PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.pnservice" + # OTHER_LDFLAGS: -ld_classic Debug: CODE_SIGN_STYLE: Automatic - OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries + # OTHER_LDFLAGS: -ld_classic Release: EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" CODE_SIGN_IDENTITY: "iPhone Distribution" PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.pnservice" + # OTHER_LDFLAGS: -ld_classic sources: - path: Sources name: NotificationService diff --git a/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift b/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift index 841ff4376..5a94d3dda 100644 --- a/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift +++ b/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift @@ -54,16 +54,9 @@ private final class DfuAssembly: Assembly { private final class MigrationAssembly: Assembly { func assemble(container: Container) { - container.register(RuuviMigration.self, name: "realm") { r in - let localImages = r.resolve(RuuviLocalImages.self)! - let settings = r.resolve(RuuviLocalSettings.self)! - return MigrationManagerToVIPER(localImages: localImages, settings: settings) - } - container.register(RuuviMigrationFactory.self) { r in let settings = r.resolve(RuuviLocalSettings.self)! let idPersistence = r.resolve(RuuviLocalIDs.self)! - let realmContext = r.resolve(RealmContext.self)! let ruuviPool = r.resolve(RuuviPool.self)! let ruuviStorage = r.resolve(RuuviStorage.self)! let ruuviAlertService = r.resolve(RuuviServiceAlert.self)! @@ -71,7 +64,6 @@ private final class MigrationAssembly: Assembly { return RuuviMigrationFactoryImpl( settings: settings, idPersistence: idPersistence, - realmContext: realmContext, ruuviPool: ruuviPool, ruuviStorage: ruuviStorage, ruuviAlertService: ruuviAlertService, @@ -84,16 +76,6 @@ private final class MigrationAssembly: Assembly { private final class PersistenceAssembly: Assembly { // swiftlint:disable:next function_body_length func assemble(container: Container) { - container.register(RealmContextFactory.self) { _ in - let factory = RealmContextFactoryImpl() - return factory - }.inObjectScope(.container) - - container.register(RealmContext.self) { r in - let factory = r.resolve(RealmContextFactory.self)! - return factory.create() - }.inObjectScope(.container) - container.register(RuuviLocalConnections.self) { r in let factory = r.resolve(RuuviLocalFactory.self)! return factory.createLocalConnections() @@ -115,14 +97,12 @@ private final class PersistenceAssembly: Assembly { container.register(RuuviPool.self) { r in let factory = r.resolve(RuuviPoolFactory.self)! - let realm = r.resolve(RuuviPersistence.self, name: "realm")! let sqlite = r.resolve(RuuviPersistence.self, name: "sqlite")! let localIDs = r.resolve(RuuviLocalIDs.self)! let localSettings = r.resolve(RuuviLocalSettings.self)! let localConnections = r.resolve(RuuviLocalConnections.self)! return factory.create( sqlite: sqlite, - realm: realm, idPersistence: localIDs, settings: localSettings, connectionPersistence: localConnections @@ -136,14 +116,10 @@ private final class PersistenceAssembly: Assembly { container.register(RuuviReactor.self) { r in let factory = r.resolve(RuuviReactorFactory.self)! let sqliteContext = r.resolve(SQLiteContext.self)! - let realmContext = r.resolve(RealmContext.self)! let sqltePersistence = r.resolve(RuuviPersistence.self, name: "sqlite")! - let realmPersistence = r.resolve(RuuviPersistence.self, name: "realm")! return factory.create( sqliteContext: sqliteContext, - realmContext: realmContext, - sqlitePersistence: sqltePersistence, - realmPersistence: realmPersistence + sqlitePersistence: sqltePersistence ) }.inObjectScope(.container) @@ -152,11 +128,6 @@ private final class PersistenceAssembly: Assembly { return factory } - container.register(RuuviPersistence.self, name: "realm") { r in - let context = r.resolve(RealmContext.self)! - return RuuviPersistenceRealm(context: context) - }.inObjectScope(.container) - container.register(RuuviPersistence.self, name: "sqlite") { r in let context = r.resolve(SQLiteContext.self)! return RuuviPersistenceSQLite(context: context) @@ -165,8 +136,7 @@ private final class PersistenceAssembly: Assembly { container.register(RuuviStorage.self) { r in let factory = r.resolve(RuuviStorageFactory.self)! let sqlite = r.resolve(RuuviPersistence.self, name: "sqlite")! - let realm = r.resolve(RuuviPersistence.self, name: "realm")! - return factory.create(realm: realm, sqlite: sqlite) + return factory.create(sqlite: sqlite) }.inObjectScope(.container) container.register(RuuviLocalFactory.self) { _ in @@ -294,14 +264,12 @@ private final class DaemonAssembly: Assembly { let ruuviPool = r.resolve(RuuviPool.self)! let foreground = r.resolve(BTForeground.self)! let idPersistence = r.resolve(RuuviLocalIDs.self)! - let realmPersistence = r.resolve(RuuviPersistence.self, name: "realm")! let sqiltePersistence = r.resolve(RuuviPersistence.self, name: "sqlite")! let daemon = RuuviTagPropertiesDaemonBTKit( ruuviPool: ruuviPool, ruuviReactor: ruuviReactor, foreground: foreground, idPersistence: idPersistence, - realmPersistence: realmPersistence, sqiltePersistence: sqiltePersistence ) return daemon diff --git a/Apps/RuuviStation/Sources/Classes/Application/AppDelegate.swift b/Apps/RuuviStation/Sources/Classes/Application/AppDelegate.swift index fecd4b110..3db3614a8 100644 --- a/Apps/RuuviStation/Sources/Classes/Application/AppDelegate.swift +++ b/Apps/RuuviStation/Sources/Classes/Application/AppDelegate.swift @@ -43,8 +43,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { featureToggleService.fetchFeatureToggles() // the order is important - r.resolve(RuuviMigration.self, name: "realm")? - .migrateIfNeeded() r.resolve(SQLiteContext.self)? .database .migrateIfNeeded() diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Assembly/AboutConfigurator.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Assembly/AboutConfigurator.swift index 85bda76f2..67965dd4a 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Assembly/AboutConfigurator.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Assembly/AboutConfigurator.swift @@ -12,7 +12,6 @@ class AboutConfigurator { presenter.view = view presenter.router = router presenter.ruuviStorage = r.resolve(RuuviStorage.self) - presenter.realmContext = r.resolve(RealmContext.self) presenter.sqliteContext = r.resolve(SQLiteContext.self) view.output = presenter } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift index 0a4d77cea..b67034fef 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/About/Presenter/AboutPresenter.swift @@ -8,7 +8,6 @@ final class AboutPresenter: AboutModuleInput { weak var view: AboutViewInput! var router: AboutRouterInput! var ruuviStorage: RuuviStorage! - var realmContext: RealmContext! var sqliteContext: SQLiteContext! private var viewModel: AboutViewModel { @@ -102,21 +101,12 @@ extension AboutPresenter { } private func obtainDatabaseSize() { - let realmSize = getRealmFileSize() let sqliteSize = getSQLiteFileSize() - let dbSize = ByteCountFormatter().string(fromByteCount: realmSize + sqliteSize) + let dbSize = ByteCountFormatter().string(fromByteCount: sqliteSize) let dbSizeString = RuuviLocalization.About.DatabaseSize.text(dbSize) viewModel.databaseSize.value = dbSizeString } - func getRealmFileSize() -> Int64 { - guard let realmPath = realmContext.main.configuration.fileURL?.relativePath - else { - return 0 - } - return fileSize(at: realmPath) - } - func getSQLiteFileSize() -> Int64 { fileSize(at: sqliteContext.database.dbPath) } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift index 5b8a80212..1acdf1d85 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Assembly/DashboardModuleFactory.swift @@ -29,7 +29,6 @@ final class DashboardModuleFactoryImpl: DashboardModuleFactory { let presenter = DashboardPresenter() presenter.router = router presenter.view = view - presenter.realmContext = r.resolve(RealmContext.self) presenter.errorPresenter = r.resolve(ErrorPresenter.self) presenter.settings = r.resolve(RuuviLocalSettings.self) presenter.foreground = r.resolve(BTForeground.self) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift index 43a7a2b1c..b7e738b7b 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift @@ -23,7 +23,6 @@ class DashboardPresenter: DashboardModuleInput { weak var view: DashboardViewInput? var router: DashboardRouterInput! var interactor: DashboardInteractorInput! - var realmContext: RealmContext! var errorPresenter: ErrorPresenter! var settings: RuuviLocalSettings! var foreground: BTForeground! diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableConfigurator.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableConfigurator.swift index 3ea9c49f2..1c609a79d 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableConfigurator.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Assembly/Table/SettingsTableConfigurator.swift @@ -21,7 +21,6 @@ class SettingsTableConfigurator { presenter.ruuviReactor = r.resolve(RuuviReactor.self) presenter.errorPresenter = r.resolve(ErrorPresenter.self) presenter.alertService = r.resolve(RuuviServiceAlert.self) - presenter.realmContext = r.resolve(RealmContext.self) presenter.featureToggleService = r.resolve(FeatureToggleService.self) presenter.ruuviAppSettingsService = r.resolve(RuuviServiceAppSettings.self) presenter.ruuviUser = r.resolve(RuuviUser.self) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift index 8cd8f70ea..7b107012d 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Module/Presenter/SettingsPresenter.swift @@ -17,7 +17,6 @@ class SettingsPresenter: SettingsModuleInput { var errorPresenter: ErrorPresenter! var ruuviReactor: RuuviReactor! var alertService: RuuviServiceAlert! - var realmContext: RealmContext! var featureToggleService: FeatureToggleService! var ruuviAppSettingsService: RuuviServiceAppSettings! var ruuviUser: RuuviUser! diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/DFUModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/DFUModuleFactory.swift index 76880f197..d22327f78 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/DFUModuleFactory.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/DFUModuleFactory.swift @@ -21,7 +21,6 @@ final class DFUModuleFactoryImpl: DFUModuleFactory { interactor.background = r.resolve(BTBackground.self) let foreground = r.resolve(BTForeground.self)! let idPersistence = r.resolve(RuuviLocalIDs.self)! - let realmPersistence = r.resolve(RuuviPersistence.self, name: "realm")! let sqiltePersistence = r.resolve(RuuviPersistence.self, name: "sqlite")! let ruuviPool = r.resolve(RuuviPool.self)! let ruuviStorage = r.resolve(RuuviStorage.self)! @@ -33,7 +32,6 @@ final class DFUModuleFactoryImpl: DFUModuleFactory { ruuviTag: ruuviTag, foreground: foreground, idPersistence: idPersistence, - realmPersistence: realmPersistence, sqiltePersistence: sqiltePersistence, ruuviPool: ruuviPool, ruuviStorage: ruuviStorage, diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift index 7957f59fc..4e625e42e 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift @@ -26,7 +26,6 @@ final class DFUPresenter: DFUModuleInput { private let interactor: DFUInteractorInput private let foreground: BTForeground! private let idPersistence: RuuviLocalIDs - private let realmPersistence: RuuviPersistence private let sqiltePersistence: RuuviPersistence private let ruuviTag: RuuviTagSensor private let ruuviPool: RuuviPool @@ -40,7 +39,6 @@ final class DFUPresenter: DFUModuleInput { ruuviTag: RuuviTagSensor, foreground: BTForeground, idPersistence: RuuviLocalIDs, - realmPersistence: RuuviPersistence, sqiltePersistence: RuuviPersistence, ruuviPool: RuuviPool, ruuviStorage: RuuviStorage, @@ -51,7 +49,6 @@ final class DFUPresenter: DFUModuleInput { self.interactor = interactor self.foreground = foreground self.idPersistence = idPersistence - self.realmPersistence = realmPersistence self.sqiltePersistence = sqiltePersistence self.ruuviTag = ruuviTag self.ruuviPool = ruuviPool @@ -63,7 +60,6 @@ final class DFUPresenter: DFUModuleInput { interactor: interactor, foreground: foreground, idPersistence: idPersistence, - realmPersistence: realmPersistence, sqiltePersistence: sqiltePersistence, ruuviTag: ruuviTag, ruuviPool: ruuviPool, diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift index 6b0fecf59..dbd4243e3 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift @@ -11,7 +11,6 @@ import RuuviPool import RuuviPresenters import RuuviStorage -// swiftlint:disable:next type_body_length final class DFUViewModel: ObservableObject { @Published private(set) var state: State = .idle @Published var downloadProgress: Double = 0 @@ -23,7 +22,6 @@ final class DFUViewModel: ObservableObject { private let interactor: DFUInteractorInput private let foreground: BTForeground! private let idPersistence: RuuviLocalIDs - private let realmPersistence: RuuviPersistence private let sqiltePersistence: RuuviPersistence private let ruuviTag: RuuviTagSensor private let ruuviPool: RuuviPool @@ -55,7 +53,6 @@ final class DFUViewModel: ObservableObject { interactor: DFUInteractorInput, foreground: BTForeground, idPersistence: RuuviLocalIDs, - realmPersistence: RuuviPersistence, sqiltePersistence: RuuviPersistence, ruuviTag: RuuviTagSensor, ruuviPool: RuuviPool, @@ -67,7 +64,6 @@ final class DFUViewModel: ObservableObject { self.interactor = interactor self.foreground = foreground self.idPersistence = idPersistence - self.realmPersistence = realmPersistence self.sqiltePersistence = sqiltePersistence self.ruuviTag = ruuviTag self.ruuviPool = ruuviPool @@ -111,9 +107,6 @@ final class DFUViewModel: ObservableObject { func storeUpdatedFirmware(currentRelease: CurrentRelease?) { guard ruuviTag.luid != nil else { return } - // If the tag is stored on realm then migration needed - // Usually tags without macId are stored in the realm database - // For tags with macId don't need migration if ruuviTag.macId != nil { guard let currentRelease else { @@ -129,9 +122,7 @@ final class DFUViewModel: ObservableObject { self?.isLoading = false }) } else { - isLoading = true - propertiesDaemon.stop() - startObserving() + assertionFailure() } } @@ -147,158 +138,6 @@ final class DFUViewModel: ObservableObject { .with(firmwareVersion: currentRelease.version)) } - private func startObserving() { - guard let luid = ruuviTag.luid - else { - isLoading = false - return - } - ruuviTagObserveToken?.invalidate() - ruuviTagObserveToken = foreground.observe( - self, - uuid: luid.value, - options: [.callbackQueue(.untouch)] - ) { - [weak self] _, device in - guard let sSelf = self else { return } - if let tag = device.ruuvi?.tag { - guard !sSelf.isMigrating - else { - return - } - sSelf.ruuviTagObserveToken?.invalidate() - sSelf.isMigrating = true - let pair = RuuviTagPropertiesDaemonPair(ruuviTag: sSelf.ruuviTag.any, device: tag) - sSelf.tryToMigrate(pair: pair) - } - } - } - - // MARK: - Migration starts - - @objc private func tryToMigrate(pair: RuuviTagPropertiesDaemonPair) { - if let mac = pair.device.mac { - moveTagToSqlite(mac: mac.mac, pair: pair) - } - } - - /// This method creates the updated instance of the Ruuvi Tag after firmware update. - private func moveTagToSqlite( - mac: MACIdentifier, - pair: RuuviTagPropertiesDaemonPair - ) { - sqiltePersistence.create( - pair.ruuviTag - .with(macId: mac) - .with(isConnectable: true) - .with(version: pair.device.version) - .with(isOwner: true) - ).on(success: { [weak self] _ in - self?.moveLatestRecordToSqlite(mac: mac, pair: pair) - }, failure: { [weak self] _ in - self?.notifyMigrationError() - }) - } - - /// This method fetches the latest record from the Realm and creates the same record to SQLite. - /// If there's no record move to the next step. - private func moveLatestRecordToSqlite( - mac: MACIdentifier, - pair: RuuviTagPropertiesDaemonPair - ) { - realmPersistence.readLatest(pair.ruuviTag).on(success: { [weak self] record in - // If there's no record move to next action - guard let record - else { - self?.moveRecordsHistoryToSqlite(mac: mac, pair: pair) - return - } - self?.sqiltePersistence.createLast(record.with(macId: mac)).on(success: { [weak self] _ in - self?.moveRecordsHistoryToSqlite(mac: mac, pair: pair) - }, failure: { [weak self] _ in - self?.notifyMigrationError() - }) - }, failure: { [weak self] _ in - self?.notifyMigrationError() - }) - } - - /// This method fetches the all the records from the Realm and creates the same records to SQLite. - /// If there are no records move to the next step. - private func moveRecordsHistoryToSqlite( - mac: MACIdentifier, - pair: RuuviTagPropertiesDaemonPair - ) { - realmPersistence.readAll(pair.device.uuid).on(success: { [weak self] realmRecords in - guard realmRecords.count > 0 - else { - self?.moveSettingsToSqlite(mac: mac, pair: pair) - return - } - let records = realmRecords.map { $0.with(macId: mac) } - self?.sqiltePersistence.create(records).on(success: { _ in - self?.idPersistence.set(mac: mac, for: pair.device.uuid.luid) - self?.moveSettingsToSqlite(mac: mac, pair: pair) - }, failure: { [weak self] _ in - self?.notifyMigrationError() - }) - }, failure: { [weak self] _ in - self?.notifyMigrationError() - }) - } - - /// This method fetches the sensor settings from the Realm and creates the same sensor settings record to SQLite. - /// If there's no record move to the next step. - private func moveSettingsToSqlite( - mac: MACIdentifier, - pair: RuuviTagPropertiesDaemonPair - ) { - realmPersistence.readSensorSettings(pair.ruuviTag.withoutMac()) - .on(success: { [weak self] sensorSettings in - if let withMacSettings = sensorSettings?.with(macId: mac) { - self?.sqiltePersistence.save(sensorSettings: withMacSettings) - .on(success: { _ in - self?.deleteRealmRecords(pair: pair) - }, failure: { [weak self] _ in - self?.notifyMigrationError() - }) - } else { - self?.deleteRealmRecords(pair: pair) - } - }, failure: { [weak self] _ in - self?.notifyMigrationError() - }) - } - - /// Delete all the records related to the tag on RealmDB. - /// If these delete operations are not completed return migration error because these redundant data - /// will cause unexpected behaviour. - private func deleteRealmRecords(pair: RuuviTagPropertiesDaemonPair) { - realmPersistence.deleteAllRecords(pair.device.uuid).on(success: { [weak self] _ in - self?.realmPersistence.deleteLatest(pair.device.uuid).on(success: { _ in - self?.realmPersistence.delete(pair.ruuviTag.withoutMac()).on(success: { _ in - self?.realmPersistence.deleteOffsetCorrection(ruuviTag: - pair.ruuviTag.withoutMac()).on(completion: { - self?.isMigrating = false - self?.isLoading = false - }) - }, failure: { [weak self] _ in - self?.notifyMigrationError() - }) - }, failure: { [weak self] _ in - self?.notifyMigrationError() - }) - }, failure: { [weak self] _ in - self?.notifyMigrationError() - }) - } - - private func notifyMigrationError() { - isMigrating = false - isLoading = false - isMigrationFailed = true - } - // Migration ends func checkBatteryState(completion: @escaping (Bool) -> Void) { diff --git a/Apps/RuuviStation/Sources/Extensions/Errors/RUError.swift b/Apps/RuuviStation/Sources/Extensions/Errors/RUError.swift index 19f152ed1..5a6d296a5 100644 --- a/Apps/RuuviStation/Sources/Extensions/Errors/RUError.swift +++ b/Apps/RuuviStation/Sources/Extensions/Errors/RUError.swift @@ -142,7 +142,6 @@ enum UnexpectedError: Error { case failedToFindRuuviTag case failedToFindLogsForTheTag case viewModelUUIDIsNil - case attemptToReadDataFromRealmWithoutLUID case failedToFindOrGenerateBackgroundImage case bothLuidAndMacAreNil } @@ -162,8 +161,6 @@ extension UnexpectedError: LocalizedError { RuuviLocalization.UnexpectedError.failedToFindLogsForTheTag case .viewModelUUIDIsNil: RuuviLocalization.UnexpectedError.viewModelUUIDIsNil - case .attemptToReadDataFromRealmWithoutLUID: - RuuviLocalization.UnexpectedError.attemptToReadDataFromRealmWithoutLUID case .failedToFindOrGenerateBackgroundImage: RuuviLocalization.UnexpectedError.failedToFindOrGenerateBackgroundImage case .bothLuidAndMacAreNil: diff --git a/Apps/RuuviStation/Sources/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift b/Apps/RuuviStation/Sources/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift index 52fcfc5ae..bae74bf85 100644 --- a/Apps/RuuviStation/Sources/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift +++ b/Apps/RuuviStation/Sources/Extensions/Errors/RuuviPersistenceError+LocalizedError.swift @@ -7,8 +7,6 @@ extension RuuviPersistenceError: LocalizedError { switch self { case let .grdb(error): error.localizedDescription - case let .realm(error): - error.localizedDescription case .failedToFindRuuviTag: RuuviLocalization.RuuviPersistenceError.failedToFindRuuviTag } diff --git a/Apps/RuuviStation/Widgets/target.yml b/Apps/RuuviStation/Widgets/target.yml index e4a7f3b6a..c8684c466 100644 --- a/Apps/RuuviStation/Widgets/target.yml +++ b/Apps/RuuviStation/Widgets/target.yml @@ -23,7 +23,6 @@ targets: PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.widgets" Debug: CODE_SIGN_STYLE: Automatic - OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries Release: CODE_SIGN_IDENTITY: "iPhone Distribution" PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station.widgets" @@ -43,10 +42,7 @@ targets: - package: Future - package: GRDB - package: Humidity - - package: Realm - package: KeychainAccess - - package: Realm - product: RealmSwift - target: RuuviUser embed: true - target: RuuviCloud diff --git a/Apps/RuuviStation/target.yml b/Apps/RuuviStation/target.yml index c1a2e69df..3995585c7 100644 --- a/Apps/RuuviStation/target.yml +++ b/Apps/RuuviStation/target.yml @@ -28,9 +28,6 @@ targets: - package: KeychainAccess - package: Humidity - package: Future - - package: Realm - - package: Realm - product: RealmSwift - package: FLEX - target: RuuviAnalytics - target: RuuviCloud @@ -95,13 +92,15 @@ targets: Alpha: CODE_SIGN_IDENTITY: "iPhone Distribution" PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station" + OTHER_LDFLAGS: -ld_classic Debug: CODE_SIGN_STYLE: Automatic - OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries + OTHER_LDFLAGS: -ld_classic Release: EXCLUDED_SOURCE_FILE_NAMES: "FLEX*" CODE_SIGN_IDENTITY: "iPhone Distribution" PROVISIONING_PROFILE_SPECIFIER: "match AdHoc com.ruuvi.station" + OTHER_LDFLAGS: -ld_classic postCompileScripts: - path: ../../scripts/build/lint.sh name: Lint diff --git a/Modules/RuuviOnboard/target.yml b/Modules/RuuviOnboard/target.yml index 498b7e522..bec6a0ada 100644 --- a/Modules/RuuviOnboard/target.yml +++ b/Modules/RuuviOnboard/target.yml @@ -8,3 +8,4 @@ targets: - Module dependencies: - target: RuuviUser + - target: RuuviLocalization diff --git a/Packages/RuuviContext/Sources/RuuviContext/RealmContext.swift b/Packages/RuuviContext/Sources/RuuviContext/RealmContext.swift deleted file mode 100644 index 5fde7ecd5..000000000 --- a/Packages/RuuviContext/Sources/RuuviContext/RealmContext.swift +++ /dev/null @@ -1,11 +0,0 @@ -import RealmSwift - -public protocol RealmContext { - var bg: Realm! { get } - var main: Realm { get } - var bgWorker: Worker { get } -} - -public protocol RealmContextFactory { - func create() -> RealmContext -} diff --git a/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextFactoryImpl.swift b/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextFactoryImpl.swift deleted file mode 100644 index 6dd330878..000000000 --- a/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextFactoryImpl.swift +++ /dev/null @@ -1,7 +0,0 @@ -public final class RealmContextFactoryImpl: RealmContextFactory { - public init() {} - - public func create() -> RealmContext { - RealmContextImpl() - } -} diff --git a/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextImpl.swift b/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextImpl.swift deleted file mode 100644 index 4dfa6f5c3..000000000 --- a/Packages/RuuviContext/Sources/RuuviContextRealm/RealmContextImpl.swift +++ /dev/null @@ -1,13 +0,0 @@ -import RealmSwift - -class RealmContextImpl: RealmContext { - var main: Realm = try! Realm() - var bg: Realm! - var bgWorker: Worker = .init() - - init() { - bgWorker.enqueue { - self.bg = try! Realm() - } - } -} diff --git a/Packages/RuuviContext/target.yml b/Packages/RuuviContext/target.yml index aa7d0c8fa..146bb2151 100644 --- a/Packages/RuuviContext/target.yml +++ b/Packages/RuuviContext/target.yml @@ -11,8 +11,5 @@ targets: - path: Sources name: Context dependencies: - - package: Realm - - package: Realm - product: RealmSwift - package: GRDB - target: RuuviOntology diff --git a/Packages/RuuviDFU/target.yml b/Packages/RuuviDFU/target.yml index 20cd7d52d..747227eb2 100644 --- a/Packages/RuuviDFU/target.yml +++ b/Packages/RuuviDFU/target.yml @@ -8,3 +8,4 @@ targets: name: DFU dependencies: - package: NordicDFU + - target: RuuviLocalization diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift index 085918b73..3c88f654e 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift @@ -6,13 +6,11 @@ import RuuviPersistence import RuuviPool import RuuviReactor -// swiftlint:disable:next type_body_length public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPropertiesDaemon { private let ruuviPool: RuuviPool private let ruuviReactor: RuuviReactor private let foreground: BTForeground private let idPersistence: RuuviLocalIDs - private let realmPersistence: RuuviPersistence private let sqiltePersistence: RuuviPersistence public init( @@ -20,14 +18,12 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro ruuviReactor: RuuviReactor, foreground: BTForeground, idPersistence: RuuviLocalIDs, - realmPersistence: RuuviPersistence, sqiltePersistence: RuuviPersistence ) { self.ruuviPool = ruuviPool self.ruuviReactor = ruuviReactor self.foreground = foreground self.idPersistence = idPersistence - self.realmPersistence = realmPersistence self.sqiltePersistence = sqiltePersistence super.init() } @@ -36,7 +32,6 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro private var observeTokens = [ObservationToken]() private var scanTokens = [ObservationToken]() private var ruuviTags = [AnyRuuviTagSensor]() - private var isTransitioningFromRealmToSQLite = false private var processingUUIDs = Set() @objc private class RuuviTagPropertiesDaemonPair: NSObject { @@ -142,7 +137,6 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro } } - // swiftlint:disable:next function_body_length @objc private func tryToUpdate(pair: RuuviTagPropertiesDaemonPair) { if let mac = pair.device.mac, mac != pair.ruuviTag.macId?.value { // this is the case when data format 3 tag (2.5.9) changes format @@ -155,54 +149,6 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro .on(failure: { [weak self] error in self?.post(error: .ruuviPool(error)) }) - } else { - isTransitioningFromRealmToSQLite = true - // now we need to remove the tag from Realm and add it to SQLite - sqiltePersistence.create( - pair.ruuviTag - .with(macId: mac.mac) - .with(isConnectable: true) - .with(version: pair.device.version) - .with(isOwner: true) - ).on(success: { [weak self] _ in - self?.realmPersistence.readAll(pair.device.uuid).on(success: { realmRecords in - let records = realmRecords.map { $0.with(macId: mac.mac) } - self?.sqiltePersistence.create(records).on(success: { _ in - self?.realmPersistence.deleteAllRecords(pair.device.uuid).on(success: { _ in - self?.idPersistence.set(mac: mac.mac, for: pair.device.uuid.luid) - self?.realmPersistence.delete(pair.ruuviTag.withoutMac()) - .on(success: { [weak self] _ in - self?.realmPersistence.readSensorSettings(pair.ruuviTag.withoutMac()) - .on(success: { [weak self] sensorSettings in - if let withMacSettings = sensorSettings?.with(macId: mac.mac) { - self?.sqiltePersistence.save(sensorSettings: withMacSettings) - .on(success: { _ in - self?.isTransitioningFromRealmToSQLite = false - }, failure: { error in - self?.post(error: .ruuviPersistence(error)) - self?.isTransitioningFromRealmToSQLite = false - }) - } else { - self?.isTransitioningFromRealmToSQLite = false - } - }, failure: { error in - self?.post(error: .ruuviPersistence(error)) - self?.isTransitioningFromRealmToSQLite = false - }) - }, failure: { error in - self?.post(error: .ruuviPersistence(error)) - self?.isTransitioningFromRealmToSQLite = false - }) - }, failure: { error in - self?.post(error: .ruuviPersistence(error)) - self?.isTransitioningFromRealmToSQLite = false - }) - }) - }) - }, failure: { [weak self] error in - self?.post(error: .ruuviPersistence(error)) - self?.isTransitioningFromRealmToSQLite = false - }) } } else if pair.ruuviTag.macId?.value != nil, pair.device.mac == nil { // this is the case when 2.5.9 tag is returning to data format 3 mode diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift index 56c22b539..5efaa110a 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift @@ -7,7 +7,6 @@ import RuuviStorage public final class RuuviMigrationFactoryImpl: RuuviMigrationFactory { private let settings: RuuviLocalSettings private let idPersistence: RuuviLocalIDs - private let realmContext: RealmContext private let ruuviPool: RuuviPool private let ruuviStorage: RuuviStorage private let ruuviAlertService: RuuviServiceAlert @@ -16,7 +15,6 @@ public final class RuuviMigrationFactoryImpl: RuuviMigrationFactory { public init( settings: RuuviLocalSettings, idPersistence: RuuviLocalIDs, - realmContext: RealmContext, ruuviPool: RuuviPool, ruuviStorage: RuuviStorage, ruuviAlertService: RuuviServiceAlert, @@ -24,7 +22,6 @@ public final class RuuviMigrationFactoryImpl: RuuviMigrationFactory { ) { self.settings = settings self.idPersistence = idPersistence - self.realmContext = realmContext self.ruuviPool = ruuviPool self.ruuviStorage = ruuviStorage self.ruuviAlertService = ruuviAlertService @@ -32,11 +29,6 @@ public final class RuuviMigrationFactoryImpl: RuuviMigrationFactory { } public func createAllOrdered() -> [RuuviMigration] { - let toSQLite = MigrationManagerToSQLite( - idPersistence: idPersistence, - realmContext: realmContext, - ruuviPool: ruuviPool - ) let toAlertService = MigrationManagerAlertService( ruuviStorage: ruuviStorage, ruuviAlertService: ruuviAlertService @@ -59,7 +51,6 @@ public final class RuuviMigrationFactoryImpl: RuuviMigrationFactory { ) let toNetworkPull60 = MigrationManagerToNetworkPull60(settings: settings) return [ - toSQLite, toAlertService, toPrune240, toChartDuration240, diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift deleted file mode 100644 index 4d66b3df0..000000000 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toSQLite/MigrationManagerToSQLite.swift +++ /dev/null @@ -1,79 +0,0 @@ -import Foundation -import RealmSwift -import RuuviContext -import RuuviLocal -import RuuviOntology -import RuuviPool - -extension Notification.Name { - static let MigrationManagerToSQLiteDidFinish = Notification.Name("MigrationManagerToSQLite.DidFinish") -} - -class MigrationManagerToSQLite: RuuviMigration { - private let idPersistence: RuuviLocalIDs - private let realmContext: RealmContext - private let ruuviPool: RuuviPool - - init( - idPersistence: RuuviLocalIDs, - realmContext: RealmContext, - ruuviPool: RuuviPool - ) { - self.idPersistence = idPersistence - self.realmContext = realmContext - self.ruuviPool = ruuviPool - } - - @UserDefault("MigrationManagerToSQLite.didMigrateRuuviTagRealmWithMAC", defaultValue: false) - private var didMigrateRuuviTagRealmWithMAC: Bool - - func migrateIfNeeded() { - if !didMigrateRuuviTagRealmWithMAC { - let realmTags = realmContext.main.objects(RuuviTagRealm.self) - let dispatchGroup = DispatchGroup() - realmTags.forEach { - dispatchGroup.enter() - migrate(realmTag: $0, group: dispatchGroup) - } - dispatchGroup.notify(queue: .main) { - NotificationCenter - .default - .post( - name: .MigrationManagerToSQLiteDidFinish, - object: self, - userInfo: nil - ) - } - didMigrateRuuviTagRealmWithMAC = true - } - } - - private func migrate(realmTag: RuuviTagRealm, group: DispatchGroup) { - if let mac = realmTag.mac, !mac.isEmpty { - idPersistence.set(mac: mac.mac, for: realmTag.uuid.luid) - ruuviPool.create(realmTag).on() - var records: [RuuviTagSensorRecord] = [] - for record in realmTag.data { - autoreleasepool { - if let anyRecord = record.any?.with(macId: mac.mac) { - records.append(anyRecord) - } - } - } - ruuviPool.create(records) - .on(completion: { - group.leave() - }) - do { - try realmContext.main.write { - realmContext.main.delete(realmTag.data) - realmContext.main.delete(realmTag) - } - } catch { - print(error.localizedDescription) - } - } else { - group.leave() - } - } -} diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift deleted file mode 100644 index 46c065c55..000000000 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/toVIPER/MigrationManagerToVIPER.swift +++ /dev/null @@ -1,161 +0,0 @@ -import Foundation -import RealmSwift -import RuuviLocal -import RuuviOntology - -public final class MigrationManagerToVIPER: RuuviMigration { - private let localImages: RuuviLocalImages - private var settings: RuuviLocalSettings - - public init( - localImages: RuuviLocalImages, - settings: RuuviLocalSettings - ) { - self.localImages = localImages - self.settings = settings - } - - public func migrateIfNeeded() { - let config = Realm.Configuration( - schemaVersion: 11, - migrationBlock: { [weak self] migration, oldSchemaVersion in - if oldSchemaVersion < 2 { - self?.from1to2(migration) - } else if oldSchemaVersion < 3 { - self?.from2to3(migration) - } else if oldSchemaVersion < 4 { - self?.from3to4(migration) - } else if oldSchemaVersion < 8 { - self?.deleteRuuviTagData(migration) - } - }, shouldCompactOnLaunch: { totalBytes, usedBytes in - let fiveHundredMegabytes = 500 * 1024 * 1024 - return (totalBytes > fiveHundredMegabytes) && (Double(usedBytes) / Double(totalBytes)) < 0.5 - } - ) - - // Tell Realm to use this new configuration object for the default Realm - Realm.Configuration.defaultConfiguration = config - - do { - _ = try Realm() - } catch { - if let url = Realm.Configuration.defaultConfiguration.fileURL { - do { - try FileManager.default.removeItem(at: url) - } catch { - print(error.localizedDescription) - } - } - } - - if !UserDefaults.standard.bool(forKey: "MigrationManagerToVIPER.useFahrenheit.checked") { - UserDefaults.standard.set(true, forKey: "MigrationManagerToVIPER.useFahrenheit.checked") - let useFahrenheit = UserDefaults.standard.bool(forKey: "useFahrenheit") - settings.temperatureUnit = useFahrenheit ? .fahrenheit : .celsius - } - - if !UserDefaults.standard.bool(forKey: "MigrationManagerToVIPER.hasShownWelcome.checked") { - UserDefaults.standard.set(true, forKey: "MigrationManagerToVIPER.hasShownWelcome.checked") - settings.welcomeShown = UserDefaults.standard.bool(forKey: "hasShownWelcome") - } - - if !UserDefaults.standard.bool(forKey: "MigrationManagerToVIPER.hasShownSwipe.checked") { - UserDefaults.standard.set(true, forKey: "MigrationManagerToVIPER.hasShownSwipe.checked") - let hasShownSwipe = UserDefaults.standard.bool(forKey: "hasShownSwipe") - UserDefaults.standard.set(hasShownSwipe, forKey: "DashboardScrollViewController.hasShownSwipeAlert") - } - } - - // swiftlint:disable:next function_body_length - private func from1to2(_ migration: Migration) { - migration.enumerateObjects(ofType: "RuuviTag") { oldObject, _ in - if let uuid = oldObject?["uuid"] as? String, - let name = oldObject?["name"] as? String, - let version = oldObject?["dataFormat"] as? Int, - let mac = oldObject?["mac"] as? String { - let realName = real(name, mac, uuid) - let ruuviTag = migration.create( - RuuviTagRealm.className(), - value: [ - "uuid": uuid, - "name": realName, - "version": version, - "mac": mac, - ] - ) - - if let temperature = oldObject?["temperature"] as? Double, - let humidity = oldObject?["humidity"] as? Double, - let pressure = oldObject?["pressure"] as? Double, - let accelerationX = oldObject?["accelerationX"] as? Double, - let accelerationY = oldObject?["accelerationY"] as? Double, - let accelerationZ = oldObject?["accelerationZ"] as? Double, - let rssi = oldObject?["rssi"] as? Int, - let voltage = oldObject?["voltage"] as? Double, - let movementCounter = oldObject?["movementCounter"] as? Int, - let measurementSequenceNumber = oldObject?["measurementSequenceNumber"] as? Int, - let txPower = oldObject?["txPower"] as? Int, - let updatedAt = oldObject?["updatedAt"] as? NSDate { - migration.create( - RuuviTagDataRealm.className(), - value: [ - "ruuviTag": ruuviTag, - "date": updatedAt, - "rssi": rssi, - "celsius": temperature, - "humidity": humidity, - "pressure": pressure, - "accelerationX": accelerationX, - "accelerationY": accelerationY, - "accelerationZ": accelerationZ, - "voltage": voltage, - "movementCounter": movementCounter, - "measurementSequenceNumber": measurementSequenceNumber, - "txPower": txPower, - ] - ) - } - } - - if let uuid = oldObject?["uuid"] as? String, let id = oldObject?["defaultBackground"] as? Int { - localImages.setBackground(id, for: uuid.luid) - } - } - } - - private func from2to3(_ migration: Migration) { - migration.enumerateObjects(ofType: RuuviTagDataRealm.className()) { oldObject, newObject in - if let value = oldObject?["celsius"] as? Double { - newObject?["celsius"] = value - } - if let value = oldObject?["humidity"] as? Double { - newObject?["humidity"] = value - } - if let value = oldObject?["pressure"] as? Double { - newObject?["pressure"] = value - } - } - } - - private func from3to4(_ migration: Migration) { - deleteRuuviTagData(migration) - } - - private func deleteRuuviTagData(_ migration: Migration) { - migration.deleteData(forType: RuuviTagDataRealm.className()) - } - - private func real(_ name: String, _ mac: String, _ uuid: String) -> String { - let realName: String = if name.isEmpty { - if mac.isEmpty { - uuid - } else { - mac - } - } else { - name - } - return realName - } -} diff --git a/Packages/RuuviMigration/target.yml b/Packages/RuuviMigration/target.yml index b41702b76..f38790b54 100644 --- a/Packages/RuuviMigration/target.yml +++ b/Packages/RuuviMigration/target.yml @@ -9,9 +9,6 @@ targets: dependencies: - package: Humidity - package: Future - - package: Realm - - package: Realm - product: RealmSwift - target: RuuviOntology - target: RuuviLocal - target: RuuviPool diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+Extension.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+Extension.swift deleted file mode 100644 index d229c82ef..000000000 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+Extension.swift +++ /dev/null @@ -1,90 +0,0 @@ -import Foundation -import Humidity -import RealmSwift - -public extension RuuviTagDataRealm { - var unitTemperature: Temperature? { - guard let celsius = celsius.value - else { - return nil - } - return Temperature( - value: celsius, - unit: .celsius - ) - } - - var unitHumidity: Humidity? { - guard let celsius = celsius.value, - let relativeHumidity = humidity.value - else { - return nil - } - return Humidity( - relative: relativeHumidity, - temperature: Temperature(value: celsius, unit: .celsius) - ) - } - - var unitPressure: Pressure? { - guard let pressure = pressure.value - else { - return nil - } - return Pressure( - value: pressure, - unit: .hectopascals - ) - } - - var acceleration: Acceleration? { - guard let accelerationX = accelerationX.value, - let accelerationY = accelerationY.value, - let accelerationZ = accelerationZ.value - else { - return nil - } - return Acceleration( - x: - AccelerationMeasurement( - value: accelerationX, - unit: .metersPerSecondSquared - ), - y: - AccelerationMeasurement( - value: accelerationY, - unit: .metersPerSecondSquared - ), - z: - AccelerationMeasurement( - value: accelerationZ, - unit: .metersPerSecondSquared - ) - ) - } - - var unitVoltage: Voltage? { - guard let voltage = voltage.value else { return nil } - return Voltage(value: voltage, unit: .volts) - } - - var measurement: RuuviMeasurement { - RuuviMeasurement( - luid: ruuviTag?.luid, - macId: ruuviTag?.macId, - measurementSequenceNumber: measurementSequenceNumber.value, - date: date, - rssi: rssi.value, - temperature: unitTemperature, - humidity: unitHumidity, - pressure: unitPressure, - acceleration: acceleration, - voltage: unitVoltage, - movementCounter: movementCounter.value, - txPower: txPower.value, - temperatureOffset: temperatureOffset, - humidityOffset: humidityOffset, - pressureOffset: pressureOffset - ) - } -} diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+RuuviTagSensorRecord.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+RuuviTagSensorRecord.swift deleted file mode 100644 index ac97c2c9d..000000000 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm+RuuviTagSensorRecord.swift +++ /dev/null @@ -1,26 +0,0 @@ -import Foundation -import RealmSwift - -public extension RuuviTagDataRealm { - var any: AnyRuuviTagSensorRecord? { - let inner = RuuviTagSensorRecordStruct( - luid: ruuviTag?.uuid.luid, - date: date, - source: source, - macId: ruuviTag?.mac?.mac, - rssi: rssi.value, - temperature: unitTemperature, - humidity: unitHumidity, - pressure: unitPressure, - acceleration: acceleration, - voltage: unitVoltage, - movementCounter: movementCounter.value, - measurementSequenceNumber: measurementSequenceNumber.value, - txPower: txPower.value, - temperatureOffset: temperatureOffset, - humidityOffset: humidityOffset, - pressureOffset: pressureOffset - ) - return AnyRuuviTagSensorRecord(object: inner) - } -} diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm.swift deleted file mode 100644 index a40a1e6d0..000000000 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagDataRealm.swift +++ /dev/null @@ -1,102 +0,0 @@ -import BTKit -import Foundation -import RealmSwift - -public final class RuuviTagDataRealm: Object { - @objc public dynamic var ruuviTag: RuuviTagRealm? - @objc public dynamic var date: Date = .init() - @objc public dynamic var compoundKey: String = UUID().uuidString - @objc public dynamic var sourceString: String = "unknown" - - // all versions - public let rssi = RealmProperty() - public let celsius = RealmProperty() - public let humidity = RealmProperty() - public let pressure = RealmProperty() - - // v3 & v5 - public let accelerationX = RealmProperty() - public let accelerationY = RealmProperty() - public let accelerationZ = RealmProperty() - public let voltage = RealmProperty() - - // v5 - public let movementCounter = RealmProperty() - public let measurementSequenceNumber = RealmProperty() - public let txPower = RealmProperty() - - @objc public dynamic var temperatureOffset: Double = 0.0 - @objc public dynamic var humidityOffset: Double = 0.0 - @objc public dynamic var pressureOffset: Double = 0.0 - - public var fahrenheit: Double? { - celsius.value?.fahrenheit - } - - public var kelvin: Double? { - celsius.value?.kelvin - } - - public var source: RuuviTagSensorRecordSource { - RuuviTagSensorRecordSource(rawValue: sourceString) ?? .unknown - } - - override public static func primaryKey() -> String? { - "compoundKey" - } - - public convenience init(ruuviTag: RuuviTagRealm, data: RuuviTagProtocol, date: Date) { - self.init(ruuviTag: ruuviTag, data: data) - self.date = date - } - - public convenience init(ruuviTag: RuuviTagRealm, data: RuuviTagProtocol) { - self.init() - self.ruuviTag = ruuviTag - sourceString = data.source.rawValue - rssi.value = data.rssi - celsius.value = data.celsius - humidity.value = data.relativeHumidity - pressure.value = data.hectopascals - accelerationX.value = data.accelerationX - accelerationY.value = data.accelerationY - accelerationZ.value = data.accelerationZ - voltage.value = data.volts - movementCounter.value = data.movementCounter - measurementSequenceNumber.value = data.measurementSequenceNumber - txPower.value = data.txPower - compoundKey = ruuviTag.uuid + "\(date.timeIntervalSince1970)" - } - - public convenience init(ruuviTag: RuuviTagRealm, data: RuuviTagEnvLogFull) { - self.init() - self.ruuviTag = ruuviTag - sourceString = RuuviTagSensorRecordSource.log.rawValue - date = data.date - celsius.value = data.temperature - humidity.value = data.humidity - pressure.value = data.pressure - compoundKey = ruuviTag.uuid + "\(date.timeIntervalSince1970)" - } - - public convenience init(ruuviTag: RuuviTagRealm, record: RuuviTagSensorRecord) { - self.init() - self.ruuviTag = ruuviTag - sourceString = record.source.rawValue - rssi.value = record.rssi - celsius.value = record.temperature?.converted(to: .celsius).value - humidity.value = record.humidity?.value - pressure.value = record.pressure?.converted(to: .hectopascals).value - accelerationX.value = record.acceleration?.x.value - accelerationY.value = record.acceleration?.y.value - accelerationZ.value = record.acceleration?.z.value - voltage.value = record.voltage?.converted(to: .volts).value - movementCounter.value = record.movementCounter - measurementSequenceNumber.value = record.measurementSequenceNumber - txPower.value = record.txPower - compoundKey = record.id - temperatureOffset = record.temperatureOffset - humidityOffset = record.humidityOffset - pressureOffset = record.pressureOffset - } -} diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+Extension.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+Extension.swift deleted file mode 100644 index 02e38a3d6..000000000 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+Extension.swift +++ /dev/null @@ -1,90 +0,0 @@ -import Foundation -import Humidity -import RealmSwift - -public extension RuuviTagLatestDataRealm { - var unitTemperature: Temperature? { - guard let celsius = celsius.value - else { - return nil - } - return Temperature( - value: celsius, - unit: .celsius - ) - } - - var unitHumidity: Humidity? { - guard let celsius = celsius.value, - let relativeHumidity = humidity.value - else { - return nil - } - return Humidity( - relative: relativeHumidity, - temperature: Temperature(value: celsius, unit: .celsius) - ) - } - - var unitPressure: Pressure? { - guard let pressure = pressure.value - else { - return nil - } - return Pressure( - value: pressure, - unit: .hectopascals - ) - } - - var acceleration: Acceleration? { - guard let accelerationX = accelerationX.value, - let accelerationY = accelerationY.value, - let accelerationZ = accelerationZ.value - else { - return nil - } - return Acceleration( - x: - AccelerationMeasurement( - value: accelerationX, - unit: .metersPerSecondSquared - ), - y: - AccelerationMeasurement( - value: accelerationY, - unit: .metersPerSecondSquared - ), - z: - AccelerationMeasurement( - value: accelerationZ, - unit: .metersPerSecondSquared - ) - ) - } - - var unitVoltage: Voltage? { - guard let voltage = voltage.value else { return nil } - return Voltage(value: voltage, unit: .volts) - } - - var measurement: RuuviMeasurement { - RuuviMeasurement( - luid: ruuviTag?.luid, - macId: ruuviTag?.macId, - measurementSequenceNumber: measurementSequenceNumber.value, - date: date, - rssi: rssi.value, - temperature: unitTemperature, - humidity: unitHumidity, - pressure: unitPressure, - acceleration: acceleration, - voltage: unitVoltage, - movementCounter: movementCounter.value, - txPower: txPower.value, - temperatureOffset: temperatureOffset, - humidityOffset: humidityOffset, - pressureOffset: pressureOffset - ) - } -} diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+RuuviTagSensorRecord.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+RuuviTagSensorRecord.swift deleted file mode 100644 index 0ef08ad04..000000000 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm+RuuviTagSensorRecord.swift +++ /dev/null @@ -1,26 +0,0 @@ -import Foundation -import RealmSwift - -public extension RuuviTagLatestDataRealm { - var any: AnyRuuviTagSensorRecord? { - let inner = RuuviTagSensorRecordStruct( - luid: ruuviTag?.uuid.luid, - date: date, - source: source, - macId: ruuviTag?.mac?.mac, - rssi: rssi.value, - temperature: unitTemperature, - humidity: unitHumidity, - pressure: unitPressure, - acceleration: acceleration, - voltage: unitVoltage, - movementCounter: movementCounter.value, - measurementSequenceNumber: measurementSequenceNumber.value, - txPower: txPower.value, - temperatureOffset: temperatureOffset, - humidityOffset: humidityOffset, - pressureOffset: pressureOffset - ) - return AnyRuuviTagSensorRecord(object: inner) - } -} diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm.swift deleted file mode 100644 index 6df825b7b..000000000 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagLatestDataRealm.swift +++ /dev/null @@ -1,102 +0,0 @@ -import BTKit -import Foundation -import RealmSwift - -public final class RuuviTagLatestDataRealm: Object { - @objc public dynamic var uuid: String = "" - @objc public dynamic var ruuviTag: RuuviTagRealm? - @objc public dynamic var date: Date = .init() - @objc public dynamic var sourceString: String = "unknown" - - // all versions - public let rssi = RealmProperty() - public let celsius = RealmProperty() - public let humidity = RealmProperty() - public let pressure = RealmProperty() - - // v3 & v5 - public let accelerationX = RealmProperty() - public let accelerationY = RealmProperty() - public let accelerationZ = RealmProperty() - public let voltage = RealmProperty() - - // v5 - public let movementCounter = RealmProperty() - public let measurementSequenceNumber = RealmProperty() - public let txPower = RealmProperty() - - @objc public dynamic var temperatureOffset: Double = 0.0 - @objc public dynamic var humidityOffset: Double = 0.0 - @objc public dynamic var pressureOffset: Double = 0.0 - - public var fahrenheit: Double? { - celsius.value?.fahrenheit - } - - public var kelvin: Double? { - celsius.value?.kelvin - } - - public var source: RuuviTagSensorRecordSource { - RuuviTagSensorRecordSource(rawValue: sourceString) ?? .unknown - } - - override public static func primaryKey() -> String? { - "uuid" - } - - public convenience init(ruuviTag: RuuviTagRealm, data: RuuviTagProtocol, date: Date) { - self.init(ruuviTag: ruuviTag, data: data) - self.date = date - } - - public convenience init(ruuviTag: RuuviTagRealm, data: RuuviTagProtocol) { - self.init() - uuid = ruuviTag.uuid - self.ruuviTag = ruuviTag - sourceString = data.source.rawValue - rssi.value = data.rssi - celsius.value = data.celsius - humidity.value = data.relativeHumidity - pressure.value = data.hectopascals - accelerationX.value = data.accelerationX - accelerationY.value = data.accelerationY - accelerationZ.value = data.accelerationZ - voltage.value = data.volts - movementCounter.value = data.movementCounter - measurementSequenceNumber.value = data.measurementSequenceNumber - txPower.value = data.txPower - } - - public convenience init(ruuviTag: RuuviTagRealm, data: RuuviTagEnvLogFull) { - self.init() - self.ruuviTag = ruuviTag - sourceString = RuuviTagSensorRecordSource.log.rawValue - date = data.date - celsius.value = data.temperature - humidity.value = data.humidity - pressure.value = data.pressure - uuid = ruuviTag.uuid - } - - public convenience init(ruuviTag: RuuviTagRealm, record: RuuviTagSensorRecord) { - self.init() - self.ruuviTag = ruuviTag - sourceString = record.source.rawValue - rssi.value = record.rssi - celsius.value = record.temperature?.converted(to: .celsius).value - humidity.value = record.humidity?.value - pressure.value = record.pressure?.converted(to: .hectopascals).value - accelerationX.value = record.acceleration?.x.value - accelerationY.value = record.acceleration?.y.value - accelerationZ.value = record.acceleration?.z.value - voltage.value = record.voltage?.converted(to: .volts).value - movementCounter.value = record.movementCounter - measurementSequenceNumber.value = record.measurementSequenceNumber - txPower.value = record.txPower - uuid = record.uuid - temperatureOffset = record.temperatureOffset - humidityOffset = record.humidityOffset - pressureOffset = record.pressureOffset - } -} diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm+RuuviTagSensor.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm+RuuviTagSensor.swift deleted file mode 100644 index 114fdade2..000000000 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm+RuuviTagSensor.swift +++ /dev/null @@ -1,60 +0,0 @@ -import Foundation -import RealmSwift - -extension RuuviTagRealm: RuuviTagSensor { - public var luid: LocalIdentifier? { - uuid.luid - } - - public var macId: MACIdentifier? { - mac?.mac - } - - public var any: AnyRuuviTagSensor { - AnyRuuviTagSensor( - object: RuuviTagSensorStruct( - version: version, - firmwareVersion: firmwareVersion, - luid: luid, - macId: macId, - isConnectable: isConnectable, - name: name, - isClaimed: isClaimed, - isOwner: isOwner, - owner: owner, - ownersPlan: ownersPlan, - isCloudSensor: isCloudSensor, - canShare: canShare, - sharedTo: sharedTo - ) - ) - } - - public var isClaimed: Bool { - false - } - - public var owner: String? { - nil - } - - public var ownersPlan: String? { - nil - } - - public var isCloudSensor: Bool? { - false - } - - public var firmwareVersion: String? { - nil - } - - public var canShare: Bool { - false - } - - public var sharedTo: [String] { - [] - } -} diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm.swift deleted file mode 100644 index be4652124..000000000 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealm.swift +++ /dev/null @@ -1,48 +0,0 @@ -import BTKit -import Foundation -import RealmSwift - -public final class RuuviTagRealm: Object, RuuviTagRealmProtocol { - @objc public dynamic var uuid: String = "" - @objc public dynamic var name: String = "" - @objc public dynamic var mac: String? - @objc public dynamic var version: Int = 0 - @objc public dynamic var isConnectable: Bool = false - @objc public dynamic var isOwner: Bool = true - - public let data = LinkingObjects(fromType: RuuviTagDataRealm.self, property: "ruuviTag") - - override public static func primaryKey() -> String { - "uuid" - } - - public required convenience init(mac: String) { - self.init() - uuid = UUID().uuidString - self.mac = mac - name = mac - version = 5 - isConnectable = true - isOwner = true - } - - public required convenience init(ruuviTag: RuuviTagProtocol, name: String) { - self.init() - uuid = ruuviTag.uuid - self.name = name - mac = ruuviTag.mac - version = ruuviTag.version - isConnectable = ruuviTag.isConnectable - isOwner = ruuviTag.isOwner - } - - public required convenience init(ruuviTag: RuuviTagSensor) { - self.init() - uuid = ruuviTag.id - name = ruuviTag.name - mac = ruuviTag.macId?.value - version = ruuviTag.version - isConnectable = ruuviTag.isConnectable - isOwner = ruuviTag.isOwner - } -} diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealmProtocol.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealmProtocol.swift deleted file mode 100644 index 6656954ff..000000000 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/RuuviTagRealmProtocol.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Foundation -import RealmSwift - -public protocol RuuviTagRealmProtocol: Object { - var uuid: String { get set } - var name: String { get set } - var mac: String? { get set } - var version: Int { get set } - var isConnectable: Bool { get set } - var data: LinkingObjects { get } - init(ruuviTag: RuuviTagProtocol, name: String) -} diff --git a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/SensorSettingsRealm.swift b/Packages/RuuviOntology/Sources/RuuviOntologyRealm/SensorSettingsRealm.swift deleted file mode 100644 index 090afd652..000000000 --- a/Packages/RuuviOntology/Sources/RuuviOntologyRealm/SensorSettingsRealm.swift +++ /dev/null @@ -1,49 +0,0 @@ -import Foundation -import RealmSwift - -public class SensorSettingsRealm: Object { - @objc public dynamic var luid: String? - @objc public dynamic var macId: String? - - public let temperatureOffset = RealmProperty() - @objc public dynamic var temperatureOffsetDate: Date? - - public let humidityOffset = RealmProperty() - @objc public dynamic var humidityOffsetDate: Date? - - public let pressureOffset = RealmProperty() - @objc public dynamic var pressureOffsetDate: Date? - - public convenience init(ruuviTag: RuuviTagSensor) { - self.init() - luid = ruuviTag.luid?.value - macId = ruuviTag.macId?.value - } - - public convenience init(settings: SensorSettings) { - self.init() - luid = settings.luid?.value - macId = settings.macId?.value - temperatureOffset.value = settings.temperatureOffset - temperatureOffsetDate = settings.temperatureOffsetDate - humidityOffset.value = settings.humidityOffset - humidityOffsetDate = settings.humidityOffsetDate - pressureOffset.value = settings.pressureOffset - pressureOffsetDate = settings.pressureOffsetDate - } -} - -public extension SensorSettingsRealm { - var sensorSettings: SensorSettings { - SensorSettingsStruct( - luid: luid?.luid, - macId: macId?.mac, - temperatureOffset: temperatureOffset.value, - temperatureOffsetDate: temperatureOffsetDate, - humidityOffset: humidityOffset.value, - humidityOffsetDate: humidityOffsetDate, - pressureOffset: pressureOffset.value, - pressureOffsetDate: pressureOffsetDate - ) - } -} diff --git a/Packages/RuuviOntology/target.yml b/Packages/RuuviOntology/target.yml index 52fc3e669..e4c8a4e34 100644 --- a/Packages/RuuviOntology/target.yml +++ b/Packages/RuuviOntology/target.yml @@ -13,7 +13,4 @@ targets: dependencies: - package: Humidity - package: BTKit - - package: Realm - - package: Realm - product: RealmSwift - package: GRDB diff --git a/Packages/RuuviPersistence/Sources/RuuviPersistence/RuuviPersistenceError.swift b/Packages/RuuviPersistence/Sources/RuuviPersistence/RuuviPersistenceError.swift index a5e25d302..a6ad5a1fc 100644 --- a/Packages/RuuviPersistence/Sources/RuuviPersistence/RuuviPersistenceError.swift +++ b/Packages/RuuviPersistence/Sources/RuuviPersistence/RuuviPersistenceError.swift @@ -2,6 +2,5 @@ import Foundation public enum RuuviPersistenceError: Error { case grdb(Error) - case realm(Error) case failedToFindRuuviTag } diff --git a/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift b/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift deleted file mode 100644 index 3ec363bc3..000000000 --- a/Packages/RuuviPersistence/Sources/RuuviPersistenceRealm/RuuviPersistenceRealm.swift +++ /dev/null @@ -1,753 +0,0 @@ -// swiftlint:disable file_length -import BTKit -import Foundation -import Future -import RealmSwift -import RuuviContext -import RuuviOntology -#if canImport(FirebaseCrashlytics) // TODO: @rinat eliminate - import FirebaseCrashlytics -#endif - -// swiftlint:disable type_body_length -public class RuuviPersistenceRealm: RuuviPersistence { - private let context: RealmContext - - public init(context: RealmContext) { - self.context = context - } - - public func create(_ ruuviTag: RuuviTagSensor) -> Future { - let promise = Promise() - assert(ruuviTag.macId == nil) - assert(ruuviTag.luid != nil) - context.bgWorker.enqueue { - do { - let realmTag = RuuviTagRealm(ruuviTag: ruuviTag) - try self.context.bg.write { - self.context.bg.add(realmTag, update: .error) - } - promise.succeed(value: true) - } catch { - self.reportToCrashlytics(error: error) - promise.fail(error: .realm(error)) - } - } - return promise.future - } - - public func update(_ ruuviTag: RuuviTagSensor) -> Future { - let promise = Promise() - assert(ruuviTag.macId == nil) - assert(ruuviTag.luid != nil) - context.bgWorker.enqueue { - do { - let realmTag = RuuviTagRealm(ruuviTag: ruuviTag) - try self.context.bg.write { - self.context.bg.add(realmTag, update: .modified) - } - promise.succeed(value: true) - } catch { - self.reportToCrashlytics(error: error) - promise.fail(error: .realm(error)) - } - } - return promise.future - } - - public func delete(_ ruuviTag: RuuviTagSensor) -> Future { - let promise = Promise() - assert(ruuviTag.macId == nil) - assert(ruuviTag.luid != nil) - context.bgWorker.enqueue { - do { - if let realmTag = self.context.bg.object( - ofType: RuuviTagRealm.self, - forPrimaryKey: ruuviTag.luid?.value ?? ruuviTag.id - ) { - try self.context.bg.write { - self.context.bg.delete(realmTag) - } - promise.succeed(value: true) - } else { - promise.fail(error: .failedToFindRuuviTag) - } - } catch { - self.reportToCrashlytics(error: error) - promise.fail(error: .realm(error)) - } - } - return promise.future - } - - public func deleteAllRecords(_ ruuviTagId: String) -> Future { - let promise = Promise() - context.bgWorker.enqueue { - do { - let data = self.context.bg.objects(RuuviTagDataRealm.self) - .filter("ruuviTag.uuid == %@", ruuviTagId) - try self.context.bg.write { - self.context.bg.delete(data) - } - promise.succeed(value: true) - } catch { - self.reportToCrashlytics(error: error) - promise.fail(error: .realm(error)) - } - } - return promise.future - } - - public func deleteAllRecords(_ ruuviTagId: String, before date: Date) -> Future { - let promise = Promise() - context.bgWorker.enqueue { - do { - let data = self.context.bg.objects(RuuviTagDataRealm.self) - .filter("ruuviTag.uuid == %@ AND date < %@", ruuviTagId, date) - try self.context.bg.write { - self.context.bg.delete(data) - } - promise.succeed(value: true) - } catch { - self.reportToCrashlytics(error: error) - promise.fail(error: .realm(error)) - } - } - return promise.future - } - - public func create(_ record: RuuviTagSensorRecord) -> Future { - let promise = Promise() - assert(record.macId == nil) - context.bgWorker.enqueue { - do { - if let ruuviTag = self.context.bg.object( - ofType: RuuviTagRealm.self, - forPrimaryKey: record.luid?.value ?? record.id - ) { - let data = RuuviTagDataRealm(ruuviTag: ruuviTag, record: record) - try self.context.bg.write { - self.context.bg.add(data, update: .all) - } - promise.succeed(value: true) - } else { - promise.fail(error: .failedToFindRuuviTag) - } - } catch { - promise.fail(error: .realm(error)) - } - } - return promise.future - } - - public func createLast(_ record: RuuviTagSensorRecord) -> Future { - let promise = Promise() - assert(record.macId == nil) - context.bgWorker.enqueue { - do { - if let ruuviTag = self.context.bg.object( - ofType: RuuviTagRealm.self, - forPrimaryKey: record.luid?.value ?? record.id - ) { - let data = RuuviTagLatestDataRealm(ruuviTag: ruuviTag, record: record) - try self.context.bg.write { - self.context.bg.add(data, update: .all) - } - promise.succeed(value: true) - } else { - promise.fail(error: .failedToFindRuuviTag) - } - } catch { - promise.fail(error: .realm(error)) - } - } - return promise.future - } - - public func updateLast(_ record: RuuviTagSensorRecord) -> Future { - let promise = Promise() - context.bgWorker.enqueue { - do { - if let ruuviTag = self.context.bg.object( - ofType: RuuviTagRealm.self, - forPrimaryKey: record.luid?.value ?? record.id - ) { - let data = RuuviTagLatestDataRealm(ruuviTag: ruuviTag, record: record) - try self.context.bg.write { - self.context.bg.add(data, update: .modified) - } - promise.succeed(value: true) - } else { - promise.fail(error: .failedToFindRuuviTag) - } - } catch { - self.reportToCrashlytics(error: error) - promise.fail(error: .realm(error)) - } - } - return promise.future - } - - public func deleteLatest(_ ruuviTagId: String) -> Future { - let promise = Promise() - context.bgWorker.enqueue { - do { - let data = self.context.bg.objects(RuuviTagLatestDataRealm.self) - .filter("ruuviTag.uuid == %@", ruuviTagId) - try self.context.bg.write { - self.context.bg.delete(data) - } - promise.succeed(value: true) - } catch { - self.reportToCrashlytics(error: error) - promise.fail(error: .realm(error)) - } - } - return promise.future - } - - public func create(_ records: [RuuviTagSensorRecord]) -> Future { - let promise = Promise() - context.bgWorker.enqueue { - do { - var failed = false - for record in records { - assert(record.macId == nil) - let extractedExpr: RuuviTagRealm? = self.context.bg - .object( - ofType: RuuviTagRealm.self, - forPrimaryKey: record.luid?.value ?? record.id - ) - if let ruuviTag = extractedExpr { - let data = RuuviTagDataRealm(ruuviTag: ruuviTag, record: record) - try self.context.bg.write { - self.context.bg.add(data, update: .all) - } - } else { - failed = true - } - } - if failed { - promise.fail(error: .failedToFindRuuviTag) - } else { - promise.succeed(value: true) - } - } catch { - promise.fail(error: .realm(error)) - } - } - return promise.future - } - - public func readOne(_ ruuviTagId: String) -> Future { - let promise = Promise() - context.bgWorker.enqueue { - if let ruuviTagRealm = self.context.bg.object(ofType: RuuviTagRealm.self, forPrimaryKey: ruuviTagId) { - let result = self.constructRuuviTagSensorStruct(from: ruuviTagRealm) - promise.succeed(value: result) - } else { - promise.fail(error: .failedToFindRuuviTag) - } - } - return promise.future - } - - public func readAll() -> Future<[AnyRuuviTagSensor], RuuviPersistenceError> { - let promise = Promise<[AnyRuuviTagSensor], RuuviPersistenceError>() - context.bgWorker.enqueue { - let realmEntities = self.context.bg.objects(RuuviTagRealm.self) - let result: [AnyRuuviTagSensor] = realmEntities.map { ruuviTagRealm in - self.constructRuuviTagSensorStruct(from: ruuviTagRealm) - } - promise.succeed(value: result) - } - return promise.future - } - - public func readAll(_ ruuviTagId: String) -> Future<[RuuviTagSensorRecord], RuuviPersistenceError> { - let promise = Promise<[RuuviTagSensorRecord], RuuviPersistenceError>() - context.bgWorker.enqueue { - let realmRecords = self.context.bg.objects(RuuviTagDataRealm.self) - .filter("ruuviTag.uuid == %@", ruuviTagId) - .sorted(byKeyPath: "date") - let result: [RuuviTagSensorRecord] = realmRecords.map { realmRecord in - self.constructRecordStruct( - from: realmRecord, - luid: realmRecord.ruuviTag?.luid, - sequenceNumber: realmRecord.measurementSequenceNumber.value - ) - } - promise.succeed(value: result) - } - return promise.future - } - - public func readAll( - _ ruuviTagId: String, - with interval: TimeInterval - ) -> Future<[RuuviTagSensorRecord], RuuviPersistenceError> { - let promise = Promise<[RuuviTagSensorRecord], RuuviPersistenceError>() - context.bgWorker.enqueue { - let ruuviTagDataRealms = self.context.bg.objects(RuuviTagDataRealm.self) - .filter("ruuviTag.uuid == %@", ruuviTagId) - .sorted(byKeyPath: "date") - var results: [RuuviTagSensorRecord] = [] - var previousDate = ruuviTagDataRealms.first?.date ?? Date() - for tagDataRealm in ruuviTagDataRealms { - autoreleasepool { - guard tagDataRealm.date >= previousDate.addingTimeInterval(interval) - else { - return - } - previousDate = tagDataRealm.date - results.append( - self.constructRecordStruct( - from: tagDataRealm, - luid: tagDataRealm.ruuviTag?.luid, - sequenceNumber: tagDataRealm.measurementSequenceNumber.value - ) - ) - } - } - promise.succeed(value: results) - } - return promise.future - } - - public func readAll( - _ ruuviTagId: String, - after date: Date - ) -> Future<[RuuviTagSensorRecord], RuuviPersistenceError> { - let promise = Promise<[RuuviTagSensorRecord], RuuviPersistenceError>() - context.bgWorker.enqueue { - let realmRecords = self.context.bg.objects(RuuviTagDataRealm.self) - .filter("ruuviTag.uuid == %@ AND date > %@", ruuviTagId, date) - .sorted(byKeyPath: "date") - var results: [RuuviTagSensorRecord] = [] - var previousDate = realmRecords.first?.date ?? Date() - for realmRecord in realmRecords { - autoreleasepool { - guard realmRecord.date >= previousDate - else { - return - } - previousDate = realmRecord.date - results.append( - self.constructRecordStruct( - from: realmRecord, - luid: realmRecord.ruuviTag?.luid, - sequenceNumber: realmRecord.measurementSequenceNumber.value - ) - ) - } - } - promise.succeed(value: results) - } - return promise.future - } - - public func read( - _ ruuviTagId: String, - after date: Date, - with interval: TimeInterval - ) -> Future<[RuuviTagSensorRecord], RuuviPersistenceError> { - let promise = Promise<[RuuviTagSensorRecord], RuuviPersistenceError>() - context.bgWorker.enqueue { - let realmRecords = self.context.bg.objects(RuuviTagDataRealm.self) - .filter("ruuviTag.uuid == %@ AND date > %@", ruuviTagId, date) - .sorted(byKeyPath: "date") - var results: [RuuviTagSensorRecord] = [] - var previousDate = realmRecords.first?.date ?? Date() - for realmRecord in realmRecords { - autoreleasepool { - guard realmRecord.date >= previousDate.addingTimeInterval(interval) - else { - return - } - previousDate = realmRecord.date - results.append( - self.constructRecordStruct( - from: realmRecord, - luid: realmRecord.ruuviTag?.luid, - sequenceNumber: realmRecord.measurementSequenceNumber.value - ) - ) - } - } - promise.succeed(value: results) - } - return promise.future - } - - public func readDownsampled( - _: String, - after _: Date, - with _: Int, - pick _: Double - ) -> Future<[RuuviTagSensorRecord], RuuviPersistenceError> { - let promise = Promise<[RuuviTagSensorRecord], RuuviPersistenceError>() - // No need to implement since the RealmDB will be removed in the future. - return promise.future - } - - public func readLast( - _ ruuviTagId: String, - from: TimeInterval - ) -> Future<[RuuviTagSensorRecord], RuuviPersistenceError> { - let promise = Promise<[RuuviTagSensorRecord], RuuviPersistenceError>() - context.bgWorker.enqueue { - let realmRecords = self.context.bg - .objects(RuuviTagDataRealm.self) - .filter( - "ruuviTag.uuid == %@ AND date > %@", - ruuviTagId, - Date(timeIntervalSince1970: from) - ) - .sorted(byKeyPath: "date") - let result: [RuuviTagSensorRecord] = realmRecords.map { record in - self.constructRecordStruct( - from: record, - luid: record.ruuviTag?.luid, - sequenceNumber: record.measurementSequenceNumber.value - ) - } - promise.succeed(value: result) - } - return promise.future - } - - public func readLast(_ ruuviTag: RuuviTagSensor) -> Future { - let promise = Promise() - guard ruuviTag.macId == nil, - let luid = ruuviTag.luid - else { - promise.succeed(value: nil) - return promise.future - } - context.bgWorker.enqueue { - if let lastRecord = self.context.bg.objects(RuuviTagDataRealm.self) - .filter("ruuviTag.uuid == %@", luid.value) - .sorted(byKeyPath: "date", ascending: false) - .first { - let sequenceNumber = lastRecord.measurementSequenceNumber.value - let lastRecordResult = self.constructRecordStruct( - from: lastRecord, - luid: luid, - sequenceNumber: sequenceNumber - ) - promise.succeed(value: lastRecordResult) - } else { - promise.succeed(value: nil) - } - } - return promise.future - } - - public func readLatest(_ ruuviTag: RuuviTagSensor) -> Future { - let promise = Promise() - guard ruuviTag.macId == nil, - let luid = ruuviTag.luid - else { - promise.succeed(value: nil) - return promise.future - } - context.bgWorker.enqueue { - if let lastRecord = self.context.bg.objects(RuuviTagLatestDataRealm.self) - .filter("ruuviTag.uuid == %@", luid.value) - .sorted(byKeyPath: "date", ascending: false) - .first { - let sequenceNumber = lastRecord.measurementSequenceNumber.value - let lastRecordResult = self.constructRecordStruct( - from: lastRecord, - luid: luid, - sequenceNumber: sequenceNumber - ) - promise.succeed(value: lastRecordResult) - } else { - promise.succeed(value: nil) - } - } - return promise.future - } - - public func getStoredTagsCount() -> Future { - let promise = Promise() - context.bgWorker.enqueue { - let tagsCount = self.context.bg.objects(RuuviTagRealm.self).count - promise.succeed(value: tagsCount) - } - return promise.future - } - - public func getStoredMeasurementsCount() -> Future { - let promise = Promise() - context.bgWorker.enqueue { - let tagsCount = self.context.bg.objects(RuuviTagDataRealm.self).count - promise.succeed(value: tagsCount) - } - return promise.future - } - - public func readSensorSettings(_ ruuviTag: RuuviTagSensor) -> Future { - let promise = Promise() - guard ruuviTag.macId == nil, - ruuviTag.luid != nil - else { - promise.fail(error: .failedToFindRuuviTag) - return promise.future - } - context.bgWorker.enqueue { - if let record = self.context.bg.objects(SensorSettingsRealm.self) - .first(where: { - ($0.luid != nil && $0.luid == ruuviTag.luid?.value) - || ($0.macId != nil && $0.macId == ruuviTag.macId?.value) - }) { - promise.succeed(value: record.sensorSettings) - } else { - promise.succeed(value: nil) - } - } - return promise.future - } - - public func save( - sensorSettings: SensorSettings - ) -> Future { - let promise = Promise() - context.bgWorker.enqueue { - do { - let sensorSettingsRealm = SensorSettingsRealm(settings: sensorSettings) - try self.context.bg.write { - self.context.bg.add(sensorSettingsRealm, update: .all) - } - promise.succeed(value: sensorSettings) - } catch { - promise.fail(error: .grdb(error)) - } - } - return promise.future - } - - public func updateOffsetCorrection( - type: OffsetCorrectionType, - with value: Double?, - of ruuviTag: RuuviTagSensor, - lastOriginalRecord _: RuuviTagSensorRecord? - ) -> Future { - let promise = Promise() - assert(ruuviTag.macId == nil) - assert(ruuviTag.luid != nil) - context.bgWorker.enqueue { - do { - if let record = self.context.bg.objects(SensorSettingsRealm.self) - .first(where: { - ($0.luid != nil && $0.luid == ruuviTag.luid?.value) - || ($0.macId != nil && $0.macId == ruuviTag.macId?.value) - }) { - try self.context.bg.write { - switch type { - case .humidity: - record.humidityOffset.value = value - record.humidityOffsetDate = value == nil ? nil : Date() - case .pressure: - record.pressureOffset.value = value - record.pressureOffsetDate = value == nil ? nil : Date() - default: - record.temperatureOffset.value = value - record.temperatureOffsetDate = value == nil ? nil : Date() - } - } - promise.succeed(value: record.sensorSettings) - } else { - let sensorSettingsRealm = SensorSettingsRealm(ruuviTag: ruuviTag) - switch type { - case .humidity: - sensorSettingsRealm.humidityOffset.value = value - sensorSettingsRealm.humidityOffsetDate = value == nil ? nil : Date() - case .pressure: - sensorSettingsRealm.pressureOffset.value = value - sensorSettingsRealm.pressureOffsetDate = value == nil ? nil : Date() - default: - sensorSettingsRealm.temperatureOffset.value = value - sensorSettingsRealm.temperatureOffsetDate = value == nil ? nil : Date() - } - try self.context.bg.write { - self.context.bg.add(sensorSettingsRealm, update: .error) - } - promise.succeed(value: sensorSettingsRealm.sensorSettings) - } - } catch { - self.reportToCrashlytics(error: error) - promise.fail(error: .realm(error)) - } - } - return promise.future - } - - public func deleteOffsetCorrection(ruuviTag: RuuviTagSensor) -> Future { - let promise = Promise() - assert(ruuviTag.macId == nil) - assert(ruuviTag.luid != nil) - context.bgWorker.enqueue { - do { - if let sensorSettingRealm = self.context.bg.objects(SensorSettingsRealm.self) - .first(where: { - ($0.luid != nil && $0.luid == ruuviTag.luid?.value) - || ($0.macId != nil && $0.macId == ruuviTag.macId?.value) - }) { - try self.context.bg.write { - self.context.bg.delete(sensorSettingRealm) - } - promise.succeed(value: true) - } else { - promise.fail(error: .failedToFindRuuviTag) - } - } catch { - self.reportToCrashlytics(error: error) - promise.fail(error: .realm(error)) - } - } - return promise.future - } - - public func cleanupDBSpace() -> Future { - let promise = Promise() - // No op for realmDB since this will be deprecated soon. - return promise.future - } - - // MARK: - Queued cloud requests - - @discardableResult - public func readQueuedRequests() -> Future<[RuuviCloudQueuedRequest], RuuviPersistenceError> { - let promise = Promise<[RuuviCloudQueuedRequest], RuuviPersistenceError>() - // No op for realmDB since this will be deprecated soon. - return promise.future - } - - @discardableResult - public func readQueuedRequests( - for _: String - ) -> Future<[RuuviCloudQueuedRequest], RuuviPersistenceError> { - let promise = Promise<[RuuviCloudQueuedRequest], RuuviPersistenceError>() - // No op for realmDB since this will be deprecated soon. - return promise.future - } - - @discardableResult - public func readQueuedRequests( - for _: RuuviCloudQueuedRequestType - ) -> Future<[RuuviCloudQueuedRequest], RuuviPersistenceError> { - let promise = Promise<[RuuviCloudQueuedRequest], RuuviPersistenceError>() - // No op for realmDB since this will be deprecated soon. - return promise.future - } - - @discardableResult - public func createQueuedRequest( - _: RuuviCloudQueuedRequest - ) -> Future { - let promise = Promise() - // No op for realmDB since this will be deprecated soon. - return promise.future - } - - @discardableResult - public func deleteQueuedRequest( - _: RuuviCloudQueuedRequest - ) -> Future { - let promise = Promise() - // No op for realmDB since this will be deprecated soon. - return promise.future - } - - @discardableResult - public func deleteQueuedRequests() -> Future { - let promise = Promise() - // No op for realmDB since this will be deprecated soon. - return promise.future - } -} - -// MARK: - Private - -extension RuuviPersistenceRealm { - func reportToCrashlytics(error: Error, method: String = #function, line: Int = #line) { - #if canImport(FirebaseCrashlytics) - Crashlytics.crashlytics().log("\(method)(line: \(line)") - Crashlytics.crashlytics().record(error: error) - #endif - } - - private func constructRuuviTagSensorStruct(from ruuviTagRealm: RuuviTagRealm) -> AnyRuuviTagSensor { - RuuviTagSensorStruct( - version: ruuviTagRealm.version, - firmwareVersion: ruuviTagRealm.firmwareVersion, - luid: ruuviTagRealm.uuid.luid, - macId: ruuviTagRealm.mac?.mac, - isConnectable: ruuviTagRealm.isConnectable, - name: ruuviTagRealm.name, - isClaimed: false, - isOwner: ruuviTagRealm.isOwner, - owner: ruuviTagRealm.owner, - ownersPlan: ruuviTagRealm.ownersPlan, - isCloudSensor: ruuviTagRealm.isCloudSensor, - canShare: ruuviTagRealm.canShare, - sharedTo: ruuviTagRealm.sharedTo - ).any - } - - private func constructRecordStruct( - from lastRecord: RuuviTagDataRealm, - luid: LocalIdentifier?, - sequenceNumber: Int? - ) -> RuuviTagSensorRecordStruct { - let lastRecordResult = RuuviTagSensorRecordStruct( - luid: luid, - date: lastRecord.date, - source: lastRecord.source, - macId: nil, - rssi: lastRecord.rssi.value, - temperature: lastRecord.unitTemperature, - humidity: lastRecord.unitHumidity, - pressure: lastRecord.unitPressure, - acceleration: lastRecord.acceleration, - voltage: lastRecord.unitVoltage, - movementCounter: lastRecord.movementCounter.value, - measurementSequenceNumber: sequenceNumber, - txPower: lastRecord.txPower.value, - temperatureOffset: lastRecord.temperatureOffset, - humidityOffset: lastRecord.humidityOffset, - pressureOffset: lastRecord.pressureOffset - ) - return lastRecordResult - } - - private func constructRecordStruct( - from lastRecord: RuuviTagLatestDataRealm, - luid: LocalIdentifier, - sequenceNumber: Int? - ) -> RuuviTagSensorRecordStruct { - let lastRecordResult = RuuviTagSensorRecordStruct( - luid: luid, - date: lastRecord.date, - source: lastRecord.source, - macId: nil, - rssi: lastRecord.rssi.value, - temperature: lastRecord.unitTemperature, - humidity: lastRecord.unitHumidity, - pressure: lastRecord.unitPressure, - acceleration: lastRecord.acceleration, - voltage: lastRecord.unitVoltage, - movementCounter: lastRecord.movementCounter.value, - measurementSequenceNumber: sequenceNumber, - txPower: lastRecord.txPower.value, - temperatureOffset: lastRecord.temperatureOffset, - humidityOffset: lastRecord.humidityOffset, - pressureOffset: lastRecord.pressureOffset - ) - return lastRecordResult - } -} - -// swiftlint:enable file_length type_body_length diff --git a/Packages/RuuviPersistence/target.yml b/Packages/RuuviPersistence/target.yml index 12a583477..392446f67 100644 --- a/Packages/RuuviPersistence/target.yml +++ b/Packages/RuuviPersistence/target.yml @@ -13,9 +13,6 @@ targets: dependencies: - package: Humidity - package: Future - - package: Realm - - package: Realm - product: RealmSwift - package: GRDB - target: RuuviOntology - target: RuuviContext diff --git a/Packages/RuuviPool/Sources/RuuviPool/RuuviPoolFactory.swift b/Packages/RuuviPool/Sources/RuuviPool/RuuviPoolFactory.swift index ad33593b1..26b4f9c4c 100644 --- a/Packages/RuuviPool/Sources/RuuviPool/RuuviPoolFactory.swift +++ b/Packages/RuuviPool/Sources/RuuviPool/RuuviPoolFactory.swift @@ -5,7 +5,6 @@ import RuuviPersistence public protocol RuuviPoolFactory { func create( sqlite: RuuviPersistence, - realm: RuuviPersistence, idPersistence: RuuviLocalIDs, settings: RuuviLocalSettings, connectionPersistence: RuuviLocalConnections diff --git a/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolCoordinator.swift b/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolCoordinator.swift index ed66fc45d..1651f8991 100644 --- a/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolCoordinator.swift +++ b/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolCoordinator.swift @@ -4,23 +4,19 @@ import RuuviLocal import RuuviOntology import RuuviPersistence -// swiftlint:disable:next type_body_length final class RuuviPoolCoordinator: RuuviPool { private var sqlite: RuuviPersistence - private var realm: RuuviPersistence private var idPersistence: RuuviLocalIDs private var settings: RuuviLocalSettings private var connectionPersistence: RuuviLocalConnections init( sqlite: RuuviPersistence, - realm: RuuviPersistence, idPersistence: RuuviLocalIDs, settings: RuuviLocalSettings, connectionPersistence: RuuviLocalConnections ) { self.sqlite = sqlite - self.realm = realm self.idPersistence = idPersistence self.settings = settings self.connectionPersistence = connectionPersistence @@ -40,11 +36,7 @@ final class RuuviPoolCoordinator: RuuviPool { promise.fail(error: .ruuviPersistence(error)) }) } else { - realm.create(ruuviTag).on(success: { result in - promise.succeed(value: result) - }, failure: { error in - promise.fail(error: .ruuviPersistence(error)) - }) + assertionFailure() } if let macId = ruuviTag.macId, let luid = ruuviTag.luid { idPersistence.set(mac: macId, for: luid) @@ -62,11 +54,7 @@ final class RuuviPoolCoordinator: RuuviPool { promise.fail(error: .ruuviPersistence(error)) }) } else { - realm.update(ruuviTag).on(success: { success in - promise.succeed(value: success) - }, failure: { error in - promise.fail(error: .ruuviPersistence(error)) - }) + assertionFailure() } if let macId = ruuviTag.macId, let luid = ruuviTag.luid { idPersistence.set(mac: macId, for: luid) @@ -91,14 +79,7 @@ final class RuuviPoolCoordinator: RuuviPool { promise.fail(error: .ruuviPersistence(error)) }) } else { - realm.delete(ruuviTag).on(success: { [weak self] success in - if let luid = ruuviTag.luid { - self?.connectionPersistence.setKeepConnection(false, for: luid) - } - promise.succeed(value: success) - }, failure: { error in - promise.fail(error: .ruuviPersistence(error)) - }) + assertionFailure() } return promise.future } @@ -119,11 +100,7 @@ final class RuuviPoolCoordinator: RuuviPool { promise.fail(error: .ruuviPersistence(error)) }) } else { - realm.create(record).on(success: { success in - promise.succeed(value: success) - }, failure: { error in - promise.fail(error: .ruuviPersistence(error)) - }) + assertionFailure() } return promise.future } @@ -144,11 +121,7 @@ final class RuuviPoolCoordinator: RuuviPool { promise.fail(error: .ruuviPersistence(error)) }) } else { - realm.createLast(record).on(success: { success in - promise.succeed(value: success) - }, failure: { error in - promise.fail(error: .ruuviPersistence(error)) - }) + assertionFailure() } return promise.future } @@ -169,11 +142,7 @@ final class RuuviPoolCoordinator: RuuviPool { promise.fail(error: .ruuviPersistence(error)) }) } else { - realm.updateLast(record).on(success: { success in - promise.succeed(value: success) - }, failure: { error in - promise.fail(error: .ruuviPersistence(error)) - }) + assertionFailure() } return promise.future } @@ -181,8 +150,7 @@ final class RuuviPoolCoordinator: RuuviPool { func deleteLast(_ ruuviTagId: String) -> Future { let promise = Promise() let sqliteOperation = sqlite.deleteLatest(ruuviTagId) - let realmOpearion = realm.deleteLatest(ruuviTagId) - Future.zip(sqliteOperation, realmOpearion).on(success: { _ in + sqliteOperation.on(success: { _ in promise.succeed(value: true) }, failure: { error in promise.fail(error: .ruuviPersistence(error)) @@ -193,10 +161,8 @@ final class RuuviPoolCoordinator: RuuviPool { func create(_ records: [RuuviTagSensorRecord]) -> Future { let promise = Promise() let sqliteRecords = records.filter { $0.macId != nil } - let realmRecords = records.filter { $0.macId == nil } let sqliteOperation = sqlite.create(sqliteRecords) - let realmOpearion = realm.create(realmRecords) - Future.zip(sqliteOperation, realmOpearion).on(success: { _ in + sqliteOperation.on(success: { _ in promise.succeed(value: true) }, failure: { error in promise.fail(error: .ruuviPersistence(error)) @@ -207,9 +173,8 @@ final class RuuviPoolCoordinator: RuuviPool { func deleteAllRecords(_ ruuviTagId: String) -> Future { let promise = Promise() let sqliteOperation = sqlite.deleteAllRecords(ruuviTagId) - let realmOpearion = realm.deleteAllRecords(ruuviTagId) let cleanUpOperation = sqlite.cleanupDBSpace() - Future.zip(sqliteOperation, realmOpearion, cleanUpOperation).on(success: { _ in + Future.zip(sqliteOperation, cleanUpOperation).on(success: { _ in promise.succeed(value: true) }, failure: { error in promise.fail(error: .ruuviPersistence(error)) @@ -220,9 +185,8 @@ final class RuuviPoolCoordinator: RuuviPool { func deleteAllRecords(_ ruuviTagId: String, before date: Date) -> Future { let promise = Promise() let sqliteOperation = sqlite.deleteAllRecords(ruuviTagId, before: date) - let realmOpearion = realm.deleteAllRecords(ruuviTagId, before: date) let cleanUpOperation = sqlite.cleanupDBSpace() - Future.zip(sqliteOperation, realmOpearion, cleanUpOperation).on(success: { _ in + Future.zip(sqliteOperation, cleanUpOperation).on(success: { _ in promise.succeed(value: true) }, failure: { error in promise.fail(error: .ruuviPersistence(error)) @@ -261,17 +225,7 @@ final class RuuviPoolCoordinator: RuuviPool { promise.fail(error: .ruuviPersistence(error)) }) } else { - realm.updateOffsetCorrection( - type: type, - with: value, - of: ruuviTag, - lastOriginalRecord: record - ) - .on(success: { settings in - promise.succeed(value: settings) - }, failure: { error in - promise.fail(error: .ruuviPersistence(error)) - }) + assertionFailure() } return promise.future } diff --git a/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolFactoryCoordinator.swift b/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolFactoryCoordinator.swift index 61e316c53..b32dae449 100644 --- a/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolFactoryCoordinator.swift +++ b/Packages/RuuviPool/Sources/RuuviPoolCoordinator/RuuviPoolFactoryCoordinator.swift @@ -7,14 +7,12 @@ public final class RuuviPoolFactoryCoordinator: RuuviPoolFactory { public func create( sqlite: RuuviPersistence, - realm: RuuviPersistence, idPersistence: RuuviLocalIDs, settings: RuuviLocalSettings, connectionPersistence: RuuviLocalConnections ) -> RuuviPool { RuuviPoolCoordinator( sqlite: sqlite, - realm: realm, idPersistence: idPersistence, settings: settings, connectionPersistence: connectionPersistence diff --git a/Packages/RuuviReactor/Sources/RuuviReactor/RuuviReactorFactory.swift b/Packages/RuuviReactor/Sources/RuuviReactor/RuuviReactorFactory.swift index 50c6c931b..db8e26cb8 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactor/RuuviReactorFactory.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactor/RuuviReactorFactory.swift @@ -5,8 +5,6 @@ import RuuviPersistence public protocol RuuviReactorFactory { func create( sqliteContext: SQLiteContext, - realmContext: RealmContext, - sqlitePersistence: RuuviPersistence, - realmPersistence: RuuviPersistence + sqlitePersistence: RuuviPersistence ) -> RuuviReactor } diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLastRecordSubjectCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLastRecordSubjectCombine.swift index 337ebac55..316049575 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLastRecordSubjectCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLastRecordSubjectCombine.swift @@ -1,7 +1,6 @@ import Combine import Foundation import GRDB -import RealmSwift import RuuviContext import RuuviOntology @@ -9,26 +8,19 @@ final class RuuviTagLastRecordSubjectCombine { var isServing: Bool = false private var sqlite: SQLiteContext - private var realm: RealmContext private var luid: LocalIdentifier? private var macId: MACIdentifier? let subject = PassthroughSubject() - private var ruuviTagDataRealmToken: NotificationToken? private var ruuviTagDataTransactionObserver: TransactionObserver? - deinit { - ruuviTagDataRealmToken?.invalidate() - } init( luid: LocalIdentifier?, macId: MACIdentifier?, - sqlite: SQLiteContext, - realm: RealmContext + sqlite: SQLiteContext ) { self.sqlite = sqlite - self.realm = realm self.luid = luid self.macId = macId } @@ -49,23 +41,5 @@ final class RuuviTagLastRecordSubjectCombine { self?.subject.send(lastRecord) } } - let results = realm.main.objects(RuuviTagDataRealm.self) - .filter( - "ruuviTag.uuid == %@ || ruuviTag.mac == %@", - luid?.value ?? "invalid", - macId?.value ?? "invalid" - ) - .sorted(byKeyPath: "date") - ruuviTagDataRealmToken = results.observe { [weak self] change in - guard let sSelf = self else { return } - switch change { - case let .update(records, _, _, _): - if let lastRecord = records.last?.any { - sSelf.subject.send(lastRecord) - } - default: - break - } - } } } diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLatestRecordSubjectCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLatestRecordSubjectCombine.swift index a31ef4622..d01e141ea 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLatestRecordSubjectCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagLatestRecordSubjectCombine.swift @@ -1,7 +1,6 @@ import Combine import Foundation import GRDB -import RealmSwift import RuuviContext import RuuviOntology @@ -9,26 +8,19 @@ final class RuuviTagLatestRecordSubjectCombine { var isServing: Bool = false private var sqlite: SQLiteContext - private var realm: RealmContext private var luid: LocalIdentifier? private var macId: MACIdentifier? let subject = PassthroughSubject() - private var ruuviTagDataRealmToken: NotificationToken? private var ruuviTagDataTransactionObserver: TransactionObserver? - deinit { - ruuviTagDataRealmToken?.invalidate() - } init( luid: LocalIdentifier?, macId: MACIdentifier?, - sqlite: SQLiteContext, - realm: RealmContext + sqlite: SQLiteContext ) { self.sqlite = sqlite - self.realm = realm self.luid = luid self.macId = macId } @@ -49,23 +41,5 @@ final class RuuviTagLatestRecordSubjectCombine { self?.subject.send(lastRecord) } } - let results = realm.main.objects(RuuviTagLatestDataRealm.self) - .filter( - "ruuviTag.uuid == %@ || ruuviTag.mac == %@", - luid?.value ?? "invalid", - macId?.value ?? "invalid" - ) - .sorted(byKeyPath: "date") - ruuviTagDataRealmToken = results.observe { [weak self] change in - guard let sSelf = self else { return } - switch change { - case let .update(records, _, _, _): - if let lastRecord = records.last?.any { - sSelf.subject.send(lastRecord) - } - default: - break - } - } } } diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagRecordSubjectCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagRecordSubjectCombine.swift index 93d7f8c72..a5762a1ed 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagRecordSubjectCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagRecordSubjectCombine.swift @@ -1,7 +1,6 @@ import Combine import Foundation import GRDB -import RealmSwift import RuuviContext import RuuviOntology @@ -9,27 +8,19 @@ final class RuuviTagRecordSubjectCombine { var isServing: Bool = false private var sqlite: SQLiteContext - private var realm: RealmContext private var luid: LocalIdentifier? private var macId: MACIdentifier? let subject = PassthroughSubject<[AnyRuuviTagSensorRecord], Never>() - private var ruuviTagDataRealmToken: NotificationToken? - private var ruuviTagDataRealmCache = [AnyRuuviTagSensorRecord]() private var ruuviTagDataTransactionObserver: TransactionObserver? - deinit { - ruuviTagDataRealmToken?.invalidate() - } init( luid: LocalIdentifier?, macId: MACIdentifier?, - sqlite: SQLiteContext, - realm: RealmContext + sqlite: SQLiteContext ) { self.sqlite = sqlite - self.realm = realm self.luid = luid self.macId = macId } @@ -49,29 +40,5 @@ final class RuuviTagRecordSubjectCombine { [weak self] records in self?.subject.send(records.map(\.any)) } - - let results = realm.main.objects(RuuviTagDataRealm.self) - .filter( - "ruuviTag.uuid == %@ || ruuviTag.mac == %@", - luid?.value ?? "invalid", - macId?.value ?? "invalid" - ) - .sorted(byKeyPath: "date") - ruuviTagDataRealmCache = results.compactMap(\.any) - ruuviTagDataRealmToken = results.observe { [weak self] change in - guard let sSelf = self else { return } - switch change { - case let .initial(records): - if records.count > 0 { - sSelf.subject.send(records.compactMap(\.any)) - } - case let .update(records, _, _, _): - if records.count > 0 { - sSelf.subject.send(records.compactMap(\.any)) - } - default: - break - } - } } } diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagSubjectCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagSubjectCombine.swift index f5ae07566..eb62bac27 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagSubjectCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/RuuviTagSubjectCombine.swift @@ -1,30 +1,20 @@ import Combine import Foundation import GRDB -import RealmSwift import RuuviContext import RuuviOntology final class RuuviTagSubjectCombine { var sqlite: SQLiteContext - var realm: RealmContext let insertSubject = PassthroughSubject() let updateSubject = PassthroughSubject() let deleteSubject = PassthroughSubject() private var ruuviTagController: FetchedRecordsController - private var ruuviTagsRealmToken: NotificationToken? - private var ruuviTagRealmCache = [AnyRuuviTagSensor]() - deinit { - ruuviTagsRealmToken?.invalidate() - } - - // swiftlint:disable:next cyclomatic_complexity function_body_length - init(sqlite: SQLiteContext, realm: RealmContext) { + init(sqlite: SQLiteContext) { self.sqlite = sqlite - self.realm = realm let request = RuuviTagSQLite.order(RuuviTagSQLite.versionColumn) ruuviTagController = try! FetchedRecordsController(sqlite.database.dbPool, request: request) @@ -49,35 +39,5 @@ final class RuuviTagSubjectCombine { break } }) - - DispatchQueue.main.async { [weak self] in - guard let sSelf = self else { return } - let results = sSelf.realm.main.objects(RuuviTagRealm.self) - sSelf.ruuviTagRealmCache = results.map(\.struct.any) - sSelf.ruuviTagsRealmToken = results.observe { [weak self] change in - guard let sSelf = self else { return } - switch change { - case let .update(ruuviSensors, deletions, insertions, modifications): - for del in deletions { - sSelf.deleteSubject.send(sSelf.ruuviTagRealmCache[del].struct.any) - } - sSelf.ruuviTagRealmCache = sSelf.ruuviTagRealmCache - .enumerated() - .filter { !deletions.contains($0.offset) } - .map(\.element) - for ins in insertions { - sSelf.insertSubject.send(ruuviSensors[ins].struct.any) - // TODO: test if ok with multiple - sSelf.ruuviTagRealmCache.insert(ruuviSensors[ins].struct.any, at: ins) - } - for mod in modifications { - sSelf.updateSubject.send(ruuviSensors[mod].struct.any) - sSelf.ruuviTagRealmCache[mod] = ruuviSensors[mod].struct.any - } - default: - break - } - } - } } } diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/SensorSettingsCombine.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/SensorSettingsCombine.swift index 6fa2d6ab8..7a897bb29 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/SensorSettingsCombine.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorCombine/SensorSettingsCombine.swift @@ -1,7 +1,6 @@ import Combine import Foundation import GRDB -import RealmSwift import RuuviContext import RuuviOntology @@ -9,31 +8,21 @@ final class SensorSettingsCombine { var luid: LocalIdentifier? var macId: MACIdentifier? var sqlite: SQLiteContext - var realm: RealmContext let insertSubject = PassthroughSubject() let updateSubject = PassthroughSubject() let deleteSubject = PassthroughSubject() private var ruuviTagController: FetchedRecordsController - private var ruuviTagsRealmToken: NotificationToken? - private var ruuviTagRealmCache = [SensorSettings]() - deinit { - ruuviTagsRealmToken?.invalidate() - } - - // swiftlint:disable:next cyclomatic_complexity function_body_length init( luid: LocalIdentifier?, macId: MACIdentifier?, - sqlite: SQLiteContext, - realm: RealmContext + sqlite: SQLiteContext ) { self.luid = luid self.macId = macId self.sqlite = sqlite - self.realm = realm let request = SensorSettingsSQLite .filter( @@ -56,40 +45,5 @@ final class SensorSettingsCombine { break } }) - - DispatchQueue.main.async { [weak self] in - guard let sSelf = self else { return } - let results = sSelf.realm.main.objects(SensorSettingsRealm.self) - .filter( - "luid == %@ || macId == %@", - luid?.value ?? "invalid", - macId?.value ?? "invalid" - ) - sSelf.ruuviTagRealmCache = results.map(\.sensorSettings) - sSelf.ruuviTagsRealmToken = results.observe { [weak self] change in - guard let sSelf = self else { return } - switch change { - case let .update(sensorSettings, deletions, insertions, modifications): - for del in deletions { - sSelf.deleteSubject.send(sSelf.ruuviTagRealmCache[del]) - } - sSelf.ruuviTagRealmCache = sSelf.ruuviTagRealmCache - .enumerated() - .filter { !deletions.contains($0.offset) } - .map(\.element) - for ins in insertions { - sSelf.insertSubject.send(sensorSettings[ins].sensorSettings) - // TODO: test if ok with multiple - sSelf.ruuviTagRealmCache.insert(sensorSettings[ins].sensorSettings, at: ins) - } - for mod in modifications { - sSelf.updateSubject.send(sensorSettings[mod].sensorSettings) - sSelf.ruuviTagRealmCache[mod] = sensorSettings[mod].sensorSettings - } - default: - break - } - } - } } } diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorFactoryImpl.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorFactoryImpl.swift index cfa55b8f2..dcf974125 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorFactoryImpl.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorFactoryImpl.swift @@ -7,15 +7,11 @@ public final class RuuviReactorFactoryImpl: RuuviReactorFactory { public func create( sqliteContext: SQLiteContext, - realmContext: RealmContext, - sqlitePersistence: RuuviPersistence, - realmPersistence: RuuviPersistence + sqlitePersistence: RuuviPersistence ) -> RuuviReactor { RuuviReactorImpl( sqliteContext: sqliteContext, - realmContext: realmContext, - sqlitePersistence: sqlitePersistence, - realmPersistence: realmPersistence + sqlitePersistence: sqlitePersistence ) } } diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift index 9d3cf3ec8..4428c1521 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift @@ -7,28 +7,20 @@ import RuuviPersistence class RuuviReactorImpl: RuuviReactor { typealias SQLiteEntity = RuuviTagSQLite - typealias RealmEntity = RuuviTagRealm private let sqliteContext: SQLiteContext - private let realmContext: RealmContext private let sqlitePersistence: RuuviPersistence - private let realmPersistence: RuuviPersistence init( sqliteContext: SQLiteContext, - realmContext: RealmContext, - sqlitePersistence: RuuviPersistence, - realmPersistence: RuuviPersistence + sqlitePersistence: RuuviPersistence ) { self.sqliteContext = sqliteContext - self.realmContext = realmContext self.sqlitePersistence = sqlitePersistence - self.realmPersistence = realmPersistence } private lazy var entityCombine = RuuviTagSubjectCombine( - sqlite: sqliteContext, - realm: realmContext + sqlite: sqliteContext ) private lazy var recordCombines = [String: RuuviTagRecordSubjectCombine]() private lazy var lastRecordCombines = [String: RuuviTagLastRecordSubjectCombine]() @@ -46,8 +38,7 @@ class RuuviReactorImpl: RuuviReactor { let combine = RuuviTagRecordSubjectCombine( luid: luid, macId: nil, - sqlite: sqliteContext, - realm: realmContext + sqlite: sqliteContext ) recordCombines[luid.value] = combine recordCombine = combine @@ -65,10 +56,9 @@ class RuuviReactorImpl: RuuviReactor { func observe(_ block: @escaping (RuuviReactorChange) -> Void) -> RuuviReactorToken { let sqliteOperation = sqlitePersistence.readAll() - let realmOperation = realmPersistence.readAll() - Future.zip(realmOperation, sqliteOperation) - .on(success: { realmEntities, sqliteEntities in - let combinedValues = sqliteEntities + realmEntities + sqliteOperation + .on(success: { sqliteEntities in + let combinedValues = sqliteEntities block(.initial(combinedValues)) }, failure: { error in block(.error(.ruuviPersistence(error))) @@ -95,11 +85,11 @@ class RuuviReactorImpl: RuuviReactor { _ block: @escaping (RuuviReactorChange) -> Void ) -> RuuviReactorToken { let sqliteOperation = sqlitePersistence.readLast(ruuviTag) - let realmOperation = realmPersistence.readLast(ruuviTag) - Future.zip(realmOperation, sqliteOperation).on(success: { realmRecord, sqliteRecord in - let result = [realmRecord, sqliteRecord].compactMap { $0?.any }.last - block(.update(result)) - }) + sqliteOperation + .on(success: { sqliteRecord in + let result = [sqliteRecord].compactMap { $0?.any }.last + block(.update(result)) + }) var recordCombine: RuuviTagLastRecordSubjectCombine if let combine = lastRecordCombines[ruuviTag.id] { recordCombine = combine @@ -107,8 +97,7 @@ class RuuviReactorImpl: RuuviReactor { let combine = RuuviTagLastRecordSubjectCombine( luid: ruuviTag.luid, macId: ruuviTag.macId, - sqlite: sqliteContext, - realm: realmContext + sqlite: sqliteContext ) lastRecordCombines[ruuviTag.id] = combine recordCombine = combine @@ -129,9 +118,8 @@ class RuuviReactorImpl: RuuviReactor { _ block: @escaping (RuuviReactorChange) -> Void ) -> RuuviReactorToken { let sqliteOperation = sqlitePersistence.readLatest(ruuviTag) - let realmOperation = realmPersistence.readLatest(ruuviTag) - Future.zip(realmOperation, sqliteOperation).on(success: { realmRecord, sqliteRecord in - let result = [realmRecord, sqliteRecord].compactMap { $0?.any }.last + sqliteOperation.on(success: { sqliteRecord in + let result = [sqliteRecord].compactMap { $0?.any }.last block(.update(result)) }) var recordCombine: RuuviTagLatestRecordSubjectCombine @@ -141,8 +129,7 @@ class RuuviReactorImpl: RuuviReactor { let combine = RuuviTagLatestRecordSubjectCombine( luid: ruuviTag.luid, macId: ruuviTag.macId, - sqlite: sqliteContext, - realm: realmContext + sqlite: sqliteContext ) latestRecordCombines[ruuviTag.id] = combine recordCombine = combine @@ -162,15 +149,11 @@ class RuuviReactorImpl: RuuviReactor { _ ruuviTag: RuuviTagSensor, _ block: @escaping (RuuviReactorChange) -> Void ) -> RuuviReactorToken { - sqlitePersistence.readSensorSettings(ruuviTag).on { [weak self] sqliteRecord in + sqlitePersistence.readSensorSettings(ruuviTag).on { sqliteRecord in if let sensorSettings = sqliteRecord { block(.update(sensorSettings)) } else { - self?.realmPersistence.readSensorSettings(ruuviTag).on(success: { realmRecord in - if let sensorSettings = realmRecord { - block(.update(sensorSettings)) - } - }) + assertionFailure() } } var sensorSettingsCombine: SensorSettingsCombine @@ -180,8 +163,7 @@ class RuuviReactorImpl: RuuviReactor { let combine = SensorSettingsCombine( luid: ruuviTag.luid, macId: ruuviTag.macId, - sqlite: sqliteContext, - realm: realmContext + sqlite: sqliteContext ) sensorSettingsCombines[ruuviTag.id] = combine sensorSettingsCombine = combine diff --git a/Packages/RuuviReactor/target.yml b/Packages/RuuviReactor/target.yml index 409ac880d..b98d45b15 100644 --- a/Packages/RuuviReactor/target.yml +++ b/Packages/RuuviReactor/target.yml @@ -14,9 +14,6 @@ targets: - package: Humidity - package: Future - package: GRDB - - package: Realm - - package: Realm - product: RealmSwift - target: RuuviOntology - target: RuuviPersistence - target: RuuviContext diff --git a/Packages/RuuviStorage/Sources/RuuviStorage/RuuviStorage.swift b/Packages/RuuviStorage/Sources/RuuviStorage/RuuviStorage.swift index 06d9e8f2e..01db4246e 100644 --- a/Packages/RuuviStorage/Sources/RuuviStorage/RuuviStorage.swift +++ b/Packages/RuuviStorage/Sources/RuuviStorage/RuuviStorage.swift @@ -41,5 +41,5 @@ public protocol RuuviStorage { } public protocol RuuviStorageFactory { - func create(realm: RuuviPersistence, sqlite: RuuviPersistence) -> RuuviStorage + func create(sqlite: RuuviPersistence) -> RuuviStorage } diff --git a/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageCoordinator.swift b/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageCoordinator.swift index 62a9d441e..088d87f9b 100644 --- a/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageCoordinator.swift +++ b/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageCoordinator.swift @@ -5,15 +5,12 @@ import RuuviPersistence final class RuuviStorageCoordinator: RuuviStorage { private let sqlite: RuuviPersistence - private let realm: RuuviPersistence - init(sqlite: RuuviPersistence, realm: RuuviPersistence) { + init(sqlite: RuuviPersistence) { self.sqlite = sqlite - self.realm = realm } func readOne(_ ruuviTagId: String) -> Future { - // TODO: @rinat respect realm let promise = Promise() sqlite.readOne(ruuviTagId).on(success: { sensor in promise.succeed(value: sensor) @@ -26,9 +23,8 @@ final class RuuviStorageCoordinator: RuuviStorage { func readAll(_ ruuviTagId: String) -> Future<[RuuviTagSensorRecord], RuuviStorageError> { let promise = Promise<[RuuviTagSensorRecord], RuuviStorageError>() let sqliteOperation = sqlite.readAll(ruuviTagId) - let realmOperation = realm.readAll(ruuviTagId) - Future.zip(sqliteOperation, realmOperation).on(success: { sqliteEntities, realmEntities in - promise.succeed(value: sqliteEntities + realmEntities) + sqliteOperation.on(success: { sqliteEntities in + promise.succeed(value: sqliteEntities) }, failure: { error in promise.fail(error: .ruuviPersistence(error)) }) @@ -38,10 +34,9 @@ final class RuuviStorageCoordinator: RuuviStorage { func readAll() -> Future<[AnyRuuviTagSensor], RuuviStorageError> { let promise = Promise<[AnyRuuviTagSensor], RuuviStorageError>() let sqliteOperation = sqlite.readAll() - let realmOperation = realm.readAll() - Future.zip(sqliteOperation, realmOperation) - .on(success: { sqliteEntities, realmEntities in - let combinedValues = sqliteEntities + realmEntities + sqliteOperation + .on(success: { sqliteEntities in + let combinedValues = sqliteEntities promise.succeed(value: combinedValues.map(\.any)) }, failure: { error in promise.fail(error: .ruuviPersistence(error)) @@ -52,9 +47,8 @@ final class RuuviStorageCoordinator: RuuviStorage { func readAll(_ id: String, after date: Date) -> Future<[RuuviTagSensorRecord], RuuviStorageError> { let promise = Promise<[RuuviTagSensorRecord], RuuviStorageError>() let sqliteOperation = sqlite.readAll(id, after: date) - let realmOperation = realm.readAll(id, after: date) - Future.zip(sqliteOperation, realmOperation).on(success: { sqliteEntities, realmEntities in - promise.succeed(value: sqliteEntities + realmEntities) + sqliteOperation.on(success: { sqliteEntities in + promise.succeed(value: sqliteEntities) }, failure: { error in promise.fail(error: .ruuviPersistence(error)) }) @@ -68,9 +62,8 @@ final class RuuviStorageCoordinator: RuuviStorage { ) -> Future<[RuuviTagSensorRecord], RuuviStorageError> { let promise = Promise<[RuuviTagSensorRecord], RuuviStorageError>() let sqliteOperation = sqlite.read(id, after: date, with: interval) - let realmOperation = realm.read(id, after: date, with: interval) - Future.zip(sqliteOperation, realmOperation).on(success: { sqliteEntities, realmEntities in - promise.succeed(value: sqliteEntities + realmEntities) + sqliteOperation.on(success: { sqliteEntities in + promise.succeed(value: sqliteEntities) }, failure: { error in promise.fail(error: .ruuviPersistence(error)) }) @@ -104,9 +97,8 @@ final class RuuviStorageCoordinator: RuuviStorage { ) -> Future<[RuuviTagSensorRecord], RuuviStorageError> { let promise = Promise<[RuuviTagSensorRecord], RuuviStorageError>() let sqliteOperation = sqlite.readAll(id, with: interval) - let realmOperation = realm.readAll(id, with: interval) - Future.zip(sqliteOperation, realmOperation).on(success: { sqliteEntities, realmEntities in - promise.succeed(value: sqliteEntities + realmEntities) + sqliteOperation.on(success: { sqliteEntities in + promise.succeed(value: sqliteEntities) }, failure: { error in promise.fail(error: .ruuviPersistence(error)) }) @@ -116,9 +108,8 @@ final class RuuviStorageCoordinator: RuuviStorage { func readLast(_ id: String, from: TimeInterval) -> Future<[RuuviTagSensorRecord], RuuviStorageError> { let promise = Promise<[RuuviTagSensorRecord], RuuviStorageError>() let sqliteOperation = sqlite.readLast(id, from: from) - let realmOperation = realm.readLast(id, from: from) - Future.zip(sqliteOperation, realmOperation).on(success: { sqliteEntities, realmEntities in - promise.succeed(value: sqliteEntities + realmEntities) + sqliteOperation.on(success: { sqliteEntities in + promise.succeed(value: sqliteEntities) }, failure: { error in promise.fail(error: .ruuviPersistence(error)) }) @@ -134,11 +125,7 @@ final class RuuviStorageCoordinator: RuuviStorage { promise.fail(error: .ruuviPersistence(error)) }) } else { - realm.readLast(ruuviTag).on(success: { record in - promise.succeed(value: record) - }, failure: { error in - promise.fail(error: .ruuviPersistence(error)) - }) + assertionFailure() } return promise.future } @@ -152,11 +139,7 @@ final class RuuviStorageCoordinator: RuuviStorage { promise.fail(error: .ruuviPersistence(error)) }) } else { - realm.readLatest(ruuviTag).on(success: { record in - promise.succeed(value: record) - }, failure: { error in - promise.fail(error: .ruuviPersistence(error)) - }) + assertionFailure() } return promise.future } @@ -164,9 +147,8 @@ final class RuuviStorageCoordinator: RuuviStorage { func getStoredTagsCount() -> Future { let promise = Promise() let sqliteOperation = sqlite.getStoredTagsCount() - let realmOperation = realm.getStoredTagsCount() - Future.zip(sqliteOperation, realmOperation).on(success: { sqliteEntities, realmEntities in - promise.succeed(value: sqliteEntities + realmEntities) + sqliteOperation.on(success: { sqliteEntities in + promise.succeed(value: sqliteEntities) }, failure: { error in promise.fail(error: .ruuviPersistence(error)) }) @@ -196,9 +178,8 @@ final class RuuviStorageCoordinator: RuuviStorage { func getStoredMeasurementsCount() -> Future { let promise = Promise() let sqliteOperation = sqlite.getStoredMeasurementsCount() - let realmOperation = realm.getStoredMeasurementsCount() - Future.zip(sqliteOperation, realmOperation).on(success: { sqliteEntities, realmEntities in - promise.succeed(value: sqliteEntities + realmEntities) + sqliteOperation.on(success: { sqliteEntities in + promise.succeed(value: sqliteEntities) }, failure: { error in promise.fail(error: .ruuviPersistence(error)) }) @@ -214,11 +195,7 @@ final class RuuviStorageCoordinator: RuuviStorage { promise.fail(error: .ruuviPersistence(error)) }) } else { - realm.readSensorSettings(ruuviTag).on(success: { settings in - promise.succeed(value: settings) - }, failure: { error in - promise.fail(error: .ruuviPersistence(error)) - }) + assertionFailure() } return promise.future } diff --git a/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageFactoryCoordinator.swift b/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageFactoryCoordinator.swift index c141fcb6e..61931b19d 100644 --- a/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageFactoryCoordinator.swift +++ b/Packages/RuuviStorage/Sources/RuuviStorageCoordinator/RuuviStorageFactoryCoordinator.swift @@ -4,7 +4,7 @@ import RuuviPersistence public final class RuuviStorageFactoryCoordinator: RuuviStorageFactory { public init() {} - public func create(realm: RuuviPersistence, sqlite: RuuviPersistence) -> RuuviStorage { - RuuviStorageCoordinator(sqlite: sqlite, realm: realm) + public func create(sqlite: RuuviPersistence) -> RuuviStorage { + RuuviStorageCoordinator(sqlite: sqlite) } } diff --git a/project.yml b/project.yml index f40535fbd..47bd9a3ae 100644 --- a/project.yml +++ b/project.yml @@ -40,10 +40,7 @@ targetTemplates: CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString: "$(MARKETING_VERSION)" CFBundleVersion: $(CURRENT_PROJECT_VERSION) - MERGEABLE_LIBRARY: true - configs: - Debug: - OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries + MERGEABLE_LIBRARY: false Module: name: "${target_name}" type: framework @@ -62,10 +59,7 @@ targetTemplates: CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString: "$(MARKETING_VERSION)" CFBundleVersion: $(CURRENT_PROJECT_VERSION) - MERGEABLE_LIBRARY: true - configs: - Debug: - OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries + MERGEABLE_LIBRARY: false CommonFramework: name: "${target_name}" type: framework @@ -84,11 +78,7 @@ targetTemplates: CFBundlePackageType: $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString: "$(MARKETING_VERSION)" CFBundleVersion: $(CURRENT_PROJECT_VERSION) - MERGEABLE_LIBRARY: true - configs: - Debug: - OTHER_LDFLAGS: -Xlinker -no_warn_duplicate_libraries - + MERGEABLE_LIBRARY: false packages: BTKit: url: https://github.com/ruuvi/BTKit @@ -123,9 +113,6 @@ packages: KeychainAccess: url: https://github.com/kishikawakatsumi/KeychainAccess from: 4.2.1 - Realm: - url: https://github.com/realm/realm-cocoa - from: 10.8.0 GRDB: url: https://github.com/groue/GRDB.swift from: 4.14.0 From 784b18083c9f43322bce866d55448fde98301dff Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 16 Dec 2023 16:29:35 +0200 Subject: [PATCH 51/84] Fix type in table creation (#1790) Fixes typo in column creation logic --- .../Sources/RuuviOntologySQLite/SensorSettingsSQLite.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/SensorSettingsSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/SensorSettingsSQLite.swift index 1043b905c..8e597921f 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/SensorSettingsSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/SensorSettingsSQLite.swift @@ -82,7 +82,7 @@ extension SensorSettingsSQLite: PersistableRecord { public extension SensorSettingsSQLite { static func createTable(in db: Database) throws { try db.create(table: SensorSettingsSQLite.databaseTableName, body: { table in - table.column(RuuviTagDataSQLite.idColumn.name, .text).notNull().primaryKey(onConflict: .replace) + table.column(SensorSettingsSQLite.idColumn.name, .text).notNull().primaryKey(onConflict: .replace) table.column(SensorSettingsSQLite.luidColumn.name, .text) table.column(SensorSettingsSQLite.macIdColumn.name, .text) table.column(SensorSettingsSQLite.temperatureOffsetColumn.name, .double) From 7c395fcadb0e43eb1dba54555796b94ba092563c Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 16 Dec 2023 16:29:49 +0200 Subject: [PATCH 52/84] Remove dependency on RuuviLocalization in RuuviDFU (#1791) Motivation: for single used string for the invalid arg case its not necessary to link against RuuviLocalization --- Packages/RuuviDFU/Sources/RuuviDFU/RuuviDFUError.swift | 7 ------- Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift | 3 ++- Packages/RuuviDFU/target.yml | 1 - 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/Packages/RuuviDFU/Sources/RuuviDFU/RuuviDFUError.swift b/Packages/RuuviDFU/Sources/RuuviDFU/RuuviDFUError.swift index dcb111ca0..aa6c7cd43 100644 --- a/Packages/RuuviDFU/Sources/RuuviDFU/RuuviDFUError.swift +++ b/Packages/RuuviDFU/Sources/RuuviDFU/RuuviDFUError.swift @@ -1,13 +1,6 @@ import Foundation -import RuuviLocalization public struct RuuviDfuError: Error { - public static let invalidFirmwareFile = RuuviDfuError( - description: RuuviLocalization.RuuviDfuError.invalidFirmwareFile - ) - public static let failedToConstructUUID = RuuviDfuError( - description: RuuviLocalization.RuuviDfuError.failedToConstructUUID - ) public let description: String public init(description: String) { self.description = description diff --git a/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift b/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift index 04ac983ef..a9f467d14 100644 --- a/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift +++ b/Packages/RuuviDFU/Sources/RuuviDFUImpl/DfuFlasher.swift @@ -32,7 +32,8 @@ class DfuFlasher: NSObject { ) -> AnyPublisher { guard let uuid = UUID(uuidString: uuid) else { - return Fail(error: RuuviDfuError.failedToConstructUUID).eraseToAnyPublisher() + assertionFailure("Invalid UUID") + return Fail(error: RuuviDfuError(description: "Invalid UUID")).eraseToAnyPublisher() } let subject = PassthroughSubject() self.subject = subject diff --git a/Packages/RuuviDFU/target.yml b/Packages/RuuviDFU/target.yml index 747227eb2..20cd7d52d 100644 --- a/Packages/RuuviDFU/target.yml +++ b/Packages/RuuviDFU/target.yml @@ -8,4 +8,3 @@ targets: name: DFU dependencies: - package: NordicDFU - - target: RuuviLocalization From e804d3fc5e61ed0421fb05e1690bfb1d2739c26b Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 16 Dec 2023 18:57:55 +0200 Subject: [PATCH 53/84] Firmware update popup for df3 (#1792) * Firmware update popup for df3 Implements firmware update alert when adding df3 tag * disable dismiss on firmware update * update localization --- .../VMP/Presenter/DiscoverPresenter.swift | 37 ++++++++++++++++--- .../VMP/View/DiscoverViewInput.swift | 3 ++ .../VMP/View/DiscoverViewOutput.swift | 1 + .../Table/DiscoverTableViewController.swift | 14 +++++++ .../RuuviFirmware/FirmwarePresenter.swift | 21 ++++++++--- .../Sources/RuuviFirmware/RuuviFirmware.swift | 2 + .../RuuviReactorImpl/RuuviReactorImpl.swift | 2 - station.localization | 2 +- 8 files changed, 69 insertions(+), 13 deletions(-) diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift index 2b4075b2d..62d0bfe2c 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift @@ -41,6 +41,7 @@ class DiscoverPresenter: NSObject, RuuviDiscover { var ruuviOwnershipService: RuuviServiceOwnership! var firmwareBuilder: RuuviFirmwareBuilder! + private weak var firmwareModule: RuuviFirmware? private weak var view: DiscoverViewInput? private var accessQueue = DispatchQueue( label: "com.ruuviDiscover.accessQueue", attributes: .concurrent @@ -122,11 +123,15 @@ extension DiscoverPresenter: DiscoverViewOutput { func viewDidChoose(device: DiscoverRuuviTagViewModel, displayName: String) { if let ruuviTag = ruuviTags.first(where: { $0.luid?.any != nil && $0.luid?.any == device.luid?.any }) { - addRuuviTagOwnership( - for: ruuviTag, - displayName: displayName, - firmwareVersion: nil - ) + if device.mac != nil { + addRuuviTagOwnership( + for: ruuviTag, + displayName: displayName, + firmwareVersion: nil + ) + } else { + view?.showUpdateFirmwareDialog(for: ruuviTag.uuid) + } } } @@ -260,6 +265,7 @@ extension DiscoverPresenter: DiscoverViewOutput { let firmwareModule = firmwareBuilder.build(uuid: sensor.id, currentFirmware: sensor.firmwareVersion) firmwareModule.output = self viewController.present(firmwareModule.viewController, animated: true) + self.firmwareModule = firmwareModule } func viewDidACopyMacAddress(of sensor: NFCSensor?) { @@ -269,6 +275,27 @@ extension DiscoverPresenter: DiscoverViewOutput { func viewDidACopySecret(of sensor: NFCSensor?) { UIPasteboard.general.string = sensor?.id } + + func viewDidConfirmToUpdateFirmware(for uuid: String) { + let firmwareModule = firmwareBuilder.build(uuid: uuid, currentFirmware: "<=2.5.9") + firmwareModule.output = self + let firmwareViewController = firmwareModule.viewController + firmwareViewController.presentationController?.delegate = self + viewController.present(firmwareViewController, animated: true) + self.firmwareModule = firmwareModule + } +} + +extension DiscoverPresenter: UIAdaptivePresentationControllerDelegate { + func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool { + guard presentationController.presentedViewController == firmwareModule?.viewController else { + return true + } + guard let firmwareModule, !firmwareModule.isSafeToDismiss() else { + return true + } + return false + } } // MARK: - RuuviFirmwareOutput diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift index b2e79c480..8bbd54b66 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewInput.swift @@ -20,4 +20,7 @@ protocol DiscoverViewInput: UIViewController { showUpgradeFirmware: Bool, isDF3: Bool ) + func showUpdateFirmwareDialog( + for uuid: String + ) } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewOutput.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewOutput.swift index ca40c6b1b..29d6ef6f6 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewOutput.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/DiscoverViewOutput.swift @@ -17,4 +17,5 @@ protocol DiscoverViewOutput { func viewDidACopyMacAddress(of sensor: NFCSensor?) func viewDidACopySecret(of sensor: NFCSensor?) func viewDidAskToUpgradeFirmware(of sensor: NFCSensor?) + func viewDidConfirmToUpdateFirmware(for uuid: String) } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift index 339a41852..b216daf2f 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift @@ -89,6 +89,20 @@ extension DiscoverTableViewController: DiscoverViewInput { session = nil } + func showUpdateFirmwareDialog( + for uuid: String + ) { + let title = RuuviLocalization.DiscoverTable.UpdateFirmware.title + let message = RuuviLocalization.DiscoverTable.UpdateFirmware.message + let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) + let cancelTitle = RuuviLocalization.cancel + alert.addAction(UIAlertAction(title: cancelTitle, style: .cancel, handler: nil)) + alert.addAction(UIAlertAction(title: title, style: .default, handler: { [weak self] _ in + self?.output.viewDidConfirmToUpdateFirmware(for: uuid) + })) + present(alert, animated: true) + } + // swiftlint:disable:next function_parameter_count function_body_length func showSensorDetailsDialog( for tag: NFCSensor?, diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift index 0cdb0ab2e..7cd8d475a 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift @@ -11,11 +11,6 @@ final class FirmwarePresenter: RuuviFirmware { if let view = weakView { return view } else { - let viewModel = FirmwareViewModel( - uuid: uuid, - currentFirmware: currentFirmware, - interactor: interactor - ) viewModel.output = self let view = UIHostingController(rootView: FirmwareView(viewModel: viewModel)) weakView = view @@ -27,6 +22,13 @@ final class FirmwarePresenter: RuuviFirmware { private let interactor: FirmwareInteractor private let uuid: String private let currentFirmware: String? + private lazy var viewModel: FirmwareViewModel = { + FirmwareViewModel( + uuid: uuid, + currentFirmware: currentFirmware, + interactor: interactor + ) + }() init( uuid: String, @@ -43,6 +45,15 @@ final class FirmwarePresenter: RuuviFirmware { firmwareRepository: firmwareRepository ) } + + func isSafeToDismiss() -> Bool { + switch viewModel.state { + case .flashing: + false + default: + true + } + } } extension FirmwarePresenter: FirmwareViewModelOutput { diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmware.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmware.swift index 4ae823873..a62c39347 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmware.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmware.swift @@ -4,6 +4,8 @@ public protocol RuuviFirmware: AnyObject { var viewController: UIViewController { get } var router: AnyObject? { get set } var output: RuuviFirmwareOutput? { get set } + + func isSafeToDismiss() -> Bool } public protocol RuuviFirmwareOutput: AnyObject { diff --git a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift index 4428c1521..dcf89a80d 100644 --- a/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift +++ b/Packages/RuuviReactor/Sources/RuuviReactorImpl/RuuviReactorImpl.swift @@ -152,8 +152,6 @@ class RuuviReactorImpl: RuuviReactor { sqlitePersistence.readSensorSettings(ruuviTag).on { sqliteRecord in if let sensorSettings = sqliteRecord { block(.update(sensorSettings)) - } else { - assertionFailure() } } var sensorSettingsCombine: SensorSettingsCombine diff --git a/station.localization b/station.localization index 7847c3820..5fb683407 160000 --- a/station.localization +++ b/station.localization @@ -1 +1 @@ -Subproject commit 7847c38208cc1a7228ed3f312b6001c83ca626d0 +Subproject commit 5fb6834077d29ff88d21b7ffe74f9e97f6576497 From b6e052f7d2204a09ef6c065f57d6b17d26b88086 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 16 Dec 2023 19:10:20 +0200 Subject: [PATCH 54/84] Quiet xcodebuild and dev branch for localization (#1794) For Alpha builds use dev branch in station.localization --- .github/workflows/firebase.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/firebase.yml b/.github/workflows/firebase.yml index 010a560ce..eaa8673d2 100644 --- a/.github/workflows/firebase.yml +++ b/.github/workflows/firebase.yml @@ -28,7 +28,7 @@ jobs: run: rm -rf ${{ github.workspace }}/station.localization - name: Clone localisation submodule - run: git clone -b master https://github.com/ruuvi/station.localization.git ${{ github.workspace }}/station.localization + run: git clone -b dev https://github.com/ruuvi/station.localization.git ${{ github.workspace }}/station.localization - name: Install the Apple certificate and provisioning profiles env: @@ -80,7 +80,7 @@ jobs: - name: Build app run: | - xcodebuild -project Ruuvi.xcodeproj -scheme station -configuration Alpha -archivePath ./Build/Station_Dev.xcarchive archive -allowProvisioningUpdates + xcodebuild -project Ruuvi.xcodeproj -scheme station -configuration Alpha -archivePath ./Build/Station_Dev.xcarchive archive -allowProvisioningUpdates -quiet - name: Export IPA env: EXPORT_PLIST: ${{ secrets.ADHOC_EXPORT_OPTIONS }} From 79819c536f220ebd28648ce0fe3ec9aeb06224b1 Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Sun, 17 Dec 2023 18:04:43 +0100 Subject: [PATCH 55/84] feature: Implement drag and drop for cards on dashboard #1632 (#1796) --- .../Dashboard/Cards/View/CardsViewModel.swift | 26 +-- .../Home/Presenter/DashboardPresenter.swift | 80 ++++++-- .../Home/View/DashboardViewController.swift | 174 +++++++++++++++++- .../Home/View/DashboardViewInput.swift | 6 +- .../Home/View/DashboardViewOutput.swift | 2 + .../Presenter/TagSettingsPresenter.swift | 2 + .../View/TagSettingsViewInput.swift | 2 + .../View/UI/TagSettingsViewController.swift | 16 +- .../Sources/RuuviCloud/RuuviCloud.swift | 3 + .../Helpers/RuuviCloudApiHelper.swift | 23 +++ .../RuuviCloudApiPostSettingRequest.swift | 4 +- .../RuuviCloudApiGetSettingsResponse.swift | 6 + .../Settings/RuuviCloudApiSettings.swift | 1 + .../RuuviCloudPure/RuuviCloudPure.swift | 27 +++ .../RuuviLocal/RuuviLocalSettings.swift | 2 + .../RuuviLocalSettingsUserDefaults.swift | 20 ++ .../Common/DashboardSortingType.swift | 4 + .../Common/RuuviCloudSettings.swift | 1 + .../RuuviServiceAppSettings.swift | 3 + .../RuuviServiceAppSettingsImpl.swift | 12 ++ .../RuuviServiceCloudSyncImpl.swift | 6 + 21 files changed, 382 insertions(+), 38 deletions(-) create mode 100644 Packages/RuuviCloud/Sources/RuuviCloudApi/Helpers/RuuviCloudApiHelper.swift create mode 100644 Packages/RuuviOntology/Sources/RuuviOntology/Common/DashboardSortingType.swift diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift index 7dd26c521..d538ae8b4 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/CardsViewModel.swift @@ -3,12 +3,13 @@ import Humidity import RuuviLocal import RuuviOntology import UIKit +import MobileCoreServices enum CardType { case ruuvi } -struct CardsViewModel { +class CardsViewModel: NSObject { var type: CardType = .ruuvi var id: Observable = .init() @@ -137,21 +138,22 @@ struct CardsViewModel { } } -extension CardsViewModel: Hashable { - public func hash(into hasher: inout Hasher) { - hasher.combine(luid.value) - hasher.combine(mac.value) +extension CardsViewModel: Reorderable { + var orderElement: String { + id.value ?? UUID().uuidString } } -extension CardsViewModel: Equatable { - public static func == (lhs: CardsViewModel, rhs: CardsViewModel) -> Bool { - lhs.luid.value == rhs.luid.value && lhs.mac.value == rhs.mac.value +// Comform to NSItemProviderWriting to enable drag and drop of item with CardsViewModel +extension CardsViewModel: NSItemProviderWriting { + public static var writableTypeIdentifiersForItemProvider: [String] { + return [kUTTypePlainText as String] } -} -extension CardsViewModel: Reorderable { - var orderElement: String { - id.value ?? UUID().uuidString + public func loadData( + withTypeIdentifier typeIdentifier: String, + forItemProviderCompletionHandler completionHandler: @escaping (Data?, Error?) -> Void + ) -> Progress? { + return Progress() } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift index b7e738b7b..70e5358f3 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift @@ -83,6 +83,7 @@ class DashboardPresenter: DashboardModuleInput { private var dashboardTapActionTypeToken: NSObjectProtocol? private var cloudSyncSuccessStateToken: NSObjectProtocol? private var cloudSyncFailStateToken: NSObjectProtocol? + private var sensorOrderChangeToken: NSObjectProtocol? private var ruuviTags = [AnyRuuviTagSensor]() private var sensorSettingsList = [SensorSettings]() private var viewModels: [CardsViewModel] = [] { @@ -133,6 +134,7 @@ class DashboardPresenter: DashboardModuleInput { dashboardTapActionTypeToken?.invalidate() cloudSyncSuccessStateToken?.invalidate() cloudSyncFailStateToken?.invalidate() + sensorOrderChangeToken?.invalidate() NotificationCenter.default.removeObserver( self, name: UIApplication.willEnterForegroundNotification, @@ -156,6 +158,7 @@ extension DashboardPresenter: DashboardViewOutput { startObserveCalibrationSettingsChange() startObservingCloudSyncSuccessTokenState() startObservingCloudSyncFailTokenState() + startObservingSensorOrderChanges() pushNotificationsManager.registerForRemoteNotifications() } @@ -244,7 +247,9 @@ extension DashboardPresenter: DashboardViewOutput { } func viewDidTriggerRename(for viewModel: CardsViewModel) { - view?.showSensorNameRenameDialog(for: viewModel) + let sortingType: DashboardSortingType = + settings.dashboardSensorOrder.count == 0 ? .alphabetical : .manual + view?.showSensorNameRenameDialog(for: viewModel, sortingType: sortingType) } func viewDidTriggerShare(for viewModel: CardsViewModel) { @@ -324,6 +329,19 @@ extension DashboardPresenter: DashboardViewOutput { self?.errorPresenter.present(error: error) }) } + + func viewDidReorderSensors( + with type: DashboardSortingType, + orderedIds: [String] + ) { + settings.dashboardSensorOrder = orderedIds + ruuviAppSettingsService.set(dashboardSensorOrder: orderedIds) + viewModels = reorder(viewModels) + } + + func viewDidResetManualSorting() { + view?.showSensorSortingResetConfirmationDialog() + } } // MARK: - MenuModuleOutput @@ -632,8 +650,15 @@ extension DashboardPresenter { } } - viewModels.append(viewModel) - viewModels = reorder(viewModels) + if settings.dashboardSensorOrder.count == 0 { + viewModels.append(viewModel) + viewModels = reorder(viewModels) + } else { + // For manual sorting, newly added sensor will be sent to the top + viewModels.insert(viewModel, at: 0) + let macIds = viewModels.compactMap { $0.mac.value?.value } + viewDidReorderSensors(with: .manual, orderedIds: macIds) + } } } @@ -662,25 +687,30 @@ extension DashboardPresenter { } private func reorder(_ viewModels: [CardsViewModel]) -> [CardsViewModel] { + let sortedSensors: [String] = settings.dashboardSensorOrder let sortedAndUniqueArray = viewModels.reduce( into: [CardsViewModel]() ) { result, element in if !result.contains(element) { - // Insert the element into the result array while maintaining the sorted order - if let index = result.firstIndex( - where: { - $0.name.value?.lowercased() ?? "" > - element.name.value?.lowercased() ?? "" - } - ) { - result.insert(element, at: index) - } else { - // If no such index is found, append the element at the end - result.append(element) - } + result.append(element) + } + } + + if !sortedSensors.isEmpty { + return sortedAndUniqueArray.sorted { (first, second) -> Bool in + guard let firstMacId = first.mac.value?.value, + let secondMacId = second.mac.value?.value else { return false } + let firstIndex = sortedSensors.firstIndex(of: firstMacId) ?? Int.max + let secondIndex = sortedSensors.firstIndex(of: secondMacId) ?? Int.max + return firstIndex < secondIndex + } + } else { + return sortedAndUniqueArray.sorted { (first, second) -> Bool in + let firstName = first.name.value?.lowercased() ?? "" + let secondName = second.name.value?.lowercased() ?? "" + return firstName < secondName } } - return sortedAndUniqueArray } private func syncAppSettingsToAppGroupContainer() { @@ -1496,6 +1526,24 @@ extension DashboardPresenter { ) } + private func startObservingSensorOrderChanges() { + sensorOrderChangeToken?.invalidate() + sensorOrderChangeToken = nil + sensorOrderChangeToken = NotificationCenter + .default + .addObserver( + forName: .DashboardSensorOrderDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + guard let self = self else { return } + DispatchQueue.main.async { + self.viewModels = self.reorder(self.viewModels) + } + } + ) + } + @objc private func systemLocaleDidChange() { syncAppSettingsToAppGroupContainer() } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift index 4302bdc5c..2f5b07cd6 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift @@ -133,6 +133,8 @@ class DashboardViewController: UIViewController { cv.showsVerticalScrollIndicator = false cv.delegate = self cv.dataSource = self + cv.dragDelegate = self + cv.dropDelegate = self cv.alwaysBounceVertical = true cv.refreshControl = refresher return cv @@ -248,6 +250,7 @@ private extension DashboardViewController { } extension DashboardViewController { + // swiftlint:disable:next function_body_length private func viewToggleMenuOptions() -> UIMenu { // Card Type let imageViewTypeAction = UIAction(title: RuuviLocalization.imageCards) { @@ -299,10 +302,27 @@ extension DashboardViewController { ] ) + // Sensor ordering + let resetSensorSortingOrderAction = UIAction( + title: RuuviLocalization.resetOrder + ) { + [weak self] _ in + self?.output.viewDidResetManualSorting() + } + resetSensorSortingOrderAction.state = .off + + let resetSensorSortingOrderMenu = UIMenu( + title: RuuviLocalization.ordering, + options: .displayInline, + children: [ + resetSensorSortingOrderAction + ] + ) + return UIMenu( title: "", children: [ - cardTypeMenu, cardActionMenu + cardTypeMenu, cardActionMenu, resetSensorSortingOrderMenu ] ) } @@ -535,6 +555,20 @@ private extension DashboardViewController { self?.reloadCollectionView() } } + + // MARK: Drag and Drop + private func dragPreviewParameters( + for cell: UICollectionViewCell + ) -> UIDragPreviewParameters? { + let previewParameters = UIDragPreviewParameters() + let path = UIBezierPath( + roundedRect: cell.contentView.frame, + cornerRadius: 8.0 + ) + previewParameters.visiblePath = path + previewParameters.backgroundColor = .clear + return previewParameters + } } extension DashboardViewController: UICollectionViewDataSource { @@ -585,7 +619,6 @@ extension DashboardViewController: UICollectionViewDelegate { func collectionView( _: UICollectionView, willEndContextMenuInteraction _: UIContextMenuConfiguration, - animator _: UIContextMenuInteractionAnimating? ) { highlightedViewModel = nil @@ -633,6 +666,103 @@ extension DashboardViewController: UICollectionViewDelegate { } } +// MARK: UICollectionViewDragDelegate +extension DashboardViewController: UICollectionViewDragDelegate { + func collectionView( + _ collectionView: UICollectionView, + itemsForBeginning session: UIDragSession, + at indexPath: IndexPath + ) -> [UIDragItem] { + guard viewModels.count > 1 else { return [] } + let item = viewModels[indexPath.item] + let itemProvider = NSItemProvider(object: item as CardsViewModel) + let dragItem = UIDragItem(itemProvider: itemProvider) + dragItem.localObject = item + return [dragItem] + } + + func collectionView( + _ collectionView: UICollectionView, + dragPreviewParametersForItemAt indexPath: IndexPath + ) -> UIDragPreviewParameters? { + guard let cell = collectionView.cellForItem(at: indexPath) else { return nil } + return dragPreviewParameters(for: cell) + } +} + +// MARK: UICollectionViewDropDelegate +extension DashboardViewController: UICollectionViewDropDelegate { + func collectionView( + _ collectionView: UICollectionView, + dropSessionDidUpdate session: UIDropSession, + withDestinationIndexPath destinationIndexPath: IndexPath? + ) -> UICollectionViewDropProposal { + if collectionView.hasActiveDrag { + return UICollectionViewDropProposal( + operation: .move, + intent: .insertAtDestinationIndexPath + ) + } + return UICollectionViewDropProposal(operation: .forbidden) + } + + func collectionView( + _ collectionView: UICollectionView, + performDropWith coordinator: UICollectionViewDropCoordinator + ) { + let destinationIndexPath: IndexPath + + if let indexPath = coordinator.destinationIndexPath { + destinationIndexPath = indexPath + } else { + let row = collectionView.numberOfItems(inSection: 0) + destinationIndexPath = IndexPath(row: row, section: 0) + } + + guard destinationIndexPath.row < viewModels.count else { return } + + if coordinator.proposal.operation == .move { + reorderItems( + coordinator, + destinationIndexPath: destinationIndexPath, + collectionView: collectionView + ) + } + } + + func reorderItems( + _ coordinator: UICollectionViewDropCoordinator, + destinationIndexPath: IndexPath, collectionView: UICollectionView + ) { + guard let item = coordinator.items.first, + let sourceIndexPath = item.sourceIndexPath, + let dragItem = item.dragItem.localObject as? CardsViewModel else { + return + } + + collectionView.performBatchUpdates({ [weak self] in + guard let self else { return } + self.viewModels.remove(at: sourceIndexPath.item) + self.viewModels.insert(dragItem, at: destinationIndexPath.item) + collectionView.deleteItems(at: [sourceIndexPath]) + collectionView.insertItems(at: [destinationIndexPath]) + }, completion: nil) + + coordinator.drop(item.dragItem, toItemAt: destinationIndexPath) + + let macIds = viewModels.compactMap { $0.mac.value?.value } + output.viewDidReorderSensors(with: .manual, orderedIds: macIds) + } + + func collectionView( + _ collectionView: UICollectionView, + dropPreviewParametersForItemAt indexPath: IndexPath + ) -> UIDragPreviewParameters? { + guard let cell = collectionView.cellForItem(at: indexPath) else { return nil } + return dragPreviewParameters(for: cell) + } +} + // MARK: - DashboardViewInput extension DashboardViewController: DashboardViewInput { @@ -742,14 +872,18 @@ extension DashboardViewController: DashboardViewInput { present(alert, animated: true) } - func showSensorNameRenameDialog(for viewModel: CardsViewModel) { + func showSensorNameRenameDialog( + for viewModel: CardsViewModel, + sortingType: DashboardSortingType + ) { let defaultName = GlobalHelpers.ruuviTagDefaultName( from: viewModel.mac.value?.mac, luid: viewModel.luid.value?.value ) let alert = UIAlertController( title: RuuviLocalization.TagSettings.TagNameTitleLabel.text, - message: RuuviLocalization.TagSettings.TagNameTitleLabel.Rename.text, + message: sortingType == .alphabetical ? + RuuviLocalization.TagSettings.TagNameTitleLabel.Rename.text : nil, preferredStyle: .alert ) alert.addTextField { [weak self] alertTextField in @@ -772,6 +906,38 @@ extension DashboardViewController: DashboardViewInput { alert.addAction(cancelAction) present(alert, animated: true, completion: nil) } + + func showSensorSortingResetConfirmationDialog() { + let message = RuuviLocalization.resetOrderConfirmation + let alert = UIAlertController( + title: nil, + message: message, + preferredStyle: .alert + ) + + let cancelTitle = RuuviLocalization.cancel + alert.addAction( + UIAlertAction( + title: cancelTitle, + style: .cancel, + handler: nil + ) + ) + + let confirmTitle = RuuviLocalization.confirm + alert.addAction( + UIAlertAction( + title: confirmTitle, + style: .default, + handler: { [weak self] _ in + self?.output.viewDidReorderSensors( + with: .alphabetical, orderedIds: [] + ) + } + ) + ) + present(alert, animated: true) + } } extension DashboardViewController: RuuviServiceMeasurementDelegate { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift index aa33aa7a3..4ae76854b 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift @@ -14,5 +14,9 @@ protocol DashboardViewInput: ViewInput { func showKeepConnectionDialogSettings(for viewModel: CardsViewModel) func showReverseGeocodingFailed() func showAlreadyLoggedInAlert(with email: String) - func showSensorNameRenameDialog(for viewModel: CardsViewModel) + func showSensorNameRenameDialog( + for viewModel: CardsViewModel, + sortingType: DashboardSortingType + ) + func showSensorSortingResetConfirmationDialog() } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewOutput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewOutput.swift index 70bdd8a17..28458705c 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewOutput.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewOutput.swift @@ -24,4 +24,6 @@ protocol DashboardViewOutput { func viewDidChangeDashboardTapAction(type: DashboardTapActionType) func viewDidTriggerPullToRefresh() func viewDidRenameTag(to name: String, viewModel: CardsViewModel) + func viewDidReorderSensors(with type: DashboardSortingType, orderedIds: [String]) + func viewDidResetManualSorting() } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift index 5d4065012..8030f7cc4 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift @@ -131,6 +131,8 @@ class TagSettingsPresenter: NSObject, TagSettingsModuleInput { } else { self.sensorSettings = emptySensorSettings() } + view.dashboardSortingType = + settings.dashboardSensorOrder.count == 0 ? .alphabetical : .manual syncUnits() syncAllAlerts() diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewInput.swift index 4dfd22835..f04f0b742 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewInput.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/TagSettingsViewInput.swift @@ -1,7 +1,9 @@ import Foundation +import RuuviOntology protocol TagSettingsViewInput: ViewInput { var viewModel: TagSettingsViewModel? { get set } + var dashboardSortingType: DashboardSortingType? { get set } func showTagClaimDialog() func showMacAddressDetail() diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift index d7ac9ae34..ebe619d50 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift @@ -82,6 +82,8 @@ class TagSettingsViewController: UIViewController { } } + var dashboardSortingType: DashboardSortingType? + private lazy var backButton: UIButton = { let button = UIButton() button.tintColor = .label @@ -711,7 +713,11 @@ extension TagSettingsViewController { return self?.tagNameCell ?? UITableViewCell() }, action: { [weak self] _ in - self?.showSensorNameRenameDialog(name: self?.viewModel?.name.value) + guard let sortingType = self?.dashboardSortingType else { return } + self?.showSensorNameRenameDialog( + name: self?.viewModel?.name.value, + sortingType: sortingType + ) } ) return settingItem @@ -3603,14 +3609,18 @@ extension TagSettingsViewController: TagSettingsBackgroundSelectionViewDelegate // MARK: - Sensor name rename dialog extension TagSettingsViewController { - private func showSensorNameRenameDialog(name: String?) { + private func showSensorNameRenameDialog( + name: String?, + sortingType: DashboardSortingType + ) { let defaultName = GlobalHelpers.ruuviTagDefaultName( from: viewModel?.mac.value, luid: viewModel?.uuid.value ) let alert = UIAlertController( title: RuuviLocalization.TagSettings.TagNameTitleLabel.text, - message: RuuviLocalization.TagSettings.TagNameTitleLabel.Rename.text, + message: sortingType == .alphabetical ? + RuuviLocalization.TagSettings.TagNameTitleLabel.Rename.text : nil, preferredStyle: .alert ) alert.addTextField { [weak self] alertTextField in diff --git a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift index 627085a28..9bc27c48b 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloud.swift @@ -182,6 +182,9 @@ public protocol RuuviCloud { @discardableResult func set(profileLanguageCode: String) -> Future + @discardableResult + func set(dashboardSensorOrder: [String]) -> Future<[String], RuuviCloudError> + @discardableResult func update( temperatureOffset: Double?, diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/Helpers/RuuviCloudApiHelper.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/Helpers/RuuviCloudApiHelper.swift new file mode 100644 index 000000000..b6896e637 --- /dev/null +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/Helpers/RuuviCloudApiHelper.swift @@ -0,0 +1,23 @@ +import Foundation + +public struct RuuviCloudApiHelper { + public static func jsonStringFromArray(_ array: [String]) -> String? { + do { + let jsonData = try JSONEncoder().encode(array) + return String(data: jsonData, encoding: .utf8) + } catch { + return nil + } + } + + public static func jsonArrayFromString(_ jsonString: String) -> [String]? { + guard let jsonData = jsonString.data(using: .utf8) else { return nil } + + do { + let array = try JSONDecoder().decode([String].self, from: jsonData) + return array + } catch { + return nil + } + } +} diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudApiPostSettingRequest.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudApiPostSettingRequest.swift index f75b1ae27..1a89b3556 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudApiPostSettingRequest.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Request/RuuviCloudApiPostSettingRequest.swift @@ -2,12 +2,12 @@ import Foundation public struct RuuviCloudApiPostSettingRequest: Codable { let name: RuuviCloudApiSetting - let value: String + let value: String? let timestamp: Int? public init( name: RuuviCloudApiSetting, - value: String, + value: String?, timestamp: Int? ) { self.name = name diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSettingsResponse.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSettingsResponse.swift index 7fbdcab0f..2a009fd8a 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSettingsResponse.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Response/RuuviCloudApiGetSettingsResponse.swift @@ -75,6 +75,10 @@ public struct RuuviCloudApiSettings: Decodable, RuuviCloudSettings { profileLanguageCodeString } + public var dashboardSensorOrder: String? { + dashboardSensorOrderString + } + var unitTemperatureString: String? var accuracyTemperatureString: String? var unitHumidityString: String? @@ -92,6 +96,7 @@ public struct RuuviCloudApiSettings: Decodable, RuuviCloudSettings { var pushAlertEnabledString: String? var emailAlertEnabledString: String? var profileLanguageCodeString: String? + var dashboardSensorOrderString: String? enum CodingKeys: String, CodingKey { case unitTemperatureString = "UNIT_TEMPERATURE" @@ -111,5 +116,6 @@ public struct RuuviCloudApiSettings: Decodable, RuuviCloudSettings { case pushAlertEnabledString = "ALERT_PUSH_ENABLED" case emailAlertEnabledString = "ALERT_EMAIL_ENABLED" case profileLanguageCodeString = "PROFILE_LANGUAGE_CODE" + case dashboardSensorOrderString = "SENSOR_ORDER" } } diff --git a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Settings/RuuviCloudApiSettings.swift b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Settings/RuuviCloudApiSettings.swift index ad1b89aec..6e3a6bf80 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Settings/RuuviCloudApiSettings.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudApi/URLSession/Models/Settings/RuuviCloudApiSettings.swift @@ -19,6 +19,7 @@ public enum RuuviCloudApiSetting: String, CaseIterable, Codable { case pushAlertEnabled = "ALERT_PUSH_ENABLED" case emailAlertEnabled = "ALERT_EMAIL_ENABLED" case profileLanguageCode = "PROFILE_LANGUAGE_CODE" + case dashboardSensorOrder = "SENSOR_ORDER" } public extension TemperatureUnit { diff --git a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift index fbb6291ef..8d087435e 100644 --- a/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift +++ b/Packages/RuuviCloud/Sources/RuuviCloudPure/RuuviCloudPure.swift @@ -552,6 +552,33 @@ public final class RuuviCloudPure: RuuviCloud { return promise.future } + @discardableResult + public func set(dashboardSensorOrder: [String]) -> Future<[String], RuuviCloudError> { + let promise = Promise<[String], RuuviCloudError>() + guard let apiKey = user.apiKey + else { + promise.fail(error: .notAuthorized) + return promise.future + } + let request = RuuviCloudApiPostSettingRequest( + name: .dashboardSensorOrder, + value: RuuviCloudApiHelper.jsonStringFromArray(dashboardSensorOrder), + timestamp: Int(Date().timeIntervalSince1970) + ) + api.postSetting(request, authorization: apiKey) + .on(success: { _ in + promise.succeed(value: dashboardSensorOrder) + }, failure: { [weak self] error in + self?.createQueuedRequest( + from: request, + type: .settings, + uniqueKey: RuuviCloudApiSetting.dashboardSensorOrder.rawValue + ) + promise.fail(error: .api(error)) + }) + return promise.future + } + @discardableResult public func getCloudSettings() -> Future { let promise = Promise() diff --git a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift index 8ead1c1e9..dbfbf254e 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift @@ -24,6 +24,7 @@ public extension Notification.Name { static let PushAlertSettingsDidChange = Notification.Name("PushAlertSettingsDidChange") static let LimitAlertNotificationsSettingsDidChange = Notification.Name("LimitAlertNotificationsSettingsDidChange") + static let DashboardSensorOrderDidChange = Notification.Name("DashboardSensorOrderDidChange") } public enum DashboardTypeKey: String { @@ -81,6 +82,7 @@ public protocol RuuviLocalSettings { var dashboardEnabled: Bool { get set } var dashboardType: DashboardType { get set } var dashboardTapActionType: DashboardTapActionType { get set } + var dashboardSensorOrder: [String] { get set } var theme: RuuviTheme { get set } var hideNFCForSensorContest: Bool { get set } var alertSound: RuuviAlertSound { get set } diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift index 9a151eefe..351d5df97 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift @@ -538,6 +538,26 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { } } + private let dashboardSensorOrderIdKey = + "SettingsUserDefaults.dashboardSortedSensors" + var dashboardSensorOrder: [String] { + get { + UserDefaults.standard.value( + forKey: dashboardSensorOrderIdKey + ) as? [String] ?? [] + } + set { + UserDefaults.standard.set(newValue, forKey: dashboardSensorOrderIdKey) + NotificationCenter + .default + .post( + name: .DashboardSensorOrderDidChange, + object: self, + userInfo: nil + ) + } + } + private let ruuviThemeIdKey = "SettingsUserDefaults.ruuviThemeIdKey" private var ruuviThemeId: Int { get { diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Common/DashboardSortingType.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Common/DashboardSortingType.swift new file mode 100644 index 000000000..6f11b386e --- /dev/null +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Common/DashboardSortingType.swift @@ -0,0 +1,4 @@ +public enum DashboardSortingType: String, Codable { + case alphabetical + case manual +} diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Common/RuuviCloudSettings.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Common/RuuviCloudSettings.swift index a64aeb66d..1e5c8e81d 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Common/RuuviCloudSettings.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Common/RuuviCloudSettings.swift @@ -18,4 +18,5 @@ public protocol RuuviCloudSettings { var pushAlertEnabled: Bool? { get } var emailAlertEnabled: Bool? { get } var profileLanguageCode: String? { get } + var dashboardSensorOrder: String? { get } } diff --git a/Packages/RuuviService/Sources/RuuviService/RuuviServiceAppSettings.swift b/Packages/RuuviService/Sources/RuuviService/RuuviServiceAppSettings.swift index e89d115a7..ede639afd 100644 --- a/Packages/RuuviService/Sources/RuuviService/RuuviServiceAppSettings.swift +++ b/Packages/RuuviService/Sources/RuuviService/RuuviServiceAppSettings.swift @@ -53,4 +53,7 @@ public protocol RuuviServiceAppSettings { @discardableResult func set(profileLanguageCode: String) -> Future + + @discardableResult + func set(dashboardSensorOrder: [String]) -> Future<[String], RuuviServiceError> } diff --git a/Packages/RuuviService/Sources/RuuviServiceAppSettings/RuuviServiceAppSettingsImpl.swift b/Packages/RuuviService/Sources/RuuviServiceAppSettings/RuuviServiceAppSettingsImpl.swift index cb99c0ce4..f30dfcd2b 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAppSettings/RuuviServiceAppSettingsImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAppSettings/RuuviServiceAppSettingsImpl.swift @@ -232,4 +232,16 @@ public final class RuuviServiceAppSettingsImpl: RuuviServiceAppSettings { }) return promise.future } + + @discardableResult + public func set(dashboardSensorOrder: [String]) -> Future<[String], RuuviServiceError> { + let promise = Promise<[String], RuuviServiceError>() + cloud.set(dashboardSensorOrder: dashboardSensorOrder) + .on(success: { dashboardSensorOrder in + promise.succeed(value: dashboardSensorOrder) + }, failure: { error in + promise.fail(error: .ruuviCloud(error)) + }) + return promise.future + } } diff --git a/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift b/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift index b34df7b89..9f5b3b4d9 100644 --- a/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceCloudSync/RuuviServiceCloudSyncImpl.swift @@ -127,6 +127,12 @@ public final class RuuviServiceCloudSyncImpl: RuuviServiceCloudSync { sSelf.ruuviLocalSettings.cloudProfileLanguageCode = languageCode } + if let dashboardSensorOrderString = cloudSettings.dashboardSensorOrder, + let dashboardSensorOrder = RuuviCloudApiHelper.jsonArrayFromString(dashboardSensorOrderString), + dashboardSensorOrder != sSelf.ruuviLocalSettings.dashboardSensorOrder { + sSelf.ruuviLocalSettings.dashboardSensorOrder = dashboardSensorOrder + } + promise.succeed(value: cloudSettings) }, failure: { error in promise.fail(error: .ruuviCloud(error)) From b4e1822e3e76c4284a1bf70f697d42d40a97aeb3 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sun, 17 Dec 2023 22:09:16 +0200 Subject: [PATCH 56/84] Remove podspec files (#1798) As outdated --- .../RuuviLocalization.podspec | 30 ---- .../RuuviPresenters/RuuviPresenters.podspec | 30 ---- Modules/RuuviDiscover/RuuviDiscover.podspec | 38 ----- Modules/RuuviFirmware/RuuviFirmware.podspec | 38 ----- Modules/RuuviOnboard/RuuviOnboard.podspec | 30 ---- .../RuuviAnalytics/RuuviAnalytics.podspec | 35 ---- Packages/RuuviCloud/RuuviCloud.podspec | 51 ------ Packages/RuuviContext/RuuviContext.podspec | 39 ----- Packages/RuuviCore/RuuviCore.podspec | 50 ------ Packages/RuuviDFU/RuuviDFU.podspec | 31 ---- Packages/RuuviDaemon/RuuviDaemon.podspec | 68 -------- Packages/RuuviLocal/RuuviLocal.podspec | 33 ---- .../RuuviMigration/RuuviMigration.podspec | 33 ---- .../RuuviNotification.podspec | 33 ---- Packages/RuuviNotifier/RuuviNotifier.podspec | 31 ---- Packages/RuuviOntology/RuuviOntology.podspec | 48 ------ .../RuuviPersistence/RuuviPersistence.podspec | 47 ------ Packages/RuuviPool/RuuviPool.podspec | 40 ----- Packages/RuuviReactor/RuuviReactor.podspec | 36 ----- .../RuuviRepository/RuuviRepository.podspec | 37 ----- Packages/RuuviService/RuuviService.podspec | 151 ------------------ Packages/RuuviStorage/RuuviStorage.podspec | 35 ---- Packages/RuuviUser/RuuviUser.podspec | 30 ---- 23 files changed, 994 deletions(-) delete mode 100644 Common/RuuviLocalization/RuuviLocalization.podspec delete mode 100644 Common/RuuviPresenters/RuuviPresenters.podspec delete mode 100644 Modules/RuuviDiscover/RuuviDiscover.podspec delete mode 100644 Modules/RuuviFirmware/RuuviFirmware.podspec delete mode 100644 Modules/RuuviOnboard/RuuviOnboard.podspec delete mode 100644 Packages/RuuviAnalytics/RuuviAnalytics.podspec delete mode 100644 Packages/RuuviCloud/RuuviCloud.podspec delete mode 100644 Packages/RuuviContext/RuuviContext.podspec delete mode 100644 Packages/RuuviCore/RuuviCore.podspec delete mode 100644 Packages/RuuviDFU/RuuviDFU.podspec delete mode 100644 Packages/RuuviDaemon/RuuviDaemon.podspec delete mode 100644 Packages/RuuviLocal/RuuviLocal.podspec delete mode 100644 Packages/RuuviMigration/RuuviMigration.podspec delete mode 100644 Packages/RuuviNotification/RuuviNotification.podspec delete mode 100644 Packages/RuuviNotifier/RuuviNotifier.podspec delete mode 100644 Packages/RuuviOntology/RuuviOntology.podspec delete mode 100644 Packages/RuuviPersistence/RuuviPersistence.podspec delete mode 100644 Packages/RuuviPool/RuuviPool.podspec delete mode 100644 Packages/RuuviReactor/RuuviReactor.podspec delete mode 100644 Packages/RuuviRepository/RuuviRepository.podspec delete mode 100644 Packages/RuuviService/RuuviService.podspec delete mode 100644 Packages/RuuviStorage/RuuviStorage.podspec delete mode 100644 Packages/RuuviUser/RuuviUser.podspec diff --git a/Common/RuuviLocalization/RuuviLocalization.podspec b/Common/RuuviLocalization/RuuviLocalization.podspec deleted file mode 100644 index e99dbbe4f..000000000 --- a/Common/RuuviLocalization/RuuviLocalization.podspec +++ /dev/null @@ -1,30 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviLocalization' - s.version = '0.0.1' - s.summary = 'Ruuvi Localization' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'RuuviLocalization' - - s.subspec 'RuuviLocalization' do |ss| - ss.source_files = 'Sources/RuuviLocalization/**/*.{h,m,swift}', 'Sources/RuuviLocalization/*.{h,m,swift}' - ss.resource_bundles = { - 'RuuviLocalization' => ['Sources/**/Resources/**/*'] - } - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end - - - diff --git a/Common/RuuviPresenters/RuuviPresenters.podspec b/Common/RuuviPresenters/RuuviPresenters.podspec deleted file mode 100644 index ac4d34817..000000000 --- a/Common/RuuviPresenters/RuuviPresenters.podspec +++ /dev/null @@ -1,30 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviPresenters' - s.version = '0.0.1' - s.summary = 'Ruuvi Presenters' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'RuuviPresenters' - - s.subspec 'RuuviPresenters' do |ss| - ss.source_files = 'Sources/RuuviPresenters/**/*.{h,m,swift}', 'Sources/RuuviPresenters/*.{h,m,swift}' - ss.resource_bundles = { - 'RuuviPresenters' => ['Sources/**/Resources/**/*'] - } - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end - - - diff --git a/Modules/RuuviDiscover/RuuviDiscover.podspec b/Modules/RuuviDiscover/RuuviDiscover.podspec deleted file mode 100644 index a6c247f57..000000000 --- a/Modules/RuuviDiscover/RuuviDiscover.podspec +++ /dev/null @@ -1,38 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviDiscover' - s.version = '0.0.2' - s.summary = 'Ruuvi Discover' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'RuuviDiscover' - - s.subspec 'RuuviDiscover' do |ss| - ss.source_files = 'Sources/RuuviDiscover/**/*.{h,m,swift}', 'Sources/RuuviDiscover/*.{h,m,swift}' - ss.resource_bundles = { - 'RuuviDiscover' => ['Sources/**/Resources/**/*'] - } - - ss.dependency 'BTKit' - ss.dependency 'RuuviContext' - ss.dependency 'RuuviReactor' - ss.dependency 'RuuviLocal' - ss.dependency 'RuuviService' - ss.dependency 'RuuviCore' - ss.dependency 'RuuviLocalization' - ss.dependency 'RuuviPresenters' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end - - diff --git a/Modules/RuuviFirmware/RuuviFirmware.podspec b/Modules/RuuviFirmware/RuuviFirmware.podspec deleted file mode 100644 index a6c247f57..000000000 --- a/Modules/RuuviFirmware/RuuviFirmware.podspec +++ /dev/null @@ -1,38 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviDiscover' - s.version = '0.0.2' - s.summary = 'Ruuvi Discover' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'RuuviDiscover' - - s.subspec 'RuuviDiscover' do |ss| - ss.source_files = 'Sources/RuuviDiscover/**/*.{h,m,swift}', 'Sources/RuuviDiscover/*.{h,m,swift}' - ss.resource_bundles = { - 'RuuviDiscover' => ['Sources/**/Resources/**/*'] - } - - ss.dependency 'BTKit' - ss.dependency 'RuuviContext' - ss.dependency 'RuuviReactor' - ss.dependency 'RuuviLocal' - ss.dependency 'RuuviService' - ss.dependency 'RuuviCore' - ss.dependency 'RuuviLocalization' - ss.dependency 'RuuviPresenters' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end - - diff --git a/Modules/RuuviOnboard/RuuviOnboard.podspec b/Modules/RuuviOnboard/RuuviOnboard.podspec deleted file mode 100644 index e368acbb4..000000000 --- a/Modules/RuuviOnboard/RuuviOnboard.podspec +++ /dev/null @@ -1,30 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviOnboard' - s.version = '0.0.4' - s.summary = 'Ruuvi Onboard' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'RuuviOnboard' - - s.subspec 'RuuviOnboard' do |ss| - ss.source_files = 'Sources/RuuviOnboard/**/*.{h,m,swift}', 'Sources/RuuviOnboard/*.{h,m,swift}' - ss.resource_bundles = { - 'RuuviOnboard' => ['Sources/**/Resources/**/*'] - } - ss.dependency 'RuuviUser' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end - - diff --git a/Packages/RuuviAnalytics/RuuviAnalytics.podspec b/Packages/RuuviAnalytics/RuuviAnalytics.podspec deleted file mode 100644 index 33464bc93..000000000 --- a/Packages/RuuviAnalytics/RuuviAnalytics.podspec +++ /dev/null @@ -1,35 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviAnalytics' - s.version = '0.0.3' - s.summary = 'Ruuvi Analytics' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - s.static_framework = true - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviAnalytics/**/*.{h,m,swift}', 'Sources/RuuviAnalytics/*.{h,m,swift}' - end - - s.subspec 'Impl' do |ss| - ss.source_files = 'Sources/RuuviAnalyticsImpl/**/*.{h,m,swift}', 'Sources/RuuviAnalyticsImpl/*.{h,m,swift}' - ss.dependency 'Firebase' - ss.dependency 'RuuviAnalytics/Contract' - ss.dependency 'RuuviStorage' - ss.dependency 'RuuviLocal' - ss.dependency 'RuuviUser' - ss.dependency 'RuuviService/Alert' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end diff --git a/Packages/RuuviCloud/RuuviCloud.podspec b/Packages/RuuviCloud/RuuviCloud.podspec deleted file mode 100644 index b94bb7b6e..000000000 --- a/Packages/RuuviCloud/RuuviCloud.podspec +++ /dev/null @@ -1,51 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviCloud' - s.version = '0.1.0' - s.summary = 'Ruuvi Cloud' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviCloud/**/*.{h,m,swift}', 'Sources/RuuviCloud/*.{h,m,swift}' - ss.dependency 'FutureX' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviUser' - ss.dependency 'RuuviPool' - ss.dependency 'RuuviPersistence' - end - - s.subspec 'Pure' do |ss| - ss.source_files = 'Sources/RuuviCloudPure/**/*.{h,m,swift}', 'Sources/RuuviCloudPure/*.{h,m,swift}' - ss.dependency 'RuuviCloud/Contract' - ss.dependency 'RuuviCloud/Api' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviUser' - ss.dependency 'FutureX' - ss.dependency 'RuuviPool' - ss.dependency 'RuuviPersistence' - end - - s.subspec 'Api' do |ss| - ss.source_files = 'Sources/RuuviCloudApi/**/*.{h,m,swift}', 'Sources/RuuviCloudApi/*.{h,m,swift}' - ss.dependency 'RuuviCloud/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviOntology/Mappers' - ss.dependency 'BTKit' - ss.dependency 'FutureX' - ss.dependency 'RuuviPool' - ss.dependency 'RuuviPersistence' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end diff --git a/Packages/RuuviContext/RuuviContext.podspec b/Packages/RuuviContext/RuuviContext.podspec deleted file mode 100644 index c46738a75..000000000 --- a/Packages/RuuviContext/RuuviContext.podspec +++ /dev/null @@ -1,39 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviContext' - s.version = '0.0.1' - s.summary = 'Ruuvi Context' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'SQLite' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviContext/**/*.{h,m,swift}', 'Sources/RuuviContext/*.{h,m,swift}' - end - - s.subspec 'Realm' do |ss| - ss.source_files = 'Sources/RuuviContextRealm/**/*.{h,m,swift}', 'Sources/RuuviContextRealm/*.{h,m,swift}' - ss.dependency 'RuuviContext/Contract' - ss.dependency 'Realm' - ss.dependency 'RealmSwift' - end - - s.subspec 'SQLite' do |ss| - ss.source_files = 'Sources/RuuviContextSQLite/**/*.{h,m,swift}', 'Sources/RuuviContextSQLite/*.{h,m,swift}' - ss.dependency 'RuuviContext/Contract' - ss.dependency 'RuuviOntology/SQLite' - ss.dependency 'GRDB.swift' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end - diff --git a/Packages/RuuviCore/RuuviCore.podspec b/Packages/RuuviCore/RuuviCore.podspec deleted file mode 100644 index 510cbe6f0..000000000 --- a/Packages/RuuviCore/RuuviCore.podspec +++ /dev/null @@ -1,50 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviCore' - s.version = '0.0.1' - s.summary = 'Ruuvi Core' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviCore/**/*.{h,m,swift}', 'Sources/RuuviCore/*.{h,m,swift}' - ss.dependency 'FutureX' - end - - s.subspec 'Image' do |ss| - ss.source_files = 'Sources/RuuviCoreImage/**/*.{h,m,swift}', 'Sources/RuuviCoreImage/*.{h,m,swift}' - ss.dependency 'RuuviCore/Contract' - ss.dependency 'FutureX' - end - - s.subspec 'Location' do |ss| - ss.source_files = 'Sources/RuuviCoreLocation/**/*.{h,m,swift}', 'Sources/RuuviCoreLocation/*.{h,m,swift}' - ss.dependency 'RuuviCore/Contract' - end - - s.subspec 'Diff' do |ss| - ss.source_files = 'Sources/RuuviCoreDiff/**/*.{h,m,swift}', 'Sources/RuuviCoreDiff/*.{h,m,swift}' - end - - s.subspec 'PN' do |ss| - ss.source_files = 'Sources/RuuviCorePN/**/*.{h,m,swift}', 'Sources/RuuviCorePN/*.{h,m,swift}' - ss.dependency 'RuuviCore/Contract' - end - - s.subspec 'Permission' do |ss| - ss.source_files = 'Sources/RuuviCorePermission/**/*.{h,m,swift}', 'Sources/RuuviCorePermission/*.{h,m,swift}' - ss.dependency 'RuuviCore/Contract' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end diff --git a/Packages/RuuviDFU/RuuviDFU.podspec b/Packages/RuuviDFU/RuuviDFU.podspec deleted file mode 100644 index eeb957f69..000000000 --- a/Packages/RuuviDFU/RuuviDFU.podspec +++ /dev/null @@ -1,31 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviDFU' - s.version = '0.0.1' - s.summary = 'Ruuvi DFU' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviDFU/**/*.{h,m,swift}', 'Sources/RuuviDFU/*.{h,m,swift}' - end - - s.subspec 'Impl' do |ss| - ss.source_files = 'Sources/RuuviDFUImpl/**/*.{h,m,swift}', 'Sources/RuuviDFUImpl/*.{h,m,swift}' - ss.dependency 'iOSDFULibrary' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end - - diff --git a/Packages/RuuviDaemon/RuuviDaemon.podspec b/Packages/RuuviDaemon/RuuviDaemon.podspec deleted file mode 100644 index 42cdde703..000000000 --- a/Packages/RuuviDaemon/RuuviDaemon.podspec +++ /dev/null @@ -1,68 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviDaemon' - s.version = '0.0.1' - s.summary = 'Ruuvi Daemon' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviDaemon/**/*.{h,m,swift}', 'Sources/RuuviDaemon/*.{h,m,swift}' - end - - s.subspec 'Worker' do |ss| - ss.source_files = 'Sources/RuuviDaemonWorker/**/*.{h,m,swift}', 'Sources/RuuviDaemonWorker/*.{h,m,swift}' - end - - s.subspec 'CloudSync' do |ss| - ss.source_files = 'Sources/RuuviDaemonCloudSync/**/*.{h,m,swift}', 'Sources/RuuviDaemonCloudSync/*.{h,m,swift}' - ss.dependency 'RuuviDaemon/Contract' - ss.dependency 'RuuviDaemon/Worker' - ss.dependency 'RuuviService' - ss.dependency 'RuuviLocal' - end - - s.subspec 'Background' do |ss| - ss.source_files = 'Sources/RuuviDaemonBackground/**/*.{h,m,swift}', 'Sources/RuuviDaemonBackground/*.{h,m,swift}' - ss.dependency 'RuuviDaemon/Contract' - ss.dependency 'RuuviDaemon/Operation' - end - - s.subspec 'Operation' do |ss| - ss.source_files = 'Sources/RuuviDaemonOperation/**/*.{h,m,swift}', 'Sources/RuuviDaemonOperation/*.{h,m,swift}' - ss.dependency 'RuuviDaemon/Contract' - ss.dependency 'RuuviStorage' - ss.dependency 'RuuviLocal' - ss.dependency 'RuuviPool' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviNotifier' - ss.dependency 'FutureX' - end - - s.subspec 'RuuviTag' do |ss| - ss.source_files = 'Sources/RuuviDaemonRuuviTag/**/*.{h,m,swift}', 'Sources/RuuviDaemonRuuviTag/*.{h,m,swift}' - ss.dependency 'RuuviDaemon/Contract' - ss.dependency 'BTKit' - ss.dependency 'RuuviLocal' - ss.dependency 'RuuviPool' - ss.dependency 'RuuviReactor' - ss.dependency 'RuuviStorage' - ss.dependency 'RuuviPersistence' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviService' - ss.dependency 'RuuviNotification' - ss.dependency 'RuuviNotifier' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end diff --git a/Packages/RuuviLocal/RuuviLocal.podspec b/Packages/RuuviLocal/RuuviLocal.podspec deleted file mode 100644 index 195a9eee3..000000000 --- a/Packages/RuuviLocal/RuuviLocal.podspec +++ /dev/null @@ -1,33 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviLocal' - s.version = '0.0.3' - s.summary = 'Ruuvi Local' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviLocal/**/*.{h,m,swift}', 'Sources/RuuviLocal/*.{h,m,swift}' - ss.dependency 'RuuviOntology' - ss.dependency 'FutureX' - end - - s.subspec 'UserDefaults' do |ss| - ss.source_files = 'Sources/RuuviLocalUserDefaults/**/*.{h,m,swift}', 'Sources/RuuviLocalUserDefaults/*.{h,m,swift}' - ss.dependency 'RuuviLocal/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'FutureX' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end diff --git a/Packages/RuuviMigration/RuuviMigration.podspec b/Packages/RuuviMigration/RuuviMigration.podspec deleted file mode 100644 index 6a57b4df6..000000000 --- a/Packages/RuuviMigration/RuuviMigration.podspec +++ /dev/null @@ -1,33 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviMigration' - s.version = '0.0.1' - s.summary = 'Ruuvi Migration' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviMigration/**/*.{h,m,swift}', 'Sources/RuuviMigration/*.{h,m,swift}' - end - - s.subspec 'Impl' do |ss| - ss.source_files = 'Sources/RuuviMigrationImpl/**/*.{h,m,swift}', 'Sources/RuuviMigrationImpl/*.{h,m,swift}' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviContext' - ss.dependency 'RuuviStorage' - ss.dependency 'RuuviLocal' - ss.dependency 'RuuviService' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end diff --git a/Packages/RuuviNotification/RuuviNotification.podspec b/Packages/RuuviNotification/RuuviNotification.podspec deleted file mode 100644 index 60275aca6..000000000 --- a/Packages/RuuviNotification/RuuviNotification.podspec +++ /dev/null @@ -1,33 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviNotification' - s.version = '0.0.2' - s.summary = 'Ruuvi Notification' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviNotification/**/*.{h,m,swift}', 'Sources/RuuviNotification/*.{h,m,swift}' - end - - s.subspec 'Local' do |ss| - ss.source_files = 'Sources/RuuviNotificationLocal/**/*.{h,m,swift}', 'Sources/RuuviNotificationLocal/*.{h,m,swift}' - ss.dependency 'RuuviNotification/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviStorage' - ss.dependency 'RuuviLocal' - ss.dependency 'RuuviService' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end diff --git a/Packages/RuuviNotifier/RuuviNotifier.podspec b/Packages/RuuviNotifier/RuuviNotifier.podspec deleted file mode 100644 index 6fe2436df..000000000 --- a/Packages/RuuviNotifier/RuuviNotifier.podspec +++ /dev/null @@ -1,31 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviNotifier' - s.version = '0.0.1' - s.summary = 'Ruuvi Notifier' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviNotifier/**/*.{h,m,swift}', 'Sources/RuuviNotifier/*.{h,m,swift}' - end - - s.subspec 'Impl' do |ss| - ss.source_files = 'Sources/RuuviNotifierImpl/**/*.{h,m,swift}', 'Sources/RuuviNotifierImpl/*.{h,m,swift}' - ss.dependency 'RuuviNotifier/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviNotification' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end diff --git a/Packages/RuuviOntology/RuuviOntology.podspec b/Packages/RuuviOntology/RuuviOntology.podspec deleted file mode 100644 index 276692d69..000000000 --- a/Packages/RuuviOntology/RuuviOntology.podspec +++ /dev/null @@ -1,48 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviOntology' - s.version = '0.0.6' - s.summary = 'Ruuvi Ontology' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviOntology/**/*.{h,m,swift}', 'Sources/RuuviOntology/*.{h,m,swift}' - ss.dependency 'Humidity' - end - - s.subspec 'Mappers' do |ss| - ss.source_files = 'Sources/RuuviOntologyMappers/**/*.{h,m,swift}', 'Sources/RuuviOntologyMappers/*.{h,m,swift}' - ss.dependency 'RuuviOntology/Contract' - ss.dependency 'BTKit' - ss.dependency 'Humidity' - end - - s.subspec 'SQLite' do |ss| - ss.source_files = 'Sources/RuuviOntologySQLite/**/*.{h,m,swift}', 'Sources/RuuviOntologySQLite/*.{h,m,swift}' - ss.dependency 'RuuviOntology/Contract' - ss.dependency 'GRDB.swift' - ss.dependency 'Humidity' - end - - s.subspec 'Realm' do |ss| - ss.source_files = 'Sources/RuuviOntologyRealm/**/*.{h,m,swift}', 'Sources/RuuviOntologyRealm/*.{h,m,swift}' - ss.dependency 'RuuviOntology/Contract' - ss.dependency 'Realm' - ss.dependency 'RealmSwift', '~> 10.33.0' - ss.dependency 'Humidity' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end - diff --git a/Packages/RuuviPersistence/RuuviPersistence.podspec b/Packages/RuuviPersistence/RuuviPersistence.podspec deleted file mode 100644 index cc69c0c9c..000000000 --- a/Packages/RuuviPersistence/RuuviPersistence.podspec +++ /dev/null @@ -1,47 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviPersistence' - s.version = '0.0.2' - s.summary = 'Ruuvi Persistence' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviPersistence/**/*.{h,m,swift}', 'Sources/RuuviPersistence/*.{h,m,swift}' - ss.dependency 'FutureX' - ss.dependency 'RuuviOntology' - end - - s.subspec 'Realm' do |ss| - ss.source_files = 'Sources/RuuviPersistenceRealm/**/*.{h,m,swift}', 'Sources/RuuviPersistenceRealm/*.{h,m,swift}' - ss.dependency 'RuuviPersistence/Contract' - ss.dependency 'RuuviContext/Realm' - ss.dependency 'RuuviOntology/Realm' - ss.dependency 'RuuviOntology' - ss.dependency 'Realm' - ss.dependency 'RealmSwift', '~> 10.33.0' - ss.dependency 'FutureX' - end - - s.subspec 'SQLite' do |ss| - ss.source_files = 'Sources/RuuviPersistenceSQLite/**/*.{h,m,swift}', 'Sources/RuuviPersistenceSQLite/*.{h,m,swift}' - ss.dependency 'RuuviPersistence/Contract' - ss.dependency 'RuuviContext/SQLite' - ss.dependency 'RuuviOntology/SQLite' - ss.dependency 'RuuviOntology' - ss.dependency 'GRDB.swift' - ss.dependency 'FutureX' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end diff --git a/Packages/RuuviPool/RuuviPool.podspec b/Packages/RuuviPool/RuuviPool.podspec deleted file mode 100644 index 049889211..000000000 --- a/Packages/RuuviPool/RuuviPool.podspec +++ /dev/null @@ -1,40 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviPool' - s.version = '0.0.1' - s.summary = 'Ruuvi Pool' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviPool/**/*.{h,m,swift}', 'Sources/RuuviPool/*.{h,m,swift}' - ss.dependency 'FutureX' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviPersistence' - ss.dependency 'RuuviLocal' - end - - s.subspec 'Coordinator' do |ss| - ss.source_files = 'Sources/RuuviPoolCoordinator/**/*.{h,m,swift}', 'Sources/RuuviPoolCoordinator/*.{h,m,swift}' - ss.dependency 'RuuviPool/Contract' - ss.dependency 'RuuviPersistence' - ss.dependency 'RuuviPersistence/Realm' - ss.dependency 'RuuviPersistence/SQLite' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviLocal' - ss.dependency 'FutureX' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end - diff --git a/Packages/RuuviReactor/RuuviReactor.podspec b/Packages/RuuviReactor/RuuviReactor.podspec deleted file mode 100644 index 78f6eba2f..000000000 --- a/Packages/RuuviReactor/RuuviReactor.podspec +++ /dev/null @@ -1,36 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviReactor' - s.version = '0.0.1' - s.summary = 'Ruuvi Reactor' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviReactor/**/*.{h,m,swift}', 'Sources/RuuviReactor/*.{h,m,swift}' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviPersistence' - end - - s.subspec 'Impl' do |ss| - ss.source_files = 'Sources/RuuviReactorImpl/**/*.{h,m,swift}', 'Sources/RuuviReactorImpl/*.{h,m,swift}' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviContext' - ss.dependency 'RealmSwift' - ss.dependency 'GRDB.swift' - ss.dependency 'FutureX' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end - diff --git a/Packages/RuuviRepository/RuuviRepository.podspec b/Packages/RuuviRepository/RuuviRepository.podspec deleted file mode 100644 index 814994242..000000000 --- a/Packages/RuuviRepository/RuuviRepository.podspec +++ /dev/null @@ -1,37 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviRepository' - s.version = '0.0.1' - s.summary = 'Ruuvi Repository' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviRepository/**/*.{h,m,swift}', 'Sources/RuuviRepository/*.{h,m,swift}' - ss.dependency 'FutureX' - ss.dependency 'RuuviOntology' - end - - s.subspec 'Coordinator' do |ss| - ss.source_files = 'Sources/RuuviRepositoryCoordinator/**/*.{h,m,swift}', 'Sources/RuuviRepositoryCoordinator/*.{h,m,swift}' - ss.dependency 'RuuviRepository/Contract' - ss.dependency 'RuuviPool' - ss.dependency 'RuuviStorage' - ss.dependency 'RuuviOntology' - ss.dependency 'FutureX' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end - - diff --git a/Packages/RuuviService/RuuviService.podspec b/Packages/RuuviService/RuuviService.podspec deleted file mode 100644 index a74879d7f..000000000 --- a/Packages/RuuviService/RuuviService.podspec +++ /dev/null @@ -1,151 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviService' - s.version = '0.0.4' - s.summary = 'Ruuvi Service' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviService/**/*.{h,m,swift}', 'Sources/RuuviService/*.{h,m,swift}' - ss.dependency 'RuuviOntology' - ss.dependency 'FutureX' - end - - s.subspec 'Factory' do |ss| - ss.source_files = 'Sources/RuuviServiceFactory/**/*.{h,m,swift}', 'Sources/RuuviServiceFactory/*.{h,m,swift}' - ss.dependency 'RuuviOntology' - ss.dependency 'FutureX' - ss.dependency 'RuuviService/CloudSync' - ss.dependency 'RuuviService/Ownership' - ss.dependency 'RuuviService/SensorProperties' - ss.dependency 'RuuviService/SensorRecords' - ss.dependency 'RuuviService/AppSettings' - ss.dependency 'RuuviService/Alert' - ss.dependency 'RuuviService/OffsetCalibration' - end - - s.subspec 'Auth' do |ss| - ss.source_files = 'Sources/RuuviServiceAuth/**/*.{h,m,swift}', 'Sources/RuuviServiceAuth/*.{h,m,swift}' - ss.dependency 'RuuviService/Contract' - ss.dependency 'RuuviUser' - ss.dependency 'FutureX' - end - - s.subspec 'CloudSync' do |ss| - ss.source_files = 'Sources/RuuviServiceCloudSync/**/*.{h,m,swift}', 'Sources/RuuviServiceCloudSync/*.{h,m,swift}' - ss.dependency 'RuuviService/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviPool' - ss.dependency 'RuuviLocal' - ss.dependency 'RuuviStorage' - ss.dependency 'RuuviCloud' - ss.dependency 'RuuviRepository' - ss.dependency 'FutureX' - end - - s.subspec 'Ownership' do |ss| - ss.source_files = 'Sources/RuuviServiceOwnership/**/*.{h,m,swift}', 'Sources/RuuviServiceOwnership/*.{h,m,swift}' - ss.dependency 'RuuviService/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviPool' - ss.dependency 'RuuviStorage' - ss.dependency 'RuuviCloud' - ss.dependency 'RuuviUser' - ss.dependency 'FutureX' - end - - s.subspec 'SensorProperties' do |ss| - ss.source_files = 'Sources/RuuviServiceSensorProperties/**/*.{h,m,swift}', 'Sources/RuuviServiceSensorProperties/*.{h,m,swift}' - ss.dependency 'RuuviService/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviPool' - ss.dependency 'RuuviStorage' - ss.dependency 'RuuviCloud' - ss.dependency 'RuuviCore' - ss.dependency 'FutureX' - end - - s.subspec 'SensorRecords' do |ss| - ss.source_files = 'Sources/RuuviServiceSensorRecords/**/*.{h,m,swift}', 'Sources/RuuviServiceSensorRecords/*.{h,m,swift}' - ss.dependency 'RuuviService/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviPool' - ss.dependency 'RuuviLocal' - ss.dependency 'FutureX' - end - - s.subspec 'AppSettings' do |ss| - ss.source_files = 'Sources/RuuviServiceAppSettings/**/*.{h,m,swift}', 'Sources/RuuviServiceAppSettings/*.{h,m,swift}' - ss.dependency 'RuuviService/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviLocal' - ss.dependency 'RuuviCloud' - ss.dependency 'FutureX' - end - - s.subspec 'Alert' do |ss| - ss.source_files = 'Sources/RuuviServiceAlert/**/*.{h,m,swift}', 'Sources/RuuviServiceAlert/*.{h,m,swift}' - ss.dependency 'RuuviService/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviCloud' - ss.dependency 'FutureX' - end - - s.subspec 'OffsetCalibration' do |ss| - ss.source_files = 'Sources/RuuviServiceOffsetCalibration/**/*.{h,m,swift}', 'Sources/RuuviServiceOffsetCalibration/*.{h,m,swift}' - ss.dependency 'RuuviService/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviPool' - ss.dependency 'RuuviCloud' - ss.dependency 'FutureX' - end - - s.subspec 'Measurement' do |ss| - ss.source_files = 'Sources/RuuviServiceMeasurement/**/*.{h,m,swift}', 'Sources/RuuviServiceMeasurement/*.{h,m,swift}' - ss.dependency 'RuuviService/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviLocal' - end - - s.subspec 'Export' do |ss| - ss.source_files = 'Sources/RuuviServiceExport/**/*.{h,m,swift}', 'Sources/RuuviServiceExport/*.{h,m,swift}' - ss.dependency 'RuuviService/Contract' - ss.dependency 'Humidity' - ss.dependency 'FutureX' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviStorage' - end - - s.subspec 'GATT' do |ss| - ss.source_files = 'Sources/RuuviServiceGATT/**/*.{h,m,swift}', 'Sources/RuuviServiceGATT/*.{h,m,swift}' - ss.dependency 'RuuviService/Contract' - ss.dependency 'BTKit' - ss.dependency 'FutureX' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviPool' - end - - s.subspec 'CloudNotification' do |ss| - ss.source_files = 'Sources/RuuviServiceCloudNotification/**/*.{h,m,swift}', 'Sources/RuuviServiceCloudNotification/*.{h,m,swift}' - ss.dependency 'RuuviService/Contract' - ss.dependency 'RuuviOntology' - ss.dependency 'RuuviPool' - ss.dependency 'RuuviStorage' - ss.dependency 'RuuviCloud' - ss.dependency 'RuuviUser' - ss.dependency 'FutureX' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end diff --git a/Packages/RuuviStorage/RuuviStorage.podspec b/Packages/RuuviStorage/RuuviStorage.podspec deleted file mode 100644 index bf4d59efd..000000000 --- a/Packages/RuuviStorage/RuuviStorage.podspec +++ /dev/null @@ -1,35 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviStorage' - s.version = '0.0.1' - s.summary = 'Ruuvi Storage' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviStorage/**/*.{h,m,swift}', 'Sources/RuuviStorage/*.{h,m,swift}' - ss.dependency 'FutureX' - ss.dependency 'RuuviOntology' - end - - s.subspec 'Coordinator' do |ss| - ss.source_files = 'Sources/RuuviStorageCoordinator/**/*.{h,m,swift}', 'Sources/RuuviStorageCoordinator/*.{h,m,swift}' - ss.dependency 'RuuviStorage/Contract' - ss.dependency 'RuuviPersistence/Realm' - ss.dependency 'RuuviPersistence/SQLite' - ss.dependency 'RuuviOntology' - ss.dependency 'FutureX' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end diff --git a/Packages/RuuviUser/RuuviUser.podspec b/Packages/RuuviUser/RuuviUser.podspec deleted file mode 100644 index a473806ac..000000000 --- a/Packages/RuuviUser/RuuviUser.podspec +++ /dev/null @@ -1,30 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'RuuviUser' - s.version = '0.0.1' - s.summary = 'Ruuvi User' - s.homepage = 'https://ruuvi.com' - s.author = { 'Rinat Enikeev' => 'rinat@ruuvi.com' } - s.license = { :type => 'BSD 3-Clause', :file => '../../LICENSE' } - s.platform = :ios, '10.0' - s.source = { git: 'https://github.com/ruuvi/com.ruuvi.station.ios' } - s.frameworks = 'Foundation' - s.requires_arc = true - s.ios.deployment_target = '10.0' - s.swift_version = '5.0' - - s.default_subspecs = 'Contract' - - s.subspec 'Contract' do |ss| - ss.source_files = 'Sources/RuuviUser/**/*.{h,m,swift}', 'Sources/RuuviUser/*.{h,m,swift}' - end - - s.subspec 'Coordinator' do |ss| - ss.source_files = 'Sources/RuuviUserCoordinator/**/*.{h,m,swift}', 'Sources/RuuviUserCoordinator/*.{h,m,swift}' - ss.dependency 'RuuviUser/Contract' - ss.dependency 'KeychainAccess' - end - - s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/**/*.{swift}', 'Tests/*.{swift}' - end -end From d0e6f181c998aa5ff06dd66b2c0ebfc408578ba7 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sun, 17 Dec 2023 22:16:18 +0200 Subject: [PATCH 57/84] Remove all Info.plists (#1799) As they are generated on make command --- .gitignore | 1 + Apps/RuuviStation/Info.plist | 103 ------------------ Apps/RuuviStation/Intents/Info.plist | 44 -------- .../NotificationService/Info.plist | 33 ------ Apps/RuuviStation/Tests/Unit/Info.plist | 22 ---- Apps/RuuviStation/Widgets/Info.plist | 40 ------- Apps/RuuviStation/Widgets/Sources/Info.plist | 40 ------- Common/RuuviLocalization/Info.plist | 22 ---- Common/RuuviPresenters/Info.plist | 22 ---- Modules/RuuviDiscover/Info.plist | 22 ---- Modules/RuuviFirmware/Info.plist | 22 ---- Modules/RuuviOnboard/Info.plist | 22 ---- Packages/RuuviAnalytics/Info.plist | 22 ---- Packages/RuuviCloud/Info.plist | 22 ---- Packages/RuuviContext/Info.plist | 22 ---- Packages/RuuviCore/Info.plist | 22 ---- Packages/RuuviDFU/Info.plist | 22 ---- Packages/RuuviDaemon/Info.plist | 22 ---- Packages/RuuviLocal/Info.plist | 22 ---- Packages/RuuviMigration/Info.plist | 22 ---- Packages/RuuviNotification/Info.plist | 22 ---- Packages/RuuviNotifier/Info.plist | 22 ---- Packages/RuuviOntology/Info.plist | 22 ---- Packages/RuuviPersistence/Info.plist | 22 ---- Packages/RuuviPool/Info.plist | 22 ---- Packages/RuuviReactor/Info.plist | 22 ---- Packages/RuuviRepository/Info.plist | 22 ---- Packages/RuuviService/Info.plist | 22 ---- Packages/RuuviStorage/Info.plist | 22 ---- Packages/RuuviUser/Info.plist | 22 ---- 30 files changed, 1 insertion(+), 788 deletions(-) delete mode 100644 Apps/RuuviStation/Info.plist delete mode 100644 Apps/RuuviStation/Intents/Info.plist delete mode 100644 Apps/RuuviStation/NotificationService/Info.plist delete mode 100644 Apps/RuuviStation/Tests/Unit/Info.plist delete mode 100644 Apps/RuuviStation/Widgets/Info.plist delete mode 100644 Apps/RuuviStation/Widgets/Sources/Info.plist delete mode 100644 Common/RuuviLocalization/Info.plist delete mode 100644 Common/RuuviPresenters/Info.plist delete mode 100644 Modules/RuuviDiscover/Info.plist delete mode 100644 Modules/RuuviFirmware/Info.plist delete mode 100644 Modules/RuuviOnboard/Info.plist delete mode 100644 Packages/RuuviAnalytics/Info.plist delete mode 100644 Packages/RuuviCloud/Info.plist delete mode 100644 Packages/RuuviContext/Info.plist delete mode 100644 Packages/RuuviCore/Info.plist delete mode 100644 Packages/RuuviDFU/Info.plist delete mode 100644 Packages/RuuviDaemon/Info.plist delete mode 100644 Packages/RuuviLocal/Info.plist delete mode 100644 Packages/RuuviMigration/Info.plist delete mode 100644 Packages/RuuviNotification/Info.plist delete mode 100644 Packages/RuuviNotifier/Info.plist delete mode 100644 Packages/RuuviOntology/Info.plist delete mode 100644 Packages/RuuviPersistence/Info.plist delete mode 100644 Packages/RuuviPool/Info.plist delete mode 100644 Packages/RuuviReactor/Info.plist delete mode 100644 Packages/RuuviRepository/Info.plist delete mode 100644 Packages/RuuviService/Info.plist delete mode 100644 Packages/RuuviStorage/Info.plist delete mode 100644 Packages/RuuviUser/Info.plist diff --git a/.gitignore b/.gitignore index edcf80ae4..c3e866686 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ # Generated Ruuvi.xcodeproj +**/Info.plist # Private station/Resources/Plists/GoogleService-Info.plist diff --git a/Apps/RuuviStation/Info.plist b/Apps/RuuviStation/Info.plist deleted file mode 100644 index d46075408..000000000 --- a/Apps/RuuviStation/Info.plist +++ /dev/null @@ -1,103 +0,0 @@ - - - - - BGTaskSchedulerPermittedIdentifiers - - com.ruuvi.station.BackgroundProcessServiceiOS13.dataPruning - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Ruuvi Station - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - FirebaseMessagingAutoInitEnabled - - LSApplicationQueriesSchemes - - https - http - mailto - - LSRequiresIPhoneOS - - NFCReaderUsageDescription - Allows user to claim a RuuviTag using NFC when the user has physical access to the sensor - NSBluetoothAlwaysUsageDescription - The app uses Bluetooth LE to read data from Ruuvi Sensors - NSBluetoothPeripheralUsageDescription - The app uses Bluetooth LE to read data from RuuviTag sensors. - NSCameraUsageDescription - Ruuvi Station needs to access your camera in order to be able to capture photos and use them as sensor background. - NSLocationAlwaysAndWhenInUseUsageDescription - Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. - NSLocationAlwaysUsageDescription - Ruuvi Station needs to access your location while being in background in order to pull data for Virtual Sensors for your current location and display alerts. - NSLocationUsageDescription - Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. - NSLocationWhenInUseUsageDescription - Ruuvi Station needs to access your location in order to determine your position and show weather parameters for you live location. - NSPhotoLibraryUsageDescription - Ruuvi Station needs to access your camera roll to enable selecting the background for the sensor. - NSUserActivityTypes - - RuuviTagSelectionIntent - - UIAppFonts - - Oswald-Bold.ttf - Oswald-ExtraLight.ttf - Muli-Regular.ttf - Muli-Bold.ttf - Muli-SemiBoldItalic.ttf - Muli-ExtraBold.ttf - Montserrat-Bold.ttf - Montserrat-Regular.ttf - Montserrat-ExtraBold.ttf - - UIBackgroundModes - - bluetooth-central - processing - remote-notification - - UILaunchStoryboardName - LaunchScreen - UIRequiredDeviceCapabilities - - armv7 - - UIRequiresFullScreen - - UIStatusBarStyle - UIStatusBarStyleLightContent - UISupportedInterfaceOrientations - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - UIInterfaceOrientationPortrait - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - - UIViewControllerBasedStatusBarAppearance - - - diff --git a/Apps/RuuviStation/Intents/Info.plist b/Apps/RuuviStation/Intents/Info.plist deleted file mode 100644 index cde80a610..000000000 --- a/Apps/RuuviStation/Intents/Info.plist +++ /dev/null @@ -1,44 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Ruuvi Station - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSExtension - - NSExtensionAttributes - - IntentsRestrictedWhileLocked - - IntentsRestrictedWhileProtectedDataUnavailable - - IntentsSupported - - RuuviTagSelectionIntent - - - NSExtensionPointIdentifier - com.apple.intents-service - NSExtensionPrincipalClass - $(PRODUCT_MODULE_NAME).IntentHandler - - NSHumanReadableCopyright - Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. - - diff --git a/Apps/RuuviStation/NotificationService/Info.plist b/Apps/RuuviStation/NotificationService/Info.plist deleted file mode 100644 index 1383832e9..000000000 --- a/Apps/RuuviStation/NotificationService/Info.plist +++ /dev/null @@ -1,33 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Ruuvi Station - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSExtension - - NSExtensionPointIdentifier - com.apple.usernotifications.service - NSExtensionPrincipalClass - $(PRODUCT_MODULE_NAME).NotificationService - - NSHumanReadableCopyright - Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. - - diff --git a/Apps/RuuviStation/Tests/Unit/Info.plist b/Apps/RuuviStation/Tests/Unit/Info.plist deleted file mode 100644 index 6c40a6cd0..000000000 --- a/Apps/RuuviStation/Tests/Unit/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/Apps/RuuviStation/Widgets/Info.plist b/Apps/RuuviStation/Widgets/Info.plist deleted file mode 100644 index df44555c2..000000000 --- a/Apps/RuuviStation/Widgets/Info.plist +++ /dev/null @@ -1,40 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Ruuvi Station - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSExtension - - NSExtensionPointIdentifier - com.apple.widgetkit-extension - - NSHumanReadableCopyright - Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. - UIAppFonts - - Oswald-Bold.ttf - Oswald-ExtraLight.ttf - Muli-Regular.ttf - Muli-Bold.ttf - Montserrat-Bold.ttf - Montserrat-Regular.ttf - - - diff --git a/Apps/RuuviStation/Widgets/Sources/Info.plist b/Apps/RuuviStation/Widgets/Sources/Info.plist deleted file mode 100644 index df44555c2..000000000 --- a/Apps/RuuviStation/Widgets/Sources/Info.plist +++ /dev/null @@ -1,40 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Ruuvi Station - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSExtension - - NSExtensionPointIdentifier - com.apple.widgetkit-extension - - NSHumanReadableCopyright - Copyright © 2023 Ruuvi Innovations Oy. All rights reserved. - UIAppFonts - - Oswald-Bold.ttf - Oswald-ExtraLight.ttf - Muli-Regular.ttf - Muli-Bold.ttf - Montserrat-Bold.ttf - Montserrat-Regular.ttf - - - diff --git a/Common/RuuviLocalization/Info.plist b/Common/RuuviLocalization/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Common/RuuviLocalization/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Common/RuuviPresenters/Info.plist b/Common/RuuviPresenters/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Common/RuuviPresenters/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Modules/RuuviDiscover/Info.plist b/Modules/RuuviDiscover/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Modules/RuuviDiscover/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Modules/RuuviFirmware/Info.plist b/Modules/RuuviFirmware/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Modules/RuuviFirmware/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Modules/RuuviOnboard/Info.plist b/Modules/RuuviOnboard/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Modules/RuuviOnboard/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviAnalytics/Info.plist b/Packages/RuuviAnalytics/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviAnalytics/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviCloud/Info.plist b/Packages/RuuviCloud/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviCloud/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviContext/Info.plist b/Packages/RuuviContext/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviContext/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviCore/Info.plist b/Packages/RuuviCore/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviCore/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviDFU/Info.plist b/Packages/RuuviDFU/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviDFU/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviDaemon/Info.plist b/Packages/RuuviDaemon/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviDaemon/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviLocal/Info.plist b/Packages/RuuviLocal/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviLocal/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviMigration/Info.plist b/Packages/RuuviMigration/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviMigration/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviNotification/Info.plist b/Packages/RuuviNotification/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviNotification/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviNotifier/Info.plist b/Packages/RuuviNotifier/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviNotifier/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviOntology/Info.plist b/Packages/RuuviOntology/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviOntology/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviPersistence/Info.plist b/Packages/RuuviPersistence/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviPersistence/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviPool/Info.plist b/Packages/RuuviPool/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviPool/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviReactor/Info.plist b/Packages/RuuviReactor/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviReactor/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviRepository/Info.plist b/Packages/RuuviRepository/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviRepository/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviService/Info.plist b/Packages/RuuviService/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviService/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviStorage/Info.plist b/Packages/RuuviStorage/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviStorage/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - diff --git a/Packages/RuuviUser/Info.plist b/Packages/RuuviUser/Info.plist deleted file mode 100644 index 0f6add7d8..000000000 --- a/Packages/RuuviUser/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - - From b26275378f50731eff60c5bd7722fb6b5e22d835 Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Mon, 18 Dec 2023 18:34:14 +0100 Subject: [PATCH 58/84] fix: Remove context menu for force tap on dashboard #1632 (#1801) --- .../Home/View/DashboardViewController.swift | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift index 2f5b07cd6..911e11df1 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift @@ -156,8 +156,6 @@ class DashboardViewController: UIViewController { private var isListRefreshable: Bool = true private var isRefreshing: Bool = false - /// The view model when context menu is presented after a card tap. - private var highlightedViewModel: CardsViewModel? deinit { appDidBecomeActiveToken?.invalidate() @@ -596,33 +594,6 @@ extension DashboardViewController: UICollectionViewDataSource { } extension DashboardViewController: UICollectionViewDelegate { - func collectionView( - _: UICollectionView, - contextMenuConfigurationForItemAt indexPath: IndexPath, - point _: CGPoint - ) -> UIContextMenuConfiguration? { - configureContextMenu(index: indexPath.row) - } - - func configureContextMenu(index: Int) -> UIContextMenuConfiguration { - let context = UIContextMenuConfiguration( - identifier: nil, - previewProvider: nil - ) { [weak self] - _ -> UIMenu? in - self?.highlightedViewModel = self?.viewModels[index] - return self?.cardContextMenuOption(for: index) - } - return context - } - - func collectionView( - _: UICollectionView, - willEndContextMenuInteraction _: UIContextMenuConfiguration, - animator _: UIContextMenuInteractionAnimating? - ) { - highlightedViewModel = nil - } func collectionView( _: UICollectionView, @@ -767,12 +738,6 @@ extension DashboardViewController: UICollectionViewDropDelegate { extension DashboardViewController: DashboardViewInput { func applyUpdate(to viewModel: CardsViewModel) { - if let highlightedViewModel, - highlightedViewModel.luid.value != nil && highlightedViewModel.luid.value == viewModel.luid.value || - highlightedViewModel.mac.value != nil && highlightedViewModel.mac.value == viewModel.mac.value { - return - } - guard isListRefreshable else { return From fccc37fee4e24c3fd0be48f3b96aeb3c90443eda Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Mon, 18 Dec 2023 18:57:06 +0100 Subject: [PATCH 59/84] fix: Hide sensor order action for alphabetical sorting #1690 (#1802) --- .../Home/Presenter/DashboardPresenter.swift | 15 +++++++++++---- .../Home/View/DashboardViewController.swift | 19 ++++++++++++++++--- .../Home/View/DashboardViewInput.swift | 1 + 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift index 70e5358f3..058794346 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift @@ -247,9 +247,10 @@ extension DashboardPresenter: DashboardViewOutput { } func viewDidTriggerRename(for viewModel: CardsViewModel) { - let sortingType: DashboardSortingType = - settings.dashboardSensorOrder.count == 0 ? .alphabetical : .manual - view?.showSensorNameRenameDialog(for: viewModel, sortingType: sortingType) + view?.showSensorNameRenameDialog( + for: viewModel, + sortingType: dashboardSortingType() + ) } func viewDidTriggerShare(for viewModel: CardsViewModel) { @@ -337,6 +338,7 @@ extension DashboardPresenter: DashboardViewOutput { settings.dashboardSensorOrder = orderedIds ruuviAppSettingsService.set(dashboardSensorOrder: orderedIds) viewModels = reorder(viewModels) + view?.dashboardSortingType = dashboardSortingType() } func viewDidResetManualSorting() { @@ -574,6 +576,7 @@ extension DashboardPresenter { view?.userSignedInOnce = settings.signedInAtleastOnce view?.dashboardType = settings.dashboardType view?.dashboardTapActionType = settings.dashboardTapActionType + view?.dashboardSortingType = dashboardSortingType() let ruuviViewModels = ruuviTags.compactMap { ruuviTag -> CardsViewModel in let viewModel = CardsViewModel(ruuviTag) @@ -650,7 +653,7 @@ extension DashboardPresenter { } } - if settings.dashboardSensorOrder.count == 0 { + if dashboardSortingType() == .alphabetical { viewModels.append(viewModel) viewModels = reorder(viewModels) } else { @@ -1919,6 +1922,10 @@ extension DashboardPresenter { } } } + + private func dashboardSortingType() -> DashboardSortingType { + return settings.dashboardSensorOrder.count == 0 ? .alphabetical : .manual + } } // swiftlint:enable file_length diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift index 911e11df1..1dc615cd1 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift @@ -36,6 +36,12 @@ class DashboardViewController: UIViewController { } } + var dashboardSortingType: DashboardSortingType! { + didSet { + viewButton.updateMenu(with: viewToggleMenuOptions()) + } + } + var userSignedInOnce: Bool = false { didSet { noSensorView.userSignedInOnce = userSignedInOnce @@ -317,11 +323,18 @@ extension DashboardViewController { ] ) + var menuItems: [UIMenuElement] = [ + cardTypeMenu, + cardActionMenu, + ] + + if dashboardSortingType == .manual { + menuItems.append(resetSensorSortingOrderMenu) + } + return UIMenu( title: "", - children: [ - cardTypeMenu, cardActionMenu, resetSensorSortingOrderMenu - ] + children: menuItems ) } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift index 4ae76854b..47139a4c1 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift @@ -6,6 +6,7 @@ protocol DashboardViewInput: ViewInput { var viewModels: [CardsViewModel] { get set } var dashboardType: DashboardType! { get set } var dashboardTapActionType: DashboardTapActionType! { get set } + var dashboardSortingType: DashboardSortingType! { get set } var userSignedInOnce: Bool { get set } func applyUpdate(to viewModel: CardsViewModel) func showNoSensorsAddedMessage(show: Bool) From e583b7267eed883fd193fa9f03511d3175dec430 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Mon, 18 Dec 2023 21:05:14 +0200 Subject: [PATCH 60/84] Bump BTKit version (#1800) * Bump BTKit version To apply fix for network df3 parser * bump one more --- project.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.yml b/project.yml index 47bd9a3ae..5faff1328 100644 --- a/project.yml +++ b/project.yml @@ -82,7 +82,7 @@ targetTemplates: packages: BTKit: url: https://github.com/ruuvi/BTKit - version: 0.4.3 + from: 0.5.2 Charts: url: https://github.com/danielgindi/Charts from: 4.1.0 From 3391e229306aaf5a80403a86f4e5df2c9d2bd408 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Tue, 19 Dec 2023 22:25:57 +0200 Subject: [PATCH 61/84] NotificationService localization fixes (#1804) Implements localization for notifications except ovement and offline --- .../Sources/NotificationService.swift | 62 +++++++------------ .../NotificationService/target.yml | 26 +++++++- .../View/UI/TagChartsViewController.swift | 2 +- .../OffsetCorrectionAppleViewController.swift | 4 +- .../View/UI/TagSettingsViewController.swift | 52 +++++++++++----- .../HumidityUnit+Localization.swift | 3 +- .../Structs/ExportHeadersProvider.swift | 8 +-- .../RuuviStation/Sources/Station.entitlements | 8 +-- .../Templates/strings-swift5.stencil | 19 ++++-- .../RuuviLocalSettingsUserDefaults.swift | 4 +- 10 files changed, 110 insertions(+), 78 deletions(-) diff --git a/Apps/RuuviStation/NotificationService/Sources/NotificationService.swift b/Apps/RuuviStation/NotificationService/Sources/NotificationService.swift index 537d14b17..aac58fb0c 100644 --- a/Apps/RuuviStation/NotificationService/Sources/NotificationService.swift +++ b/Apps/RuuviStation/NotificationService/Sources/NotificationService.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UserNotifications class NotificationService: UNNotificationServiceExtension { @@ -106,62 +107,45 @@ extension NotificationService { return "" } - var format = "" + let languageUDKey = "SettingsUserDegaults.languageUDKey" + let locale: Locale + if let languageCode = notificationServiceAppGroup?.string(forKey: languageUDKey) { + locale = Locale(identifier: languageCode) + } else { + locale = .current + } + switch triggerType { case .under: switch alertType { case .temperature: - format = "alert_notification_temperature_low_threshold" + return RuuviLocalization.alertNotificationTemperatureLowThreshold(threshold, locale) case .humidity: - format = "alert_notification_humidity_low_threshold" + return RuuviLocalization.alertNotificationHumidityLowThreshold(threshold, locale) case .pressure: - format = "alert_notification_pressure_low_threshold" + return RuuviLocalization.alertNotificationPressureLowThreshold(threshold, locale) case .signal: - format = "alert_notification_rssi_low_threshold" + return RuuviLocalization.alertNotificationRssiLowThreshold(threshold, locale) case .movement: - let format = "LocalNotificationsManager.DidMove.title" - return localized(value: format) - default: - break + return RuuviLocalization.LocalNotificationsManager.DidMove.title // TODO: @rinat localize + case .offline: + return "" // TODO: @rinat obtain spec } case .over: switch alertType { case .temperature: - format = "alert_notification_temperature_high_threshold" + return RuuviLocalization.alertNotificationTemperatureHighThreshold(threshold, locale) case .humidity: - format = "alert_notification_humidity_high_threshold" + return RuuviLocalization.alertNotificationHumidityHighThreshold(threshold, locale) case .pressure: - format = "alert_notification_pressure_high_threshold" + return RuuviLocalization.alertNotificationPressureHighThreshold(threshold, locale) case .signal: - format = "alert_notification_rssi_high_threshold" + return RuuviLocalization.alertNotificationRssiHighThreshold(threshold, locale) case .movement: - let format = "LocalNotificationsManager.DidMove.title" - return localized(value: format) - default: - break + return RuuviLocalization.LocalNotificationsManager.DidMove.title // TODO: @rinat localize + case .offline: + return "" // TODO: @rinat obtain spec } } - - return String(format: localized(value: format), threshold) - } - - private func localized(value: String) -> String { - let languageUDKey = "SettingsUserDegaults.languageUDKey" - guard let languageCode = notificationServiceAppGroup?.string(forKey: languageUDKey), - let bundle = Bundle.main.path( - forResource: languageCode, - ofType: "lproj" - ), - let languageBundle = Bundle(path: bundle) - else { - return NSLocalizedString(value, comment: value) - } - - return NSLocalizedString( - value, - tableName: nil, - bundle: languageBundle, - comment: value - ) } } diff --git a/Apps/RuuviStation/NotificationService/target.yml b/Apps/RuuviStation/NotificationService/target.yml index 78a600716..6bdf91c5b 100644 --- a/Apps/RuuviStation/NotificationService/target.yml +++ b/Apps/RuuviStation/NotificationService/target.yml @@ -36,6 +36,30 @@ targets: excludes: - "*.entitlements" - Info.plist + - path: ../Widgets/Sources resources: - path: ../Sources/Resources/Strings/ - - path: ../Sources/Resources/Sounds/ \ No newline at end of file + - path: ../Sources/Resources/Sounds/ + dependencies: + - package: Swinject + - package: BTKit + - package: Future + - package: GRDB + - package: Humidity + - package: KeychainAccess + - target: RuuviUser + embed: true + - target: RuuviCloud + embed: true + - target: RuuviOntology + embed: true + - target: RuuviPool + embed: true + - target: RuuviLocal + embed: true + - target: RuuviPersistence + embed: true + - target: RuuviContext + embed: true + - target: RuuviLocalization + embed: true \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift index b53c01d7b..28646ec8d 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift @@ -798,7 +798,7 @@ extension TagChartsViewController: TagChartsViewInput { syncStatusLabel.text = RuuviLocalization.TagCharts.Status.serving case let .reading(points): let format = RuuviLocalization.readingHistoryX - syncStatusLabel.text = format(Float(points)) + syncStatusLabel.text = format(Float(points), Locale.current) case .disconnecting: syncStatusLabel.text = RuuviLocalization.TagCharts.Status.disconnecting case .success: diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift index a09096e17..f891261fa 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift @@ -195,11 +195,11 @@ extension OffsetCorrectionAppleViewController: OffsetCorrectionViewInput { case .pressure: let format = RuuviLocalization.OffsetCorrection.Dialog.Calibration.enterPressure let unit = viewModel.pressureUnit.value ?? .hectopascals - message = format(unit.symbol) + message = format(unit.symbol, Locale.current) default: let format = RuuviLocalization.OffsetCorrection.Dialog.Calibration.enterTemperature let unit = viewModel.temperatureUnit.value ?? .celsius - message = format(unit.symbol) + message = format(unit.symbol, Locale.current) } let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift index ebe619d50..3041a7c3d 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift @@ -178,7 +178,8 @@ class TagSettingsViewController: UIViewController { private lazy var temperatureAlertSection: TagSettingsSection? = { let sectionTitle = temperatureAlertFormat( - viewModel?.temperatureUnit.value?.symbol ?? RuuviLocalization.na + viewModel?.temperatureUnit.value?.symbol ?? RuuviLocalization.na, + Locale.current ) let section = TagSettingsSection( identifier: .alertTemperature, @@ -203,7 +204,7 @@ class TagSettingsViewController: UIViewController { private lazy var humidityAlertSection: TagSettingsSection? = { let symbol = HumidityUnit.percent.symbol - let sectionTitle = airHumidityAlertFormat(symbol) + let sectionTitle = airHumidityAlertFormat(symbol, Locale.current) let section = TagSettingsSection( identifier: .alertHumidity, title: sectionTitle, @@ -227,7 +228,7 @@ class TagSettingsViewController: UIViewController { private lazy var pressureAlertSection: TagSettingsSection? = { let sectionTitle = pressureAlertFormat( - viewModel?.pressureUnit.value?.symbol ?? RuuviLocalization.na + viewModel?.pressureUnit.value?.symbol ?? RuuviLocalization.na, Locale.current ) let section = TagSettingsSection( identifier: .alertPressure, @@ -941,7 +942,7 @@ extension TagSettingsViewController { tableView.bind(viewModel.temperatureUnit) { [weak self] _, value in guard let sSelf = self else { return } sSelf.temperatureAlertSection?.title = sSelf.temperatureAlertFormat( - value?.symbol ?? RuuviLocalization.na + value?.symbol ?? RuuviLocalization.na, Locale.current ) } @@ -999,7 +1000,7 @@ extension TagSettingsViewController { header, unit in guard let sSelf = self else { return } let sectionTitle = sSelf.temperatureAlertFormat( - unit?.symbol ?? RuuviLocalization.na + unit?.symbol ?? RuuviLocalization.na, Locale.current ) header.setTitle(with: sectionTitle) } @@ -1119,7 +1120,7 @@ extension TagSettingsViewController { tableView.bind(viewModel.pressureUnit) { [weak self] _, value in guard let sSelf = self else { return } sSelf.pressureAlertSection?.title = sSelf.pressureAlertFormat( - value?.symbol ?? RuuviLocalization.na + value?.symbol ?? RuuviLocalization.na, Locale.current ) } @@ -1179,7 +1180,7 @@ extension TagSettingsViewController { [weak self] header, unit in guard let sSelf = self else { return } let sectionTitle = sSelf.pressureAlertFormat( - unit?.symbol ?? RuuviLocalization.na + unit?.symbol ?? RuuviLocalization.na, Locale.current ) header.setTitle(with: sectionTitle) } @@ -1876,13 +1877,27 @@ extension TagSettingsViewController { guard isViewLoaded else { return nil } let format = RuuviLocalization.TagSettings.Alerts.Temperature.description if let min, let max { - return attributedString(from: format(Float(min), Float(max))) + return attributedString(from: format(Float(min), Float(max), Locale.current)) } if let tu = viewModel?.temperatureUnit.value?.unitTemperature, let l = viewModel?.temperatureLowerBound.value?.converted(to: tu), let u = viewModel?.temperatureUpperBound.value?.converted(to: tu) { - return attributedString(from: format(Float(l.value.round(to: 2)), Float(u.value.round(to: 2)))) + return attributedString( + from: format( + Float( + l.value.round( + to: 2 + ) + ), + Float( + u.value.round( + to: 2 + ) + ), + Locale.current + ) + ) } else { return nil } @@ -1932,13 +1947,14 @@ extension TagSettingsViewController { guard isViewLoaded else { return nil } let format = RuuviLocalization.TagSettings.Alerts.Temperature.description if let min, let max { - return attributedString(from: format(Float(min), Float(max))) + return attributedString(from: format(Float(min), Float(max), Locale.current)) } if let l = viewModel?.relativeHumidityLowerBound.value, let u = viewModel?.relativeHumidityUpperBound.value { let message = format( Float(l.round(to: 2)), - Float(u.round(to: 2)) + Float(u.round(to: 2)), + Locale.current ) return attributedString(from: message) } else { @@ -1984,7 +2000,7 @@ extension TagSettingsViewController { if let minValue, let maxValue { return attributedString( - from: format(Float(minValue), Float(maxValue)) + from: format(Float(minValue), Float(maxValue), Locale.current) ) } @@ -2001,7 +2017,8 @@ extension TagSettingsViewController { ) let message = format( Float(l.round(to: 2)), - Float(u.round(to: 2)) + Float(u.round(to: 2)), + Locale.current ) return attributedString(from: message) } else { @@ -2063,7 +2080,7 @@ extension TagSettingsViewController { if let min, let max { return attributedString( - from: format(Float(min), Float(max)) + from: format(Float(min), Float(max), Locale.current) ) } @@ -2071,7 +2088,8 @@ extension TagSettingsViewController { let upper = viewModel?.signalUpperBound.value { let message = format( Float(lower), - Float(upper) + Float(upper), + Locale.current ) return attributedString(from: message) } else { @@ -3740,7 +3758,7 @@ extension TagSettingsViewController { alertTextField.delegate = self let format = RuuviLocalization.TagSettings.AlertSettings.Dialog.min alertTextField.placeholder = format( - Float(minimumBound) + Float(minimumBound), Locale.current ) alertTextField.keyboardType = .decimalPad alertMinRangeTextField = alertTextField @@ -3757,7 +3775,7 @@ extension TagSettingsViewController { alertTextField.delegate = self let format = RuuviLocalization.TagSettings.AlertSettings.Dialog.max alertTextField.placeholder = format( - Float(maximumBound) + Float(maximumBound), Locale.current ) alertTextField.keyboardType = .decimalPad alertMaxRangeTextField = alertTextField diff --git a/Apps/RuuviStation/Sources/Extensions/HumidityUnit+Localization.swift b/Apps/RuuviStation/Sources/Extensions/HumidityUnit+Localization.swift index 922004d74..5e0c978fa 100644 --- a/Apps/RuuviStation/Sources/Extensions/HumidityUnit+Localization.swift +++ b/Apps/RuuviStation/Sources/Extensions/HumidityUnit+Localization.swift @@ -7,8 +7,7 @@ extension HumidityUnit: SelectionItemProtocol { switch self { case .percent: { _ in RuuviLocalization.HumidityUnit.Percent.title } case .gm3: { _ in RuuviLocalization.HumidityUnit.Gm3.title } - case .dew: - RuuviLocalization.HumidityUnit.Dew.title + case .dew: { param in RuuviLocalization.HumidityUnit.Dew.title(param, Locale.current) } } } diff --git a/Apps/RuuviStation/Sources/Extensions/Structs/ExportHeadersProvider.swift b/Apps/RuuviStation/Sources/Extensions/Structs/ExportHeadersProvider.swift index 0af7acf2b..92240a85e 100644 --- a/Apps/RuuviStation/Sources/Extensions/Structs/ExportHeadersProvider.swift +++ b/Apps/RuuviStation/Sources/Extensions/Structs/ExportHeadersProvider.swift @@ -9,11 +9,11 @@ struct ExportHeadersProvider: RuuviServiceExportHeaders { let humidityFormat = RuuviLocalization.ExportService.humidity return [ RuuviLocalization.ExportService.date, - tempFormat(units.temperatureUnit.symbol), + tempFormat(units.temperatureUnit.symbol, Locale.current), units.humidityUnit == .dew - ? humidityFormat(units.temperatureUnit.symbol) - : humidityFormat(units.humidityUnit.symbol), - pressureFormat(units.pressureUnit.symbol), + ? humidityFormat(units.temperatureUnit.symbol, Locale.current) + : humidityFormat(units.humidityUnit.symbol, Locale.current), + pressureFormat(units.pressureUnit.symbol, Locale.current), "RSSI" + " (\(RuuviLocalization.dBm))", RuuviLocalization.ExportService.accelerationX + " (\(RuuviLocalization.g))", RuuviLocalization.ExportService.accelerationY + " (\(RuuviLocalization.g))", diff --git a/Apps/RuuviStation/Sources/Station.entitlements b/Apps/RuuviStation/Sources/Station.entitlements index 8e9efd5cd..6b8b1a52d 100644 --- a/Apps/RuuviStation/Sources/Station.entitlements +++ b/Apps/RuuviStation/Sources/Station.entitlements @@ -9,12 +9,12 @@ applinks:network.ruuvi.com applinks:station.ruuvi.com + com.apple.developer.nfc.readersession.formats + + TAG + com.apple.security.app-sandbox - com.apple.developer.nfc.readersession.formats - - TAG - com.apple.security.application-groups group.com.ruuvi.station.pnservice diff --git a/Common/RuuviLocalization/Templates/strings-swift5.stencil b/Common/RuuviLocalization/Templates/strings-swift5.stencil index 14f387f37..0a54436cd 100644 --- a/Common/RuuviLocalization/Templates/strings-swift5.stencil +++ b/Common/RuuviLocalization/Templates/strings-swift5.stencil @@ -40,8 +40,8 @@ import Foundation {% endif %} {% set translation string.translation|replace:'"','\"'|replace:' ','\t' %} {% if string.types %} - {{accessModifier}} static func {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}({% call parametersBlock string.types %}) -> String { - {{enumName}}.tr("{{table}}", "{{string.key}}", {%+ call argumentsBlock string.types %}, fallback: "{{translation}}") + {{accessModifier}} static func {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}({% call parametersBlock string.types %}, _ locale: Locale = Locale.current) -> String { + {{enumName}}.tr("{{table}}", "{{string.key}}", {%+ call argumentsBlock string.types %}, fallback: "{{translation}}", locale: locale) } {% elif param.lookupFunction %} {{accessModifier}} static var {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}: String { return {{enumName}}.tr("{{table}}", "{{string.key}}", fallback: "{{translation}}") } @@ -75,13 +75,22 @@ import Foundation // MARK: - Implementation Details extension {{enumName}} { - private static func tr(_ table: String, _ key: String, _ args: CVarArg..., fallback value: String) -> String { + private static func tr(_ table: String, _ key: String, _ args: CVarArg..., fallback value: String, locale: Locale = Locale.current) -> String { {% if param.lookupFunction %} let format = {{ param.lookupFunction }}(key, table, value) {% else %} - let format = {{param.bundle|default:"BundleToken.bundle"}}.localizedString(forKey: key, value: value, table: table) + let format: String + if let bundle = BundleToken.bundle.path( + forResource: locale.identifier, + ofType: "lproj" + ), let languageBundle = Bundle(path: bundle) { + format = languageBundle.localizedString(forKey: key, value: value, table: table) + } else { + format = {{param.bundle|default:"BundleToken.bundle"}}.localizedString(forKey: key, value: value, table: table) + } + {% endif %} - return String(format: format, locale: Locale.current, arguments: args) + return String(format: format, locale: locale, arguments: args) } } {% if not param.bundle and not param.lookupFunction %} diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift index 351d5df97..e66d292d4 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift @@ -42,10 +42,8 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { private let notificationServiceAppGroup = UserDefaults(suiteName: "group.com.ruuvi.station.pnservice") var language: Language { get { - if let savedCode = UserDefaults.standard.string(forKey: languageUDKey) { + if let savedCode = notificationServiceAppGroup?.string(forKey: languageUDKey) { Language(rawValue: savedCode) ?? .english - } else if let regionCode = Locale.current.languageCode { - Language(rawValue: regionCode) ?? .english } else { .english } From 3f94a7590b46a7779d369238a702345a6006d5d3 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Wed, 20 Dec 2023 19:13:07 +0200 Subject: [PATCH 62/84] Fix localizations in PN service (#1807) Including movement --- .../Sources/NotificationService.swift | 4 +- .../View/UI/TagChartsViewController.swift | 2 +- .../OffsetCorrectionAppleViewController.swift | 4 +- .../View/UI/TagSettingsViewController.swift | 39 ++++++++----------- .../HumidityUnit+Localization.swift | 2 +- .../Structs/ExportHeadersProvider.swift | 8 ++-- .../Templates/strings-swift5.stencil | 16 +++++--- Common/RuuviLocalization/target.yml | 2 + 8 files changed, 40 insertions(+), 37 deletions(-) diff --git a/Apps/RuuviStation/NotificationService/Sources/NotificationService.swift b/Apps/RuuviStation/NotificationService/Sources/NotificationService.swift index aac58fb0c..e112c4315 100644 --- a/Apps/RuuviStation/NotificationService/Sources/NotificationService.swift +++ b/Apps/RuuviStation/NotificationService/Sources/NotificationService.swift @@ -127,7 +127,7 @@ extension NotificationService { case .signal: return RuuviLocalization.alertNotificationRssiLowThreshold(threshold, locale) case .movement: - return RuuviLocalization.LocalNotificationsManager.DidMove.title // TODO: @rinat localize + return RuuviLocalization.LocalNotificationsManager.DidMove.title(locale) case .offline: return "" // TODO: @rinat obtain spec } @@ -142,7 +142,7 @@ extension NotificationService { case .signal: return RuuviLocalization.alertNotificationRssiHighThreshold(threshold, locale) case .movement: - return RuuviLocalization.LocalNotificationsManager.DidMove.title // TODO: @rinat localize + return RuuviLocalization.LocalNotificationsManager.DidMove.title(locale) case .offline: return "" // TODO: @rinat obtain spec } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift index 28646ec8d..b53c01d7b 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift @@ -798,7 +798,7 @@ extension TagChartsViewController: TagChartsViewInput { syncStatusLabel.text = RuuviLocalization.TagCharts.Status.serving case let .reading(points): let format = RuuviLocalization.readingHistoryX - syncStatusLabel.text = format(Float(points), Locale.current) + syncStatusLabel.text = format(Float(points)) case .disconnecting: syncStatusLabel.text = RuuviLocalization.TagCharts.Status.disconnecting case .success: diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift index f891261fa..a09096e17 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift @@ -195,11 +195,11 @@ extension OffsetCorrectionAppleViewController: OffsetCorrectionViewInput { case .pressure: let format = RuuviLocalization.OffsetCorrection.Dialog.Calibration.enterPressure let unit = viewModel.pressureUnit.value ?? .hectopascals - message = format(unit.symbol, Locale.current) + message = format(unit.symbol) default: let format = RuuviLocalization.OffsetCorrection.Dialog.Calibration.enterTemperature let unit = viewModel.temperatureUnit.value ?? .celsius - message = format(unit.symbol, Locale.current) + message = format(unit.symbol) } let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift index 3041a7c3d..ba4ae9467 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift @@ -178,8 +178,7 @@ class TagSettingsViewController: UIViewController { private lazy var temperatureAlertSection: TagSettingsSection? = { let sectionTitle = temperatureAlertFormat( - viewModel?.temperatureUnit.value?.symbol ?? RuuviLocalization.na, - Locale.current + viewModel?.temperatureUnit.value?.symbol ?? RuuviLocalization.na ) let section = TagSettingsSection( identifier: .alertTemperature, @@ -204,7 +203,7 @@ class TagSettingsViewController: UIViewController { private lazy var humidityAlertSection: TagSettingsSection? = { let symbol = HumidityUnit.percent.symbol - let sectionTitle = airHumidityAlertFormat(symbol, Locale.current) + let sectionTitle = airHumidityAlertFormat(symbol) let section = TagSettingsSection( identifier: .alertHumidity, title: sectionTitle, @@ -228,7 +227,7 @@ class TagSettingsViewController: UIViewController { private lazy var pressureAlertSection: TagSettingsSection? = { let sectionTitle = pressureAlertFormat( - viewModel?.pressureUnit.value?.symbol ?? RuuviLocalization.na, Locale.current + viewModel?.pressureUnit.value?.symbol ?? RuuviLocalization.na ) let section = TagSettingsSection( identifier: .alertPressure, @@ -942,7 +941,7 @@ extension TagSettingsViewController { tableView.bind(viewModel.temperatureUnit) { [weak self] _, value in guard let sSelf = self else { return } sSelf.temperatureAlertSection?.title = sSelf.temperatureAlertFormat( - value?.symbol ?? RuuviLocalization.na, Locale.current + value?.symbol ?? RuuviLocalization.na ) } @@ -1000,7 +999,7 @@ extension TagSettingsViewController { header, unit in guard let sSelf = self else { return } let sectionTitle = sSelf.temperatureAlertFormat( - unit?.symbol ?? RuuviLocalization.na, Locale.current + unit?.symbol ?? RuuviLocalization.na ) header.setTitle(with: sectionTitle) } @@ -1120,7 +1119,7 @@ extension TagSettingsViewController { tableView.bind(viewModel.pressureUnit) { [weak self] _, value in guard let sSelf = self else { return } sSelf.pressureAlertSection?.title = sSelf.pressureAlertFormat( - value?.symbol ?? RuuviLocalization.na, Locale.current + value?.symbol ?? RuuviLocalization.na ) } @@ -1180,7 +1179,7 @@ extension TagSettingsViewController { [weak self] header, unit in guard let sSelf = self else { return } let sectionTitle = sSelf.pressureAlertFormat( - unit?.symbol ?? RuuviLocalization.na, Locale.current + unit?.symbol ?? RuuviLocalization.na ) header.setTitle(with: sectionTitle) } @@ -1877,7 +1876,7 @@ extension TagSettingsViewController { guard isViewLoaded else { return nil } let format = RuuviLocalization.TagSettings.Alerts.Temperature.description if let min, let max { - return attributedString(from: format(Float(min), Float(max), Locale.current)) + return attributedString(from: format(Float(min), Float(max))) } if let tu = viewModel?.temperatureUnit.value?.unitTemperature, @@ -1894,8 +1893,7 @@ extension TagSettingsViewController { u.value.round( to: 2 ) - ), - Locale.current + ) ) ) } else { @@ -1947,14 +1945,13 @@ extension TagSettingsViewController { guard isViewLoaded else { return nil } let format = RuuviLocalization.TagSettings.Alerts.Temperature.description if let min, let max { - return attributedString(from: format(Float(min), Float(max), Locale.current)) + return attributedString(from: format(Float(min), Float(max))) } if let l = viewModel?.relativeHumidityLowerBound.value, let u = viewModel?.relativeHumidityUpperBound.value { let message = format( Float(l.round(to: 2)), - Float(u.round(to: 2)), - Locale.current + Float(u.round(to: 2)) ) return attributedString(from: message) } else { @@ -2000,7 +1997,7 @@ extension TagSettingsViewController { if let minValue, let maxValue { return attributedString( - from: format(Float(minValue), Float(maxValue), Locale.current) + from: format(Float(minValue), Float(maxValue)) ) } @@ -2017,8 +2014,7 @@ extension TagSettingsViewController { ) let message = format( Float(l.round(to: 2)), - Float(u.round(to: 2)), - Locale.current + Float(u.round(to: 2)) ) return attributedString(from: message) } else { @@ -2080,7 +2076,7 @@ extension TagSettingsViewController { if let min, let max { return attributedString( - from: format(Float(min), Float(max), Locale.current) + from: format(Float(min), Float(max)) ) } @@ -2088,8 +2084,7 @@ extension TagSettingsViewController { let upper = viewModel?.signalUpperBound.value { let message = format( Float(lower), - Float(upper), - Locale.current + Float(upper) ) return attributedString(from: message) } else { @@ -3758,7 +3753,7 @@ extension TagSettingsViewController { alertTextField.delegate = self let format = RuuviLocalization.TagSettings.AlertSettings.Dialog.min alertTextField.placeholder = format( - Float(minimumBound), Locale.current + Float(minimumBound) ) alertTextField.keyboardType = .decimalPad alertMinRangeTextField = alertTextField @@ -3775,7 +3770,7 @@ extension TagSettingsViewController { alertTextField.delegate = self let format = RuuviLocalization.TagSettings.AlertSettings.Dialog.max alertTextField.placeholder = format( - Float(maximumBound), Locale.current + Float(maximumBound) ) alertTextField.keyboardType = .decimalPad alertMaxRangeTextField = alertTextField diff --git a/Apps/RuuviStation/Sources/Extensions/HumidityUnit+Localization.swift b/Apps/RuuviStation/Sources/Extensions/HumidityUnit+Localization.swift index 5e0c978fa..ce3798906 100644 --- a/Apps/RuuviStation/Sources/Extensions/HumidityUnit+Localization.swift +++ b/Apps/RuuviStation/Sources/Extensions/HumidityUnit+Localization.swift @@ -7,7 +7,7 @@ extension HumidityUnit: SelectionItemProtocol { switch self { case .percent: { _ in RuuviLocalization.HumidityUnit.Percent.title } case .gm3: { _ in RuuviLocalization.HumidityUnit.Gm3.title } - case .dew: { param in RuuviLocalization.HumidityUnit.Dew.title(param, Locale.current) } + case .dew: { param in RuuviLocalization.HumidityUnit.Dew.title(param) } } } diff --git a/Apps/RuuviStation/Sources/Extensions/Structs/ExportHeadersProvider.swift b/Apps/RuuviStation/Sources/Extensions/Structs/ExportHeadersProvider.swift index 92240a85e..0af7acf2b 100644 --- a/Apps/RuuviStation/Sources/Extensions/Structs/ExportHeadersProvider.swift +++ b/Apps/RuuviStation/Sources/Extensions/Structs/ExportHeadersProvider.swift @@ -9,11 +9,11 @@ struct ExportHeadersProvider: RuuviServiceExportHeaders { let humidityFormat = RuuviLocalization.ExportService.humidity return [ RuuviLocalization.ExportService.date, - tempFormat(units.temperatureUnit.symbol, Locale.current), + tempFormat(units.temperatureUnit.symbol), units.humidityUnit == .dew - ? humidityFormat(units.temperatureUnit.symbol, Locale.current) - : humidityFormat(units.humidityUnit.symbol, Locale.current), - pressureFormat(units.pressureUnit.symbol, Locale.current), + ? humidityFormat(units.temperatureUnit.symbol) + : humidityFormat(units.humidityUnit.symbol), + pressureFormat(units.pressureUnit.symbol), "RSSI" + " (\(RuuviLocalization.dBm))", RuuviLocalization.ExportService.accelerationX + " (\(RuuviLocalization.g))", RuuviLocalization.ExportService.accelerationY + " (\(RuuviLocalization.g))", diff --git a/Common/RuuviLocalization/Templates/strings-swift5.stencil b/Common/RuuviLocalization/Templates/strings-swift5.stencil index 0a54436cd..e85db8278 100644 --- a/Common/RuuviLocalization/Templates/strings-swift5.stencil +++ b/Common/RuuviLocalization/Templates/strings-swift5.stencil @@ -40,13 +40,19 @@ import Foundation {% endif %} {% set translation string.translation|replace:'"','\"'|replace:' ','\t' %} {% if string.types %} - {{accessModifier}} static func {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}({% call parametersBlock string.types %}, _ locale: Locale = Locale.current) -> String { + {{accessModifier}} static func {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}({% call parametersBlock string.types %}) -> String { + {{enumName}}.tr("{{table}}", "{{string.key}}", {%+ call argumentsBlock string.types %}, fallback: "{{translation}}") + } + {{accessModifier}} static func {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}({% call parametersBlock string.types %}, _ locale: Locale? = nil) -> String { {{enumName}}.tr("{{table}}", "{{string.key}}", {%+ call argumentsBlock string.types %}, fallback: "{{translation}}", locale: locale) } {% elif param.lookupFunction %} {{accessModifier}} static var {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}: String { return {{enumName}}.tr("{{table}}", "{{string.key}}", fallback: "{{translation}}") } {% else %} {{accessModifier}} static let {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{enumName}}.tr("{{table}}", "{{string.key}}", fallback: "{{translation}}") + {{accessModifier}} static func {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}(_ locale: Locale? = nil) -> String { + {{enumName}}.tr("{{table}}", "{{string.key}}", fallback: "{{translation}}", locale: locale) + } {% endif %} {% endfor %} {% for child in item.children %} @@ -75,13 +81,13 @@ import Foundation // MARK: - Implementation Details extension {{enumName}} { - private static func tr(_ table: String, _ key: String, _ args: CVarArg..., fallback value: String, locale: Locale = Locale.current) -> String { + private static func tr(_ table: String, _ key: String, _ args: CVarArg..., fallback value: String, locale: Locale? = nil) -> String { {% if param.lookupFunction %} let format = {{ param.lookupFunction }}(key, table, value) {% else %} let format: String - if let bundle = BundleToken.bundle.path( - forResource: locale.identifier, + if let locale, let languageCode = locale.languageCode, let bundle = BundleToken.bundle.path( + forResource: languageCode, ofType: "lproj" ), let languageBundle = Bundle(path: bundle) { format = languageBundle.localizedString(forKey: key, value: value, table: table) @@ -90,7 +96,7 @@ extension {{enumName}} { } {% endif %} - return String(format: format, locale: locale, arguments: args) + return String(format: format, locale: locale ?? Locale.current, arguments: args) } } {% if not param.bundle and not param.lookupFunction %} diff --git a/Common/RuuviLocalization/target.yml b/Common/RuuviLocalization/target.yml index 452f2cc84..d646b051b 100644 --- a/Common/RuuviLocalization/target.yml +++ b/Common/RuuviLocalization/target.yml @@ -19,6 +19,8 @@ targets: inputFiles: - $(SRCROOT)/station.localization/station.localization.json - $(SRCROOT)/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets + - $(SRCROOT)/Common/RuuviLocalization/Templates/strings-swift5.stencil + - $(SRCROOT)/Common/RuuviLocalization/Templates/xcassets-swift5.stencil outputFiles: - $(SRCROOT)/Common/RuuviLocalization/Sources/Resources/en.lproj/Localizable.strings - $(SRCROOT)/Common/RuuviLocalization/Sources/Resources/sv.lproj/Localizable.strings From 1a96ad877c291f5870cda34980f8e9f43c2709cf Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Wed, 20 Dec 2023 21:23:35 +0200 Subject: [PATCH 63/84] TestFlight workflow (#1808) Implements workflow to upload build to TestFlight --- .github/workflows/testflight.yml | 49 +++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/.github/workflows/testflight.yml b/.github/workflows/testflight.yml index a63368311..4e496b8e2 100644 --- a/.github/workflows/testflight.yml +++ b/.github/workflows/testflight.yml @@ -4,14 +4,18 @@ on: pull_request: types: - closed - branches: [ testflight ] + branches: [testflight] jobs: build: if: github.event.pull_request.merged == true - runs-on: macos-latest + runs-on: macos-13 steps: + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: '15' + - name: Checkout repository uses: actions/checkout@v4 @@ -24,18 +28,7 @@ jobs: run: rm -rf ${{ github.workspace }}/station.localization - name: Clone localisation submodule - run: git clone -b dev https://github.com/ruuvi/station.localization.git ${{ github.workspace }}/station.localization - - - name: Cocoapods Cache - uses: actions/cache@v2 - with: - path: Pods - key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} - restore-keys: | - ${{ runner.os }}-pods- - - - name: CocoaPods Install - run: pod install + run: git clone -b master https://github.com/ruuvi/station.localization.git ${{ github.workspace }}/station.localization - name: Install the Apple certificate and provisioning profiles env: @@ -66,10 +59,34 @@ jobs: echo -n "${{ secrets.INTENTS_APP_APPSTORE_PROVISION_PROFILE_BASE64 }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/match__AppStore_com.ruuvi.station.intents.mobileprovision echo -n "${{ secrets.PNSERVICE_APP_APPSTORE_PROVISION_PROFILE_BASE64 }}" | base64 --decode > ~/Library/MobileDevice/Provisioning\ Profiles/match_AppStore_com.ruuvi.station.pnservice.mobileprovision + - name: Increment build number + run: | + make set_build_number + + - name: Tools cache + uses: actions/cache@v2 + with: + path: .tools/ + key: ${{ runner.os }}-tools-${{ hashFiles('/.tools/') }} + restore-keys: | + ${{ runner.os }}-tools- + + - name: Make xcodeproj + run: | + make xcodeproj + + - name: SPM Cache + uses: actions/cache@v2 + with: + path: ~/Library/Developer/Xcode/DerivedData/Ruuvi*/SourcePackages/ + key: ${{ runner.os }}-Ruuvi-${{ hashFiles('Ruuvi.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved') }} + restore-keys: | + ${{ runner.os }}-Ruuvi- + - name: Build app run: | - xcodebuild -workspace station.xcworkspace -scheme station -configuration Release -archivePath ./Build/Station.xcarchive archive -allowProvisioningUpdates - + xcodebuild -project Ruuvi.xcodeproj -scheme station -configuration Release -archivePath ./Build/Station.xcarchive archive -allowProvisioningUpdates -quiet + - name: Export IPA env: EXPORT_PLIST: ${{ secrets.APPSTORE_EXPORT_OPTIONS }} From c069e776e2604423e590e6ea476624c47375e2ae Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Wed, 20 Dec 2023 21:27:53 +0200 Subject: [PATCH 64/84] Bump version to 2.6.0 (#1809) Bimps version to 2.6.0 --- project.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.yml b/project.yml index 5faff1328..1a0c2b35f 100644 --- a/project.yml +++ b/project.yml @@ -1,5 +1,5 @@ BUILD_NUMBER: &BUILD_NUMBER 1 -APP_VERSION: &APP_VERSION 2.5.2 +APP_VERSION: &APP_VERSION 2.6.0 PROJECT_NAME: &PROJECT_NAME Ruuvi DEVELOPMENT_TEAM: &DEVELOPMENT_TEAM 4MUYJ4YYH4 BUNDLE_ID_PREFIX: &BUNDLE_ID_PREFIX com.ruuvi From cb9bd00b30fa59106fa524e447a2f6c1b758dfe3 Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Wed, 20 Dec 2023 20:46:52 +0100 Subject: [PATCH 65/84] fix: Fix sensor order not updated on sensor cards page #1632 (#1812) --- .../Cards/Presenter/CardsPresenter.swift | 64 +++++++++++++++---- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift index c334ae532..d05ce6a02 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Presenter/CardsPresenter.swift @@ -49,11 +49,14 @@ class CardsPresenter { /// Index for visible card private var visibleViewModelIndex: Int = 0 { didSet { + currentVisibleViewModel = viewModels[visibleViewModelIndex] guard let view, shouldTriggerScroll else { return } view.scrollIndex = visibleViewModelIndex } } + private var currentVisibleViewModel: CardsViewModel? + /// Whether bluetooth permission is already granted. private var isBluetoothPermissionGranted: Bool { CBCentralManager.authorization == .allowedAlways @@ -88,6 +91,7 @@ class CardsPresenter { private var didConnectToken: NSObjectProtocol? private var didDisconnectToken: NSObjectProtocol? private var cloudModeToken: NSObjectProtocol? + private var sensorOrderChangeToken: NSObjectProtocol? func dismiss(completion: (() -> Void)?) { shutdownModule() @@ -646,6 +650,33 @@ extension CardsPresenter { ) } + private func startObservingSensorOrderChanges() { + sensorOrderChangeToken?.invalidate() + sensorOrderChangeToken = nil + sensorOrderChangeToken = NotificationCenter + .default + .addObserver( + forName: .DashboardSensorOrderDidChange, + object: nil, + queue: .main, + using: { [weak self] _ in + guard let self = self else { return } + DispatchQueue.main.async { + self.viewModels = self.reorder(self.viewModels) + if let viewModel = self.currentVisibleViewModel { + if let index = self.viewModels.firstIndex(where: { + ($0.luid.value != nil && $0.luid.value == viewModel.luid.value) || + ($0.mac.value != nil && $0.mac.value == viewModel.mac.value) + }) { + self.visibleViewModelIndex = index + } + } + self.view?.scroll(to: self.visibleViewModelIndex) + } + } + ) + } + /// The method handles all the operations when cloud mode toggle is turned on/off private func handleCloudModeState() { // Sync with cloud if cloud mode is turned on @@ -705,25 +736,30 @@ extension CardsPresenter { } private func reorder(_ viewModels: [CardsViewModel]) -> [CardsViewModel] { + let sortedSensors: [String] = settings.dashboardSensorOrder let sortedAndUniqueArray = viewModels.reduce( into: [CardsViewModel]() ) { result, element in if !result.contains(element) { - // Insert the element into the result array while maintaining the sorted order - if let index = result.firstIndex( - where: { - $0.name.value?.lowercased() ?? "" > - element.name.value?.lowercased() ?? "" - } - ) { - result.insert(element, at: index) - } else { - // If no such index is found, append the element at the end - result.append(element) - } + result.append(element) + } + } + + if !sortedSensors.isEmpty { + return sortedAndUniqueArray.sorted { (first, second) -> Bool in + guard let firstMacId = first.mac.value?.value, + let secondMacId = second.mac.value?.value else { return false } + let firstIndex = sortedSensors.firstIndex(of: firstMacId) ?? Int.max + let secondIndex = sortedSensors.firstIndex(of: secondMacId) ?? Int.max + return firstIndex < secondIndex + } + } else { + return sortedAndUniqueArray.sorted { (first, second) -> Bool in + let firstName = first.name.value?.lowercased() ?? "" + let secondName = second.name.value?.lowercased() ?? "" + return firstName < secondName } } - return sortedAndUniqueArray } private func openTagSettingsScreens(viewModel: CardsViewModel) { @@ -796,6 +832,7 @@ extension CardsPresenter { didDisconnectToken?.invalidate() cloudModeToken?.invalidate() mutedTillTimer?.invalidate() + sensorOrderChangeToken?.invalidate() router.dismiss() NotificationCenter.default.removeObserver( self, @@ -811,6 +848,7 @@ extension CardsPresenter: CardsViewOutput { func viewDidLoad() { startObservingAppState() startMutedTillTimer() + startObservingSensorOrderChanges() } func viewWillAppear() { From cd3f07e9e03b8d40d329f188bc162afea5723440 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Wed, 20 Dec 2023 22:19:36 +0200 Subject: [PATCH 66/84] Respect app extension only API requirement (#1813) In order to distribute to TestFlight --- Apps/RuuviStation/Intents/target.yml | 11 ++--------- Apps/RuuviStation/NotificationService/target.yml | 11 ++--------- Apps/RuuviStation/Widgets/target.yml | 11 ++--------- Common/RuuviLocalization/target.yml | 1 + Packages/RuuviCloud/target.yml | 3 +++ Packages/RuuviContext/target.yml | 1 + Packages/RuuviLocal/target.yml | 4 ++++ Packages/RuuviOntology/target.yml | 1 + Packages/RuuviPersistence/target.yml | 1 + Packages/RuuviPool/target.yml | 3 +++ Packages/RuuviUser/target.yml | 3 +++ 11 files changed, 23 insertions(+), 27 deletions(-) diff --git a/Apps/RuuviStation/Intents/target.yml b/Apps/RuuviStation/Intents/target.yml index 513f57399..c422ed3e1 100644 --- a/Apps/RuuviStation/Intents/target.yml +++ b/Apps/RuuviStation/Intents/target.yml @@ -21,6 +21,7 @@ targets: settings: base: CODE_SIGN_ENTITLEMENTS: Apps/RuuviStation/Intents/Sources/Intents.entitlements + APPLICATION_EXTENSION_API_ONLY: true configs: Alpha: CODE_SIGN_IDENTITY: "iPhone Distribution" @@ -51,18 +52,10 @@ targets: - package: Humidity - package: KeychainAccess - target: RuuviUser - embed: true - target: RuuviCloud - embed: true - target: RuuviOntology - embed: true - target: RuuviPool - embed: true - target: RuuviLocal - embed: true - target: RuuviPersistence - embed: true - target: RuuviContext - embed: true - - target: RuuviLocalization - embed: true \ No newline at end of file + - target: RuuviLocalization \ No newline at end of file diff --git a/Apps/RuuviStation/NotificationService/target.yml b/Apps/RuuviStation/NotificationService/target.yml index 6bdf91c5b..b6328747f 100644 --- a/Apps/RuuviStation/NotificationService/target.yml +++ b/Apps/RuuviStation/NotificationService/target.yml @@ -17,6 +17,7 @@ targets: settings: base: CODE_SIGN_ENTITLEMENTS: Apps/RuuviStation/NotificationService/Sources/NotificationService.entitlements + APPLICATION_EXTENSION_API_ONLY: true configs: Alpha: CODE_SIGN_IDENTITY: "iPhone Distribution" @@ -48,18 +49,10 @@ targets: - package: Humidity - package: KeychainAccess - target: RuuviUser - embed: true - target: RuuviCloud - embed: true - target: RuuviOntology - embed: true - target: RuuviPool - embed: true - target: RuuviLocal - embed: true - target: RuuviPersistence - embed: true - target: RuuviContext - embed: true - - target: RuuviLocalization - embed: true \ No newline at end of file + - target: RuuviLocalization \ No newline at end of file diff --git a/Apps/RuuviStation/Widgets/target.yml b/Apps/RuuviStation/Widgets/target.yml index c8684c466..7f1ad524c 100644 --- a/Apps/RuuviStation/Widgets/target.yml +++ b/Apps/RuuviStation/Widgets/target.yml @@ -17,6 +17,7 @@ targets: settings: base: CODE_SIGN_ENTITLEMENTS: Apps/RuuviStation/Widgets/Sources/Widgets.entitlements + APPLICATION_EXTENSION_API_ONLY: true configs: Alpha: CODE_SIGN_IDENTITY: "iPhone Distribution" @@ -44,18 +45,10 @@ targets: - package: Humidity - package: KeychainAccess - target: RuuviUser - embed: true - target: RuuviCloud - embed: true - target: RuuviOntology - embed: true - target: RuuviPool - embed: true - target: RuuviLocal - embed: true - target: RuuviPersistence - embed: true - target: RuuviContext - embed: true - - target: RuuviLocalization - embed: true \ No newline at end of file + - target: RuuviLocalization \ No newline at end of file diff --git a/Common/RuuviLocalization/target.yml b/Common/RuuviLocalization/target.yml index d646b051b..e7de8eaa4 100644 --- a/Common/RuuviLocalization/target.yml +++ b/Common/RuuviLocalization/target.yml @@ -4,6 +4,7 @@ targets: settings: base: MERGEABLE_LIBRARY: false + APPLICATION_EXTENSION_API_ONLY: true templates: - CommonFramework sources: diff --git a/Packages/RuuviCloud/target.yml b/Packages/RuuviCloud/target.yml index 0e5614b89..0e8268340 100644 --- a/Packages/RuuviCloud/target.yml +++ b/Packages/RuuviCloud/target.yml @@ -1,6 +1,9 @@ --- targets: RuuviCloud: + settings: + base: + APPLICATION_EXTENSION_API_ONLY: true templates: - Framework sources: diff --git a/Packages/RuuviContext/target.yml b/Packages/RuuviContext/target.yml index 146bb2151..889768da3 100644 --- a/Packages/RuuviContext/target.yml +++ b/Packages/RuuviContext/target.yml @@ -5,6 +5,7 @@ targets: settings: base: MERGEABLE_LIBRARY: false + APPLICATION_EXTENSION_API_ONLY: true templates: - Framework sources: diff --git a/Packages/RuuviLocal/target.yml b/Packages/RuuviLocal/target.yml index dec929954..6302910c4 100644 --- a/Packages/RuuviLocal/target.yml +++ b/Packages/RuuviLocal/target.yml @@ -1,6 +1,10 @@ --- targets: RuuviLocal: + settings: + base: + MERGEABLE_LIBRARY: false + APPLICATION_EXTENSION_API_ONLY: true templates: - Framework sources: diff --git a/Packages/RuuviOntology/target.yml b/Packages/RuuviOntology/target.yml index e4c8a4e34..cda2dbc0c 100644 --- a/Packages/RuuviOntology/target.yml +++ b/Packages/RuuviOntology/target.yml @@ -5,6 +5,7 @@ targets: settings: base: MERGEABLE_LIBRARY: false + APPLICATION_EXTENSION_API_ONLY: true templates: - Framework sources: diff --git a/Packages/RuuviPersistence/target.yml b/Packages/RuuviPersistence/target.yml index 392446f67..130827b3a 100644 --- a/Packages/RuuviPersistence/target.yml +++ b/Packages/RuuviPersistence/target.yml @@ -5,6 +5,7 @@ targets: settings: base: MERGEABLE_LIBRARY: false + APPLICATION_EXTENSION_API_ONLY: true templates: - Framework sources: diff --git a/Packages/RuuviPool/target.yml b/Packages/RuuviPool/target.yml index e1275fbff..74dfdd998 100644 --- a/Packages/RuuviPool/target.yml +++ b/Packages/RuuviPool/target.yml @@ -1,6 +1,9 @@ --- targets: RuuviPool: + settings: + base: + APPLICATION_EXTENSION_API_ONLY: true templates: - Framework sources: diff --git a/Packages/RuuviUser/target.yml b/Packages/RuuviUser/target.yml index bb1df5782..10c5daf0e 100644 --- a/Packages/RuuviUser/target.yml +++ b/Packages/RuuviUser/target.yml @@ -1,6 +1,9 @@ --- targets: RuuviUser: + settings: + base: + APPLICATION_EXTENSION_API_ONLY: true templates: - Framework sources: From 567c2458fbc4b3e3074e5c965d8db0ffb8808bcd Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Thu, 21 Dec 2023 13:01:25 +0100 Subject: [PATCH 67/84] fix: Fix UI glitch after toast is dismissed #1600 (#1816) (#1817) Increase min screen on time for toast to 1.5 seconds from 1 second. --- .../Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift index ae77b5891..01aa45655 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift @@ -1,7 +1,7 @@ import UIKit public final class ActivityPresenterRuuviLogo: ActivityPresenter { - let minAnimationTime: CFTimeInterval = 1.0 + let minAnimationTime: CFTimeInterval = 1.5 var startTime: CFTimeInterval? let window = UIWindow(frame: UIScreen.main.bounds) let activityPresenterViewProvider: ActivityPresenterViewProvider @@ -45,10 +45,10 @@ public extension ActivityPresenterRuuviLogo { let additionalWaitTime = immediately ? 0 : executionTime < minAnimationTime ? (minAnimationTime - executionTime) : 0 DispatchQueue.main.asyncAfter(deadline: .now() + additionalWaitTime) { [weak self] in - self?.activityPresenterViewProvider.updateState(.dismiss) + self?.window.isHidden = true self?.appWindow?.makeKeyAndVisible() self?.appWindow = nil - self?.window.isHidden = true + self?.activityPresenterViewProvider.updateState(.dismiss) } } } From 58f145e87f0934a9cd001ec7705fac7da04e2260 Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Wed, 27 Dec 2023 17:40:30 +0100 Subject: [PATCH 68/84] Enhancements and bug fixes (#1823) * fix: Fix UI glitch after toast is dismissed #1600 (#1816) Increase min screen on time for toast to 1.5 seconds from 1 second. * Add battery level check on FW upgrade from Discover (#1819) Implements battery charge check on Firmware upgrade process on Discover * task: Disable RSSI alert editing for local sensors #1751 (#1820) * fix: View menu not updating after sync from cloud #1632 (#1822) * fix: Improve activity presenter transition #1600 (#1821) --------- Co-authored-by: Rinat Enikeev --- .../Home/Presenter/DashboardPresenter.swift | 1 + .../Presenter/TagSettingsPresenter.swift | 37 ++--- .../View/UI/TagSettingsAlertConfigCell.swift | 2 + .../View/UI/TagSettingsViewController.swift | 17 +- .../ActivityPresenterRuuviLogo.swift | 150 ++++++++++++++---- .../RuuviPresenters/ActivityPresenter.swift | 13 +- .../Error/Alert/ErrorPresenterAlert.swift | 2 +- .../Alert/PermissionPresenterAlert.swift | 2 +- .../Util/RuuviPresenterHelper.swift | 17 ++ .../Util/UIApplication+ViewController.swift | 20 --- .../RuuviFirmware/FirmwareInteractor.swift | 35 ++++ .../RuuviFirmware/FirmwarePresenter.swift | 3 + .../RuuviFirmware/RuuviFirmwareBuilder.swift | 3 + .../RuuviFirmware/SwiftUI/FirmwareView.swift | 11 ++ .../SwiftUI/FirmwareViewModel.swift | 8 + .../RuuviCloudRequestStateObserver.swift | 48 ++++++ 16 files changed, 290 insertions(+), 79 deletions(-) create mode 100644 Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviPresenterHelper.swift delete mode 100644 Common/RuuviPresenters/Sources/RuuviPresenters/Util/UIApplication+ViewController.swift create mode 100644 Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloudRequestStateObserver.swift diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift index 058794346..5f0adbf70 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift @@ -1541,6 +1541,7 @@ extension DashboardPresenter { using: { [weak self] _ in guard let self = self else { return } DispatchQueue.main.async { + self.view?.dashboardSortingType = self.dashboardSortingType() self.viewModels = self.reorder(self.viewModels) } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift index 8030f7cc4..0b156c2f5 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Presenter/TagSettingsPresenter.swift @@ -76,7 +76,6 @@ class TagSettingsPresenter: NSObject, TagSettingsModuleInput { private var appDidBecomeActiveToken: NSObjectProtocol? private var alertDidChangeToken: NSObjectProtocol? private var backgroundToken: NSObjectProtocol? - private var cloudRequestStateToken: NSObjectProtocol? private var mutedTillTimer: Timer? private var exportFileUrl: URL? private var previousAdvertisementSequence: Int? @@ -108,8 +107,10 @@ class TagSettingsPresenter: NSObject, TagSettingsModuleInput { appDidBecomeActiveToken?.invalidate() alertDidChangeToken?.invalidate() backgroundToken?.invalidate() - cloudRequestStateToken?.invalidate() timer?.invalidate() + RuuviCloudRequestStateObserverManager + .shared + .stopObserving(for: ruuviTag.macId?.value) NotificationCenter.default.removeObserver(self) } @@ -1143,27 +1144,17 @@ extension TagSettingsPresenter { } private func startObservingCloudRequestState() { - cloudRequestStateToken?.invalidate() - cloudRequestStateToken = nil - - cloudRequestStateToken = NotificationCenter - .default - .addObserver( - forName: .RuuviCloudRequestStateDidChange, - object: nil, - queue: .main, - using: { [weak self] notification in - guard let self, - let userInfo = notification.userInfo, - let macId = userInfo[RuuviCloudRequestStateKey.macId] as? String, - macId == self.ruuviTag.macId?.value, - let state = userInfo[RuuviCloudRequestStateKey.state] as? RuuviCloudRequestStateType - else { - return - } - self.presentActivityIndicator(with: state) - } - ) + guard let macId = ruuviTag.macId?.value else { return } + // Stop if already observing + RuuviCloudRequestStateObserverManager + .shared + .stopObserving(for: macId) + + RuuviCloudRequestStateObserverManager + .shared + .startObserving(for: macId) { [weak self] state in + self?.presentActivityIndicator(with: state) + } } private func reloadMutedTill() { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift index 7cbefda37..5b0e77c81 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsAlertConfigCell.swift @@ -395,6 +395,8 @@ extension TagSettingsAlertConfigCell { alertLimitSliderView.disable(disable) case .alertRSSI: noticeView.disable(disable) + alertLimitDescriptionView.disable(disable) + alertLimitSliderView.disable(disable) case .alertMovement, .alertConnection: additionalTextView.disable(disable) default: break diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift index ba4ae9467..e16381b60 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift @@ -1243,8 +1243,17 @@ extension TagSettingsViewController { } rssiAlertCell.bind(viewModel.latestMeasurement) { cell, measurement in + let isClaimed = GlobalHelpers.getBool(from: viewModel.isClaimedTag.value) cell.disableEditing( - disable: measurement == nil, + disable: measurement == nil || !isClaimed, + identifier: .alertRSSI + ) + } + + rssiAlertCell.bind(viewModel.isClaimedTag) { [weak self] cell, isClaimed in + let hasMeasurement = GlobalHelpers.getBool(from: self?.hasMeasurement()) + cell.disableEditing( + disable: !hasMeasurement || !GlobalHelpers.getBool(from: isClaimed), identifier: .alertRSSI ) } @@ -1603,7 +1612,8 @@ extension TagSettingsViewController { private func rssiAlertItem() -> TagSettingsItem { let (minRange, maxRange) = rssiMinMaxForSliders() - let disableRssi = !hasMeasurement() + let disableRssi = !hasMeasurement() || + !GlobalHelpers.getBool(from: viewModel?.isClaimedTag.value) let settingItem = TagSettingsItem( createdCell: { [weak self] in self?.rssiAlertCell?.showNoticeView() @@ -3485,7 +3495,8 @@ extension TagSettingsViewController: TagSettingsExpandableSectionHeaderDelegate selectedMaxValue: rssiUpperBound() ) rssiAlertCell.disableEditing( - disable: GlobalHelpers.getBool(from: !hasMeasurement()), + disable: GlobalHelpers.getBool(from: !hasMeasurement()) || + !GlobalHelpers.getBool(from: viewModel?.isClaimedTag.value), identifier: currentSection.identifier ) } diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift index 01aa45655..d8aec8a35 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/ActivityPresenterRuuviLogo.swift @@ -1,54 +1,146 @@ import UIKit -public final class ActivityPresenterRuuviLogo: ActivityPresenter { - let minAnimationTime: CFTimeInterval = 1.5 - var startTime: CFTimeInterval? - let window = UIWindow(frame: UIScreen.main.bounds) - let activityPresenterViewProvider: ActivityPresenterViewProvider - let activityPresenterViewController: UIViewController - let stateHolder = ActivityPresenterStateHolder() +public final class ActivityPresenterRuuviLogo { + // Minimum duration to keep the activity indicator on the screen + private let minAnimationTime: CFTimeInterval = 1.5 + // Animation duration for presenting and dismissing the activity indicator. + private let animationDuration: CGFloat = 0.5 + // Vertical(top/bottom) padding for activity indicator depending on position. + private let verticalPadding: CGFloat = 8 - weak var appWindow: UIWindow? + private let activityPresenterViewProvider: ActivityPresenterViewProvider + private let activityPresenterViewController: UIViewController + private let stateHolder = ActivityPresenterStateHolder() + + private var activityPresenterPosition: ActivityPresenterPosition = .bottom + private var startTime: CFTimeInterval? public init() { activityPresenterViewProvider = ActivityPresenterViewProvider(stateHolder: stateHolder) activityPresenterViewController = activityPresenterViewProvider.makeViewController() activityPresenterViewController.view.backgroundColor = .clear - window.windowLevel = .normal - activityPresenterViewController.view.translatesAutoresizingMaskIntoConstraints = false - window.rootViewController = activityPresenterViewController } } -public extension ActivityPresenterRuuviLogo { - func setPosition(_ position: ActivityPresenterPosition) { +extension ActivityPresenterRuuviLogo: ActivityPresenter { + public func show( + with state: ActivityPresenterState, + atPosition position: ActivityPresenterPosition + ) { + activityPresenterPosition = position activityPresenterViewProvider.updatePosition(position) - } - - func show(with state: ActivityPresenterState) { startTime = CFAbsoluteTimeGetCurrent() - appWindow = UIWindow.key - window.makeKeyAndVisible() - window.layoutIfNeeded() + + guard let topController = RuuviPresenterHelper.topViewController(), + let toastView = activityPresenterViewController.view else { + return + } + + topController.view.addSubview(toastView) + setupConstraints(for: toastView, in: topController) + animateActivityViewPresentation(toastView, atPosition: position) + activityPresenterViewProvider.updateState(state) } - func update(with state: ActivityPresenterState) { - // Reset start time with state update since we want to show - // latest state message before dismissing the presenter. + public func update(with state: ActivityPresenterState) { startTime = CFAbsoluteTimeGetCurrent() activityPresenterViewProvider.updateState(state) } - func dismiss(immediately: Bool) { + public func dismiss(immediately: Bool) { let executionTime = CFAbsoluteTimeGetCurrent() - (startTime ?? 0) - let additionalWaitTime = immediately ? 0 : - executionTime < minAnimationTime ? (minAnimationTime - executionTime) : 0 - DispatchQueue.main.asyncAfter(deadline: .now() + additionalWaitTime) { [weak self] in - self?.window.isHidden = true - self?.appWindow?.makeKeyAndVisible() - self?.appWindow = nil + let additionalWaitTime = immediately ? 0 : max(minAnimationTime - executionTime, 0) + + guard let toastView = activityPresenterViewController.view else { + return + } + + DispatchQueue.main.asyncAfter( + deadline: .now() + additionalWaitTime + ) { [weak self] in + self?.animateActivityViewDismissal(toastView) + } + } +} + +extension ActivityPresenterRuuviLogo { + private func setupConstraints( + for view: UIView, + in viewController: UIViewController + ) { + view.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + view.leadingAnchor.constraint( + equalTo: viewController.view.leadingAnchor + ), + view.trailingAnchor.constraint( + equalTo: viewController.view.trailingAnchor + ), + view.topAnchor.constraint( + equalTo: viewController.view.topAnchor + ), + view.bottomAnchor.constraint( + equalTo: viewController.view.bottomAnchor + ), + ]) + } + + private func animateActivityViewPresentation( + _ view: UIView, + atPosition position: ActivityPresenterPosition + ) { + UIView.animate( + withDuration: animationDuration, + delay: 0, + options: [.curveEaseOut] + ) { [weak self] in + guard let self = self else { return } + switch position { + case .top: + view.transform = CGAffineTransform( + translationX: 0, + y: self.safeAreaInsets().top + self.verticalPadding + ) + case .bottom: + view.transform = CGAffineTransform( + translationX: 0, + y: -(self.safeAreaInsets().bottom + self.verticalPadding) + ) + case .center: + view.transform = .identity + } + } + } + + private func animateActivityViewDismissal(_ view: UIView) { + UIView.animate( + withDuration: animationDuration, + delay: 0, + options: [.curveEaseIn] + ) { [weak self] in + guard let self = self else { return } + switch self.activityPresenterPosition { + case .top: + view.transform = CGAffineTransform( + translationX: 0, + y: -(view.frame.height + verticalPadding) + ) + case .bottom: + view.transform = CGAffineTransform( + translationX: 0, + y: view.frame.height + verticalPadding + ) + case .center: + break + } + } completion: { [weak self] _ in + view.removeFromSuperview() self?.activityPresenterViewProvider.updateState(.dismiss) } } + + private func safeAreaInsets() -> UIEdgeInsets { + RuuviPresenterHelper.topViewController()?.view.safeAreaInsets ?? .zero + } } diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/ActivityPresenter.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/ActivityPresenter.swift index 084b591bd..7b6537e57 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/ActivityPresenter.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/ActivityPresenter.swift @@ -1,13 +1,22 @@ import Foundation public protocol ActivityPresenter { - func setPosition(_ position: ActivityPresenterPosition) - func show(with state: ActivityPresenterState) + func show( + with state: ActivityPresenterState, + atPosition position: ActivityPresenterPosition + ) func update(with state: ActivityPresenterState) func dismiss(immediately: Bool) } public extension ActivityPresenter { + func show( + with state: ActivityPresenterState, + atPosition position: ActivityPresenterPosition = .bottom + ) { + show(with: state, atPosition: position) + } + func dismiss(immediately: Bool = false) { dismiss(immediately: immediately) } diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Error/Alert/ErrorPresenterAlert.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Error/Alert/ErrorPresenterAlert.swift index 61ef977af..ad4bc3f2f 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Error/Alert/ErrorPresenterAlert.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Error/Alert/ErrorPresenterAlert.swift @@ -29,7 +29,7 @@ public final class ErrorPresenterAlert: ErrorPresenter { let feedback = UINotificationFeedbackGenerator() feedback.notificationOccurred(.error) feedback.prepare() - UIApplication.shared.topViewController()?.present(alert, animated: true) + RuuviPresenterHelper.topViewController()?.present(alert, animated: true) } } } diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Permission/Alert/PermissionPresenterAlert.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Permission/Alert/PermissionPresenterAlert.swift index 15de129b0..acd00439c 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Permission/Alert/PermissionPresenterAlert.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Permission/Alert/PermissionPresenterAlert.swift @@ -25,7 +25,7 @@ public final class PermissionPresenterAlert: PermissionPresenter { } private func presentAlert(with message: String) { - guard let viewController = UIApplication.shared.topViewController() else { return } + guard let viewController = RuuviPresenterHelper.topViewController() else { return } let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert) let cancel = UIAlertAction(title: RuuviLocalization.cancel, style: .cancel, handler: nil) let actionTitle = RuuviLocalization.PermissionPresenter.settings diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviPresenterHelper.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviPresenterHelper.swift new file mode 100644 index 000000000..dae7db3fb --- /dev/null +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviPresenterHelper.swift @@ -0,0 +1,17 @@ +import UIKit + +struct RuuviPresenterHelper { + public static func topViewController() -> UIViewController? { + if var topController = keyWindow()?.rootViewController { + while let presentedViewController = topController.presentedViewController { + topController = presentedViewController + } + return topController + } + return nil + } + + private static func keyWindow() -> UIWindow? { + return UIApplication.shared.windows.first(where: { $0.isKeyWindow }) + } +} diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/UIApplication+ViewController.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/UIApplication+ViewController.swift deleted file mode 100644 index dc60647e6..000000000 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/UIApplication+ViewController.swift +++ /dev/null @@ -1,20 +0,0 @@ -import UIKit - -extension UIApplication { - func topViewController(_ base: UIViewController? = nil) -> UIViewController? { - let base = base ?? UIWindow.key?.rootViewController - if let top = (base as? UINavigationController)?.topViewController { - return topViewController(top) - } - if let selected = (base as? UITabBarController)?.selectedViewController { - return topViewController(selected) - } - if let presented = base as? UIAlertController { - return presented.parent - } - if let presented = base?.presentedViewController, !presented.isBeingDismissed { - return topViewController(presented) - } - return base - } -} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift index 81a29a664..2bc3bda07 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift @@ -18,20 +18,55 @@ enum FirmwareError: Error { } final class FirmwareInteractor { + var batteryIsLow = CurrentValueSubject(false) private let background: BTBackground + private let foreground: BTForeground private let firmwareRepository: FirmwareRepository private let ruuviDFU: RuuviDFU + private var ruuviTagObservationToken: ObservationToken? init( background: BTBackground, + foreground: BTForeground, ruuviDFU: RuuviDFU, firmwareRepository: FirmwareRepository ) { self.background = background + self.foreground = foreground self.ruuviDFU = ruuviDFU self.firmwareRepository = firmwareRepository } + deinit { + ruuviTagObservationToken?.invalidate() + } + + func ensureBatteryHasEnoughPower(uuid: String) { + ruuviTagObservationToken?.invalidate() + ruuviTagObservationToken = foreground.observe(self, uuid: uuid) { observer, device in + if let ruuviTag = device.ruuvi?.tag { + self.batteryIsLow.value = observer.batteryNeedsReplacement(ruuviTag: ruuviTag) + } + } + } + + private func batteryNeedsReplacement( + ruuviTag: RuuviTag + ) -> Bool { + if let temperature = ruuviTag.celsius, + let voltage = ruuviTag.volts { + if temperature < 0, temperature >= -20 { + voltage < 2.3 + } else if temperature < -20 { + voltage < 2 + } else { + voltage < 2.5 + } + } else { + false + } + } + func loadLatestGitHubRelease() -> AnyPublisher { let urlString = "https://api.github.com/repos/ruuvi/ruuvi.firmware.c/releases/latest" guard let url = URL(string: urlString) diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift index 7cd8d475a..673318a9b 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift @@ -34,6 +34,7 @@ final class FirmwarePresenter: RuuviFirmware { uuid: String, currentFirmware: String?, background: BTBackground, + foreground: BTForeground, ruuviDFU: RuuviDFU, firmwareRepository: FirmwareRepository ) { @@ -41,9 +42,11 @@ final class FirmwarePresenter: RuuviFirmware { self.currentFirmware = currentFirmware interactor = FirmwareInteractor( background: background, + foreground: foreground, ruuviDFU: ruuviDFU, firmwareRepository: firmwareRepository ) + interactor.ensureBatteryHasEnoughPower(uuid: uuid) } func isSafeToDismiss() -> Bool { diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmwareBuilder.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmwareBuilder.swift index 870d5a354..c4c63d5fe 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmwareBuilder.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmwareBuilder.swift @@ -3,6 +3,7 @@ import RuuviDFU public struct RuuviFirmwareDependencies { public var background: BTBackground + public var foreground: BTForeground public var ruuviDFU: RuuviDFU public var firmwareRepository: FirmwareRepository } @@ -19,6 +20,7 @@ public final class RuuviFirmwareBuilder { uuid: uuid, currentFirmware: currentFirmware, background: dependencies.background, + foreground: dependencies.foreground, ruuviDFU: dependencies.ruuviDFU, firmwareRepository: dependencies.firmwareRepository ) @@ -30,6 +32,7 @@ public extension RuuviFirmwareDependencies { static var `default`: Self { RuuviFirmwareDependencies( background: BTKit.background, + foreground: BTKit.foreground, ruuviDFU: RuuviDFUImpl.shared, firmwareRepository: FirmwareRepositoryImpl() ) diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift index c01d4bd2a..c8208ac9e 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift @@ -362,6 +362,9 @@ struct FirmwareView: View { alignment: .top ) .padding(EdgeInsets(top: 0, leading: 20, bottom: 20, trailing: 20)) + .onAppear { + viewModel.ensureBatteryHasEnoughPower(uuid: uuid) + } .eraseToAnyView() case .flashing: VStack(alignment: .center, spacing: 24) { @@ -425,6 +428,14 @@ struct FirmwareView: View { VStack { content } + .alert(isPresented: $viewModel.isBatteryLow) { + Alert( + title: Text(""), + message: Text(texts.lowBatteryWarningMessage), + dismissButton: .cancel(Text(texts.okTitle)) + ) + } + .padding() .accentColor(.red) .navigationBarBackButtonHidden(true) .onAppear { diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift index 743063220..0bc14e3f3 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift @@ -10,6 +10,8 @@ final class FirmwareViewModel: ObservableObject { @Published private(set) var state: State = .idle @Published var downloadProgress: Double = 0 @Published var flashProgress: Double = 0 + @Published var isBatteryLow: Bool = false + var output: FirmwareViewModelOutput? private let input = PassthroughSubject() private let uuid: String @@ -42,6 +44,8 @@ final class FirmwareViewModel: ObservableObject { ) .assign(to: \.state, on: self) .store(in: &bag) + + interactor.batteryIsLow.assign(to: &$isBatteryLow) } func send(event: Event) { @@ -51,6 +55,10 @@ final class FirmwareViewModel: ObservableObject { func finish() { output?.firmwareUpgradeDidFinishSuccessfully() } + + func ensureBatteryHasEnoughPower(uuid: String) { + interactor.ensureBatteryHasEnoughPower(uuid: uuid) + } } // MARK: - Feedbacks diff --git a/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloudRequestStateObserver.swift b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloudRequestStateObserver.swift new file mode 100644 index 000000000..b7e1ab3c5 --- /dev/null +++ b/Packages/RuuviCloud/Sources/RuuviCloud/RuuviCloudRequestStateObserver.swift @@ -0,0 +1,48 @@ +import Foundation + +public class RuuviCloudRequestStateObserverManager { + public static let shared = RuuviCloudRequestStateObserverManager() + private var cloudRequestStateTokens: [String: NSObjectProtocol] = [:] + + private init() {} + + public func startObserving( + for macId: String?, + callback: @escaping (RuuviCloudRequestStateType) -> Void + ) { + // Ensures no duplicate observers for the same macId + guard let macId = macId else { return } + stopObserving(for: macId) + + let token = NotificationCenter.default.addObserver( + forName: .RuuviCloudRequestStateDidChange, + object: nil, + queue: .main, + using: { notification in + guard let userInfo = notification.userInfo, + let observedMacId = userInfo[RuuviCloudRequestStateKey.macId] as? String, + observedMacId == macId, + let state = userInfo[RuuviCloudRequestStateKey.state] as? RuuviCloudRequestStateType else { + return + } + callback(state) + } + ) + + cloudRequestStateTokens[macId] = token + } + + public func stopObserving(for macId: String?) { + guard let macId = macId else { return } + if let token = cloudRequestStateTokens[macId] { + NotificationCenter.default.removeObserver(token) + cloudRequestStateTokens[macId] = nil + } + } + + public func stopAllObservers() { + for (macId, _) in cloudRequestStateTokens { + stopObserving(for: macId) + } + } +} From 440da6088a3fe51244fd8ad25d323d1952e875a2 Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Fri, 29 Dec 2023 18:07:17 +0100 Subject: [PATCH 69/84] fix: Disable RSSI alert after unclaim #1751 (#1826) --- .../TagSettings/View/UI/TagSettingsViewController.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift index e16381b60..12b186fa4 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift @@ -1256,6 +1256,15 @@ extension TagSettingsViewController { disable: !hasMeasurement || !GlobalHelpers.getBool(from: isClaimed), identifier: .alertRSSI ) + // Disable active signal alert if tag is unclaimed. + if !isClaimed.bound, + let isSignalAlertOn = self?.viewModel?.isSignalAlertOn.value, + isSignalAlertOn { + self?.output.viewDidChangeAlertState( + for: .signal(lower: 0, upper: 0), + isOn: false + ) + } } } From 95fdcbdbc1b145e2a21adefcf93ad4c8a1b5f92d Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Mon, 1 Jan 2024 15:30:20 +0200 Subject: [PATCH 70/84] Fix signed in initial empty screen (#1829) fixes #1828 --- .../Modules/Dashboard/Home/View/NoSensorView.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift index e5c58ffa4..9dde8072f 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift @@ -130,13 +130,14 @@ extension NoSensorView { centerButtonStackView.subviews.forEach { $0.removeFromSuperview() } } - let buttons = userSignInOnce ? [signInButton, addSensorButton] : [addSensorButton] + let buttons = userSignInOnce ? [addSensorButton] : [signInButton, addSensorButton] for button in buttons { centerButtonStackView.addArrangedSubview(button) } messageLabel.text = userSignInOnce ? - RuuviLocalization.dashboardNoSensorsMessageSignedOut : - RuuviLocalization.dashboardNoSensorsMessage + RuuviLocalization.dashboardNoSensorsMessage : + RuuviLocalization.dashboardNoSensorsMessageSignedOut + centerButtonCenterYAnchor.isActive = userSignInOnce ? activateCenterButtonStackConstraint() : true } From 0fde50ab313639c700ffb05c93aadf40b61320ba Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Mon, 1 Jan 2024 17:08:07 +0200 Subject: [PATCH 71/84] Fix signed in initial empty screen (#1831) fixes #1828 with spec from #1634 --- .../Home/Presenter/DashboardPresenter.swift | 1 + .../Home/View/DashboardViewController.swift | 25 ++++++++++++++++--- .../Home/View/DashboardViewInput.swift | 1 + .../Dashboard/Home/View/NoSensorView.swift | 16 ++++++------ 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift index 5f0adbf70..b97c17b42 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Presenter/DashboardPresenter.swift @@ -574,6 +574,7 @@ extension DashboardPresenter: TagSettingsModuleOutput { extension DashboardPresenter { private func syncViewModels() { view?.userSignedInOnce = settings.signedInAtleastOnce + view?.isAuthorized = ruuviUser.isAuthorized view?.dashboardType = settings.dashboardType view?.dashboardTapActionType = settings.dashboardTapActionType view?.dashboardSortingType = dashboardSortingType() diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift index 1dc615cd1..7f9550c5a 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift @@ -42,9 +42,26 @@ class DashboardViewController: UIViewController { } } + var showSignInButtonOnNoSensorView: Bool { + switch (isAuthorized, userSignedInOnce) { + case (true, _): + return false + case (false, true): + return true + case (false, false): + return false + } + } + var userSignedInOnce: Bool = false { didSet { - noSensorView.userSignedInOnce = userSignedInOnce + noSensorView.showSignInButtonOnNoSensorView = showSignInButtonOnNoSensorView + } + } + + var isAuthorized: Bool = false { + didSet { + noSensorView.showSignInButtonOnNoSensorView = showSignInButtonOnNoSensorView } } @@ -86,7 +103,7 @@ class DashboardViewController: UIViewController { view.layer.cornerRadius = 12 view.clipsToBounds = true view.delegate = self - view.userSignedInOnce = userSignedInOnce + view.showSignInButtonOnNoSensorView = showSignInButtonOnNoSensorView return view }() @@ -803,7 +820,9 @@ extension DashboardViewController: DashboardViewInput { } func showNoSensorsAddedMessage(show: Bool) { - noSensorView.updateView(userSignInOnce: userSignedInOnce) + noSensorView.updateView( + showSignInButtonOnNoSensorView: showSignInButtonOnNoSensorView + ) noSensorView.isHidden = !show collectionView.isHidden = show } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift index 47139a4c1..ae7dfa5ff 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewInput.swift @@ -8,6 +8,7 @@ protocol DashboardViewInput: ViewInput { var dashboardTapActionType: DashboardTapActionType! { get set } var dashboardSortingType: DashboardSortingType! { get set } var userSignedInOnce: Bool { get set } + var isAuthorized: Bool { get set } func applyUpdate(to viewModel: CardsViewModel) func showNoSensorsAddedMessage(show: Bool) func showBluetoothDisabled(userDeclined: Bool) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift index 9dde8072f..7f94387d1 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/NoSensorView.swift @@ -19,7 +19,7 @@ class NoSensorView: UIView { } weak var delegate: NoSensorViewDelegate? - var userSignedInOnce: Bool = false + var showSignInButtonOnNoSensorView: Bool = false private lazy var scrollView: UIScrollView = { let scroll = UIScrollView() @@ -125,21 +125,21 @@ extension NoSensorView { // MARK: - Public extension NoSensorView { - func updateView(userSignInOnce: Bool) { + func updateView(showSignInButtonOnNoSensorView: Bool) { if centerButtonStackView.subviews.count > 0 { centerButtonStackView.subviews.forEach { $0.removeFromSuperview() } } - let buttons = userSignInOnce ? [addSensorButton] : [signInButton, addSensorButton] + let buttons = showSignInButtonOnNoSensorView ? [signInButton, addSensorButton] : [addSensorButton] for button in buttons { centerButtonStackView.addArrangedSubview(button) } - messageLabel.text = userSignInOnce ? - RuuviLocalization.dashboardNoSensorsMessage : - RuuviLocalization.dashboardNoSensorsMessageSignedOut + messageLabel.text = showSignInButtonOnNoSensorView ? + RuuviLocalization.dashboardNoSensorsMessageSignedOut : + RuuviLocalization.dashboardNoSensorsMessage centerButtonCenterYAnchor.isActive = - userSignInOnce ? activateCenterButtonStackConstraint() : true + showSignInButtonOnNoSensorView ? activateCenterButtonStackConstraint() : true } } @@ -246,7 +246,7 @@ extension NoSensorView { } private func activateCenterButtonStackConstraint() -> Bool { - if !userSignedInOnce { + if !showSignInButtonOnNoSensorView { return true } From 2b019845b2249040dc874429cafa94912b6b4a67 Mon Sep 17 00:00:00 2001 From: Priyonto M Rahman Date: Tue, 2 Jan 2024 17:45:16 +0100 Subject: [PATCH 72/84] fix: Show message for cloud connection alert #1833 (#1834) --- .../NotificationService/Sources/NotificationService.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Apps/RuuviStation/NotificationService/Sources/NotificationService.swift b/Apps/RuuviStation/NotificationService/Sources/NotificationService.swift index e112c4315..e27b19fe9 100644 --- a/Apps/RuuviStation/NotificationService/Sources/NotificationService.swift +++ b/Apps/RuuviStation/NotificationService/Sources/NotificationService.swift @@ -79,6 +79,8 @@ extension NotificationService { .signal case "movement": .movement + case "offline": + .offline default: nil } @@ -129,7 +131,9 @@ extension NotificationService { case .movement: return RuuviLocalization.LocalNotificationsManager.DidMove.title(locale) case .offline: - return "" // TODO: @rinat obtain spec + // No message for alert type under for offline since + // the trigger is always 'Over' i.e. Sensor has been offline over x mins. + return "" } case .over: switch alertType { @@ -144,7 +148,7 @@ extension NotificationService { case .movement: return RuuviLocalization.LocalNotificationsManager.DidMove.title(locale) case .offline: - return "" // TODO: @rinat obtain spec + return RuuviLocalization.alertNotificationOfflineMessage(threshold, locale) } } } From 0bb8afc490990070bf41c70d37adfa540ad24273 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 6 Jan 2024 11:40:38 +0200 Subject: [PATCH 73/84] update station.localization pointer --- station.localization | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/station.localization b/station.localization index 5fb683407..b732c1789 160000 --- a/station.localization +++ b/station.localization @@ -1 +1 @@ -Subproject commit 5fb6834077d29ff88d21b7ffe74f9e97f6576497 +Subproject commit b732c178953b19382911f7707dc5d9af8429c644 From 0386f9764e82ecaf557895a4444f9b1672979b7a Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 6 Jan 2024 12:27:06 +0200 Subject: [PATCH 74/84] Dont remove localIds when signing out (#1837) Its not private data, it is connected to this device [by uuid] only. Motivation: during sign out heartbeat received may fail to find macId --- .../RuuviLocal/Sources/RuuviLocal/RuuviLocalIDs.swift | 1 - .../RuuviLocalIDsUserDefaults.swift | 9 --------- .../Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift | 1 - .../RuuviServiceOwnershipImpl.swift | 1 - 4 files changed, 12 deletions(-) diff --git a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalIDs.swift b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalIDs.swift index e72b0f8e4..0b6c07850 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalIDs.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalIDs.swift @@ -6,5 +6,4 @@ public protocol RuuviLocalIDs { func set(mac: MACIdentifier, for luid: LocalIdentifier) func luid(for mac: MACIdentifier) -> LocalIdentifier? func set(luid: LocalIdentifier, for mac: MACIdentifier) - func clear(sensor: RuuviTagSensor) } diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalIDsUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalIDsUserDefaults.swift index 3d593962c..cda352070 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalIDsUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalIDsUserDefaults.swift @@ -17,13 +17,4 @@ class RuuviLocalIDsUserDefaults: RuuviLocalIDs { func set(luid: LocalIdentifier, for mac: MACIdentifier) { UserDefaults.standard.set(luid.value, forKey: mac.value) } - - func clear(sensor: RuuviTagSensor) { - if let luid = sensor.luid { - UserDefaults.standard.set(nil, forKey: luid.value) - } - if let macId = sensor.macId { - UserDefaults.standard.set(nil, forKey: macId.value) - } - } } diff --git a/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift b/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift index 5725beb93..8c3bef155 100644 --- a/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceAuth/RuuviServiceAuthImpl.swift @@ -51,7 +51,6 @@ public final class RuuviServiceAuthImpl: RuuviServiceAuth { let deleteQueuedRequestsOperation = sSelf.pool.deleteQueuedRequests() let cleanUpOperation = sSelf.pool.cleanupDBSpace() sSelf.propertiesService.removeImage(for: sensor) - sSelf.localIDs.clear(sensor: sensor) sSelf.localSyncState.setSyncDate(nil, for: sensor.macId) sSelf.localSyncState.setSyncDate(nil) sSelf.localSyncState.setGattSyncDate(nil, for: sensor.macId) diff --git a/Packages/RuuviService/Sources/RuuviServiceOwnership/RuuviServiceOwnershipImpl.swift b/Packages/RuuviService/Sources/RuuviServiceOwnership/RuuviServiceOwnershipImpl.swift index 5f9df21a0..bb318788f 100644 --- a/Packages/RuuviService/Sources/RuuviServiceOwnership/RuuviServiceOwnershipImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceOwnership/RuuviServiceOwnershipImpl.swift @@ -220,7 +220,6 @@ public final class RuuviServiceOwnershipImpl: RuuviServiceOwnership { } } propertiesService.removeImage(for: sensor) - localIDs.clear(sensor: sensor) Future.zip([ deleteTagOperation, deleteRecordsOperation, From cda030a30fd8480cfc64814c76a25507a30e4a0a Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 6 Jan 2024 12:27:23 +0200 Subject: [PATCH 75/84] Dont abort if same RuuviTag is added by id - just replace it (#1838) Motivation: fixed #1418 --- .../Sources/RuuviOntologySQLite/RuuviTagSQLite.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSQLite.swift b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSQLite.swift index 0bba62ac2..2167b65e7 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSQLite.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntologySQLite/RuuviTagSQLite.swift @@ -121,7 +121,7 @@ extension RuuviTagSQLite: PersistableRecord { public extension RuuviTagSQLite { static func createTable(in db: Database) throws { try db.create(table: RuuviTagSQLite.databaseTableName, body: { table in - table.column(RuuviTagSQLite.idColumn.name, .text).notNull().primaryKey(onConflict: .abort) + table.column(RuuviTagSQLite.idColumn.name, .text).notNull().primaryKey(onConflict: .replace) table.column(RuuviTagSQLite.macColumn.name, .text) table.column(RuuviTagSQLite.luidColumn.name, .text) table.column(RuuviTagSQLite.nameColumn.name, .text).notNull() From 9449eb7ba308e03b9ba28e4c356d6c431bb06f87 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 6 Jan 2024 13:29:13 +0200 Subject: [PATCH 76/84] Listen to UUID updates for given MAC (#1841) * Listen to UUID updates for given MAC E.g. the Ruuvi Tag could change its UUID because of update with nRF tools * use observer instead of weka self --- .../RuuviTagPropertiesDaemonBTKit.swift | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift index 3c88f654e..6c78abe81 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift @@ -111,6 +111,7 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro private func restartObserving() { removeTokens() + listenToUuidChangesForMac() for ruuviTag in ruuviTags { if let luid = ruuviTag.luid { observeTokens.append(foreground.observe( @@ -173,6 +174,21 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro } } + private func listenToUuidChangesForMac() { + let scanToken = foreground.scan(self, closure: { observer, device in + guard let tag = device.ruuvi?.tag, + let luid = tag.luid, + let macId = tag.macId + else { + return + } + if observer.idPersistence.luid(for: macId)?.any != luid.any { + observer.idPersistence.set(luid: luid, for: macId) + } + }) + scanTokens.append(scanToken) + } + private func scanRemoteSensor(ruuviTag: AnyRuuviTagSensor) { guard let mac = ruuviTag.macId, ruuviTag.luid == nil From d07196663b1fa17608bf050478759b71709340af Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 6 Jan 2024 13:43:23 +0200 Subject: [PATCH 77/84] Update in SQLite the luid of a sensor (#1843) To ensure we are listening to the correct one --- .../RuuviTagPropertiesDaemonBTKit.swift | 4 ++++ .../Sensor/RuuviTag/RuuviTagSensor.swift | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift index 6c78abe81..04be7f5ba 100644 --- a/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift +++ b/Packages/RuuviDaemon/Sources/RuuviDaemonRuuviTag/Properties/RuuviTagPropertiesDaemonBTKit.swift @@ -184,6 +184,10 @@ public final class RuuviTagPropertiesDaemonBTKit: RuuviDaemonWorker, RuuviTagPro } if observer.idPersistence.luid(for: macId)?.any != luid.any { observer.idPersistence.set(luid: luid, for: macId) + observer.sqiltePersistence.readOne(macId.mac) + .on { [weak observer] sensor in + observer?.ruuviPool.update(sensor.with(luid: luid)) + } } }) scanTokens.append(scanToken) diff --git a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensor.swift b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensor.swift index 8e8e0a95f..fd16a7483 100644 --- a/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensor.swift +++ b/Packages/RuuviOntology/Sources/RuuviOntology/Sensor/RuuviTag/RuuviTagSensor.swift @@ -181,6 +181,24 @@ public extension RuuviTagSensor { ) } + func with(luid: LocalIdentifier) -> RuuviTagSensor { + RuuviTagSensorStruct( + version: version, + firmwareVersion: firmwareVersion, + luid: luid, + macId: macId, + isConnectable: isConnectable, + name: name, + isClaimed: isClaimed, + isOwner: isOwner, + owner: owner, + ownersPlan: ownersPlan, + isCloudSensor: isCloudSensor, + canShare: canShare, + sharedTo: sharedTo + ) + } + func withoutMac() -> RuuviTagSensor { RuuviTagSensorStruct( version: version, From 4121ecffc5d3b3aff46e3056229381bfda9b5450 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 6 Jan 2024 15:50:41 +0200 Subject: [PATCH 78/84] Upgrade Charts to 5+ (#1846) Motivation: use SwiftUI charts without conflicts in namespaces --- .../Dashboard/Charts/Helpers/CustomXAxisRenderer.swift | 2 +- .../Dashboard/Charts/Helpers/CustomYAxisRenderer.swift | 2 +- .../Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift | 2 +- .../Dashboard/Charts/Helpers/XAxisValueFormatter.swift | 2 +- .../Dashboard/Charts/Helpers/YAxisValueFormatter.swift | 2 +- .../Dashboard/Charts/Presenter/TagChartsViewPresenter.swift | 2 +- .../Modules/Dashboard/Charts/View/TagChartsViewInput.swift | 2 +- .../Modules/Dashboard/Charts/View/TagChartsViewModel.swift | 2 +- .../Dashboard/Charts/View/UI/TagChartsMarkerView.swift | 2 +- .../Modules/Dashboard/Charts/View/UI/TagChartsView.swift | 2 +- .../Dashboard/Charts/View/UI/TagChartsViewController.swift | 2 +- Apps/RuuviStation/target.yml | 2 +- project.yml | 4 ++-- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift index 004a21c4f..7ba8ca944 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomXAxisRenderer.swift @@ -1,4 +1,4 @@ -import Charts +import DGCharts import Foundation import RuuviOntology diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift index 45acf3092..57ee13bc6 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/CustomYAxisRenderer.swift @@ -1,4 +1,4 @@ -import Charts +import DGCharts import UIKit class CustomYAxisRenderer: YAxisRenderer { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift index 4d8ed7e3c..5c412db4b 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/TagChartsHelper.swift @@ -1,4 +1,4 @@ -import Charts +import DGCharts import Foundation import RuuviLocalization diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/XAxisValueFormatter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/XAxisValueFormatter.swift index 719d702bb..a77792830 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/XAxisValueFormatter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/XAxisValueFormatter.swift @@ -1,4 +1,4 @@ -import Charts +import DGCharts import Foundation import RuuviOntology diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift index 8980d432b..84bf40b04 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Helpers/YAxisValueFormatter.swift @@ -1,4 +1,4 @@ -import Charts +import DGCharts import Foundation public class YAxisValueFormatter: NSObject, AxisValueFormatter { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift index 279f2857b..5caff5d1f 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/Presenter/TagChartsViewPresenter.swift @@ -1,5 +1,5 @@ import BTKit -import Charts +import DGCharts import CoreBluetooth import Foundation import Future diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift index 2ebd66e7f..c59ade856 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewInput.swift @@ -1,5 +1,5 @@ import BTKit -import Charts +import DGCharts import Foundation import RuuviLocal import RuuviOntology diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift index 4b61643dc..202192f75 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/TagChartsViewModel.swift @@ -1,4 +1,4 @@ -import Charts +import DGCharts import Humidity import RuuviOntology import UIKit diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift index 1aacac812..5527aa8aa 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsMarkerView.swift @@ -1,4 +1,4 @@ -import Charts +import DGCharts import RuuviLocalization import RuuviService import UIKit diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift index 7c5be0f38..9fbaa1484 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsView.swift @@ -1,4 +1,4 @@ -import Charts +import DGCharts import RuuviLocal import RuuviLocalization import RuuviOntology diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift index b53c01d7b..823bf9de9 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift @@ -1,5 +1,5 @@ import BTKit -import Charts +import DGCharts // swiftlint:disable file_length import Foundation import GestureInstructions diff --git a/Apps/RuuviStation/target.yml b/Apps/RuuviStation/target.yml index 3995585c7..e90233621 100644 --- a/Apps/RuuviStation/target.yml +++ b/Apps/RuuviStation/target.yml @@ -14,7 +14,7 @@ targets: - target: "station.intents" - target: "station.pnservice" - package: BTKit - - package: Charts + - package: DGCharts - package: GRDB - package: LightRoute - package: Swinject diff --git a/project.yml b/project.yml index 1a0c2b35f..ea79781df 100644 --- a/project.yml +++ b/project.yml @@ -83,9 +83,9 @@ packages: BTKit: url: https://github.com/ruuvi/BTKit from: 0.5.2 - Charts: + DGCharts: url: https://github.com/danielgindi/Charts - from: 4.1.0 + from: 5.0.0 LightRoute: url: https://github.com/rinat-enikeev/LightRoute from: 2.2.2 From baab231f6d7fa55bd17fab6250274c50fb50218c Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Sat, 6 Jan 2024 19:14:24 +0200 Subject: [PATCH 79/84] Move Assets to RuuviLocalization (#1847) * Move Assets to RuuviLocalization Motivation: avoid duplicate assets, easy to import compile time safe usage * remove icon weather station * merge * eliminate preparation for RuuviDiscover assets * remove not used * rename to Onboarding * remove RuuviAsset [codegened] * add ruuvi asset to gitignore --- .swiftgen.assets.yml | 12 +++- .../BackgroundSelectionPresenter.swift | 2 +- .../BackgroundSelectionViewController.swift | 2 +- .../Cards/View/UI/CardsBackgroundView.swift | 3 +- .../Cards/View/UI/CardsLargeImageCell.swift | 18 ++---- .../Cards/View/UI/CardsViewController.swift | 20 +++--- .../View/UI/TagChartsViewController.swift | 18 ++---- .../Home/View/DashboardImageCell.swift | 24 +++---- .../Home/View/DashboardPlainCell.swift | 24 +++---- .../Home/View/DashboardViewController.swift | 6 +- .../ViewController/ShareViewController.swift | 2 +- .../View/SignInBenefitsViewController.swift | 4 +- .../View/UI/Helper/SignInVerifyView.swift | 2 +- .../SignIn/View/UI/SignInViewController.swift | 4 +- .../UI/SensorForceClaimViewController.swift | 2 +- .../OffsetCorrectionAppleViewController.swift | 2 +- .../Owner/View/OwnerViewController.swift | 2 +- .../View/UI/SensorRemovalViewController.swift | 2 +- .../RUAlertDetailsCellChildView.swift | 2 +- .../RUAlertExpandButton.swift | 2 +- .../View/UI/TagSettingsBasicCell.swift | 2 +- .../TagSettingsExpandableSectionHeader.swift | 10 +-- .../View/UI/TagSettingsViewController.swift | 2 +- .../Extensions/UIImage+Extension.swift | 12 +--- .../Resources/Assets/RuuviAssets.swift | 25 -------- .../Contents.json | 16 ----- .../Contents.json | 15 ----- .../bluetooth_icon.imageset/Contents.json | 15 ----- .../dismiss-modal-icon.imageset/Contents.json | 26 -------- .../Contents.json | 12 ---- .../ic_refresh.imageset/Contents.json | 16 ----- .../icon-alert-active.imageset/Contents.json | 16 ----- .../icon-alert-off.imageset/Contents.json | 16 ----- .../icon-alert-on.imageset/Contents.json | 16 ----- .../icon-bg-camera.imageset/Contents.json | 16 ----- .../icon-cards-button.imageset/Contents.json | 16 ----- .../icon-charts-button.imageset/Contents.json | 15 ----- .../Contents.json | 16 ----- .../icon-download.imageset/Contents.json | 16 ----- .../icon-refresh.imageset/Contents.json | 16 ----- .../icon-warning.imageset/Contents.json | 16 ----- .../icon-weatherstation.pdf | Bin 1363 -> 0 bytes .../iphone_icon.imageset/Contents.json | 15 ----- .../plus_icon.imageset/Contents.json | 15 ----- .../Contents.json | 15 ----- .../web-ruuvi-eye-nega.pdf | Bin 1049 -> 0 bytes .../Contents.json | 15 ----- Common/RuuviLocalization/.gitignore | 1 + .../RuuviAssets.xcassets}/Contents.json | 0 .../Onboarding}/Contents.json | 0 .../gateway.imageset/Contents.json | 0 .../Onboarding}/gateway.imageset/gateway.png | Bin .../onboarding_alerts.imageset/Contents.json | 0 .../ipad-alerts.png | Bin .../onboarding_alerts.png | Bin .../Contents.json | 0 .../beaver-sign.png | Bin .../1-beaver-start.png | Bin .../Contents.json | 0 .../Contents.json | 0 .../bg_layer_dark.jpg | Bin .../Contents.json | 0 .../ipad-dashboard.png | Bin .../onboarding_dashboard.png | Bin .../onboarding_history.imageset/Contents.json | 0 .../ipad-graphs.png | Bin .../onboarding_history.png | Bin .../onboarding_sensors.imageset/Contents.json | 0 .../ipad-sensor-view.png | Bin .../onboarding_sensors.png | Bin .../onboarding_share.imageset/Contents.json | 0 .../onboarding_share.png | Bin .../onboarding_web.imageset/9-web.png | Bin .../onboarding_web.imageset/Contents.json | 0 .../onboarding_widgets.imageset/Contents.json | 0 .../ipad-widgets.png | Bin .../onboarding_widgets.png | Bin .../access_data.imageset/2.pdf | Bin .../access_data.imageset/Contents.json | 0 .../arrow_drop_down.imageset/Contents.json | 0 .../arrow_drop_down.svg | 0 .../background.imageset/Contents.json | 0 .../background.imageset/bg9.jpg | Bin .../Contents.json | 12 ++-- ...eline_keyboard_backspace_white_48pt_1x.png | Bin ...eline_keyboard_backspace_white_48pt_2x.png | Bin ...eline_keyboard_backspace_white_48pt_3x.png | Bin .../Contents.json | 12 ++-- .../baseline_menu_white_48pt_1x.png | Bin .../baseline_menu_white_48pt_2x.png | Bin .../baseline_menu_white_48pt_3x.png | Bin .../Contents.json | 12 ++-- .../baseline_settings_white_48pt_1x.png | Bin .../baseline_settings_white_48pt_2x.png | Bin .../baseline_settings_white_48pt_3x.png | Bin .../beaver-mail.imageset/Contents.json | 0 .../beaver-mail.imageset/beaver-mail.png | Bin .../Contents.json | 16 +++++ .../bluetooth_connected-24px.pdf | Bin .../Contents.json | 0 .../bluetooth_disabled_black_108x108.png | Bin .../bluetooth_icon.imageset}/Contents.json | 2 +- .../bluetooth_white_108x108.png | Bin .../checkmark_icon.imageset/Contents.json | 10 +-- ...seline_check_circle_outline_black_18dp.png | Bin .../chevron.down.imageset/Contents.json | 0 .../chevron.down.imageset/chevron.down.pdf | Bin .../chevron.up.imageset/Contents.json | 0 .../chevron.up.imageset/chevron.up.pdf | Bin .../chevron_back.imageset/Contents.json | 0 .../chevron_back.imageset/chevron_back.png | Bin .../chevron_back.imageset/chevron_back@2x.png | Bin .../chevron_back.imageset/chevron_back@3x.png | Bin .../dismiss-modal-icon.imageset/Contents.json | 0 .../dismiss-modal-icon.imageset/down.png | Bin .../dismiss-modal-icon.imageset/down@2x.png | Bin .../dismiss-modal-icon.imageset/down@3x.png | Bin .../edit_pen.imageset/Contents.json | 0 .../edit_pen.imageset/edit_pen.svg | 0 .../eye_circle.imageset/Contents.json | 8 +-- .../eye_circle.imageset/eye_circle.png | Bin .../Contents.json | 5 +- .../gesture-assistant-hand.imageset/hand.pdf | Bin .../get_started.imageset/5.pdf | Bin .../get_started.imageset/Contents.json | 0 .../gradient_layer.imageset/Contents.json | 8 +-- .../gradient_layer.png | Bin .../ic_refresh.imageset/Contents.json | 16 +++++ .../ic_refresh.imageset/ic_refresh_24px.pdf | Bin .../icon-alert-active.imageset}/Contents.json | 5 +- .../icon-alert-active.imageset/active.pdf | Bin .../icon-alert-off.imageset/Contents.json | 16 +++++ .../icon-alert-off.imageset/alert-off.pdf | Bin .../icon-alert-on.imageset/Contents.json | 16 +++++ .../icon-alert-on.imageset/alert-on.pdf | Bin .../icon-bg-camera.imageset/Contents.json | 16 +++++ .../icon-bg-camera-1.pdf | Bin .../Contents.json | 0 .../icon-bluetooth-connected.pdf | Bin .../icon-bluetooth.imageset/Contents.json | 0 .../icon-bluetooth.pdf | Bin .../icon-cards-button.imageset/Contents.json | 16 +++++ .../icon-cards-button.imageset/vector.pdf | Bin .../Contents.json | 2 +- .../icon-charts-button.imageset/vector-3.pdf | Bin .../icon-connectable.imageset/Contents.json | 0 .../icons8-connected-1.png | Bin .../icons8-connected-2.png | Bin .../icons8-connected.png | Bin .../icon-connection-1.imageset/Contents.json | 8 +-- .../icon-connection-1.png | Bin .../icon-connection-2.imageset/Contents.json | 8 +-- .../icon-connection-2.png | Bin .../icon-connection-3.imageset/Contents.json | 8 +-- .../icon-connection-3.png | Bin .../Contents.json | 16 +++++ .../delete_forever_48px.pdf | Bin .../icon-download.imageset/Contents.json | 16 +++++ .../icon-download.imageset/download.pdf | Bin .../icon-gateway.imageset/Contents.json | 0 .../icon-gateway.imageset/icon-gateway.pdf | Bin .../Contents.json | 8 +-- .../icon-measure-humidity.png | Bin .../Contents.json | 12 ++-- .../icon-measure.png | Bin .../icon-measure@2x.png | Bin .../icon_measure@3x.png | Bin .../Contents.json | 0 .../icon-measure-movement.pdf | Bin .../Contents.json | 8 +-- .../icon-measure-pressure.png | Bin .../Contents.json | 8 +-- .../icon-measure-signal.png | Bin .../icon-refresh.imageset/Contents.json | 16 +++++ .../icon-refresh.imageset/sync_48px.pdf | Bin .../icon-warning.imageset/Contents.json | 16 +++++ .../icon-warning.imageset/warning-sign.pdf | Bin .../icon_back_arrow.imageset/Contents.json | 0 .../icon_back_arrow.imageset/icons8-back.pdf | Bin .../icon_sync_bt.imageset/Contents.json | 0 .../icon_sync_bt.imageset/icon_sync_bt.png | Bin .../iphone_icon.imageset}/Contents.json | 2 +- .../iphone_icon.imageset/phone_black.png | Bin .../Contents.json | 12 ++-- .../location-picker-pin-icon.png | Bin .../location-picker-pin-icon@2x.png | Bin .../location-picker-pin-icon@3x.png | Bin .../measure_data.imageset/1.pdf | Bin .../measure_data.imageset/Contents.json | 0 .../more_3dot.imageset/Contents.json | 0 .../more_3dot.imageset/more_3dot.pdf | Bin .../no-image.imageset/Contents.json | 0 .../no-image.imageset/icons8-no_image.pdf | Bin .../overlay.imageset/Contents.json | 0 .../overlay.imageset/gradient_layer.png | Bin .../plus_icon.imageset}/Contents.json | 4 +- .../icons8-plus-math-filled-100.png | Bin .../ruuvi-cloud.imageset/Contents.json | 0 .../ruuvi-cloud.imageset/ruuvi-cloud.pdf | Bin .../Contents.json | 0 .../ruuvi_activity_presenter_logo.png | Bin .../ruuvi_logo.imageset/Contents.json | 0 .../ruuvi_logo.imageset}/ruuvi_logo.png | Bin .../ruuvi_station.imageset/Contents.json | 12 ++-- .../ruuvi_station.imageset/ruuvi_station.png | Bin .../ruuvi_station_2x.png | Bin .../ruuvi_station_3x.png | Bin .../Contents.json | 0 .../ruuvitag-b8-and-older-button-location.png | Bin .../set_alerts.imageset/3.pdf | Bin .../set_alerts.imageset/Contents.json | 0 .../sign_in_bg_layer.imageset}/Contents.json | 0 .../bg_layer_dark.jpg | Bin .../Contents.json | 12 ++-- .../baseline_clear_black_36pt_1x.png | Bin .../baseline_clear_black_36pt_2x.png | Bin .../baseline_clear_black_36pt_3x.png | Bin .../Contents.json | 0 .../info_icon.png | Bin .../tag_bg_layer.imageset/Contents.json | 8 +-- .../tag_bg_layer.imageset/tag_bg_layer.png | Bin .../welcome_friend 1.imageset}/Contents.json | 0 .../title-welcome1x.png | Bin .../title-welcome2x.png | Bin .../title-welcome3x.png | Bin .../welcome_friend.imageset/Contents.json | 12 ++-- .../title-welcome1x.png | Bin .../title-welcome2x.png | Bin .../title-welcome3x.png | Bin Common/RuuviLocalization/target.yml | 6 +- .../View/ActivityPresenterView.swift | 5 +- .../Util/RuuviBundleUtils.swift | 60 ------------------ .../bluetooth_disabled_black_108x108.png | Bin 2319 -> 0 bytes .../button_tint_color.colorset/Contents.json | 20 ------ .../dismiss-modal-icon.imageset/down.png | Bin 319 -> 0 bytes .../dismiss-modal-icon.imageset/down@2x.png | Bin 494 -> 0 bytes .../dismiss-modal-icon.imageset/down@3x.png | Bin 609 -> 0 bytes .../icon-connection-1.png | Bin 361 -> 0 bytes .../icon-connection-2.png | Bin 358 -> 0 bytes .../icon-connection-3.png | Bin 336 -> 0 bytes .../primary_color.colorset/Contents.json | 38 ----------- .../ruuvi_logo.imageset/eye_circle.png | Bin 7545 -> 0 bytes .../Contents.json | 38 ----------- .../ruuvi_text_color.colorset/Contents.json | 38 ----------- .../info_icon.png | Bin 1136 -> 0 bytes .../RuuviDiscover/Util/RuuviBundleUtils.swift | 22 ------- .../VMP/Presenter/DiscoverPresenter.swift | 3 +- .../Table/DiscoverTableViewController.swift | 15 ++++- .../RuuviFirmware/Common/RuuvoBoardView.swift | 6 +- .../RuuviFirmware.xcassets/Contents.json | 6 -- .../RuuviFirmware/Util/RuuviBundleUtils.swift | 60 ------------------ .../Pages/Assests/RuuviAssets.swift | 15 ----- .../Pages/RuuviOnboardCoreFeaturesCell.swift | 2 +- .../RuuviOnboardGatewayFeaturesCell.swift | 7 +- .../Pages/RuuviOnboardSignInCell.swift | 5 +- .../Pages/RuuviOnboardStartCell.swift | 6 +- .../Pages/RuuviOnboardViewController.swift | 21 +++--- .../Pages/Util/RuuviBundleUtils.swift | 60 ------------------ .../RuuviOnboard.xcassets/Contents.json | 6 -- .../Resources/Contents.json | 6 -- .../ruuvi_logo.imageset/ruuvi_logo.png | Bin 7490 -> 0 bytes .../RuuviTag/RuuviTagSensorRecord.swift | 1 - 262 files changed, 378 insertions(+), 950 deletions(-) delete mode 100644 Apps/RuuviStation/Sources/Resources/Assets/RuuviAssets.swift delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth-connected.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_disabled_icon.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_icon.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gesture-assistant-hand.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ic_refresh.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-active.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-off.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-on.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bg-camera.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-cards-button.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-charts-button.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-delete-forever.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-download.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-refresh.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-warning.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-weatherstation.imageset/icon-weatherstation.pdf delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/iphone_icon.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/plus_icon.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/Contents.json delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/web-ruuvi-eye-nega.pdf delete mode 100644 Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag-settings-info-icon.imageset/Contents.json rename Common/{RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets => RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/Contents.json (100%) rename {Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/Contents.json (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/gateway.imageset/Contents.json (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/gateway.imageset/gateway.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_alerts.imageset/Contents.json (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_alerts.imageset/ipad-alerts.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_alerts.imageset/onboarding_alerts.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_beaver_sign_in.imageset/Contents.json (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_beaver_sign_in.imageset/beaver-sign.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_beaver_start.imageset/1-beaver-start.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_beaver_start.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/sign_in_bg_layer.imageset => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_bg_layer.imageset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/sign_in_bg_layer.imageset => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_bg_layer.imageset}/bg_layer_dark.jpg (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_dashboard.imageset/Contents.json (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_dashboard.imageset/ipad-dashboard.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_dashboard.imageset/onboarding_dashboard.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_history.imageset/Contents.json (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_history.imageset/ipad-graphs.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_history.imageset/onboarding_history.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_sensors.imageset/Contents.json (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_sensors.imageset/ipad-sensor-view.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_sensors.imageset/onboarding_sensors.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_share.imageset/Contents.json (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_share.imageset/onboarding_share.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_web.imageset/9-web.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_web.imageset/Contents.json (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_widgets.imageset/Contents.json (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_widgets.imageset/ipad-widgets.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding}/onboarding_widgets.imageset/onboarding_widgets.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/access_data.imageset/2.pdf (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/access_data.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/arrow_drop_down.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/arrow_drop_down.imageset/arrow_drop_down.svg (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/background.imageset/Contents.json (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/background.imageset/bg9.jpg (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/baseline_keyboard_backspace_white_48pt.imageset/Contents.json (91%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_1x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_2x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_3x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/baseline_menu_white_48pt.imageset/Contents.json (91%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_1x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_2x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_3x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/baseline_settings_white_48pt.imageset/Contents.json (91%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_1x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_2x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_3x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/beaver-mail.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/beaver-mail.imageset/beaver-mail.png (100%) create mode 100644 Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/bluetooth-connected.imageset/Contents.json rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/bluetooth-connected.imageset/bluetooth_connected-24px.pdf (100%) rename {Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/bluetooth_disabled_icon.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/bluetooth_disabled_icon.imageset/bluetooth_disabled_black_108x108.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/bluetooth_icon.imageset}/Contents.json (79%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/bluetooth_icon.imageset/bluetooth_white_108x108.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/checkmark_icon.imageset/Contents.json (71%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/checkmark_icon.imageset/baseline_check_circle_outline_black_18dp.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/chevron.down.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/chevron.down.imageset/chevron.down.pdf (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/chevron.up.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/chevron.up.imageset/chevron.up.pdf (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/chevron_back.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/chevron_back.imageset/chevron_back.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/chevron_back.imageset/chevron_back@2x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/chevron_back.imageset/chevron_back@3x.png (100%) rename {Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/dismiss-modal-icon.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/dismiss-modal-icon.imageset/down.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/dismiss-modal-icon.imageset/down@2x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/dismiss-modal-icon.imageset/down@3x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/edit_pen.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/edit_pen.imageset/edit_pen.svg (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/eye_circle.imageset/Contents.json (85%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/eye_circle.imageset/eye_circle.png (100%) rename {Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-3.imageset => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/gesture-assistant-hand.imageset}/Contents.json (52%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/gesture-assistant-hand.imageset/hand.pdf (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/get_started.imageset/5.pdf (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/get_started.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/gradient_layer.imageset/Contents.json (85%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/gradient_layer.imageset/gradient_layer.png (100%) create mode 100644 Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ic_refresh.imageset/Contents.json rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/ic_refresh.imageset/ic_refresh_24px.pdf (100%) rename {Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-2.imageset => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-active.imageset}/Contents.json (54%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-alert-active.imageset/active.pdf (100%) create mode 100644 Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-off.imageset/Contents.json rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-alert-off.imageset/alert-off.pdf (100%) create mode 100644 Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-on.imageset/Contents.json rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-alert-on.imageset/alert-on.pdf (100%) create mode 100644 Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-bg-camera.imageset/Contents.json rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-bg-camera.imageset/icon-bg-camera-1.pdf (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-bluetooth-connected.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-bluetooth-connected.imageset/icon-bluetooth-connected.pdf (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-bluetooth.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-bluetooth.imageset/icon-bluetooth.pdf (100%) create mode 100644 Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-cards-button.imageset/Contents.json rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-cards-button.imageset/vector.pdf (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-weatherstation.imageset => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-charts-button.imageset}/Contents.json (80%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-charts-button.imageset/vector-3.pdf (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-connectable.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-connectable.imageset/icons8-connected-1.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-connectable.imageset/icons8-connected-2.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-connectable.imageset/icons8-connected.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-connection-1.imageset/Contents.json (86%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-connection-1.imageset/icon-connection-1.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-connection-2.imageset/Contents.json (86%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-connection-2.imageset/icon-connection-2.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-connection-3.imageset/Contents.json (86%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-connection-3.imageset/icon-connection-3.png (100%) create mode 100644 Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-delete-forever.imageset/Contents.json rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-delete-forever.imageset/delete_forever_48px.pdf (100%) create mode 100644 Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-download.imageset/Contents.json rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-download.imageset/download.pdf (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-gateway.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-gateway.imageset/icon-gateway.pdf (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-measure-humidity.imageset/Contents.json (86%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-measure-humidity.imageset/icon-measure-humidity.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-measure-location.imageset/Contents.json (88%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-measure-location.imageset/icon-measure.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-measure-location.imageset/icon-measure@2x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-measure-location.imageset/icon_measure@3x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-measure-movement.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-measure-movement.imageset/icon-measure-movement.pdf (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-measure-pressure.imageset/Contents.json (86%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-measure-pressure.imageset/icon-measure-pressure.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-measure-signal.imageset/Contents.json (86%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-measure-signal.imageset/icon-measure-signal.png (100%) create mode 100644 Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-refresh.imageset/Contents.json rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-refresh.imageset/sync_48px.pdf (100%) create mode 100644 Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-warning.imageset/Contents.json rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon-warning.imageset/warning-sign.pdf (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon_back_arrow.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon_back_arrow.imageset/icons8-back.pdf (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon_sync_bt.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/icon_sync_bt.imageset/icon_sync_bt.png (100%) rename {Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/ruuvi_logo.imageset => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/iphone_icon.imageset}/Contents.json (83%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/iphone_icon.imageset/phone_black.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/location-picker-pin-icon.imageset/Contents.json (91%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/location-picker-pin-icon.imageset/location-picker-pin-icon.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/location-picker-pin-icon.imageset/location-picker-pin-icon@2x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/location-picker-pin-icon.imageset/location-picker-pin-icon@3x.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/measure_data.imageset/1.pdf (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/measure_data.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/more_3dot.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/more_3dot.imageset/more_3dot.pdf (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/no-image.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/no-image.imageset/icons8-no_image.pdf (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/overlay.imageset/Contents.json (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/overlay.imageset/gradient_layer.png (100%) rename {Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-1.imageset => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/plus_icon.imageset}/Contents.json (59%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/plus_icon.imageset/icons8-plus-math-filled-100.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/ruuvi-cloud.imageset/Contents.json (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/ruuvi-cloud.imageset/ruuvi-cloud.pdf (100%) rename Common/{RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets => RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/ruuvi_activity_presenter_logo.imageset/Contents.json (100%) rename Common/{RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets => RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/ruuvi_activity_presenter_logo.imageset/ruuvi_activity_presenter_logo.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/ruuvi_logo.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_logo.imageset}/ruuvi_logo.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/ruuvi_station.imageset/Contents.json (88%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/ruuvi_station.imageset/ruuvi_station.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/ruuvi_station.imageset/ruuvi_station_2x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/ruuvi_station.imageset/ruuvi_station_3x.png (100%) rename {Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/ruuvitag-b8-and-older-button-location.imageset/Contents.json (100%) rename {Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/ruuvitag-b8-and-older-button-location.imageset/ruuvitag-b8-and-older-button-location.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/set_alerts.imageset/3.pdf (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/set_alerts.imageset/Contents.json (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_bg_layer.imageset => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/sign_in_bg_layer.imageset}/Contents.json (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_bg_layer.imageset => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/sign_in_bg_layer.imageset}/bg_layer_dark.jpg (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/small-cross-clear-icon.imageset/Contents.json (91%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/small-cross-clear-icon.imageset/baseline_clear_black_36pt_1x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/small-cross-clear-icon.imageset/baseline_clear_black_36pt_2x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/small-cross-clear-icon.imageset/baseline_clear_black_36pt_3x.png (100%) rename {Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/tag-settings-info-icon.imageset/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/tag-settings-info-icon.imageset/info_icon.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/tag_bg_layer.imageset/Contents.json (85%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/tag_bg_layer.imageset/tag_bg_layer.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/welcome_friend.imageset => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend 1.imageset}/Contents.json (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend 1.imageset}/title-welcome1x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend 1.imageset}/title-welcome2x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend 1.imageset}/title-welcome3x.png (100%) rename {Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/welcome_friend.imageset/Contents.json (88%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/welcome_friend.imageset/title-welcome1x.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/welcome_friend.imageset/title-welcome2x.png (100%) rename {Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets => Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets}/welcome_friend.imageset/title-welcome3x.png (100%) delete mode 100644 Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/bluetooth_disabled_icon.imageset/bluetooth_disabled_black_108x108.png delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/button_tint_color.colorset/Contents.json delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/dismiss-modal-icon.imageset/down.png delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/dismiss-modal-icon.imageset/down@2x.png delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/dismiss-modal-icon.imageset/down@3x.png delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-1.imageset/icon-connection-1.png delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-2.imageset/icon-connection-2.png delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-3.imageset/icon-connection-3.png delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/primary_color.colorset/Contents.json delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/ruuvi_logo.imageset/eye_circle.png delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/ruuvi_menu_text_color.colorset/Contents.json delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/ruuvi_text_color.colorset/Contents.json delete mode 100644 Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/tag-settings-info-icon.imageset/info_icon.png delete mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/Contents.json delete mode 100644 Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift delete mode 100644 Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Assests/RuuviAssets.swift delete mode 100644 Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift delete mode 100644 Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Contents.json delete mode 100644 Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/Contents.json delete mode 100644 Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/ruuvi_logo.imageset/ruuvi_logo.png diff --git a/.swiftgen.assets.yml b/.swiftgen.assets.yml index f38d655cd..70de46091 100644 --- a/.swiftgen.assets.yml +++ b/.swiftgen.assets.yml @@ -16,4 +16,14 @@ strings: params: forceProvidesNamespaces: true publicAccess: true - enumName: RuuviLocalization \ No newline at end of file + enumName: RuuviLocalization + +xcassets: + - inputs: ./Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets + outputs: + - templatePath: ./Common/RuuviLocalization/Templates/xcassets-swift5.stencil + output: ./Common/RuuviLocalization/Sources/RuuviAsset.swift + params: + forceProvidesNamespaces: true + publicAccess: true + enumName: RuuviAsset \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift index d65c60f15..6e121e9f9 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/Presenter/BackgroundSelectionPresenter.swift @@ -155,7 +155,7 @@ extension BackgroundSelectionPresenter { let model = DefaultBackgroundModel( id: i, image: image, - thumbnail: image.resize() + thumbnail: image?.resize() ) defaultImages.append(model) } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift index 67b28d3ec..b3aecb138 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/View/UI/BackgroundSelectionViewController.swift @@ -14,7 +14,7 @@ class BackgroundSelectionViewController: UIViewController { private lazy var backButton: UIButton = { let button = UIButton() button.tintColor = .label - let buttonImage = RuuviAssets.backButtonImage + let buttonImage = RuuviAsset.chevronBack.image button.setImage(buttonImage, for: .normal) button.setImage(buttonImage, for: .highlighted) button.imageView?.tintColor = .label diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift index 02a7e1ca5..9764a1306 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsBackgroundView.swift @@ -1,3 +1,4 @@ +import RuuviLocalization import UIKit class CardsBackgroundView: UIView { @@ -12,7 +13,7 @@ class CardsBackgroundView: UIView { let iv = UIImageView() iv.contentMode = .scaleAspectFill iv.backgroundColor = .clear - iv.image = UIImage(named: "tag_bg_layer") + iv.image = RuuviAsset.tagBgLayer.image return iv }() diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift index c6170474f..03e63bfd9 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsLargeImageCell.swift @@ -24,9 +24,9 @@ class CardsLargeImageCell: UICollectionViewCell { return label }() - private lazy var humidityView = CardsIndicatorView(icon: RuuviAssets.humidityImage) - private lazy var pressureView = CardsIndicatorView(icon: RuuviAssets.pressureImage) - private lazy var movementView = CardsIndicatorView(icon: RuuviAssets.movementCounterImage) + private lazy var humidityView = CardsIndicatorView(icon: RuuviAsset.iconMeasureHumidity.image) + private lazy var pressureView = CardsIndicatorView(icon: RuuviAsset.iconMeasurePressure.image) + private lazy var movementView = CardsIndicatorView(icon: RuuviAsset.iconMeasureMovement.image) private lazy var batteryLevelView = BatteryLevelView(fontSize: 12) @@ -335,15 +335,11 @@ extension CardsLargeImageCell { case .unknown: dataSourceIconView.image = nil case .advertisement: - dataSourceIconView.image = RuuviAssets.advertisementImage - case .heartbeat: - dataSourceIconView.image = RuuviAssets.heartbeatImage - case .log: - dataSourceIconView.image = RuuviAssets.heartbeatImage + dataSourceIconView.image = RuuviAsset.iconBluetooth.image + case .heartbeat, .log: + dataSourceIconView.image = RuuviAsset.iconBluetoothConnected.image case .ruuviNetwork: - dataSourceIconView.image = RuuviAssets.ruuviNetworkImage - case .weatherProvider: - dataSourceIconView.image = RuuviAssets.weatherProviderImage + dataSourceIconView.image = RuuviAsset.iconGateway.image } } else { dataSourceIconView.image = nil diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift index cbf95aaad..95ce9473f 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/View/UI/CardsViewController.swift @@ -62,7 +62,7 @@ class CardsViewController: UIViewController { // Ruuvi Logo private lazy var ruuviLogoView: UIImageView = { let iv = UIImageView( - image: UIImage(named: "ruuvi_logo_"), + image: RuuviAsset.ruuviLogo.image.withRenderingMode(.alwaysTemplate), contentMode: .scaleAspectFit ) iv.tintColor = .white @@ -73,7 +73,7 @@ class CardsViewController: UIViewController { private lazy var backButton: UIButton = { let button = UIButton() button.tintColor = .white - let buttonImage = RuuviAssets.backButtonImage + let buttonImage = RuuviAsset.chevronBack.image button.setImage(buttonImage, for: .normal) button.setImage(buttonImage, for: .highlighted) button.imageView?.tintColor = .white @@ -98,7 +98,7 @@ class CardsViewController: UIViewController { }() private lazy var chartButton: RuuviCustomButton = { - let button = RuuviCustomButton(icon: RuuviAssets.chartsIcon) + let button = RuuviCustomButton(icon: RuuviAsset.iconChartsButton.image) button.backgroundColor = .clear button.addGestureRecognizer( UITapGestureRecognizer( @@ -111,7 +111,7 @@ class CardsViewController: UIViewController { private lazy var settingsButton: RuuviCustomButton = { let button = RuuviCustomButton( - icon: RuuviAssets.settingsIcon, + icon: RuuviAsset.baselineSettingsWhite48pt.image, iconSize: .init(width: 26, height: 25) ) button.backgroundColor = .clear @@ -505,7 +505,7 @@ extension CardsViewController { } func showChart(module: UIViewController) { - chartButton.image = RuuviAssets.cardsIcon + chartButton.image = RuuviAsset.iconCardsButton.image chartViewBackground.alpha = 1 collectionView.isHidden = true module.willMove(toParent: self) @@ -517,7 +517,7 @@ extension CardsViewController { } func dismissChart() { - chartButton.image = RuuviAssets.chartsIcon + chartButton.image = RuuviAsset.iconChartsButton.image chartViewBackground.alpha = 0 children.forEach { $0.willMove(toParent: nil) @@ -791,7 +791,7 @@ extension CardsViewController { ] if mutedTills.first(where: { $0 != nil }) != nil { - alertButton.image = RuuviAssets.alertOffImage + alertButton.image = RuuviAsset.iconAlertOff.image removeAlertAnimations(alpha: 0.5) return } @@ -799,14 +799,14 @@ extension CardsViewController { if let state = currentVisibleItem?.alertState.value { switch state { case .empty: - alertButton.image = RuuviAssets.alertOffImage + alertButton.image = RuuviAsset.iconAlertOff.image removeAlertAnimations(alpha: 0.5) case .registered: - alertButton.image = RuuviAssets.alertOnImage + alertButton.image = RuuviAsset.iconAlertOn.image removeAlertAnimations() case .firing: alertButton.alpha = 1.0 - alertButton.image = RuuviAssets.alertActiveImage + alertButton.image = RuuviAsset.iconAlertActive.image DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { UIView.animate( withDuration: 0.5, diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift index 823bf9de9..83de625fe 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Charts/View/UI/TagChartsViewController.swift @@ -83,7 +83,7 @@ class TagChartsViewController: UIViewController { menu: historyLengthOptions(), titleColor: .white, title: RuuviLocalization.day1, - icon: RuuviAssets.dropDownArrowImage, + icon: RuuviAsset.arrowDropDown.image, iconTintColor: RuuviColor.logoTintColor.color, iconSize: .init(width: 14, height: 14), preccedingIcon: false @@ -93,7 +93,7 @@ class TagChartsViewController: UIViewController { private lazy var moreButton: UIButton = { let button = UIButton() button.tintColor = .white - button.setImage(RuuviAssets.threeDotMoreImage, for: .normal) + button.setImage(RuuviAsset.more3dot.image, for: .normal) button.imageView?.contentMode = .scaleAspectFit button.showsMenuAsPrimaryAction = true button.menu = moreButtonOptions() @@ -137,7 +137,7 @@ class TagChartsViewController: UIViewController { menu: nil, titleColor: .white, title: RuuviLocalization.TagCharts.Sync.title, - icon: UIImage(named: "icon_sync_bt"), + icon: RuuviAsset.iconSyncBt.image, iconTintColor: .white, iconSize: .init(width: 22, height: 22), preccedingIcon: true @@ -738,15 +738,11 @@ extension TagChartsViewController: TagChartsViewInput { case .unknown: dataSourceIconView.image = nil case .advertisement: - dataSourceIconView.image = RuuviAssets.advertisementImage - case .heartbeat: - dataSourceIconView.image = RuuviAssets.heartbeatImage - case .log: - dataSourceIconView.image = RuuviAssets.heartbeatImage + dataSourceIconView.image = RuuviAsset.iconBluetooth.image + case .heartbeat, .log: + dataSourceIconView.image = RuuviAsset.iconBluetoothConnected.image case .ruuviNetwork: - dataSourceIconView.image = RuuviAssets.ruuviNetworkImage - case .weatherProvider: - dataSourceIconView.image = RuuviAssets.weatherProviderImage + dataSourceIconView.image = RuuviAsset.iconGateway.image } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift index f118dda09..316a9ca4f 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardImageCell.swift @@ -41,7 +41,7 @@ class DashboardImageCell: UICollectionViewCell { let iv = UIImageView() iv.contentMode = .scaleAspectFit iv.backgroundColor = .clear - iv.image = RuuviAssets.threeDotMoreImage + iv.image = RuuviAsset.more3dot.image iv.tintColor = RuuviColor.dashboardIndicatorBig.color return iv }() @@ -431,22 +431,18 @@ extension DashboardImageCell { case .unknown: dataSourceIconView.image = nil case .advertisement: - dataSourceIconView.image = RuuviAssets.advertisementImage - case .heartbeat: - dataSourceIconView.image = RuuviAssets.heartbeatImage - case .log: - dataSourceIconView.image = RuuviAssets.heartbeatImage + dataSourceIconView.image = RuuviAsset.iconBluetooth.image + case .heartbeat, .log: + dataSourceIconView.image = RuuviAsset.iconBluetoothConnected.image case .ruuviNetwork: - dataSourceIconView.image = RuuviAssets.ruuviNetworkImage - case .weatherProvider: - dataSourceIconView.image = RuuviAssets.weatherProviderImage + dataSourceIconView.image = RuuviAsset.iconGateway.image } } else { dataSourceIconView.image = nil } switch viewModel.source.value { - case .ruuviNetwork, .weatherProvider: + case .ruuviNetwork: dataSourceIconViewWidthConstraint.constant = dataSourceIconViewRegularWidth default: dataSourceIconViewWidthConstraint.constant = dataSourceIconViewCompactWidth @@ -525,9 +521,9 @@ extension DashboardImageCell { alertButton.isUserInteractionEnabled = false case .registered: alertButton.isUserInteractionEnabled = true - if alertIcon.image != RuuviAssets.alertOnImage { + if alertIcon.image != RuuviAsset.iconAlertOn.image { alertIcon.alpha = 1 - alertIcon.image = RuuviAssets.alertOnImage + alertIcon.image = RuuviAsset.iconAlertOn.image removeAlertAnimations() } alertIcon.tintColor = RuuviColor.logoTintColor.color @@ -535,8 +531,8 @@ extension DashboardImageCell { alertButton.isUserInteractionEnabled = true alertIcon.alpha = 1.0 alertIcon.tintColor = RuuviColor.orangeColor.color - if alertIcon.image != RuuviAssets.alertActiveImage { - alertIcon.image = RuuviAssets.alertActiveImage + if alertIcon.image != RuuviAsset.iconAlertActive.image { + alertIcon.image = RuuviAsset.iconAlertActive.image } DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { UIView.animate( diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift index a909756d5..f9eaba4b8 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardPlainCell.swift @@ -37,7 +37,7 @@ class DashboardPlainCell: UICollectionViewCell { let iv = UIImageView() iv.contentMode = .scaleAspectFit iv.backgroundColor = .clear - iv.image = RuuviAssets.threeDotMoreImage + iv.image = RuuviAsset.more3dot.image iv.tintColor = RuuviColor.dashboardIndicatorBig.color return iv }() @@ -382,22 +382,18 @@ extension DashboardPlainCell { case .unknown: dataSourceIconView.image = nil case .advertisement: - dataSourceIconView.image = RuuviAssets.advertisementImage - case .heartbeat: - dataSourceIconView.image = RuuviAssets.heartbeatImage - case .log: - dataSourceIconView.image = RuuviAssets.heartbeatImage + dataSourceIconView.image = RuuviAsset.iconBluetooth.image + case .heartbeat, .log: + dataSourceIconView.image = RuuviAsset.iconBluetoothConnected.image case .ruuviNetwork: - dataSourceIconView.image = RuuviAssets.ruuviNetworkImage - case .weatherProvider: - dataSourceIconView.image = RuuviAssets.weatherProviderImage + dataSourceIconView.image = RuuviAsset.iconGateway.image } } else { dataSourceIconView.image = nil } switch viewModel.source.value { - case .ruuviNetwork, .weatherProvider: + case .ruuviNetwork: dataSourceIconViewWidthConstraint.constant = dataSourceIconViewRegularWidth default: dataSourceIconViewWidthConstraint.constant = dataSourceIconViewCompactWidth @@ -477,9 +473,9 @@ extension DashboardPlainCell { alertButton.isUserInteractionEnabled = false case .registered: alertButton.isUserInteractionEnabled = true - if alertIcon.image != RuuviAssets.alertOnImage { + if alertIcon.image != RuuviAsset.iconAlertOn.image { alertIcon.alpha = 1 - alertIcon.image = RuuviAssets.alertOnImage + alertIcon.image = RuuviAsset.iconAlertOn.image removeAlertAnimations() } alertIcon.tintColor = RuuviColor.logoTintColor.color @@ -487,8 +483,8 @@ extension DashboardPlainCell { alertButton.isUserInteractionEnabled = true alertIcon.alpha = 1.0 alertIcon.tintColor = RuuviColor.orangeColor.color - if alertIcon.image != RuuviAssets.alertActiveImage { - alertIcon.image = RuuviAssets.alertActiveImage + if alertIcon.image != RuuviAsset.iconAlertActive.image { + alertIcon.image = RuuviAsset.iconAlertActive.image } DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { UIView.animate( diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift index 7f9550c5a..77d33afec 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/View/DashboardViewController.swift @@ -111,7 +111,7 @@ class DashboardViewController: UIViewController { // Ruuvi Logo private lazy var ruuviLogoView: UIImageView = { let iv = UIImageView( - image: UIImage(named: "ruuvi_logo_"), + image: RuuviAsset.ruuviLogo.image.withRenderingMode(.alwaysTemplate), contentMode: .scaleAspectFit ) iv.backgroundColor = .clear @@ -123,7 +123,7 @@ class DashboardViewController: UIViewController { private lazy var menuButton: UIButton = { let button = UIButton() button.tintColor = RuuviColor.menuTintColor.color - let menuImage = UIImage(named: "baseline_menu_white_48pt") + let menuImage = RuuviAsset.baselineMenuWhite48pt.image button.setImage(menuImage, for: .normal) button.setImage(menuImage, for: .highlighted) button.backgroundColor = .clear @@ -140,7 +140,7 @@ class DashboardViewController: UIViewController { menu: viewToggleMenuOptions(), titleColor: RuuviColor.dashboardIndicator.color, title: RuuviLocalization.view, - icon: RuuviAssets.dropDownArrowImage, + icon: RuuviAsset.arrowDropDown.image, iconTintColor: RuuviColor.logoTintColor.color, iconSize: .init(width: 14, height: 14), preccedingIcon: false diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift index 3c13f2b2a..9c7690992 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Share/View/ViewController/ShareViewController.swift @@ -38,7 +38,7 @@ class ShareViewController: UITableViewController { private lazy var backButton: UIButton = { let button = UIButton() button.tintColor = .label - let buttonImage = RuuviAssets.backButtonImage + let buttonImage = RuuviAsset.chevronBack.image button.setImage(buttonImage, for: .normal) button.setImage(buttonImage, for: .highlighted) button.imageView?.tintColor = .label diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift index 107accc9c..0d90f1516 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/Submodules/Sign In Benefits/View/SignInBenefitsViewController.swift @@ -9,7 +9,7 @@ class SignInBenefitsViewController: UIViewController, SignInBenefitsViewInput { // UI Componenets starts private lazy var closeButton: UIBarButtonItem = { let button = UIBarButtonItem( - image: RuuviAssets.closeButtonImage, + image: RuuviAsset.dismissModalIcon.image, style: .plain, target: self, action: #selector(handleCloseButtonTap) @@ -19,7 +19,7 @@ class SignInBenefitsViewController: UIViewController, SignInBenefitsViewInput { }() private lazy var bgLayer: UIImageView = { - let iv = UIImageView(image: RuuviAssets.signInBgLayer) + let iv = UIImageView(image: RuuviAsset.signInBgLayer.image) iv.backgroundColor = .clear return iv }() diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift index 432a46f74..dcc10c51a 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/Helper/SignInVerifyView.swift @@ -124,7 +124,7 @@ extension SignInVerifyView { trailing: beaverContainerView.trailingAnchor ) beaverImageView.constrainHeight(constant: 400) - beaverImageView.image = RuuviAssets.signInBeaver.resize(targetHeight: 400) + beaverImageView.image = RuuviAsset.beaverMail.image.resize(targetHeight: 400) beaverImageView.centerYInSuperview() } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift index bda968102..d258d8eaa 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/SignIn/View/UI/SignInViewController.swift @@ -21,7 +21,7 @@ class SignInViewController: UIViewController { // UI Componenets starts private lazy var backButton: UIBarButtonItem = { let button = UIBarButtonItem( - image: RuuviAssets.backButtonImage, + image: RuuviAsset.chevronBack.image, style: .plain, target: self, action: #selector(handleBackButtonTap) @@ -31,7 +31,7 @@ class SignInViewController: UIViewController { }() private lazy var bgLayer: UIImageView = { - let iv = UIImageView(image: RuuviAssets.signInBgLayer) + let iv = UIImageView(image: RuuviAsset.signInBgLayer.image) iv.backgroundColor = .clear return iv }() diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift index 9036507f8..206bcb2bd 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Force Claim/View/UI/SensorForceClaimViewController.swift @@ -7,7 +7,7 @@ class SensorForceClaimViewController: UIViewController { private lazy var backButton: UIButton = { let button = UIButton() button.tintColor = .label - let buttonImage = RuuviAssets.backButtonImage + let buttonImage = RuuviAsset.chevronBack.image button.setImage(buttonImage, for: .normal) button.setImage(buttonImage, for: .highlighted) button.imageView?.tintColor = .label diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift index a09096e17..b4c11d802 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/OffsetCorrection/View/Apple/OffsetCorrectionAppleViewController.swift @@ -17,7 +17,7 @@ class OffsetCorrectionAppleViewController: UIViewController { private lazy var backButton: UIButton = { let button = UIButton() button.tintColor = .label - let buttonImage = RuuviAssets.backButtonImage + let buttonImage = RuuviAsset.chevronBack.image button.setImage(buttonImage, for: .normal) button.setImage(buttonImage, for: .highlighted) button.imageView?.tintColor = .label diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift index 4379903da..9343da713 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/View/OwnerViewController.swift @@ -39,7 +39,7 @@ final class OwnerViewController: UIViewController { private lazy var backButton: UIButton = { let button = UIButton() button.tintColor = .label - let buttonImage = RuuviAssets.backButtonImage + let buttonImage = RuuviAsset.chevronBack.image button.setImage(buttonImage, for: .normal) button.setImage(buttonImage, for: .highlighted) button.imageView?.tintColor = .label diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift index 35b947ae6..46ebd99e2 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Removal/View/UI/SensorRemovalViewController.swift @@ -7,7 +7,7 @@ class SensorRemovalViewController: UIViewController { private lazy var backButton: UIButton = { let button = UIButton() button.tintColor = .label - let buttonImage = RuuviAssets.backButtonImage + let buttonImage = RuuviAsset.chevronBack.image button.setImage(buttonImage, for: .normal) button.setImage(buttonImage, for: .highlighted) button.imageView?.tintColor = .label diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift index 74dc3dc19..4f3db4b96 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertDetailsCellChildView/RUAlertDetailsCellChildView.swift @@ -22,7 +22,7 @@ class RUAlertDetailsCellChildView: UIView { private lazy var imageView: UIImageView = { let iv = UIImageView() iv.backgroundColor = .clear - iv.image = RuuviAssets.editPenImage + iv.image = RuuviAsset.editPen.image iv.tintColor = RuuviColor.tintColor.color iv.contentMode = .scaleAspectFit return iv diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift index d0095de03..3cb0181aa 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/RUAlertExpandButton/RUAlertExpandButton.swift @@ -15,7 +15,7 @@ class RUAlertExpandButton: UIView { lazy var imageView: UIImageView = { let iv = UIImageView() iv.backgroundColor = .clear - iv.image = UIImage(named: "chevron.down") + iv.image = RuuviAsset.chevronDown.image iv.tintColor = RuuviColor.tintColor.color iv.contentMode = .scaleAspectFit return iv diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift index 081c166c7..4439f9ebb 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsBasicCell.swift @@ -113,7 +113,7 @@ class TagSettingsBasicCell: UITableViewCell { func setAccessory(type: TagSettingsBasicAccessory) { switch type { case .pencil: - iconView.image = RuuviAssets.editPenImage + iconView.image = RuuviAsset.editPen.image iconView.tintColor = RuuviColor.tintColor.color iconHiddenWidthConstraints.forEach { anchor in anchor.isActive = false diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift index 02096b71b..104f06138 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsExpandableSectionHeader.swift @@ -43,7 +43,7 @@ class TagSettingsExpandableSectionHeader: UIView { lazy var arrowView: UIImageView = { let iv = UIImageView() iv.backgroundColor = .clear - iv.image = RuuviAssets.dropDownArrowImage + iv.image = RuuviAsset.arrowDropDown.image iv.tintColor = RuuviColor.tintColor.color iv.contentMode = .scaleAspectFit return iv @@ -249,12 +249,12 @@ extension TagSettingsExpandableSectionHeader { mutedTillLabel.text = AppDateFormatter .shared .shortTimeString(from: date) - alertIcon.image = RuuviAssets.alertOffImage + alertIcon.image = RuuviAsset.iconAlertOff.image alertIcon.tintColor = RuuviColor.logoTintColor.color return } else { mutedTillLabel.isHidden = true - alertIcon.image = isOn ? RuuviAssets.alertOnImage : nil + alertIcon.image = isOn ? RuuviAsset.iconAlertOn.image : nil alertIcon.tintColor = RuuviColor.logoTintColor.color removeAlertAnimations() } @@ -266,13 +266,13 @@ extension TagSettingsExpandableSectionHeader { } switch state { case .registered: - alertIcon.image = RuuviAssets.alertOnImage + alertIcon.image = RuuviAsset.iconAlertOn.image alertIcon.tintColor = RuuviColor.logoTintColor.color removeAlertAnimations() case .firing: alertIcon.alpha = 1.0 alertIcon.tintColor = RuuviColor.orangeColor.color - alertIcon.image = RuuviAssets.alertActiveImage + alertIcon.image = RuuviAsset.iconAlertActive.image DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { UIView.animate( withDuration: 0.5, diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift index 12b186fa4..47246a6e2 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/View/UI/TagSettingsViewController.swift @@ -87,7 +87,7 @@ class TagSettingsViewController: UIViewController { private lazy var backButton: UIButton = { let button = UIButton() button.tintColor = .label - let buttonImage = RuuviAssets.backButtonImage + let buttonImage = RuuviAsset.chevronBack.image button.setImage(buttonImage, for: .normal) button.setImage(buttonImage, for: .highlighted) button.imageView?.tintColor = .label diff --git a/Apps/RuuviStation/Sources/Extensions/UIImage+Extension.swift b/Apps/RuuviStation/Sources/Extensions/UIImage+Extension.swift index 90d491053..eb9c60906 100644 --- a/Apps/RuuviStation/Sources/Extensions/UIImage+Extension.swift +++ b/Apps/RuuviStation/Sources/Extensions/UIImage+Extension.swift @@ -1,12 +1,7 @@ import UIKit -extension UIImage? { +extension UIImage { func resize(targetWidth: CGFloat = 100) -> UIImage? { - guard let self - else { - return nil - } - let aspectRatio = self.size.width / self.size.height let targetHeight = targetWidth / aspectRatio @@ -19,11 +14,6 @@ extension UIImage? { } func resize(targetHeight: CGFloat) -> UIImage? { - guard let self - else { - return nil - } - let scale = targetHeight / self.size.height let newWidth = self.size.width * scale let newSize = CGSize(width: newWidth, height: targetHeight) diff --git a/Apps/RuuviStation/Sources/Resources/Assets/RuuviAssets.swift b/Apps/RuuviStation/Sources/Resources/Assets/RuuviAssets.swift deleted file mode 100644 index f6c43c5dc..000000000 --- a/Apps/RuuviStation/Sources/Resources/Assets/RuuviAssets.swift +++ /dev/null @@ -1,25 +0,0 @@ -import UIKit - -enum RuuviAssets { - static let alertActiveImage = UIImage(named: "icon-alert-active") - static let alertOffImage = UIImage(named: "icon-alert-off") - static let alertOnImage = UIImage(named: "icon-alert-on") - static let backButtonImage = UIImage(named: "chevron_back") - static let closeButtonImage = UIImage(named: "dismiss-modal-icon") - static let threeDotMoreImage = UIImage(named: "more_3dot") - static let cardsIcon = UIImage(named: "icon-cards-button") - static let chartsIcon = UIImage(named: "icon-charts-button") - static let settingsIcon = UIImage(named: "baseline_settings_white_48pt") - static let signInBgLayer = UIImage(named: "sign_in_bg_layer") - static let signInBeaver = UIImage(named: "beaver-mail") - static let advertisementImage = UIImage(named: "icon-bluetooth") - static let heartbeatImage = UIImage(named: "icon-bluetooth-connected") - static let ruuviNetworkImage = UIImage(named: "icon-gateway") - static let weatherProviderImage = UIImage(named: "icon-weatherstation") - static let humidityImage = UIImage(named: "icon-measure-humidity") - static let pressureImage = UIImage(named: "icon-measure-pressure") - static let movementCounterImage = UIImage(named: "icon-measure-movement") - static let locationImage = UIImage(named: "icon-measure-location") - static let editPenImage = UIImage(named: "edit_pen") - static let dropDownArrowImage = UIImage(named: "arrow_drop_down") -} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth-connected.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth-connected.imageset/Contents.json deleted file mode 100644 index b1135ae4a..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth-connected.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "bluetooth_connected-24px.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_disabled_icon.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_disabled_icon.imageset/Contents.json deleted file mode 100644 index 96e4bd452..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_disabled_icon.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "bluetooth_disabled_black_108x108.png" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template" - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_icon.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_icon.imageset/Contents.json deleted file mode 100644 index d8928d8f9..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_icon.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "bluetooth_white_108x108.png" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template" - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/Contents.json deleted file mode 100644 index 01e81da35..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/Contents.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "down.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "down@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "down@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template" - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gesture-assistant-hand.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gesture-assistant-hand.imageset/Contents.json deleted file mode 100644 index c870cfb5a..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gesture-assistant-hand.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "hand.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ic_refresh.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ic_refresh.imageset/Contents.json deleted file mode 100644 index 26378d9c7..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ic_refresh.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "ic_refresh_24px.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-active.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-active.imageset/Contents.json deleted file mode 100644 index 19d49d8fa..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-active.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "active.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-off.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-off.imageset/Contents.json deleted file mode 100644 index 4d275ca60..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-off.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "alert-off.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-on.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-on.imageset/Contents.json deleted file mode 100644 index 3f26168db..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-on.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "alert-on.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bg-camera.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bg-camera.imageset/Contents.json deleted file mode 100644 index 192fff9ee..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bg-camera.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "icon-bg-camera-1.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-cards-button.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-cards-button.imageset/Contents.json deleted file mode 100644 index e8367157d..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-cards-button.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "vector.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-charts-button.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-charts-button.imageset/Contents.json deleted file mode 100644 index 04e081eb9..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-charts-button.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "vector-3.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-delete-forever.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-delete-forever.imageset/Contents.json deleted file mode 100644 index e19e4c702..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-delete-forever.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "delete_forever_48px.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-download.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-download.imageset/Contents.json deleted file mode 100644 index 52ebbcc87..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-download.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "download.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-refresh.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-refresh.imageset/Contents.json deleted file mode 100644 index 92a2b9cde..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-refresh.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "sync_48px.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-warning.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-warning.imageset/Contents.json deleted file mode 100644 index b0c7aa340..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-warning.imageset/Contents.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "warning-sign.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template", - "preserves-vector-representation" : true - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-weatherstation.imageset/icon-weatherstation.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-weatherstation.imageset/icon-weatherstation.pdf deleted file mode 100644 index afb8508b461b974c739b58817718626326914983..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1363 zcmY!laBDSrg$Nf-J3Fq_ zJRm2F%NU_9IZ?roOW(;?LEkUGC^s<&p~wWG$SpIc1Zb4LTTWt0s!M8eeo88rzE5gi zdP##b#)emeEBj;Y|kd`r6}OOHSQ_*{c=+Ly33SA6DL>@9rxWci#w|3BNF?cXnd z{Cl~t{C~b@VMWp|s+o&hX5Ufu4wU3eNmBDHX&anF zkBh9jTWYniB0)xrh-3nJdI$yJZI77Ri)f^jFnHhIE6S5d!P0?GJQ$kJRYHaD!n-`CeG$4EWNzI z{ZZajpSLX0(;Raa9!UA5ylnNcy=fw0<^OZ$G4<4je2jBEAz7oVe0N@(UaEhOr9n^?X>s&ya!h=tQR`WY8gLo|MTLi z?=i<7Zn&Xuc<|n`Fyr9NcW37m^UG~-e_+jcz>;moof|qc(qum79J}zs;>X_^=XdIF zv|Kjf=0b&EbAEeRRZ4FN5HL#K;Qm3X>d1yOxtA+@c1=h)=y&MzgWGGrCd}cveo$bQ zkGuTt8OFbh-#NeW{kpd1^GS2>-f#C_AKw5q_PkR5kD2;~!t&{wVyz-rW_~56T?SWDLzFMu;2`Qdy9ypdXN!4ovt# zsm1xFMaikf3Xpu39GqIB5Umf)iVFH6sTCy(`kuK!g-%e~8A^M`a_PHPl(+|%05cIt ztGlrRC?f{h0Rfl3Z)!?rqEmi_LbL%;(8wH!fEt|h^GZ_lN{SUgxiN@KKe(i*G`S=o zu?Q?^zy)*?h^b%-F$k8yL0o7-fN*&+$hcCVVqk{%&P*v*hz5BuC>D|B&CsO~I8ZP%H8nO>NK=4|83HwdfI=Qz%)$(4F`AfxDW*CD zOAK{}1|}BhdJPQ?fZ+%;ucRn3GbgnOR0alTR;2=6ryrD`U!nl=8!!Mp^V0GaK;J5{pW}zA!X2HQ-WJb@g`x0CF4{qyPW_ diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/iphone_icon.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/iphone_icon.imageset/Contents.json deleted file mode 100644 index 69fea8e45..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/iphone_icon.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "phone_black.png" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template" - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/plus_icon.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/plus_icon.imageset/Contents.json deleted file mode 100644 index 9e4725910..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/plus_icon.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "icons8-plus-math-filled-100.png" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template" - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/Contents.json deleted file mode 100644 index b1c902ce1..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "web-ruuvi-eye-nega.pdf" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template" - } -} \ No newline at end of file diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/web-ruuvi-eye-nega.pdf b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_dark_bg_pdf.imageset/web-ruuvi-eye-nega.pdf deleted file mode 100644 index af34efc705628fdf39e5746a1c81ecbd1d371c30..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1049 zcmY!laBDSrg$Nf-E~sEh zW`3SeW>QgNQKf=LaCT;*KF}0}TyqmmJ3Fq_JfQL{E@OmA$%zVvT>4JF3i^KeMY)MN z2t_6cMQ)inB|yvc-EtC3Qe9G$^HWl}^nFtE(n~TFj7==;>=cSiic%AExhm%PPW0`Q zG303dZpSK~acKWTmd$?a0)o;e$EobxFH-RJjEm~jGwJpf49s7@Klo=Tc<^h?esTE| z4UaxdNaXqax1#y?hv&7m)xj12cdy~v>+oQwi-_&79}a>7g+B8(Hw!0Q3Lf4nrSfL3 zhwBmprS6@tJ~2%`_sMwAwR?Sa>{rW`Lbu2CWz0A=XAX;Hlwrp6xz-n!#IxtEyQT1= z=8VtkJBpRuc2P54T<;QFwuO71*ZI^*D@@PtUy-t)O1$aB5nXd*9&5iF6LRv_FWqvn z!}~z1Ve3+dsexLNvn}(U>#ch?_v4D$NB3RbR^I>8{)uhxZu8goPT5CFn*@B4J2+$K zHSwu8_BMaoCeXMf-N?&BMEaWC zd!?go_}!87DsS}cpx3Hr{&HIgzlx|iYIyicdb+rV~AM-gAJyxq$n{nC$$Kam4h>@Qh~11 p56aIkQ2_Z37=WI6Y55AE><$ciuHur!q7tw#ER4;$R8?L5-2f^jZpr`v diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag-settings-info-icon.imageset/Contents.json b/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag-settings-info-icon.imageset/Contents.json deleted file mode 100644 index 3862c478b..000000000 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag-settings-info-icon.imageset/Contents.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "info_icon.png" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - }, - "properties" : { - "template-rendering-intent" : "template" - } -} \ No newline at end of file diff --git a/Common/RuuviLocalization/.gitignore b/Common/RuuviLocalization/.gitignore index 1eacdd81b..9023d5a67 100644 --- a/Common/RuuviLocalization/.gitignore +++ b/Common/RuuviLocalization/.gitignore @@ -7,4 +7,5 @@ DerivedData/ .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata RuuviLocalization.swift RuuviColor.swift +RuuviAsset.swift Localizable.strings \ No newline at end of file diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Contents.json similarity index 100% rename from Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Contents.json diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/Contents.json similarity index 100% rename from Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/Contents.json diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/gateway.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/gateway.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/gateway.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/gateway.imageset/Contents.json diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/gateway.imageset/gateway.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/gateway.imageset/gateway.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/gateway.imageset/gateway.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/gateway.imageset/gateway.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_alerts.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_alerts.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_alerts.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_alerts.imageset/Contents.json diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_alerts.imageset/ipad-alerts.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_alerts.imageset/ipad-alerts.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_alerts.imageset/ipad-alerts.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_alerts.imageset/ipad-alerts.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_alerts.imageset/onboarding_alerts.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_alerts.imageset/onboarding_alerts.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_alerts.imageset/onboarding_alerts.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_alerts.imageset/onboarding_alerts.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_beaver_sign_in.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_beaver_sign_in.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_beaver_sign_in.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_beaver_sign_in.imageset/Contents.json diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_beaver_sign_in.imageset/beaver-sign.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_beaver_sign_in.imageset/beaver-sign.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_beaver_sign_in.imageset/beaver-sign.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_beaver_sign_in.imageset/beaver-sign.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_beaver_start.imageset/1-beaver-start.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_beaver_start.imageset/1-beaver-start.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_beaver_start.imageset/1-beaver-start.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_beaver_start.imageset/1-beaver-start.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_beaver_start.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_beaver_start.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_beaver_start.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_beaver_start.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/sign_in_bg_layer.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_bg_layer.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/sign_in_bg_layer.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_bg_layer.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/sign_in_bg_layer.imageset/bg_layer_dark.jpg b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_bg_layer.imageset/bg_layer_dark.jpg similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/sign_in_bg_layer.imageset/bg_layer_dark.jpg rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_bg_layer.imageset/bg_layer_dark.jpg diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_dashboard.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_dashboard.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_dashboard.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_dashboard.imageset/Contents.json diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_dashboard.imageset/ipad-dashboard.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_dashboard.imageset/ipad-dashboard.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_dashboard.imageset/ipad-dashboard.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_dashboard.imageset/ipad-dashboard.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_dashboard.imageset/onboarding_dashboard.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_dashboard.imageset/onboarding_dashboard.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_dashboard.imageset/onboarding_dashboard.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_dashboard.imageset/onboarding_dashboard.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_history.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_history.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_history.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_history.imageset/Contents.json diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_history.imageset/ipad-graphs.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_history.imageset/ipad-graphs.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_history.imageset/ipad-graphs.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_history.imageset/ipad-graphs.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_history.imageset/onboarding_history.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_history.imageset/onboarding_history.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_history.imageset/onboarding_history.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_history.imageset/onboarding_history.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_sensors.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_sensors.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_sensors.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_sensors.imageset/Contents.json diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_sensors.imageset/ipad-sensor-view.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_sensors.imageset/ipad-sensor-view.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_sensors.imageset/ipad-sensor-view.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_sensors.imageset/ipad-sensor-view.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_sensors.imageset/onboarding_sensors.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_sensors.imageset/onboarding_sensors.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_sensors.imageset/onboarding_sensors.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_sensors.imageset/onboarding_sensors.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_share.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_share.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_share.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_share.imageset/Contents.json diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_share.imageset/onboarding_share.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_share.imageset/onboarding_share.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_share.imageset/onboarding_share.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_share.imageset/onboarding_share.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_web.imageset/9-web.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_web.imageset/9-web.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_web.imageset/9-web.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_web.imageset/9-web.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_web.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_web.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_web.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_web.imageset/Contents.json diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_widgets.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_widgets.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_widgets.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_widgets.imageset/Contents.json diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_widgets.imageset/ipad-widgets.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_widgets.imageset/ipad-widgets.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_widgets.imageset/ipad-widgets.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_widgets.imageset/ipad-widgets.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_widgets.imageset/onboarding_widgets.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_widgets.imageset/onboarding_widgets.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_widgets.imageset/onboarding_widgets.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/Onboarding/onboarding_widgets.imageset/onboarding_widgets.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/access_data.imageset/2.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/access_data.imageset/2.pdf similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/access_data.imageset/2.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/access_data.imageset/2.pdf diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/access_data.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/access_data.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/access_data.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/access_data.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/arrow_drop_down.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/arrow_drop_down.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/arrow_drop_down.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/arrow_drop_down.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/arrow_drop_down.imageset/arrow_drop_down.svg b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/arrow_drop_down.imageset/arrow_drop_down.svg similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/arrow_drop_down.imageset/arrow_drop_down.svg rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/arrow_drop_down.imageset/arrow_drop_down.svg diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/background.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/background.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/background.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/background.imageset/Contents.json diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/background.imageset/bg9.jpg b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/background.imageset/bg9.jpg similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/background.imageset/bg9.jpg rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/background.imageset/bg9.jpg diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/Contents.json similarity index 91% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/Contents.json index debce19cd..0ea6eb530 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/Contents.json @@ -1,26 +1,26 @@ { "images" : [ { - "idiom" : "universal", "filename" : "baseline_keyboard_backspace_white_48pt_1x.png", + "idiom" : "universal", "scale" : "1x" }, { - "idiom" : "universal", "filename" : "baseline_keyboard_backspace_white_48pt_2x.png", + "idiom" : "universal", "scale" : "2x" }, { - "idiom" : "universal", "filename" : "baseline_keyboard_backspace_white_48pt_3x.png", + "idiom" : "universal", "scale" : "3x" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 }, "properties" : { "template-rendering-intent" : "template" } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_1x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_1x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_1x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_1x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_2x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_2x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_2x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_2x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_3x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_3x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_3x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_keyboard_backspace_white_48pt.imageset/baseline_keyboard_backspace_white_48pt_3x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_menu_white_48pt.imageset/Contents.json similarity index 91% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_menu_white_48pt.imageset/Contents.json index 8782e8045..b4299d0d9 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_menu_white_48pt.imageset/Contents.json @@ -1,26 +1,26 @@ { "images" : [ { - "idiom" : "universal", "filename" : "baseline_menu_white_48pt_1x.png", + "idiom" : "universal", "scale" : "1x" }, { - "idiom" : "universal", "filename" : "baseline_menu_white_48pt_2x.png", + "idiom" : "universal", "scale" : "2x" }, { - "idiom" : "universal", "filename" : "baseline_menu_white_48pt_3x.png", + "idiom" : "universal", "scale" : "3x" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 }, "properties" : { "template-rendering-intent" : "template" } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_1x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_1x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_1x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_1x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_2x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_2x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_2x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_2x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_3x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_3x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_3x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_menu_white_48pt.imageset/baseline_menu_white_48pt_3x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_settings_white_48pt.imageset/Contents.json similarity index 91% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_settings_white_48pt.imageset/Contents.json index bc25e2905..55bd50ccd 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_settings_white_48pt.imageset/Contents.json @@ -1,26 +1,26 @@ { "images" : [ { - "idiom" : "universal", "filename" : "baseline_settings_white_48pt_1x.png", + "idiom" : "universal", "scale" : "1x" }, { - "idiom" : "universal", "filename" : "baseline_settings_white_48pt_2x.png", + "idiom" : "universal", "scale" : "2x" }, { - "idiom" : "universal", "filename" : "baseline_settings_white_48pt_3x.png", + "idiom" : "universal", "scale" : "3x" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 }, "properties" : { "template-rendering-intent" : "template" } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_1x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_1x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_1x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_1x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_2x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_2x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_2x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_2x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_3x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_3x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_3x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/baseline_settings_white_48pt.imageset/baseline_settings_white_48pt_3x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/beaver-mail.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/beaver-mail.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/beaver-mail.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/beaver-mail.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/beaver-mail.imageset/beaver-mail.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/beaver-mail.imageset/beaver-mail.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/beaver-mail.imageset/beaver-mail.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/beaver-mail.imageset/beaver-mail.png diff --git a/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/bluetooth-connected.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/bluetooth-connected.imageset/Contents.json new file mode 100644 index 000000000..c609324bd --- /dev/null +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/bluetooth-connected.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "bluetooth_connected-24px.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth-connected.imageset/bluetooth_connected-24px.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/bluetooth-connected.imageset/bluetooth_connected-24px.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth-connected.imageset/bluetooth_connected-24px.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/bluetooth-connected.imageset/bluetooth_connected-24px.pdf diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/bluetooth_disabled_icon.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/bluetooth_disabled_icon.imageset/Contents.json similarity index 100% rename from Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/bluetooth_disabled_icon.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/bluetooth_disabled_icon.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_disabled_icon.imageset/bluetooth_disabled_black_108x108.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/bluetooth_disabled_icon.imageset/bluetooth_disabled_black_108x108.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_disabled_icon.imageset/bluetooth_disabled_black_108x108.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/bluetooth_disabled_icon.imageset/bluetooth_disabled_black_108x108.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/bluetooth_icon.imageset/Contents.json similarity index 79% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/bluetooth_icon.imageset/Contents.json index 4edd31560..a219e0705 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/bluetooth_icon.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "ruuvi_logo.png", + "filename" : "bluetooth_white_108x108.png", "idiom" : "universal" } ], diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_icon.imageset/bluetooth_white_108x108.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/bluetooth_icon.imageset/bluetooth_white_108x108.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/bluetooth_icon.imageset/bluetooth_white_108x108.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/bluetooth_icon.imageset/bluetooth_white_108x108.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/checkmark_icon.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/checkmark_icon.imageset/Contents.json similarity index 71% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/checkmark_icon.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/checkmark_icon.imageset/Contents.json index af502fb3d..106dbd855 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/checkmark_icon.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/checkmark_icon.imageset/Contents.json @@ -1,15 +1,15 @@ { "images" : [ { - "idiom" : "universal", - "filename" : "baseline_check_circle_outline_black_18dp.png" + "filename" : "baseline_check_circle_outline_black_18dp.png", + "idiom" : "universal" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 }, "properties" : { "template-rendering-intent" : "template" } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/checkmark_icon.imageset/baseline_check_circle_outline_black_18dp.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/checkmark_icon.imageset/baseline_check_circle_outline_black_18dp.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/checkmark_icon.imageset/baseline_check_circle_outline_black_18dp.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/checkmark_icon.imageset/baseline_check_circle_outline_black_18dp.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron.down.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/chevron.down.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron.down.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/chevron.down.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron.down.imageset/chevron.down.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/chevron.down.imageset/chevron.down.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron.down.imageset/chevron.down.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/chevron.down.imageset/chevron.down.pdf diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron.up.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/chevron.up.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron.up.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/chevron.up.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron.up.imageset/chevron.up.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/chevron.up.imageset/chevron.up.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron.up.imageset/chevron.up.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/chevron.up.imageset/chevron.up.pdf diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron_back.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/chevron_back.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron_back.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/chevron_back.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/chevron_back.imageset/chevron_back.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/chevron_back.imageset/chevron_back.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back@2x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/chevron_back.imageset/chevron_back@2x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back@2x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/chevron_back.imageset/chevron_back@2x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back@3x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/chevron_back.imageset/chevron_back@3x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/chevron_back.imageset/chevron_back@3x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/chevron_back.imageset/chevron_back@3x.png diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/dismiss-modal-icon.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/dismiss-modal-icon.imageset/Contents.json similarity index 100% rename from Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/dismiss-modal-icon.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/dismiss-modal-icon.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/dismiss-modal-icon.imageset/down.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/dismiss-modal-icon.imageset/down.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down@2x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/dismiss-modal-icon.imageset/down@2x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down@2x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/dismiss-modal-icon.imageset/down@2x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down@3x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/dismiss-modal-icon.imageset/down@3x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/dismiss-modal-icon.imageset/down@3x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/dismiss-modal-icon.imageset/down@3x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/edit_pen.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/edit_pen.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/edit_pen.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/edit_pen.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/edit_pen.imageset/edit_pen.svg b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/edit_pen.imageset/edit_pen.svg similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/edit_pen.imageset/edit_pen.svg rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/edit_pen.imageset/edit_pen.svg diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/eye_circle.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/eye_circle.imageset/Contents.json similarity index 85% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/eye_circle.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/eye_circle.imageset/Contents.json index 01d9fafc8..aee9f7fb6 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/eye_circle.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/eye_circle.imageset/Contents.json @@ -1,8 +1,8 @@ { "images" : [ { - "idiom" : "universal", "filename" : "eye_circle.png", + "idiom" : "universal", "scale" : "1x" }, { @@ -15,7 +15,7 @@ } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/eye_circle.imageset/eye_circle.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/eye_circle.imageset/eye_circle.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/eye_circle.imageset/eye_circle.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/eye_circle.imageset/eye_circle.png diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-3.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/gesture-assistant-hand.imageset/Contents.json similarity index 52% rename from Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-3.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/gesture-assistant-hand.imageset/Contents.json index 8357c714b..0190d881f 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-3.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/gesture-assistant-hand.imageset/Contents.json @@ -1,15 +1,12 @@ { "images" : [ { - "filename" : "icon-connection-3.png", + "filename" : "hand.pdf", "idiom" : "universal" } ], "info" : { "author" : "xcode", "version" : 1 - }, - "properties" : { - "template-rendering-intent" : "original" } } diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gesture-assistant-hand.imageset/hand.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/gesture-assistant-hand.imageset/hand.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gesture-assistant-hand.imageset/hand.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/gesture-assistant-hand.imageset/hand.pdf diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/get_started.imageset/5.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/get_started.imageset/5.pdf similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/get_started.imageset/5.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/get_started.imageset/5.pdf diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/get_started.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/get_started.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/get_started.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/get_started.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gradient_layer.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/gradient_layer.imageset/Contents.json similarity index 85% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gradient_layer.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/gradient_layer.imageset/Contents.json index 550ba1fec..c5af5b18a 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gradient_layer.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/gradient_layer.imageset/Contents.json @@ -1,8 +1,8 @@ { "images" : [ { - "idiom" : "universal", "filename" : "gradient_layer.png", + "idiom" : "universal", "scale" : "1x" }, { @@ -15,7 +15,7 @@ } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gradient_layer.imageset/gradient_layer.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/gradient_layer.imageset/gradient_layer.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/gradient_layer.imageset/gradient_layer.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/gradient_layer.imageset/gradient_layer.png diff --git a/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ic_refresh.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ic_refresh.imageset/Contents.json new file mode 100644 index 000000000..3f90d2376 --- /dev/null +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ic_refresh.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "ic_refresh_24px.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ic_refresh.imageset/ic_refresh_24px.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ic_refresh.imageset/ic_refresh_24px.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ic_refresh.imageset/ic_refresh_24px.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ic_refresh.imageset/ic_refresh_24px.pdf diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-2.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-active.imageset/Contents.json similarity index 54% rename from Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-2.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-active.imageset/Contents.json index 6369423d6..14e6d538d 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-2.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-active.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "icon-connection-2.png", + "filename" : "active.pdf", "idiom" : "universal" } ], @@ -10,6 +10,7 @@ "version" : 1 }, "properties" : { - "template-rendering-intent" : "original" + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" } } diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-active.imageset/active.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-active.imageset/active.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-active.imageset/active.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-active.imageset/active.pdf diff --git a/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-off.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-off.imageset/Contents.json new file mode 100644 index 000000000..6f2b161b2 --- /dev/null +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-off.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "alert-off.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-off.imageset/alert-off.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-off.imageset/alert-off.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-off.imageset/alert-off.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-off.imageset/alert-off.pdf diff --git a/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-on.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-on.imageset/Contents.json new file mode 100644 index 000000000..48806fbfb --- /dev/null +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-on.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "alert-on.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-on.imageset/alert-on.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-on.imageset/alert-on.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-alert-on.imageset/alert-on.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-alert-on.imageset/alert-on.pdf diff --git a/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-bg-camera.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-bg-camera.imageset/Contents.json new file mode 100644 index 000000000..873c33517 --- /dev/null +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-bg-camera.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "icon-bg-camera-1.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bg-camera.imageset/icon-bg-camera-1.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-bg-camera.imageset/icon-bg-camera-1.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bg-camera.imageset/icon-bg-camera-1.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-bg-camera.imageset/icon-bg-camera-1.pdf diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bluetooth-connected.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-bluetooth-connected.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bluetooth-connected.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-bluetooth-connected.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bluetooth-connected.imageset/icon-bluetooth-connected.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-bluetooth-connected.imageset/icon-bluetooth-connected.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bluetooth-connected.imageset/icon-bluetooth-connected.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-bluetooth-connected.imageset/icon-bluetooth-connected.pdf diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bluetooth.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-bluetooth.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bluetooth.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-bluetooth.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bluetooth.imageset/icon-bluetooth.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-bluetooth.imageset/icon-bluetooth.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-bluetooth.imageset/icon-bluetooth.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-bluetooth.imageset/icon-bluetooth.pdf diff --git a/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-cards-button.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-cards-button.imageset/Contents.json new file mode 100644 index 000000000..29264701b --- /dev/null +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-cards-button.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "vector.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-cards-button.imageset/vector.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-cards-button.imageset/vector.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-cards-button.imageset/vector.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-cards-button.imageset/vector.pdf diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-weatherstation.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-charts-button.imageset/Contents.json similarity index 80% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-weatherstation.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-charts-button.imageset/Contents.json index 3290199a1..a3651f11d 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-weatherstation.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-charts-button.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "icon-weatherstation.pdf", + "filename" : "vector-3.pdf", "idiom" : "universal" } ], diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-charts-button.imageset/vector-3.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-charts-button.imageset/vector-3.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-charts-button.imageset/vector-3.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-charts-button.imageset/vector-3.pdf diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connectable.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connectable.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connectable.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connectable.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected-1.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connectable.imageset/icons8-connected-1.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected-1.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connectable.imageset/icons8-connected-1.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected-2.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connectable.imageset/icons8-connected-2.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected-2.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connectable.imageset/icons8-connected-2.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connectable.imageset/icons8-connected.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connectable.imageset/icons8-connected.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connectable.imageset/icons8-connected.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-1.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connection-1.imageset/Contents.json similarity index 86% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-1.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connection-1.imageset/Contents.json index b79388d8b..31dd310f8 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-1.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connection-1.imageset/Contents.json @@ -1,8 +1,8 @@ { "images" : [ { - "idiom" : "universal", "filename" : "icon-connection-1.png", + "idiom" : "universal", "scale" : "1x" }, { @@ -15,7 +15,7 @@ } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-1.imageset/icon-connection-1.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connection-1.imageset/icon-connection-1.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-1.imageset/icon-connection-1.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connection-1.imageset/icon-connection-1.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-2.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connection-2.imageset/Contents.json similarity index 86% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-2.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connection-2.imageset/Contents.json index 27a1c3277..ec226131b 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-2.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connection-2.imageset/Contents.json @@ -1,8 +1,8 @@ { "images" : [ { - "idiom" : "universal", "filename" : "icon-connection-2.png", + "idiom" : "universal", "scale" : "1x" }, { @@ -15,7 +15,7 @@ } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-2.imageset/icon-connection-2.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connection-2.imageset/icon-connection-2.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-2.imageset/icon-connection-2.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connection-2.imageset/icon-connection-2.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-3.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connection-3.imageset/Contents.json similarity index 86% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-3.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connection-3.imageset/Contents.json index 42a2ec408..d6074cb5a 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-3.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connection-3.imageset/Contents.json @@ -1,8 +1,8 @@ { "images" : [ { - "idiom" : "universal", "filename" : "icon-connection-3.png", + "idiom" : "universal", "scale" : "1x" }, { @@ -15,7 +15,7 @@ } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-3.imageset/icon-connection-3.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connection-3.imageset/icon-connection-3.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-connection-3.imageset/icon-connection-3.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-connection-3.imageset/icon-connection-3.png diff --git a/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-delete-forever.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-delete-forever.imageset/Contents.json new file mode 100644 index 000000000..956b1c03e --- /dev/null +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-delete-forever.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "delete_forever_48px.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-delete-forever.imageset/delete_forever_48px.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-delete-forever.imageset/delete_forever_48px.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-delete-forever.imageset/delete_forever_48px.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-delete-forever.imageset/delete_forever_48px.pdf diff --git a/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-download.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-download.imageset/Contents.json new file mode 100644 index 000000000..f3d0e714d --- /dev/null +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-download.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "download.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-download.imageset/download.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-download.imageset/download.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-download.imageset/download.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-download.imageset/download.pdf diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-gateway.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-gateway.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-gateway.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-gateway.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-gateway.imageset/icon-gateway.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-gateway.imageset/icon-gateway.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-gateway.imageset/icon-gateway.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-gateway.imageset/icon-gateway.pdf diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-humidity.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-humidity.imageset/Contents.json similarity index 86% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-humidity.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-humidity.imageset/Contents.json index 93a66882d..da8228fa3 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-humidity.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-humidity.imageset/Contents.json @@ -1,8 +1,8 @@ { "images" : [ { - "idiom" : "universal", "filename" : "icon-measure-humidity.png", + "idiom" : "universal", "scale" : "1x" }, { @@ -15,7 +15,7 @@ } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-humidity.imageset/icon-measure-humidity.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-humidity.imageset/icon-measure-humidity.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-humidity.imageset/icon-measure-humidity.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-humidity.imageset/icon-measure-humidity.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-location.imageset/Contents.json similarity index 88% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-location.imageset/Contents.json index e93d455cf..7ec77ffc1 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-location.imageset/Contents.json @@ -1,23 +1,23 @@ { "images" : [ { - "idiom" : "universal", "filename" : "icon-measure.png", + "idiom" : "universal", "scale" : "1x" }, { - "idiom" : "universal", "filename" : "icon-measure@2x.png", + "idiom" : "universal", "scale" : "2x" }, { - "idiom" : "universal", "filename" : "icon_measure@3x.png", + "idiom" : "universal", "scale" : "3x" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon-measure.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-location.imageset/icon-measure.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon-measure.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-location.imageset/icon-measure.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon-measure@2x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-location.imageset/icon-measure@2x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon-measure@2x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-location.imageset/icon-measure@2x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon_measure@3x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-location.imageset/icon_measure@3x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-location.imageset/icon_measure@3x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-location.imageset/icon_measure@3x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-movement.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-movement.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-movement.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-movement.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-movement.imageset/icon-measure-movement.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-movement.imageset/icon-measure-movement.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-movement.imageset/icon-measure-movement.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-movement.imageset/icon-measure-movement.pdf diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-pressure.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-pressure.imageset/Contents.json similarity index 86% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-pressure.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-pressure.imageset/Contents.json index a25de334a..783379bcc 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-pressure.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-pressure.imageset/Contents.json @@ -1,8 +1,8 @@ { "images" : [ { - "idiom" : "universal", "filename" : "icon-measure-pressure.png", + "idiom" : "universal", "scale" : "1x" }, { @@ -15,7 +15,7 @@ } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-pressure.imageset/icon-measure-pressure.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-pressure.imageset/icon-measure-pressure.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-pressure.imageset/icon-measure-pressure.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-pressure.imageset/icon-measure-pressure.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-signal.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-signal.imageset/Contents.json similarity index 86% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-signal.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-signal.imageset/Contents.json index b9447119b..ec24fc4af 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-signal.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-signal.imageset/Contents.json @@ -1,8 +1,8 @@ { "images" : [ { - "idiom" : "universal", "filename" : "icon-measure-signal.png", + "idiom" : "universal", "scale" : "1x" }, { @@ -15,7 +15,7 @@ } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-signal.imageset/icon-measure-signal.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-signal.imageset/icon-measure-signal.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-measure-signal.imageset/icon-measure-signal.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-measure-signal.imageset/icon-measure-signal.png diff --git a/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-refresh.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-refresh.imageset/Contents.json new file mode 100644 index 000000000..10ae94513 --- /dev/null +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-refresh.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "sync_48px.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-refresh.imageset/sync_48px.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-refresh.imageset/sync_48px.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-refresh.imageset/sync_48px.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-refresh.imageset/sync_48px.pdf diff --git a/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-warning.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-warning.imageset/Contents.json new file mode 100644 index 000000000..dc30cd046 --- /dev/null +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-warning.imageset/Contents.json @@ -0,0 +1,16 @@ +{ + "images" : [ + { + "filename" : "warning-sign.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true, + "template-rendering-intent" : "template" + } +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-warning.imageset/warning-sign.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-warning.imageset/warning-sign.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon-warning.imageset/warning-sign.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon-warning.imageset/warning-sign.pdf diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon_back_arrow.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon_back_arrow.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon_back_arrow.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon_back_arrow.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon_back_arrow.imageset/icons8-back.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon_back_arrow.imageset/icons8-back.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon_back_arrow.imageset/icons8-back.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon_back_arrow.imageset/icons8-back.pdf diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon_sync_bt.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon_sync_bt.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon_sync_bt.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon_sync_bt.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon_sync_bt.imageset/icon_sync_bt.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon_sync_bt.imageset/icon_sync_bt.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/icon_sync_bt.imageset/icon_sync_bt.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/icon_sync_bt.imageset/icon_sync_bt.png diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/ruuvi_logo.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/iphone_icon.imageset/Contents.json similarity index 83% rename from Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/ruuvi_logo.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/iphone_icon.imageset/Contents.json index 18b253d0a..72f32cfd7 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/ruuvi_logo.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/iphone_icon.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "eye_circle.png", + "filename" : "phone_black.png", "idiom" : "universal" } ], diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/iphone_icon.imageset/phone_black.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/iphone_icon.imageset/phone_black.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/iphone_icon.imageset/phone_black.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/iphone_icon.imageset/phone_black.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/location-picker-pin-icon.imageset/Contents.json similarity index 91% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/location-picker-pin-icon.imageset/Contents.json index 3bf06cae6..1c1f0e55a 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/location-picker-pin-icon.imageset/Contents.json @@ -1,26 +1,26 @@ { "images" : [ { - "idiom" : "universal", "filename" : "location-picker-pin-icon.png", + "idiom" : "universal", "scale" : "1x" }, { - "idiom" : "universal", "filename" : "location-picker-pin-icon@2x.png", + "idiom" : "universal", "scale" : "2x" }, { - "idiom" : "universal", "filename" : "location-picker-pin-icon@3x.png", + "idiom" : "universal", "scale" : "3x" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 }, "properties" : { "template-rendering-intent" : "template" } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@2x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@2x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@2x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@2x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@3x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@3x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@3x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/location-picker-pin-icon.imageset/location-picker-pin-icon@3x.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/measure_data.imageset/1.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/measure_data.imageset/1.pdf similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/measure_data.imageset/1.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/measure_data.imageset/1.pdf diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/measure_data.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/measure_data.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/measure_data.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/measure_data.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/more_3dot.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/more_3dot.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/more_3dot.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/more_3dot.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/more_3dot.imageset/more_3dot.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/more_3dot.imageset/more_3dot.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/more_3dot.imageset/more_3dot.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/more_3dot.imageset/more_3dot.pdf diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/no-image.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/no-image.imageset/Contents.json similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/no-image.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/no-image.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/no-image.imageset/icons8-no_image.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/no-image.imageset/icons8-no_image.pdf similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/no-image.imageset/icons8-no_image.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/no-image.imageset/icons8-no_image.pdf diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/overlay.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/overlay.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/overlay.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/overlay.imageset/Contents.json diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/overlay.imageset/gradient_layer.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/overlay.imageset/gradient_layer.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/overlay.imageset/gradient_layer.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/overlay.imageset/gradient_layer.png diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-1.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/plus_icon.imageset/Contents.json similarity index 59% rename from Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-1.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/plus_icon.imageset/Contents.json index d249c68dc..4975e3b31 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-1.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/plus_icon.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "icon-connection-1.png", + "filename" : "icons8-plus-math-filled-100.png", "idiom" : "universal" } ], @@ -10,6 +10,6 @@ "version" : 1 }, "properties" : { - "template-rendering-intent" : "original" + "template-rendering-intent" : "template" } } diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/plus_icon.imageset/icons8-plus-math-filled-100.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/plus_icon.imageset/icons8-plus-math-filled-100.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/plus_icon.imageset/icons8-plus-math-filled-100.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/plus_icon.imageset/icons8-plus-math-filled-100.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/ruuvi-cloud.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi-cloud.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/ruuvi-cloud.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi-cloud.imageset/Contents.json diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/ruuvi-cloud.imageset/ruuvi-cloud.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi-cloud.imageset/ruuvi-cloud.pdf similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/ruuvi-cloud.imageset/ruuvi-cloud.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi-cloud.imageset/ruuvi-cloud.pdf diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/ruuvi_activity_presenter_logo.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_activity_presenter_logo.imageset/Contents.json similarity index 100% rename from Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/ruuvi_activity_presenter_logo.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_activity_presenter_logo.imageset/Contents.json diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/ruuvi_activity_presenter_logo.imageset/ruuvi_activity_presenter_logo.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_activity_presenter_logo.imageset/ruuvi_activity_presenter_logo.png similarity index 100% rename from Common/RuuviPresenters/Sources/RuuviPresenters/Resources/RuuviPresenters.xcassets/ruuvi_activity_presenter_logo.imageset/ruuvi_activity_presenter_logo.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_activity_presenter_logo.imageset/ruuvi_activity_presenter_logo.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/ruuvi_logo.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_logo.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/ruuvi_logo.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_logo.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset/ruuvi_logo.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_logo.imageset/ruuvi_logo.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_logo_.imageset/ruuvi_logo.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_logo.imageset/ruuvi_logo.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_station.imageset/Contents.json similarity index 88% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_station.imageset/Contents.json index bc11e12d5..59c888b80 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_station.imageset/Contents.json @@ -1,23 +1,23 @@ { "images" : [ { - "idiom" : "universal", "filename" : "ruuvi_station.png", + "idiom" : "universal", "scale" : "1x" }, { - "idiom" : "universal", "filename" : "ruuvi_station_2x.png", + "idiom" : "universal", "scale" : "2x" }, { - "idiom" : "universal", "filename" : "ruuvi_station_3x.png", + "idiom" : "universal", "scale" : "3x" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_station.imageset/ruuvi_station.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_station.imageset/ruuvi_station.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station_2x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_station.imageset/ruuvi_station_2x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station_2x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_station.imageset/ruuvi_station_2x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station_3x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_station.imageset/ruuvi_station_3x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/ruuvi_station.imageset/ruuvi_station_3x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvi_station.imageset/ruuvi_station_3x.png diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/ruuvitag-b8-and-older-button-location.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvitag-b8-and-older-button-location.imageset/Contents.json similarity index 100% rename from Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/ruuvitag-b8-and-older-button-location.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvitag-b8-and-older-button-location.imageset/Contents.json diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/ruuvitag-b8-and-older-button-location.imageset/ruuvitag-b8-and-older-button-location.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvitag-b8-and-older-button-location.imageset/ruuvitag-b8-and-older-button-location.png similarity index 100% rename from Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/ruuvitag-b8-and-older-button-location.imageset/ruuvitag-b8-and-older-button-location.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/ruuvitag-b8-and-older-button-location.imageset/ruuvitag-b8-and-older-button-location.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/set_alerts.imageset/3.pdf b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/set_alerts.imageset/3.pdf similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/set_alerts.imageset/3.pdf rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/set_alerts.imageset/3.pdf diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/set_alerts.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/set_alerts.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/set_alerts.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/set_alerts.imageset/Contents.json diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_bg_layer.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/sign_in_bg_layer.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_bg_layer.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/sign_in_bg_layer.imageset/Contents.json diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_bg_layer.imageset/bg_layer_dark.jpg b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/sign_in_bg_layer.imageset/bg_layer_dark.jpg similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/onboarding_bg_layer.imageset/bg_layer_dark.jpg rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/sign_in_bg_layer.imageset/bg_layer_dark.jpg diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/small-cross-clear-icon.imageset/Contents.json similarity index 91% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/small-cross-clear-icon.imageset/Contents.json index 815c9f195..403789449 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/small-cross-clear-icon.imageset/Contents.json @@ -1,26 +1,26 @@ { "images" : [ { - "idiom" : "universal", "filename" : "baseline_clear_black_36pt_1x.png", + "idiom" : "universal", "scale" : "1x" }, { - "idiom" : "universal", "filename" : "baseline_clear_black_36pt_2x.png", + "idiom" : "universal", "scale" : "2x" }, { - "idiom" : "universal", "filename" : "baseline_clear_black_36pt_3x.png", + "idiom" : "universal", "scale" : "3x" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 }, "properties" : { "template-rendering-intent" : "template" } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_1x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_1x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_1x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_1x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_2x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_2x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_2x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_2x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_3x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_3x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_3x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/small-cross-clear-icon.imageset/baseline_clear_black_36pt_3x.png diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/tag-settings-info-icon.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/tag-settings-info-icon.imageset/Contents.json similarity index 100% rename from Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/tag-settings-info-icon.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/tag-settings-info-icon.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag-settings-info-icon.imageset/info_icon.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/tag-settings-info-icon.imageset/info_icon.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag-settings-info-icon.imageset/info_icon.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/tag-settings-info-icon.imageset/info_icon.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag_bg_layer.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/tag_bg_layer.imageset/Contents.json similarity index 85% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag_bg_layer.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/tag_bg_layer.imageset/Contents.json index 844ad8fc4..2dbebe0aa 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag_bg_layer.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/tag_bg_layer.imageset/Contents.json @@ -1,8 +1,8 @@ { "images" : [ { - "idiom" : "universal", "filename" : "tag_bg_layer.png", + "idiom" : "universal", "scale" : "1x" }, { @@ -15,7 +15,7 @@ } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag_bg_layer.imageset/tag_bg_layer.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/tag_bg_layer.imageset/tag_bg_layer.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/tag_bg_layer.imageset/tag_bg_layer.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/tag_bg_layer.imageset/tag_bg_layer.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/welcome_friend.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend 1.imageset/Contents.json similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/welcome_friend.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend 1.imageset/Contents.json diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome1x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend 1.imageset/title-welcome1x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome1x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend 1.imageset/title-welcome1x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome2x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend 1.imageset/title-welcome2x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome2x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend 1.imageset/title-welcome2x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome3x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend 1.imageset/title-welcome3x.png similarity index 100% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/title-welcome3x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend 1.imageset/title-welcome3x.png diff --git a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/Contents.json b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend.imageset/Contents.json similarity index 88% rename from Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/Contents.json rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend.imageset/Contents.json index 0d05d631f..802d0a624 100644 --- a/Apps/RuuviStation/Sources/Resources/Images/Assets.xcassets/welcome_friend.imageset/Contents.json +++ b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend.imageset/Contents.json @@ -1,23 +1,23 @@ { "images" : [ { - "idiom" : "universal", "filename" : "title-welcome1x.png", + "idiom" : "universal", "scale" : "1x" }, { - "idiom" : "universal", "filename" : "title-welcome2x.png", + "idiom" : "universal", "scale" : "2x" }, { - "idiom" : "universal", "filename" : "title-welcome3x.png", + "idiom" : "universal", "scale" : "3x" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/welcome_friend.imageset/title-welcome1x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend.imageset/title-welcome1x.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/welcome_friend.imageset/title-welcome1x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend.imageset/title-welcome1x.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/welcome_friend.imageset/title-welcome2x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend.imageset/title-welcome2x.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/welcome_friend.imageset/title-welcome2x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend.imageset/title-welcome2x.png diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/welcome_friend.imageset/title-welcome3x.png b/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend.imageset/title-welcome3x.png similarity index 100% rename from Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/welcome_friend.imageset/title-welcome3x.png rename to Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets/welcome_friend.imageset/title-welcome3x.png diff --git a/Common/RuuviLocalization/target.yml b/Common/RuuviLocalization/target.yml index e7de8eaa4..f86babc82 100644 --- a/Common/RuuviLocalization/target.yml +++ b/Common/RuuviLocalization/target.yml @@ -14,12 +14,15 @@ targets: optional: true - path: Sources/RuuviColor.swift optional: true + - path: Sources/RuuviAsset.swift + optional: true preBuildScripts: - path: ../../scripts/build/generate_resources.sh name: Generate Resources inputFiles: - $(SRCROOT)/station.localization/station.localization.json - $(SRCROOT)/Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets + - $(SRCROOT)/Common/RuuviLocalization/Sources/Resources/RuuviAssets.xcassets - $(SRCROOT)/Common/RuuviLocalization/Templates/strings-swift5.stencil - $(SRCROOT)/Common/RuuviLocalization/Templates/xcassets-swift5.stencil outputFiles: @@ -30,4 +33,5 @@ targets: - $(SRCROOT)/Common/RuuviLocalization/Sources/Resources/fr.lproj/Localizable.strings - $(SRCROOT)/Common/RuuviLocalization/Sources/Resources/de.lproj/Localizable.strings - $(SRCROOT)/Common/RuuviLocalization/Sources/RuuviLocalization.swift - - $(SRCROOT)/Common/RuuviLocalization/Sources/RuuviColor.swift \ No newline at end of file + - $(SRCROOT)/Common/RuuviLocalization/Sources/RuuviColor.swift + - $(SRCROOT)/Common/RuuviLocalization/Sources/RuuviAsset.swift \ No newline at end of file diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift index 16df14e25..9c4eb7e29 100644 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift +++ b/Common/RuuviPresenters/Sources/RuuviPresenters/Activity/RuuviLogo/View/ActivityPresenterView.swift @@ -62,10 +62,7 @@ struct ActivityPresenterContentView: View { private var contentImage: Image? { switch state { case .loading: - Image( - ActivityPresenterAssets.activityLogoRuuvi, - bundle: .pod(ActivityPresenterViewProvider.self) - ) + RuuviAsset.ruuviActivityPresenterLogo.swiftUIImage case .success: Image(systemName: "checkmark") case .failed: diff --git a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift b/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift deleted file mode 100644 index d0385bb30..000000000 --- a/Common/RuuviPresenters/Sources/RuuviPresenters/Util/RuuviBundleUtils.swift +++ /dev/null @@ -1,60 +0,0 @@ -import Foundation -import UIKit - -public extension Bundle { - static func pod(_ clazz: AnyClass) -> Bundle { - if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { - if let bundleURL = Bundle( - for: clazz - ).resourceURL?.appendingPathComponent( - "\(module).bundle" - ), let bundle = Bundle( - url: bundleURL - ) { - return bundle - } else if let bundleURL = Bundle(for: clazz).resourceURL, let bundle = Bundle(url: bundleURL) { - return bundle - } else { - assertionFailure() - return Bundle.main - } - } else { - assertionFailure() - return Bundle.main - } - } -} - -public extension UIImage { - static func named(_ name: String, for clazz: AnyClass) -> UIImage? { - #if SWIFT_PACKAGE - return UIImage(named: name, in: Bundle.module, compatibleWith: nil) - #else - return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) - #endif - } -} - -public extension UIStoryboard { - static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { - let bundle: Bundle - #if SWIFT_PACKAGE - bundle = Bundle.module - #else - bundle = Bundle.pod(clazz) - #endif - return UIStoryboard(name: name, bundle: bundle) - } -} - -public extension UINib { - static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { - let bundle: Bundle - #if SWIFT_PACKAGE - bundle = Bundle.module - #else - bundle = Bundle.pod(clazz) - #endif - return UINib(nibName: nibName, bundle: bundle) - } -} diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/bluetooth_disabled_icon.imageset/bluetooth_disabled_black_108x108.png b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/bluetooth_disabled_icon.imageset/bluetooth_disabled_black_108x108.png deleted file mode 100644 index 3b9d16e565b704eb3e5015ba64ba145122dc0ef9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2319 zcmbVO4Nwzj8cvKq<*%NNq8BT!t5Pi_*(94l7NTN;f+k>- z+Mxo|Sc8B;w+m2{UL25%6hce_%Yh`NNTQIzN@XG-g(S&hC|N9#2_*^yh7hR~n7u&8 zn%8PWc5AlH+G4&`pq-{Yh*+GTpD)UniAZm*SfW%a#gJ4il?oYzkn+1})F*UPYv&j= zIE8r$4^5D6fMrB2WFD;o8Bb>Jdvs5G!dKXvM-fPoCE~ZQP29 zaVPG=-898uC1I?`PSPZ0C;tm|c=<;Ln9%BUVH-c`i^~-@LDA`l7#Xtx`AIaD0BfTz^ zQBAneTwLsN=Yl{umWY~kl3vCzR z+v^BPRh&rwf8&Y#FFPj6Hwc3eHXw zzd8alwE1?NA^jgIF$1GW8=a4O@w8kfT0bxE#Eb$lTeUM{#Q&~ydhM|apMx`PgB^zZ z74s49c(|Ksb6%#OS*Oe@4u@BrsY%Q6)sBz6la-UUbkRS45Ja`28wHpoB7w%yVh)b&2k#wGB7G zan6XhePzuD282Z5?DePaJh{l%+EBGGxN^;ew)hXmeWu^W*AE;Q-tBuII6JryyY)qA z%=ok^C6L*;=Ke;i#(Pl|^NQ0@^hGYzJ=MTD?r0?T8qnU&Vv-o6iV7>9s1miqGXPU`!ov zF~&g~UD5ntp;$tl+n&^jQrqpQPA9WY& zd%An?Ct6H!)6_Q^8RaMXvwAeG87n4&*_!gAej{jF8o2({hZb{TY)ve;qNNHxQdQe? z&fiTZF6>)giA{yRyVA0_U3KA^#2f8rQ!oC`^~#iaz5YQol6|;PZ^reHJTGV;9&2ma zaa9gn@OOUQG|?sR`@FW)w)lLo7h2LM*oL)*=EKjgI6d$r??LX)XNXD&Xg&+*6FCRN-TyLm*xB9%X^P8sBzz5ZT9w_a+*7j_Us5fT4uDLH-@gk zk>!up7D*bljxWufd}(=PjqS9(0W#P8?ObT`zCmf?zqBEA>^0*?6OUe0ncH{sP*!m} zH{o(TQPjU>xp};4i3@u9@Fe=3Va?cEif@Z=QX~5>@#$mH+#cP$VC8#5W5bI-Wq(;R)3Y>}wwizcFChkBz5oCK diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/button_tint_color.colorset/Contents.json b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/button_tint_color.colorset/Contents.json deleted file mode 100644 index 986f01823..000000000 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/button_tint_color.colorset/Contents.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "1.000", - "blue" : "0.624", - "green" : "0.678", - "red" : "0.208" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/dismiss-modal-icon.imageset/down.png b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/dismiss-modal-icon.imageset/down.png deleted file mode 100644 index 266f1f852a52b1432a282b36ef3d7e3d94035b6e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 319 zcmeAS@N?(olHy`uVBq!ia0vp^f*{Pn1|+R>-G2co&H|6fVg?3oVGw3ym^DWND9BhG zwn`WqgefAiwT zMuSRb+a_}czXzf=P0D$@c3LrC)UIIqBNw#j$g)(^8qbGIJ?m@N_xz1tGDS{WQt?R4 zRli9p(dT~3UN|P!@wnpouDtqVnX}vi7+)kXKfJ`V-&U;j(ZzdfR;@~wXyd-(?eJQG zL+-}zmkcqpf_m%2L|pGFeR-)cDV*i!zW-}p|H@+i;=w-m0&B18h7=LkJvyg1b7ss> zx?yxrm37j_@77Q6I_iE9mUPmxdXPQme8QG)sk1B+&axMig5938{zopr0Qtyz;{X5v diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/dismiss-modal-icon.imageset/down@2x.png b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/dismiss-modal-icon.imageset/down@2x.png deleted file mode 100644 index acba77b2e97e2065f671a5e118140b41343a74e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 494 zcmVO2o64a6O6=99@}6d9NZc1=G@lGD(?y~r zGNepb2}CMB*tQ)`r_&8gKbUpcGd^_rmNZ}(#zR*LgmN}Kl0sJ(Hr&C6?^VBnf8qf7 zJsVGwF-o7mv1YT$^cusvaqIVwc3oEqs+-lsR8fa@@ul$ zY>K^JZ$ej)xi;Q*X0usiI2=y*=c)b4#@JPW_}eJ(I^OB$+D7yFytofi5s+OM1p&gF z0k0u@VE7kEGo($2A?O==iF@b>1Qjxw%&U1q^W-{jClp=cAPWc@Ef$N0c_Qwf*)Nex z&K7d;p4shO1IPt}lzDJTkShdf^8gFPLMh>Uh#^np2tn%5$t1raK=^&yadUXQ!=F>9 zBdMr?BtSkPNJkCqE;$B`C^~>YOQlkQPRut1>9|3F(&_XuP&SoH4Nd`tfFNZvsaC6H zSF06n(6|Lp*Xwn$-|xr4gF%oL2KfMmgdlA@vD@uVT`oC>v_e9VH3ppv+CpLpM%x3psWc1_88OF5h_fksR^`L1$xj@qY##Iuqm*f^NvM@p#EHDQI4ZecP!v>C00000NkvXXu0mjfGgkQK diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-1.imageset/icon-connection-1.png b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-1.imageset/icon-connection-1.png deleted file mode 100644 index 0712ba3dc9dd8e796fcf2ea8f3779bd1621428f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 361 zcmV-v0ha!WP){wNlMx7jNeC3cXao{q6ao#PMj!%I2vk5Z0vS+*KnDyW7y!Kp7C{MbZtVIyYx`Jf4&7603r}{k)}gJ&Hw-a07*qoM6N<$ Ef?UXW3jhEB diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-3.imageset/icon-connection-3.png b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/icon-connection-3.imageset/icon-connection-3.png deleted file mode 100644 index 91262ac9c4b8c314bffe4745a34ec91145c08e90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 336 zcmeAS@N?(olHy`uVBq!ia0vp^h9Jzr1|*B;ILZJi$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWw1GpFCY0Ln>}vIe(J3*+IZ1kcY1!U`K&^u+oQvf)A$5VPtml zm=>A#a_Ooi>%-*lFII~CFLk@1txd+Db)Tu_g6MynMg4($N| zfXCFtz=nCI>>ix#%zv9Pe-7q}i(q0;0swA--2(*V+!6u+_72~ZcENU*78+Q5fTFu6 z-UFu?7C>O40YFnHjNp#-!v#YYgwiZK!6L2GcFo{(wX?K_ zV(>&96s@SDfJG>yp{nYN2o;pFy1G0R2}h_Y!PS%yCX!!t z90^PGB?SB81EISf-97NCq7+u;5)-hb+tbTXWPQ?kL4@aKqF91||}Yba8%VF)wCpJe|HW5WFSC*}R zd4XauyIEC-%38W(eFJx0AK7K~(+X$c9*on1?IIN5DhdeHNd!UzjnqJ@$-&VYaQNR) zOT4GASNK0dk?@lUv<5;|1BLnrD6{B1-Gkl#9k8XPhG`%v*gX)7Gd0kHF@sX{_4U+H zQ%B<9C>5*%9E(CLC?nia3hqcXxB|i*tB%8YsH2p<-2aM;X>WkXp4-*%m%S&`-UtC# zHc~b+R6}F*5eP$dJ$-ewzP=$6Zm5nnGSbugWqX|H%baQM{{J^0o>&bpJTbtXSr)zl z?%p^hLZCMc`a3-u7`#88$P|vLF6zIwn_@85M7)=;KeK~mW2_G~HN>bO)Kydzkcx=i zDZ-Rtml%%d8-nvRBH{y}f0eF=?>~|1CsqA_P4#bE&wniw=3m+>{SL;&m&B~E@SiJy zEiUNimA@}DHs;LGaL4Y>W+owbX3VgkjsGlQRduu%GrJxNYG^b2Ob zRYPInDkv{ib?h(uP#+xA<$o(pwDPZd`+IB>-YYoNoru%(X4b*KS^s}qVtw2Ly>ZMX zRtdJtb$2cL-!uC6s`c*y|B=x@nL+>0jFfgM{hcnQzsu@BGx=BFe_4u|0{qp)T;F#u ze{U?zo8Ma#E|4h}k-71}_Ao>M;DDp4f!@imTMM@@^abFYU+63?kU7-i$VArULSwjr z0l4$&bzWrlk+iAwEJbWVGFs(o@-!}o(IxHoY7YYQnA=d;{`4(gTirvc9x7sbjbRp= zU1;6U1od01AGfCJCDy9*wl)18y{;atR&48ilhZP>KECAA)-tqCqeu1P9-`}8TaybR z8JhzjSu?W%;8p$!uX(@!-G`<~P$CTZG?Ttp`>_u3x6b5W&UUksc?Lv32+&b2 z!mSqN)$%NHqJlo(4^ZcVN+-Z75=S5WH}&WM2TP3S7rb1EMrm4|;{OLMoB z!e$DKH}FWeH7$0 z69C5!9*PXVR5@HF#*h6=!QL$|a_Vw-i0twzrJ1a7gvB2b%96**U{=dZSxlFOr&NU2$UI$ zkLF%3rOeLi+sd~>p77i>U;e@4AXim)XaCYys$z28YN}w$QN|iUgJ{u%xtx1YSoQQ; z&V#}J=MbvMh!db9IlC4xtN+^4nWOm}$Ln@)G9PffFUG%51-xN)hs{lHS(U>5_R@hr z&b=PI4_2EzKz&G2d?sc1FyHcUs$7Kawxmet9x3=*P{I9CW`f*?w^14CMMcw~a7# zU|4HU!=BmiCGox{#cInF`c|qfDVf2^w!yKO$q9=?EA{tn2cbu_*H3>I!h1!GEhGm` zy(sVnZ*;VAie8bgIBP@42)3HPn`l4%*-pZk+oCU+>vQh-IK;`4R4RM_OSP{V{{*W` ziW3|D(yVE7@g~LUr<|ISWM&AOAEIuJt<`zaE8v^#WBIF*;cUqVB=bU zIu~Paqh?Y7`ME`39B9n^x;%8K?@8=*$D{P3tCy!b;}7r}+-Gr=tCeVO;-OYdsow3q zMDgWWaJ*+VJ~8DRFa75FRklNO`-gmi3G11C%kI=}^y1LG<5lxZyiYcaJJ>F<4k3*qgss+`rcp3c$Ew39hS ziURX`iryqSq~@GrZoHY8LM6Uq22LfOq(>H3EJX+`XT^J+l@Mpf-e1)=;c~maym9$gEuLt@h;xj-Im^&OWncA|AD|%utJf)V8NcZkb)KEUu4z$Xt$+IjO zEmjMP2u5GHH}&DxWv5TgndT2WWMd+3IKPm(+k5#wesMVKZInkAh8A-M7W%YihT~|K z{wWms(GOSsz{a9U3B}5k_w3Y^vI30gC~&Q7;fjmPN@OJMM3dn>Hbi6jTH?Vs!(T6% z+1_RSmb4|xPFJlOP?yG_bl>cQ{Rlm{TCK@S=O>}+t>jMr4!-Vd)w4_J>6y_h>6lP>56j(S9XKR; zbW21kf>SWs-iEX4cs=k0$iU%-Apt$Y4qrgOHd2hp> zCx<>+5 zwUX-4teXLp3MaqC!`L}%83*@|-+Rk7ht#(acyc8{O5bn`XdQ{>MlMQxz4HWv-yU^} z?a)-I)SlTxIQlsEdSuKK=7id60}Do5jL^kuf{1~88>0LXAfuTVTp@8=@671*Bi9!Ejo!%ece;nziy! zYhKA`vwm2S?%Fw#w-r^Ziho8By<{;4D}k`e$#-DPG%IsQ}qaJ$lMH z7b5%0A=JU0M*wfa-g|G&?`K1e3<<1-{bM8+N$|$2JT^DSIOxLqnJwcvi^oZ`X;4m| z3Lkbg)ampD8v$=*I6U=V7br{4$j)9mo*JYz+Z zVEr+n43KpRB;kZt9@)uZ+(qb&EV$v?RhR24BQPHcm_^>)&Or9{7J|%&s7hzXt^GPi zorS%V$A1jFm?Y!&hF{S;UM^!~xU#Rv=EJLCjs|NkPjB*!A*ab}37yEmZJs0AMe2Ie zB&7UFmc~)iT!PJsvy)*Zv?^PpE)?HmwlIg=X}sBzH4NN62ZX;tO>VQmd}|kds!|Yq zf?l@qb;gd4>$7#}JsR^y=Q*4_xMQ}bUE*3>add*_>jE^m!`N}hD~z4(*i-mzw&ZfT zrkKJ>d@@$H;Xqg5W_R7a=fIWceVr5EXC@4;T0Qn-LFUln&%6Z zZM<{y2Ji=#okzyHfhz<1M&Q<;O8hpjdnV~vVsc|2-F2I`f-A8s7`>cdqWoTX)P zHvAQ*{o&N`%1m7|`J6j;=n z`WkX)uSdl)TX$>|A^Cm*>HCus`vVF6g?MpFH{if>YYzLsLsQ zpVo*eT-@rkj1L(f)Hx$TIk2NaFpeYFKx}e8t4O1re1rzNStlwab#ZFNT^03{O3~8G z8M=XA+t?#o>fnO79HIBm0xaqo%wlkWc;`~vjCyIwYv9QnlgH3WA!V$uoFFqzIG(V5 z9|R@g3mmeRkGa(kQiizhKp(IY>m?IeW4vOr(>E2d%GXOgR&eB-MY{0et=s_bILiLJ zTp`!7tejpV6qTo0`uMjPW$xgtbJPcvqbP@H&Me*O#@nDpJsQX?$_5QiHh;iBL4_%3<5meZTZaCOad> zG|4M@N92_!`4sg4bz11e6&63l*;qutredIxvakYJXzVKdLUZBS0kIMV4(-E;){AyY z6M~dI?}VYY^wgzic8flJb3Wc@Kq)7$j#NKVM0g6+%vLXf7;HPs-d>yFO%z#)oB5<0 zd5J>P&5i5ZU#U$hH(DZfefBT=p>!JrX^kSAs%E8#WBWSgfp&!6G*78O8;8*vOm5DJlt4(v>=n<izHs!x9y9k_z2+}Aa>H6<*rM&&UVH+@^^-%UmU$t_}1U4`HCHni87ke&TR$ zolt>7(EdM(pYQi(I7Z95uyns-ISA%E$OV0&O*1Qf*|VBUL~anb68k`{j%~v{ zlNm!gnt4c6-;S?K>^WM`uvP?9in%O~I@Hxo2x&d{^pXC8WIm-Jm%mz^ee-44$$PVW z>nmZxjRns;aV)PY@ps1uf)W+kTic75%~Q5V)4Kuc5@eLOh4tp)O81{)Mi8GW_Jt#+1$QyGGWxFbK#;{6i-cR!DKt&hHIKeyE*0anyi#`=|gE6z$0V&~+!nv>IA{Mead44YSy zdGET+(UW!9=o~k4D$VbV zWgUBIE)N!p@J?#HN!>?%)kQmpwU+8AU0nKMW+2j!A%IH|IypL&jZwpUD~cgLT7d%Qgwmhxu5R3WWvA_9ndRSg#WalOg(&97Skcc}pT0 z8W6XxIlgSZ^GY7E7tSWOCmScFrbxHSNHJ(a*V@vWCQ1~+8>bU<_;B8_k%^WBZ_COJ z4_mtOdy_FPIuaJu{ITAT@k&l>mA_d)^9Li&J7FPt1w=um;T}28LAnI;-uf32WR`iQ z9ixVTT1fa-Sv6~{>3Wl#(YOUc=Ub<82G{(?WwUpA6Y)DyC4Nz%cfB7fv=sz`DGd;0 zN^2`QAU2ex9?hR6GL@Q`I=TAsvgj!7rvH!ek%>XG1%!$_kUh`6G05E*8Cx$^{oL}M z$%7m5>3Iv+x)3c{k2f$wYmYLTXn-vZW8r-~{pQOmu+TcUg~X?AibyV`4>LsLy4Ovg zNmR=5%F;BVXFOW4y|kZwx%)sf>bXeyf|KXr+2_*W?)-(zCJJHgE>tWfq-2IX_G7!& zDg@VG1ESzrP#T^o{KKO`6g;@sPve7Vv5J8sE1tx$tnFDI-R4a?*m!uaPB8+AvwR%S z`O!P>VwwdZFg9%UZMyJ??D_VYmdC|&}b@p z>WZ>N)%B-E6yvmat^uE#&2up`-%EV23LFBSD@<#?yFGQd{$+{ai@*ZKt=j&#v;g!R_6WgVaAOmagIA>VX;XaX)QOw%IQ(31ekFLz6T! z@pW+*Q{QVKwD_=|bW-3SbIg^Lcsy7ZNZ;zc>8ftw~z!`u9JVTQ) zM(|O46PeA~Bx5ak2Hytwd2LkYvg5m9o_-ZDxs4?HihZ$;YlDqySu`ZKVrN*f5{w{X z=l)E5_^qWmr!a|~{IVxVR^-F>MZ>Q_TptqTE2D5lC)TsR#^@MT47#zlPMoiCjBtIB z_oP~+@F6>V!whzzVSw`^`r_vJY38f`a8X_cy&QVRyBV_KTB3BJ(SN(=K%4#7_amn# zN*373v$@(r0u93yg_QXTywR(|ArJ>zBx)v1v{Ap^RmyK|p?cF_pd3Cv*PJEqU%OEt z!cGn{{mh${<4+AqUogIKj5SPa*_Lvm`_cs0BDexzTwMu>pYI-;%stgox4iJFd+^!= zId*tlm0srFvF`F?BbPld35aa7E=>7RCSc~7-CLq(=+$vcna6JLJv9UYZVXezj(ih- zD%iFi0lH}!1ztY-ImZw~HT4wTL4LlTu_&g4kzVGS5F1)b&u{VpF6Q!#{keawEUlM+ zZQ?*G?n5a^hvim`Q-9NO<~yJaj4qOP_hsF3WMTczG_PMs-TV64Di9<*iHf@D$5P!5 zmVvgHc>^zQL=BTp494JLg>9gQj9I_>%MOw2=oW$20zRfjRbAe!p^8tv6WC^Ir+4x| zxAxqMb?R9e{t;blGtVAq6nJFol;_}}HqZMOyPHcv@52L3Hu{2AFwqdVY+PLVzL!~S z5nkCGylhtbR(;`%K7QXkZ*RwcSOQwLMp}6_pM7r}(q3tn=B)kRBG_7hXUdgG{i@tN z{1mO*#kzQ*2V@Lwf6!}Cb$N5sX^pgr^x$nm>2c*A0{ z)m!Nj{>uXpL|ba(4L>qYj;<-))#TSq`!czw`(f>ZLdpil9(wX)+#Ky=Lh%y&XN5SN7yDT!!_ohPJIB}QC=iMwm(YECU z8fe5R_y&ZULlN|s1(&1LQO6!+NErAnVdJ?woC+FY&QkvInz6mFfVHCSv80!gPNX|C zXoI~^`OG#hOL_qk+G$N+Q`|ys=hgGUuW3e-?YF_%E?Gr|q1IrFsk%N%+qkpzzORu> z0Vp}{4U12VTR+ZEM6vhso9EkmW|*uMg^O=p5bvK!lKlR~?`3U<68VsuN=2%EY)I$r oQ)_Pyv3HNOE!B=Z%lfZs7XLhYGG?tUCKHMBCQ(07ad4?rP1zyJUM diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/ruuvi_menu_text_color.colorset/Contents.json b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/ruuvi_menu_text_color.colorset/Contents.json deleted file mode 100644 index 4f4b48058..000000000 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/ruuvi_menu_text_color.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "1.000", - "blue" : "0.239", - "green" : "0.235", - "red" : "0.031" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "1.000", - "blue" : "1.000", - "green" : "1.000", - "red" : "1.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/ruuvi_text_color.colorset/Contents.json b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/ruuvi_text_color.colorset/Contents.json deleted file mode 100644 index b0d918ee4..000000000 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/ruuvi_text_color.colorset/Contents.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "colors" : [ - { - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "1.000", - "blue" : "0.239", - "green" : "0.235", - "red" : "0.031" - } - }, - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "color" : { - "color-space" : "display-p3", - "components" : { - "alpha" : "0.800", - "blue" : "1.000", - "green" : "1.000", - "red" : "1.000" - } - }, - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/tag-settings-info-icon.imageset/info_icon.png b/Modules/RuuviDiscover/Sources/RuuviDiscover/Resources/RuuviDiscover.xcassets/tag-settings-info-icon.imageset/info_icon.png deleted file mode 100644 index c1ece5b9539a468130b2adb04286ef2f90ba6f45..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1136 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=3?wxlRx~p(FlGe!gt)pF_~=f1XgcGz2@p-c zt-b21<(#W3lWsfAzYh|baSKGw1k292Z8-0?(Nv(w9pjlmbQi1uD0Rnp#%;4H*C8s6 zXWn*b*bfvjnRO?0)qkKMh&|)B=`1h_R5|?)SR+Um!+($hQ;>nTOu*ts)9wL9%xB-z zTXfNE_6_5iXF!UlL-iWZxMeyWsQwm6JwzPrHi-Lyg65Neia}C95rg^nfsQeneha7z z=n>PIw@txT0F?o)HlBIYvhT48#2lb3Pz}&iGeB-LodtBvEz_x>5CB>S76%8yG>|iZ z?t}&x*a2YofC9t_>`1d2H?^l;1v*%7`W=hu;4lFyn{hjsb@^Uk(3h74`2{lwcKmqC zCdAJ1bL-jLr*DdCb_MYNIe6oi@bv;WmLgB)J5#@DZ}JWN{p<+>8HQ#f+$`l7>e3=B*To-U3d9>#57N2b01X}EcF@UC5Q8I{b!F)4FWk3YV1q-XW#?|0?z z?QKhI4GWWWfAI3T(1XYsd_Q6qFV>4s__vpRLD1cAM;v4Yt~W-rP!pp6jUy3}a zKJ)8VxI*?%_i&qY=P!k+znm;{Bysb;nT|CV&OK7(bh^A^ifWA9jp~=bdVftl$S+s# zHs@W@6RAb_<_90yd+Yv}&q7a^ZJjlvWzD;?!gb#d*Gju>zc*hdYZk|~!e!f=ce!fp z)nj~kZ;Stf%X23_u@fraH$9y4gt4Oh*N92Kx`+B-}l<7RaFP$MVYnjZ!rEe}Qtyf6S z^73W8WN!V)$>GcNNLwAH=^jyxC$9)f+3ViU7Q12o{obhqiUm2>|70KX^^d#8D{}9w zmcZM>8M;EL4ZP>YekGa6O3#_ayZOMod7oYQuc!t6Qmc9K>2#e{qRmF$jfO4k4V h_vg}fseS*Lw!fP3S1U806PTPCJYD@<);T3K0RSI^J0<`C diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift index d0385bb30..95b9ccd2b 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/Util/RuuviBundleUtils.swift @@ -25,16 +25,6 @@ public extension Bundle { } } -public extension UIImage { - static func named(_ name: String, for clazz: AnyClass) -> UIImage? { - #if SWIFT_PACKAGE - return UIImage(named: name, in: Bundle.module, compatibleWith: nil) - #else - return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) - #endif - } -} - public extension UIStoryboard { static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { let bundle: Bundle @@ -46,15 +36,3 @@ public extension UIStoryboard { return UIStoryboard(name: name, bundle: bundle) } } - -public extension UINib { - static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { - let bundle: Bundle - #if SWIFT_PACKAGE - bundle = Bundle.module - #else - bundle = Bundle.pod(clazz) - #endif - return UINib(nibName: nibName, bundle: bundle) - } -} diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift index 62d0bfe2c..26dee4504 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift @@ -84,7 +84,6 @@ class DiscoverPresenter: NSObject, RuuviDiscover { private var stateToken: ObservationToken? private var lostToken: ObservationToken? private var persistedReactorToken: RuuviReactorToken? - private lazy var ruuviLogoImage = UIImage.named("ruuvi_logo", for: Self.self) private var isBluetoothPermissionGranted: Bool { CBCentralManager.authorization == .allowedAlways } @@ -394,7 +393,7 @@ extension DiscoverPresenter { rssi: ruuviTag.rssi, mac: ruuviTag.mac, name: nil, - logo: ruuviLogoImage + logo: RuuviAsset.ruuviLogo.image ) } view?.ruuviTags = visibleTags(ruuviTags: ruuviTags) diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift index b216daf2f..10dfc61d0 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/View/Table/DiscoverTableViewController.swift @@ -51,6 +51,12 @@ class DiscoverTableViewController: UIViewController { // MARK: - DiscoverViewInput extension DiscoverTableViewController: DiscoverViewInput { + func style() { + actionButton.tintColor = RuuviColor.tintColor.color + navigationItem.leftBarButtonItem?.image = RuuviAsset.dismissModalIcon.image + view.backgroundColor = RuuviColor.primary.color + } + func localize() { navigationItem.title = RuuviLocalization.DiscoverTable.NavigationItem.title } @@ -213,6 +219,7 @@ extension DiscoverTableViewController { override func viewDidLoad() { super.viewDidLoad() localize() + style() configureViews() updateUI() output.viewDidLoad() @@ -276,6 +283,7 @@ extension DiscoverTableViewController: UITableViewDataSource { cell.descriptionLabel.text = isBluetoothEnabled ? RuuviLocalization.DiscoverTable.NoDevicesSection.NotFound.text : RuuviLocalization.DiscoverTable.NoDevicesSection.BluetoothDisabled.text + cell.descriptionLabel.textColor = RuuviColor.menuTextColor.color return cell } } @@ -306,16 +314,17 @@ extension DiscoverTableViewController: UITableViewDelegate { extension DiscoverTableViewController { private func configure(cell: DiscoverDeviceTableViewCell, with device: DiscoverRuuviTagViewModel) { cell.identifierLabel.text = displayName(for: device) + cell.identifierLabel.textColor = RuuviColor.menuTextColor.color // RSSI if let rssi = device.rssi { cell.rssiLabel.text = "\(rssi)" + " " + RuuviLocalization.dBm if rssi < -80 { - cell.rssiImageView.image = UIImage.named("icon-connection-1", for: Self.self) + cell.rssiImageView.image = RuuviAsset.iconConnection1.image } else if rssi < -50 { - cell.rssiImageView.image = UIImage.named("icon-connection-2", for: Self.self) + cell.rssiImageView.image = RuuviAsset.iconConnection2.image } else { - cell.rssiImageView.image = UIImage.named("icon-connection-3", for: Self.self) + cell.rssiImageView.image = RuuviAsset.iconConnection3.image } } else { cell.rssiImageView.image = nil diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/RuuvoBoardView.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/RuuvoBoardView.swift index 7831a5f7f..0a9377fe6 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/RuuvoBoardView.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/Common/RuuvoBoardView.swift @@ -1,19 +1,19 @@ +import RuuviLocalization import SwiftUI public struct RuuviBoardView: View { @State private var isPortrait = false - private let boardImageName = "ruuvitag-b8-and-older-button-location" public init() {} public var body: some View { HStack { if isPortrait { - Image(boardImageName, bundle: .pod(RuuviFirmwareDummyClass.self)) + RuuviAsset.ruuvitagB8AndOlderButtonLocation.swiftUIImage .resizable() .aspectRatio(contentMode: .fit) } else { Spacer() - Image(boardImageName, bundle: .pod(RuuviFirmwareDummyClass.self)) + RuuviAsset.ruuvitagB8AndOlderButtonLocation.swiftUIImage .resizable() .aspectRatio(contentMode: .fit) .scaledToFit() diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/Contents.json b/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Resources/RuuviFirmware.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift deleted file mode 100644 index d0385bb30..000000000 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/Util/RuuviBundleUtils.swift +++ /dev/null @@ -1,60 +0,0 @@ -import Foundation -import UIKit - -public extension Bundle { - static func pod(_ clazz: AnyClass) -> Bundle { - if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { - if let bundleURL = Bundle( - for: clazz - ).resourceURL?.appendingPathComponent( - "\(module).bundle" - ), let bundle = Bundle( - url: bundleURL - ) { - return bundle - } else if let bundleURL = Bundle(for: clazz).resourceURL, let bundle = Bundle(url: bundleURL) { - return bundle - } else { - assertionFailure() - return Bundle.main - } - } else { - assertionFailure() - return Bundle.main - } - } -} - -public extension UIImage { - static func named(_ name: String, for clazz: AnyClass) -> UIImage? { - #if SWIFT_PACKAGE - return UIImage(named: name, in: Bundle.module, compatibleWith: nil) - #else - return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) - #endif - } -} - -public extension UIStoryboard { - static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { - let bundle: Bundle - #if SWIFT_PACKAGE - bundle = Bundle.module - #else - bundle = Bundle.pod(clazz) - #endif - return UIStoryboard(name: name, bundle: bundle) - } -} - -public extension UINib { - static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { - let bundle: Bundle - #if SWIFT_PACKAGE - bundle = Bundle.module - #else - bundle = Bundle.pod(clazz) - #endif - return UINib(nibName: nibName, bundle: bundle) - } -} diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Assests/RuuviAssets.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Assests/RuuviAssets.swift deleted file mode 100644 index 989ad260d..000000000 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Assests/RuuviAssets.swift +++ /dev/null @@ -1,15 +0,0 @@ -import UIKit - -enum RuuviAssets { - static let bg_layer = "onboarding_bg_layer" - static let beaver_start = "onboarding_beaver_start" - static let dashboard = "onboarding_dashboard" - static let sensors = "onboarding_sensors" - static let history = "onboarding_history" - static let alerts = "onboarding_alerts" - static let share = "onboarding_share" - static let widgets = "onboarding_widgets" - static let web = "onboarding_web" - static let beaver_sign_in = "onboarding_beaver_sign_in" - static let gateway = "gateway" -} diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardCoreFeaturesCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardCoreFeaturesCell.swift index fac8a36cf..1f8f548fa 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardCoreFeaturesCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardCoreFeaturesCell.swift @@ -95,6 +95,6 @@ extension RuuviOnboardCoreFeaturesCell { else { return } - appImageView.image = UIImage.named(image, for: Self.self) + appImageView.image = image } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift index 4be61b635..68191d7b0 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardGatewayFeaturesCell.swift @@ -31,10 +31,7 @@ class RuuviOnboardGatewayFeaturesCell: UICollectionViewCell { private lazy var gateWayImageView: UIImageView = { let iv = UIImageView( - image: UIImage.named( - RuuviAssets.gateway, - for: Self.self - ), + image: RuuviAsset.Onboarding.gateway.image, contentMode: .scaleAspectFit ) iv.backgroundColor = .clear @@ -165,6 +162,6 @@ extension RuuviOnboardGatewayFeaturesCell { else { return } - appImageView.image = UIImage.named(image, for: Self.self) + appImageView.image = image } } diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift index 11dc6eadf..10ea0d06a 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardSignInCell.swift @@ -10,10 +10,7 @@ class RuuviOnboardSignInCell: UICollectionViewCell { private lazy var beaverImageView: UIImageView = { let iv = UIImageView( - image: UIImage.named( - RuuviAssets.beaver_sign_in, - for: Self.self - ), + image: RuuviAsset.Onboarding.onboardingBeaverSignIn.image, contentMode: .scaleAspectFit ) iv.backgroundColor = .clear diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardStartCell.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardStartCell.swift index 3e55256fd..c3836b982 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardStartCell.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardStartCell.swift @@ -1,12 +1,10 @@ +import RuuviLocalization import UIKit class RuuviOnboardStartCell: UICollectionViewCell { private lazy var beaverImageView: UIImageView = { let iv = UIImageView( - image: UIImage.named( - RuuviAssets.beaver_start, - for: Self.self - ), + image: RuuviAsset.Onboarding.onboardingBeaverStart.image, contentMode: .scaleAspectFit ) iv.backgroundColor = .clear diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift index 90ab40f58..71dde4abc 100644 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift +++ b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/RuuviOnboardViewController.swift @@ -32,7 +32,7 @@ struct OnboardViewModel { var title: String var subtitle: String var sub_subtitle: String? - var image: String? + var image: UIImage? } class RuuviOnboardViewController: UIViewController { @@ -49,10 +49,7 @@ class RuuviOnboardViewController: UIViewController { } private lazy var bgLayer: UIImageView = { - let iv = UIImageView(image: UIImage.named( - RuuviAssets.bg_layer, - for: Self.self - )) + let iv = UIImageView(image: RuuviAsset.Onboarding.onboardingBgLayer.image) iv.backgroundColor = .clear return iv }() @@ -381,49 +378,49 @@ private extension RuuviOnboardViewController { pageType: .dashboard, title: RuuviLocalization.onboardingDashboard, subtitle: RuuviLocalization.onboardingFollowMeasurement, - image: RuuviAssets.dashboard + image: RuuviAsset.Onboarding.onboardingDashboard.image ) let sensorItem = OnboardViewModel( pageType: .sensors, title: RuuviLocalization.onboardingYourSensors, subtitle: RuuviLocalization.onboardingPersonalise, - image: RuuviAssets.sensors + image: RuuviAsset.Onboarding.onboardingSensors.image ) let historyItem = OnboardViewModel( pageType: .history, title: RuuviLocalization.onboardingHistory, subtitle: RuuviLocalization.onboardingExploreDetailed, - image: RuuviAssets.history + image: RuuviAsset.Onboarding.onboardingHistory.image ) let alertItem = OnboardViewModel( pageType: .alerts, title: RuuviLocalization.onboardingAlerts, subtitle: RuuviLocalization.onboardingSetCustom, - image: RuuviAssets.alerts + image: RuuviAsset.Onboarding.onboardingAlerts.image ) let shareItem = OnboardViewModel( pageType: .share, title: RuuviLocalization.onboardingShareYourSensors, subtitle: RuuviLocalization.onboardingShareesCanUse, - image: RuuviAssets.share + image: RuuviAsset.Onboarding.onboardingShare.image ) let widgetItem = OnboardViewModel( pageType: .widgets, title: RuuviLocalization.onboardingHandyWidgets, subtitle: RuuviLocalization.onboardingAccessWidgets, - image: RuuviAssets.widgets + image: RuuviAsset.Onboarding.onboardingWidgets.image ) let webItem = OnboardViewModel( pageType: .web, title: RuuviLocalization.onboardingStationWeb, subtitle: RuuviLocalization.onboardingWebPros, - image: RuuviAssets.web + image: RuuviAsset.Onboarding.onboardingWeb.image ) let signInItem = OnboardViewModel( diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift b/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift deleted file mode 100644 index d0385bb30..000000000 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Pages/Util/RuuviBundleUtils.swift +++ /dev/null @@ -1,60 +0,0 @@ -import Foundation -import UIKit - -public extension Bundle { - static func pod(_ clazz: AnyClass) -> Bundle { - if let module = NSStringFromClass(clazz).components(separatedBy: ".").first { - if let bundleURL = Bundle( - for: clazz - ).resourceURL?.appendingPathComponent( - "\(module).bundle" - ), let bundle = Bundle( - url: bundleURL - ) { - return bundle - } else if let bundleURL = Bundle(for: clazz).resourceURL, let bundle = Bundle(url: bundleURL) { - return bundle - } else { - assertionFailure() - return Bundle.main - } - } else { - assertionFailure() - return Bundle.main - } - } -} - -public extension UIImage { - static func named(_ name: String, for clazz: AnyClass) -> UIImage? { - #if SWIFT_PACKAGE - return UIImage(named: name, in: Bundle.module, compatibleWith: nil) - #else - return UIImage(named: name, in: Bundle.pod(clazz), compatibleWith: nil) - #endif - } -} - -public extension UIStoryboard { - static func named(_ name: String, for clazz: AnyClass) -> UIStoryboard { - let bundle: Bundle - #if SWIFT_PACKAGE - bundle = Bundle.module - #else - bundle = Bundle.pod(clazz) - #endif - return UIStoryboard(name: name, bundle: bundle) - } -} - -public extension UINib { - static func nibName(_ nibName: String, for clazz: AnyClass) -> UINib { - let bundle: Bundle - #if SWIFT_PACKAGE - bundle = Bundle.module - #else - bundle = Bundle.pod(clazz) - #endif - return UINib(nibName: nibName, bundle: bundle) - } -} diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Contents.json b/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/Contents.json b/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/Contents.json deleted file mode 100644 index 73c00596a..000000000 --- a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/Resources/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/ruuvi_logo.imageset/ruuvi_logo.png b/Modules/RuuviOnboard/Sources/RuuviOnboard/Resources/RuuviOnboard.xcassets/ruuvi_logo.imageset/ruuvi_logo.png deleted file mode 100644 index 3a94fb63f5cae187d6b5b02cf4658af18e2d29b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7490 zcmbVR2T)Vnx(?DrK$_Bf5fDNMC6EA8LJ25Uq=*LzN$8M3kP>Q+Ql%e25fB6vh0qaE zS`<*Egsy;8DM6{y5z!Yl3-FD4Kv9^&ichlhpeNd7JtMjQW}21$zl4hi(uk<|aGP~5@XN*s<2 zz=%VXlz}K^Wr(;2R0)lAMWS3?6~$GQRlp!+H4s=0sH_ZAg~HU-#Q(e`Y3c&dZZI1| z<3E+r-gG2A0t0a{5GXh}SSeUl2^-)J0z;utkg^I$MFmJh0P&%IfyfY`A71J&35FOv zD!>yL=!x|c|0xmaioFr2BT1wBhYh~Czs36D|MU~hW1tWu4g^+G{%OuJA7MC+e zqCEY68X^A=TQG*mK#Y#0iZU1q1cQMp5L;y^Ohpw2R##9~hbb%n0X4^>J>5e8f~tUl z${IkhhAmhPrltZ@hW-7tg8o?o8CW2?R`k^qUhB}fo z_b7RKqG7JeXjOF-SRIIQ!)OB4z{+kwS63tksDe~;g=o4$!D^~BMZd=kW{5@I_?ZNM z?MKu0tANq!U^D~@R70ZGfoc$>CeRhCq6$P}phz`!6cnoBiu!B6Wq>EG3XwklZ#h3} z^Jn(J5T1BiTtojXp34~jKSw^E;=d;h42k+#2s)CepBaEbOa3|S`7b>1-&yd7*kBI~ zP3V8fi$7p^tXp6(G619RPV?4(k$IqhM<0(2`p@M5yYT%p`G1?K{~dW1CAEJpn?JUp zJdl3w7+PxuN&Ykk^s@*35g5?_j@j>P|In}gg43Gd&*9(gm-g~^1IPH$LWoG^aJ>q@y%3`m86I={KLcXtH=w*Gq=q+8ujc zlfX!1A2&n13;84uFn|KhQIvMb;DoYpWpY}7KDNdVG!K@9m6pG7f7FIwTGnoPe&xnS z?voGC%3hS^;#1=9it(S^VdSO%3TPpQ!lHiYY@XgcwOQK|3J3(S22Sh%mDvv@(tx~d z47`j>>)#H&XW_H+fQDWUMRrBoou~qUSm4B{7u$)i^tYvEVm64T3Xf|O>(En zFUb`0`76`=>NqhR7cMRX*ak>pXsDQPK@qpp`r&nhe43(%dApTgrdh~m$v=v=p;{-# z#2h5r!OsAt^r`j{ckq<0(HUrPJbqo2I%!Ld3(mtk$&G7~p~1e!VWR$&iYj#Kp0^Bj zvPGc(J(NnZt#uERjhaymU(Wkr|5kMEeI@02s_OkJJY{Mz&uO9#NL{RMhf@6lDL1x# zZZCP`sgotb)WZjOzq=+{kRVD+c6*Ael0RjaRMP(W*Y(-FreWwl{HE;XWGS5w%`tdC zWBNVejd9W2ZG$8x3XRQrspuN?DV-B-q>|d;&}@O-3@?RJ-)+0RF`zu>6RcnKj?Ic7K`^W=Yi=gg$%B z942^UhtY4x<#y+ank9854_^*(F#%C0bMLPx$D&0_L+XpkYShWC zhcD_~_m}~102e(^R=xC6%T~N9XnNx4Bd1G=NocDhQ^;^}vwa$ay>kP=ZyU`@enJ-0 z>E2G>*gj@kHfb#)nh>uO>M@qmaokc>l7|}CS5rE+>Tm#DtBFwJ;R#ccrNXy3ta}?> zMx#Sd=|EBvb2fJNpfvia&bUpX?q;idPAmUS=?f77!ngnms#JW`;(|cZq#?(n>x$fzQdrpz)u);eTB2iWuxpx+cH!{&1bb;mb5l(ap^5a(B(7=h2$8|F- z{yU?eiSRUP>T~f;p_$k-;7is)qJ+Y_GEg=0^*)IH+a+4C;b$?_2cWGpWk%Vus}&<8 z&eDe1qHiP*C9@-|>*!ffA|!K&Z(Maat?q|v?UN_>wQ|&tyVf##;*%2kbVPKk>9z0+Z4hQ8D6$6nKIZ|uoc@RVV|IHwa3QOX z-aef7aHb5M5`{crHdGZH=)WIM~P3J1=!*Wsna_U;Rdkmy7 zz9)G{*tMiI(;2~M?JH_9Az?3NtAEi%hY~6Eaq5h10(B4@mX|eVH&inft_Ha*^BJWG z(MpOd7E=Pg@k31Of7NkmSi-Q!g#LFiEzV3DGN%IKZLE+)rV|pfF z_`r+_pqBdhe%T}ciP+4Sbf_}uQAGOmslL}pwf&N!Tc;-;KJBBNnLS6Z1F!aPWhD72 z?FLmf+m9x0X)}jgza0m~_o4E!en!T{orqIXw`3Y*bNFk#I(?s7mdZjNeyoxVO(ldd zn2wgiXydZE(q=9}&fjiz@A)3aI_ zX1u}VAD@(x5=1iLbcddW3CtE%FO76wd%%t`G$O@t@CkhyoVIS_t}d%Rou>U}B{c`5uWC-9O ztM>lW^q2_-nM1oZfvqLzx*qS7qtNSOL&Zfjmmt$#5+lnVWYKlY$sO#bxzj^u|xp_yxdZ$c`Y2T`2v zy3j(M1jD8PR+Z|jxjI=3>+$BG^J1!DQLNYI^)0~da&@rZ;j*9 z5YkKNOkzsRK+de&=uWS_N|-y^(4+XlG&P-ZyKgbladoxg$UG`$k{HZ1t@bV-Azg+i zri;$h>|)+RGQgny69ple!7v+^&?_mZ86&|fm8MyY_?P4RMz3V;niJ67Rq7)-2a>|S$EaUcpd^U|4 z<=38WG9JW;HF?!Sl?M^_lGc|j7fD@aU5FEP!4I{G01*r0IKIG0=_H z`tdW4Axn$!c`D!J8Ski*Z8cA2sxu0b`AhKzp_aT zIsxiT;_2(QC*NQqWE*^5uX7#UQGE9jabuA9-G{=7YTPOmaWe(a8>*ttmQyA^yRgh^ z2*ze^a?2!l-b+5clRp{Oy%mw3=PzlUQ(EKcU8_FswW#jIz*k&@dY8H0HNtQHNUq0H znj4bGk>^?HF7{b$%H290Ek{++aCFZYAP1HXrZuV zSft*_rb&P7LDnCku0|#A+t!=mf$fw8DE_YiccTHt;08n?p)FllqiPb_p_jkZL-gud|9N znx0}=>AEJbeDP^sZ9EBvc1mgkgUO#yPf3DTs&mF}XepR%L00bh83ep zYNg$GIaYav=;xBr-KT3%892JI`M5Tvb(uZoD!`%Q zK-Z@CLONn$&TsZIy-xe`i{cpr)RVfN*t#G*ZuG#+G17-}F0135V5jRYD-K6(gGUz#EH??|et8m+xfuLu zAvf>Xr(PqfGpJ(t(mTWA=D5gfLM6LjG7vKaR#H%}7ax1C(>M6O*@hRq-u^|6%*o*e zQgttzZ?r7srQ6<$2-$#%aE>lmV43c&lVjwakGTu0Yw>;0U-Q~|X)IM7XUA3(GMee0 z7;O}j+^=8`8I@Fq=wGvv#|&62E(KJMdOqtf3iAH)se9{o%^1cj=8EWvou28YF6=Xq zgQRmk&qB?EW1}C&j*(!h(C48AE}yU89R?TQzI-*V(Zl}GadjuAq3*3+aK{i)|vT%d)*frMB3@I7M;#{ zuqLq;4l`RygvMo`gC320L_v8O25?Ve5*^ zB|uBEtGX9h?(KNLTW#&P7~=PCSnWU;sfW-t5oz#Ye4jqDh*a$S)p{u1iuj~^OJUF_ z1rJk(rTGn)9xtrAZ_9rzKN`(ieBT3G4xY@-`*O@P*q0k9b$_KTnRt3F*IlOa!SjqY zdrqZ}&-gP)^NhNJzB99Mj7Y9L?X(ub9*ABO)MPnuXit-jELUuEKA-$y`>iY!tosW) z?uPhO=*b*+#2WXBt%llfzAOcD*Eq+f^!l5iDFPc)iIuB{2P#ZJsfAW9qPvCPwYE7WdtPutLZ%mnB=fQwnQ(aUvC_vcV|Jc&7?WvDU3WJ^Uz&69& z{@IRc!mQA2*?_TwD=omDh}S%{^8m9Fc;Ir1Q_{|Yh{u-_dxh>{R#VBVs{ESmi1#RC zLYY6KKi1Z#!7!k`M5O)~fz(S`@0WtfK}>{1s94keS&jwm^&38wKOkfz6XDbjov6x4 zaKVF0vv9_1LKE@lJH9W><)5i5_$@4X=USZfilQcqCK>U5Uu|h@{R;-cZVYH=-%*TS z9k@24$A`E*eJ3e!RMIZ)>#2-9Uj-X=O5UW;;}waW9=d+O_YzX^-6Ky@e;+&TtK+8k zz%O&4+Y2DYk2{R6pC=F0lqKr9Fdl~&G#6=Yz+(M%PYS$@$B74bB_;yQ(cjCqiJQa@l1zeT^t(yU9@PcIafrVhff zasQa^xY?{2e*0FbAd+|Qw6|tP)nN;>qql^m?2nF+IO$E^&7>O2)g;Mqj1{=pbKS1@ zxhbVpTf#NDTq>bYE4t$Cx||)8g^_5kh&ZrDJEeo@Rui?) zUbtzlbt|BQU#j55B>zObs>#}bNhj*!Dp&Svnjzvs7rG6S6w<$!@M^_h^+2F zbk>NF=>d?LO`kB;F|dyb{kAq4&fqZf8>v}4wPW(S!G!LaR~K2uTVj~#%f&?$;lXOh zryb%o-)L2u2rm}Sr}uj(=CKKv%SD~34xWo!PfWa*kE$;3m4CzCl^j6L_)%b#XNlgQ z3%>om=2kGLH|Jh#K}>qbr)4@(6N5|d4sY8~SV=SYlq|==uw;iuju0p<2JyStB`vOR znwuo|oQiHmv^%cXp+4bpZ1FL7-7lxi6@^WFc<$A@3|=if+en`;H2?jSic>ld%ln~5 zXC-#h55mVbfd}9;Z5awVez-1MD z#zFJQnF*#g4y>n3$4hRe7k!)I3Qo-$P#dOhlk^C(F2lj{UN-!t5FR2NF2p5|rF)~W zayKPY{oK+5VYYI>7(Hw4LlDav@=F-6E#ZB$>#t;U>h5wkuQ9=R_`t2gZk`p*f3fb% zGXM<4TBr(B%!_#Ua=4~e#`nc`}OvED^Q$m)MZcqijaD zi_II^J##0|Uvnvx8ae1EH$yWXI$l) zI4M=B7uA)lK9Mky8?Os47uj9TAaCfs?($SIb&Nz<=#|-A%_$|0R)?-qx)%{ywspy^ zy{`nw>kpExT)1&fMc-7*i0T zXy3RsMk?+jlA~fF2I*X80W-#epE^^PDBIA5;6kTYyP%KpU%c=<)#p{Z8n0-kEG2NI z>c>8tqM@wCFo) z-{lhH=6as{{e`@x(<|3*vhfhq>LrZx<{YOl&ARrhJmpUfpHU0R%oy-CDXnEblW7j; zzPNUa{xl$VC~vMD&tr}9&3d!xNi<6>&sp-rv6ErI%t}zq7 zB9BfvWSYvu0~90_E*Gp?96^sZ2Wg)@2t zjlA#3Q0J=1VgaH}A^~`;-CofbPv_r=?8F+{Z>7(xbSWpk3oWO^$DbfH#jW!nbR`n- z=;}tuX~)i)#LUaB-i4}eOyU%zT(#2Sg%wBsxJ%kiA}l#F=j&9tG0XPUqZxhS#dfnj zhgyk@cK*Eiv7_`AtC|;2^6Ho!1T`5P7eQCxZ>jM-0xZpG?Oj2SWH);#?_mg^@wn{* zy5^KjXPwxN&55a(_8(>A+ph~bh`hZHoQ`e=r7wKD*cDsQrxB;NIlfCpd*S zf!`w@E|Zx{qvADnDz!r*@!{(;@YoNjES{NMH`C3N>4`?f o^{# Date: Tue, 9 Jan 2024 21:40:52 +0200 Subject: [PATCH 80/84] update station.localization --- station.localization | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/station.localization b/station.localization index b732c1789..f7c368508 160000 --- a/station.localization +++ b/station.localization @@ -1 +1 @@ -Subproject commit b732c178953b19382911f7707dc5d9af8429c644 +Subproject commit f7c36850885c125f80e381cbf3fb6f62885fb3e0 From 26601adcb98faf7bdb9f169e996093306f4cd188 Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Tue, 9 Jan 2024 21:59:43 +0200 Subject: [PATCH 81/84] Show last seen date on widget (#1851) fixes #1850. Motivation: avoid confusing users --- .../Sources/View Model/WidgetViewModel.swift | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Apps/RuuviStation/Widgets/Sources/View Model/WidgetViewModel.swift b/Apps/RuuviStation/Widgets/Sources/View Model/WidgetViewModel.swift index 38933ee87..ee22ca9ab 100644 --- a/Apps/RuuviStation/Widgets/Sources/View Model/WidgetViewModel.swift +++ b/Apps/RuuviStation/Widgets/Sources/View Model/WidgetViewModel.swift @@ -136,9 +136,16 @@ public extension WidgetViewModel { internal func measurementTime(from entry: WidgetEntry) -> String { let formatter = DateFormatter() formatter.locale = Locale.autoupdatingCurrent - formatter.dateStyle = .none - formatter.timeStyle = .short - return formatter.string(from: entry.record?.date ?? Date()) + let date = entry.record?.date ?? Date() + let calendar = Calendar.current + if calendar.isDateInToday(date) { + formatter.dateStyle = .none + formatter.timeStyle = .short + } else { + formatter.dateStyle = .short + formatter.timeStyle = .none + } + return formatter.string(from: date) } } From df5e3aea250acbf757d0d3d2e9505b060a6d640b Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Tue, 9 Jan 2024 22:40:47 +0200 Subject: [PATCH 82/84] Don't support transferring Ruuvi Station data on device change (#1852) fixes #1848 --- .../Classes/Application/AppAssembly.swift | 2 ++ ...MigrationManagerIsExcludedFromBackup.swift | 26 +++++++++++++++++++ .../RuuviMigrationFactoryImpl.swift | 5 ++++ .../Keychain/Impl/KeychainServiceImpl.swift | 2 +- 4 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 Packages/RuuviMigration/Sources/RuuviMigrationImpl/IsExcludedFromBackup/MigrationManagerIsExcludedFromBackup.swift diff --git a/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift b/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift index 5a94d3dda..872895c2d 100644 --- a/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift +++ b/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift @@ -58,6 +58,7 @@ private final class MigrationAssembly: Assembly { let settings = r.resolve(RuuviLocalSettings.self)! let idPersistence = r.resolve(RuuviLocalIDs.self)! let ruuviPool = r.resolve(RuuviPool.self)! + let sqliteContext = r.resolve(SQLiteContext.self)! let ruuviStorage = r.resolve(RuuviStorage.self)! let ruuviAlertService = r.resolve(RuuviServiceAlert.self)! let ruuviOffsetCalibrationService = r.resolve(RuuviServiceOffsetCalibration.self)! @@ -65,6 +66,7 @@ private final class MigrationAssembly: Assembly { settings: settings, idPersistence: idPersistence, ruuviPool: ruuviPool, + sqliteContext: sqliteContext, ruuviStorage: ruuviStorage, ruuviAlertService: ruuviAlertService, ruuviOffsetCalibrationService: ruuviOffsetCalibrationService diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/IsExcludedFromBackup/MigrationManagerIsExcludedFromBackup.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/IsExcludedFromBackup/MigrationManagerIsExcludedFromBackup.swift new file mode 100644 index 000000000..4eef080a7 --- /dev/null +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/IsExcludedFromBackup/MigrationManagerIsExcludedFromBackup.swift @@ -0,0 +1,26 @@ +import Foundation +import RuuviContext + +final class MigrationManagerIsExcludedFromBackup: RuuviMigration { + private let sqliteContext: SQLiteContext + + init(sqliteContext: SQLiteContext) { + self.sqliteContext = sqliteContext + } + + func migrateIfNeeded() { + let databaseUrl = NSURL(fileURLWithPath: sqliteContext.database.dbPath) + do { + let resourceValues = try databaseUrl.resourceValues(forKeys: [.isExcludedFromBackupKey]) + guard resourceValues[.isExcludedFromBackupKey] == nil + || resourceValues[.isExcludedFromBackupKey] as? Bool == false else { + return + } + try databaseUrl.setResourceValue(true, forKey: .isExcludedFromBackupKey) + } catch let error as NSError { + print("Error excluding \(databaseUrl.lastPathComponent ?? "") from backup \(error)") + } + } + + private let migratedUdKey = "MigrationManagerIsExcludedFromBackup.migrated" +} diff --git a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift index 5efaa110a..d25b2d7c3 100644 --- a/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift +++ b/Packages/RuuviMigration/Sources/RuuviMigrationImpl/RuuviMigrationFactoryImpl.swift @@ -8,6 +8,7 @@ public final class RuuviMigrationFactoryImpl: RuuviMigrationFactory { private let settings: RuuviLocalSettings private let idPersistence: RuuviLocalIDs private let ruuviPool: RuuviPool + private let sqliteContext: SQLiteContext private let ruuviStorage: RuuviStorage private let ruuviAlertService: RuuviServiceAlert private let ruuviOffsetCalibrationService: RuuviServiceOffsetCalibration @@ -16,6 +17,7 @@ public final class RuuviMigrationFactoryImpl: RuuviMigrationFactory { settings: RuuviLocalSettings, idPersistence: RuuviLocalIDs, ruuviPool: RuuviPool, + sqliteContext: SQLiteContext, ruuviStorage: RuuviStorage, ruuviAlertService: RuuviServiceAlert, ruuviOffsetCalibrationService: RuuviServiceOffsetCalibration @@ -23,6 +25,7 @@ public final class RuuviMigrationFactoryImpl: RuuviMigrationFactory { self.settings = settings self.idPersistence = idPersistence self.ruuviPool = ruuviPool + self.sqliteContext = sqliteContext self.ruuviStorage = ruuviStorage self.ruuviAlertService = ruuviAlertService self.ruuviOffsetCalibrationService = ruuviOffsetCalibrationService @@ -50,6 +53,7 @@ public final class RuuviMigrationFactoryImpl: RuuviMigrationFactory { ruuviAlertService: ruuviAlertService ) let toNetworkPull60 = MigrationManagerToNetworkPull60(settings: settings) + let isExcludedFromBackup = MigrationManagerIsExcludedFromBackup(sqliteContext: sqliteContext) return [ toAlertService, toPrune240, @@ -59,6 +63,7 @@ public final class RuuviMigrationFactoryImpl: RuuviMigrationFactory { toTimeouts, fixRHAlerts, toNetworkPull60, + isExcludedFromBackup, ] } } diff --git a/Packages/RuuviUser/Sources/RuuviUserCoordinator/Keychain/Impl/KeychainServiceImpl.swift b/Packages/RuuviUser/Sources/RuuviUserCoordinator/Keychain/Impl/KeychainServiceImpl.swift index 398dd1192..84c988388 100644 --- a/Packages/RuuviUser/Sources/RuuviUserCoordinator/Keychain/Impl/KeychainServiceImpl.swift +++ b/Packages/RuuviUser/Sources/RuuviUserCoordinator/Keychain/Impl/KeychainServiceImpl.swift @@ -8,7 +8,7 @@ final class KeychainServiceImpl { ) .label("Ruuvi Station") .synchronizable(false) - .accessibility(.afterFirstUnlock) + .accessibility(.afterFirstUnlockThisDeviceOnly) private enum Account: String { case ruuviUserApi From 7d0fc87f033820135080babdc6d6ca1daddf21cf Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Tue, 9 Jan 2024 22:56:47 +0200 Subject: [PATCH 83/84] fix swiftgen --- .swiftgen.assets.yml | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/.swiftgen.assets.yml b/.swiftgen.assets.yml index 70de46091..8da49ab02 100644 --- a/.swiftgen.assets.yml +++ b/.swiftgen.assets.yml @@ -1,13 +1,3 @@ -xcassets: - - inputs: ./Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets - outputs: - - templatePath: ./Common/RuuviLocalization/Templates/xcassets-swift5.stencil - output: ./Common/RuuviLocalization/Sources/RuuviColor.swift - params: - forceProvidesNamespaces: true - publicAccess: true - enumName: RuuviColor - strings: - inputs: ./Common/RuuviLocalization/Sources/Resources/en.lproj/Localizable.strings outputs: @@ -26,4 +16,12 @@ xcassets: params: forceProvidesNamespaces: true publicAccess: true - enumName: RuuviAsset \ No newline at end of file + enumName: RuuviAsset + - inputs: ./Common/RuuviLocalization/Sources/Resources/RuuviColors.xcassets + outputs: + - templatePath: ./Common/RuuviLocalization/Templates/xcassets-swift5.stencil + output: ./Common/RuuviLocalization/Sources/RuuviColor.swift + params: + forceProvidesNamespaces: true + publicAccess: true + enumName: RuuviColor \ No newline at end of file From a449a24a9e3cab8937e297549acd815715056f1b Mon Sep 17 00:00:00 2001 From: Rinat Enikeev Date: Wed, 10 Jan 2024 22:46:23 +0200 Subject: [PATCH 84/84] DFU improvements (#1856) * Idle Timer and Properties Daemon for Firmware Upgrade Implements dont lock screen feature during firmware upgrade and fixes missing charts icon with properties daemon restart * Ensure you cant dismiss DFU module during upgrade And present it modally, not pushing --- .../Classes/Application/AppAssembly.swift | 6 +++ .../Dashboard/Cards/Router/CardsRouter.swift | 19 ++++++++- .../Home/Router/DashboardRouter.swift | 19 ++++++--- .../Router/TagSettingsRouter.swift | 17 +++++--- .../DFU/Presenter/DFUModuleInput.swift | 6 ++- .../DFU/Presenter/DFUPresenter.swift | 9 +++- .../Submodules/DFU/View/DFUViewModel.swift | 20 ++++----- .../DFU/View/SwiftUI/DFUUIView.swift | 41 +++++++++++++++---- .../Submodules/Owner/Router/OwnerRouter.swift | 23 +++++++++-- .../RuuviDiscover/RuuviDiscoverFactory.swift | 14 +++++++ .../VMP/Presenter/DiscoverPresenter.swift | 27 +++++++++++- Modules/RuuviDiscover/target.yml | 2 + .../RuuviFirmware/FirmwareInteractor.swift | 8 ++++ .../RuuviFirmware/FirmwarePresenter.swift | 3 ++ .../RuuviFirmware/RuuviFirmwareBuilder.swift | 31 +++++++------- .../RuuviFirmware/SwiftUI/FirmwareView.swift | 5 +++ .../SwiftUI/FirmwareViewModel.swift | 4 ++ Modules/RuuviFirmware/target.yml | 1 + 18 files changed, 202 insertions(+), 53 deletions(-) diff --git a/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift b/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift index 872895c2d..0c3ba6c70 100644 --- a/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift +++ b/Apps/RuuviStation/Sources/Classes/Application/AppAssembly.swift @@ -640,8 +640,11 @@ private final class ModulesAssembly: Assembly { let permissionsManager = r.resolve(RuuviCorePermission.self)! let permissionPresenter = r.resolve(PermissionPresenter.self)! let foreground = r.resolve(BTForeground.self)! + let background = r.resolve(BTBackground.self)! let ruuviReactor = r.resolve(RuuviReactor.self)! let ruuviOwnershipService = r.resolve(RuuviServiceOwnership.self)! + let propertiesDaemon = r.resolve(RuuviTagPropertiesDaemon.self)! + let ruuviDFU = r.resolve(RuuviDFU.self)! let factory = RuuviDiscoverFactory() let dependencies = RuuviDiscoverDependencies( @@ -650,6 +653,9 @@ private final class ModulesAssembly: Assembly { permissionsManager: permissionsManager, permissionPresenter: permissionPresenter, foreground: foreground, + background: background, + propertiesDaemon: propertiesDaemon, + ruuviDFU: ruuviDFU, ruuviReactor: ruuviReactor, ruuviOwnershipService: ruuviOwnershipService, firmwareBuilder: RuuviFirmwareBuilder() diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift index 63ce7ae9d..096d83b49 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Cards/Router/CardsRouter.swift @@ -41,13 +41,16 @@ class CardsRouter: NSObject, CardsRouterInput { func openUpdateFirmware(ruuviTag: RuuviTagSensor) { let factory: DFUModuleFactory = DFUModuleFactoryImpl() let module = factory.create(for: ruuviTag) + module.output = self dfuModule = module transitionHandler? - .navigationController? - .pushViewController( + .present( module.viewController, animated: true ) + module.viewController + .presentationController? + .delegate = self } } @@ -63,3 +66,15 @@ extension CardsRouter: DiscoverRouterDelegate { router.viewController.dismiss(animated: true) } } + +extension CardsRouter: UIAdaptivePresentationControllerDelegate { + func presentationControllerShouldDismiss(_: UIPresentationController) -> Bool { + dfuModule?.isSafeToDismiss() ?? true + } +} + +extension CardsRouter: DFUModuleOutput { + func dfuModuleSuccessfullyUpgraded(_ dfuModule: DFUModuleInput) { + dfuModule.viewController.dismiss(animated: true) + } +} diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift index ba01991fa..9a8d218d6 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Home/Router/DashboardRouter.swift @@ -213,15 +213,14 @@ class DashboardRouter: NSObject, DashboardRouterInput { func openUpdateFirmware(ruuviTag: RuuviTagSensor) { let factory: DFUModuleFactory = DFUModuleFactoryImpl() let module = factory.create(for: ruuviTag) + module.output = self dfuModule = module transitionHandler - .navigationController? - .pushViewController( + .present( module.viewController, animated: true ) - transitionHandler - .navigationController? + module.viewController .presentationController? .delegate = self } @@ -264,6 +263,16 @@ extension DashboardRouter: UIAdaptivePresentationControllerDelegate { func presentationControllerShouldDismiss( _: UIPresentationController ) -> Bool { - delegate.shouldDismissDiscover() + if let dfuModule { + dfuModule.isSafeToDismiss() + } else { + delegate.shouldDismissDiscover() + } + } +} + +extension DashboardRouter: DFUModuleOutput { + func dfuModuleSuccessfullyUpgraded(_ dfuModule: DFUModuleInput) { + dfuModule.viewController.dismiss(animated: true) } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift index 92711f5dd..b27e1467e 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Router/TagSettingsRouter.swift @@ -6,7 +6,7 @@ import UIKit class TagSettingsRouter: NSObject, TagSettingsRouterInput { weak var transitionHandler: UIViewController! - private var dfuModule: DFUModuleInput? + private weak var dfuModule: DFUModuleInput? private var backgroundSelectionModule: BackgroundSelectionModuleInput? func dismiss(completion: (() -> Void)?) { @@ -62,15 +62,14 @@ class TagSettingsRouter: NSObject, TagSettingsRouterInput { func openUpdateFirmware(ruuviTag: RuuviTagSensor) { let factory: DFUModuleFactory = DFUModuleFactoryImpl() let module = factory.create(for: ruuviTag) + module.output = self dfuModule = module transitionHandler - .navigationController? - .pushViewController( + .present( module.viewController, animated: true ) - transitionHandler - .navigationController? + module.viewController .presentationController? .delegate = self } @@ -119,6 +118,12 @@ class TagSettingsRouter: NSObject, TagSettingsRouterInput { extension TagSettingsRouter: UIAdaptivePresentationControllerDelegate { func presentationControllerShouldDismiss(_: UIPresentationController) -> Bool { - dfuModule?.isSafeToDismiss() ?? false + dfuModule?.isSafeToDismiss() ?? true + } +} + +extension TagSettingsRouter: DFUModuleOutput { + func dfuModuleSuccessfullyUpgraded(_ dfuModule: DFUModuleInput) { + dfuModule.viewController.dismiss(animated: true) } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUModuleInput.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUModuleInput.swift index ae5064321..23e69038a 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUModuleInput.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUModuleInput.swift @@ -4,6 +4,10 @@ import UIKit protocol DFUModuleInput: AnyObject { var viewController: UIViewController { get } - + var output: DFUModuleOutput? { get set } func isSafeToDismiss() -> Bool } + +protocol DFUModuleOutput: AnyObject { + func dfuModuleSuccessfullyUpgraded(_ dfuModule: DFUModuleInput) +} diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift index 4e625e42e..a76405f2c 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/Presenter/DFUPresenter.swift @@ -15,12 +15,13 @@ final class DFUPresenter: DFUModuleInput { if let view = weakView { return view } else { + viewModel.output = self let view = UIHostingController(rootView: DFUUIView(viewModel: viewModel)) weakView = view return view } } - + var output: DFUModuleOutput? private weak var weakView: UIViewController? private let viewModel: DFUViewModel private let interactor: DFUInteractorInput @@ -79,3 +80,9 @@ final class DFUPresenter: DFUModuleInput { } } } + +extension DFUPresenter: DFUViewModelOutput { + func firmwareUpgradeDidFinishSuccessfully() { + output?.dfuModuleSuccessfullyUpgraded(self) + } +} diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift index dbd4243e3..d842c5b0b 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/DFUViewModel.swift @@ -11,12 +11,18 @@ import RuuviPool import RuuviPresenters import RuuviStorage +protocol DFUViewModelOutput: AnyObject { + func firmwareUpgradeDidFinishSuccessfully() +} + final class DFUViewModel: ObservableObject { @Published private(set) var state: State = .idle @Published var downloadProgress: Double = 0 @Published var flashProgress: Double = 0 @Published var isMigrationFailed: Bool = false + var output: DFUViewModelOutput? + private var bag = Set() private let input = PassthroughSubject() private let interactor: DFUInteractorInput @@ -39,16 +45,6 @@ final class DFUViewModel: ObservableObject { } } - private class RuuviTagPropertiesDaemonPair: NSObject { - var ruuviTag: AnyRuuviTagSensor - var device: RuuviTag - - init(ruuviTag: AnyRuuviTagSensor, device: RuuviTag) { - self.ruuviTag = ruuviTag - self.device = device - } - } - init( interactor: DFUInteractorInput, foreground: BTForeground, @@ -105,6 +101,10 @@ final class DFUViewModel: ObservableObject { input.send(event) } + func finish() { + output?.firmwareUpgradeDidFinishSuccessfully() + } + func storeUpdatedFirmware(currentRelease: CurrentRelease?) { guard ruuviTag.luid != nil else { return } if ruuviTag.macId != nil { diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift index abea5d4e1..99f016e56 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/DFU/View/SwiftUI/DFUUIView.swift @@ -32,6 +32,7 @@ struct DFUUIView: View { let successfulTitle = RuuviLocalization.DFUUIView.successfulTitle let errorTitle = RuuviLocalization.ErrorPresenterAlert.error let dbMigrationErrorTitle = RuuviLocalization.DFUUIView.DBMigration.Error.message + let finish = RuuviLocalization.DfuFlash.Finish.text } private let muliBold16 = Font(UIFont.Muli(.bold, size: 16)) @@ -65,9 +66,11 @@ struct DFUUIView: View { }) .onAppear { viewModel.send(event: .onAppear) + UIApplication.shared.isIdleTimerDisabled = true } .onDisappear { viewModel.restartPropertiesDaemon() + UIApplication.shared.isIdleTimerDisabled = false } } @@ -433,16 +436,38 @@ struct DFUUIView: View { .eraseToAnyView() case let .firmwareAfterUpdate(currentRelease): viewModel.storeUpdatedFirmware(currentRelease: currentRelease) - return Text(texts.successfulTitle) - .font(muliRegular16) - .foregroundColor(RuuviColor.textColor.swiftUIColor) - .frame( - maxWidth: .infinity, - maxHeight: .infinity, - alignment: .topLeading + return VStack { + Text(texts.successfulTitle) + .font(muliRegular16) + .foregroundColor(RuuviColor.textColor.swiftUIColor) + .frame( + maxWidth: .infinity, + maxHeight: .infinity, + alignment: .topLeading + ) + .padding() + Button( + action: { + viewModel.finish() + }, + label: { + Text(texts.finish) + .font(muliBold16) + .frame(maxWidth: .infinity) + } + ) + .buttonStyle( + LargeButtonStyle( + backgroundColor: RuuviColor.tintColor.swiftUIColor, + foregroundColor: Color.white, + isDisabled: false + ) ) .padding() - .eraseToAnyView() + .frame(maxWidth: .infinity) + } + .padding() + .eraseToAnyView() } } diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift index 14ac4b772..58f11692b 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/TagSettings/Submodules/Owner/Router/OwnerRouter.swift @@ -2,9 +2,9 @@ import LightRoute import RuuviOntology import UIKit -final class OwnerRouter: OwnerRouterInput { +final class OwnerRouter: NSObject, OwnerRouterInput { weak var transitionHandler: UIViewController! - private var dfuModule: DFUModuleInput? + private weak var dfuModule: DFUModuleInput? func dismiss() { try! transitionHandler.closeCurrentModule().perform() @@ -13,12 +13,27 @@ final class OwnerRouter: OwnerRouterInput { func openUpdateFirmware(ruuviTag: RuuviTagSensor) { let factory: DFUModuleFactory = DFUModuleFactoryImpl() let module = factory.create(for: ruuviTag) + module.output = self dfuModule = module transitionHandler - .navigationController? - .pushViewController( + .present( module.viewController, animated: true ) + module.viewController + .presentationController? + .delegate = self + } +} + +extension OwnerRouter: UIAdaptivePresentationControllerDelegate { + func presentationControllerShouldDismiss(_: UIPresentationController) -> Bool { + dfuModule?.isSafeToDismiss() ?? true + } +} + +extension OwnerRouter: DFUModuleOutput { + func dfuModuleSuccessfullyUpgraded(_ dfuModule: DFUModuleInput) { + dfuModule.viewController.dismiss(animated: true) } } diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscoverFactory.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscoverFactory.swift index 34e46614f..ab3768a43 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscoverFactory.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/RuuviDiscoverFactory.swift @@ -2,6 +2,8 @@ import BTKit import Foundation import RuuviContext import RuuviCore +import RuuviDaemon +import RuuviDFU import RuuviFirmware import RuuviLocal import RuuviPresenters @@ -14,6 +16,9 @@ public struct RuuviDiscoverDependencies { var permissionsManager: RuuviCorePermission var permissionPresenter: PermissionPresenter var foreground: BTForeground + var background: BTBackground + var propertiesDaemon: RuuviTagPropertiesDaemon + var ruuviDFU: RuuviDFU var ruuviReactor: RuuviReactor var ruuviOwnershipService: RuuviServiceOwnership var firmwareBuilder: RuuviFirmwareBuilder @@ -24,6 +29,9 @@ public struct RuuviDiscoverDependencies { permissionsManager: RuuviCorePermission, permissionPresenter: PermissionPresenter, foreground: BTForeground, + background: BTBackground, + propertiesDaemon: RuuviTagPropertiesDaemon, + ruuviDFU: RuuviDFU, ruuviReactor: RuuviReactor, ruuviOwnershipService: RuuviServiceOwnership, firmwareBuilder: RuuviFirmwareBuilder @@ -33,6 +41,9 @@ public struct RuuviDiscoverDependencies { self.permissionsManager = permissionsManager self.permissionPresenter = permissionPresenter self.foreground = foreground + self.background = background + self.propertiesDaemon = propertiesDaemon + self.ruuviDFU = ruuviDFU self.ruuviReactor = ruuviReactor self.ruuviOwnershipService = ruuviOwnershipService self.firmwareBuilder = firmwareBuilder @@ -49,6 +60,9 @@ public final class RuuviDiscoverFactory { presenter.permissionsManager = dependencies.permissionsManager presenter.permissionPresenter = dependencies.permissionPresenter presenter.foreground = dependencies.foreground + presenter.background = dependencies.background + presenter.propertiesDaemon = dependencies.propertiesDaemon + presenter.ruuviDFU = dependencies.ruuviDFU presenter.ruuviReactor = dependencies.ruuviReactor presenter.ruuviOwnershipService = dependencies.ruuviOwnershipService presenter.firmwareBuilder = dependencies.firmwareBuilder diff --git a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift index 26dee4504..edbdbc3c0 100644 --- a/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift +++ b/Modules/RuuviDiscover/Sources/RuuviDiscover/VMP/Presenter/DiscoverPresenter.swift @@ -6,6 +6,8 @@ import Foundation import Future import RuuviContext import RuuviCore +import RuuviDaemon +import RuuviDFU import RuuviFirmware import RuuviLocal import RuuviLocalization @@ -35,6 +37,9 @@ class DiscoverPresenter: NSObject, RuuviDiscover { var errorPresenter: ErrorPresenter! var activityPresenter: ActivityPresenter! var foreground: BTForeground! + var background: BTBackground! + var propertiesDaemon: RuuviTagPropertiesDaemon! + var ruuviDFU: RuuviDFU! var permissionsManager: RuuviCorePermission! var permissionPresenter: PermissionPresenter! var ruuviReactor: RuuviReactor! @@ -261,7 +266,16 @@ extension DiscoverPresenter: DiscoverViewOutput { func viewDidAskToUpgradeFirmware(of sensor: NFCSensor?) { guard let sensor else { return } - let firmwareModule = firmwareBuilder.build(uuid: sensor.id, currentFirmware: sensor.firmwareVersion) + let firmwareModule = firmwareBuilder.build( + uuid: sensor.id, + currentFirmware: sensor.firmwareVersion, + dependencies: RuuviFirmwareDependencies( + background: background, + foreground: foreground, + propertiesDaemon: propertiesDaemon, + ruuviDFU: ruuviDFU + ) + ) firmwareModule.output = self viewController.present(firmwareModule.viewController, animated: true) self.firmwareModule = firmwareModule @@ -276,7 +290,16 @@ extension DiscoverPresenter: DiscoverViewOutput { } func viewDidConfirmToUpdateFirmware(for uuid: String) { - let firmwareModule = firmwareBuilder.build(uuid: uuid, currentFirmware: "<=2.5.9") + let firmwareModule = firmwareBuilder.build( + uuid: uuid, + currentFirmware: "<=2.5.9", + dependencies: RuuviFirmwareDependencies( + background: background, + foreground: foreground, + propertiesDaemon: propertiesDaemon, + ruuviDFU: ruuviDFU + ) + ) firmwareModule.output = self let firmwareViewController = firmwareModule.viewController firmwareViewController.presentationController?.delegate = self diff --git a/Modules/RuuviDiscover/target.yml b/Modules/RuuviDiscover/target.yml index 8d63f051f..be79ef3ca 100644 --- a/Modules/RuuviDiscover/target.yml +++ b/Modules/RuuviDiscover/target.yml @@ -11,6 +11,8 @@ targets: - package: Future - target: RuuviOntology - target: RuuviContext + - target: RuuviDaemon + - target: RuuviDFU - target: RuuviReactor - target: RuuviLocal - target: RuuviService diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift index 2bc3bda07..da14a76ed 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwareInteractor.swift @@ -1,6 +1,7 @@ import BTKit import Combine import Foundation +import RuuviDaemon import RuuviDFU struct CurrentRelease { @@ -21,6 +22,7 @@ final class FirmwareInteractor { var batteryIsLow = CurrentValueSubject(false) private let background: BTBackground private let foreground: BTForeground + private let propertiesDaemon: RuuviTagPropertiesDaemon private let firmwareRepository: FirmwareRepository private let ruuviDFU: RuuviDFU private var ruuviTagObservationToken: ObservationToken? @@ -28,11 +30,13 @@ final class FirmwareInteractor { init( background: BTBackground, foreground: BTForeground, + propertiesDaemon: RuuviTagPropertiesDaemon, ruuviDFU: RuuviDFU, firmwareRepository: FirmwareRepository ) { self.background = background self.foreground = foreground + self.propertiesDaemon = propertiesDaemon self.ruuviDFU = ruuviDFU self.firmwareRepository = firmwareRepository } @@ -41,6 +45,10 @@ final class FirmwareInteractor { ruuviTagObservationToken?.invalidate() } + func restartPropertiesDaemon() { + propertiesDaemon.start() + } + func ensureBatteryHasEnoughPower(uuid: String) { ruuviTagObservationToken?.invalidate() ruuviTagObservationToken = foreground.observe(self, uuid: uuid) { observer, device in diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift index 673318a9b..60b2747c1 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/FirmwarePresenter.swift @@ -1,4 +1,5 @@ import BTKit +import RuuviDaemon import RuuviDFU import SwiftUI import UIKit @@ -35,6 +36,7 @@ final class FirmwarePresenter: RuuviFirmware { currentFirmware: String?, background: BTBackground, foreground: BTForeground, + propertiesDaemon: RuuviTagPropertiesDaemon, ruuviDFU: RuuviDFU, firmwareRepository: FirmwareRepository ) { @@ -43,6 +45,7 @@ final class FirmwarePresenter: RuuviFirmware { interactor = FirmwareInteractor( background: background, foreground: foreground, + propertiesDaemon: propertiesDaemon, ruuviDFU: ruuviDFU, firmwareRepository: firmwareRepository ) diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmwareBuilder.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmwareBuilder.swift index c4c63d5fe..437d08ef2 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmwareBuilder.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/RuuviFirmwareBuilder.swift @@ -1,11 +1,24 @@ import BTKit +import RuuviDaemon import RuuviDFU public struct RuuviFirmwareDependencies { public var background: BTBackground public var foreground: BTForeground + public var propertiesDaemon: RuuviTagPropertiesDaemon public var ruuviDFU: RuuviDFU - public var firmwareRepository: FirmwareRepository + + public init( + background: BTBackground, + foreground: BTForeground, + propertiesDaemon: RuuviTagPropertiesDaemon, + ruuviDFU: RuuviDFU + ) { + self.background = background + self.foreground = foreground + self.propertiesDaemon = propertiesDaemon + self.ruuviDFU = ruuviDFU + } } public final class RuuviFirmwareBuilder { @@ -14,27 +27,17 @@ public final class RuuviFirmwareBuilder { public func build( uuid: String, currentFirmware: String? = nil, - dependencies: RuuviFirmwareDependencies = .default + dependencies: RuuviFirmwareDependencies ) -> RuuviFirmware { let presenter = FirmwarePresenter( uuid: uuid, currentFirmware: currentFirmware, background: dependencies.background, foreground: dependencies.foreground, + propertiesDaemon: dependencies.propertiesDaemon, ruuviDFU: dependencies.ruuviDFU, - firmwareRepository: dependencies.firmwareRepository - ) - return presenter - } -} - -public extension RuuviFirmwareDependencies { - static var `default`: Self { - RuuviFirmwareDependencies( - background: BTKit.background, - foreground: BTKit.foreground, - ruuviDFU: RuuviDFUImpl.shared, firmwareRepository: FirmwareRepositoryImpl() ) + return presenter } } diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift index c8208ac9e..d90ff66ef 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareView.swift @@ -440,6 +440,11 @@ struct FirmwareView: View { .navigationBarBackButtonHidden(true) .onAppear { viewModel.send(event: .onAppear) + UIApplication.shared.isIdleTimerDisabled = true + } + .onDisappear { + viewModel.restartPropertiesDaemon() + UIApplication.shared.isIdleTimerDisabled = false } } } diff --git a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift index 0bc14e3f3..ee7327e71 100644 --- a/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift +++ b/Modules/RuuviFirmware/Sources/RuuviFirmware/SwiftUI/FirmwareViewModel.swift @@ -59,6 +59,10 @@ final class FirmwareViewModel: ObservableObject { func ensureBatteryHasEnoughPower(uuid: String) { interactor.ensureBatteryHasEnoughPower(uuid: uuid) } + + func restartPropertiesDaemon() { + interactor.restartPropertiesDaemon() + } } // MARK: - Feedbacks diff --git a/Modules/RuuviFirmware/target.yml b/Modules/RuuviFirmware/target.yml index 8b0f80002..10b30ff42 100644 --- a/Modules/RuuviFirmware/target.yml +++ b/Modules/RuuviFirmware/target.yml @@ -11,5 +11,6 @@ targets: - Module dependencies: - package: BTKit + - target: RuuviDaemon - target: RuuviDFU - target: RuuviLocalization