mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-21 15:00:40 +00:00
[FilmEditScreen
] added validation
This commit is contained in:
parent
b7f0305055
commit
1eebc7008e
8 changed files with 229 additions and 41 deletions
|
@ -150,5 +150,9 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"close": "Close"
|
||||
"close": "Close",
|
||||
"filmFormula": "Formula",
|
||||
"filmFormulaExponential": "T=t^Rf",
|
||||
"filmFormulaExponentialRf": "Rf",
|
||||
"name": "Name"
|
||||
}
|
|
@ -67,7 +67,8 @@ ThemeData themeFrom(Color primaryColor, Brightness brightness) {
|
|||
style: ListTileStyle.list,
|
||||
iconColor: scheme.onSurface,
|
||||
textColor: scheme.onSurface,
|
||||
subtitleTextStyle: theme.textTheme.bodyMedium!.copyWith(color: scheme.onSurfaceVariant),
|
||||
subtitleTextStyle: theme.textTheme.bodyMedium,
|
||||
leadingAndTrailingTextStyle: theme.textTheme.bodyMedium,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,11 +4,18 @@ import 'package:lightmeter/screens/film_edit/state_film_edit.dart';
|
|||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class FilmEditBloc extends Bloc<FilmEditEvent, FilmEditState> {
|
||||
final FilmExponential _originalFilm;
|
||||
FilmExponential _newFilm;
|
||||
|
||||
FilmEditBloc(FilmExponential film)
|
||||
: super(
|
||||
: _originalFilm = film,
|
||||
_newFilm = film,
|
||||
super(
|
||||
FilmEditState(
|
||||
film,
|
||||
IsoValue.values.firstWhere((element) => element.value == film.iso),
|
||||
name: film.name,
|
||||
isoValue: IsoValue.values.firstWhere((element) => element.value == film.iso),
|
||||
exponent: film.exponent,
|
||||
canSave: false,
|
||||
),
|
||||
) {
|
||||
on<FilmEditEvent>(
|
||||
|
@ -27,18 +34,47 @@ class FilmEditBloc extends Bloc<FilmEditEvent, FilmEditState> {
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> _onNameChanged(FilmEditNameChangedEvent event, Emitter emit) async {}
|
||||
|
||||
Future<void> _onIsoChanged(FilmEditIsoChangedEvent event, Emitter emit) async {
|
||||
Future<void> _onNameChanged(FilmEditNameChangedEvent event, Emitter emit) async {
|
||||
_newFilm = _newFilm.copyWith(name: event.name);
|
||||
emit(
|
||||
FilmEditState(
|
||||
state.film.copyWith(iso: event.iso.value),
|
||||
event.iso,
|
||||
name: event.name,
|
||||
isoValue: state.isoValue,
|
||||
exponent: state.exponent,
|
||||
canSave: _canSave(event.name, state.exponent),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onExpChanged(FilmEditExpChangedEvent event, Emitter emit) async {}
|
||||
Future<void> _onIsoChanged(FilmEditIsoChangedEvent event, Emitter emit) async {
|
||||
_newFilm = _newFilm.copyWith(iso: event.iso.value);
|
||||
emit(
|
||||
FilmEditState(
|
||||
name: state.name,
|
||||
isoValue: event.iso,
|
||||
exponent: state.exponent,
|
||||
canSave: _canSave(state.name, state.exponent),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onExpChanged(FilmEditExpChangedEvent event, Emitter emit) async {
|
||||
if (event.exponent != null) {
|
||||
_newFilm = _newFilm.copyWith(exponent: event.exponent);
|
||||
}
|
||||
emit(
|
||||
FilmEditState(
|
||||
name: state.name,
|
||||
isoValue: state.isoValue,
|
||||
exponent: event.exponent,
|
||||
canSave: _canSave(state.name, event.exponent),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onSave(FilmEditSaveEvent _, Emitter emit) async {}
|
||||
|
||||
bool _canSave(String name, double? exponent) {
|
||||
return name.isNotEmpty && exponent != null && _newFilm != _originalFilm;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:lightmeter/screens/shared/text_field/widget_text_field.dart';
|
||||
|
||||
class ExponentialFormulaInput extends StatefulWidget {
|
||||
final double? value;
|
||||
final ValueChanged<double?> onChanged;
|
||||
|
||||
const ExponentialFormulaInput({
|
||||
super.key,
|
||||
required this.value,
|
||||
required this.onChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ExponentialFormulaInput> createState() => _ExponentialFormulaInputState();
|
||||
}
|
||||
|
||||
class _ExponentialFormulaInputState extends State<ExponentialFormulaInput> {
|
||||
TextStyle get style =>
|
||||
Theme.of(context).textTheme.bodyMedium!.copyWith(color: Theme.of(context).listTileTheme.textColor);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
ListTile(
|
||||
leading: const Icon(Icons.show_chart),
|
||||
title: Text(S.of(context).filmFormula),
|
||||
trailing: Text(S.of(context).filmFormulaExponential),
|
||||
),
|
||||
ListTile(
|
||||
leading: const SizedBox(),
|
||||
title: Text(
|
||||
S.of(context).filmFormulaExponentialRf,
|
||||
style: Theme.of(context).listTileTheme.titleTextStyle,
|
||||
),
|
||||
trailing: SizedBox(
|
||||
width: _textInputWidth(context),
|
||||
child: LightmeterTextField(
|
||||
initialValue: widget.value?.toString() ?? '',
|
||||
inputFormatters: [FilteringTextInputFormatter.allow(RegExp("[0-9.]"))],
|
||||
onChanged: (value) {
|
||||
widget.onChanged(double.tryParse(value));
|
||||
},
|
||||
textAlign: TextAlign.end,
|
||||
style: style,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
double _textInputWidth(BuildContext context) {
|
||||
final textPainter = TextPainter(
|
||||
text: TextSpan(text: widget.value.toString(), style: style),
|
||||
maxLines: 1,
|
||||
textDirection: TextDirection.ltr,
|
||||
)..layout();
|
||||
return textPainter.maxIntrinsicWidth + Dimens.grid4;
|
||||
}
|
||||
}
|
|
@ -17,9 +17,9 @@ class FilmEditIsoChangedEvent extends FilmEditEvent {
|
|||
}
|
||||
|
||||
class FilmEditExpChangedEvent extends FilmEditEvent {
|
||||
final double exp;
|
||||
final double? exponent;
|
||||
|
||||
const FilmEditExpChangedEvent(this.exp);
|
||||
const FilmEditExpChangedEvent(this.exponent);
|
||||
}
|
||||
|
||||
class FilmEditSaveEvent extends FilmEditEvent {
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:lightmeter/screens/film_edit/bloc_film_edit.dart';
|
||||
import 'package:lightmeter/screens/film_edit/components/exponential_formula_input/widget_input_exponential_formula.dart';
|
||||
import 'package:lightmeter/screens/film_edit/event_film_edit.dart';
|
||||
import 'package:lightmeter/screens/film_edit/state_film_edit.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/settings/components/shared/dialog_filter/widget_dialog_filter.dart';
|
||||
import 'package:lightmeter/screens/settings/components/shared/expandable_section_list/widget_expandable_section_list.dart';
|
||||
import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart';
|
||||
import 'package:lightmeter/screens/shared/text_field/widget_text_field.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class FilmEditScreen extends StatefulWidget {
|
||||
|
@ -22,37 +24,54 @@ class _FilmEditScreenState extends State<FilmEditScreen> {
|
|||
Widget build(BuildContext context) {
|
||||
return SliverScreen(
|
||||
title: BlocBuilder<FilmEditBloc, FilmEditState>(
|
||||
buildWhen: (previous, current) => previous.film.name != current.film.name,
|
||||
builder: (context, state) => TextFormField(
|
||||
initialValue: state.film.name,
|
||||
onChanged: (value) {},
|
||||
),
|
||||
buildWhen: (previous, current) => previous.name != current.name,
|
||||
builder: (_, state) => Text(state.name),
|
||||
),
|
||||
appBarActions: [
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(Icons.save),
|
||||
BlocBuilder<FilmEditBloc, FilmEditState>(
|
||||
buildWhen: (previous, current) => previous.canSave != current.canSave,
|
||||
builder: (context, state) => IconButton(
|
||||
onPressed: state.canSave ? () {} : null,
|
||||
icon: const Icon(Icons.save),
|
||||
),
|
||||
),
|
||||
],
|
||||
slivers: [
|
||||
SliverToBoxAdapter(
|
||||
child: BlocBuilder<FilmEditBloc, FilmEditState>(
|
||||
buildWhen: (previous, current) => previous.isoValue != current.isoValue,
|
||||
builder: (context, state) => _IsoPickerListTile(
|
||||
selected: state.isoValue,
|
||||
onChanged: (value) {
|
||||
context.read<FilmEditBloc>().add(FilmEditIsoChangedEvent(value));
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
Dimens.paddingM,
|
||||
0,
|
||||
Dimens.paddingM,
|
||||
Dimens.paddingM,
|
||||
),
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: BlocBuilder<FilmEditBloc, FilmEditState>(
|
||||
buildWhen: (previous, current) => previous.film.exponent != current.film.exponent,
|
||||
builder: (context, state) => ListTile(
|
||||
leading: const Icon(Icons.equalizer),
|
||||
title: Text('Formula'),
|
||||
trailing: Text(state.film.exponent.toString()),
|
||||
child: Card(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: Dimens.paddingM),
|
||||
child: Column(
|
||||
children: [
|
||||
_NameFieldBuilder(),
|
||||
BlocBuilder<FilmEditBloc, FilmEditState>(
|
||||
buildWhen: (previous, current) => previous.isoValue != current.isoValue,
|
||||
builder: (context, state) => _IsoPickerListTile(
|
||||
selected: state.isoValue,
|
||||
onChanged: (value) {
|
||||
context.read<FilmEditBloc>().add(FilmEditIsoChangedEvent(value));
|
||||
},
|
||||
),
|
||||
),
|
||||
BlocBuilder<FilmEditBloc, FilmEditState>(
|
||||
buildWhen: (previous, current) => previous.exponent != current.exponent,
|
||||
builder: (context, state) => ExponentialFormulaInput(
|
||||
value: state.exponent,
|
||||
onChanged: (value) {
|
||||
context.read<FilmEditBloc>().add(FilmEditExpChangedEvent(value));
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -62,6 +81,33 @@ class _FilmEditScreenState extends State<FilmEditScreen> {
|
|||
}
|
||||
}
|
||||
|
||||
class _NameFieldBuilder extends StatelessWidget {
|
||||
const _NameFieldBuilder();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: Dimens.paddingM,
|
||||
top: Dimens.paddingS / 2,
|
||||
right: Dimens.paddingL,
|
||||
bottom: Dimens.paddingS / 2,
|
||||
),
|
||||
child: BlocBuilder<FilmEditBloc, FilmEditState>(
|
||||
buildWhen: (previous, current) => previous.name != current.name,
|
||||
builder: (context, state) => LightmeterTextField(
|
||||
initialValue: state.name,
|
||||
onChanged: (value) {
|
||||
context.read<FilmEditBloc>().add(FilmEditNameChangedEvent(value));
|
||||
},
|
||||
style: Theme.of(context).listTileTheme.titleTextStyle,
|
||||
leading: const Icon(Icons.edit_outlined),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _IsoPickerListTile extends StatelessWidget {
|
||||
final IsoValue selected;
|
||||
final ValueChanged<IsoValue> onChanged;
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class FilmEditState {
|
||||
final FilmExponential film;
|
||||
final String name;
|
||||
final IsoValue isoValue;
|
||||
final double? exponent;
|
||||
final bool canSave;
|
||||
|
||||
const FilmEditState(this.film, this.isoValue);
|
||||
const FilmEditState({
|
||||
required this.name,
|
||||
required this.isoValue,
|
||||
required this.exponent,
|
||||
required this.canSave,
|
||||
});
|
||||
}
|
||||
|
|
29
lib/screens/shared/text_field/widget_text_field.dart
Normal file
29
lib/screens/shared/text_field/widget_text_field.dart
Normal file
|
@ -0,0 +1,29 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class LightmeterTextField extends TextFormField {
|
||||
LightmeterTextField({
|
||||
super.controller,
|
||||
super.focusNode,
|
||||
super.initialValue,
|
||||
super.inputFormatters,
|
||||
super.onChanged,
|
||||
super.style,
|
||||
super.textAlign,
|
||||
Widget? leading,
|
||||
}) : super(
|
||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||
maxLines: 1,
|
||||
decoration: InputDecoration(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
errorStyle: const TextStyle(fontSize: 0),
|
||||
icon: leading,
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return '';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
Loading…
Reference in a new issue