mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-24 16:30:40 +00:00
added placeholder for empty custom films list
This commit is contained in:
parent
68cecf5391
commit
45d7728c85
5 changed files with 145 additions and 116 deletions
|
@ -95,7 +95,6 @@ class FilmsProviderState extends State<FilmsProvider> {
|
|||
setState(() {});
|
||||
}
|
||||
|
||||
// TODO: add delete button to UI
|
||||
void deleteCustomFilm(FilmExponential film) {
|
||||
customFilms.remove(film.id);
|
||||
_discardSelectedIfNotIncluded();
|
||||
|
@ -170,12 +169,7 @@ class Films extends InheritedModel<_FilmsModelAspect> {
|
|||
|
||||
@override
|
||||
bool updateShouldNotifyDependent(Films oldWidget, Set<_FilmsModelAspect> dependencies) {
|
||||
if (dependencies.contains(_FilmsModelAspect.customFilmsList)) {}
|
||||
if (dependencies.contains(_FilmsModelAspect.selected)) {
|
||||
return selected != oldWidget.selected;
|
||||
} else {
|
||||
// TODO: reduce unnecessary notifications
|
||||
return true;
|
||||
}
|
||||
// TODO: reduce unnecessary notifications
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ 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';
|
||||
|
||||
|
@ -17,6 +18,14 @@ class FilmsScreen extends StatefulWidget {
|
|||
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();
|
||||
|
@ -50,22 +59,19 @@ class _FilmsScreenState extends State<FilmsScreen> with SingleTickerProviderStat
|
|||
),
|
||||
],
|
||||
slivers: [
|
||||
SliverFillRemaining(
|
||||
child: TabBarView(
|
||||
controller: tabController,
|
||||
children: [
|
||||
_FilmsListBuilder(
|
||||
films: Films.predefinedFilmsOf(context).toList(),
|
||||
onFilmSelected: FilmsProvider.of(context).toggleFilm,
|
||||
),
|
||||
_FilmsListBuilder<FilmExponential>(
|
||||
films: Films.customFilmsOf(context).toList(),
|
||||
onFilmSelected: FilmsProvider.of(context).toggleFilm,
|
||||
onFilmEdit: _editFilm,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
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),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@ -98,36 +104,41 @@ class _FilmsListBuilder<T extends Film> extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.all(Dimens.paddingM).add(EdgeInsets.only(bottom: MediaQuery.paddingOf(context).bottom)),
|
||||
return SliverList.builder(
|
||||
itemCount: films.length,
|
||||
itemBuilder: (_, index) => Card(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: index == 0 ? const Radius.circular(Dimens.borderRadiusL) : Radius.zero,
|
||||
topRight: index == 0 ? const Radius.circular(Dimens.borderRadiusL) : Radius.zero,
|
||||
bottomLeft: index == films.length - 1 ? const Radius.circular(Dimens.borderRadiusL) : Radius.zero,
|
||||
bottomRight: index == films.length - 1 ? const Radius.circular(Dimens.borderRadiusL) : Radius.zero,
|
||||
),
|
||||
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: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: index == 0 ? Dimens.paddingM : 0.0,
|
||||
bottom: index == films.length - 1 ? Dimens.paddingM : 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: 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),
|
||||
)
|
||||
: null,
|
||||
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),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -4,7 +4,7 @@ import 'package:lightmeter/providers/equipment_profile_provider.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/metering/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/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';
|
||||
|
||||
|
@ -37,12 +37,7 @@ class _EquipmentProfilesScreenState extends State<EquipmentProfilesScreen> {
|
|||
),
|
||||
],
|
||||
slivers: profilesCount == 1
|
||||
? [
|
||||
SliverFillRemaining(
|
||||
hasScrollBody: false,
|
||||
child: _EquipmentProfilesListPlaceholder(onTap: _addProfile),
|
||||
),
|
||||
]
|
||||
? [SliverPlaceholder(onTap: _addProfile)]
|
||||
: [
|
||||
SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
|
@ -131,32 +126,3 @@ class _EquipmentProfilesScreenState extends State<EquipmentProfilesScreen> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _EquipmentProfilesListPlaceholder extends StatelessWidget {
|
||||
final VoidCallback onTap;
|
||||
|
||||
const _EquipmentProfilesListPlaceholder({required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: Dimens.sliverAppBarExpandedHeight),
|
||||
child: FractionallySizedBox(
|
||||
widthFactor: 1 / 1.618,
|
||||
child: Center(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(Dimens.paddingL),
|
||||
child: IconPlaceholder(
|
||||
icon: Icons.add_outlined,
|
||||
text: S.of(context).tapToAdd,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:lightmeter/screens/shared/icon_placeholder/widget_icon_placeholder.dart';
|
||||
import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart';
|
||||
|
||||
class SliverPlaceholder extends StatelessWidget {
|
||||
final VoidCallback onTap;
|
||||
|
||||
const SliverPlaceholder({required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final sliverScreenBottomHeight =
|
||||
context.findAncestorWidgetOfExactType<SliverScreen>()?.bottom?.preferredSize.height ?? 0.0;
|
||||
return SliverFillRemaining(
|
||||
hasScrollBody: false,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(bottom: Dimens.sliverAppBarExpandedHeight - sliverScreenBottomHeight),
|
||||
child: FractionallySizedBox(
|
||||
widthFactor: 1 / 1.618,
|
||||
child: Center(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(Dimens.paddingL),
|
||||
child: IconPlaceholder(
|
||||
icon: Icons.add_outlined,
|
||||
text: S.of(context).tapToAdd,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -25,36 +25,10 @@ class SliverScreen extends StatelessWidget {
|
|||
bottom: false,
|
||||
child: CustomScrollView(
|
||||
slivers: <Widget>[
|
||||
SliverAppBar.large(
|
||||
automaticallyImplyLeading: false,
|
||||
expandedHeight: Dimens.sliverAppBarExpandedHeight + (bottom?.preferredSize.height ?? 0.0),
|
||||
flexibleSpace: FlexibleSpaceBar(
|
||||
centerTitle: false,
|
||||
titlePadding: const EdgeInsets.symmetric(horizontal: Dimens.paddingM),
|
||||
title: DefaultTextStyle(
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headlineSmall!
|
||||
.copyWith(color: Theme.of(context).colorScheme.onSurface),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: _Title(
|
||||
actionsCount: appBarActions.length + (Navigator.of(context).canPop() ? 1 : 0),
|
||||
bottomSize: bottom?.preferredSize.height ?? 0.0,
|
||||
child: title,
|
||||
),
|
||||
),
|
||||
),
|
||||
_AppBar(
|
||||
title: title,
|
||||
appBarActions: appBarActions,
|
||||
bottom: bottom,
|
||||
actions: [
|
||||
...appBarActions,
|
||||
if (Navigator.of(context).canPop())
|
||||
IconButton(
|
||||
onPressed: Navigator.of(context).pop,
|
||||
icon: const Icon(Icons.close_outlined),
|
||||
tooltip: S.of(context).tooltipClose,
|
||||
),
|
||||
],
|
||||
),
|
||||
...slivers,
|
||||
],
|
||||
|
@ -64,6 +38,51 @@ class SliverScreen extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
|
||||
class _AppBar extends StatelessWidget {
|
||||
final Widget title;
|
||||
final List<Widget> appBarActions;
|
||||
final PreferredSizeWidget? bottom;
|
||||
|
||||
const _AppBar({
|
||||
required this.title,
|
||||
this.appBarActions = const [],
|
||||
this.bottom,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SliverAppBar.large(
|
||||
automaticallyImplyLeading: false,
|
||||
expandedHeight: Dimens.sliverAppBarExpandedHeight + (bottom?.preferredSize.height ?? 0.0),
|
||||
flexibleSpace: FlexibleSpaceBar(
|
||||
centerTitle: false,
|
||||
titlePadding: const EdgeInsets.symmetric(horizontal: Dimens.paddingM),
|
||||
title: DefaultTextStyle(
|
||||
style: Theme.of(context).textTheme.headlineSmall!.copyWith(color: Theme.of(context).colorScheme.onSurface),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
child: _Title(
|
||||
actionsCount: appBarActions.length + (Navigator.of(context).canPop() ? 1 : 0),
|
||||
bottomSize: bottom?.preferredSize.height ?? 0.0,
|
||||
child: title,
|
||||
),
|
||||
),
|
||||
),
|
||||
bottom: bottom,
|
||||
actions: [
|
||||
...appBarActions,
|
||||
if (Navigator.of(context).canPop())
|
||||
IconButton(
|
||||
onPressed: Navigator.of(context).pop,
|
||||
icon: const Icon(Icons.close_outlined),
|
||||
tooltip: S.of(context).tooltipClose,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Title extends StatelessWidget {
|
||||
final Widget child;
|
||||
final int actionsCount;
|
||||
|
|
Loading…
Reference in a new issue