Browse Source

Implemented multi select interaction (#13)

Alex 3 years ago
parent
commit
328f382f86

+ 3 - 0
README.md

@@ -15,8 +15,11 @@ This project is under heavy development, there will be continous functions, feat
 # Features
 # Features
 
 
 [x] Upload assets(videos/images)
 [x] Upload assets(videos/images)
+
 [x] View assets
 [x] View assets
+
 [x] Quick navigation with drag scroll bar
 [x] Quick navigation with drag scroll bar
+
 [x] Auto Backup
 [x] Auto Backup
 
 
 # Development
 # Development

+ 66 - 0
mobile/lib/modules/home/models/home_page_state.model.dart

@@ -0,0 +1,66 @@
+import 'dart:convert';
+
+import 'package:collection/collection.dart';
+
+import 'package:immich_mobile/shared/models/immich_asset.model.dart';
+
+class HomePageState {
+  final bool isMultiSelectEnable;
+  final Set<ImmichAsset> selectedItems;
+  final Set<String> selectedDateGroup;
+  HomePageState({
+    required this.isMultiSelectEnable,
+    required this.selectedItems,
+    required this.selectedDateGroup,
+  });
+
+  HomePageState copyWith({
+    bool? isMultiSelectEnable,
+    Set<ImmichAsset>? selectedItems,
+    Set<String>? selectedDateGroup,
+  }) {
+    return HomePageState(
+      isMultiSelectEnable: isMultiSelectEnable ?? this.isMultiSelectEnable,
+      selectedItems: selectedItems ?? this.selectedItems,
+      selectedDateGroup: selectedDateGroup ?? this.selectedDateGroup,
+    );
+  }
+
+  Map<String, dynamic> toMap() {
+    return {
+      'isMultiSelectEnable': isMultiSelectEnable,
+      'selectedItems': selectedItems.map((x) => x.toMap()).toList(),
+      'selectedDateGroup': selectedDateGroup.toList(),
+    };
+  }
+
+  factory HomePageState.fromMap(Map<String, dynamic> map) {
+    return HomePageState(
+      isMultiSelectEnable: map['isMultiSelectEnable'] ?? false,
+      selectedItems: Set<ImmichAsset>.from(map['selectedItems']?.map((x) => ImmichAsset.fromMap(x))),
+      selectedDateGroup: Set<String>.from(map['selectedDateGroup']),
+    );
+  }
+
+  String toJson() => json.encode(toMap());
+
+  factory HomePageState.fromJson(String source) => HomePageState.fromMap(json.decode(source));
+
+  @override
+  String toString() =>
+      'HomePageState(isMultiSelectEnable: $isMultiSelectEnable, selectedItems: $selectedItems, selectedDateGroup: $selectedDateGroup)';
+
+  @override
+  bool operator ==(Object other) {
+    if (identical(this, other)) return true;
+    final setEquals = const DeepCollectionEquality().equals;
+
+    return other is HomePageState &&
+        other.isMultiSelectEnable == isMultiSelectEnable &&
+        setEquals(other.selectedItems, selectedItems) &&
+        setEquals(other.selectedDateGroup, selectedDateGroup);
+  }
+
+  @override
+  int get hashCode => isMultiSelectEnable.hashCode ^ selectedItems.hashCode ^ selectedDateGroup.hashCode;
+}

+ 63 - 0
mobile/lib/modules/home/providers/home_page_state.provider.dart

@@ -0,0 +1,63 @@
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/modules/home/models/home_page_state.model.dart';
+import 'package:immich_mobile/shared/models/immich_asset.model.dart';
+
+class HomePageStateNotifier extends StateNotifier<HomePageState> {
+  HomePageStateNotifier()
+      : super(
+          HomePageState(
+            isMultiSelectEnable: false,
+            selectedItems: {},
+            selectedDateGroup: {},
+          ),
+        );
+
+  void addSelectedDateGroup(String dateGroupTitle) {
+    state = state.copyWith(selectedDateGroup: {...state.selectedDateGroup, dateGroupTitle});
+  }
+
+  void removeSelectedDateGroup(String dateGroupTitle) {
+    var currentDateGroup = state.selectedDateGroup;
+
+    currentDateGroup.removeWhere((e) => e == dateGroupTitle);
+
+    state = state.copyWith(selectedDateGroup: currentDateGroup);
+  }
+
+  void enableMultiSelect(Set<ImmichAsset> selectedItems) {
+    state = state.copyWith(isMultiSelectEnable: true, selectedItems: selectedItems);
+  }
+
+  void disableMultiSelect() {
+    state = state.copyWith(isMultiSelectEnable: false, selectedItems: {}, selectedDateGroup: {});
+  }
+
+  void addSingleSelectedItem(ImmichAsset asset) {
+    state = state.copyWith(selectedItems: {...state.selectedItems, asset});
+  }
+
+  void addMultipleSelectedItems(List<ImmichAsset> assets) {
+    state = state.copyWith(selectedItems: {...state.selectedItems, ...assets});
+  }
+
+  void removeSingleSelectedItem(ImmichAsset asset) {
+    Set<ImmichAsset> currentList = state.selectedItems;
+
+    currentList.removeWhere((e) => e.id == asset.id);
+
+    state = state.copyWith(selectedItems: currentList);
+  }
+
+  void removeMultipleSelectedItem(List<ImmichAsset> assets) {
+    Set<ImmichAsset> currentList = state.selectedItems;
+
+    for (ImmichAsset asset in assets) {
+      currentList.removeWhere((e) => e.id == asset.id);
+    }
+
+    state = state.copyWith(selectedItems: currentList);
+  }
+}
+
+final homePageStateProvider =
+    StateNotifierProvider<HomePageStateNotifier, HomePageState>(((ref) => HomePageStateNotifier()));

+ 75 - 0
mobile/lib/modules/home/ui/daily_title_text.dart

@@ -0,0 +1,75 @@
+import 'package:flutter/material.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/modules/home/providers/home_page_state.provider.dart';
+import 'package:immich_mobile/shared/models/immich_asset.model.dart';
+import 'package:intl/intl.dart';
+
+class DailyTitleText extends ConsumerWidget {
+  const DailyTitleText({
+    Key? key,
+    required this.isoDate,
+    required this.assetGroup,
+  }) : super(key: key);
+
+  final String isoDate;
+  final List<ImmichAsset> assetGroup;
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    var currentYear = DateTime.now().year;
+    var groupYear = DateTime.parse(isoDate).year;
+    var formatDateTemplate = currentYear == groupYear ? 'E, MMM dd' : 'E, MMM dd, yyyy';
+    var dateText = DateFormat(formatDateTemplate).format(DateTime.parse(isoDate));
+    var isMultiSelectEnable = ref.watch(homePageStateProvider).isMultiSelectEnable;
+    var selectedDateGroup = ref.watch(homePageStateProvider).selectedDateGroup;
+    var selectedItems = ref.watch(homePageStateProvider).selectedItems;
+
+    return SliverToBoxAdapter(
+      child: Padding(
+        padding: const EdgeInsets.only(top: 29.0, bottom: 29.0, left: 12.0, right: 12.0),
+        child: Row(
+          children: [
+            Text(
+              dateText,
+              style: const TextStyle(
+                fontSize: 14,
+                fontWeight: FontWeight.bold,
+                color: Colors.black87,
+              ),
+            ),
+            const Spacer(),
+            GestureDetector(
+              onTap: () {
+                if (isMultiSelectEnable &&
+                    selectedDateGroup.contains(dateText) &&
+                    selectedDateGroup.length == 1 &&
+                    selectedItems.length == assetGroup.length) {
+                  ref.watch(homePageStateProvider.notifier).disableMultiSelect();
+                } else if (isMultiSelectEnable &&
+                    selectedDateGroup.contains(dateText) &&
+                    selectedItems.length != assetGroup.length) {
+                  ref.watch(homePageStateProvider.notifier).removeSelectedDateGroup(dateText);
+                  ref.watch(homePageStateProvider.notifier).removeMultipleSelectedItem(assetGroup);
+                } else if (isMultiSelectEnable &&
+                    selectedDateGroup.contains(dateText) &&
+                    selectedDateGroup.length > 1) {
+                  ref.watch(homePageStateProvider.notifier).removeSelectedDateGroup(dateText);
+                  ref.watch(homePageStateProvider.notifier).removeMultipleSelectedItem(assetGroup);
+                } else if (isMultiSelectEnable && !selectedDateGroup.contains(dateText)) {
+                  ref.watch(homePageStateProvider.notifier).addSelectedDateGroup(dateText);
+                  ref.watch(homePageStateProvider.notifier).addMultipleSelectedItems(assetGroup);
+                } else {
+                  ref.watch(homePageStateProvider.notifier).enableMultiSelect(assetGroup.toSet());
+                  ref.watch(homePageStateProvider.notifier).addSelectedDateGroup(dateText);
+                }
+              },
+              child: isMultiSelectEnable && selectedDateGroup.contains(dateText)
+                  ? const Icon(Icons.check_circle_rounded)
+                  : const Icon(Icons.check_circle_outline_rounded),
+            )
+          ],
+        ),
+      ),
+    );
+  }
+}

+ 30 - 0
mobile/lib/modules/home/ui/monthly_title_text.dart

@@ -0,0 +1,30 @@
+import 'package:flutter/material.dart';
+import 'package:intl/intl.dart';
+
+class MonthlyTitleText extends StatelessWidget {
+  const MonthlyTitleText({
+    Key? key,
+    required this.isoDate,
+  }) : super(key: key);
+
+  final String isoDate;
+
+  @override
+  Widget build(BuildContext context) {
+    var monthTitleText = DateFormat('MMMM y').format(DateTime.parse(isoDate));
+
+    return SliverToBoxAdapter(
+      child: Padding(
+        padding: const EdgeInsets.only(left: 12.0, top: 32),
+        child: Text(
+          monthTitleText,
+          style: TextStyle(
+            fontSize: 26,
+            fontWeight: FontWeight.bold,
+            color: Theme.of(context).primaryColor,
+          ),
+        ),
+      ),
+    );
+  }
+}

+ 91 - 36
mobile/lib/modules/home/ui/thumbnail_image.dart

@@ -1,66 +1,121 @@
 import 'package:auto_route/auto_route.dart';
 import 'package:auto_route/auto_route.dart';
 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:flutter/services.dart';
 import 'package:flutter_hooks/flutter_hooks.dart';
 import 'package:flutter_hooks/flutter_hooks.dart';
 import 'package:hive_flutter/hive_flutter.dart';
 import 'package:hive_flutter/hive_flutter.dart';
+import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:immich_mobile/constants/hive_box.dart';
 import 'package:immich_mobile/constants/hive_box.dart';
+import 'package:immich_mobile/modules/home/providers/home_page_state.provider.dart';
 import 'package:immich_mobile/shared/models/immich_asset.model.dart';
 import 'package:immich_mobile/shared/models/immich_asset.model.dart';
 import 'package:immich_mobile/routing/router.dart';
 import 'package:immich_mobile/routing/router.dart';
 
 
-class ThumbnailImage extends HookWidget {
+class ThumbnailImage extends HookConsumerWidget {
   final ImmichAsset asset;
   final ImmichAsset asset;
 
 
   const ThumbnailImage({Key? key, required this.asset}) : super(key: key);
   const ThumbnailImage({Key? key, required this.asset}) : super(key: key);
 
 
   @override
   @override
-  Widget build(BuildContext context) {
+  Widget build(BuildContext context, WidgetRef ref) {
     final cacheKey = useState(1);
     final cacheKey = useState(1);
 
 
     var box = Hive.box(userInfoBox);
     var box = Hive.box(userInfoBox);
     var thumbnailRequestUrl =
     var thumbnailRequestUrl =
         '${box.get(serverEndpointKey)}/asset/file?aid=${asset.deviceAssetId}&did=${asset.deviceId}&isThumb=true';
         '${box.get(serverEndpointKey)}/asset/file?aid=${asset.deviceAssetId}&did=${asset.deviceId}&isThumb=true';
+
+    var selectedAsset = ref.watch(homePageStateProvider).selectedItems;
+    var isMultiSelectEnable = ref.watch(homePageStateProvider).isMultiSelectEnable;
+
+    Widget _buildSelectionIcon(ImmichAsset asset) {
+      if (selectedAsset.contains(asset)) {
+        return Icon(
+          Icons.check_circle,
+          color: Theme.of(context).primaryColor,
+        );
+      } else {
+        return const Icon(
+          Icons.circle_outlined,
+          color: Colors.white,
+        );
+      }
+    }
+
     return GestureDetector(
     return GestureDetector(
       onTap: () {
       onTap: () {
-        if (asset.type == 'IMAGE') {
-          AutoRouter.of(context).push(
-            ImageViewerRoute(
-              imageUrl:
-                  '${box.get(serverEndpointKey)}/asset/file?aid=${asset.deviceAssetId}&did=${asset.deviceId}&isThumb=false',
-              heroTag: asset.id,
-              thumbnailUrl: thumbnailRequestUrl,
-            ),
-          );
+        if (isMultiSelectEnable && selectedAsset.contains(asset) && selectedAsset.length == 1) {
+          ref.watch(homePageStateProvider.notifier).disableMultiSelect();
+        } else if (isMultiSelectEnable && selectedAsset.contains(asset) && selectedAsset.length > 1) {
+          ref.watch(homePageStateProvider.notifier).removeSingleSelectedItem(asset);
+        } else if (isMultiSelectEnable && !selectedAsset.contains(asset)) {
+          ref.watch(homePageStateProvider.notifier).addSingleSelectedItem(asset);
         } else {
         } else {
-          debugPrint("Navigate to video player");
+          if (asset.type == 'IMAGE') {
+            AutoRouter.of(context).push(
+              ImageViewerRoute(
+                imageUrl:
+                    '${box.get(serverEndpointKey)}/asset/file?aid=${asset.deviceAssetId}&did=${asset.deviceId}&isThumb=false',
+                heroTag: asset.id,
+                thumbnailUrl: thumbnailRequestUrl,
+              ),
+            );
+          } else {
+            debugPrint("Navigate to video player");
 
 
-          AutoRouter.of(context).push(
-            VideoViewerRoute(
-              videoUrl: '${box.get(serverEndpointKey)}/asset/file?aid=${asset.deviceAssetId}&did=${asset.deviceId}',
-            ),
-          );
+            AutoRouter.of(context).push(
+              VideoViewerRoute(
+                videoUrl: '${box.get(serverEndpointKey)}/asset/file?aid=${asset.deviceAssetId}&did=${asset.deviceId}',
+              ),
+            );
+          }
         }
         }
       },
       },
-      onLongPress: () {},
+      onLongPress: () {
+        // Enable multi selecte function
+        ref.watch(homePageStateProvider.notifier).enableMultiSelect({asset});
+        HapticFeedback.heavyImpact();
+      },
       child: Hero(
       child: Hero(
         tag: asset.id,
         tag: asset.id,
-        child: CachedNetworkImage(
-          cacheKey: "${asset.id}-${cacheKey.value}",
-          width: 300,
-          height: 300,
-          memCacheHeight: asset.type == 'IMAGE' ? 250 : 400,
-          fit: BoxFit.cover,
-          imageUrl: thumbnailRequestUrl,
-          httpHeaders: {"Authorization": "Bearer ${box.get(accessTokenKey)}"},
-          fadeInDuration: const Duration(milliseconds: 250),
-          progressIndicatorBuilder: (context, url, downloadProgress) => Transform.scale(
-            scale: 0.2,
-            child: CircularProgressIndicator(value: downloadProgress.progress),
-          ),
-          errorWidget: (context, url, error) {
-            debugPrint("Error Loading Thumbnail Widget $error");
-            cacheKey.value += 1;
-            return const Icon(Icons.error);
-          },
+        child: Stack(
+          children: [
+            Container(
+              decoration: BoxDecoration(
+                border: isMultiSelectEnable && selectedAsset.contains(asset)
+                    ? Border.all(color: Theme.of(context).primaryColorLight, width: 10)
+                    : const Border(),
+              ),
+              child: CachedNetworkImage(
+                cacheKey: "${asset.id}-${cacheKey.value}",
+                width: 300,
+                height: 300,
+                memCacheHeight: asset.type == 'IMAGE' ? 250 : 400,
+                fit: BoxFit.cover,
+                imageUrl: thumbnailRequestUrl,
+                httpHeaders: {"Authorization": "Bearer ${box.get(accessTokenKey)}"},
+                fadeInDuration: const Duration(milliseconds: 250),
+                progressIndicatorBuilder: (context, url, downloadProgress) => Transform.scale(
+                  scale: 0.2,
+                  child: CircularProgressIndicator(value: downloadProgress.progress),
+                ),
+                errorWidget: (context, url, error) {
+                  debugPrint("Error Loading Thumbnail Widget $error");
+                  cacheKey.value += 1;
+                  return const Icon(Icons.error);
+                },
+              ),
+            ),
+            Container(
+              child: isMultiSelectEnable
+                  ? Padding(
+                      padding: const EdgeInsets.all(3.0),
+                      child: Align(
+                        alignment: Alignment.topLeft,
+                        child: _buildSelectionIcon(asset),
+                      ),
+                    )
+                  : Container(),
+            ),
+          ],
         ),
         ),
       ),
       ),
     );
     );

+ 15 - 88
mobile/lib/modules/home/views/home_page.dart

@@ -1,24 +1,23 @@
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_hooks/flutter_hooks.dart';
 import 'package:flutter_hooks/flutter_hooks.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
+import 'package:immich_mobile/modules/home/ui/daily_title_text.dart';
 import 'package:immich_mobile/modules/home/ui/draggable_scrollbar.dart';
 import 'package:immich_mobile/modules/home/ui/draggable_scrollbar.dart';
 import 'package:immich_mobile/modules/home/ui/image_grid.dart';
 import 'package:immich_mobile/modules/home/ui/image_grid.dart';
 import 'package:immich_mobile/modules/home/ui/immich_sliver_appbar.dart';
 import 'package:immich_mobile/modules/home/ui/immich_sliver_appbar.dart';
+import 'package:immich_mobile/modules/home/ui/monthly_title_text.dart';
 import 'package:immich_mobile/modules/home/ui/profile_drawer.dart';
 import 'package:immich_mobile/modules/home/ui/profile_drawer.dart';
 import 'package:immich_mobile/modules/home/models/get_all_asset_respose.model.dart';
 import 'package:immich_mobile/modules/home/models/get_all_asset_respose.model.dart';
 import 'package:immich_mobile/modules/home/providers/asset.provider.dart';
 import 'package:immich_mobile/modules/home/providers/asset.provider.dart';
-import 'package:intl/intl.dart';
 
 
 class HomePage extends HookConsumerWidget {
 class HomePage extends HookConsumerWidget {
   const HomePage({Key? key}) : super(key: key);
   const HomePage({Key? key}) : super(key: key);
 
 
   @override
   @override
   Widget build(BuildContext context, WidgetRef ref) {
   Widget build(BuildContext context, WidgetRef ref) {
-    final ValueNotifier<bool> _showBackToTopBtn = useState(false);
     ScrollController _scrollController = useScrollController();
     ScrollController _scrollController = useScrollController();
-
-    List<ImmichAssetGroupByDate> assetGroup = ref.watch(assetProvider);
-    List<Widget> imageGridGroup = [];
+    List<ImmichAssetGroupByDate> _assetGroup = ref.watch(assetProvider);
+    List<Widget> _imageGridGroup = [];
 
 
     _scrollControllerCallback() {
     _scrollControllerCallback() {
       var endOfPage = _scrollController.position.maxScrollExtent;
       var endOfPage = _scrollController.position.maxScrollExtent;
@@ -26,12 +25,6 @@ class HomePage extends HookConsumerWidget {
       if (_scrollController.offset >= endOfPage - (endOfPage * 0.1) && !_scrollController.position.outOfRange) {
       if (_scrollController.offset >= endOfPage - (endOfPage * 0.1) && !_scrollController.position.outOfRange) {
         ref.read(assetProvider.notifier).getOlderAsset();
         ref.read(assetProvider.notifier).getOlderAsset();
       }
       }
-
-      if (_scrollController.offset >= 400) {
-        _showBackToTopBtn.value = true;
-      } else {
-        _showBackToTopBtn.value = false;
-      }
     }
     }
 
 
     useEffect(() {
     useEffect(() {
@@ -49,18 +42,18 @@ class HomePage extends HookConsumerWidget {
       // Remove and force getting new widget again if there is not many widget on screen.
       // Remove and force getting new widget again if there is not many widget on screen.
       // Otherwise do nothing.
       // Otherwise do nothing.
 
 
-      if (imageGridGroup.isNotEmpty && imageGridGroup.length < 20) {
+      if (_imageGridGroup.isNotEmpty && _imageGridGroup.length < 20) {
         ref.read(assetProvider.notifier).getOlderAsset();
         ref.read(assetProvider.notifier).getOlderAsset();
-      } else if (imageGridGroup.isEmpty) {
+      } else if (_imageGridGroup.isEmpty) {
         ref.read(assetProvider.notifier).getImmichAssets();
         ref.read(assetProvider.notifier).getImmichAssets();
       }
       }
     }
     }
 
 
     Widget _buildBody() {
     Widget _buildBody() {
-      if (assetGroup.isNotEmpty) {
-        String lastGroupDate = assetGroup[0].date;
+      if (_assetGroup.isNotEmpty) {
+        String lastGroupDate = _assetGroup[0].date;
 
 
-        for (var group in assetGroup) {
+        for (var group in _assetGroup) {
           var dateTitle = group.date;
           var dateTitle = group.date;
           var assetGroup = group.assets;
           var assetGroup = group.assets;
 
 
@@ -71,19 +64,19 @@ class HomePage extends HookConsumerWidget {
 
 
           if (currentMonth != null && previousMonth != null) {
           if (currentMonth != null && previousMonth != null) {
             if ((currentMonth - previousMonth) != 0) {
             if ((currentMonth - previousMonth) != 0) {
-              imageGridGroup.add(
+              _imageGridGroup.add(
                 MonthlyTitleText(isoDate: dateTitle),
                 MonthlyTitleText(isoDate: dateTitle),
               );
               );
             }
             }
           }
           }
 
 
           // Add Daily Title Group
           // Add Daily Title Group
-          imageGridGroup.add(
-            DailyTitleText(isoDate: dateTitle),
+          _imageGridGroup.add(
+            DailyTitleText(isoDate: dateTitle, assetGroup: assetGroup),
           );
           );
 
 
           // Add Image Group
           // Add Image Group
-          imageGridGroup.add(
+          _imageGridGroup.add(
             ImageGrid(assetGroup: assetGroup),
             ImageGrid(assetGroup: assetGroup),
           );
           );
           //
           //
@@ -100,10 +93,10 @@ class HomePage extends HookConsumerWidget {
             controller: _scrollController,
             controller: _scrollController,
             slivers: [
             slivers: [
               ImmichSliverAppBar(
               ImmichSliverAppBar(
-                imageGridGroup: imageGridGroup,
+                imageGridGroup: _imageGridGroup,
                 onPopBack: onPopBackFromBackupPage,
                 onPopBack: onPopBackFromBackupPage,
               ),
               ),
-              ...imageGridGroup,
+              ..._imageGridGroup,
             ],
             ],
           ),
           ),
         ),
         ),
@@ -116,69 +109,3 @@ class HomePage extends HookConsumerWidget {
     );
     );
   }
   }
 }
 }
-
-class MonthlyTitleText extends StatelessWidget {
-  const MonthlyTitleText({
-    Key? key,
-    required this.isoDate,
-  }) : super(key: key);
-
-  final String isoDate;
-
-  @override
-  Widget build(BuildContext context) {
-    var monthTitleText = DateFormat('MMMM, y').format(DateTime.parse(isoDate));
-
-    return SliverToBoxAdapter(
-      child: Padding(
-        padding: const EdgeInsets.only(left: 10.0, top: 32),
-        child: Text(
-          monthTitleText,
-          style: TextStyle(
-            fontSize: 24,
-            fontWeight: FontWeight.bold,
-            color: Theme.of(context).primaryColor,
-          ),
-        ),
-      ),
-    );
-  }
-}
-
-class DailyTitleText extends StatelessWidget {
-  const DailyTitleText({
-    Key? key,
-    required this.isoDate,
-  }) : super(key: key);
-
-  final String isoDate;
-
-  @override
-  Widget build(BuildContext context) {
-    var currentYear = DateTime.now().year;
-    var groupYear = DateTime.parse(isoDate).year;
-    var formatDateTemplate = currentYear == groupYear ? 'E, MMM dd' : 'E, MMM dd, yyyy';
-    var dateText = DateFormat(formatDateTemplate).format(DateTime.parse(isoDate));
-
-    return SliverToBoxAdapter(
-      child: Padding(
-        padding: const EdgeInsets.only(top: 24.0, bottom: 24.0, left: 3.0),
-        child: Row(
-          children: [
-            Padding(
-              padding: const EdgeInsets.only(left: 8.0, bottom: 5.0, top: 5.0),
-              child: Text(
-                dateText,
-                style: const TextStyle(
-                  fontSize: 14,
-                  fontWeight: FontWeight.bold,
-                  color: Colors.black87,
-                ),
-              ),
-            ),
-          ],
-        ),
-      ),
-    );
-  }
-}