diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/Assembly/BackgroundSelectionModuleFactory.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/Assembly/BackgroundSelectionModuleFactory.swift index 19a2dd86e..6323e878d 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/Assembly/BackgroundSelectionModuleFactory.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Dashboard/Background/Assembly/BackgroundSelectionModuleFactory.swift @@ -18,6 +18,7 @@ final class BackgroundSelectionModuleFactoryImpl: BackgroundSelectionModuleFacto presenter.photoPickerPresenter = r.resolve(PhotoPickerPresenter.self) presenter.ruuviSensorPropertiesService = r.resolve(RuuviServiceSensorProperties.self) presenter.ruuviLocalImages = r.resolve(RuuviLocalImages.self) + presenter.settings = r.resolve(RuuviLocalSettings.self) presenter.errorPresenter = r.resolve(ErrorPresenter.self) return presenter } 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 6e121e9f9..0e9e00849 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 @@ -31,6 +31,7 @@ final class BackgroundSelectionPresenter: BackgroundSelectionModuleInput { // TODO: Find out why backgroundToken is getting notification twice. /// A boolean to keep track of background upload for local sensors private var didUploadBackground: Bool = false + private let maxSize: CGSize = .init(width: 3000, height: 3000) var photoPickerPresenter: PhotoPickerPresenter! { didSet { @@ -40,6 +41,7 @@ final class BackgroundSelectionPresenter: BackgroundSelectionModuleInput { var ruuviSensorPropertiesService: RuuviServiceSensorProperties! var ruuviLocalImages: RuuviLocalImages! + var settings: RuuviLocalSettings! var errorPresenter: ErrorPresenter! init(ruuviTag: RuuviTagSensor?) { @@ -174,7 +176,9 @@ extension BackgroundSelectionPresenter: PhotoPickerPresenterDelegate { viewModel.isUploadingBackground.value = true ruuviSensorPropertiesService.set( image: photo, - for: ruuviTag + for: ruuviTag, + maxSize: maxSize, + compressionQuality: CGFloat(settings.imageCompressionQuality)*0.1 ).on(success: { [weak self] _ in self?.viewModel.isUploadingBackground.value = false self?.viewModel.background.value = photo diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift index 6c92959f7..8f3692c69 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/Presenter/DefaultsPresenter.swift @@ -56,6 +56,7 @@ extension DefaultsPresenter { buildChartDurationHours(), saveAdvertisementsInterval(), saveHeartbeatsForgroundInterval(), + buildImageCompressionQuality(), buildAskForReviewFirstTime(), buildAskForReviewLater(), buildDashboardCardTapAction(), @@ -261,6 +262,20 @@ extension DefaultsPresenter { return heartbeatsInterval } + private func buildImageCompressionQuality() -> DefaultsViewModel { + let viewModel = DefaultsViewModel() + viewModel.item.value = .imageCompressionQuality + viewModel.title = RuuviLocalization.Defaults.ImageCompressionQuality.title + viewModel.integer.value = settings.imageCompressionQuality + viewModel.unit = .decimal + viewModel.type.value = .stepper + + bind(viewModel.integer, fire: false) { observer, integer in + observer.settings.imageCompressionQuality = integer.bound + } + return viewModel + } + private func saveAdvertisementsInterval() -> DefaultsViewModel { let advertisementInterval = DefaultsViewModel() advertisementInterval.title = RuuviLocalization.ForegroundRow.Advertisement.title diff --git a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewModel.swift b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewModel.swift index ee09160e3..8b17f97b2 100644 --- a/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewModel.swift +++ b/Apps/RuuviStation/Sources/Classes/Presentation/Modules/Settings/Submodules/Defaults/View/DefaultsViewModel.swift @@ -6,11 +6,17 @@ enum DefaultsType { case plain } +enum DefaultItem { + case imageCompressionQuality + case other +} + class DefaultsViewModel: Identifiable { var id = UUID().uuidString var title: String? var type: Observable = .init() + var item: Observable = .init() // Value for switcher type var boolean: Observable = .init() var hideStatusLabel: Observable = .init(false) diff --git a/Apps/RuuviStation/Sources/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 index a922cdfdd..67f210111 100644 --- a/Apps/RuuviStation/Sources/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 @@ -8,6 +8,7 @@ protocol DefaultsStepperTableViewCellDelegate: AnyObject { class DefaultsStepperTableViewCell: UITableViewCell { weak var delegate: DefaultsStepperTableViewCellDelegate? var unit: DefaultsIntegerUnit = .seconds + var item: DefaultItem? @IBOutlet var titleLabel: UILabel! @IBOutlet var stepper: UIStepper! @@ -31,11 +32,16 @@ class DefaultsStepperTableViewCell: UITableViewCell { case .decimal: "" } - switch unit { - case .hours, .minutes, .seconds: - titleLabel.text = prefix + " " + "(" + "\(result)" + " " + unitString + ")" - case .decimal: - titleLabel.text = prefix + " " + "(" + "\(result)" + ")" + switch item { + case .imageCompressionQuality: + titleLabel.text = prefix + " " + "(" + "\(result)" + "%)" + default: + switch unit { + case .hours, .minutes, .seconds: + titleLabel.text = prefix + " " + "(" + "\(result)" + " " + unitString + ")" + case .decimal: + titleLabel.text = prefix + " " + "(" + "\(result)" + ")" + } } delegate?.defaultsStepper(cell: self, didChange: result) } 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 9a761f685..82f18fdb4 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 @@ -48,7 +48,7 @@ extension DefaultsTableViewController { viewModels.count } - // swiftlint:disable:next function_body_length + // swiftlint:disable:next function_body_length cyclomatic_complexity override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let viewModel = viewModels[indexPath.row] switch viewModel.type.value { @@ -88,36 +88,48 @@ extension DefaultsTableViewController { ) as! DefaultsStepperTableViewCell // swiftlint:enable force_cast let title = viewModel.title ?? "" - let unitString: String - switch viewModel.unit { - case .hours: - unitString = RuuviLocalization.Defaults.Interval.Hour.string - cell.stepper.stepValue = 1 - case .minutes: - unitString = RuuviLocalization.Defaults.Interval.Min.string - cell.stepper.stepValue = 5 - case .seconds: - unitString = RuuviLocalization.Defaults.Interval.Sec.string - cell.stepper.stepValue = 30 - case .decimal: - unitString = "" - cell.stepper.stepValue = 5 - cell.stepper.minimumValue = 5 - } + cell.unit = viewModel.unit + cell.item = viewModel.item.value let result = viewModel.integer.value.bound - switch viewModel.unit { - case .hours, .minutes, .seconds: - cell.titleLabel.text = title + " " - + "(" + "\(result)" + " " - + unitString + ")" - case .decimal: - cell.titleLabel.text = title + " " + "(" + "\(result)" + ")" + switch viewModel.item.value { + case .imageCompressionQuality: + cell.titleLabel.text = title + " " + "(" + "\(result)" + "%)" + cell.stepper.stepValue = 10 + cell.stepper.minimumValue = 10 + cell.stepper.maximumValue = 100 + cell.stepper.value = Double(viewModel.integer.value.bound) + default: + let unitString: String + switch viewModel.unit { + case .hours: + unitString = RuuviLocalization.Defaults.Interval.Hour.string + cell.stepper.stepValue = 1 + case .minutes: + unitString = RuuviLocalization.Defaults.Interval.Min.string + cell.stepper.stepValue = 5 + case .seconds: + unitString = RuuviLocalization.Defaults.Interval.Sec.string + cell.stepper.stepValue = 30 + case .decimal: + unitString = "" + cell.stepper.stepValue = 5 + cell.stepper.minimumValue = 5 + } + switch viewModel.unit { + case .hours, .minutes, .seconds: + cell.titleLabel.text = title + " " + + "(" + "\(result)" + " " + + unitString + ")" + case .decimal: + cell.titleLabel.text = title + " " + "(" + "\(result)" + ")" + } + cell.stepper.value = Double(viewModel.integer.value.bound) } + 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 return cell default: diff --git a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift index 986d0a14a..829dc154e 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocal/RuuviLocalSettings.swift @@ -98,6 +98,7 @@ public protocol RuuviLocalSettings { var showSwitchStatusLabel: Bool { get set } var showAlertsRangeInGraph: Bool { get set } var useNewGraphRendering: Bool { get set } + var imageCompressionQuality: Int { get set } /// Syncs full history for all sensoers after code verification /// on sign in, before presenting dashboard. Heavy after sign in diff --git a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift index 21ddebb89..6d74f5c24 100644 --- a/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift +++ b/Packages/RuuviLocal/Sources/RuuviLocalUserDefaults/RuuviLocalSettingsUserDefaults.swift @@ -738,6 +738,9 @@ final class RuuviLocalSettingsUserDefaults: RuuviLocalSettings { var showAlertsRangeInGraph: Bool @UserDefault("SettingsUserDefaults.useNewGraphRendering", defaultValue: false) var useNewGraphRendering: Bool + // On a scale of 10-100, 100 being best quality, and 10 being the worst. + @UserDefault("SettingsUserDefaults.imageCompressionQuality", defaultValue: 40) + var imageCompressionQuality: Int @UserDefault("SettingsUserDefaults.historySyncLegacy", defaultValue: false) var historySyncLegacy: Bool diff --git a/Packages/RuuviService/Sources/RuuviService/RuuviServiceSensorProperties.swift b/Packages/RuuviService/Sources/RuuviService/RuuviServiceSensorProperties.swift index d129aa99c..40578ae21 100644 --- a/Packages/RuuviService/Sources/RuuviService/RuuviServiceSensorProperties.swift +++ b/Packages/RuuviService/Sources/RuuviService/RuuviServiceSensorProperties.swift @@ -15,7 +15,8 @@ public protocol RuuviServiceSensorProperties { image: UIImage, for sensor: RuuviTagSensor, progress: ((MACIdentifier, Double) -> Void)?, - maxSize: CGSize + maxSize: CGSize, + compressionQuality: CGFloat ) -> Future @discardableResult @@ -29,13 +30,16 @@ public protocol RuuviServiceSensorProperties { public extension RuuviServiceSensorProperties { func set( image: UIImage, - for sensor: RuuviTagSensor + for sensor: RuuviTagSensor, + maxSize: CGSize, + compressionQuality: CGFloat ) -> Future { set( image: image, for: sensor, progress: nil, - maxSize: CGSize(width: 3000, height: 3000) + maxSize: maxSize, + compressionQuality: compressionQuality ) } } diff --git a/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift b/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift index cd0d8d615..6d64a3ae9 100644 --- a/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift +++ b/Packages/RuuviService/Sources/RuuviServiceSensorProperties/RuuviServiceSensorPropertiesImpl.swift @@ -83,11 +83,12 @@ public final class RuuviServiceSensorPropertiesImpl: RuuviServiceSensorPropertie image: UIImage, for sensor: RuuviTagSensor, progress: ((MACIdentifier, Double) -> Void)?, - maxSize: CGSize + maxSize: CGSize, + compressionQuality: CGFloat ) -> Future { let promise = Promise() let croppedImage = coreImage.cropped(image: image, to: maxSize) - guard let jpegData = croppedImage.jpegData(compressionQuality: 0.6) + guard let jpegData = croppedImage.jpegData(compressionQuality: compressionQuality) else { promise.fail(error: .failedToGetJpegRepresentation) return promise.future diff --git a/station.localization b/station.localization index d81d9d9c4..0ad1be10d 160000 --- a/station.localization +++ b/station.localization @@ -1 +1 @@ -Subproject commit d81d9d9c4f18552eb06372e8c6daac88f3e8d20d +Subproject commit 0ad1be10d8ab0da62e475e1e282d4a2844a14a0c