m3_lightmeter/lib/screens/metering/components/camera_container/widget_container_camera.dart

213 lines
8 KiB
Dart
Raw Normal View History

import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:lightmeter/data/models/exposure_pair.dart';
import 'package:lightmeter/data/models/feature.dart';
import 'package:lightmeter/data/models/metering_screen_layout_config.dart';
import 'package:lightmeter/platform_config.dart';
import 'package:lightmeter/providers/remote_config_provider.dart';
import 'package:lightmeter/res/dimens.dart';
import 'package:lightmeter/screens/metering/components/camera_container/bloc_container_camera.dart';
import 'package:lightmeter/screens/metering/components/camera_container/components/camera_controls/widget_camera_controls.dart';
import 'package:lightmeter/screens/metering/components/camera_container/components/camera_controls_placeholder/widget_placeholder_camera_controls.dart';
import 'package:lightmeter/screens/metering/components/camera_container/components/camera_preview/widget_camera_preview.dart';
import 'package:lightmeter/screens/metering/components/camera_container/event_container_camera.dart';
import 'package:lightmeter/screens/metering/components/camera_container/models/camera_error_type.dart';
import 'package:lightmeter/screens/metering/components/camera_container/state_container_camera.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/readings_container/widget_container_readings.dart';
import 'package:lightmeter/utils/context_utils.dart';
ML-42 Implement equipment profiles creating (#45) * added Equipment section placeholder * get iso & nd values from equipment profile * use photography values from remote repo * removed equipment section * wip * moved `EquipmentProfileProvider` from iap repo * wip * moved equipment profiles screen from iap * improved equipment profiles screen * mock add/delete * collapse on expand * add profile with name * show selected values count (wip) * fixed profile update * cleanup * Update pubspec.yaml * made `AnimatedDialogPicker` more generic * switched to local `Dimens` * fixed `MeteringTopBarShape` * rename * animated `EquipmentProfileContainer` * added default equipment profile * change equipment profile name via dialog * fixed profile selection * filter equipment profile update/delete * removed `enabled` param from settings section * non-null `EquipmentProfile` * fixed duplicate GlobalKeys * animated equipment list * Update ci.yml * fixed shutter speed anchor issue * autofocus * added firebase to project * save/restore equipment profiles * unified `SliverList` * added SSH key to iap repo * Update ci.yml * ci recursive submodules * try full url * Revert "try full url" This reverts commit a9b692b60ea5b2e88188a5d497467708becb4a02. * restore firebase_options.dart * changed runner to macos * restore options earlier * removed problematic file from analysis :) * removed launch_app * textoverflow * implemented `DialogRangePicker` * add iap repo to cd * typo * added workflow_dispatch to crowdin push * removed `equipmentProfileValuesCount` from intl * fr & ru translations * style * removed iap
2023-03-30 19:24:18 +00:00
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
class CameraContainer extends StatelessWidget {
final ExposurePair? fastest;
final ExposurePair? slowest;
final IsoValue iso;
final NdValue nd;
final ValueChanged<IsoValue> onIsoChanged;
final ValueChanged<NdValue> onNdChanged;
final List<ExposurePair> exposurePairs;
2024-05-02 15:11:53 +00:00
final ValueChanged<ExposurePair> onExposurePairTap;
const CameraContainer({
required this.fastest,
required this.slowest,
required this.iso,
required this.nd,
required this.onIsoChanged,
required this.onNdChanged,
required this.exposurePairs,
2024-05-02 14:54:37 +00:00
required this.onExposurePairTap,
super.key,
});
@override
Widget build(BuildContext context) {
final double meteringContainerHeight = _meteringContainerHeight(context);
final double cameraPreviewHeight = _cameraPreviewHeight(context);
final double topBarOverflow = meteringContainerHeight - cameraPreviewHeight;
ML-42 Implement equipment profiles creating (#45) * added Equipment section placeholder * get iso & nd values from equipment profile * use photography values from remote repo * removed equipment section * wip * moved `EquipmentProfileProvider` from iap repo * wip * moved equipment profiles screen from iap * improved equipment profiles screen * mock add/delete * collapse on expand * add profile with name * show selected values count (wip) * fixed profile update * cleanup * Update pubspec.yaml * made `AnimatedDialogPicker` more generic * switched to local `Dimens` * fixed `MeteringTopBarShape` * rename * animated `EquipmentProfileContainer` * added default equipment profile * change equipment profile name via dialog * fixed profile selection * filter equipment profile update/delete * removed `enabled` param from settings section * non-null `EquipmentProfile` * fixed duplicate GlobalKeys * animated equipment list * Update ci.yml * fixed shutter speed anchor issue * autofocus * added firebase to project * save/restore equipment profiles * unified `SliverList` * added SSH key to iap repo * Update ci.yml * ci recursive submodules * try full url * Revert "try full url" This reverts commit a9b692b60ea5b2e88188a5d497467708becb4a02. * restore firebase_options.dart * changed runner to macos * restore options earlier * removed problematic file from analysis :) * removed launch_app * textoverflow * implemented `DialogRangePicker` * add iap repo to cd * typo * added workflow_dispatch to crowdin push * removed `equipmentProfileValuesCount` from intl * fr & ru translations * style * removed iap
2023-03-30 19:24:18 +00:00
return Stack(
children: [
Positioned(
left: 0,
top: 0,
right: 0,
child: MeteringTopBar(
readingsContainer: ReadingsContainer(
fastest: fastest,
slowest: slowest,
iso: iso,
nd: nd,
onIsoChanged: onIsoChanged,
onNdChanged: onNdChanged,
),
appendixHeight: topBarOverflow,
preview: const _CameraViewBuilder(),
),
),
SafeArea(
bottom: false,
child: Column(
children: [
SizedBox(
height: min(meteringContainerHeight, cameraPreviewHeight) + Dimens.paddingM * 2,
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingM),
child: Row(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.only(top: topBarOverflow >= 0 ? topBarOverflow : 0),
2024-05-02 14:54:37 +00:00
child: ExposurePairsList(
exposurePairs,
onExposurePairTap: onExposurePairTap,
),
),
),
const SizedBox(width: Dimens.grid8),
Expanded(
child: Padding(
padding: EdgeInsets.only(top: topBarOverflow <= 0 ? -topBarOverflow : 0),
child: const _CameraControlsBuilder(),
),
),
],
),
),
),
],
),
),
],
);
}
double _meteringContainerHeight(BuildContext context) {
double enabledFeaturesHeight = 0;
if (!context.isPro) {
if (RemoteConfig.isEnabled(context, Feature.showUnlockProOnMainScreen)) {
enabledFeaturesHeight += Dimens.readingContainerSingleValueHeight;
enabledFeaturesHeight += Dimens.paddingS;
}
} else {
if (context.meteringFeature(MeteringScreenLayoutFeature.equipmentProfiles)) {
enabledFeaturesHeight += Dimens.readingContainerSingleValueHeight;
enabledFeaturesHeight += Dimens.paddingS;
}
if (context.meteringFeature(MeteringScreenLayoutFeature.filmPicker)) {
enabledFeaturesHeight += Dimens.readingContainerSingleValueHeight;
enabledFeaturesHeight += Dimens.paddingS;
}
ML-42 Implement equipment profiles creating (#45) * added Equipment section placeholder * get iso & nd values from equipment profile * use photography values from remote repo * removed equipment section * wip * moved `EquipmentProfileProvider` from iap repo * wip * moved equipment profiles screen from iap * improved equipment profiles screen * mock add/delete * collapse on expand * add profile with name * show selected values count (wip) * fixed profile update * cleanup * Update pubspec.yaml * made `AnimatedDialogPicker` more generic * switched to local `Dimens` * fixed `MeteringTopBarShape` * rename * animated `EquipmentProfileContainer` * added default equipment profile * change equipment profile name via dialog * fixed profile selection * filter equipment profile update/delete * removed `enabled` param from settings section * non-null `EquipmentProfile` * fixed duplicate GlobalKeys * animated equipment list * Update ci.yml * fixed shutter speed anchor issue * autofocus * added firebase to project * save/restore equipment profiles * unified `SliverList` * added SSH key to iap repo * Update ci.yml * ci recursive submodules * try full url * Revert "try full url" This reverts commit a9b692b60ea5b2e88188a5d497467708becb4a02. * restore firebase_options.dart * changed runner to macos * restore options earlier * removed problematic file from analysis :) * removed launch_app * textoverflow * implemented `DialogRangePicker` * add iap repo to cd * typo * added workflow_dispatch to crowdin push * removed `equipmentProfileValuesCount` from intl * fr & ru translations * style * removed iap
2023-03-30 19:24:18 +00:00
}
if (context.meteringFeature(MeteringScreenLayoutFeature.extremeExposurePairs)) {
enabledFeaturesHeight += Dimens.readingContainerDoubleValueHeight;
enabledFeaturesHeight += Dimens.paddingS;
}
ML-42 Implement equipment profiles creating (#45) * added Equipment section placeholder * get iso & nd values from equipment profile * use photography values from remote repo * removed equipment section * wip * moved `EquipmentProfileProvider` from iap repo * wip * moved equipment profiles screen from iap * improved equipment profiles screen * mock add/delete * collapse on expand * add profile with name * show selected values count (wip) * fixed profile update * cleanup * Update pubspec.yaml * made `AnimatedDialogPicker` more generic * switched to local `Dimens` * fixed `MeteringTopBarShape` * rename * animated `EquipmentProfileContainer` * added default equipment profile * change equipment profile name via dialog * fixed profile selection * filter equipment profile update/delete * removed `enabled` param from settings section * non-null `EquipmentProfile` * fixed duplicate GlobalKeys * animated equipment list * Update ci.yml * fixed shutter speed anchor issue * autofocus * added firebase to project * save/restore equipment profiles * unified `SliverList` * added SSH key to iap repo * Update ci.yml * ci recursive submodules * try full url * Revert "try full url" This reverts commit a9b692b60ea5b2e88188a5d497467708becb4a02. * restore firebase_options.dart * changed runner to macos * restore options earlier * removed problematic file from analysis :) * removed launch_app * textoverflow * implemented `DialogRangePicker` * add iap repo to cd * typo * added workflow_dispatch to crowdin push * removed `equipmentProfileValuesCount` from intl * fr & ru translations * style * removed iap
2023-03-30 19:24:18 +00:00
return enabledFeaturesHeight + Dimens.readingContainerSingleValueHeight; // ISO & ND
}
double _cameraPreviewHeight(BuildContext context) {
return ((MediaQuery.sizeOf(context).width - Dimens.grid8 - 2 * Dimens.paddingM) / 2) /
PlatformConfig.cameraPreviewAspectRatio;
}
}
class _CameraViewBuilder extends StatelessWidget {
const _CameraViewBuilder();
@override
Widget build(BuildContext context) {
return BlocBuilder<CameraContainerBloc, CameraContainerState>(
buildWhen: (previous, current) => current is! CameraActiveState,
builder: (context, state) => CameraPreview(
controller: state is CameraInitializedState ? state.controller : null,
error: state is CameraErrorState ? state.error : null,
onSpotTap: (value) {
context.read<CameraContainerBloc>().add(ExposureSpotChangedEvent(value));
},
),
);
}
}
class _CameraControlsBuilder extends StatelessWidget {
const _CameraControlsBuilder();
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(
Dimens.paddingL,
Dimens.paddingL,
0,
Dimens.paddingM,
),
child: BlocBuilder<CameraContainerBloc, CameraContainerState>(
builder: (context, state) {
late final Widget child;
if (state is CameraActiveState) {
child = CameraControls(
exposureOffsetRange: state.exposureOffsetRange,
exposureOffsetValue: state.currentExposureOffset,
onExposureOffsetChanged: (value) {
context.read<CameraContainerBloc>().add(ExposureOffsetChangedEvent(value));
},
zoomRange: state.zoomRange,
zoomValue: state.currentZoom,
onZoomChanged: (value) {
context.read<CameraContainerBloc>().add(ZoomChangedEvent(value));
},
);
} else if (state is CameraErrorState) {
child = CameraControlsPlaceholder(
error: state.error,
onReset: () {
context.read<CameraContainerBloc>().add(
state.error == CameraErrorType.permissionNotGranted
? const OpenAppSettingsEvent()
: const InitializeEvent(),
);
},
);
} else {
child = const Column(
children: [Expanded(child: SizedBox.shrink())],
);
}
return AnimatedSwitcher(
duration: Dimens.switchDuration,
child: child,
);
},
),
);
}
}