mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-21 15:00:40 +00:00
ML-107 Films filter (#118)
* added stub `FilmsProvider` * moved dialogs to the shared folder * typo * separated `EquipmentSettingsSection` * copy * `IAPBuilder` -> `IAPListTile` * moved `Film` to resources repo * fixed films selection * untied iso and selected film * removed film from exposure pairs building * indicate push/pull * copy * Update .gitignore * fixed extreme exposure pairs reciprocity display * sync with iap changes * sync iap stub with iap changes * added reciprocity description * added workspace file * Update .gitignore
This commit is contained in:
parent
1be7c3be48
commit
cc9f162933
58 changed files with 592 additions and 978 deletions
9
.github/workflows/pr_check.yml
vendored
9
.github/workflows/pr_check.yml
vendored
|
@ -15,7 +15,7 @@ jobs:
|
||||||
analyze_and_test:
|
analyze_and_test:
|
||||||
name: Analyze & test
|
name: Analyze & test
|
||||||
runs-on: macos-11
|
runs-on: macos-11
|
||||||
timeout-minutes: 10
|
timeout-minutes: 5
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
|
@ -47,3 +47,10 @@ jobs:
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: flutter test
|
run: flutter test
|
||||||
|
|
||||||
|
- name: Analyze project source with stub
|
||||||
|
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
|
||||||
|
run: |
|
||||||
|
bash ./.github/scripts/stub_iap.sh
|
||||||
|
flutter pub get
|
||||||
|
flutter analyze lib --fatal-infos
|
||||||
|
|
25
README.md
25
README.md
|
@ -33,11 +33,7 @@ Without further delay behold my new Lightmeter app inspired by Material You (a.k
|
||||||
|
|
||||||
To build this app you need to install Flutter 3.10.0 stable. [How to install](https://docs.flutter.dev/get-started/install).
|
To build this app you need to install Flutter 3.10.0 stable. [How to install](https://docs.flutter.dev/get-started/install).
|
||||||
|
|
||||||
### 2. (Optional) Install Firebase
|
### 3. Project setup
|
||||||
|
|
||||||
Out of the box Firebase Crashlytics won't work. If you want to add Crashlytics to your local build please follow [this guide](https://firebase.google.com/docs/flutter/setup).
|
|
||||||
|
|
||||||
### 3. Get packages
|
|
||||||
|
|
||||||
As part of the app's functionallity is in the private repo, you have to replace these lines in _pubspec.yaml_:
|
As part of the app's functionallity is in the private repo, you have to replace these lines in _pubspec.yaml_:
|
||||||
|
|
||||||
|
@ -47,24 +43,39 @@ m3_lightmeter_iap:
|
||||||
url: "https://github.com/vodemn/m3_lightmeter_iap"
|
url: "https://github.com/vodemn/m3_lightmeter_iap"
|
||||||
ref: main
|
ref: main
|
||||||
```
|
```
|
||||||
|
|
||||||
with these:
|
with these:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
m3_lightmeter_iap:
|
m3_lightmeter_iap:
|
||||||
path: iap
|
path: iap
|
||||||
```
|
```
|
||||||
and run `flutter pub get` from the _iap/_ folder.
|
|
||||||
|
You can do it simply by running the script:
|
||||||
|
|
||||||
|
```console
|
||||||
|
sh .github/scripts/stub_iap.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
> If you are using VSCode, you can open the workspace like so: _File -> Open Workspace from File -> m3_lightmeter.code-workspace_. Otherwise you have to run `flutter pub get` command from the iap folder.
|
||||||
|
|
||||||
Then you can fetch all the neccessary dependencies and generate translation files by running the following commands:
|
Then you can fetch all the neccessary dependencies and generate translation files by running the following commands:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
flutter pub get
|
flutter pub get
|
||||||
flutter pub run intl_utils:generate
|
flutter pub run intl_utils:generate
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. Build
|
### 4. (Optional) Install Firebase
|
||||||
|
|
||||||
|
Out of the box Firebase Crashlytics won't work. If you want to add Crashlytics to your local build please follow [this guide](https://firebase.google.com/docs/flutter/setup).
|
||||||
|
|
||||||
|
### 5. Build
|
||||||
|
|
||||||
#### Android
|
#### Android
|
||||||
|
|
||||||
You can build an apk by running the following command from the root of the repository:
|
You can build an apk by running the following command from the root of the repository:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
flutter build apk --release --flavor dev --dart-define cameraPreviewAspectRatio=240/320 -t lib/main_dev.dart
|
flutter build apk --release --flavor dev --dart-define cameraPreviewAspectRatio=240/320 -t lib/main_dev.dart
|
||||||
```
|
```
|
||||||
|
|
|
@ -2,11 +2,13 @@ library m3_lightmeter_iap;
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:m3_lightmeter_iap/src/providers/equipment_profile_provider.dart';
|
import 'package:m3_lightmeter_iap/src/providers/equipment_profile_provider.dart';
|
||||||
|
import 'package:m3_lightmeter_iap/src/providers/films_provider.dart';
|
||||||
import 'package:m3_lightmeter_iap/src/providers/iap_products_provider.dart';
|
import 'package:m3_lightmeter_iap/src/providers/iap_products_provider.dart';
|
||||||
|
|
||||||
export 'src/data/models/iap_product.dart';
|
export 'src/data/models/iap_product.dart';
|
||||||
|
|
||||||
export 'src/providers/equipment_profile_provider.dart' hide EquipmentProfilesAspect;
|
export 'src/providers/equipment_profile_provider.dart';
|
||||||
|
export 'src/providers/films_provider.dart';
|
||||||
export 'src/providers/iap_products_provider.dart';
|
export 'src/providers/iap_products_provider.dart';
|
||||||
|
|
||||||
class IAPProviders extends StatelessWidget {
|
class IAPProviders extends StatelessWidget {
|
||||||
|
@ -22,8 +24,10 @@ class IAPProviders extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return IAPProductsProvider(
|
return IAPProductsProvider(
|
||||||
child: EquipmentProfileProvider(
|
child: FilmsProvider(
|
||||||
child: child,
|
child: EquipmentProfileProvider(
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:m3_lightmeter_iap/src/providers/selectable_provider.dart';
|
||||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
|
|
||||||
class EquipmentProfileProvider extends StatefulWidget {
|
class EquipmentProfileProvider extends StatefulWidget {
|
||||||
|
@ -27,7 +28,7 @@ class EquipmentProfileProviderState extends State<EquipmentProfileProvider> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return EquipmentProfiles(
|
return EquipmentProfiles(
|
||||||
profiles: const [_defaultProfile],
|
values: const [_defaultProfile],
|
||||||
selected: _defaultProfile,
|
selected: _defaultProfile,
|
||||||
child: widget.child,
|
child: widget.child,
|
||||||
);
|
);
|
||||||
|
@ -42,38 +43,19 @@ class EquipmentProfileProviderState extends State<EquipmentProfileProvider> {
|
||||||
void deleteProfile(EquipmentProfile data) {}
|
void deleteProfile(EquipmentProfile data) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum EquipmentProfilesAspect { list, selected }
|
class EquipmentProfiles extends SelectableInheritedModel<EquipmentProfile> {
|
||||||
|
|
||||||
class EquipmentProfiles extends InheritedModel<EquipmentProfilesAspect> {
|
|
||||||
const EquipmentProfiles({
|
const EquipmentProfiles({
|
||||||
super.key,
|
super.key,
|
||||||
required this.profiles,
|
required super.values,
|
||||||
required this.selected,
|
required super.selected,
|
||||||
required super.child,
|
required super.child,
|
||||||
});
|
});
|
||||||
|
|
||||||
final List<EquipmentProfile> profiles;
|
|
||||||
final EquipmentProfile selected;
|
|
||||||
|
|
||||||
static List<EquipmentProfile> of(BuildContext context) {
|
static List<EquipmentProfile> of(BuildContext context) {
|
||||||
return InheritedModel.inheritFrom<EquipmentProfiles>(
|
return InheritedModel.inheritFrom<EquipmentProfiles>(context, aspect: SelectableAspect.list)!.values;
|
||||||
context,
|
|
||||||
aspect: EquipmentProfilesAspect.list,
|
|
||||||
)!
|
|
||||||
.profiles;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static EquipmentProfile selectedOf(BuildContext context) {
|
static EquipmentProfile selectedOf(BuildContext context) {
|
||||||
return InheritedModel.inheritFrom<EquipmentProfiles>(
|
return InheritedModel.inheritFrom<EquipmentProfiles>(context, aspect: SelectableAspect.selected)!.selected;
|
||||||
context,
|
|
||||||
aspect: EquipmentProfilesAspect.selected,
|
|
||||||
)!
|
|
||||||
.selected;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
bool updateShouldNotify(EquipmentProfiles oldWidget) => false;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool updateShouldNotifyDependent(EquipmentProfiles oldWidget, Set<EquipmentProfilesAspect> dependencies) => false;
|
|
||||||
}
|
}
|
||||||
|
|
65
iap/lib/src/providers/films_provider.dart
Normal file
65
iap/lib/src/providers/films_provider.dart
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:m3_lightmeter_iap/src/providers/selectable_provider.dart';
|
||||||
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
|
|
||||||
|
class FilmsProvider extends StatefulWidget {
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
const FilmsProvider({
|
||||||
|
required this.child,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
static FilmsProviderState of(BuildContext context) {
|
||||||
|
return context.findAncestorStateOfType<FilmsProviderState>()!;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<FilmsProvider> createState() => FilmsProviderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class FilmsProviderState extends State<FilmsProvider> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Films(
|
||||||
|
values: const [Film.other()],
|
||||||
|
filmsInUse: const [Film.other()],
|
||||||
|
selected: const Film.other(),
|
||||||
|
child: widget.child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFilm(Film film) {}
|
||||||
|
|
||||||
|
void saveFilms(List<Film> films) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Films extends SelectableInheritedModel<Film> {
|
||||||
|
final List<Film> filmsInUse;
|
||||||
|
|
||||||
|
const Films({
|
||||||
|
super.key,
|
||||||
|
required super.values,
|
||||||
|
required this.filmsInUse,
|
||||||
|
required super.selected,
|
||||||
|
required super.child,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// [Film.other()] + all the custom fields with actual reciprocity formulas
|
||||||
|
static List<Film> of(BuildContext context) {
|
||||||
|
return InheritedModel.inheritFrom<Films>(context)!.values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// [Film.other()] + films in use selected by user
|
||||||
|
static List<Film> inUseOf<T>(BuildContext context) {
|
||||||
|
return InheritedModel.inheritFrom<Films>(
|
||||||
|
context,
|
||||||
|
aspect: SelectableAspect.list,
|
||||||
|
)!
|
||||||
|
.filmsInUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Film selectedOf(BuildContext context) {
|
||||||
|
return InheritedModel.inheritFrom<Films>(context, aspect: SelectableAspect.selected)!.selected;
|
||||||
|
}
|
||||||
|
}
|
29
iap/lib/src/providers/selectable_provider.dart
Normal file
29
iap/lib/src/providers/selectable_provider.dart
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
enum SelectableAspect { list, selected }
|
||||||
|
|
||||||
|
class SelectableInheritedModel<T> extends InheritedModel<SelectableAspect> {
|
||||||
|
const SelectableInheritedModel({
|
||||||
|
super.key,
|
||||||
|
required this.values,
|
||||||
|
required this.selected,
|
||||||
|
required super.child,
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<T> values;
|
||||||
|
final T selected;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool updateShouldNotify(SelectableInheritedModel oldWidget) => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool updateShouldNotifyDependent(SelectableInheritedModel oldWidget, Set<SelectableAspect> dependencies) {
|
||||||
|
if (dependencies.contains(SelectableAspect.list)) {
|
||||||
|
return true;
|
||||||
|
} else if (dependencies.contains(SelectableAspect.selected)) {
|
||||||
|
return selected != oldWidget.selected;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,235 +0,0 @@
|
||||||
import 'dart:math';
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
|
||||||
|
|
||||||
double log10(double x) => log(x) / log(10);
|
|
||||||
|
|
||||||
double log10polynomian(
|
|
||||||
double x,
|
|
||||||
double a,
|
|
||||||
double b,
|
|
||||||
double c,
|
|
||||||
) =>
|
|
||||||
a * pow(log10(x), 2) + b * log10(x) + c;
|
|
||||||
|
|
||||||
typedef ReciprocityFailureBuilder = ShutterSpeedValue Function(ShutterSpeedValue shutterSpeed);
|
|
||||||
|
|
||||||
/// Only Ilford films have reciprocity formulas provided by the manufacturer:
|
|
||||||
/// https://www.ilfordphoto.com/wp/wp-content/uploads/2017/06/Reciprocity-Failure-Compensation.pdf
|
|
||||||
///
|
|
||||||
/// Reciprocity formulas for Fomapan films and Kodak films are from here:
|
|
||||||
/// https://www.flickr.com/groups/86738082@N00/discuss/72157626050157470/
|
|
||||||
///
|
|
||||||
/// Cinema films like Kodak 5222/7222 Double-X and respective CineStill films (cause they are basically a modification of Kodak)
|
|
||||||
/// 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.
|
|
||||||
///
|
|
||||||
/// Because of this: https://github.com/dart-lang/sdk/issues/38934#issuecomment-803938315
|
|
||||||
/// `super` calls are ignored in test coverage
|
|
||||||
class Film {
|
|
||||||
final String name;
|
|
||||||
final int iso;
|
|
||||||
|
|
||||||
const Film(this.name, this.iso);
|
|
||||||
|
|
||||||
const Film.other()
|
|
||||||
: name = '',
|
|
||||||
iso = 0;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() => name;
|
|
||||||
|
|
||||||
ShutterSpeedValue reciprocityFailure(ShutterSpeedValue shutterSpeed) {
|
|
||||||
if (shutterSpeed.isFraction) {
|
|
||||||
return shutterSpeed;
|
|
||||||
} else {
|
|
||||||
return ShutterSpeedValue(
|
|
||||||
reciprocityFormula(shutterSpeed.rawValue),
|
|
||||||
shutterSpeed.isFraction,
|
|
||||||
shutterSpeed.stopType,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@protected
|
|
||||||
double reciprocityFormula(double t) => t;
|
|
||||||
|
|
||||||
static const List<Film> values = [
|
|
||||||
Film.other(),
|
|
||||||
FomapanFilm.creative100(),
|
|
||||||
FomapanFilm.creative200(),
|
|
||||||
FomapanFilm.action400(),
|
|
||||||
IlfordFilm.ortho(),
|
|
||||||
IlfordFilm.delta100(),
|
|
||||||
IlfordFilm.delta400(),
|
|
||||||
IlfordFilm.delta3200(),
|
|
||||||
IlfordFilm.fp4(),
|
|
||||||
IlfordFilm.hp5(),
|
|
||||||
IlfordFilm.panf(),
|
|
||||||
IlfordFilm.sfx200(),
|
|
||||||
IlfordFilm.xp2super(),
|
|
||||||
IlfordFilm.pan100(),
|
|
||||||
IlfordFilm.pan400(),
|
|
||||||
KodakFilm.tmax100(),
|
|
||||||
KodakFilm.tmax400(),
|
|
||||||
KodakFilm.tmax3200(),
|
|
||||||
KodakFilm.trix320(),
|
|
||||||
KodakFilm.trix400(),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// https://www.tate.org.uk/documents/598/page_6_7_agfa_stocks_0.pdf
|
|
||||||
/// 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}};
|
|
||||||
// class AgfaFilm extends Film {
|
|
||||||
// final double a;
|
|
||||||
// final double b;
|
|
||||||
// final double c;
|
|
||||||
|
|
||||||
// const AgfaFilm.apx100()
|
|
||||||
// : a = 1,
|
|
||||||
// b = 5,
|
|
||||||
// c = 2,
|
|
||||||
// super('Agfa APX 100', 100); // coverage:ignore-line
|
|
||||||
|
|
||||||
// const AgfaFilm.apx400()
|
|
||||||
// : a = 1.5,
|
|
||||||
// b = 4.5,
|
|
||||||
// c = 3,
|
|
||||||
// super('Agfa APX 400', 400); // coverage:ignore-line
|
|
||||||
|
|
||||||
// @override
|
|
||||||
// double reciprocityFormula(double t) => t * log10polynomian(t, a, b, c);
|
|
||||||
// }
|
|
||||||
|
|
||||||
class FomapanFilm extends Film {
|
|
||||||
final double a;
|
|
||||||
final double b;
|
|
||||||
final double c;
|
|
||||||
|
|
||||||
/// https://www.foma.cz/en/fomapan-100
|
|
||||||
const FomapanFilm.creative100()
|
|
||||||
: a = 1,
|
|
||||||
b = 5,
|
|
||||||
c = 2,
|
|
||||||
super('Fomapan CREATIVE 100', 100); // coverage:ignore-line
|
|
||||||
|
|
||||||
/// https://www.foma.cz/en/fomapan-200
|
|
||||||
const FomapanFilm.creative200()
|
|
||||||
: a = 1.5,
|
|
||||||
b = 4.5,
|
|
||||||
c = 3,
|
|
||||||
super('Fomapan CREATIVE 200', 200); // coverage:ignore-line
|
|
||||||
|
|
||||||
/// https://www.foma.cz/en/fomapan-100
|
|
||||||
const FomapanFilm.action400()
|
|
||||||
: a = -1.25, // coverage:ignore-line
|
|
||||||
b = 5.75,
|
|
||||||
c = 1.5,
|
|
||||||
super('Fomapan ACTION 400', 400); // coverage:ignore-line
|
|
||||||
|
|
||||||
@override
|
|
||||||
double reciprocityFormula(double t) => t * log10polynomian(t, a, b, c);
|
|
||||||
}
|
|
||||||
|
|
||||||
class IlfordFilm extends Film {
|
|
||||||
final double reciprocityPower;
|
|
||||||
|
|
||||||
/// https://www.ilfordphoto.com/amfile/file/download/file/1948/product/1650/
|
|
||||||
const IlfordFilm.ortho()
|
|
||||||
: reciprocityPower = 1.25,
|
|
||||||
super('Ilford ORTHO+', 80); // coverage:ignore-line
|
|
||||||
|
|
||||||
/// https://www.ilfordphoto.com/amfile/file/download/file/1919/product/686/
|
|
||||||
const IlfordFilm.fp4()
|
|
||||||
: reciprocityPower = 1.26,
|
|
||||||
super('Ilford FP4+', 125); // coverage:ignore-line
|
|
||||||
|
|
||||||
/// https://www.ilfordphoto.com/amfile/file/download/file/1903/product/691/
|
|
||||||
const IlfordFilm.hp5()
|
|
||||||
: reciprocityPower = 1.31,
|
|
||||||
super('Ilford HP5+', 400); // coverage:ignore-line
|
|
||||||
|
|
||||||
/// https://www.ilfordphoto.com/amfile/file/download/file/3/product/679/
|
|
||||||
const IlfordFilm.delta100()
|
|
||||||
: reciprocityPower = 1.26,
|
|
||||||
super('Ilford DELTA 100', 100); // coverage:ignore-line
|
|
||||||
|
|
||||||
/// https://www.ilfordphoto.com/amfile/file/download/file/1915/product/684/
|
|
||||||
const IlfordFilm.delta400()
|
|
||||||
: reciprocityPower = 1.41,
|
|
||||||
super('Ilford DELTA 400', 400); // coverage:ignore-line
|
|
||||||
|
|
||||||
/// https://www.ilfordphoto.com/amfile/file/download/file/1913/product/682/
|
|
||||||
const IlfordFilm.delta3200()
|
|
||||||
: reciprocityPower = 1.33,
|
|
||||||
super('Ilford DELTA 3200', 3200); // coverage:ignore-line
|
|
||||||
|
|
||||||
/// https://www.ilfordphoto.com/amfile/file/download/file/1905/product/699/
|
|
||||||
const IlfordFilm.panf()
|
|
||||||
: reciprocityPower = 1.33,
|
|
||||||
super('Ilford Pan F+', 50); // coverage:ignore-line
|
|
||||||
|
|
||||||
/// https://www.ilfordphoto.com/amfile/file/download/file/1907/product/701/
|
|
||||||
const IlfordFilm.sfx200()
|
|
||||||
: reciprocityPower = 1.31,
|
|
||||||
super('Ilford SFX 200', 200); // coverage:ignore-line
|
|
||||||
|
|
||||||
/// https://www.ilfordphoto.com/amfile/file/download/file/1909/product/703/
|
|
||||||
const IlfordFilm.xp2super()
|
|
||||||
: reciprocityPower = 1.31,
|
|
||||||
super('Ilford XP2 SUPER', 400); // coverage:ignore-line
|
|
||||||
|
|
||||||
/// https://www.ilfordphoto.com/amfile/file/download/file/1958/product/696/
|
|
||||||
const IlfordFilm.pan100()
|
|
||||||
: reciprocityPower = 1.26,
|
|
||||||
super('Kentemere 100', 100); // coverage:ignore-line
|
|
||||||
|
|
||||||
/// https://www.ilfordphoto.com/amfile/file/download/file/1959/product/697/
|
|
||||||
const IlfordFilm.pan400()
|
|
||||||
: reciprocityPower = 1.30,
|
|
||||||
super('Kentemere 400', 400); // coverage:ignore-line
|
|
||||||
|
|
||||||
@override
|
|
||||||
double reciprocityFormula(double t) => pow(t, reciprocityPower).toDouble();
|
|
||||||
}
|
|
||||||
|
|
||||||
class KodakFilm extends Film {
|
|
||||||
final double a;
|
|
||||||
final double b;
|
|
||||||
final double c;
|
|
||||||
|
|
||||||
const KodakFilm.tmax100()
|
|
||||||
: a = 1 / 6, // coverage:ignore-line
|
|
||||||
b = 0, // coverage:ignore-line
|
|
||||||
c = 4 / 3, // coverage:ignore-line
|
|
||||||
super('Kodak T-MAX 100', 100); // coverage:ignore-line
|
|
||||||
|
|
||||||
const KodakFilm.tmax400()
|
|
||||||
: a = 2 / 3, // coverage:ignore-line
|
|
||||||
b = -1 / 2, // coverage:ignore-line
|
|
||||||
c = 4 / 3, // coverage:ignore-line
|
|
||||||
super('Kodak T-MAX 400', 400); // coverage:ignore-line
|
|
||||||
|
|
||||||
const KodakFilm.tmax3200()
|
|
||||||
: a = 7 / 6, // coverage:ignore-line
|
|
||||||
b = -1, // coverage:ignore-line
|
|
||||||
c = 4 / 3, // coverage:ignore-line
|
|
||||||
super('Kodak T-MAX 3200', 3200); // coverage:ignore-line
|
|
||||||
|
|
||||||
const KodakFilm.trix320()
|
|
||||||
: a = 2,
|
|
||||||
b = 1,
|
|
||||||
c = 2,
|
|
||||||
super('Kodak TRI-X 320', 320); // coverage:ignore-line
|
|
||||||
|
|
||||||
const KodakFilm.trix400()
|
|
||||||
: a = 2,
|
|
||||||
b = 1,
|
|
||||||
c = 2,
|
|
||||||
super('Kodak TRI-X 400', 400); // coverage:ignore-line
|
|
||||||
|
|
||||||
@override
|
|
||||||
double reciprocityFormula(double t) => t * log10polynomian(t, a, b, c);
|
|
||||||
}
|
|
|
@ -2,7 +2,6 @@ import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/data/models/ev_source_type.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/metering_screen_layout_config.dart';
|
||||||
import 'package:lightmeter/data/models/supported_locale.dart';
|
import 'package:lightmeter/data/models/supported_locale.dart';
|
||||||
import 'package:lightmeter/data/models/theme_type.dart';
|
import 'package:lightmeter/data/models/theme_type.dart';
|
||||||
|
@ -19,7 +18,6 @@ class UserPreferencesService {
|
||||||
static const cameraEvCalibrationKey = "cameraEvCalibration";
|
static const cameraEvCalibrationKey = "cameraEvCalibration";
|
||||||
static const lightSensorEvCalibrationKey = "lightSensorEvCalibration";
|
static const lightSensorEvCalibrationKey = "lightSensorEvCalibration";
|
||||||
static const meteringScreenLayoutKey = "meteringScreenLayout";
|
static const meteringScreenLayoutKey = "meteringScreenLayout";
|
||||||
static const filmKey = "film";
|
|
||||||
|
|
||||||
static const caffeineKey = "caffeine";
|
static const caffeineKey = "caffeine";
|
||||||
static const hapticsKey = "haptics";
|
static const hapticsKey = "haptics";
|
||||||
|
@ -142,10 +140,4 @@ class UserPreferencesService {
|
||||||
|
|
||||||
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(
|
|
||||||
(e) => e.name == _sharedPreferences.getString(filmKey),
|
|
||||||
orElse: () => Film.values.first,
|
|
||||||
);
|
|
||||||
set film(Film value) => _sharedPreferences.setString(filmKey, value.name);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ import 'package:app_settings/app_settings.dart';
|
||||||
import 'package:lightmeter/data/caffeine_service.dart';
|
import 'package:lightmeter/data/caffeine_service.dart';
|
||||||
import 'package:lightmeter/data/haptics_service.dart';
|
import 'package:lightmeter/data/haptics_service.dart';
|
||||||
import 'package:lightmeter/data/light_sensor_service.dart';
|
import 'package:lightmeter/data/light_sensor_service.dart';
|
||||||
import 'package:lightmeter/data/models/film.dart';
|
|
||||||
import 'package:lightmeter/data/models/volume_action.dart';
|
import 'package:lightmeter/data/models/volume_action.dart';
|
||||||
import 'package:lightmeter/data/permissions_service.dart';
|
import 'package:lightmeter/data/permissions_service.dart';
|
||||||
import 'package:lightmeter/data/shared_prefs_service.dart';
|
import 'package:lightmeter/data/shared_prefs_service.dart';
|
||||||
|
@ -45,9 +44,6 @@ class MeteringInteractor {
|
||||||
NdValue get ndFilter => _userPreferencesService.ndFilter;
|
NdValue get ndFilter => _userPreferencesService.ndFilter;
|
||||||
set ndFilter(NdValue value) => _userPreferencesService.ndFilter = value;
|
set ndFilter(NdValue value) => _userPreferencesService.ndFilter = value;
|
||||||
|
|
||||||
Film get film => _userPreferencesService.film;
|
|
||||||
set film(Film value) => _userPreferencesService.film = value;
|
|
||||||
|
|
||||||
VolumeAction get volumeAction => _userPreferencesService.volumeAction;
|
VolumeAction get volumeAction => _userPreferencesService.volumeAction;
|
||||||
|
|
||||||
/// Executes vibration if haptics are enabled in settings
|
/// Executes vibration if haptics are enabled in settings
|
||||||
|
|
|
@ -41,6 +41,9 @@
|
||||||
"meteringScreenFeatureFilmPicker": "Film picker",
|
"meteringScreenFeatureFilmPicker": "Film picker",
|
||||||
"meteringScreenFeatureHistogram": "Histogram",
|
"meteringScreenFeatureHistogram": "Histogram",
|
||||||
"film": "Film",
|
"film": "Film",
|
||||||
|
"filmPush": "Film (push)",
|
||||||
|
"filmPull": "Film (pull)",
|
||||||
|
"filmReciprocityHint": "Applies correction for shutter speeds grater than 1 second",
|
||||||
"equipment": "Equipment",
|
"equipment": "Equipment",
|
||||||
"equipmentProfileName": "Equipment profile name",
|
"equipmentProfileName": "Equipment profile name",
|
||||||
"equipmentProfileNameHint": "Praktica MTL5B",
|
"equipmentProfileNameHint": "Praktica MTL5B",
|
||||||
|
@ -56,6 +59,8 @@
|
||||||
"equipmentProfile": "Equipment profile",
|
"equipmentProfile": "Equipment profile",
|
||||||
"equipmentProfiles": "Equipment profiles",
|
"equipmentProfiles": "Equipment profiles",
|
||||||
"tapToAdd": "Tap to add",
|
"tapToAdd": "Tap to add",
|
||||||
|
"filmsInUse": "Films in use",
|
||||||
|
"filmsInUseDescription": "Select films which you use.",
|
||||||
"general": "General",
|
"general": "General",
|
||||||
"keepScreenOn": "Keep screen on",
|
"keepScreenOn": "Keep screen on",
|
||||||
"haptics": "Haptics",
|
"haptics": "Haptics",
|
||||||
|
|
|
@ -41,9 +41,11 @@
|
||||||
"meteringScreenFeatureFilmPicker": "Sélecteur de film",
|
"meteringScreenFeatureFilmPicker": "Sélecteur de film",
|
||||||
"meteringScreenFeatureHistogram": "Histogramme",
|
"meteringScreenFeatureHistogram": "Histogramme",
|
||||||
"film": "Pellicule",
|
"film": "Pellicule",
|
||||||
|
"filmPush": "Pellicule (push)",
|
||||||
|
"filmPull": "Pellicule (pull)",
|
||||||
|
"filmReciprocityHint": "La correction s'applique aux vitesses d'obturation supérieures à 1 seconde",
|
||||||
"equipment": "Équipement",
|
"equipment": "Équipement",
|
||||||
"equipmentProfileName": "Nom du profil de l'équipement",
|
"equipmentProfileName": "Nom du profil de l'équipement",
|
||||||
"tapToAdd": "Appuie pour ajouter",
|
|
||||||
"equipmentProfileNameHint": "Praktica MTL5B",
|
"equipmentProfileNameHint": "Praktica MTL5B",
|
||||||
"equipmentProfileAllValues": "Tout",
|
"equipmentProfileAllValues": "Tout",
|
||||||
"apertureValues": "Valeurs Aperture",
|
"apertureValues": "Valeurs Aperture",
|
||||||
|
@ -56,6 +58,9 @@
|
||||||
"isoValuesFilterDescription": "Sélectionnez les valeurs ISO à afficher. Ce sont peut-être vos valeurs les plus couramment utilisées ou celles prises en charge par votre caméra.",
|
"isoValuesFilterDescription": "Sélectionnez les valeurs ISO à afficher. Ce sont peut-être vos valeurs les plus couramment utilisées ou celles prises en charge par votre caméra.",
|
||||||
"equipmentProfile": "Profil de l'équipement",
|
"equipmentProfile": "Profil de l'équipement",
|
||||||
"equipmentProfiles": "Profils de l'équipement",
|
"equipmentProfiles": "Profils de l'équipement",
|
||||||
|
"tapToAdd": "Appuie pour ajouter",
|
||||||
|
"filmsInUse": "Films en usage",
|
||||||
|
"filmsInUseDescription": "Sélectionnez les films que vous utilisez.",
|
||||||
"general": "Général",
|
"general": "Général",
|
||||||
"keepScreenOn": "Garder l'écran allumé",
|
"keepScreenOn": "Garder l'écran allumé",
|
||||||
"haptics": "Haptiques",
|
"haptics": "Haptiques",
|
||||||
|
|
|
@ -41,6 +41,9 @@
|
||||||
"meteringScreenFeatureFilmPicker": "Выбор пленки",
|
"meteringScreenFeatureFilmPicker": "Выбор пленки",
|
||||||
"meteringScreenFeatureHistogram": "Гистограмма",
|
"meteringScreenFeatureHistogram": "Гистограмма",
|
||||||
"film": "Пленка",
|
"film": "Пленка",
|
||||||
|
"filmPush": "Пленка (push)",
|
||||||
|
"filmPull": "Пленка (pull)",
|
||||||
|
"filmReciprocityHint": "Применяет коррекцию для выдержек длиннее 1 секунды",
|
||||||
"equipment": "Оборудование",
|
"equipment": "Оборудование",
|
||||||
"equipmentProfileName": "Название профиля",
|
"equipmentProfileName": "Название профиля",
|
||||||
"equipmentProfileNameHint": "Praktica MTL5B",
|
"equipmentProfileNameHint": "Praktica MTL5B",
|
||||||
|
@ -56,6 +59,8 @@
|
||||||
"equipmentProfile": "Оборудование",
|
"equipmentProfile": "Оборудование",
|
||||||
"equipmentProfiles": "Профили оборудования",
|
"equipmentProfiles": "Профили оборудования",
|
||||||
"tapToAdd": "Нажмите, чтобы добавить",
|
"tapToAdd": "Нажмите, чтобы добавить",
|
||||||
|
"filmsInUse": "Используемые пленки",
|
||||||
|
"filmsInUseDescription": "Выберите пленки, которыми вы пользуетесь.",
|
||||||
"general": "Общие",
|
"general": "Общие",
|
||||||
"keepScreenOn": "Запрет блокировки",
|
"keepScreenOn": "Запрет блокировки",
|
||||||
"haptics": "Вибрация",
|
"haptics": "Вибрация",
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
"thirdStops": "1/3",
|
"thirdStops": "1/3",
|
||||||
"calibration": "校准",
|
"calibration": "校准",
|
||||||
"calibrationMessage": "此应用测量读数的准确性完全取决于设备的硬件。因此,请考虑测试此应用并手动设置 EV 校准,以获得准确的测量结果。",
|
"calibrationMessage": "此应用测量读数的准确性完全取决于设备的硬件。因此,请考虑测试此应用并手动设置 EV 校准,以获得准确的测量结果。",
|
||||||
"calibrationMessageCameraOnly": "此应用程序测量读数的准确性完全取决于设备的后置摄像头。因此,请考虑测试此应用并手动设置 EV 校准,以获得准确的测量结果。",
|
"calibrationMessageCameraOnly": "此应用程序测量读数的准确s性完全取决于设备的后置摄像头。因此,请考虑测试此应用并手动设置 EV 校准,以获得准确的测量结果。",
|
||||||
"camera": "摄像头",
|
"camera": "摄像头",
|
||||||
"lightSensor": "光传感器",
|
"lightSensor": "光传感器",
|
||||||
"meteringScreenLayout": "布局",
|
"meteringScreenLayout": "布局",
|
||||||
|
@ -41,6 +41,9 @@
|
||||||
"meteringScreenFeatureFilmPicker": "胶片选择",
|
"meteringScreenFeatureFilmPicker": "胶片选择",
|
||||||
"meteringScreenFeatureHistogram": "直方图",
|
"meteringScreenFeatureHistogram": "直方图",
|
||||||
"film": "胶片",
|
"film": "胶片",
|
||||||
|
"filmPush": "胶片 (push)",
|
||||||
|
"filmPull": "胶片 (pull)",
|
||||||
|
"filmReciprocityHint": "Applies correction for shutter speeds grater than 1 second",
|
||||||
"equipment": "设备",
|
"equipment": "设备",
|
||||||
"equipmentProfileName": "设备配置名称",
|
"equipmentProfileName": "设备配置名称",
|
||||||
"equipmentProfileNameHint": "Praktica MTL5B",
|
"equipmentProfileNameHint": "Praktica MTL5B",
|
||||||
|
@ -56,6 +59,8 @@
|
||||||
"equipmentProfile": "设备配置",
|
"equipmentProfile": "设备配置",
|
||||||
"equipmentProfiles": "设备配置",
|
"equipmentProfiles": "设备配置",
|
||||||
"tapToAdd": "點擊添加",
|
"tapToAdd": "點擊添加",
|
||||||
|
"filmsInUse": "Films in use",
|
||||||
|
"filmsInUseDescription": "Select films which you use.",
|
||||||
"general": "通用",
|
"general": "通用",
|
||||||
"keepScreenOn": "保持屏幕常亮",
|
"keepScreenOn": "保持屏幕常亮",
|
||||||
"haptics": "震动",
|
"haptics": "震动",
|
||||||
|
|
|
@ -3,7 +3,6 @@ import 'dart:async';
|
||||||
import 'package:bloc_concurrency/bloc_concurrency.dart';
|
import 'package:bloc_concurrency/bloc_concurrency.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:lightmeter/data/models/film.dart';
|
|
||||||
import 'package:lightmeter/data/models/volume_action.dart';
|
import 'package:lightmeter/data/models/volume_action.dart';
|
||||||
import 'package:lightmeter/interactors/metering_interactor.dart';
|
import 'package:lightmeter/interactors/metering_interactor.dart';
|
||||||
import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart';
|
import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart';
|
||||||
|
@ -29,7 +28,6 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
||||||
) : super(
|
) : super(
|
||||||
MeteringDataState(
|
MeteringDataState(
|
||||||
ev100: null,
|
ev100: null,
|
||||||
film: _meteringInteractor.film,
|
|
||||||
iso: _meteringInteractor.iso,
|
iso: _meteringInteractor.iso,
|
||||||
nd: _meteringInteractor.ndFilter,
|
nd: _meteringInteractor.ndFilter,
|
||||||
isMetering: false,
|
isMetering: false,
|
||||||
|
@ -42,7 +40,6 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
||||||
.listen(onCommunicationState);
|
.listen(onCommunicationState);
|
||||||
|
|
||||||
on<EquipmentProfileChangedEvent>(_onEquipmentProfileChanged);
|
on<EquipmentProfileChangedEvent>(_onEquipmentProfileChanged);
|
||||||
on<FilmChangedEvent>(_onFilmChanged);
|
|
||||||
on<IsoChangedEvent>(_onIsoChanged);
|
on<IsoChangedEvent>(_onIsoChanged);
|
||||||
on<NdChangedEvent>(_onNdChanged);
|
on<NdChangedEvent>(_onNdChanged);
|
||||||
on<MeasureEvent>(_onMeasure, transformer: droppable());
|
on<MeasureEvent>(_onMeasure, transformer: droppable());
|
||||||
|
@ -92,12 +89,9 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
||||||
/// Update selected ISO value and discard selected film, if selected equipment profile
|
/// Update selected ISO value and discard selected film, if selected equipment profile
|
||||||
/// doesn't contain currently selected value
|
/// doesn't contain currently selected value
|
||||||
IsoValue iso = state.iso;
|
IsoValue iso = state.iso;
|
||||||
Film film = state.film;
|
|
||||||
if (!event.equipmentProfileData.isoValues.any((v) => state.iso.value == v.value)) {
|
if (!event.equipmentProfileData.isoValues.any((v) => state.iso.value == v.value)) {
|
||||||
_meteringInteractor.iso = event.equipmentProfileData.isoValues.first;
|
_meteringInteractor.iso = event.equipmentProfileData.isoValues.first;
|
||||||
iso = event.equipmentProfileData.isoValues.first;
|
iso = event.equipmentProfileData.isoValues.first;
|
||||||
_meteringInteractor.film = Film.values.first;
|
|
||||||
film = Film.values.first;
|
|
||||||
willUpdateMeasurements = true;
|
willUpdateMeasurements = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +107,6 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
||||||
emit(
|
emit(
|
||||||
MeteringDataState(
|
MeteringDataState(
|
||||||
ev100: state.ev100,
|
ev100: state.ev100,
|
||||||
film: film,
|
|
||||||
iso: iso,
|
iso: iso,
|
||||||
nd: nd,
|
nd: nd,
|
||||||
isMetering: state.isMetering,
|
isMetering: state.isMetering,
|
||||||
|
@ -122,46 +115,12 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onFilmChanged(FilmChangedEvent event, Emitter emit) {
|
|
||||||
if (state.film.name != event.film.name) {
|
|
||||||
_meteringInteractor.film = event.film;
|
|
||||||
|
|
||||||
/// Find `IsoValue` with matching value
|
|
||||||
IsoValue iso = state.iso;
|
|
||||||
if (state.iso.value != event.film.iso && event.film != const Film.other()) {
|
|
||||||
iso = IsoValue.values.firstWhere(
|
|
||||||
(e) => e.value == event.film.iso,
|
|
||||||
orElse: () => state.iso,
|
|
||||||
);
|
|
||||||
_meteringInteractor.iso = iso;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If user selects 'Other' film we preserve currently selected ISO
|
|
||||||
/// and therefore only discard reciprocity formula
|
|
||||||
emit(
|
|
||||||
MeteringDataState(
|
|
||||||
ev100: state.ev100,
|
|
||||||
film: event.film,
|
|
||||||
iso: iso,
|
|
||||||
nd: state.nd,
|
|
||||||
isMetering: state.isMetering,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onIsoChanged(IsoChangedEvent event, Emitter emit) {
|
void _onIsoChanged(IsoChangedEvent event, Emitter emit) {
|
||||||
/// Discard currently selected film even if ISO is the same,
|
|
||||||
/// because, for example, Fomapan 400 and any Ilford 400
|
|
||||||
/// have different reciprocity formulas
|
|
||||||
_meteringInteractor.film = Film.values.first;
|
|
||||||
|
|
||||||
if (state.iso != event.isoValue) {
|
if (state.iso != event.isoValue) {
|
||||||
_meteringInteractor.iso = event.isoValue;
|
_meteringInteractor.iso = event.isoValue;
|
||||||
emit(
|
emit(
|
||||||
MeteringDataState(
|
MeteringDataState(
|
||||||
ev100: state.ev100,
|
ev100: state.ev100,
|
||||||
film: Film.values.first,
|
|
||||||
iso: event.isoValue,
|
iso: event.isoValue,
|
||||||
nd: state.nd,
|
nd: state.nd,
|
||||||
isMetering: state.isMetering,
|
isMetering: state.isMetering,
|
||||||
|
@ -176,7 +135,6 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
||||||
emit(
|
emit(
|
||||||
MeteringDataState(
|
MeteringDataState(
|
||||||
ev100: state.ev100,
|
ev100: state.ev100,
|
||||||
film: state.film,
|
|
||||||
iso: state.iso,
|
iso: state.iso,
|
||||||
nd: event.ndValue,
|
nd: event.ndValue,
|
||||||
isMetering: state.isMetering,
|
isMetering: state.isMetering,
|
||||||
|
@ -190,7 +148,6 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
||||||
_communicationBloc.add(const communication_events.MeasureEvent());
|
_communicationBloc.add(const communication_events.MeasureEvent());
|
||||||
emit(
|
emit(
|
||||||
LoadingState(
|
LoadingState(
|
||||||
film: state.film,
|
|
||||||
iso: state.iso,
|
iso: state.iso,
|
||||||
nd: state.nd,
|
nd: state.nd,
|
||||||
),
|
),
|
||||||
|
@ -209,7 +166,6 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
||||||
emit(
|
emit(
|
||||||
MeteringDataState(
|
MeteringDataState(
|
||||||
ev100: event.ev100,
|
ev100: event.ev100,
|
||||||
film: state.film,
|
|
||||||
iso: state.iso,
|
iso: state.iso,
|
||||||
nd: state.nd,
|
nd: state.nd,
|
||||||
isMetering: event.isMetering,
|
isMetering: event.isMetering,
|
||||||
|
@ -221,7 +177,6 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
|
||||||
emit(
|
emit(
|
||||||
MeteringDataState(
|
MeteringDataState(
|
||||||
ev100: null,
|
ev100: null,
|
||||||
film: state.film,
|
|
||||||
iso: state.iso,
|
iso: state.iso,
|
||||||
nd: state.nd,
|
nd: state.nd,
|
||||||
isMetering: event.isMetering,
|
isMetering: event.isMetering,
|
||||||
|
|
|
@ -31,27 +31,7 @@ class _CameraPreviewState extends State<CameraPreview> {
|
||||||
AnimatedSwitcher(
|
AnimatedSwitcher(
|
||||||
duration: Dimens.switchDuration,
|
duration: Dimens.switchDuration,
|
||||||
child: widget.controller != null
|
child: widget.controller != null
|
||||||
? ValueListenableBuilder<CameraValue>(
|
? _CameraPreviewBuilder(controller: widget.controller!)
|
||||||
valueListenable: widget.controller!,
|
|
||||||
builder: (_, __, ___) => widget.controller!.value.isInitialized
|
|
||||||
? Stack(
|
|
||||||
alignment: Alignment.bottomCenter,
|
|
||||||
children: [
|
|
||||||
CameraView(controller: widget.controller!),
|
|
||||||
if (UserPreferencesProvider.meteringScreenFeatureOf(
|
|
||||||
context,
|
|
||||||
MeteringScreenLayoutFeature.histogram,
|
|
||||||
))
|
|
||||||
Positioned(
|
|
||||||
left: Dimens.grid8,
|
|
||||||
right: Dimens.grid8,
|
|
||||||
bottom: Dimens.grid16,
|
|
||||||
child: CameraHistogram(controller: widget.controller!),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
: const SizedBox.shrink(),
|
|
||||||
)
|
|
||||||
: CameraViewPlaceholder(error: widget.error),
|
: CameraViewPlaceholder(error: widget.error),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -60,3 +40,59 @@ class _CameraPreviewState extends State<CameraPreview> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _CameraPreviewBuilder extends StatefulWidget {
|
||||||
|
final CameraController controller;
|
||||||
|
|
||||||
|
const _CameraPreviewBuilder({required this.controller});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_CameraPreviewBuilder> createState() => _CameraPreviewBuilderState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CameraPreviewBuilderState extends State<_CameraPreviewBuilder> {
|
||||||
|
late final ValueNotifier<bool> _initializedNotifier =
|
||||||
|
ValueNotifier<bool>(widget.controller.value.isInitialized);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
widget.controller.addListener(_update);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
widget.controller.removeListener(_update);
|
||||||
|
_initializedNotifier.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ValueListenableBuilder<bool>(
|
||||||
|
valueListenable: _initializedNotifier,
|
||||||
|
builder: (context, value, child) => value
|
||||||
|
? Stack(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
children: [
|
||||||
|
CameraView(controller: widget.controller),
|
||||||
|
if (UserPreferencesProvider.meteringScreenFeatureOf(
|
||||||
|
context,
|
||||||
|
MeteringScreenLayoutFeature.histogram,
|
||||||
|
))
|
||||||
|
Positioned(
|
||||||
|
left: Dimens.grid8,
|
||||||
|
right: Dimens.grid8,
|
||||||
|
bottom: Dimens.grid16,
|
||||||
|
child: CameraHistogram(controller: widget.controller),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: const SizedBox.shrink(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _update() {
|
||||||
|
_initializedNotifier.value = widget.controller.value.isInitialized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:lightmeter/data/models/exposure_pair.dart';
|
import 'package:lightmeter/data/models/exposure_pair.dart';
|
||||||
import 'package:lightmeter/data/models/film.dart';
|
|
||||||
import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart';
|
import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart';
|
||||||
import 'package:lightmeter/screens/metering/components/camera_container/bloc_container_camera.dart';
|
import 'package:lightmeter/screens/metering/components/camera_container/bloc_container_camera.dart';
|
||||||
import 'package:lightmeter/screens/metering/components/camera_container/event_container_camera.dart';
|
import 'package:lightmeter/screens/metering/components/camera_container/event_container_camera.dart';
|
||||||
|
@ -12,10 +11,8 @@ import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
class CameraContainerProvider extends StatelessWidget {
|
class CameraContainerProvider extends StatelessWidget {
|
||||||
final ExposurePair? fastest;
|
final ExposurePair? fastest;
|
||||||
final ExposurePair? slowest;
|
final ExposurePair? slowest;
|
||||||
final Film film;
|
|
||||||
final IsoValue iso;
|
final IsoValue iso;
|
||||||
final NdValue nd;
|
final NdValue nd;
|
||||||
final ValueChanged<Film> onFilmChanged;
|
|
||||||
final ValueChanged<IsoValue> onIsoChanged;
|
final ValueChanged<IsoValue> onIsoChanged;
|
||||||
final ValueChanged<NdValue> onNdChanged;
|
final ValueChanged<NdValue> onNdChanged;
|
||||||
final List<ExposurePair> exposurePairs;
|
final List<ExposurePair> exposurePairs;
|
||||||
|
@ -23,10 +20,8 @@ class CameraContainerProvider extends StatelessWidget {
|
||||||
const CameraContainerProvider({
|
const CameraContainerProvider({
|
||||||
required this.fastest,
|
required this.fastest,
|
||||||
required this.slowest,
|
required this.slowest,
|
||||||
required this.film,
|
|
||||||
required this.iso,
|
required this.iso,
|
||||||
required this.nd,
|
required this.nd,
|
||||||
required this.onFilmChanged,
|
|
||||||
required this.onIsoChanged,
|
required this.onIsoChanged,
|
||||||
required this.onNdChanged,
|
required this.onNdChanged,
|
||||||
required this.exposurePairs,
|
required this.exposurePairs,
|
||||||
|
@ -44,10 +39,8 @@ class CameraContainerProvider extends StatelessWidget {
|
||||||
child: CameraContainer(
|
child: CameraContainer(
|
||||||
fastest: fastest,
|
fastest: fastest,
|
||||||
slowest: slowest,
|
slowest: slowest,
|
||||||
film: film,
|
|
||||||
iso: iso,
|
iso: iso,
|
||||||
nd: nd,
|
nd: nd,
|
||||||
onFilmChanged: onFilmChanged,
|
|
||||||
onIsoChanged: onIsoChanged,
|
onIsoChanged: onIsoChanged,
|
||||||
onNdChanged: onNdChanged,
|
onNdChanged: onNdChanged,
|
||||||
exposurePairs: exposurePairs,
|
exposurePairs: exposurePairs,
|
||||||
|
|
|
@ -3,7 +3,6 @@ import 'dart:math';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:lightmeter/data/models/exposure_pair.dart';
|
import 'package:lightmeter/data/models/exposure_pair.dart';
|
||||||
import 'package:lightmeter/data/models/film.dart';
|
|
||||||
import 'package:lightmeter/data/models/metering_screen_layout_config.dart';
|
import 'package:lightmeter/data/models/metering_screen_layout_config.dart';
|
||||||
import 'package:lightmeter/platform_config.dart';
|
import 'package:lightmeter/platform_config.dart';
|
||||||
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
||||||
|
@ -23,10 +22,8 @@ import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
class CameraContainer extends StatelessWidget {
|
class CameraContainer extends StatelessWidget {
|
||||||
final ExposurePair? fastest;
|
final ExposurePair? fastest;
|
||||||
final ExposurePair? slowest;
|
final ExposurePair? slowest;
|
||||||
final Film film;
|
|
||||||
final IsoValue iso;
|
final IsoValue iso;
|
||||||
final NdValue nd;
|
final NdValue nd;
|
||||||
final ValueChanged<Film> onFilmChanged;
|
|
||||||
final ValueChanged<IsoValue> onIsoChanged;
|
final ValueChanged<IsoValue> onIsoChanged;
|
||||||
final ValueChanged<NdValue> onNdChanged;
|
final ValueChanged<NdValue> onNdChanged;
|
||||||
final List<ExposurePair> exposurePairs;
|
final List<ExposurePair> exposurePairs;
|
||||||
|
@ -34,10 +31,8 @@ class CameraContainer extends StatelessWidget {
|
||||||
const CameraContainer({
|
const CameraContainer({
|
||||||
required this.fastest,
|
required this.fastest,
|
||||||
required this.slowest,
|
required this.slowest,
|
||||||
required this.film,
|
|
||||||
required this.iso,
|
required this.iso,
|
||||||
required this.nd,
|
required this.nd,
|
||||||
required this.onFilmChanged,
|
|
||||||
required this.onIsoChanged,
|
required this.onIsoChanged,
|
||||||
required this.onNdChanged,
|
required this.onNdChanged,
|
||||||
required this.exposurePairs,
|
required this.exposurePairs,
|
||||||
|
@ -60,10 +55,8 @@ class CameraContainer extends StatelessWidget {
|
||||||
readingsContainer: ReadingsContainer(
|
readingsContainer: ReadingsContainer(
|
||||||
fastest: fastest,
|
fastest: fastest,
|
||||||
slowest: slowest,
|
slowest: slowest,
|
||||||
film: film,
|
|
||||||
iso: iso,
|
iso: iso,
|
||||||
nd: nd,
|
nd: nd,
|
||||||
onFilmChanged: onFilmChanged,
|
|
||||||
onIsoChanged: onIsoChanged,
|
onIsoChanged: onIsoChanged,
|
||||||
onNdChanged: onNdChanged,
|
onNdChanged: onNdChanged,
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:lightmeter/data/models/exposure_pair.dart';
|
import 'package:lightmeter/data/models/exposure_pair.dart';
|
||||||
import 'package:lightmeter/data/models/film.dart';
|
|
||||||
import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart';
|
import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart';
|
||||||
import 'package:lightmeter/screens/metering/components/light_sensor_container/bloc_container_light_sensor.dart';
|
import 'package:lightmeter/screens/metering/components/light_sensor_container/bloc_container_light_sensor.dart';
|
||||||
import 'package:lightmeter/screens/metering/components/light_sensor_container/widget_container_light_sensor.dart';
|
import 'package:lightmeter/screens/metering/components/light_sensor_container/widget_container_light_sensor.dart';
|
||||||
|
@ -11,10 +10,8 @@ import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
class LightSensorContainerProvider extends StatelessWidget {
|
class LightSensorContainerProvider extends StatelessWidget {
|
||||||
final ExposurePair? fastest;
|
final ExposurePair? fastest;
|
||||||
final ExposurePair? slowest;
|
final ExposurePair? slowest;
|
||||||
final Film film;
|
|
||||||
final IsoValue iso;
|
final IsoValue iso;
|
||||||
final NdValue nd;
|
final NdValue nd;
|
||||||
final ValueChanged<Film> onFilmChanged;
|
|
||||||
final ValueChanged<IsoValue> onIsoChanged;
|
final ValueChanged<IsoValue> onIsoChanged;
|
||||||
final ValueChanged<NdValue> onNdChanged;
|
final ValueChanged<NdValue> onNdChanged;
|
||||||
final List<ExposurePair> exposurePairs;
|
final List<ExposurePair> exposurePairs;
|
||||||
|
@ -22,10 +19,8 @@ class LightSensorContainerProvider extends StatelessWidget {
|
||||||
const LightSensorContainerProvider({
|
const LightSensorContainerProvider({
|
||||||
required this.fastest,
|
required this.fastest,
|
||||||
required this.slowest,
|
required this.slowest,
|
||||||
required this.film,
|
|
||||||
required this.iso,
|
required this.iso,
|
||||||
required this.nd,
|
required this.nd,
|
||||||
required this.onFilmChanged,
|
|
||||||
required this.onIsoChanged,
|
required this.onIsoChanged,
|
||||||
required this.onNdChanged,
|
required this.onNdChanged,
|
||||||
required this.exposurePairs,
|
required this.exposurePairs,
|
||||||
|
@ -43,10 +38,8 @@ class LightSensorContainerProvider extends StatelessWidget {
|
||||||
child: LightSensorContainer(
|
child: LightSensorContainer(
|
||||||
fastest: fastest,
|
fastest: fastest,
|
||||||
slowest: slowest,
|
slowest: slowest,
|
||||||
film: film,
|
|
||||||
iso: iso,
|
iso: iso,
|
||||||
nd: nd,
|
nd: nd,
|
||||||
onFilmChanged: onFilmChanged,
|
|
||||||
onIsoChanged: onIsoChanged,
|
onIsoChanged: onIsoChanged,
|
||||||
onNdChanged: onNdChanged,
|
onNdChanged: onNdChanged,
|
||||||
exposurePairs: exposurePairs,
|
exposurePairs: exposurePairs,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/data/models/exposure_pair.dart';
|
import 'package:lightmeter/data/models/exposure_pair.dart';
|
||||||
import 'package:lightmeter/data/models/film.dart';
|
|
||||||
import 'package:lightmeter/res/dimens.dart';
|
import 'package:lightmeter/res/dimens.dart';
|
||||||
import 'package:lightmeter/screens/metering/components/shared/exposure_pairs_list/widget_list_exposure_pairs.dart';
|
import 'package:lightmeter/screens/metering/components/shared/exposure_pairs_list/widget_list_exposure_pairs.dart';
|
||||||
import 'package:lightmeter/screens/metering/components/shared/metering_top_bar/widget_top_bar_metering.dart';
|
import 'package:lightmeter/screens/metering/components/shared/metering_top_bar/widget_top_bar_metering.dart';
|
||||||
|
@ -10,10 +9,8 @@ import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
class LightSensorContainer extends StatelessWidget {
|
class LightSensorContainer extends StatelessWidget {
|
||||||
final ExposurePair? fastest;
|
final ExposurePair? fastest;
|
||||||
final ExposurePair? slowest;
|
final ExposurePair? slowest;
|
||||||
final Film film;
|
|
||||||
final IsoValue iso;
|
final IsoValue iso;
|
||||||
final NdValue nd;
|
final NdValue nd;
|
||||||
final ValueChanged<Film> onFilmChanged;
|
|
||||||
final ValueChanged<IsoValue> onIsoChanged;
|
final ValueChanged<IsoValue> onIsoChanged;
|
||||||
final ValueChanged<NdValue> onNdChanged;
|
final ValueChanged<NdValue> onNdChanged;
|
||||||
final List<ExposurePair> exposurePairs;
|
final List<ExposurePair> exposurePairs;
|
||||||
|
@ -21,10 +18,8 @@ class LightSensorContainer extends StatelessWidget {
|
||||||
const LightSensorContainer({
|
const LightSensorContainer({
|
||||||
required this.fastest,
|
required this.fastest,
|
||||||
required this.slowest,
|
required this.slowest,
|
||||||
required this.film,
|
|
||||||
required this.iso,
|
required this.iso,
|
||||||
required this.nd,
|
required this.nd,
|
||||||
required this.onFilmChanged,
|
|
||||||
required this.onIsoChanged,
|
required this.onIsoChanged,
|
||||||
required this.onNdChanged,
|
required this.onNdChanged,
|
||||||
required this.exposurePairs,
|
required this.exposurePairs,
|
||||||
|
@ -39,10 +34,8 @@ class LightSensorContainer extends StatelessWidget {
|
||||||
readingsContainer: ReadingsContainer(
|
readingsContainer: ReadingsContainer(
|
||||||
fastest: fastest,
|
fastest: fastest,
|
||||||
slowest: slowest,
|
slowest: slowest,
|
||||||
film: film,
|
|
||||||
iso: iso,
|
iso: iso,
|
||||||
nd: nd,
|
nd: nd,
|
||||||
onFilmChanged: onFilmChanged,
|
|
||||||
onIsoChanged: onIsoChanged,
|
onIsoChanged: onIsoChanged,
|
||||||
onNdChanged: onNdChanged,
|
onNdChanged: onNdChanged,
|
||||||
),
|
),
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:lightmeter/res/dimens.dart';
|
||||||
|
|
||||||
import 'package:lightmeter/screens/metering/components/shared/exposure_pairs_list/components/exposure_pairs_list_item/widget_item_list_exposure_pairs.dart';
|
import 'package:lightmeter/screens/metering/components/shared/exposure_pairs_list/components/exposure_pairs_list_item/widget_item_list_exposure_pairs.dart';
|
||||||
import 'package:lightmeter/screens/shared/icon_placeholder/widget_icon_placeholder.dart';
|
import 'package:lightmeter/screens/shared/icon_placeholder/widget_icon_placeholder.dart';
|
||||||
|
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||||
|
|
||||||
class ExposurePairsList extends StatelessWidget {
|
class ExposurePairsList extends StatelessWidget {
|
||||||
final List<ExposurePair> exposurePairs;
|
final List<ExposurePair> exposurePairs;
|
||||||
|
@ -47,7 +48,8 @@ class ExposurePairsList extends StatelessWidget {
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: ExposurePairsListItem(
|
child: ExposurePairsListItem(
|
||||||
exposurePairs[index].shutterSpeed,
|
Films.selectedOf(context)
|
||||||
|
.reciprocityFailure(exposurePairs[index].shutterSpeed),
|
||||||
tickOnTheLeft: true,
|
tickOnTheLeft: true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
|
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/widget_picker_dialog_animated.dart';
|
||||||
|
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/reading_value_container/widget_container_reading_value.dart';
|
||||||
|
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||||
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
|
|
||||||
|
class EquipmentProfilePicker extends StatelessWidget {
|
||||||
|
const EquipmentProfilePicker();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AnimatedDialogPicker<EquipmentProfile>(
|
||||||
|
icon: Icons.camera,
|
||||||
|
title: S.of(context).equipmentProfile,
|
||||||
|
selectedValue: EquipmentProfiles.selectedOf(context),
|
||||||
|
values: EquipmentProfiles.of(context),
|
||||||
|
itemTitleBuilder: (_, value) => Text(value.id.isEmpty ? S.of(context).none : value.name),
|
||||||
|
onChanged: EquipmentProfileProvider.of(context).setProfile,
|
||||||
|
closedChild: ReadingValueContainer.singleValue(
|
||||||
|
value: ReadingValue(
|
||||||
|
label: S.of(context).equipmentProfile,
|
||||||
|
value: EquipmentProfiles.selectedOf(context).id.isEmpty
|
||||||
|
? S.of(context).none
|
||||||
|
: EquipmentProfiles.selectedOf(context).name,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:lightmeter/data/models/exposure_pair.dart';
|
||||||
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
|
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/reading_value_container/widget_container_reading_value.dart';
|
||||||
|
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||||
|
|
||||||
|
class ExtremeExposurePairsContainer extends StatelessWidget {
|
||||||
|
final ExposurePair? fastest;
|
||||||
|
final ExposurePair? slowest;
|
||||||
|
|
||||||
|
const ExtremeExposurePairsContainer({
|
||||||
|
required this.fastest,
|
||||||
|
required this.slowest,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ReadingValueContainer(
|
||||||
|
values: [
|
||||||
|
ReadingValue(
|
||||||
|
label: S.of(context).fastestExposurePair,
|
||||||
|
value: _exposurePairToString(context, fastest),
|
||||||
|
),
|
||||||
|
ReadingValue(
|
||||||
|
label: S.of(context).slowestExposurePair,
|
||||||
|
value: _exposurePairToString(context, slowest),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String _exposurePairToString(BuildContext context, ExposurePair? pair) {
|
||||||
|
if (pair == null) {
|
||||||
|
return '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
return '${pair.aperture} - ${Films.selectedOf(context).reciprocityFailure(pair.shutterSpeed)}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
|
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/widget_picker_dialog_animated.dart';
|
||||||
|
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/reading_value_container/widget_container_reading_value.dart';
|
||||||
|
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||||
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
|
|
||||||
|
class FilmPicker extends StatelessWidget {
|
||||||
|
final IsoValue selectedIso;
|
||||||
|
|
||||||
|
const FilmPicker({required this.selectedIso});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AnimatedDialogPicker<Film>(
|
||||||
|
icon: Icons.camera_roll,
|
||||||
|
title: S.of(context).film,
|
||||||
|
subtitle: S.of(context).filmReciprocityHint,
|
||||||
|
selectedValue: Films.selectedOf(context),
|
||||||
|
values: Films.inUseOf(context),
|
||||||
|
itemTitleBuilder: (_, value) => Text(value.name.isEmpty ? S.of(context).none : value.name),
|
||||||
|
onChanged: FilmsProvider.of(context).setFilm,
|
||||||
|
closedChild: ReadingValueContainer.singleValue(
|
||||||
|
value: ReadingValue(
|
||||||
|
label: _label(context),
|
||||||
|
value: Films.selectedOf(context).name.isEmpty
|
||||||
|
? S.of(context).none
|
||||||
|
: Films.selectedOf(context).name,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String _label(BuildContext context) {
|
||||||
|
if (Films.selectedOf(context) == const Film.other() ||
|
||||||
|
Films.selectedOf(context).iso == selectedIso.value) {
|
||||||
|
return S.of(context).film;
|
||||||
|
}
|
||||||
|
|
||||||
|
final evDiff = IsoValue(
|
||||||
|
Films.selectedOf(context).iso,
|
||||||
|
StopType.full,
|
||||||
|
).difference(selectedIso);
|
||||||
|
|
||||||
|
if (evDiff > 0) {
|
||||||
|
return S.of(context).filmPush;
|
||||||
|
} else if (evDiff < 0) {
|
||||||
|
return S.of(context).filmPull;
|
||||||
|
} else {
|
||||||
|
return S.of(context).film;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
|
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/widget_picker_dialog_animated.dart';
|
||||||
|
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/reading_value_container/widget_container_reading_value.dart';
|
||||||
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
|
|
||||||
|
class IsoValuePicker extends StatelessWidget {
|
||||||
|
final List<IsoValue> values;
|
||||||
|
final IsoValue selectedValue;
|
||||||
|
final ValueChanged<IsoValue> onChanged;
|
||||||
|
|
||||||
|
const IsoValuePicker({
|
||||||
|
required this.selectedValue,
|
||||||
|
required this.values,
|
||||||
|
required this.onChanged,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AnimatedDialogPicker<IsoValue>(
|
||||||
|
icon: Icons.iso,
|
||||||
|
title: S.of(context).iso,
|
||||||
|
subtitle: S.of(context).filmSpeed,
|
||||||
|
selectedValue: selectedValue,
|
||||||
|
values: values,
|
||||||
|
itemTitleBuilder: (_, value) => Text(value.value.toString()),
|
||||||
|
// using ascending order, because increase in film speed rises EV
|
||||||
|
itemTrailingBuilder: (selected, value) => value.value != selected.value
|
||||||
|
? Text(S.of(context).evValue(selected.toStringDifference(value)))
|
||||||
|
: null,
|
||||||
|
onChanged: onChanged,
|
||||||
|
closedChild: ReadingValueContainer.singleValue(
|
||||||
|
value: ReadingValue(
|
||||||
|
label: S.of(context).iso,
|
||||||
|
value: selectedValue.value.toString(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
|
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/widget_picker_dialog_animated.dart';
|
||||||
|
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/reading_value_container/widget_container_reading_value.dart';
|
||||||
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
|
|
||||||
|
class NdValuePicker extends StatelessWidget {
|
||||||
|
final List<NdValue> values;
|
||||||
|
final NdValue selectedValue;
|
||||||
|
final ValueChanged<NdValue> onChanged;
|
||||||
|
|
||||||
|
const NdValuePicker({
|
||||||
|
required this.selectedValue,
|
||||||
|
required this.values,
|
||||||
|
required this.onChanged,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return AnimatedDialogPicker<NdValue>(
|
||||||
|
icon: Icons.filter_b_and_w,
|
||||||
|
title: S.of(context).nd,
|
||||||
|
subtitle: S.of(context).ndFilterFactor,
|
||||||
|
selectedValue: selectedValue,
|
||||||
|
values: values,
|
||||||
|
itemTitleBuilder: (_, value) => Text(
|
||||||
|
value.value == 0 ? S.of(context).none : value.value.toString(),
|
||||||
|
),
|
||||||
|
// using descending order, because ND filter darkens image & lowers EV
|
||||||
|
itemTrailingBuilder: (selected, value) => value.value != selected.value
|
||||||
|
? Text(S.of(context).evValue(value.toStringDifference(selected)))
|
||||||
|
: null,
|
||||||
|
onChanged: onChanged,
|
||||||
|
closedChild: ReadingValueContainer.singleValue(
|
||||||
|
value: ReadingValue(
|
||||||
|
label: S.of(context).nd,
|
||||||
|
value: selectedValue.value.toString(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/components/animated_dialog/widget_dialog_animated.dart';
|
||||||
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/animated_dialog_picker/components/animated_dialog/widget_dialog_animated.dart';
|
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/shared/animated_dialog_picker/components/dialog_picker/widget_picker_dialog.dart';
|
||||||
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/animated_dialog_picker/components/dialog_picker/widget_picker_dialog.dart';
|
|
||||||
|
|
||||||
// Has to be stateful, so that [GlobalKey] is not recreated.
|
// Has to be stateful, so that [GlobalKey] is not recreated.
|
||||||
// Otherwise use will no be able to close the dialog after EV value has changed.
|
// Otherwise use will no be able to close the dialog after EV value has changed.
|
|
@ -1,32 +1,29 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/data/models/exposure_pair.dart';
|
import 'package:lightmeter/data/models/exposure_pair.dart';
|
||||||
import 'package:lightmeter/data/models/film.dart';
|
|
||||||
import 'package:lightmeter/data/models/metering_screen_layout_config.dart';
|
import 'package:lightmeter/data/models/metering_screen_layout_config.dart';
|
||||||
import 'package:lightmeter/generated/l10n.dart';
|
|
||||||
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
||||||
import 'package:lightmeter/res/dimens.dart';
|
import 'package:lightmeter/res/dimens.dart';
|
||||||
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/animated_dialog_picker/widget_picker_dialog_animated.dart';
|
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/equipment_profile_picker/widget_picker_equipment_profiles.dart';
|
||||||
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/reading_value_container/widget_container_reading_value.dart';
|
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/extreme_exposure_pairs_container/widget_container_extreme_exposure_pairs.dart';
|
||||||
|
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/film_picker/widget_picker_film.dart';
|
||||||
|
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/iso_picker/widget_picker_iso.dart';
|
||||||
|
import 'package:lightmeter/screens/metering/components/shared/readings_container/components/nd_picker/widget_picker_nd.dart';
|
||||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
|
|
||||||
class ReadingsContainer extends StatelessWidget {
|
class ReadingsContainer extends StatelessWidget {
|
||||||
final ExposurePair? fastest;
|
final ExposurePair? fastest;
|
||||||
final ExposurePair? slowest;
|
final ExposurePair? slowest;
|
||||||
final Film film;
|
|
||||||
final IsoValue iso;
|
final IsoValue iso;
|
||||||
final NdValue nd;
|
final NdValue nd;
|
||||||
final ValueChanged<Film> onFilmChanged;
|
|
||||||
final ValueChanged<IsoValue> onIsoChanged;
|
final ValueChanged<IsoValue> onIsoChanged;
|
||||||
final ValueChanged<NdValue> onNdChanged;
|
final ValueChanged<NdValue> onNdChanged;
|
||||||
|
|
||||||
const ReadingsContainer({
|
const ReadingsContainer({
|
||||||
required this.fastest,
|
required this.fastest,
|
||||||
required this.slowest,
|
required this.slowest,
|
||||||
required this.film,
|
|
||||||
required this.iso,
|
required this.iso,
|
||||||
required this.nd,
|
required this.nd,
|
||||||
required this.onFilmChanged,
|
|
||||||
required this.onIsoChanged,
|
required this.onIsoChanged,
|
||||||
required this.onNdChanged,
|
required this.onNdChanged,
|
||||||
super.key,
|
super.key,
|
||||||
|
@ -41,24 +38,16 @@ class ReadingsContainer extends StatelessWidget {
|
||||||
context,
|
context,
|
||||||
MeteringScreenLayoutFeature.equipmentProfiles,
|
MeteringScreenLayoutFeature.equipmentProfiles,
|
||||||
)) ...[
|
)) ...[
|
||||||
const _EquipmentProfilePicker(),
|
const EquipmentProfilePicker(),
|
||||||
const _InnerPadding(),
|
const _InnerPadding(),
|
||||||
],
|
],
|
||||||
if (UserPreferencesProvider.meteringScreenFeatureOf(
|
if (UserPreferencesProvider.meteringScreenFeatureOf(
|
||||||
context,
|
context,
|
||||||
MeteringScreenLayoutFeature.extremeExposurePairs,
|
MeteringScreenLayoutFeature.extremeExposurePairs,
|
||||||
)) ...[
|
)) ...[
|
||||||
ReadingValueContainer(
|
ExtremeExposurePairsContainer(
|
||||||
values: [
|
fastest: fastest,
|
||||||
ReadingValue(
|
slowest: slowest,
|
||||||
label: S.of(context).fastestExposurePair,
|
|
||||||
value: fastest != null ? fastest!.toString() : '-',
|
|
||||||
),
|
|
||||||
ReadingValue(
|
|
||||||
label: S.of(context).slowestExposurePair,
|
|
||||||
value: fastest != null ? slowest!.toString() : '-',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
const _InnerPadding(),
|
const _InnerPadding(),
|
||||||
],
|
],
|
||||||
|
@ -66,17 +55,13 @@ class ReadingsContainer extends StatelessWidget {
|
||||||
context,
|
context,
|
||||||
MeteringScreenLayoutFeature.filmPicker,
|
MeteringScreenLayoutFeature.filmPicker,
|
||||||
)) ...[
|
)) ...[
|
||||||
_FilmPicker(
|
FilmPicker(selectedIso: iso),
|
||||||
values: Film.values,
|
|
||||||
selectedValue: film,
|
|
||||||
onChanged: onFilmChanged,
|
|
||||||
),
|
|
||||||
const _InnerPadding(),
|
const _InnerPadding(),
|
||||||
],
|
],
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _IsoValuePicker(
|
child: IsoValuePicker(
|
||||||
selectedValue: iso,
|
selectedValue: iso,
|
||||||
values: EquipmentProfiles.selectedOf(context).isoValues,
|
values: EquipmentProfiles.selectedOf(context).isoValues,
|
||||||
onChanged: onIsoChanged,
|
onChanged: onIsoChanged,
|
||||||
|
@ -84,7 +69,7 @@ class ReadingsContainer extends StatelessWidget {
|
||||||
),
|
),
|
||||||
const _InnerPadding(),
|
const _InnerPadding(),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _NdValuePicker(
|
child: NdValuePicker(
|
||||||
selectedValue: nd,
|
selectedValue: nd,
|
||||||
values: EquipmentProfiles.selectedOf(context).ndValues,
|
values: EquipmentProfiles.selectedOf(context).ndValues,
|
||||||
onChanged: onNdChanged,
|
onChanged: onNdChanged,
|
||||||
|
@ -100,129 +85,3 @@ class ReadingsContainer extends StatelessWidget {
|
||||||
class _InnerPadding extends SizedBox {
|
class _InnerPadding extends SizedBox {
|
||||||
const _InnerPadding() : super(height: Dimens.grid8, width: Dimens.grid8);
|
const _InnerPadding() : super(height: Dimens.grid8, width: Dimens.grid8);
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EquipmentProfilePicker extends StatelessWidget {
|
|
||||||
const _EquipmentProfilePicker();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return AnimatedDialogPicker<EquipmentProfile>(
|
|
||||||
icon: Icons.camera,
|
|
||||||
title: S.of(context).equipmentProfile,
|
|
||||||
selectedValue: EquipmentProfiles.selectedOf(context),
|
|
||||||
values: EquipmentProfiles.of(context),
|
|
||||||
itemTitleBuilder: (_, value) => Text(value.id.isEmpty ? S.of(context).none : value.name),
|
|
||||||
onChanged: EquipmentProfileProvider.of(context).setProfile,
|
|
||||||
closedChild: ReadingValueContainer.singleValue(
|
|
||||||
value: ReadingValue(
|
|
||||||
label: S.of(context).equipmentProfile,
|
|
||||||
value: EquipmentProfiles.selectedOf(context).id.isEmpty
|
|
||||||
? S.of(context).none
|
|
||||||
: EquipmentProfiles.selectedOf(context).name,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _FilmPicker extends StatelessWidget {
|
|
||||||
final List<Film> values;
|
|
||||||
final Film selectedValue;
|
|
||||||
final ValueChanged<Film> onChanged;
|
|
||||||
|
|
||||||
const _FilmPicker({
|
|
||||||
required this.values,
|
|
||||||
required this.selectedValue,
|
|
||||||
required this.onChanged,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return AnimatedDialogPicker<Film>(
|
|
||||||
icon: Icons.camera_roll,
|
|
||||||
title: S.of(context).film,
|
|
||||||
selectedValue: selectedValue,
|
|
||||||
values: values,
|
|
||||||
itemTitleBuilder: (_, value) => Text(value.name.isEmpty ? S.of(context).none : value.name),
|
|
||||||
onChanged: onChanged,
|
|
||||||
closedChild: ReadingValueContainer.singleValue(
|
|
||||||
value: ReadingValue(
|
|
||||||
label: S.of(context).film,
|
|
||||||
value: selectedValue.name.isEmpty ? S.of(context).none : selectedValue.name,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _IsoValuePicker extends StatelessWidget {
|
|
||||||
final List<IsoValue> values;
|
|
||||||
final IsoValue selectedValue;
|
|
||||||
final ValueChanged<IsoValue> onChanged;
|
|
||||||
|
|
||||||
const _IsoValuePicker({
|
|
||||||
required this.selectedValue,
|
|
||||||
required this.values,
|
|
||||||
required this.onChanged,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return AnimatedDialogPicker<IsoValue>(
|
|
||||||
icon: Icons.iso,
|
|
||||||
title: S.of(context).iso,
|
|
||||||
subtitle: S.of(context).filmSpeed,
|
|
||||||
selectedValue: selectedValue,
|
|
||||||
values: values,
|
|
||||||
itemTitleBuilder: (_, value) => Text(value.value.toString()),
|
|
||||||
// using ascending order, because increase in film speed rises EV
|
|
||||||
itemTrailingBuilder: (selected, value) => value.value != selected.value
|
|
||||||
? Text(S.of(context).evValue(selected.toStringDifference(value)))
|
|
||||||
: null,
|
|
||||||
onChanged: onChanged,
|
|
||||||
closedChild: ReadingValueContainer.singleValue(
|
|
||||||
value: ReadingValue(
|
|
||||||
label: S.of(context).iso,
|
|
||||||
value: selectedValue.value.toString(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class _NdValuePicker extends StatelessWidget {
|
|
||||||
final List<NdValue> values;
|
|
||||||
final NdValue selectedValue;
|
|
||||||
final ValueChanged<NdValue> onChanged;
|
|
||||||
|
|
||||||
const _NdValuePicker({
|
|
||||||
required this.selectedValue,
|
|
||||||
required this.values,
|
|
||||||
required this.onChanged,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return AnimatedDialogPicker<NdValue>(
|
|
||||||
icon: Icons.filter_b_and_w,
|
|
||||||
title: S.of(context).nd,
|
|
||||||
subtitle: S.of(context).ndFilterFactor,
|
|
||||||
selectedValue: selectedValue,
|
|
||||||
values: values,
|
|
||||||
itemTitleBuilder: (_, value) => Text(
|
|
||||||
value.value == 0 ? S.of(context).none : value.value.toString(),
|
|
||||||
),
|
|
||||||
// using descending order, because ND filter darkens image & lowers EV
|
|
||||||
itemTrailingBuilder: (selected, value) => value.value != selected.value
|
|
||||||
? Text(S.of(context).evValue(value.toStringDifference(selected)))
|
|
||||||
: null,
|
|
||||||
onChanged: onChanged,
|
|
||||||
closedChild: ReadingValueContainer.singleValue(
|
|
||||||
value: ReadingValue(
|
|
||||||
label: S.of(context).nd,
|
|
||||||
value: selectedValue.value.toString(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import 'package:lightmeter/data/models/film.dart';
|
|
||||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
|
|
||||||
sealed class MeteringEvent {
|
sealed class MeteringEvent {
|
||||||
|
@ -11,12 +10,6 @@ class EquipmentProfileChangedEvent extends MeteringEvent {
|
||||||
const EquipmentProfileChangedEvent(this.equipmentProfileData);
|
const EquipmentProfileChangedEvent(this.equipmentProfileData);
|
||||||
}
|
}
|
||||||
|
|
||||||
class FilmChangedEvent extends MeteringEvent {
|
|
||||||
final Film film;
|
|
||||||
|
|
||||||
const FilmChangedEvent(this.film);
|
|
||||||
}
|
|
||||||
|
|
||||||
class IsoChangedEvent extends MeteringEvent {
|
class IsoChangedEvent extends MeteringEvent {
|
||||||
final IsoValue isoValue;
|
final IsoValue isoValue;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:lightmeter/data/models/ev_source_type.dart';
|
import 'package:lightmeter/data/models/ev_source_type.dart';
|
||||||
import 'package:lightmeter/data/models/exposure_pair.dart';
|
import 'package:lightmeter/data/models/exposure_pair.dart';
|
||||||
import 'package:lightmeter/data/models/film.dart';
|
|
||||||
import 'package:lightmeter/data/models/metering_screen_layout_config.dart';
|
import 'package:lightmeter/data/models/metering_screen_layout_config.dart';
|
||||||
import 'package:lightmeter/providers/services_provider.dart';
|
import 'package:lightmeter/providers/services_provider.dart';
|
||||||
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
||||||
|
@ -33,11 +32,8 @@ class MeteringScreen extends StatelessWidget {
|
||||||
child: BlocBuilder<MeteringBloc, MeteringState>(
|
child: BlocBuilder<MeteringBloc, MeteringState>(
|
||||||
builder: (_, state) => MeteringContainerBuidler(
|
builder: (_, state) => MeteringContainerBuidler(
|
||||||
ev: state is MeteringDataState ? state.ev : null,
|
ev: state is MeteringDataState ? state.ev : null,
|
||||||
film: state.film,
|
|
||||||
iso: state.iso,
|
iso: state.iso,
|
||||||
nd: state.nd,
|
nd: state.nd,
|
||||||
onFilmChanged: (value) =>
|
|
||||||
context.read<MeteringBloc>().add(FilmChangedEvent(value)),
|
|
||||||
onIsoChanged: (value) => context.read<MeteringBloc>().add(IsoChangedEvent(value)),
|
onIsoChanged: (value) => context.read<MeteringBloc>().add(IsoChangedEvent(value)),
|
||||||
onNdChanged: (value) => context.read<MeteringBloc>().add(NdChangedEvent(value)),
|
onNdChanged: (value) => context.read<MeteringBloc>().add(NdChangedEvent(value)),
|
||||||
),
|
),
|
||||||
|
@ -81,7 +77,7 @@ class _InheritedListeners extends StatelessWidget {
|
||||||
feature: MeteringScreenLayoutFeature.filmPicker,
|
feature: MeteringScreenLayoutFeature.filmPicker,
|
||||||
onDidChangeDependencies: (value) {
|
onDidChangeDependencies: (value) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
context.read<MeteringBloc>().add(const FilmChangedEvent(Film.other()));
|
FilmsProvider.of(context).setFilm(const Film.other());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: child,
|
child: child,
|
||||||
|
@ -92,19 +88,15 @@ class _InheritedListeners extends StatelessWidget {
|
||||||
|
|
||||||
class MeteringContainerBuidler extends StatelessWidget {
|
class MeteringContainerBuidler extends StatelessWidget {
|
||||||
final double? ev;
|
final double? ev;
|
||||||
final Film film;
|
|
||||||
final IsoValue iso;
|
final IsoValue iso;
|
||||||
final NdValue nd;
|
final NdValue nd;
|
||||||
final ValueChanged<Film> onFilmChanged;
|
|
||||||
final ValueChanged<IsoValue> onIsoChanged;
|
final ValueChanged<IsoValue> onIsoChanged;
|
||||||
final ValueChanged<NdValue> onNdChanged;
|
final ValueChanged<NdValue> onNdChanged;
|
||||||
|
|
||||||
const MeteringContainerBuidler({
|
const MeteringContainerBuidler({
|
||||||
required this.ev,
|
required this.ev,
|
||||||
required this.film,
|
|
||||||
required this.iso,
|
required this.iso,
|
||||||
required this.nd,
|
required this.nd,
|
||||||
required this.onFilmChanged,
|
|
||||||
required this.onIsoChanged,
|
required this.onIsoChanged,
|
||||||
required this.onNdChanged,
|
required this.onNdChanged,
|
||||||
});
|
});
|
||||||
|
@ -116,7 +108,6 @@ class MeteringContainerBuidler extends StatelessWidget {
|
||||||
ev!,
|
ev!,
|
||||||
UserPreferencesProvider.stopTypeOf(context),
|
UserPreferencesProvider.stopTypeOf(context),
|
||||||
EquipmentProfiles.selectedOf(context),
|
EquipmentProfiles.selectedOf(context),
|
||||||
film,
|
|
||||||
)
|
)
|
||||||
: <ExposurePair>[];
|
: <ExposurePair>[];
|
||||||
final fastest = exposurePairs.isNotEmpty ? exposurePairs.first : null;
|
final fastest = exposurePairs.isNotEmpty ? exposurePairs.first : null;
|
||||||
|
@ -126,10 +117,8 @@ class MeteringContainerBuidler extends StatelessWidget {
|
||||||
? CameraContainerProvider(
|
? CameraContainerProvider(
|
||||||
fastest: fastest,
|
fastest: fastest,
|
||||||
slowest: slowest,
|
slowest: slowest,
|
||||||
film: film,
|
|
||||||
iso: iso,
|
iso: iso,
|
||||||
nd: nd,
|
nd: nd,
|
||||||
onFilmChanged: onFilmChanged,
|
|
||||||
onIsoChanged: onIsoChanged,
|
onIsoChanged: onIsoChanged,
|
||||||
onNdChanged: onNdChanged,
|
onNdChanged: onNdChanged,
|
||||||
exposurePairs: exposurePairs,
|
exposurePairs: exposurePairs,
|
||||||
|
@ -137,10 +126,8 @@ class MeteringContainerBuidler extends StatelessWidget {
|
||||||
: LightSensorContainerProvider(
|
: LightSensorContainerProvider(
|
||||||
fastest: fastest,
|
fastest: fastest,
|
||||||
slowest: slowest,
|
slowest: slowest,
|
||||||
film: film,
|
|
||||||
iso: iso,
|
iso: iso,
|
||||||
nd: nd,
|
nd: nd,
|
||||||
onFilmChanged: onFilmChanged,
|
|
||||||
onIsoChanged: onIsoChanged,
|
onIsoChanged: onIsoChanged,
|
||||||
onNdChanged: onNdChanged,
|
onNdChanged: onNdChanged,
|
||||||
exposurePairs: exposurePairs,
|
exposurePairs: exposurePairs,
|
||||||
|
@ -152,7 +139,6 @@ class MeteringContainerBuidler extends StatelessWidget {
|
||||||
double ev,
|
double ev,
|
||||||
StopType stopType,
|
StopType stopType,
|
||||||
EquipmentProfile equipmentProfile,
|
EquipmentProfile equipmentProfile,
|
||||||
Film film,
|
|
||||||
) {
|
) {
|
||||||
if (ev.isNaN || ev.isInfinite) {
|
if (ev.isNaN || ev.isInfinite) {
|
||||||
return List.empty();
|
return List.empty();
|
||||||
|
@ -195,7 +181,7 @@ class MeteringContainerBuidler extends StatelessWidget {
|
||||||
itemsCount,
|
itemsCount,
|
||||||
(index) => ExposurePair(
|
(index) => ExposurePair(
|
||||||
apertureValues[index + apertureOffset],
|
apertureValues[index + apertureOffset],
|
||||||
film.reciprocityFailure(shutterSpeedValues[index + shutterSpeedOffset]),
|
shutterSpeedValues[index + shutterSpeedOffset],
|
||||||
),
|
),
|
||||||
growable: false,
|
growable: false,
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,18 +1,15 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/data/models/film.dart';
|
|
||||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
abstract class MeteringState {
|
abstract class MeteringState {
|
||||||
final double? ev100;
|
final double? ev100;
|
||||||
final Film film;
|
|
||||||
final IsoValue iso;
|
final IsoValue iso;
|
||||||
final NdValue nd;
|
final NdValue nd;
|
||||||
final bool isMetering;
|
final bool isMetering;
|
||||||
|
|
||||||
const MeteringState({
|
const MeteringState({
|
||||||
this.ev100,
|
this.ev100,
|
||||||
required this.film,
|
|
||||||
required this.iso,
|
required this.iso,
|
||||||
required this.nd,
|
required this.nd,
|
||||||
required this.isMetering,
|
required this.isMetering,
|
||||||
|
@ -21,7 +18,6 @@ abstract class MeteringState {
|
||||||
|
|
||||||
class LoadingState extends MeteringState {
|
class LoadingState extends MeteringState {
|
||||||
const LoadingState({
|
const LoadingState({
|
||||||
required super.film,
|
|
||||||
required super.iso,
|
required super.iso,
|
||||||
required super.nd,
|
required super.nd,
|
||||||
}) : super(isMetering: true);
|
}) : super(isMetering: true);
|
||||||
|
@ -30,7 +26,6 @@ class LoadingState extends MeteringState {
|
||||||
class MeteringDataState extends MeteringState {
|
class MeteringDataState extends MeteringState {
|
||||||
const MeteringDataState({
|
const MeteringDataState({
|
||||||
required super.ev100,
|
required super.ev100,
|
||||||
required super.film,
|
|
||||||
required super.iso,
|
required super.iso,
|
||||||
required super.nd,
|
required super.nd,
|
||||||
required super.isMetering,
|
required super.isMetering,
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
|
||||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
|
||||||
|
|
||||||
class EquipmentProfileListener extends StatefulWidget {
|
|
||||||
final ValueChanged<EquipmentProfile> onDidChangeDependencies;
|
|
||||||
final Widget child;
|
|
||||||
|
|
||||||
const EquipmentProfileListener({
|
|
||||||
required this.onDidChangeDependencies,
|
|
||||||
required this.child,
|
|
||||||
super.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<EquipmentProfileListener> createState() => _EquipmentProfileListenerState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _EquipmentProfileListenerState extends State<EquipmentProfileListener> {
|
|
||||||
@override
|
|
||||||
void didChangeDependencies() {
|
|
||||||
super.didChangeDependencies();
|
|
||||||
widget.onDidChangeDependencies(EquipmentProfiles.selectedOf(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return widget.child;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/generated/l10n.dart';
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_container/components/equipment_list_tiles/components/dialog_filter/widget_dialog_filter.dart';
|
import 'package:lightmeter/screens/settings/components/shared/dialog_filter/widget_dialog_filter.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_container/components/equipment_list_tiles/components/dialog_range_picker/widget_dialog_picker_range.dart';
|
import 'package:lightmeter/screens/settings/components/shared/dialog_range_picker/widget_dialog_picker_range.dart';
|
||||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
|
|
||||||
class EquipmentListTiles extends StatelessWidget {
|
class EquipmentListTiles extends StatelessWidget {
|
|
@ -3,8 +3,8 @@ import 'dart:math';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
import 'package:lightmeter/res/dimens.dart';
|
import 'package:lightmeter/res/dimens.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_container/components/equipment_list_tiles/widget_list_tiles_equipments.dart';
|
import 'package:lightmeter/screens/settings/components/equipment/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_container/components/equipment_list_tiles/widget_list_tiles_equipments.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_name_dialog/widget_dialog_equipment_profile_name.dart';
|
import 'package:lightmeter/screens/settings/components/equipment/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_name_dialog/widget_dialog_equipment_profile_name.dart';
|
||||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
|
|
||||||
class EquipmentProfileContainer extends StatefulWidget {
|
class EquipmentProfileContainer extends StatefulWidget {
|
|
@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/generated/l10n.dart';
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
|
|
||||||
import 'package:lightmeter/res/dimens.dart';
|
import 'package:lightmeter/res/dimens.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_container/widget_container_equipment_profile.dart';
|
import 'package:lightmeter/screens/settings/components/equipment/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_container/widget_container_equipment_profile.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_name_dialog/widget_dialog_equipment_profile_name.dart';
|
import 'package:lightmeter/screens/settings/components/equipment/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_name_dialog/widget_dialog_equipment_profile_name.dart';
|
||||||
import 'package:lightmeter/screens/shared/icon_placeholder/widget_icon_placeholder.dart';
|
import 'package:lightmeter/screens/shared/icon_placeholder/widget_icon_placeholder.dart';
|
||||||
import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart';
|
import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart';
|
||||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
|
@ -0,0 +1,22 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
|
import 'package:lightmeter/screens/settings/components/equipment/components/equipment_profiles/components/equipment_profile_screen/screen_equipment_profile.dart';
|
||||||
|
import 'package:lightmeter/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart';
|
||||||
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
|
|
||||||
|
class EquipmentProfilesListTile extends StatelessWidget {
|
||||||
|
const EquipmentProfilesListTile({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return IAPListTile(
|
||||||
|
leading: const Icon(Icons.camera),
|
||||||
|
title: Text(S.of(context).equipmentProfiles),
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).push<EquipmentProfile>(
|
||||||
|
MaterialPageRoute(builder: (_) => const EquipmentProfilesScreen()),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
|
import 'package:lightmeter/screens/settings/components/shared/dialog_filter/widget_dialog_filter.dart';
|
||||||
|
import 'package:lightmeter/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart';
|
||||||
|
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||||
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
|
|
||||||
|
class FilmsListTile extends StatelessWidget {
|
||||||
|
const FilmsListTile({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return IAPListTile(
|
||||||
|
leading: const Icon(Icons.camera_roll),
|
||||||
|
title: Text(S.of(context).filmsInUse),
|
||||||
|
onTap: () {
|
||||||
|
showDialog<List<Film>>(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => DialogFilter<Film>(
|
||||||
|
icon: const Icon(Icons.camera_roll),
|
||||||
|
title: S.of(context).filmsInUse,
|
||||||
|
description: S.of(context).filmsInUseDescription,
|
||||||
|
values: Films.of(context).sublist(1),
|
||||||
|
selectedValues: Films.inUseOf(context),
|
||||||
|
titleAdapter: (_, value) => value.name,
|
||||||
|
),
|
||||||
|
).then((values) {
|
||||||
|
if (values != null) {
|
||||||
|
FilmsProvider.of(context).saveFilms(values);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
|
import 'package:lightmeter/screens/settings/components/equipment/components/equipment_profiles/widget_list_tile_equipment_profiles.dart';
|
||||||
|
import 'package:lightmeter/screens/settings/components/equipment/components/films/widget_list_tile_films.dart';
|
||||||
|
import 'package:lightmeter/screens/settings/components/shared/settings_section/widget_settings_section.dart';
|
||||||
|
|
||||||
|
class EquipmentSettingsSection extends StatelessWidget {
|
||||||
|
const EquipmentSettingsSection({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SettingsSection(
|
||||||
|
title: S.of(context).equipment,
|
||||||
|
children: const [
|
||||||
|
EquipmentProfilesListTile(),
|
||||||
|
FilmsListTile(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/data/models/supported_locale.dart';
|
import 'package:lightmeter/data/models/supported_locale.dart';
|
||||||
import 'package:lightmeter/generated/l10n.dart';
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/shared/dialog_picker.dart/widget_dialog_picker.dart';
|
import 'package:lightmeter/screens/settings/components/shared/dialog_picker/widget_dialog_picker.dart';
|
||||||
|
|
||||||
class LanguageListTile extends StatelessWidget {
|
class LanguageListTile extends StatelessWidget {
|
||||||
const LanguageListTile({super.key});
|
const LanguageListTile({super.key});
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:lightmeter/generated/l10n.dart';
|
|
||||||
import 'package:lightmeter/res/dimens.dart';
|
|
||||||
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/screen_equipment_profile.dart';
|
|
||||||
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
|
||||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
|
||||||
|
|
||||||
class EquipmentProfilesListTile extends StatelessWidget {
|
|
||||||
const EquipmentProfilesListTile({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final paidStatus = IAPProducts.productOf(context, IAPProductType.paidFeatures)?.status ??
|
|
||||||
IAPProductStatus.pending;
|
|
||||||
log(paidStatus.toString());
|
|
||||||
return ListTile(
|
|
||||||
leading: const Icon(Icons.camera),
|
|
||||||
title: Text(S.of(context).equipmentProfiles),
|
|
||||||
onTap: switch (paidStatus) {
|
|
||||||
IAPProductStatus.purchased => () {
|
|
||||||
Navigator.of(context).push<EquipmentProfile>(
|
|
||||||
MaterialPageRoute(builder: (_) => const EquipmentProfilesScreen()),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
IAPProductStatus.pending => null,
|
|
||||||
_ => () {
|
|
||||||
IAPProductsProvider.of(context).buy(IAPProductType.paidFeatures);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
trailing: switch (paidStatus) {
|
|
||||||
IAPProductStatus.purchasable => const Icon(Icons.lock),
|
|
||||||
IAPProductStatus.pending => const SizedBox(
|
|
||||||
height: Dimens.grid24,
|
|
||||||
width: Dimens.grid24,
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
),
|
|
||||||
_ => null,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/generated/l10n.dart';
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/shared/dialog_picker.dart/widget_dialog_picker.dart';
|
import 'package:lightmeter/screens/settings/components/shared/dialog_picker/widget_dialog_picker.dart';
|
||||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
|
|
||||||
class StopTypeListTile extends StatelessWidget {
|
class StopTypeListTile extends StatelessWidget {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/generated/l10n.dart';
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/metering/components/calibration/widget_list_tile_calibration.dart';
|
import 'package:lightmeter/screens/settings/components/metering/components/calibration/widget_list_tile_calibration.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/metering/components/equipment_profiles/widget_list_tile_equipment_profiles.dart';
|
|
||||||
import 'package:lightmeter/screens/settings/components/metering/components/fractional_stops/widget_list_tile_fractional_stops.dart';
|
import 'package:lightmeter/screens/settings/components/metering/components/fractional_stops/widget_list_tile_fractional_stops.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/metering/components/metering_screen_layout/widget_list_tile_metering_screen_layout.dart';
|
import 'package:lightmeter/screens/settings/components/metering/components/metering_screen_layout/widget_list_tile_metering_screen_layout.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/shared/settings_section/widget_settings_section.dart';
|
import 'package:lightmeter/screens/settings/components/shared/settings_section/widget_settings_section.dart';
|
||||||
|
@ -17,7 +16,6 @@ class MeteringSettingsSection extends StatelessWidget {
|
||||||
StopTypeListTile(),
|
StopTypeListTile(),
|
||||||
CalibrationListTile(),
|
CalibrationListTile(),
|
||||||
MeteringScreenLayoutListTile(),
|
MeteringScreenLayoutListTile(),
|
||||||
EquipmentProfilesListTile(),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/generated/l10n.dart';
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
import 'package:lightmeter/res/dimens.dart';
|
import 'package:lightmeter/res/dimens.dart';
|
||||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
|
||||||
|
|
||||||
class DialogFilter<T extends PhotographyValue> extends StatefulWidget {
|
class DialogFilter<T> extends StatefulWidget {
|
||||||
final Icon icon;
|
final Icon icon;
|
||||||
final String title;
|
final String title;
|
||||||
final String description;
|
final String description;
|
||||||
|
@ -25,10 +24,10 @@ class DialogFilter<T extends PhotographyValue> extends StatefulWidget {
|
||||||
State<DialogFilter<T>> createState() => _DialogFilterState<T>();
|
State<DialogFilter<T>> createState() => _DialogFilterState<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DialogFilterState<T extends PhotographyValue> extends State<DialogFilter<T>> {
|
class _DialogFilterState<T> extends State<DialogFilter<T>> {
|
||||||
late final List<bool> checkboxValues = List.generate(
|
late final List<bool> checkboxValues = List.generate(
|
||||||
widget.values.length,
|
widget.values.length,
|
||||||
(index) => widget.selectedValues.any((element) => element.value == widget.values[index].value),
|
(index) => widget.selectedValues.any((element) => element == widget.values[index]),
|
||||||
growable: false,
|
growable: false,
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
|
||||||
|
|
||||||
|
/// Depends on the product status and replaces [onTap] with purchase callback
|
||||||
|
/// if the product is purchasable.
|
||||||
|
class IAPListTile extends StatelessWidget {
|
||||||
|
final IAPProductType product;
|
||||||
|
final Icon leading;
|
||||||
|
final Text title;
|
||||||
|
final VoidCallback onTap;
|
||||||
|
|
||||||
|
const IAPListTile({
|
||||||
|
this.product = IAPProductType.paidFeatures,
|
||||||
|
required this.leading,
|
||||||
|
required this.title,
|
||||||
|
required this.onTap,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListTile(
|
||||||
|
leading: leading,
|
||||||
|
title: title,
|
||||||
|
onTap: switch (IAPProducts.productOf(context, product)?.status) {
|
||||||
|
IAPProductStatus.purchasable => () => IAPProductsProvider.of(context).buy(product),
|
||||||
|
IAPProductStatus.pending => null,
|
||||||
|
IAPProductStatus.purchased => onTap,
|
||||||
|
null => null,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,10 +4,12 @@ import 'package:lightmeter/res/dimens.dart';
|
||||||
class SettingsSection extends StatelessWidget {
|
class SettingsSection extends StatelessWidget {
|
||||||
final String title;
|
final String title;
|
||||||
final List<Widget> children;
|
final List<Widget> children;
|
||||||
|
final bool enabled;
|
||||||
|
|
||||||
const SettingsSection({
|
const SettingsSection({
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.children,
|
required this.children,
|
||||||
|
this.enabled = true,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -23,22 +25,25 @@ class SettingsSection extends StatelessWidget {
|
||||||
child: Card(
|
child: Card(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: Dimens.paddingM),
|
padding: const EdgeInsets.symmetric(vertical: Dimens.paddingM),
|
||||||
child: Column(
|
child: Opacity(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
opacity: enabled ? Dimens.enabledOpacity : Dimens.disabledOpacity,
|
||||||
mainAxisSize: MainAxisSize.min,
|
child: Column(
|
||||||
children: [
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
Padding(
|
mainAxisSize: MainAxisSize.min,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingM),
|
children: [
|
||||||
child: Text(
|
Padding(
|
||||||
title,
|
padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingM),
|
||||||
style: Theme.of(context)
|
child: Text(
|
||||||
.textTheme
|
title,
|
||||||
.labelLarge
|
style: Theme.of(context)
|
||||||
?.copyWith(color: Theme.of(context).colorScheme.onSurface),
|
.textTheme
|
||||||
|
.labelLarge
|
||||||
|
?.copyWith(color: Theme.of(context).colorScheme.onSurface),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
...children,
|
||||||
...children,
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/data/models/theme_type.dart';
|
import 'package:lightmeter/data/models/theme_type.dart';
|
||||||
import 'package:lightmeter/generated/l10n.dart';
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/shared/dialog_picker.dart/widget_dialog_picker.dart';
|
import 'package:lightmeter/screens/settings/components/shared/dialog_picker/widget_dialog_picker.dart';
|
||||||
|
|
||||||
class ThemeTypeListTile extends StatelessWidget {
|
class ThemeTypeListTile extends StatelessWidget {
|
||||||
const ThemeTypeListTile({super.key});
|
const ThemeTypeListTile({super.key});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/generated/l10n.dart';
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/about/widget_settings_section_about.dart';
|
import 'package:lightmeter/screens/settings/components/about/widget_settings_section_about.dart';
|
||||||
|
import 'package:lightmeter/screens/settings/components/equipment/widget_settings_section_equipment.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/general/widget_settings_section_general.dart';
|
import 'package:lightmeter/screens/settings/components/general/widget_settings_section_general.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/metering/widget_settings_section_metering.dart';
|
import 'package:lightmeter/screens/settings/components/metering/widget_settings_section_metering.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/theme/widget_settings_section_theme.dart';
|
import 'package:lightmeter/screens/settings/components/theme/widget_settings_section_theme.dart';
|
||||||
|
@ -43,6 +44,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||||
delegate: SliverChildListDelegate(
|
delegate: SliverChildListDelegate(
|
||||||
<Widget>[
|
<Widget>[
|
||||||
const MeteringSettingsSection(),
|
const MeteringSettingsSection(),
|
||||||
|
const EquipmentSettingsSection(),
|
||||||
const GeneralSettingsSection(),
|
const GeneralSettingsSection(),
|
||||||
const ThemeSettingsSection(),
|
const ThemeSettingsSection(),
|
||||||
const AboutSettingsSection(),
|
const AboutSettingsSection(),
|
||||||
|
|
11
m3_lightmeter.code-workspace
Normal file
11
m3_lightmeter.code-workspace
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": "iap"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": {}
|
||||||
|
}
|
|
@ -1,121 +0,0 @@
|
||||||
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),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:lightmeter/data/models/ev_source_type.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/metering_screen_layout_config.dart';
|
||||||
import 'package:lightmeter/data/models/supported_locale.dart';
|
import 'package:lightmeter/data/models/supported_locale.dart';
|
||||||
import 'package:lightmeter/data/models/theme_type.dart';
|
import 'package:lightmeter/data/models/theme_type.dart';
|
||||||
|
@ -392,26 +391,4 @@ void main() {
|
||||||
.called(1);
|
.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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:lightmeter/data/caffeine_service.dart';
|
import 'package:lightmeter/data/caffeine_service.dart';
|
||||||
import 'package:lightmeter/data/haptics_service.dart';
|
import 'package:lightmeter/data/haptics_service.dart';
|
||||||
import 'package:lightmeter/data/light_sensor_service.dart';
|
import 'package:lightmeter/data/light_sensor_service.dart';
|
||||||
import 'package:lightmeter/data/models/film.dart';
|
|
||||||
import 'package:lightmeter/data/models/volume_action.dart';
|
import 'package:lightmeter/data/models/volume_action.dart';
|
||||||
import 'package:lightmeter/data/permissions_service.dart';
|
import 'package:lightmeter/data/permissions_service.dart';
|
||||||
import 'package:lightmeter/data/shared_prefs_service.dart';
|
import 'package:lightmeter/data/shared_prefs_service.dart';
|
||||||
|
@ -124,19 +123,6 @@ void main() {
|
||||||
interactor.ndFilter = NdValue.values.first;
|
interactor.ndFilter = NdValue.values.first;
|
||||||
verify(() => mockUserPreferencesService.ndFilter = NdValue.values.first).called(1);
|
verify(() => mockUserPreferencesService.ndFilter = NdValue.values.first).called(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('film - get', () async {
|
|
||||||
when(() => mockUserPreferencesService.film).thenReturn(Film.values.first);
|
|
||||||
expect(interactor.film, Film.values.first);
|
|
||||||
verify(() => mockUserPreferencesService.film).called(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('film - set', () async {
|
|
||||||
when(() => mockUserPreferencesService.film = Film.values.first)
|
|
||||||
.thenReturn(Film.values.first);
|
|
||||||
interactor.film = Film.values.first;
|
|
||||||
verify(() => mockUserPreferencesService.film = Film.values.first).called(1);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:bloc_test/bloc_test.dart';
|
import 'package:bloc_test/bloc_test.dart';
|
||||||
import 'package:lightmeter/data/models/film.dart';
|
|
||||||
import 'package:lightmeter/data/models/volume_action.dart';
|
import 'package:lightmeter/data/models/volume_action.dart';
|
||||||
import 'package:lightmeter/interactors/metering_interactor.dart';
|
import 'package:lightmeter/interactors/metering_interactor.dart';
|
||||||
import 'package:lightmeter/screens/metering/bloc_metering.dart';
|
import 'package:lightmeter/screens/metering/bloc_metering.dart';
|
||||||
|
@ -34,7 +33,6 @@ void main() {
|
||||||
meteringInteractor = _MockMeteringInteractor();
|
meteringInteractor = _MockMeteringInteractor();
|
||||||
when<IsoValue>(() => meteringInteractor.iso).thenReturn(iso100);
|
when<IsoValue>(() => meteringInteractor.iso).thenReturn(iso100);
|
||||||
when<NdValue>(() => meteringInteractor.ndFilter).thenReturn(NdValue.values.first);
|
when<NdValue>(() => meteringInteractor.ndFilter).thenReturn(NdValue.values.first);
|
||||||
when<Film>(() => meteringInteractor.film).thenReturn(Film.values.first);
|
|
||||||
when(meteringInteractor.quickVibration).thenAnswer((_) async {});
|
when(meteringInteractor.quickVibration).thenAnswer((_) async {});
|
||||||
when(meteringInteractor.responseVibration).thenAnswer((_) async {});
|
when(meteringInteractor.responseVibration).thenAnswer((_) async {});
|
||||||
when(meteringInteractor.errorVibration).thenAnswer((_) async {});
|
when(meteringInteractor.errorVibration).thenAnswer((_) async {});
|
||||||
|
@ -157,7 +155,6 @@ void main() {
|
||||||
build: () => bloc,
|
build: () => bloc,
|
||||||
seed: () => MeteringDataState(
|
seed: () => MeteringDataState(
|
||||||
ev100: 1.0,
|
ev100: 1.0,
|
||||||
film: Film.values[1],
|
|
||||||
iso: const IsoValue(100, StopType.full),
|
iso: const IsoValue(100, StopType.full),
|
||||||
nd: NdValue.values.first,
|
nd: NdValue.values.first,
|
||||||
isMetering: false,
|
isMetering: false,
|
||||||
|
@ -166,14 +163,12 @@ void main() {
|
||||||
bloc.add(const IsoChangedEvent(IsoValue(200, StopType.full)));
|
bloc.add(const IsoChangedEvent(IsoValue(200, StopType.full)));
|
||||||
},
|
},
|
||||||
verify: (_) {
|
verify: (_) {
|
||||||
verify(() => meteringInteractor.film = Film.values.first).called(1);
|
|
||||||
verify(() => meteringInteractor.iso = const IsoValue(200, StopType.full)).called(1);
|
verify(() => meteringInteractor.iso = const IsoValue(200, StopType.full)).called(1);
|
||||||
},
|
},
|
||||||
expect: () => [
|
expect: () => [
|
||||||
isA<MeteringDataState>()
|
isA<MeteringDataState>()
|
||||||
.having((state) => state.ev100, 'ev100', 1.0)
|
.having((state) => state.ev100, 'ev100', 1.0)
|
||||||
.having((state) => state.ev, 'ev', 2.0)
|
.having((state) => state.ev, 'ev', 2.0)
|
||||||
.having((state) => state.film, 'film', Film.values.first)
|
|
||||||
.having((state) => state.iso, 'iso', const IsoValue(200, StopType.full))
|
.having((state) => state.iso, 'iso', const IsoValue(200, StopType.full))
|
||||||
.having((state) => state.nd, 'nd', NdValue.values.first)
|
.having((state) => state.nd, 'nd', NdValue.values.first)
|
||||||
.having((state) => state.isMetering, 'isMetering', false),
|
.having((state) => state.isMetering, 'isMetering', false),
|
||||||
|
@ -185,7 +180,6 @@ void main() {
|
||||||
build: () => bloc,
|
build: () => bloc,
|
||||||
seed: () => MeteringDataState(
|
seed: () => MeteringDataState(
|
||||||
ev100: null,
|
ev100: null,
|
||||||
film: Film.values[1],
|
|
||||||
iso: const IsoValue(100, StopType.full),
|
iso: const IsoValue(100, StopType.full),
|
||||||
nd: NdValue.values.first,
|
nd: NdValue.values.first,
|
||||||
isMetering: false,
|
isMetering: false,
|
||||||
|
@ -194,14 +188,12 @@ void main() {
|
||||||
bloc.add(const IsoChangedEvent(IsoValue(200, StopType.full)));
|
bloc.add(const IsoChangedEvent(IsoValue(200, StopType.full)));
|
||||||
},
|
},
|
||||||
verify: (_) {
|
verify: (_) {
|
||||||
verify(() => meteringInteractor.film = Film.values.first).called(1);
|
|
||||||
verify(() => meteringInteractor.iso = const IsoValue(200, StopType.full)).called(1);
|
verify(() => meteringInteractor.iso = const IsoValue(200, StopType.full)).called(1);
|
||||||
},
|
},
|
||||||
expect: () => [
|
expect: () => [
|
||||||
isA<MeteringDataState>()
|
isA<MeteringDataState>()
|
||||||
.having((state) => state.ev100, 'ev100', null)
|
.having((state) => state.ev100, 'ev100', null)
|
||||||
.having((state) => state.ev, 'ev', null)
|
.having((state) => state.ev, 'ev', null)
|
||||||
.having((state) => state.film, 'film', Film.values.first)
|
|
||||||
.having((state) => state.iso, 'iso', const IsoValue(200, StopType.full))
|
.having((state) => state.iso, 'iso', const IsoValue(200, StopType.full))
|
||||||
.having((state) => state.nd, 'nd', NdValue.values.first)
|
.having((state) => state.nd, 'nd', NdValue.values.first)
|
||||||
.having((state) => state.isMetering, 'isMetering', false),
|
.having((state) => state.isMetering, 'isMetering', false),
|
||||||
|
@ -213,7 +205,6 @@ void main() {
|
||||||
build: () => bloc,
|
build: () => bloc,
|
||||||
seed: () => MeteringDataState(
|
seed: () => MeteringDataState(
|
||||||
ev100: 1.0,
|
ev100: 1.0,
|
||||||
film: Film.values[1],
|
|
||||||
iso: const IsoValue(100, StopType.full),
|
iso: const IsoValue(100, StopType.full),
|
||||||
nd: NdValue.values.first,
|
nd: NdValue.values.first,
|
||||||
isMetering: false,
|
isMetering: false,
|
||||||
|
@ -222,7 +213,6 @@ void main() {
|
||||||
bloc.add(const IsoChangedEvent(IsoValue(100, StopType.full)));
|
bloc.add(const IsoChangedEvent(IsoValue(100, StopType.full)));
|
||||||
},
|
},
|
||||||
verify: (_) {
|
verify: (_) {
|
||||||
verify(() => meteringInteractor.film = Film.values.first).called(1);
|
|
||||||
verifyNever(() => meteringInteractor.iso = const IsoValue(100, StopType.full));
|
verifyNever(() => meteringInteractor.iso = const IsoValue(100, StopType.full));
|
||||||
},
|
},
|
||||||
expect: () => [],
|
expect: () => [],
|
||||||
|
@ -233,7 +223,6 @@ void main() {
|
||||||
build: () => bloc,
|
build: () => bloc,
|
||||||
seed: () => MeteringDataState(
|
seed: () => MeteringDataState(
|
||||||
ev100: 1.0,
|
ev100: 1.0,
|
||||||
film: Film.values[1],
|
|
||||||
iso: const IsoValue(100, StopType.full),
|
iso: const IsoValue(100, StopType.full),
|
||||||
nd: NdValue.values.first,
|
nd: NdValue.values.first,
|
||||||
isMetering: false,
|
isMetering: false,
|
||||||
|
@ -244,14 +233,12 @@ void main() {
|
||||||
bloc.onCommunicationState(const communication_states.MeteringEndedState(2));
|
bloc.onCommunicationState(const communication_states.MeteringEndedState(2));
|
||||||
},
|
},
|
||||||
verify: (_) {
|
verify: (_) {
|
||||||
verify(() => meteringInteractor.film = Film.values.first).called(1);
|
|
||||||
verify(() => meteringInteractor.iso = const IsoValue(200, StopType.full)).called(1);
|
verify(() => meteringInteractor.iso = const IsoValue(200, StopType.full)).called(1);
|
||||||
},
|
},
|
||||||
expect: () => [
|
expect: () => [
|
||||||
isA<MeteringDataState>()
|
isA<MeteringDataState>()
|
||||||
.having((state) => state.ev100, 'ev100', 1.0)
|
.having((state) => state.ev100, 'ev100', 1.0)
|
||||||
.having((state) => state.ev, 'ev', 2.0)
|
.having((state) => state.ev, 'ev', 2.0)
|
||||||
.having((state) => state.film, 'film', Film.values.first)
|
|
||||||
.having((state) => state.iso, 'iso', const IsoValue(200, StopType.full))
|
.having((state) => state.iso, 'iso', const IsoValue(200, StopType.full))
|
||||||
.having((state) => state.nd, 'nd', NdValue.values.first)
|
.having((state) => state.nd, 'nd', NdValue.values.first)
|
||||||
.having((state) => state.isMetering, 'isMetering', false),
|
.having((state) => state.isMetering, 'isMetering', false),
|
||||||
|
@ -259,7 +246,6 @@ void main() {
|
||||||
isA<MeteringDataState>()
|
isA<MeteringDataState>()
|
||||||
.having((state) => state.ev100, 'ev100', 2.0)
|
.having((state) => state.ev100, 'ev100', 2.0)
|
||||||
.having((state) => state.ev, 'ev', 3.0)
|
.having((state) => state.ev, 'ev', 3.0)
|
||||||
.having((state) => state.film, 'film', Film.values.first)
|
|
||||||
.having((state) => state.iso, 'iso', const IsoValue(200, StopType.full))
|
.having((state) => state.iso, 'iso', const IsoValue(200, StopType.full))
|
||||||
.having((state) => state.nd, 'nd', NdValue.values.first)
|
.having((state) => state.nd, 'nd', NdValue.values.first)
|
||||||
.having((state) => state.isMetering, 'isMetering', false),
|
.having((state) => state.isMetering, 'isMetering', false),
|
||||||
|
@ -276,7 +262,6 @@ void main() {
|
||||||
build: () => bloc,
|
build: () => bloc,
|
||||||
seed: () => MeteringDataState(
|
seed: () => MeteringDataState(
|
||||||
ev100: 1.0,
|
ev100: 1.0,
|
||||||
film: Film.values[1],
|
|
||||||
iso: const IsoValue(100, StopType.full),
|
iso: const IsoValue(100, StopType.full),
|
||||||
nd: NdValue.values.first,
|
nd: NdValue.values.first,
|
||||||
isMetering: false,
|
isMetering: false,
|
||||||
|
@ -291,7 +276,6 @@ void main() {
|
||||||
isA<MeteringDataState>()
|
isA<MeteringDataState>()
|
||||||
.having((state) => state.ev100, 'ev100', 1.0)
|
.having((state) => state.ev100, 'ev100', 1.0)
|
||||||
.having((state) => state.ev, 'ev', 0.0)
|
.having((state) => state.ev, 'ev', 0.0)
|
||||||
.having((state) => state.film, 'film', Film.values[1])
|
|
||||||
.having((state) => state.iso, 'iso', const IsoValue(100, StopType.full))
|
.having((state) => state.iso, 'iso', const IsoValue(100, StopType.full))
|
||||||
.having((state) => state.nd, 'nd', const NdValue(2))
|
.having((state) => state.nd, 'nd', const NdValue(2))
|
||||||
.having((state) => state.isMetering, 'isMetering', false),
|
.having((state) => state.isMetering, 'isMetering', false),
|
||||||
|
@ -303,7 +287,6 @@ void main() {
|
||||||
build: () => bloc,
|
build: () => bloc,
|
||||||
seed: () => MeteringDataState(
|
seed: () => MeteringDataState(
|
||||||
ev100: null,
|
ev100: null,
|
||||||
film: Film.values[1],
|
|
||||||
iso: const IsoValue(100, StopType.full),
|
iso: const IsoValue(100, StopType.full),
|
||||||
nd: NdValue.values.first,
|
nd: NdValue.values.first,
|
||||||
isMetering: false,
|
isMetering: false,
|
||||||
|
@ -318,7 +301,6 @@ void main() {
|
||||||
isA<MeteringDataState>()
|
isA<MeteringDataState>()
|
||||||
.having((state) => state.ev100, 'ev100', null)
|
.having((state) => state.ev100, 'ev100', null)
|
||||||
.having((state) => state.ev, 'ev', null)
|
.having((state) => state.ev, 'ev', null)
|
||||||
.having((state) => state.film, 'film', Film.values[1])
|
|
||||||
.having((state) => state.iso, 'iso', const IsoValue(100, StopType.full))
|
.having((state) => state.iso, 'iso', const IsoValue(100, StopType.full))
|
||||||
.having((state) => state.nd, 'nd', const NdValue(2))
|
.having((state) => state.nd, 'nd', const NdValue(2))
|
||||||
.having((state) => state.isMetering, 'isMetering', false),
|
.having((state) => state.isMetering, 'isMetering', false),
|
||||||
|
@ -330,7 +312,6 @@ void main() {
|
||||||
build: () => bloc,
|
build: () => bloc,
|
||||||
seed: () => MeteringDataState(
|
seed: () => MeteringDataState(
|
||||||
ev100: 1.0,
|
ev100: 1.0,
|
||||||
film: Film.values[1],
|
|
||||||
iso: const IsoValue(100, StopType.full),
|
iso: const IsoValue(100, StopType.full),
|
||||||
nd: NdValue.values.first,
|
nd: NdValue.values.first,
|
||||||
isMetering: false,
|
isMetering: false,
|
||||||
|
@ -349,7 +330,6 @@ void main() {
|
||||||
build: () => bloc,
|
build: () => bloc,
|
||||||
seed: () => MeteringDataState(
|
seed: () => MeteringDataState(
|
||||||
ev100: 1.0,
|
ev100: 1.0,
|
||||||
film: Film.values[1],
|
|
||||||
iso: const IsoValue(100, StopType.full),
|
iso: const IsoValue(100, StopType.full),
|
||||||
nd: NdValue.values.first,
|
nd: NdValue.values.first,
|
||||||
isMetering: false,
|
isMetering: false,
|
||||||
|
@ -366,7 +346,6 @@ void main() {
|
||||||
isA<MeteringDataState>()
|
isA<MeteringDataState>()
|
||||||
.having((state) => state.ev100, 'ev100', 1.0)
|
.having((state) => state.ev100, 'ev100', 1.0)
|
||||||
.having((state) => state.ev, 'ev', 0.0)
|
.having((state) => state.ev, 'ev', 0.0)
|
||||||
.having((state) => state.film, 'film', Film.values[1])
|
|
||||||
.having((state) => state.iso, 'iso', const IsoValue(100, StopType.full))
|
.having((state) => state.iso, 'iso', const IsoValue(100, StopType.full))
|
||||||
.having((state) => state.nd, 'nd', const NdValue(2))
|
.having((state) => state.nd, 'nd', const NdValue(2))
|
||||||
.having((state) => state.isMetering, 'isMetering', false),
|
.having((state) => state.isMetering, 'isMetering', false),
|
||||||
|
@ -374,7 +353,6 @@ void main() {
|
||||||
isA<MeteringDataState>()
|
isA<MeteringDataState>()
|
||||||
.having((state) => state.ev100, 'ev100', 2.0)
|
.having((state) => state.ev100, 'ev100', 2.0)
|
||||||
.having((state) => state.ev, 'ev', 1.0)
|
.having((state) => state.ev, 'ev', 1.0)
|
||||||
.having((state) => state.film, 'film', Film.values[1])
|
|
||||||
.having((state) => state.iso, 'iso', const IsoValue(100, StopType.full))
|
.having((state) => state.iso, 'iso', const IsoValue(100, StopType.full))
|
||||||
.having((state) => state.nd, 'nd', const NdValue(2))
|
.having((state) => state.nd, 'nd', const NdValue(2))
|
||||||
.having((state) => state.isMetering, 'isMetering', false),
|
.having((state) => state.isMetering, 'isMetering', false),
|
||||||
|
@ -383,115 +361,6 @@ void main() {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
group(
|
|
||||||
'`FilmChangedEvent`',
|
|
||||||
() {
|
|
||||||
blocTest<MeteringBloc, MeteringState>(
|
|
||||||
'Pick different film with different ISO',
|
|
||||||
build: () => bloc,
|
|
||||||
seed: () => MeteringDataState(
|
|
||||||
ev100: 1.0,
|
|
||||||
film: const FomapanFilm.creative100(),
|
|
||||||
iso: const IsoValue(100, StopType.full),
|
|
||||||
nd: NdValue.values.first,
|
|
||||||
isMetering: false,
|
|
||||||
),
|
|
||||||
act: (bloc) async {
|
|
||||||
bloc.add(const FilmChangedEvent(FomapanFilm.creative200()));
|
|
||||||
},
|
|
||||||
verify: (_) {
|
|
||||||
verify(() => meteringInteractor.film = const FomapanFilm.creative200()).called(1);
|
|
||||||
verify(() => meteringInteractor.iso = const IsoValue(200, StopType.full)).called(1);
|
|
||||||
},
|
|
||||||
expect: () => [
|
|
||||||
isA<MeteringDataState>()
|
|
||||||
.having((state) => state.ev100, 'ev100', 1.0)
|
|
||||||
.having((state) => state.ev, 'ev', 2.0)
|
|
||||||
.having((state) => state.film, 'film', const FomapanFilm.creative200())
|
|
||||||
.having((state) => state.iso, 'iso', const IsoValue(200, StopType.full))
|
|
||||||
.having((state) => state.nd, 'nd', NdValue.values.first)
|
|
||||||
.having((state) => state.isMetering, 'isMetering', false),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
blocTest<MeteringBloc, MeteringState>(
|
|
||||||
'Pick different film with same ISO',
|
|
||||||
build: () => bloc,
|
|
||||||
seed: () => MeteringDataState(
|
|
||||||
ev100: 1.0,
|
|
||||||
film: const FomapanFilm.creative100(),
|
|
||||||
iso: const IsoValue(100, StopType.full),
|
|
||||||
nd: NdValue.values.first,
|
|
||||||
isMetering: false,
|
|
||||||
),
|
|
||||||
act: (bloc) async {
|
|
||||||
bloc.add(const FilmChangedEvent(IlfordFilm.delta100()));
|
|
||||||
},
|
|
||||||
verify: (_) {
|
|
||||||
verify(() => meteringInteractor.film = const IlfordFilm.delta100()).called(1);
|
|
||||||
verifyNever(() => meteringInteractor.iso = const IsoValue(100, StopType.full));
|
|
||||||
},
|
|
||||||
expect: () => [
|
|
||||||
isA<MeteringDataState>()
|
|
||||||
.having((state) => state.ev100, 'ev100', 1.0)
|
|
||||||
.having((state) => state.ev, 'ev', 1.0)
|
|
||||||
.having((state) => state.film, 'film', const IlfordFilm.delta100())
|
|
||||||
.having((state) => state.iso, 'iso', const IsoValue(100, StopType.full))
|
|
||||||
.having((state) => state.nd, 'nd', NdValue.values.first)
|
|
||||||
.having((state) => state.isMetering, 'isMetering', false),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
blocTest<MeteringBloc, MeteringState>(
|
|
||||||
'Pick same film',
|
|
||||||
build: () => bloc,
|
|
||||||
seed: () => MeteringDataState(
|
|
||||||
ev100: 1.0,
|
|
||||||
film: const FomapanFilm.creative100(),
|
|
||||||
iso: const IsoValue(100, StopType.full),
|
|
||||||
nd: NdValue.values.first,
|
|
||||||
isMetering: false,
|
|
||||||
),
|
|
||||||
act: (bloc) async {
|
|
||||||
bloc.add(const FilmChangedEvent(FomapanFilm.creative100()));
|
|
||||||
},
|
|
||||||
verify: (_) {
|
|
||||||
verifyNever(() => meteringInteractor.film = const FomapanFilm.creative100());
|
|
||||||
},
|
|
||||||
expect: () => [],
|
|
||||||
);
|
|
||||||
|
|
||||||
blocTest<MeteringBloc, MeteringState>(
|
|
||||||
'Pick `Film.other()`',
|
|
||||||
build: () => bloc,
|
|
||||||
seed: () => MeteringDataState(
|
|
||||||
ev100: 1.0,
|
|
||||||
film: const FomapanFilm.creative100(),
|
|
||||||
iso: const IsoValue(100, StopType.full),
|
|
||||||
nd: NdValue.values.first,
|
|
||||||
isMetering: false,
|
|
||||||
),
|
|
||||||
act: (bloc) async {
|
|
||||||
bloc.add(const FilmChangedEvent(Film.other()));
|
|
||||||
},
|
|
||||||
verify: (_) {
|
|
||||||
verify(() => meteringInteractor.film = const Film.other()).called(1);
|
|
||||||
verifyNever(() => meteringInteractor.iso = const IsoValue(0, StopType.full));
|
|
||||||
verifyNever(() => meteringInteractor.responseVibration());
|
|
||||||
},
|
|
||||||
expect: () => [
|
|
||||||
isA<MeteringDataState>()
|
|
||||||
.having((state) => state.ev100, 'ev100', 1.0)
|
|
||||||
.having((state) => state.ev, 'ev', 1.0)
|
|
||||||
.having((state) => state.film, 'film', const Film.other())
|
|
||||||
.having((state) => state.iso, 'iso', const IsoValue(100, StopType.full))
|
|
||||||
.having((state) => state.nd, 'nd', NdValue.values.first)
|
|
||||||
.having((state) => state.isMetering, 'isMetering', false),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
group(
|
group(
|
||||||
'`EquipmentProfileChangedEvent`',
|
'`EquipmentProfileChangedEvent`',
|
||||||
() {
|
() {
|
||||||
|
@ -509,7 +378,6 @@ void main() {
|
||||||
build: () => bloc,
|
build: () => bloc,
|
||||||
seed: () => MeteringDataState(
|
seed: () => MeteringDataState(
|
||||||
ev100: 1.0,
|
ev100: 1.0,
|
||||||
film: Film.values[1],
|
|
||||||
iso: const IsoValue(100, StopType.full),
|
iso: const IsoValue(100, StopType.full),
|
||||||
nd: NdValue.values.first,
|
nd: NdValue.values.first,
|
||||||
isMetering: false,
|
isMetering: false,
|
||||||
|
@ -518,7 +386,6 @@ void main() {
|
||||||
bloc.add(EquipmentProfileChangedEvent(reducedProfile));
|
bloc.add(EquipmentProfileChangedEvent(reducedProfile));
|
||||||
},
|
},
|
||||||
verify: (_) {
|
verify: (_) {
|
||||||
verifyNever(() => meteringInteractor.film = const Film.other());
|
|
||||||
verifyNever(() => meteringInteractor.iso = reducedProfile.isoValues.first);
|
verifyNever(() => meteringInteractor.iso = reducedProfile.isoValues.first);
|
||||||
verifyNever(() => meteringInteractor.ndFilter = reducedProfile.ndValues.first);
|
verifyNever(() => meteringInteractor.ndFilter = reducedProfile.ndValues.first);
|
||||||
verifyNever(() => meteringInteractor.responseVibration());
|
verifyNever(() => meteringInteractor.responseVibration());
|
||||||
|
@ -531,7 +398,6 @@ void main() {
|
||||||
build: () => bloc,
|
build: () => bloc,
|
||||||
seed: () => MeteringDataState(
|
seed: () => MeteringDataState(
|
||||||
ev100: 1.0,
|
ev100: 1.0,
|
||||||
film: Film.values[1],
|
|
||||||
iso: IsoValue.values[2],
|
iso: IsoValue.values[2],
|
||||||
nd: NdValue.values.first,
|
nd: NdValue.values.first,
|
||||||
isMetering: false,
|
isMetering: false,
|
||||||
|
@ -540,7 +406,6 @@ void main() {
|
||||||
bloc.add(EquipmentProfileChangedEvent(reducedProfile));
|
bloc.add(EquipmentProfileChangedEvent(reducedProfile));
|
||||||
},
|
},
|
||||||
verify: (_) {
|
verify: (_) {
|
||||||
verify(() => meteringInteractor.film = const Film.other()).called(1);
|
|
||||||
verify(() => meteringInteractor.iso = reducedProfile.isoValues.first).called(1);
|
verify(() => meteringInteractor.iso = reducedProfile.isoValues.first).called(1);
|
||||||
verifyNever(() => meteringInteractor.ndFilter = reducedProfile.ndValues.first);
|
verifyNever(() => meteringInteractor.ndFilter = reducedProfile.ndValues.first);
|
||||||
verify(() => meteringInteractor.responseVibration()).called(1);
|
verify(() => meteringInteractor.responseVibration()).called(1);
|
||||||
|
@ -548,7 +413,6 @@ void main() {
|
||||||
expect: () => [
|
expect: () => [
|
||||||
isA<MeteringDataState>()
|
isA<MeteringDataState>()
|
||||||
.having((state) => state.ev100, 'ev100', 1.0)
|
.having((state) => state.ev100, 'ev100', 1.0)
|
||||||
.having((state) => state.film, 'film', const Film.other())
|
|
||||||
.having((state) => state.iso, 'iso', reducedProfile.isoValues.first)
|
.having((state) => state.iso, 'iso', reducedProfile.isoValues.first)
|
||||||
.having((state) => state.nd, 'nd', NdValue.values.first)
|
.having((state) => state.nd, 'nd', NdValue.values.first)
|
||||||
.having((state) => state.isMetering, 'isMetering', false),
|
.having((state) => state.isMetering, 'isMetering', false),
|
||||||
|
@ -560,7 +424,6 @@ void main() {
|
||||||
build: () => bloc,
|
build: () => bloc,
|
||||||
seed: () => MeteringDataState(
|
seed: () => MeteringDataState(
|
||||||
ev100: 1.0,
|
ev100: 1.0,
|
||||||
film: Film.values[1],
|
|
||||||
iso: const IsoValue(100, StopType.full),
|
iso: const IsoValue(100, StopType.full),
|
||||||
nd: NdValue.values[4],
|
nd: NdValue.values[4],
|
||||||
isMetering: false,
|
isMetering: false,
|
||||||
|
@ -569,7 +432,6 @@ void main() {
|
||||||
bloc.add(EquipmentProfileChangedEvent(reducedProfile));
|
bloc.add(EquipmentProfileChangedEvent(reducedProfile));
|
||||||
},
|
},
|
||||||
verify: (_) {
|
verify: (_) {
|
||||||
verifyNever(() => meteringInteractor.film = const Film.other());
|
|
||||||
verifyNever(() => meteringInteractor.iso = reducedProfile.isoValues.first);
|
verifyNever(() => meteringInteractor.iso = reducedProfile.isoValues.first);
|
||||||
verify(() => meteringInteractor.ndFilter = reducedProfile.ndValues.first).called(1);
|
verify(() => meteringInteractor.ndFilter = reducedProfile.ndValues.first).called(1);
|
||||||
verify(() => meteringInteractor.responseVibration()).called(1);
|
verify(() => meteringInteractor.responseVibration()).called(1);
|
||||||
|
@ -577,7 +439,6 @@ void main() {
|
||||||
expect: () => [
|
expect: () => [
|
||||||
isA<MeteringDataState>()
|
isA<MeteringDataState>()
|
||||||
.having((state) => state.ev100, 'ev100', 1.0)
|
.having((state) => state.ev100, 'ev100', 1.0)
|
||||||
.having((state) => state.film, 'film', Film.values[1])
|
|
||||||
.having((state) => state.iso, 'iso', const IsoValue(100, StopType.full))
|
.having((state) => state.iso, 'iso', const IsoValue(100, StopType.full))
|
||||||
.having((state) => state.nd, 'nd', reducedProfile.ndValues.first)
|
.having((state) => state.nd, 'nd', reducedProfile.ndValues.first)
|
||||||
.having((state) => state.isMetering, 'isMetering', false),
|
.having((state) => state.isMetering, 'isMetering', false),
|
||||||
|
@ -589,7 +450,6 @@ void main() {
|
||||||
build: () => bloc,
|
build: () => bloc,
|
||||||
seed: () => MeteringDataState(
|
seed: () => MeteringDataState(
|
||||||
ev100: 1.0,
|
ev100: 1.0,
|
||||||
film: Film.values[1],
|
|
||||||
iso: IsoValue.values[2],
|
iso: IsoValue.values[2],
|
||||||
nd: NdValue.values[4],
|
nd: NdValue.values[4],
|
||||||
isMetering: false,
|
isMetering: false,
|
||||||
|
@ -598,7 +458,6 @@ void main() {
|
||||||
bloc.add(EquipmentProfileChangedEvent(reducedProfile));
|
bloc.add(EquipmentProfileChangedEvent(reducedProfile));
|
||||||
},
|
},
|
||||||
verify: (_) {
|
verify: (_) {
|
||||||
verify(() => meteringInteractor.film = const Film.other()).called(1);
|
|
||||||
verify(() => meteringInteractor.iso = reducedProfile.isoValues.first).called(1);
|
verify(() => meteringInteractor.iso = reducedProfile.isoValues.first).called(1);
|
||||||
verify(() => meteringInteractor.ndFilter = reducedProfile.ndValues.first).called(1);
|
verify(() => meteringInteractor.ndFilter = reducedProfile.ndValues.first).called(1);
|
||||||
verify(() => meteringInteractor.responseVibration()).called(1);
|
verify(() => meteringInteractor.responseVibration()).called(1);
|
||||||
|
@ -606,7 +465,6 @@ void main() {
|
||||||
expect: () => [
|
expect: () => [
|
||||||
isA<MeteringDataState>()
|
isA<MeteringDataState>()
|
||||||
.having((state) => state.ev100, 'ev100', 1.0)
|
.having((state) => state.ev100, 'ev100', 1.0)
|
||||||
.having((state) => state.film, 'film', const Film.other())
|
|
||||||
.having((state) => state.iso, 'iso', reducedProfile.isoValues.first)
|
.having((state) => state.iso, 'iso', reducedProfile.isoValues.first)
|
||||||
.having((state) => state.nd, 'nd', reducedProfile.ndValues.first)
|
.having((state) => state.nd, 'nd', reducedProfile.ndValues.first)
|
||||||
.having((state) => state.isMetering, 'isMetering', false),
|
.having((state) => state.isMetering, 'isMetering', false),
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:lightmeter/data/models/exposure_pair.dart';
|
import 'package:lightmeter/data/models/exposure_pair.dart';
|
||||||
import 'package:lightmeter/data/models/film.dart';
|
|
||||||
import 'package:lightmeter/screens/metering/screen_metering.dart';
|
import 'package:lightmeter/screens/metering/screen_metering.dart';
|
||||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||||
|
|
||||||
|
@ -19,7 +18,6 @@ void main() {
|
||||||
ev,
|
ev,
|
||||||
StopType.full,
|
StopType.full,
|
||||||
defaultEquipmentProfile,
|
defaultEquipmentProfile,
|
||||||
const Film.other(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
test('isNan', () {
|
test('isNan', () {
|
||||||
|
@ -42,7 +40,6 @@ void main() {
|
||||||
ev,
|
ev,
|
||||||
StopType.full,
|
StopType.full,
|
||||||
defaultEquipmentProfile,
|
defaultEquipmentProfile,
|
||||||
const Film.other(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
test('EV 1', () {
|
test('EV 1', () {
|
||||||
|
@ -142,7 +139,6 @@ void main() {
|
||||||
ev,
|
ev,
|
||||||
StopType.half,
|
StopType.half,
|
||||||
defaultEquipmentProfile,
|
defaultEquipmentProfile,
|
||||||
const Film.other(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
test('EV 1', () {
|
test('EV 1', () {
|
||||||
|
@ -242,7 +238,6 @@ void main() {
|
||||||
ev,
|
ev,
|
||||||
StopType.third,
|
StopType.third,
|
||||||
defaultEquipmentProfile,
|
defaultEquipmentProfile,
|
||||||
const Film.other(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
test('EV 1', () {
|
test('EV 1', () {
|
||||||
|
@ -356,7 +351,6 @@ void main() {
|
||||||
ev,
|
ev,
|
||||||
StopType.full,
|
StopType.full,
|
||||||
equipmentProfile,
|
equipmentProfile,
|
||||||
const Film.other(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
test('EV 1', () {
|
test('EV 1', () {
|
||||||
|
@ -456,7 +450,6 @@ void main() {
|
||||||
ev,
|
ev,
|
||||||
StopType.half,
|
StopType.half,
|
||||||
equipmentProfile,
|
equipmentProfile,
|
||||||
const Film.other(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
test('EV 1', () {
|
test('EV 1', () {
|
||||||
|
@ -556,7 +549,6 @@ void main() {
|
||||||
ev,
|
ev,
|
||||||
StopType.third,
|
StopType.third,
|
||||||
equipmentProfile,
|
equipmentProfile,
|
||||||
const Film.other(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
test('EV 1', () {
|
test('EV 1', () {
|
||||||
|
@ -669,7 +661,6 @@ void main() {
|
||||||
ev,
|
ev,
|
||||||
StopType.full,
|
StopType.full,
|
||||||
equipmentProfile,
|
equipmentProfile,
|
||||||
const Film.other(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
test('EV 1', () {
|
test('EV 1', () {
|
||||||
|
@ -769,7 +760,6 @@ void main() {
|
||||||
ev,
|
ev,
|
||||||
StopType.half,
|
StopType.half,
|
||||||
equipmentProfile,
|
equipmentProfile,
|
||||||
const Film.other(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
test('EV 1', () {
|
test('EV 1', () {
|
||||||
|
@ -869,7 +859,6 @@ void main() {
|
||||||
ev,
|
ev,
|
||||||
StopType.third,
|
StopType.third,
|
||||||
equipmentProfile,
|
equipmentProfile,
|
||||||
const Film.other(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
test('EV 1', () {
|
test('EV 1', () {
|
||||||
|
|
Loading…
Reference in a new issue