From 7a7fae9a386e055d272d203ffd8340e24feec384 Mon Sep 17 00:00:00 2001 From: Anton Gustafsson Date: Sat, 18 Nov 2023 18:22:27 +0100 Subject: [PATCH] Feat add option to prefer cl over ml (#438) * feat: add option to prefer cl over ml * fix --- .eslintrc.json | 3 +- android/app/build.gradle | 4 +- .../android/en-US/changelogs/14300.txt | 1 + .../cocktail-dialog/cocktail-dialog.html | 2 +- .../cocktail-dialog/cocktail-dialog.ts | 2 + src/converters/amount-format.ts | 8 +- src/domain/entities/setting-entity.ts | 3 +- src/locales/en/translation.json | 3 +- src/modules/home/home.ts | 2 +- src/modules/user/settings/settings.html | 14 ++- src/modules/user/settings/settings.ts | 10 +++ src/services/local-storage-service.ts | 9 ++ tests/converters/amount-format.test.ts | 88 +++++++++++++++++++ 13 files changed, 138 insertions(+), 11 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/14300.txt create mode 100644 tests/converters/amount-format.test.ts diff --git a/.eslintrc.json b/.eslintrc.json index 2e5c9d62..57bf7280 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -13,7 +13,8 @@ "@typescript-eslint/no-unused-vars": [1], "@typescript-eslint/no-empty-function": [1], "@typescript-eslint/no-inferrable-types": [1], - "@typescript-eslint/no-extraneous-class": [1] + "@typescript-eslint/no-extraneous-class": [1], + "eqeqeq": ["error", "always", { "null": "ignore" }] }, "overrides": [ diff --git a/android/app/build.gradle b/android/app/build.gradle index 574d51a0..493bf849 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "com.moimob.drinkable" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 14201 - versionName "1.42.1" + versionCode 14300 + versionName "1.43.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/fastlane/metadata/android/en-US/changelogs/14300.txt b/fastlane/metadata/android/en-US/changelogs/14300.txt new file mode 100644 index 00000000..4841b04f --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/14300.txt @@ -0,0 +1 @@ +• Added option for users using the metric measurement system to select their preferred unit between ml and cl \ No newline at end of file diff --git a/src/components/dialogs/cocktail-dialog/cocktail-dialog.html b/src/components/dialogs/cocktail-dialog/cocktail-dialog.html index b2e8caf6..16bade38 100644 --- a/src/components/dialogs/cocktail-dialog/cocktail-dialog.html +++ b/src/components/dialogs/cocktail-dialog/cocktail-dialog.html @@ -242,7 +242,7 @@

- ${ingredientGroup.amount | amountFormat:multiplier:ingredientGroup.unit} + ${ingredientGroup.amount | amountFormat:multiplier:ingredientGroup.unit:preferCl}

!this.extendedIngredientGroup.map(x => x.ingredientId).includes(x.id) ); this.noteState = this.cocktail.notes?.length > 0 ? 'exists' : 'none'; + this.preferCl = this._localStorageService.getPreferCl(); } attached() { diff --git a/src/converters/amount-format.ts b/src/converters/amount-format.ts index 0723a88b..cd478ae9 100644 --- a/src/converters/amount-format.ts +++ b/src/converters/amount-format.ts @@ -8,7 +8,7 @@ import { convertToFraction } from 'functions/utils'; export class AmountFormatValueConverter { constructor(private _localStorageService: LocalStorageService) {} - toView(value: string, multiplier: number, unit: Unit) { + toView(value: string, multiplier: number, unit: Unit, preferCl: boolean) { if (value === '' || value === undefined) { return value; } @@ -22,6 +22,12 @@ export class AmountFormatValueConverter { const fraction = convertToFraction(newValue); + if (preferCl && newUnit === Unit.ML && system === MessuarementSystem.Metric) { + const clValue = newValue / 10; + const clFraction = convertToFraction(clValue); + return `${clFraction} ${Unit.CL}`; + } + return newUnit === Unit.None ? fraction : `${fraction} ${newUnit}`; } getUnit(unit: Unit, system: MessuarementSystem) { diff --git a/src/domain/entities/setting-entity.ts b/src/domain/entities/setting-entity.ts index b685a072..e58434f6 100644 --- a/src/domain/entities/setting-entity.ts +++ b/src/domain/entities/setting-entity.ts @@ -1,8 +1,9 @@ export class SettingEntity { - language?: string; showMocktails: boolean; + language?: string; exploreWidgetState?: number; lastSelectedIngredientListId?: number; + preferCl?: boolean; constructor() { this.showMocktails = false; diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 5d61e70b..aaa194ae 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -166,5 +166,6 @@ "copy-name-to-clipboard": "Copy name to Clipboard", "copied-to-clipboard": "Copied to Clipboard", "add-to-favorites": "Add to Favorites", - "remove-from-favorites": "Remove from Favorites" + "remove-from-favorites": "Remove from Favorites", + "preferred-unit": "Preferred Unit" } diff --git a/src/modules/home/home.ts b/src/modules/home/home.ts index e027688b..189b5ddb 100644 --- a/src/modules/home/home.ts +++ b/src/modules/home/home.ts @@ -35,7 +35,7 @@ export class Home { } private setupSnowflakes() { - if (new Date().getMonth() == 11) { + if (new Date().getMonth() === 11) { this.snowflakes = new Snowflakes({ count: 10, speed: 0.3, diff --git a/src/modules/user/settings/settings.html b/src/modules/user/settings/settings.html index ada4e1c6..4bf51191 100644 --- a/src/modules/user/settings/settings.html +++ b/src/modules/user/settings/settings.html @@ -9,7 +9,7 @@
-
+
@@ -23,14 +23,22 @@
-
+
+

+ +
+ +
-
+
diff --git a/src/modules/user/settings/settings.ts b/src/modules/user/settings/settings.ts index 00de4854..0b6c2eba 100644 --- a/src/modules/user/settings/settings.ts +++ b/src/modules/user/settings/settings.ts @@ -13,6 +13,7 @@ export class Settings { @observable public selectedTheme: string; @observable public selectedLanguage: string; @observable public selectedMessuarementSystem: MessuarementSystem; + @observable public preferCl: boolean; @observable public showMocktails: boolean; public themes = [ @@ -73,6 +74,7 @@ export class Settings { public attached() { this.selectedTheme = this._themeService.getLocalStorageResult(); this.selectedMessuarementSystem = this._localStorageService.getMessuarementSystem(); + this.preferCl = this._localStorageService.getPreferCl(); this._settings = this._localStorageService.getSettings(); this.selectedLanguage = this._settings.language; this.showMocktails = this._settings.showMocktails; @@ -93,6 +95,14 @@ export class Settings { await this._localStorageService.updateMessuarmentSystem(newValue); } + async preferClChanged(newValue: boolean, oldValue: boolean) { + if (oldValue === undefined) { + return; + } + + await this._localStorageService.updatePreferCL(newValue); + } + async showMocktailsChanged(newValue: boolean, oldValue: boolean) { if (oldValue === undefined) { return; diff --git a/src/services/local-storage-service.ts b/src/services/local-storage-service.ts index 5574673e..5a7867a9 100644 --- a/src/services/local-storage-service.ts +++ b/src/services/local-storage-service.ts @@ -215,6 +215,10 @@ export class LocalStorageService { return this._activeIngredientListId; } + public getPreferCl() { + return this._settings.preferCl ?? false; + } + public getIngredientList() { return this._ingredientLists.find(x => x.id === this._activeIngredientListId); } @@ -254,6 +258,11 @@ export class LocalStorageService { this._activeIngredientListId = id; } + public async updatePreferCL(preferCl: boolean) { + this._settings.preferCl = preferCl; + await this.updateSettings(this._settings); + } + public async keyExists(key: string): Promise { const { keys } = await Preferences.keys(); if (keys.length > 0 && keys.includes(key)) { diff --git a/tests/converters/amount-format.test.ts b/tests/converters/amount-format.test.ts new file mode 100644 index 00000000..625ebe0d --- /dev/null +++ b/tests/converters/amount-format.test.ts @@ -0,0 +1,88 @@ +import { LocalStorageService } from 'services/local-storage-service'; +import { expect } from '@jest/globals'; +import { AmountFormatValueConverter } from '../../src/converters/amount-format'; +import { Unit } from 'domain/enums/unit'; +import { MessuarementSystem } from 'domain/enums/messuarement-system'; + +describe('IngredientService', () => { + let localStorageService: LocalStorageService; + let sut: AmountFormatValueConverter; + + beforeEach(async () => { + localStorageService = new LocalStorageService(); + await localStorageService.initialize(); + + sut = new AmountFormatValueConverter(localStorageService); + }); + + afterEach(() => { + window.localStorage.clear(); + }); + + describe('Metric', () => { + beforeEach(async () => { + await localStorageService.updateMessuarmentSystem(MessuarementSystem.Metric); + }); + + test('Pass Milliliter - Should return same as input', () => { + const result = sut.toView('10', 1, Unit.ML, false); + + expect(result).toEqual('10 ml'); + }); + + test('Pass Milliliter and multiplyer - Should return multiplied value', () => { + const result = sut.toView('10', 3, Unit.ML, false); + + expect(result).toEqual('30 ml'); + }); + + test('Pass Milliliter with preferCl - Should return value in Cl', () => { + const result = sut.toView('10', 1, Unit.ML, true); + + expect(result).toEqual('1 cl'); + }); + + test('Pass Milliliter with preferCl - Should handle fraction', () => { + const result = sut.toView('5', 1, Unit.ML, true); + + expect(result).toEqual('1/2 cl'); + }); + + test('Pass Milliliter and multiplyer with preferCl - Should return multiplied value but in Cl', () => { + const result = sut.toView('10', 3, Unit.ML, true); + + expect(result).toEqual('3 cl'); + }); + }); + + describe('Imperial', () => { + test('Pass Milliliter - Should return in fl oz', () => { + const result = sut.toView('30', 1, Unit.ML, false); + + expect(result).toEqual('1 fl oz'); + }); + + test('Pass Milliliter with preferCl- Should return same as above', () => { + const result = sut.toView('30', 1, Unit.ML, true); + + expect(result).toEqual('1 fl oz'); + }); + + test('Pass Milliliter and multiplyer - Should return multiplied value', () => { + const result = sut.toView('30', 3, Unit.ML, false); + + expect(result).toEqual('3 fl oz'); + }); + + test('Pass Milliliter with preferCl - Should return value in Cl', () => { + const result = sut.toView('15', 1, Unit.ML, false); + + expect(result).toEqual('1/2 fl oz'); + }); + + test('should return empty string when value is empty', () => { + const result = sut.toView('', 1, Unit.ML, false); + expect(result).toEqual(''); + }); + }); +});