Added mock ev bloc

This commit is contained in:
Vadim 2022-12-15 14:00:28 +03:00
parent a054a55f15
commit 07dc5d8f57
13 changed files with 176 additions and 92 deletions

12
.vscode/launch.json vendored
View file

@ -12,6 +12,17 @@
"--flavor", "--flavor",
"dev", "dev",
], ],
"program": "${workspaceFolder}/lib/main.dart",
},
{
"name": "dev (mock)",
"request": "launch",
"type": "dart",
"args": [
"--flavor",
"dev",
],
"program": "${workspaceFolder}/lib/main_mock.dart",
}, },
{ {
"name": "prod", "name": "prod",
@ -21,6 +32,7 @@
"--flavor", "--flavor",
"prod", "prod",
], ],
"program": "${workspaceFolder}/lib/main.dart",
}, },
], ],
} }

72
lib/application.dart Normal file
View file

@ -0,0 +1,72 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:lightmeter/data/ev_source/ev_source_type.dart';
import 'package:lightmeter/data/permissions_service.dart';
import 'package:lightmeter/screens/settings/settings_screen.dart';
import 'package:provider/provider.dart';
import 'generated/l10n.dart';
import 'res/theme.dart';
import 'screens/metering/flow_metering.dart';
import 'utils/stop_type_provider.dart';
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
class Application extends StatefulWidget {
final EvSourceType evSource;
const Application(this.evSource, {super.key});
@override
State<Application> createState() => _ApplicationState();
}
class _ApplicationState extends State<Application> {
@override
void initState() {
super.initState();
final mySystemTheme = SystemUiOverlayStyle.light.copyWith(
statusBarColor: Colors.transparent,
statusBarBrightness: Brightness.light,
statusBarIconBrightness: Brightness.dark,
systemNavigationBarColor: Colors.transparent,
systemNavigationBarIconBrightness: Brightness.dark,
);
SystemChrome.setSystemUIOverlayStyle(mySystemTheme);
}
@override
Widget build(BuildContext context) {
return Provider.value(
value: widget.evSource,
child: Provider(
create: (context) => PermissionsService(),
child: StopTypeProvider(
child: MaterialApp(
theme: ThemeData(
useMaterial3: true,
colorScheme: lightColorScheme,
),
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: S.delegate.supportedLocales,
builder: (context, child) => MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
child: child!,
),
home: const MeteringFlow(),
routes: {
"metering": (context) => const MeteringFlow(),
"settings": (context) => const SettingsScreen(),
},
),
),
),
);
}
}

View file

@ -6,6 +6,7 @@ import 'package:camera/camera.dart';
import 'package:exif/exif.dart'; import 'package:exif/exif.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lightmeter/data/ev_source/ev_source_bloc.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/communication/event_communication_metering.dart' as communication_event; import 'package:lightmeter/screens/metering/communication/event_communication_metering.dart' as communication_event;
import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' as communication_states; import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' as communication_states;
@ -14,21 +15,20 @@ import 'package:lightmeter/utils/log_2.dart';
import 'event_camera.dart'; import 'event_camera.dart';
import 'state_camera.dart'; import 'state_camera.dart';
class CameraBloc extends Bloc<CameraEvent, CameraState> { class CameraBloc extends EvSourceBloc<CameraEvent, CameraState> {
final MeteringCommunicationBloc _communicationBloc;
late final StreamSubscription<communication_states.MeteringCommunicationState> _communicationSubscription;
late final _WidgetsBindingObserver _observer; late final _WidgetsBindingObserver _observer;
CameraController? _cameraController; CameraController? _cameraController;
CameraController? get cameraController => _cameraController; CameraController? get cameraController => _cameraController;
CameraBloc(this._communicationBloc) : super(const CameraInitState()) { CameraBloc(MeteringCommunicationBloc communicationBloc)
_communicationSubscription = _communicationBloc.stream.listen(_onCommunicationState); : super(
communicationBloc,
const CameraInitState(),
) {
_observer = _WidgetsBindingObserver(_appLifecycleStateObserver); _observer = _WidgetsBindingObserver(_appLifecycleStateObserver);
WidgetsBinding.instance.addObserver(_observer); WidgetsBinding.instance.addObserver(_observer);
on<InitializeEvent>(_onInitialized); on<InitializeEvent>(_onInitialize);
add(const InitializeEvent()); add(const InitializeEvent());
} }
@ -37,21 +37,21 @@ class CameraBloc extends Bloc<CameraEvent, CameraState> {
Future<void> close() async { Future<void> close() async {
WidgetsBinding.instance.removeObserver(_observer); WidgetsBinding.instance.removeObserver(_observer);
_cameraController?.dispose(); _cameraController?.dispose();
await _communicationSubscription.cancel();
super.close(); super.close();
} }
void _onCommunicationState(communication_states.MeteringCommunicationState communicationState) { @override
void onCommunicationState(communication_states.SourceState communicationState) {
if (communicationState is communication_states.MeasureState) { if (communicationState is communication_states.MeasureState) {
_takePhoto().then((ev100) { _takePhoto().then((ev100) {
if (ev100 != null) { if (ev100 != null) {
_communicationBloc.add(communication_event.MeasuredEvent(ev100)); communicationBloc.add(communication_event.MeasuredEvent(ev100));
} }
}); });
} }
} }
Future<void> _onInitialized(_, Emitter emit) async { Future<void> _onInitialize(_, Emitter emit) async {
emit(const CameraLoadingState()); emit(const CameraLoadingState());
try { try {
final cameras = await availableCameras(); final cameras = await availableCameras();
@ -69,7 +69,7 @@ class CameraBloc extends Bloc<CameraEvent, CameraState> {
emit(CameraReadyState(_cameraController!)); emit(CameraReadyState(_cameraController!));
_takePhoto().then((ev100) { _takePhoto().then((ev100) {
if (ev100 != null) { if (ev100 != null) {
_communicationBloc.add(communication_event.MeasuredEvent(ev100)); communicationBloc.add(communication_event.MeasuredEvent(ev100));
} }
}); });
} catch (e) { } catch (e) {

View file

@ -0,0 +1,24 @@
import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart';
import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' as communication_states;
abstract class EvSourceBloc<E, S> extends Bloc<E, S> {
final MeteringCommunicationBloc communicationBloc;
late final StreamSubscription<communication_states.SourceState> _communicationSubscription;
EvSourceBloc(this.communicationBloc, super.initialState) {
_communicationSubscription = communicationBloc.stream
.where((event) => event is communication_states.SourceState)
.map((event) => event as communication_states.SourceState)
.listen(onCommunicationState);
}
@override
Future<void> close() async {
await _communicationSubscription.cancel();
super.close();
}
void onCommunicationState(communication_states.SourceState communicationState);
}

View file

@ -0,0 +1 @@
enum EvSourceType { camera, mock }

View file

@ -0,0 +1,25 @@
import 'dart:math';
import 'package:lightmeter/data/ev_source/ev_source_bloc.dart';
import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart';
import 'package:lightmeter/screens/metering/communication/event_communication_metering.dart' as communication_event;
import 'package:lightmeter/screens/metering/communication/state_communication_metering.dart' as communication_states;
import 'event_random_ev.dart';
import 'state_random_ev.dart';
class RandomEvBloc extends EvSourceBloc<RandomEvEvent, RandomEvState> {
final random = Random();
RandomEvBloc(MeteringCommunicationBloc communicationBloc)
: super(
communicationBloc,
RandomEvState(Random().nextDouble() * 15),
);
@override
void onCommunicationState(communication_states.SourceState communicationState) {
if (communicationState is communication_states.MeasureState) {
communicationBloc.add(communication_event.MeasuredEvent(random.nextDouble() * 15));
}
}
}

View file

@ -0,0 +1,3 @@
abstract class RandomEvEvent {
const RandomEvEvent();
}

View file

@ -0,0 +1,5 @@
class RandomEvState {
final double ev;
const RandomEvState(this.ev);
}

View file

@ -1,70 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:lightmeter/data/ev_source/ev_source_type.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:lightmeter/data/permissions_service.dart';
import 'package:lightmeter/screens/settings/settings_screen.dart';
import 'package:provider/provider.dart';
import 'generated/l10n.dart'; import 'application.dart';
import 'res/theme.dart';
import 'screens/metering/flow_metering.dart';
import 'utils/stop_type_provider.dart';
void main() { void main() {
runApp(const Application()); runApp(const Application(EvSourceType.camera));
}
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
class Application extends StatefulWidget {
const Application({super.key});
@override
State<Application> createState() => _ApplicationState();
}
class _ApplicationState extends State<Application> {
@override
void initState() {
super.initState();
final mySystemTheme = SystemUiOverlayStyle.light.copyWith(
statusBarColor: Colors.transparent,
statusBarBrightness: Brightness.light,
statusBarIconBrightness: Brightness.dark,
systemNavigationBarColor: Colors.transparent,
systemNavigationBarIconBrightness: Brightness.dark,
);
SystemChrome.setSystemUIOverlayStyle(mySystemTheme);
}
@override
Widget build(BuildContext context) {
return Provider(
create: (context) => PermissionsService(),
child: StopTypeProvider(
child: MaterialApp(
theme: ThemeData(
useMaterial3: true,
colorScheme: lightColorScheme,
),
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: S.delegate.supportedLocales,
builder: (context, child) => MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
child: child!,
),
home: const MeteringFlow(),
routes: {
"metering": (context) => const MeteringFlow(),
"settings": (context) => const SettingsScreen(),
},
),
),
);
}
} }

8
lib/main_mock.dart Normal file
View file

@ -0,0 +1,8 @@
import 'package:flutter/material.dart';
import 'package:lightmeter/data/ev_source/ev_source_type.dart';
import 'application.dart';
void main() {
runApp(const Application(EvSourceType.mock));
}

View file

@ -22,7 +22,6 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
List<ApertureValue> get _apertureValues => apertureValues.whereStopType(stopType); List<ApertureValue> get _apertureValues => apertureValues.whereStopType(stopType);
List<ShutterSpeedValue> get _shutterSpeedValues => shutterSpeedValues.whereStopType(stopType); List<ShutterSpeedValue> get _shutterSpeedValues => shutterSpeedValues.whereStopType(stopType);
final _random = Random();
StopType stopType; StopType stopType;
@ -30,7 +29,7 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
: super( : super(
MeteringState( MeteringState(
iso: isoValues.where((element) => element.value == 100).first, iso: isoValues.where((element) => element.value == 100).first,
ev: 21.3, ev: 0.0,
evCompensation: 0.0, evCompensation: 0.0,
nd: ndValues.first, nd: ndValues.first,
exposurePairs: [], exposurePairs: [],
@ -62,16 +61,6 @@ class MeteringBloc extends Bloc<MeteringEvent, MeteringState> {
} }
} }
/// https://www.scantips.com/lights/exposurecalc.html
Future<double> measureEv() async {
final aperture = _apertureValues[_random.nextInt(_apertureValues.length)];
final shutterSpeed = _shutterSpeedValues[_random.nextInt(_shutterSpeedValues.thirdStops().length)];
final iso = isoValues[_random.nextInt(isoValues.thirdStops().length)];
final evAtSystemIso = log2(pow(aperture.value, 2).toDouble() / shutterSpeed.value);
return evAtSystemIso - log2(iso.value / state.iso.value);
}
void _onStopTypeChanged(StopTypeChangedEvent event, Emitter emit) { void _onStopTypeChanged(StopTypeChangedEvent event, Emitter emit) {
stopType = event.stopType; stopType = event.stopType;
emit(MeteringState( emit(MeteringState(

View file

@ -63,13 +63,13 @@ class MeteringTopBar extends StatelessWidget {
label: S.of(context).fastestExposurePair, label: S.of(context).fastestExposurePair,
value: fastest != null value: fastest != null
? '${fastest!.aperture.toString()} - ${fastest!.shutterSpeed.toString()}' ? '${fastest!.aperture.toString()} - ${fastest!.shutterSpeed.toString()}'
: 'N/A', : '-',
), ),
ReadingValue( ReadingValue(
label: S.of(context).slowestExposurePair, label: S.of(context).slowestExposurePair,
value: fastest != null value: fastest != null
? '${slowest!.aperture.toString()} - ${slowest!.shutterSpeed.toString()}' ? '${slowest!.aperture.toString()} - ${slowest!.shutterSpeed.toString()}'
: 'N/A', : '-',
), ),
], ],
), ),

View file

@ -1,6 +1,8 @@
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/ev_source/camera/bloc_camera.dart'; import 'package:lightmeter/data/ev_source/camera/bloc_camera.dart';
import 'package:lightmeter/data/ev_source/ev_source_type.dart';
import 'package:lightmeter/data/ev_source/random_ev/bloc_random_ev.dart';
import 'package:lightmeter/models/photography_value.dart'; import 'package:lightmeter/models/photography_value.dart';
import 'package:lightmeter/screens/metering/bloc_metering.dart'; import 'package:lightmeter/screens/metering/bloc_metering.dart';
import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart'; import 'package:lightmeter/screens/metering/communication/bloc_communication_metering.dart';
@ -22,6 +24,11 @@ class MeteringFlow extends StatelessWidget {
), ),
), ),
BlocProvider(create: (context) => CameraBloc(context.read<MeteringCommunicationBloc>())), BlocProvider(create: (context) => CameraBloc(context.read<MeteringCommunicationBloc>())),
if (context.read<EvSourceType>() == EvSourceType.mock)
BlocProvider(
lazy: false,
create: (context) => RandomEvBloc(context.read<MeteringCommunicationBloc>()),
),
], ],
child: const MeteringScreen(), child: const MeteringScreen(),
); );