Compare commits

...

8 commits

Author SHA1 Message Date
Vadim
67818f7c8c run push on ubuntu-latest 2023-06-28 11:28:27 +02:00
Vadim
0c89affe1b added push to protected branch action 2023-06-28 11:11:24 +02:00
Vadim
7c1ec32453 Merge branch 'main' of https://github.com/vodemn/m3_lightmeter into feature/ML-61 2023-06-28 10:58:35 +02:00
Vadim
79d6034894
ML-61 Update version in pubspec & create Github release from GitHub actions (#84)
* Replaced zipping action

thedoctor0/zip-release@0.7.1 -> vimtor/action-zip@v1.1

* typo

* recursive: false

* typo

* typo

* debugSymbolLevel 'FULL'

* Update build.gradle

* Version bump

* wip

* wip

* `create-release` job

* removed changelog input

* added `needs`

* Version bump

* typo

* returned to macos-11 runner

* reverted pubspec version

* Version bump

* download artifacts

* Version bump

* extended artifacts path

* Version bump

* added LS

* Version bump

* Version bump

* rename files

* Version bump

* removed ls

* Version bump

* revert version

* typo
2023-06-27 12:17:35 +02:00
Vadim
8ff387c5c5 Fixed com.google.gms:google-services version 2023-06-23 11:41:58 +02:00
Vadim
2735f0b66f
ML-81 Unsaved fractional stops (#83)
* save stop type to sharedPrefs

* tests
2023-06-23 10:47:34 +02:00
Vadim
0c58134733
ML-62 Services tests (#82)
* removed redundant `UserPreferencesService` from `MeteringBloc`

* wip

* post-merge fixes

* `MeasureEvent` tests

* `MeasureEvent` tests revision

* `MeasureEvent` tests added timeout

* added stubs for other `MeteringBloc` events

* rewritten `MeteringBloc` logic

* wip

* `IsoChangedEvent` tests

* refined `IsoChangedEvent` tests

* `NdChangedEvent` tests

* `FilmChangedEvent` tests

* `MeteringCommunicationBloc` tests

* added test run to ci

* overriden `==` for `MeasuredState`

* `LuxMeteringEvent` tests

* refined `LuxMeteringEvent` tests

* rename

* wip

* wip

* `InitializeEvent`/`DeinitializeEvent` tests

* clamp minZoomLevel

* fixed `MeteringCommunicationBloc` tests

* wip

* `ZoomChangedEvent` tests

* `ExposureOffsetChangedEvent`/`ExposureOffsetResetEvent` tests

* renamed test groups

* added test coverage script

* improved `CameraContainerBloc` test coverage

* `EquipmentProfileChangedEvent` tests

* verify response vibration

* fixed running all tests

* `MeteringCommunicationBloc` equality tests

* `CameraContainerBloc` equality tests

* removed generated code from coverage

* `MeteringScreenLayoutFeature` tests

* `SupportedLocale` tests

* `Film` tests

* `CaffeineService` tests

* `UserPreferencesService` tests (wip)

* `LightSensorService` tests (wip)

* `migrateOldKeys()` tests

* ignore currently unused getters & setters

* gradle upgrade

* `reset(sharedPreferences);` calls count

* typo
2023-06-23 10:35:33 +02:00
Vadim
a7b8de6912
ML-62 Models tests (#80)
* removed redundant `UserPreferencesService` from `MeteringBloc`

* wip

* post-merge fixes

* `MeasureEvent` tests

* `MeasureEvent` tests revision

* `MeasureEvent` tests added timeout

* added stubs for other `MeteringBloc` events

* rewritten `MeteringBloc` logic

* wip

* `IsoChangedEvent` tests

* refined `IsoChangedEvent` tests

* `NdChangedEvent` tests

* `FilmChangedEvent` tests

* `MeteringCommunicationBloc` tests

* added test run to ci

* overriden `==` for `MeasuredState`

* `LuxMeteringEvent` tests

* refined `LuxMeteringEvent` tests

* rename

* wip

* wip

* `InitializeEvent`/`DeinitializeEvent` tests

* clamp minZoomLevel

* fixed `MeteringCommunicationBloc` tests

* wip

* `ZoomChangedEvent` tests

* `ExposureOffsetChangedEvent`/`ExposureOffsetResetEvent` tests

* renamed test groups

* added test coverage script

* improved `CameraContainerBloc` test coverage

* `EquipmentProfileChangedEvent` tests

* verify response vibration

* fixed running all tests

* `MeteringCommunicationBloc` equality tests

* `CameraContainerBloc` equality tests

* removed generated code from coverage

* `MeteringScreenLayoutFeature` tests

* `SupportedLocale` tests

* `Film` tests
2023-06-21 11:29:36 +02:00
15 changed files with 853 additions and 128 deletions

View file

@ -101,7 +101,7 @@ jobs:
update-version-in-repo: update-version-in-repo:
name: Update repo version name: Update repo version
needs: [build] needs: [build]
runs-on: macos-11 runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
with: with:
@ -110,14 +110,19 @@ jobs:
- name: Increment build number & replace version number - name: Increment build number & replace version number
run: perl -i -pe 's/^(version:\s+)(\d+\.\d+\.\d+)(\+)(\d+)$/$1."${{ github.event.inputs.version }}".$3.($4+1)/e' pubspec.yaml run: perl -i -pe 's/^(version:\s+)(\d+\.\d+\.\d+)(\+)(\d+)$/$1."${{ github.event.inputs.version }}".$3.($4+1)/e' pubspec.yaml
- name: Commit and push changes - name: Commit changes
run: | run: |
git config --global user.name "vodemn" git config --global user.name "vodemn"
git config --global user.email "vadim.turko@gmail.com" git config --global user.email "vadim.turko@gmail.com"
git add -A git add -A
git commit -m "Version bump" git commit -m "Version bump"
git push
- name: Push to main
uses: CasperWA/push-protected@v2
with:
token: ${{ secrets.PUSH_TO_MAIN_TOKEN }}
branch: main
unprotect_reviews: true
create-release: create-release:
name: Create Github release name: Create Github release

View file

@ -33,10 +33,6 @@ apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
gradle.beforeProject({ project->
project.setProperty("target-platform", "android-arm,android-arm64")
})
android { android {
compileSdkVersion 33 compileSdkVersion 33
ndkVersion flutter.ndkVersion ndkVersion flutter.ndkVersion
@ -112,5 +108,5 @@ flutter {
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "com.android.billingclient:billing-ktx:5.1.0" implementation "com.android.billingclient:billing-ktx:6.0.0"
} }

View file

@ -6,8 +6,8 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.2.1' classpath 'com.android.tools.build:gradle:7.4.2'
classpath 'com.google.gms:google-services:4.3.10' classpath 'com.google.gms:google-services:4.3.15'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }

View file

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip

View file

@ -9,7 +9,7 @@ class CaffeineService {
return _methodChannel.invokeMethod<bool>("isKeepScreenOn").then((value) => value!); return _methodChannel.invokeMethod<bool>("isKeepScreenOn").then((value) => value!);
} }
Future<void> keepScreenOn(bool keep) async { Future<bool> keepScreenOn(bool keep) async {
await _methodChannel.invokeMethod<bool>("setKeepScreenOn", keep); return _methodChannel.invokeMethod<bool>("setKeepScreenOn", keep).then((value) => value!);
} }
} }

View file

@ -23,6 +23,8 @@ double log10polynomian(
/// do not have any reciprocity failure information, as these films are ment to be used in cinema /// do not have any reciprocity failure information, as these films are ment to be used in cinema
/// with appropriate light and pretty short shutter speeds. /// with appropriate light and pretty short shutter speeds.
/// ///
/// Because of this: https://github.com/dart-lang/sdk/issues/38934#issuecomment-803938315
/// `super` calls are ignored in test coverage
class Film { class Film {
final String name; final String name;
final int iso; final int iso;
@ -78,26 +80,26 @@ class Film {
/// https://www.tate.org.uk/documents/598/page_6_7_agfa_stocks_0.pdf /// https://www.tate.org.uk/documents/598/page_6_7_agfa_stocks_0.pdf
/// https://www.filmwasters.com/forum/index.php?topic=5298.0 /// https://www.filmwasters.com/forum/index.php?topic=5298.0
// {{1,1.87},{2,3.73},{3,8.06},{4,13.93},{5,21.28},{6,23.00},{7,30.12},{8,38.05},{9,44.75},{10,50.12},{20,117},{30,202},{40,293},{50,413},{60,547},{70,694},{80,853},{90,1022},{100,1202}}; // {{1,1.87},{2,3.73},{3,8.06},{4,13.93},{5,21.28},{6,23.00},{7,30.12},{8,38.05},{9,44.75},{10,50.12},{20,117},{30,202},{40,293},{50,413},{60,547},{70,694},{80,853},{90,1022},{100,1202}};
class AgfaFilm extends Film { // class AgfaFilm extends Film {
final double a; // final double a;
final double b; // final double b;
final double c; // final double c;
const AgfaFilm.apx100() // const AgfaFilm.apx100()
: a = 1, // : a = 1,
b = 5, // b = 5,
c = 2, // c = 2,
super('Agfa APX 100', 100); // super('Agfa APX 100', 100); // coverage:ignore-line
const AgfaFilm.apx400() // const AgfaFilm.apx400()
: a = 1.5, // : a = 1.5,
b = 4.5, // b = 4.5,
c = 3, // c = 3,
super('Agfa APX 400', 400); // super('Agfa APX 400', 400); // coverage:ignore-line
@override // @override
double reciprocityFormula(double t) => t * log10polynomian(t, a, b, c); // double reciprocityFormula(double t) => t * log10polynomian(t, a, b, c);
} // }
class FomapanFilm extends Film { class FomapanFilm extends Film {
final double a; final double a;
@ -109,21 +111,21 @@ class FomapanFilm extends Film {
: a = 1, : a = 1,
b = 5, b = 5,
c = 2, c = 2,
super('Fomapan CREATIVE 100', 100); super('Fomapan CREATIVE 100', 100); // coverage:ignore-line
/// https://www.foma.cz/en/fomapan-200 /// https://www.foma.cz/en/fomapan-200
const FomapanFilm.creative200() const FomapanFilm.creative200()
: a = 1.5, : a = 1.5,
b = 4.5, b = 4.5,
c = 3, c = 3,
super('Fomapan CREATIVE 200', 200); super('Fomapan CREATIVE 200', 200); // coverage:ignore-line
/// https://www.foma.cz/en/fomapan-100 /// https://www.foma.cz/en/fomapan-100
const FomapanFilm.action400() const FomapanFilm.action400()
: a = -1.25, : a = -1.25, // coverage:ignore-line
b = 5.75, b = 5.75,
c = 1.5, c = 1.5,
super('Fomapan ACTION 400', 400); super('Fomapan ACTION 400', 400); // coverage:ignore-line
@override @override
double reciprocityFormula(double t) => t * log10polynomian(t, a, b, c); double reciprocityFormula(double t) => t * log10polynomian(t, a, b, c);
@ -135,57 +137,57 @@ class IlfordFilm extends Film {
/// https://www.ilfordphoto.com/amfile/file/download/file/1948/product/1650/ /// https://www.ilfordphoto.com/amfile/file/download/file/1948/product/1650/
const IlfordFilm.ortho() const IlfordFilm.ortho()
: reciprocityPower = 1.25, : reciprocityPower = 1.25,
super('Ilford ORTHO+', 80); super('Ilford ORTHO+', 80); // coverage:ignore-line
/// https://www.ilfordphoto.com/amfile/file/download/file/1919/product/686/ /// https://www.ilfordphoto.com/amfile/file/download/file/1919/product/686/
const IlfordFilm.fp4() const IlfordFilm.fp4()
: reciprocityPower = 1.26, : reciprocityPower = 1.26,
super('Ilford FP4+', 125); super('Ilford FP4+', 125); // coverage:ignore-line
/// https://www.ilfordphoto.com/amfile/file/download/file/1903/product/691/ /// https://www.ilfordphoto.com/amfile/file/download/file/1903/product/691/
const IlfordFilm.hp5() const IlfordFilm.hp5()
: reciprocityPower = 1.31, : reciprocityPower = 1.31,
super('Ilford HP5+', 400); super('Ilford HP5+', 400); // coverage:ignore-line
/// https://www.ilfordphoto.com/amfile/file/download/file/3/product/679/ /// https://www.ilfordphoto.com/amfile/file/download/file/3/product/679/
const IlfordFilm.delta100() const IlfordFilm.delta100()
: reciprocityPower = 1.26, : reciprocityPower = 1.26,
super('Ilford DELTA 100', 100); super('Ilford DELTA 100', 100); // coverage:ignore-line
/// https://www.ilfordphoto.com/amfile/file/download/file/1915/product/684/ /// https://www.ilfordphoto.com/amfile/file/download/file/1915/product/684/
const IlfordFilm.delta400() const IlfordFilm.delta400()
: reciprocityPower = 1.41, : reciprocityPower = 1.41,
super('Ilford DELTA 400', 400); super('Ilford DELTA 400', 400); // coverage:ignore-line
/// https://www.ilfordphoto.com/amfile/file/download/file/1913/product/682/ /// https://www.ilfordphoto.com/amfile/file/download/file/1913/product/682/
const IlfordFilm.delta3200() const IlfordFilm.delta3200()
: reciprocityPower = 1.33, : reciprocityPower = 1.33,
super('Ilford DELTA 3200', 3200); super('Ilford DELTA 3200', 3200); // coverage:ignore-line
/// https://www.ilfordphoto.com/amfile/file/download/file/1905/product/699/ /// https://www.ilfordphoto.com/amfile/file/download/file/1905/product/699/
const IlfordFilm.panf() const IlfordFilm.panf()
: reciprocityPower = 1.33, : reciprocityPower = 1.33,
super('Ilford Pan F+', 50); super('Ilford Pan F+', 50); // coverage:ignore-line
/// https://www.ilfordphoto.com/amfile/file/download/file/1907/product/701/ /// https://www.ilfordphoto.com/amfile/file/download/file/1907/product/701/
const IlfordFilm.sfx200() const IlfordFilm.sfx200()
: reciprocityPower = 1.31, : reciprocityPower = 1.31,
super('Ilford SFX 200', 200); super('Ilford SFX 200', 200); // coverage:ignore-line
/// https://www.ilfordphoto.com/amfile/file/download/file/1909/product/703/ /// https://www.ilfordphoto.com/amfile/file/download/file/1909/product/703/
const IlfordFilm.xp2super() const IlfordFilm.xp2super()
: reciprocityPower = 1.31, : reciprocityPower = 1.31,
super('Ilford XP2 SUPER', 400); super('Ilford XP2 SUPER', 400); // coverage:ignore-line
/// https://www.ilfordphoto.com/amfile/file/download/file/1958/product/696/ /// https://www.ilfordphoto.com/amfile/file/download/file/1958/product/696/
const IlfordFilm.pan100() const IlfordFilm.pan100()
: reciprocityPower = 1.26, : reciprocityPower = 1.26,
super('Kentemere 100', 100); super('Kentemere 100', 100); // coverage:ignore-line
/// https://www.ilfordphoto.com/amfile/file/download/file/1959/product/697/ /// https://www.ilfordphoto.com/amfile/file/download/file/1959/product/697/
const IlfordFilm.pan400() const IlfordFilm.pan400()
: reciprocityPower = 1.30, : reciprocityPower = 1.30,
super('Kentemere 400', 400); super('Kentemere 400', 400); // coverage:ignore-line
@override @override
double reciprocityFormula(double t) => pow(t, reciprocityPower).toDouble(); double reciprocityFormula(double t) => pow(t, reciprocityPower).toDouble();
@ -197,34 +199,34 @@ class KodakFilm extends Film {
final double c; final double c;
const KodakFilm.tmax100() const KodakFilm.tmax100()
: a = 1 / 6, : a = 1 / 6, // coverage:ignore-line
b = 0, b = 0, // coverage:ignore-line
c = 4 / 3, c = 4 / 3, // coverage:ignore-line
super('Kodak T-MAX 100', 100); super('Kodak T-MAX 100', 100); // coverage:ignore-line
const KodakFilm.tmax400() const KodakFilm.tmax400()
: a = 2 / 3, : a = 2 / 3, // coverage:ignore-line
b = -1 / 2, b = -1 / 2, // coverage:ignore-line
c = 4 / 3, c = 4 / 3, // coverage:ignore-line
super('Kodak T-MAX 400', 400); super('Kodak T-MAX 400', 400); // coverage:ignore-line
const KodakFilm.tmax3200() const KodakFilm.tmax3200()
: a = 7 / 6, : a = 7 / 6, // coverage:ignore-line
b = -1, b = -1, // coverage:ignore-line
c = 4 / 3, c = 4 / 3, // coverage:ignore-line
super('Kodak T-MAX 3200', 3200); super('Kodak T-MAX 3200', 3200); // coverage:ignore-line
const KodakFilm.trix320() const KodakFilm.trix320()
: a = 2, : a = 2,
b = 1, b = 1,
c = 2, c = 2,
super('Kodak TRI-X 320', 320); super('Kodak TRI-X 320', 320); // coverage:ignore-line
const KodakFilm.trix400() const KodakFilm.trix400()
: a = 2, : a = 2,
b = 1, b = 1,
c = 2, c = 2,
super('Kodak TRI-X 400', 400); super('Kodak TRI-X 400', 400); // coverage:ignore-line
@override @override
double reciprocityFormula(double t) => t * log10polynomian(t, a, b, c); double reciprocityFormula(double t) => t * log10polynomian(t, a, b, c);

View file

@ -1,20 +1,5 @@
import 'package:intl/intl.dart';
enum SupportedLocale { en, fr, ru } enum SupportedLocale { en, fr, ru }
SupportedLocale get currentLanguage {
switch (Intl.getCurrentLocale()) {
case "en":
return SupportedLocale.en;
case "fr":
return SupportedLocale.fr;
case "ru":
return SupportedLocale.ru;
default:
return SupportedLocale.en;
}
}
extension SupportedLocaleExtension on SupportedLocale { extension SupportedLocaleExtension on SupportedLocale {
String get intlName => toString().replaceAll("SupportedLocale.", ""); String get intlName => toString().replaceAll("SupportedLocale.", "");

View file

@ -10,30 +10,32 @@ import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
class UserPreferencesService { class UserPreferencesService {
static const _isoKey = "iso"; static const isoKey = "iso";
static const _ndFilterKey = "ndFilter"; static const ndFilterKey = "ndFilter";
static const _evSourceTypeKey = "evSourceType"; static const evSourceTypeKey = "evSourceType";
static const _cameraEvCalibrationKey = "cameraEvCalibration"; static const stopTypeKey = "stopType";
static const _lightSensorEvCalibrationKey = "lightSensorEvCalibration"; static const cameraEvCalibrationKey = "cameraEvCalibration";
static const _meteringScreenLayoutKey = "meteringScreenLayout"; static const lightSensorEvCalibrationKey = "lightSensorEvCalibration";
static const _filmKey = "film"; static const meteringScreenLayoutKey = "meteringScreenLayout";
static const filmKey = "film";
static const _caffeineKey = "caffeine"; static const caffeineKey = "caffeine";
static const _hapticsKey = "haptics"; static const hapticsKey = "haptics";
static const _localeKey = "locale"; static const localeKey = "locale";
static const _themeTypeKey = "themeType"; static const themeTypeKey = "themeType";
static const _primaryColorKey = "primaryColor"; static const primaryColorKey = "primaryColor";
static const _dynamicColorKey = "dynamicColor"; static const dynamicColorKey = "dynamicColor";
final SharedPreferences _sharedPreferences; final SharedPreferences _sharedPreferences;
UserPreferencesService(this._sharedPreferences) { UserPreferencesService(this._sharedPreferences) {
_migrateOldKeys(); migrateOldKeys();
} }
Future<void> _migrateOldKeys() async { @visibleForTesting
Future<void> migrateOldKeys() async {
final legacyIsoIndex = _sharedPreferences.getInt("curIsoIndex"); final legacyIsoIndex = _sharedPreferences.getInt("curIsoIndex");
if (legacyIsoIndex != null) { if (legacyIsoIndex != null) {
iso = IsoValue.values[legacyIsoIndex]; iso = IsoValue.values[legacyIsoIndex];
@ -69,22 +71,25 @@ class UserPreferencesService {
} }
IsoValue get iso => IsoValue get iso =>
IsoValue.values.firstWhere((v) => v.value == (_sharedPreferences.getInt(_isoKey) ?? 100)); IsoValue.values.firstWhere((v) => v.value == (_sharedPreferences.getInt(isoKey) ?? 100));
set iso(IsoValue value) => _sharedPreferences.setInt(_isoKey, value.value); set iso(IsoValue value) => _sharedPreferences.setInt(isoKey, value.value);
NdValue get ndFilter => NdValue get ndFilter =>
NdValue.values.firstWhere((v) => v.value == (_sharedPreferences.getInt(_ndFilterKey) ?? 0)); NdValue.values.firstWhere((v) => v.value == (_sharedPreferences.getInt(ndFilterKey) ?? 0));
set ndFilter(NdValue value) => _sharedPreferences.setInt(_ndFilterKey, value.value); set ndFilter(NdValue value) => _sharedPreferences.setInt(ndFilterKey, value.value);
EvSourceType get evSourceType => EvSourceType get evSourceType =>
EvSourceType.values[_sharedPreferences.getInt(_evSourceTypeKey) ?? 0]; EvSourceType.values[_sharedPreferences.getInt(evSourceTypeKey) ?? 0];
set evSourceType(EvSourceType value) => _sharedPreferences.setInt(_evSourceTypeKey, value.index); set evSourceType(EvSourceType value) => _sharedPreferences.setInt(evSourceTypeKey, value.index);
bool get caffeine => _sharedPreferences.getBool(_caffeineKey) ?? false; bool get caffeine => _sharedPreferences.getBool(caffeineKey) ?? false;
set caffeine(bool value) => _sharedPreferences.setBool(_caffeineKey, value); set caffeine(bool value) => _sharedPreferences.setBool(caffeineKey, value);
StopType get stopType => StopType.values[_sharedPreferences.getInt(stopTypeKey) ?? 2];
set stopType(StopType value) => _sharedPreferences.setInt(stopTypeKey, value.index);
MeteringScreenLayoutConfig get meteringScreenLayout { MeteringScreenLayoutConfig get meteringScreenLayout {
final configJson = _sharedPreferences.getString(_meteringScreenLayoutKey); final configJson = _sharedPreferences.getString(meteringScreenLayoutKey);
if (configJson != null) { if (configJson != null) {
return MeteringScreenLayoutConfigJson.fromJson( return MeteringScreenLayoutConfigJson.fromJson(
json.decode(configJson) as Map<String, dynamic>, json.decode(configJson) as Map<String, dynamic>,
@ -98,44 +103,44 @@ class UserPreferencesService {
} }
set meteringScreenLayout(MeteringScreenLayoutConfig value) => set meteringScreenLayout(MeteringScreenLayoutConfig value) =>
_sharedPreferences.setString(_meteringScreenLayoutKey, json.encode(value.toJson())); _sharedPreferences.setString(meteringScreenLayoutKey, json.encode(value.toJson()));
bool get haptics => _sharedPreferences.getBool(_hapticsKey) ?? true; bool get haptics => _sharedPreferences.getBool(hapticsKey) ?? true;
set haptics(bool value) => _sharedPreferences.setBool(_hapticsKey, value); set haptics(bool value) => _sharedPreferences.setBool(hapticsKey, value);
SupportedLocale get locale => SupportedLocale.values.firstWhere( SupportedLocale get locale => SupportedLocale.values.firstWhere(
(e) => e.toString() == _sharedPreferences.getString(_localeKey), (e) => e.toString() == _sharedPreferences.getString(localeKey),
orElse: () => SupportedLocale.en, orElse: () => SupportedLocale.en,
); );
set locale(SupportedLocale value) => _sharedPreferences.setString(_localeKey, value.toString()); set locale(SupportedLocale value) => _sharedPreferences.setString(localeKey, value.toString());
double get cameraEvCalibration => _sharedPreferences.getDouble(_cameraEvCalibrationKey) ?? 0.0; double get cameraEvCalibration => _sharedPreferences.getDouble(cameraEvCalibrationKey) ?? 0.0;
set cameraEvCalibration(double value) => set cameraEvCalibration(double value) =>
_sharedPreferences.setDouble(_cameraEvCalibrationKey, value); _sharedPreferences.setDouble(cameraEvCalibrationKey, value);
double get lightSensorEvCalibration => double get lightSensorEvCalibration =>
_sharedPreferences.getDouble(_lightSensorEvCalibrationKey) ?? 0.0; _sharedPreferences.getDouble(lightSensorEvCalibrationKey) ?? 0.0;
set lightSensorEvCalibration(double value) => set lightSensorEvCalibration(double value) =>
_sharedPreferences.setDouble(_lightSensorEvCalibrationKey, value); _sharedPreferences.setDouble(lightSensorEvCalibrationKey, value);
ThemeType get themeType => ThemeType.values[_sharedPreferences.getInt(_themeTypeKey) ?? 0]; ThemeType get themeType => ThemeType.values[_sharedPreferences.getInt(themeTypeKey) ?? 0];
set themeType(ThemeType value) => _sharedPreferences.setInt(_themeTypeKey, value.index); set themeType(ThemeType value) => _sharedPreferences.setInt(themeTypeKey, value.index);
Color get primaryColor => Color(_sharedPreferences.getInt(_primaryColorKey) ?? 0xff2196f3); Color get primaryColor => Color(_sharedPreferences.getInt(primaryColorKey) ?? 0xff2196f3);
set primaryColor(Color value) => _sharedPreferences.setInt(_primaryColorKey, value.value); set primaryColor(Color value) => _sharedPreferences.setInt(primaryColorKey, value.value);
bool get dynamicColor => _sharedPreferences.getBool(_dynamicColorKey) ?? false; bool get dynamicColor => _sharedPreferences.getBool(dynamicColorKey) ?? false;
set dynamicColor(bool value) => _sharedPreferences.setBool(_dynamicColorKey, value); set dynamicColor(bool value) => _sharedPreferences.setBool(dynamicColorKey, value);
Film get film => Film.values.firstWhere( Film get film => Film.values.firstWhere(
(e) => e.name == _sharedPreferences.getString(_filmKey), (e) => e.name == _sharedPreferences.getString(filmKey),
orElse: () => Film.values.first, orElse: () => Film.values.first,
); );
set film(Film value) => _sharedPreferences.setString(_filmKey, value.name); set film(Film value) => _sharedPreferences.setString(filmKey, value.name);
String get selectedEquipmentProfileId => ''; String get selectedEquipmentProfileId => ''; // coverage:ignore-line
set selectedEquipmentProfileId(String id) {} set selectedEquipmentProfileId(String id) {} // coverage:ignore-line
List<EquipmentProfileData> get equipmentProfiles => []; List<EquipmentProfileData> get equipmentProfiles => []; // coverage:ignore-line
set equipmentProfiles(List<EquipmentProfileData> profiles) {} set equipmentProfiles(List<EquipmentProfileData> profiles) {} // coverage:ignore-line
} }

View file

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:lightmeter/data/shared_prefs_service.dart';
import 'package:lightmeter/utils/inherited_generics.dart'; import 'package:lightmeter/utils/inherited_generics.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
@ -16,14 +17,12 @@ class StopTypeProvider extends StatefulWidget {
} }
class StopTypeProviderState extends State<StopTypeProvider> { class StopTypeProviderState extends State<StopTypeProvider> {
StopType _stopType = StopType.third; late StopType _stopType;
StopType get stopType => _stopType; @override
void initState() {
void set(StopType type) { super.initState();
setState(() { _stopType = context.get<UserPreferencesService>().stopType;
_stopType = type;
});
} }
@override @override
@ -33,4 +32,11 @@ class StopTypeProviderState extends State<StopTypeProvider> {
child: widget.child, child: widget.child,
); );
} }
void set(StopType type) {
setState(() {
_stopType = type;
});
context.get<UserPreferencesService>().stopType = type;
}
} }

View file

@ -0,0 +1,76 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:lightmeter/data/caffeine_service.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
late CaffeineService service;
const methodChannel = MethodChannel('com.vodemn.lightmeter/keepScreenOn');
Future<Object?>? methodCallSuccessHandler(MethodCall methodCall) async {
switch (methodCall.method) {
case "isKeepScreenOn":
return true;
case "setKeepScreenOn":
return methodCall.arguments as bool;
default:
return null;
}
}
setUp(() {
service = const CaffeineService();
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(methodChannel, methodCallSuccessHandler);
});
tearDown(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(methodChannel, null);
});
group(
'isKeepScreenOn()',
() {
test('true', () async {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(methodChannel, null);
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(methodChannel, (methodCall) async {
switch (methodCall.method) {
case "isKeepScreenOn":
return true;
default:
return null;
}
});
expectLater(service.isKeepScreenOn(), completion(true));
});
test('false', () async {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(methodChannel, null);
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(methodChannel, (methodCall) async {
switch (methodCall.method) {
case "isKeepScreenOn":
return false;
default:
return null;
}
});
expectLater(service.isKeepScreenOn(), completion(false));
});
},
);
group(
'keepScreenOn()',
() {
test('true', () async => expectLater(service.keepScreenOn(true), completion(true)));
test('false', () async => expectLater(service.keepScreenOn(false), completion(false)));
},
);
}

View file

@ -0,0 +1,71 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:lightmeter/data/light_sensor_service.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
late LightSensorService service;
const methodChannel = MethodChannel('system_feature');
// TODO: add event channel mock
//const eventChannel = EventChannel('light.eventChannel');
setUp(() {
service = const LightSensorService();
});
tearDown(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(methodChannel, null);
});
group(
'hasSensor()',
() {
test('true', () async {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(methodChannel, null);
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(methodChannel, (methodCall) async {
switch (methodCall.method) {
case "sensor":
return true;
default:
return null;
}
});
expectLater(service.hasSensor(), completion(true));
});
test('false', () async {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(methodChannel, null);
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(methodChannel, (methodCall) async {
switch (methodCall.method) {
case "sensor":
return false;
default:
return null;
}
});
expectLater(service.hasSensor(), completion(false));
});
test('null', () async {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(methodChannel, null);
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(methodChannel, (methodCall) async {
switch (methodCall.method) {
case "sensor":
return null;
default:
return null;
}
});
expectLater(service.hasSensor(), completion(false));
});
},
);
}

View file

@ -0,0 +1,121 @@
import 'package:lightmeter/data/models/film.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import 'package:test/test.dart';
void main() {
test('iso', () {
expect(const Film.other().iso, 0);
expect(const FomapanFilm.creative100().iso, 100);
expect(const FomapanFilm.creative200().iso, 200);
expect(const FomapanFilm.action400().iso, 400);
expect(const IlfordFilm.ortho().iso, 80);
expect(const IlfordFilm.delta100().iso, 100);
expect(const IlfordFilm.delta400().iso, 400);
expect(const IlfordFilm.delta3200().iso, 3200);
expect(const IlfordFilm.fp4().iso, 125);
expect(const IlfordFilm.hp5().iso, 400);
expect(const IlfordFilm.panf().iso, 50);
expect(const IlfordFilm.sfx200().iso, 200);
expect(const IlfordFilm.xp2super().iso, 400);
expect(const IlfordFilm.pan100().iso, 100);
expect(const IlfordFilm.pan400().iso, 400);
expect(const KodakFilm.tmax100().iso, 100);
expect(const KodakFilm.tmax400().iso, 400);
expect(const KodakFilm.tmax3200().iso, 3200);
expect(const KodakFilm.trix320().iso, 320);
expect(const KodakFilm.trix400().iso, 400);
});
test('toString()', () {
expect(const Film.other().toString(), "");
expect(const FomapanFilm.creative100().toString(), "Fomapan CREATIVE 100");
expect(const FomapanFilm.creative200().toString(), "Fomapan CREATIVE 200");
expect(const FomapanFilm.action400().toString(), "Fomapan ACTION 400");
expect(const IlfordFilm.ortho().toString(), "Ilford ORTHO+");
expect(const IlfordFilm.delta100().toString(), "Ilford DELTA 100");
expect(const IlfordFilm.delta400().toString(), "Ilford DELTA 400");
expect(const IlfordFilm.delta3200().toString(), "Ilford DELTA 3200");
expect(const IlfordFilm.fp4().toString(), "Ilford FP4+");
expect(const IlfordFilm.hp5().toString(), "Ilford HP5+");
expect(const IlfordFilm.panf().toString(), "Ilford Pan F+");
expect(const IlfordFilm.sfx200().toString(), "Ilford SFX 200");
expect(const IlfordFilm.xp2super().toString(), "Ilford XP2 SUPER");
expect(const IlfordFilm.pan100().toString(), "Kentemere 100");
expect(const IlfordFilm.pan400().toString(), "Kentemere 400");
expect(const KodakFilm.tmax100().toString(), "Kodak T-MAX 100");
expect(const KodakFilm.tmax400().toString(), "Kodak T-MAX 400");
expect(const KodakFilm.tmax3200().toString(), "Kodak T-MAX 3200");
expect(const KodakFilm.trix320().toString(), "Kodak TRI-X 320");
expect(const KodakFilm.trix400().toString(), "Kodak TRI-X 400");
});
group(
'reciprocityFailure',
() {
const inputSpeeds = [
ShutterSpeedValue(1000, true, StopType.full),
ShutterSpeedValue(1, false, StopType.full),
ShutterSpeedValue(16, false, StopType.full)
];
test('No change `Film.other()`', () {
expect(
const Film.other().reciprocityFailure(inputSpeeds[0]),
const ShutterSpeedValue(1000, true, StopType.full),
);
expect(
const Film.other().reciprocityFailure(inputSpeeds[1]),
const ShutterSpeedValue(1, false, StopType.full),
);
expect(
const Film.other().reciprocityFailure(inputSpeeds[2]),
const ShutterSpeedValue(16, false, StopType.full),
);
});
test('pow `IlfordFilm.delta100()`', () {
expect(
const IlfordFilm.delta100().reciprocityFailure(inputSpeeds[0]),
const ShutterSpeedValue(1000, true, StopType.full),
);
expect(
const IlfordFilm.delta100().reciprocityFailure(inputSpeeds[1]),
const ShutterSpeedValue(1, false, StopType.full),
);
expect(
const IlfordFilm.delta100().reciprocityFailure(inputSpeeds[2]),
const ShutterSpeedValue(32.899642452994128, false, StopType.full),
);
});
test('log10polynomian `FomapanFilm.creative100()`', () {
expect(
const FomapanFilm.creative100().reciprocityFailure(inputSpeeds[0]),
const ShutterSpeedValue(1000, true, StopType.full),
);
expect(
const FomapanFilm.creative100().reciprocityFailure(inputSpeeds[1]),
const ShutterSpeedValue(2, false, StopType.full),
);
expect(
const FomapanFilm.creative100().reciprocityFailure(inputSpeeds[2]),
const ShutterSpeedValue(151.52807753457483, false, StopType.full),
);
});
test('log10polynomian `Kodak.tmax400()`', () {
expect(
const KodakFilm.tmax400().reciprocityFailure(inputSpeeds[0]),
const ShutterSpeedValue(1000, true, StopType.full),
);
expect(
const KodakFilm.tmax400().reciprocityFailure(inputSpeeds[1]),
const ShutterSpeedValue(1.3333333333333333, false, StopType.full),
);
expect(
const KodakFilm.tmax400().reciprocityFailure(inputSpeeds[2]),
const ShutterSpeedValue(27.166026086819844, false, StopType.full),
);
});
},
);
}

View file

@ -0,0 +1,31 @@
import 'package:lightmeter/data/models/metering_screen_layout_config.dart';
import 'package:test/test.dart';
void main() {
test('fromJson', () {
expect(
MeteringScreenLayoutConfigJson.fromJson({'0': true, '1': true}),
{
MeteringScreenLayoutFeature.extremeExposurePairs: true,
MeteringScreenLayoutFeature.filmPicker: true,
},
);
expect(
MeteringScreenLayoutConfigJson.fromJson({'0': false, '1': false}),
{
MeteringScreenLayoutFeature.extremeExposurePairs: false,
MeteringScreenLayoutFeature.filmPicker: false,
},
);
});
test('toJson', () {
expect(
{
MeteringScreenLayoutFeature.extremeExposurePairs: true,
MeteringScreenLayoutFeature.filmPicker: true,
}.toJson(),
{'0': true, '1': true},
);
});
}

View file

@ -0,0 +1,16 @@
import 'package:lightmeter/data/models/supported_locale.dart';
import 'package:test/test.dart';
void main() {
test('intlName', () {
expect(SupportedLocale.en.intlName, 'en');
expect(SupportedLocale.fr.intlName, 'fr');
expect(SupportedLocale.ru.intlName, 'ru');
});
test('localizedName', () {
expect(SupportedLocale.en.localizedName, 'English');
expect(SupportedLocale.fr.localizedName, 'Français');
expect(SupportedLocale.ru.localizedName, 'Русский');
});
}

View file

@ -0,0 +1,411 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:lightmeter/data/models/ev_source_type.dart';
import 'package:lightmeter/data/models/film.dart';
import 'package:lightmeter/data/models/metering_screen_layout_config.dart';
import 'package:lightmeter/data/models/supported_locale.dart';
import 'package:lightmeter/data/models/theme_type.dart';
import 'package:lightmeter/data/shared_prefs_service.dart';
import 'package:lightmeter/providers/theme_provider.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
import 'package:mocktail/mocktail.dart';
import 'package:shared_preferences/shared_preferences.dart';
class _MockSharedPreferences extends Mock implements SharedPreferences {}
void main() {
late _MockSharedPreferences sharedPreferences;
late UserPreferencesService service;
setUpAll(() {
sharedPreferences = _MockSharedPreferences();
service = UserPreferencesService(sharedPreferences);
});
tearDown(() {
reset(sharedPreferences);
});
group('migrateOldKeys()', () {
test('no legacy keys', () async {
when(() => sharedPreferences.getInt("curIsoIndex")).thenReturn(null);
when(() => sharedPreferences.getInt("curndIndex")).thenReturn(null);
when(() => sharedPreferences.getDouble("cameraCalibr")).thenReturn(null);
when(() => sharedPreferences.getDouble("sensorCalibr")).thenReturn(null);
when(() => sharedPreferences.getBool("vibrate")).thenReturn(null);
when(() => sharedPreferences.remove("curIsoIndex")).thenAnswer((_) async => true);
when(() => sharedPreferences.remove("curndIndex")).thenAnswer((_) async => true);
when(() => sharedPreferences.remove("cameraCalibr")).thenAnswer((_) async => true);
when(() => sharedPreferences.remove("sensorCalibr")).thenAnswer((_) async => true);
when(() => sharedPreferences.remove("vibrate")).thenAnswer((_) async => true);
await service.migrateOldKeys();
verifyNever(() => sharedPreferences.remove("curIsoIndex"));
verifyNever(() => sharedPreferences.remove("curndIndex"));
verifyNever(() => sharedPreferences.remove("cameraCalibr"));
verifyNever(() => sharedPreferences.remove("sensorCalibr"));
verifyNever(() => sharedPreferences.remove("vibrate"));
});
test('migrate all keys', () async {
when(() => sharedPreferences.getInt("curIsoIndex")).thenReturn(1);
when(() => sharedPreferences.getInt("curndIndex")).thenReturn(0);
when(() => sharedPreferences.getDouble("cameraCalibr")).thenReturn(1.0);
when(() => sharedPreferences.getDouble("sensorCalibr")).thenReturn(-1.0);
when(() => sharedPreferences.getBool("vibrate")).thenReturn(false);
when(
() => sharedPreferences.setInt(UserPreferencesService.isoKey, IsoValue.values[1].value),
).thenAnswer((_) => Future.value(true));
when(
() => sharedPreferences.setInt(UserPreferencesService.ndFilterKey, NdValue.values[0].value),
).thenAnswer((_) => Future.value(true));
when(
() => sharedPreferences.setDouble(UserPreferencesService.cameraEvCalibrationKey, 1.0),
).thenAnswer((_) => Future.value(true));
when(
() => sharedPreferences.setDouble(UserPreferencesService.lightSensorEvCalibrationKey, -1.0),
).thenAnswer((_) => Future.value(true));
when(
() => sharedPreferences.setBool(UserPreferencesService.hapticsKey, false),
).thenAnswer((_) => Future.value(true));
when(() => sharedPreferences.remove("curIsoIndex")).thenAnswer((_) async => true);
when(() => sharedPreferences.remove("curndIndex")).thenAnswer((_) async => true);
when(() => sharedPreferences.remove("cameraCalibr")).thenAnswer((_) async => true);
when(() => sharedPreferences.remove("sensorCalibr")).thenAnswer((_) async => true);
when(() => sharedPreferences.remove("vibrate")).thenAnswer((_) async => true);
await service.migrateOldKeys();
verify(() => sharedPreferences.remove("curIsoIndex")).called(1);
verify(() => sharedPreferences.remove("curndIndex")).called(1);
verify(() => sharedPreferences.remove("cameraCalibr")).called(1);
verify(() => sharedPreferences.remove("sensorCalibr")).called(1);
verify(() => sharedPreferences.remove("vibrate")).called(1);
});
});
group('iso', () {
test('get default', () {
when(() => sharedPreferences.getInt(UserPreferencesService.isoKey)).thenReturn(null);
expect(service.iso, const IsoValue(100, StopType.full));
});
test('get', () {
when(() => sharedPreferences.getInt(UserPreferencesService.isoKey)).thenReturn(100);
expect(service.iso, const IsoValue(100, StopType.full));
});
test('set', () {
when(() => sharedPreferences.setInt(UserPreferencesService.isoKey, 200))
.thenAnswer((_) => Future.value(true));
service.iso = const IsoValue(200, StopType.full);
verify(() => sharedPreferences.setInt(UserPreferencesService.isoKey, 200)).called(1);
});
});
group('ndFilter', () {
test('get default', () {
when(() => sharedPreferences.getInt(UserPreferencesService.ndFilterKey)).thenReturn(null);
expect(service.ndFilter, const NdValue(0));
});
test('get', () {
when(() => sharedPreferences.getInt(UserPreferencesService.ndFilterKey)).thenReturn(4);
expect(service.ndFilter, const NdValue(4));
});
test('set', () {
when(() => sharedPreferences.setInt(UserPreferencesService.ndFilterKey, 0))
.thenAnswer((_) => Future.value(true));
service.ndFilter = const NdValue(0);
verify(() => sharedPreferences.setInt(UserPreferencesService.ndFilterKey, 0)).called(1);
});
});
group('evSourceType', () {
test('get default', () {
when(() => sharedPreferences.getInt(UserPreferencesService.evSourceTypeKey)).thenReturn(null);
expect(service.evSourceType, EvSourceType.camera);
});
test('get', () {
when(() => sharedPreferences.getInt(UserPreferencesService.evSourceTypeKey)).thenReturn(1);
expect(service.evSourceType, EvSourceType.sensor);
});
test('set', () {
when(() => sharedPreferences.setInt(UserPreferencesService.evSourceTypeKey, 1))
.thenAnswer((_) => Future.value(true));
service.evSourceType = EvSourceType.sensor;
verify(() => sharedPreferences.setInt(UserPreferencesService.evSourceTypeKey, 1)).called(1);
});
});
group('caffeine', () {
test('get default', () {
when(() => sharedPreferences.getBool(UserPreferencesService.caffeineKey)).thenReturn(null);
expect(service.caffeine, false);
});
test('get', () {
when(() => sharedPreferences.getBool(UserPreferencesService.caffeineKey)).thenReturn(true);
expect(service.caffeine, true);
});
test('set', () {
when(() => sharedPreferences.setBool(UserPreferencesService.caffeineKey, false))
.thenAnswer((_) => Future.value(true));
service.caffeine = false;
verify(() => sharedPreferences.setBool(UserPreferencesService.caffeineKey, false)).called(1);
});
});
group('stopType', () {
test('get default', () {
when(() => sharedPreferences.getInt(UserPreferencesService.stopTypeKey)).thenReturn(null);
expect(service.stopType, StopType.third);
});
test('get', () {
when(() => sharedPreferences.getInt(UserPreferencesService.stopTypeKey)).thenReturn(1);
expect(service.stopType, StopType.half);
});
test('set', () {
when(() => sharedPreferences.setInt(UserPreferencesService.stopTypeKey, 0))
.thenAnswer((_) => Future.value(true));
service.stopType = StopType.full;
verify(() => sharedPreferences.setInt(UserPreferencesService.stopTypeKey, 0)).called(1);
});
});
group('meteringScreenLayout', () {
test('get default', () {
when(
() => sharedPreferences.getString(UserPreferencesService.meteringScreenLayoutKey),
).thenReturn(null);
expect(
service.meteringScreenLayout,
{
MeteringScreenLayoutFeature.extremeExposurePairs: true,
MeteringScreenLayoutFeature.filmPicker: true,
},
);
});
test('get', () {
when(
() => sharedPreferences.getString(UserPreferencesService.meteringScreenLayoutKey),
).thenReturn("""{"0":false,"1":true}""");
expect(
service.meteringScreenLayout,
{
MeteringScreenLayoutFeature.extremeExposurePairs: false,
MeteringScreenLayoutFeature.filmPicker: true,
},
);
});
test('set', () {
when(
() => sharedPreferences.setString(
UserPreferencesService.meteringScreenLayoutKey,
"""{"0":false,"1":true}""",
),
).thenAnswer((_) => Future.value(true));
service.meteringScreenLayout = {
MeteringScreenLayoutFeature.extremeExposurePairs: false,
MeteringScreenLayoutFeature.filmPicker: true,
};
verify(
() => sharedPreferences.setString(
UserPreferencesService.meteringScreenLayoutKey,
"""{"0":false,"1":true}""",
),
).called(1);
});
});
group('haptics', () {
test('get default', () {
when(() => sharedPreferences.getBool(UserPreferencesService.hapticsKey)).thenReturn(null);
expect(service.haptics, true);
});
test('get', () {
when(() => sharedPreferences.getBool(UserPreferencesService.hapticsKey)).thenReturn(true);
expect(service.haptics, true);
});
test('set', () {
when(() => sharedPreferences.setBool(UserPreferencesService.hapticsKey, false))
.thenAnswer((_) => Future.value(true));
service.haptics = false;
verify(() => sharedPreferences.setBool(UserPreferencesService.hapticsKey, false)).called(1);
});
});
group('locale', () {
test('get default', () {
when(() => sharedPreferences.getString(UserPreferencesService.localeKey)).thenReturn(null);
expect(service.locale, SupportedLocale.en);
});
test('get', () {
when(() => sharedPreferences.getString(UserPreferencesService.localeKey))
.thenReturn('SupportedLocale.ru');
expect(service.locale, SupportedLocale.ru);
});
test('set', () {
when(
() => sharedPreferences.setString(UserPreferencesService.localeKey, 'SupportedLocale.en'),
).thenAnswer((_) => Future.value(true));
service.locale = SupportedLocale.en;
verify(
() => sharedPreferences.setString(UserPreferencesService.localeKey, 'SupportedLocale.en'),
).called(1);
});
});
group('cameraEvCalibration', () {
test('get default', () {
when(() => sharedPreferences.getDouble(UserPreferencesService.cameraEvCalibrationKey))
.thenReturn(null);
expect(service.cameraEvCalibration, 0.0);
});
test('get', () {
when(() => sharedPreferences.getDouble(UserPreferencesService.cameraEvCalibrationKey))
.thenReturn(2.0);
expect(service.cameraEvCalibration, 2.0);
});
test('set', () {
when(
() => sharedPreferences.setDouble(UserPreferencesService.cameraEvCalibrationKey, 1.0),
).thenAnswer((_) => Future.value(true));
service.cameraEvCalibration = 1.0;
verify(
() => sharedPreferences.setDouble(UserPreferencesService.cameraEvCalibrationKey, 1.0),
).called(1);
});
});
group('lightSensorEvCalibration', () {
test('get default', () {
when(() => sharedPreferences.getDouble(UserPreferencesService.lightSensorEvCalibrationKey))
.thenReturn(null);
expect(service.lightSensorEvCalibration, 0.0);
});
test('get', () {
when(() => sharedPreferences.getDouble(UserPreferencesService.lightSensorEvCalibrationKey))
.thenReturn(2.0);
expect(service.lightSensorEvCalibration, 2.0);
});
test('set', () {
when(
() => sharedPreferences.setDouble(UserPreferencesService.lightSensorEvCalibrationKey, 1.0),
).thenAnswer((_) => Future.value(true));
service.lightSensorEvCalibration = 1.0;
verify(
() => sharedPreferences.setDouble(UserPreferencesService.lightSensorEvCalibrationKey, 1.0),
).called(1);
});
});
group('themeType', () {
test('get default', () {
when(() => sharedPreferences.getInt(UserPreferencesService.themeTypeKey)).thenReturn(null);
expect(service.themeType, ThemeType.light);
});
test('get', () {
when(() => sharedPreferences.getInt(UserPreferencesService.themeTypeKey)).thenReturn(1);
expect(service.themeType, ThemeType.dark);
});
test('set', () {
when(
() => sharedPreferences.setInt(UserPreferencesService.themeTypeKey, 1),
).thenAnswer((_) => Future.value(true));
service.themeType = ThemeType.dark;
verify(
() => sharedPreferences.setInt(UserPreferencesService.themeTypeKey, 1),
).called(1);
});
});
group('primaryColor', () {
test('get default', () {
when(() => sharedPreferences.getInt(UserPreferencesService.primaryColorKey)).thenReturn(null);
expect(service.primaryColor, ThemeProvider.primaryColorsList[5]);
});
test('get', () {
when(() => sharedPreferences.getInt(UserPreferencesService.primaryColorKey))
.thenReturn(0xff9c27b0);
expect(service.primaryColor, ThemeProvider.primaryColorsList[2]);
});
test('set', () {
when(
() => sharedPreferences.setInt(UserPreferencesService.primaryColorKey, 0xff000000),
).thenAnswer((_) => Future.value(true));
service.primaryColor = Colors.black;
verify(
() => sharedPreferences.setInt(UserPreferencesService.primaryColorKey, 0xff000000),
).called(1);
});
});
group('dynamicColor', () {
test('get default', () {
when(() => sharedPreferences.getBool(UserPreferencesService.dynamicColorKey))
.thenReturn(null);
expect(service.dynamicColor, false);
});
test('get', () {
when(() => sharedPreferences.getBool(UserPreferencesService.dynamicColorKey))
.thenReturn(true);
expect(service.dynamicColor, true);
});
test('set', () {
when(() => sharedPreferences.setBool(UserPreferencesService.dynamicColorKey, false))
.thenAnswer((_) => Future.value(true));
service.dynamicColor = false;
verify(() => sharedPreferences.setBool(UserPreferencesService.dynamicColorKey, false))
.called(1);
});
});
group('film', () {
test('get default', () {
when(() => sharedPreferences.getString(UserPreferencesService.filmKey)).thenReturn(null);
expect(service.film, Film.values.first);
});
test('get', () {
when(() => sharedPreferences.getString(UserPreferencesService.filmKey))
.thenReturn('Fomapan ACTION 400');
expect(service.film, const FomapanFilm.action400());
});
test('set', () {
when(() => sharedPreferences.setString(UserPreferencesService.filmKey, 'Fomapan ACTION 400'))
.thenAnswer((_) => Future.value(true));
service.film = const FomapanFilm.action400();
verify(
() => sharedPreferences.setString(UserPreferencesService.filmKey, 'Fomapan ACTION 400'),
).called(1);
});
});
}