m3_lightmeter/lib/screens/films/screen_films.dart
Vadim 30418a9cfd
ML-196 Allow to select equipment profile in use (#197)
* integrated `EquipmentProfilesStorageService`

* implemented `EquipmentProfileEditScreen`

* added equipment profiles screens to navigation

* fixed tests

* fixed splashscreen removal

* replaced old `EquipmentProfilesScreen`

* typo

* use outlined icons

* fixed storage mock for integration tests

* recovered copy feature for profiles

* added profile deletion to e2e test

* added translations

* added film translations

* wip

* add ability to toggle equipment profiles

* lints

* fixed tests

* sync with iap rename

* use `Toggleable` from resources

* use iap 2.1.0

* use outlined edit icon
2024-11-11 17:20:12 +01:00

147 lines
4.6 KiB
Dart

import 'package:flutter/material.dart';
import 'package:lightmeter/generated/l10n.dart';
import 'package:lightmeter/navigation/routes.dart';
import 'package:lightmeter/providers/films_provider.dart';
import 'package:lightmeter/res/dimens.dart';
import 'package:lightmeter/screens/film_edit/flow_film_edit.dart';
import 'package:lightmeter/screens/shared/sliver_placeholder/widget_sliver_placeholder.dart';
import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart';
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
class FilmsScreen extends StatefulWidget {
const FilmsScreen({super.key});
@override
State<FilmsScreen> createState() => _FilmsScreenState();
}
class _FilmsScreenState extends State<FilmsScreen> with SingleTickerProviderStateMixin {
late final tabController = TabController(length: 2, vsync: this);
@override
void initState() {
super.initState();
tabController.addListener(() {
setState(() {});
});
}
@override
void dispose() {
tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SliverScreen(
title: Text(S.of(context).films),
bottom: TabBar(
controller: tabController,
tabs: [
Tab(text: S.of(context).filmsInUse),
Tab(text: S.of(context).filmsCustom),
],
),
appBarActions: [
AnimatedBuilder(
animation: tabController,
builder: (context, _) => AnimatedSwitcher(
duration: Dimens.switchDuration,
child: tabController.index == 0
? const SizedBox.shrink()
: IconButton(
onPressed: _addFilm,
icon: const Icon(Icons.add_outlined),
tooltip: S.of(context).tooltipAdd,
),
),
),
],
slivers: [
if (tabController.index == 0)
_FilmsListBuilder(
films: Films.predefinedFilmsOf(context).toList(),
onFilmSelected: FilmsProvider.of(context).toggleFilm,
)
else if (tabController.index == 1 && Films.customFilmsOf(context).isNotEmpty)
_FilmsListBuilder<FilmExponential>(
films: Films.customFilmsOf(context).toList(),
onFilmSelected: FilmsProvider.of(context).toggleFilm,
onFilmEdit: _editFilm,
)
else
SliverPlaceholder(onTap: _addFilm),
],
);
}
void _addFilm() {
Navigator.of(context).pushNamed(
NavigationRoutes.filmEditScreen.name,
arguments: const FilmEditArgs(),
);
}
void _editFilm(FilmExponential film) {
Navigator.of(context).pushNamed(
NavigationRoutes.filmEditScreen.name,
arguments: FilmEditArgs(film: film),
);
}
}
class _FilmsListBuilder<T extends Film> extends StatelessWidget {
final List<T> films;
final void Function(T film, bool value) onFilmSelected;
final void Function(T film)? onFilmEdit;
const _FilmsListBuilder({
required this.films,
required this.onFilmSelected,
this.onFilmEdit,
});
@override
Widget build(BuildContext context) {
return SliverList.builder(
itemCount: films.length,
itemBuilder: (_, index) => Padding(
padding: EdgeInsets.fromLTRB(
Dimens.paddingM,
index == 0 ? Dimens.paddingM : 0,
Dimens.paddingM,
index == films.length - 1 ? Dimens.paddingM + MediaQuery.paddingOf(context).bottom : 0.0,
),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: index == 0 ? const Radius.circular(Dimens.borderRadiusL) : Radius.zero,
bottom: index == films.length - 1 ? const Radius.circular(Dimens.borderRadiusL) : Radius.zero,
),
),
child: Padding(
padding: EdgeInsets.only(
top: index == 0 ? Dimens.paddingM : 0.0,
bottom: index == films.length - 1 ? Dimens.paddingM : 0.0,
),
child: CheckboxListTile(
controlAffinity: ListTileControlAffinity.leading,
value: Films.inUseOf(context).contains(films[index]),
title: Text(films[index].name),
onChanged: (value) {
onFilmSelected(films[index], value ?? false);
},
secondary: onFilmEdit != null
? IconButton(
onPressed: () => onFilmEdit!(films[index]),
icon: const Icon(Icons.edit_outlined),
)
: null,
),
),
),
),
);
}
}