refactoring
This commit is contained in:
parent
68d7f70ded
commit
895a34d9f3
13 changed files with 75 additions and 48 deletions
|
@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
||||||
abstract class ConstColours {
|
abstract class ConstColours {
|
||||||
/// Smoke Gray => a neutral grey with neutral warmth/cold
|
/// Smoke Gray => a neutral grey with neutral warmth/cold
|
||||||
static const galleryBackgroundColour = Color.fromRGBO(127, 127, 125, 1.0);
|
static const galleryBackgroundColour = Color.fromRGBO(127, 127, 125, 1.0);
|
||||||
|
static const red = Colors.red;
|
||||||
|
|
||||||
static const white = Colors.white;
|
static const white = Colors.white;
|
||||||
static const black = Colors.black;
|
static const black = Colors.black;
|
||||||
|
|
|
@ -3,7 +3,7 @@ abstract class ConstValues {
|
||||||
static const String backendHost = 'source.unsplash.com';
|
static const String backendHost = 'source.unsplash.com';
|
||||||
static const List<String> backendUrlPathSegments = ['user', 'c_v_r'];
|
static const List<String> backendUrlPathSegments = ['user', 'c_v_r'];
|
||||||
|
|
||||||
static const int numberOfImages = 20;
|
static const int numberOfImages = 25;
|
||||||
static const int minImageSize = 50;
|
static const int minImageSize = 50;
|
||||||
static const int maxImageSize = 100;
|
static const int maxImageSize = 100;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import '../data/dtos/image_model_dto.dart';
|
||||||
/// Since I used a site that was more obscure than the ones in the examples, this (otherwise pointless
|
/// Since I used a site that was more obscure than the ones in the examples, this (otherwise pointless
|
||||||
/// and convoluting) interface is for adding a bit of flexibility to change strategy to some other site.
|
/// and convoluting) interface is for adding a bit of flexibility to change strategy to some other site.
|
||||||
abstract class ImagesApi {
|
abstract class ImagesApi {
|
||||||
|
/// Returns images fetched through an API as [ImageModelDTO]s.
|
||||||
FutureOr<Iterable<ImageModelDTO>> fetchImageUri({required String token});
|
FutureOr<Iterable<ImageModelDTO>> fetchImageUri({required String token});
|
||||||
|
|
||||||
FutureOr<Iterable<ImageModelDTO>> searchImages({
|
FutureOr<Iterable<ImageModelDTO>> searchImages({
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import '/l10n/generated/l10n.dart';
|
import '/l10n/generated/l10n.dart';
|
||||||
|
|
||||||
|
/// Represents an option for specifying a search strategy, for an [ImageModel]
|
||||||
enum SearchOption {
|
enum SearchOption {
|
||||||
local,
|
local,
|
||||||
web;
|
web;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import '../dtos/image_model_dto.dart';
|
import '../dtos/image_model_dto.dart';
|
||||||
|
|
||||||
|
/// Represents an Image, that would be displayed in the gallery.
|
||||||
class ImageModel {
|
class ImageModel {
|
||||||
const ImageModel({
|
const ImageModel({
|
||||||
required this.uri,
|
required this.uri,
|
||||||
|
|
|
@ -2,7 +2,6 @@ import 'dart:async';
|
||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
|
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:mc_gallery/features/home/data/dtos/image_model_dto.dart';
|
|
||||||
|
|
||||||
import '/features/core/data/constants/const_sorters.dart';
|
import '/features/core/data/constants/const_sorters.dart';
|
||||||
import '/features/core/data/extensions/iterable_extensions.dart';
|
import '/features/core/data/extensions/iterable_extensions.dart';
|
||||||
|
@ -11,6 +10,7 @@ import '/features/core/data/extensions/string_extensions.dart';
|
||||||
import '/features/core/services/local_storage_service.dart';
|
import '/features/core/services/local_storage_service.dart';
|
||||||
import '/features/core/services/logging_service.dart';
|
import '/features/core/services/logging_service.dart';
|
||||||
import '/features/core/utils/mutex.dart';
|
import '/features/core/utils/mutex.dart';
|
||||||
|
import '/features/home/data/dtos/image_model_dto.dart';
|
||||||
import '/locator.dart';
|
import '/locator.dart';
|
||||||
import '../abstracts/images_api.dart';
|
import '../abstracts/images_api.dart';
|
||||||
import '../data/enums/search_option.dart';
|
import '../data/enums/search_option.dart';
|
||||||
|
|
|
@ -18,12 +18,7 @@ class _DownloadedGalleryView extends StatelessWidget {
|
||||||
child: ValueListenableBuilder<bool>(
|
child: ValueListenableBuilder<bool>(
|
||||||
valueListenable: galleryViewModel.isViewingFavouriteListenable,
|
valueListenable: galleryViewModel.isViewingFavouriteListenable,
|
||||||
builder: (context, final isViewingFavourites, _) => !isViewingFavourites
|
builder: (context, final isViewingFavourites, _) => !isViewingFavourites
|
||||||
? Wrap(
|
? CustomWrap(
|
||||||
runSpacing: 24,
|
|
||||||
spacing: 8,
|
|
||||||
alignment: WrapAlignment.center,
|
|
||||||
runAlignment: WrapAlignment.center,
|
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
for (final imageModel in galleryViewModel.imageModels)
|
for (final imageModel in galleryViewModel.imageModels)
|
||||||
_StarrableImage(
|
_StarrableImage(
|
||||||
|
@ -33,12 +28,7 @@ class _DownloadedGalleryView extends StatelessWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: Wrap(
|
: CustomWrap(
|
||||||
runSpacing: 24,
|
|
||||||
spacing: 8,
|
|
||||||
alignment: WrapAlignment.center,
|
|
||||||
runAlignment: WrapAlignment.center,
|
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
for (final favouriteImageModel in galleryViewModel.favouriteImageModels)
|
for (final favouriteImageModel in galleryViewModel.favouriteImageModels)
|
||||||
_StarrableImage(
|
_StarrableImage(
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mc_gallery/features/core/data/constants/const_media.dart';
|
|
||||||
|
|
||||||
import '/features/core/data/constants/const_colors.dart';
|
import '/features/core/data/constants/const_colors.dart';
|
||||||
import '/features/core/data/constants/const_durations.dart';
|
import '/features/core/data/constants/const_durations.dart';
|
||||||
|
import '/features/core/data/constants/const_media.dart';
|
||||||
import '/features/core/widgets/gap.dart';
|
import '/features/core/widgets/gap.dart';
|
||||||
import '/features/core/widgets/mcg_scaffold.dart';
|
import '/features/core/widgets/mcg_scaffold.dart';
|
||||||
import '/features/core/widgets/state/multi_value_listenable_builder.dart';
|
import '/features/core/widgets/state/multi_value_listenable_builder.dart';
|
||||||
import '/features/core/widgets/state/view_model_builder.dart';
|
import '/features/core/widgets/state/view_model_builder.dart';
|
||||||
|
import '/features/home/widgets/custom_wrap.dart';
|
||||||
import '../../data/enums/search_option.dart';
|
import '../../data/enums/search_option.dart';
|
||||||
import '../../data/models/image_model.dart';
|
import '../../data/models/image_model.dart';
|
||||||
import 'gallery_view_model.dart';
|
import 'gallery_view_model.dart';
|
||||||
|
@ -81,21 +82,38 @@ class GalleryView extends StatelessWidget {
|
||||||
valueListenable: model.isSearchingListenable,
|
valueListenable: model.isSearchingListenable,
|
||||||
builder: (context, final isSearching, _) => AnimatedSwitcher(
|
builder: (context, final isSearching, _) => AnimatedSwitcher(
|
||||||
duration: ConstDurations.oneAndHalfDefaultAnimationDuration,
|
duration: ConstDurations.oneAndHalfDefaultAnimationDuration,
|
||||||
child: Column(
|
child: !isSearching
|
||||||
children: [
|
? Column(
|
||||||
ValueListenableBuilder<bool>(
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
valueListenable: model.isViewingFavouriteListenable,
|
children: [
|
||||||
builder: (context, final isViewingFavourites, child) =>
|
ValueListenableBuilder<bool>(
|
||||||
Switch(
|
valueListenable: model.isViewingFavouriteListenable,
|
||||||
value: isViewingFavourites,
|
builder:
|
||||||
onChanged: model.onFavouriteViewChange,
|
(context, final isViewingFavourites, child) =>
|
||||||
),
|
Row(
|
||||||
),
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
!isSearching
|
children: [
|
||||||
? _DownloadedGalleryView(galleryViewModel: model)
|
ConstMedia.buildIcon(
|
||||||
: _SearchGalleryView(galleryViewModel: model),
|
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),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@ import 'dart:async';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||||
import 'package:mc_gallery/features/core/data/extensions/value_notifier_extensions.dart';
|
|
||||||
|
|
||||||
import '/features/core/abstracts/base_view_model.dart';
|
import '/features/core/abstracts/base_view_model.dart';
|
||||||
|
import '/features/core/data/extensions/value_notifier_extensions.dart';
|
||||||
import '/features/core/services/logging_service.dart';
|
import '/features/core/services/logging_service.dart';
|
||||||
import '/features/core/services/navigation_service.dart';
|
import '/features/core/services/navigation_service.dart';
|
||||||
import '/locator.dart';
|
import '/locator.dart';
|
||||||
|
|
|
@ -29,12 +29,7 @@ class _SearchGalleryView extends StatelessWidget {
|
||||||
builder: (context, final searchOption, child) {
|
builder: (context, final searchOption, child) {
|
||||||
switch (searchOption) {
|
switch (searchOption) {
|
||||||
case SearchOption.local:
|
case SearchOption.local:
|
||||||
return Wrap(
|
return CustomWrap(
|
||||||
runSpacing: 24,
|
|
||||||
spacing: 8,
|
|
||||||
alignment: WrapAlignment.center,
|
|
||||||
runAlignment: WrapAlignment.center,
|
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
for (final resultsImageModel in resultsImageModels)
|
for (final resultsImageModel in resultsImageModels)
|
||||||
CachedNetworkImage(
|
CachedNetworkImage(
|
||||||
|
@ -48,12 +43,7 @@ class _SearchGalleryView extends StatelessWidget {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
case SearchOption.web:
|
case SearchOption.web:
|
||||||
return Wrap(
|
return CustomWrap(
|
||||||
runSpacing: 24,
|
|
||||||
spacing: 8,
|
|
||||||
alignment: WrapAlignment.center,
|
|
||||||
runAlignment: WrapAlignment.center,
|
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
for (final imageResult in resultsImageModels)
|
for (final imageResult in resultsImageModels)
|
||||||
Image.network(
|
Image.network(
|
||||||
|
|
|
@ -3,7 +3,6 @@ import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||||
|
|
||||||
import '/features/core/abstracts/base_view_model.dart';
|
import '/features/core/abstracts/base_view_model.dart';
|
||||||
import '/features/core/services/logging_service.dart';
|
import '/features/core/services/logging_service.dart';
|
||||||
import '/features/core/services/navigation_service.dart';
|
|
||||||
import '/features/home/services/images_service.dart';
|
import '/features/home/services/images_service.dart';
|
||||||
import '/features/home/views/image_carousel/image_carousel_view.dart';
|
import '/features/home/views/image_carousel/image_carousel_view.dart';
|
||||||
import '/locator.dart';
|
import '/locator.dart';
|
||||||
|
@ -12,14 +11,11 @@ import '../../data/models/image_model.dart';
|
||||||
class ImageCarouselViewModel extends BaseViewModel {
|
class ImageCarouselViewModel extends BaseViewModel {
|
||||||
ImageCarouselViewModel({
|
ImageCarouselViewModel({
|
||||||
required ImagesService imagesService,
|
required ImagesService imagesService,
|
||||||
required NavigationService navigationService,
|
|
||||||
required LoggingService loggingService,
|
required LoggingService loggingService,
|
||||||
}) : _imagesService = imagesService,
|
}) : _imagesService = imagesService,
|
||||||
_navigationService = navigationService,
|
|
||||||
_loggingService = loggingService;
|
_loggingService = loggingService;
|
||||||
|
|
||||||
final ImagesService _imagesService;
|
final ImagesService _imagesService;
|
||||||
final NavigationService _navigationService;
|
|
||||||
final LoggingService _loggingService;
|
final LoggingService _loggingService;
|
||||||
|
|
||||||
late final ValueNotifier<ImageModel> _currentImageModelNotifier;
|
late final ValueNotifier<ImageModel> _currentImageModelNotifier;
|
||||||
|
|
30
lib/features/home/widgets/custom_wrap.dart
Normal file
30
lib/features/home/widgets/custom_wrap.dart
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '/features/core/data/constants/const_colors.dart';
|
||||||
|
|
||||||
|
class CustomWrap extends StatelessWidget {
|
||||||
|
const CustomWrap({
|
||||||
|
required this.children,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<Widget> children;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return children.isNotEmpty
|
||||||
|
? Wrap(
|
||||||
|
runSpacing: 24,
|
||||||
|
spacing: 8,
|
||||||
|
alignment: WrapAlignment.center,
|
||||||
|
runAlignment: WrapAlignment.center,
|
||||||
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
|
children: children,
|
||||||
|
)
|
||||||
|
: const Icon(
|
||||||
|
Icons.not_interested_sharp,
|
||||||
|
size: 80,
|
||||||
|
color: ConstColours.red,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -53,7 +53,6 @@ class Locator {
|
||||||
instance().registerFactory(
|
instance().registerFactory(
|
||||||
() => ImageCarouselViewModel(
|
() => ImageCarouselViewModel(
|
||||||
imagesService: ImagesService.locate,
|
imagesService: ImagesService.locate,
|
||||||
navigationService: NavigationService.locate,
|
|
||||||
loggingService: LoggingService.locate,
|
loggingService: LoggingService.locate,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue