2022-12-20 20:52:24 +00:00
|
|
|
import 'package:cached_network_image/cached_network_image.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
|
|
import '/features/core/data/constants/const_colors.dart';
|
|
|
|
import '/features/core/data/constants/const_durations.dart';
|
2022-12-25 21:17:59 +00:00
|
|
|
import '/features/core/data/constants/const_media.dart';
|
2022-12-23 10:20:46 +00:00
|
|
|
import '/features/core/widgets/gap.dart';
|
2022-12-20 20:52:24 +00:00
|
|
|
import '/features/core/widgets/mcg_scaffold.dart';
|
2022-12-23 10:20:46 +00:00
|
|
|
import '/features/core/widgets/state/multi_value_listenable_builder.dart';
|
|
|
|
import '/features/core/widgets/state/view_model_builder.dart';
|
2022-12-25 21:17:59 +00:00
|
|
|
import '/features/home/widgets/custom_wrap.dart';
|
2022-12-23 10:20:46 +00:00
|
|
|
import '../../data/enums/search_option.dart';
|
|
|
|
import '../../data/models/image_model.dart';
|
2022-12-20 20:52:24 +00:00
|
|
|
import 'gallery_view_model.dart';
|
2022-12-19 13:03:38 +00:00
|
|
|
|
2022-12-23 10:20:46 +00:00
|
|
|
part 'downloaded_gallery_view.dart';
|
|
|
|
part 'search_gallery_view.dart';
|
|
|
|
|
2022-12-19 13:03:38 +00:00
|
|
|
class GalleryView extends StatelessWidget {
|
|
|
|
const GalleryView({super.key});
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2022-12-20 20:52:24 +00:00
|
|
|
return ViewModelBuilder<GalleryViewModel>(
|
|
|
|
viewModelBuilder: () => GalleryViewModel.locate,
|
|
|
|
builder: (context, final model) => McgScaffold(
|
|
|
|
bodyBuilderWaiter: model.isInitialised,
|
2022-12-22 11:17:08 +00:00
|
|
|
forceInternetCheck: true,
|
2022-12-20 20:52:24 +00:00
|
|
|
appBar: AppBar(
|
2022-12-23 10:20:46 +00:00
|
|
|
centerTitle: true,
|
|
|
|
primary: true,
|
|
|
|
title: ValueListenableBuilder<bool>(
|
|
|
|
valueListenable: model.isSearchingListenable,
|
|
|
|
builder: (context, final isSearching, _) => AnimatedSwitcher(
|
|
|
|
duration: ConstDurations.quarterDefaultAnimationDuration,
|
|
|
|
child: !isSearching
|
|
|
|
? Center(child: Text(model.strings.gallery))
|
|
|
|
: _SearchBox(galleryViewModel: model),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
actions: [
|
|
|
|
Padding(
|
|
|
|
padding: const EdgeInsets.only(right: 40),
|
|
|
|
child: MultiValueListenableBuilder(
|
|
|
|
valueListenables: [
|
|
|
|
model.isDisplayingPressingPrompt,
|
|
|
|
model.isSearchingListenable,
|
|
|
|
],
|
|
|
|
builder: (context, final values, child) => !model.isDisplayingPressingPrompt.value
|
|
|
|
? IconButton(
|
2022-12-23 23:32:53 +00:00
|
|
|
isSelected: model.isSearchingListenable.value,
|
|
|
|
icon: const Icon(Icons.search),
|
|
|
|
selectedIcon: const Icon(Icons.close),
|
2022-12-23 10:20:46 +00:00
|
|
|
onPressed: model.searchPressed,
|
|
|
|
)
|
|
|
|
: const SizedBox.shrink(),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
],
|
2022-12-20 20:52:24 +00:00
|
|
|
),
|
|
|
|
body: Center(
|
|
|
|
child: ValueListenableBuilder<bool>(
|
|
|
|
valueListenable: model.isDisplayingPressingPrompt,
|
|
|
|
builder: (context, final isDisplayingPressingPrompt, _) => AnimatedSwitcher(
|
|
|
|
duration: ConstDurations.defaultAnimationDuration,
|
|
|
|
child: isDisplayingPressingPrompt
|
|
|
|
? ElevatedButton(
|
|
|
|
onPressed: model.onPromptPressed,
|
|
|
|
child: Text(model.strings.startLoadingPrompt),
|
|
|
|
)
|
2022-12-23 10:20:46 +00:00
|
|
|
: SingleChildScrollView(
|
|
|
|
child: FutureBuilder<void>(
|
|
|
|
future: model.initImageFetchIsDone,
|
|
|
|
builder: (context, final snapshot) {
|
|
|
|
switch (snapshot.connectionState) {
|
|
|
|
case ConnectionState.none:
|
|
|
|
case ConnectionState.waiting:
|
|
|
|
case ConnectionState.active:
|
|
|
|
return const CircularProgressIndicator();
|
|
|
|
case ConnectionState.done:
|
|
|
|
return ValueListenableBuilder<bool>(
|
|
|
|
valueListenable: model.isSearchingListenable,
|
|
|
|
builder: (context, final isSearching, _) => AnimatedSwitcher(
|
|
|
|
duration: ConstDurations.oneAndHalfDefaultAnimationDuration,
|
2022-12-25 21:17:59 +00:00
|
|
|
child: !isSearching
|
|
|
|
? Column(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
|
|
children: [
|
|
|
|
ValueListenableBuilder<bool>(
|
|
|
|
valueListenable: model.isViewingFavouriteListenable,
|
|
|
|
builder:
|
|
|
|
(context, final isViewingFavourites, child) =>
|
|
|
|
Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
children: [
|
|
|
|
ConstMedia.buildIcon(
|
|
|
|
ConstMedia.favStarOutline,
|
|
|
|
width: 24,
|
|
|
|
height: 24,
|
|
|
|
),
|
|
|
|
Switch(
|
|
|
|
value: isViewingFavourites,
|
|
|
|
onChanged: model.onFavouriteViewChange,
|
|
|
|
),
|
|
|
|
ConstMedia.buildIcon(
|
|
|
|
ConstMedia.favStarFilled,
|
|
|
|
width: 24,
|
|
|
|
height: 24,
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
_DownloadedGalleryView(galleryViewModel: model),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
: _SearchGalleryView(galleryViewModel: model),
|
2022-12-20 20:52:24 +00:00
|
|
|
),
|
2022-12-23 10:20:46 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
},
|
2022-12-20 20:52:24 +00:00
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
2022-12-19 13:03:38 +00:00
|
|
|
}
|
|
|
|
}
|
2022-12-23 10:20:46 +00:00
|
|
|
|
|
|
|
class _SearchBox extends StatelessWidget {
|
|
|
|
const _SearchBox({
|
|
|
|
required this.galleryViewModel,
|
|
|
|
super.key,
|
|
|
|
});
|
|
|
|
|
|
|
|
final GalleryViewModel galleryViewModel;
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return Row(
|
|
|
|
children: [
|
|
|
|
ValueListenableBuilder<SearchOption>(
|
|
|
|
valueListenable: galleryViewModel.searchOptionListenable,
|
|
|
|
builder: (context, final searchOption, _) => Padding(
|
|
|
|
padding: const EdgeInsets.only(top: 8),
|
|
|
|
child: DropdownButton<SearchOption>(
|
|
|
|
underline: const SizedBox.shrink(),
|
|
|
|
borderRadius: BorderRadius.circular(24),
|
|
|
|
items: [
|
|
|
|
for (final searchOption in SearchOption.values)
|
|
|
|
DropdownMenuItem(
|
|
|
|
value: searchOption,
|
2023-01-01 12:04:22 +00:00
|
|
|
child: Center(child: Text(searchOption.name)),
|
2022-12-23 10:20:46 +00:00
|
|
|
),
|
|
|
|
],
|
|
|
|
value: searchOption,
|
|
|
|
onChanged: galleryViewModel.onSearchOptionChanged,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
const Gap(18),
|
|
|
|
Expanded(
|
|
|
|
child: TextField(
|
|
|
|
autofocus: true,
|
|
|
|
decoration: InputDecoration(
|
|
|
|
hintText: galleryViewModel.strings.searchForImage,
|
|
|
|
),
|
|
|
|
onChanged: galleryViewModel.onSearchTermUpdate,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|