mirror of
https://github.com/immich-app/immich.git
synced 2024-12-25 10:43:13 +02:00
feat(mobile): Responsive layout improvements with a navigation rail and album grid (#1583)
This commit is contained in:
parent
18647203cc
commit
dc9da7480c
@ -1,18 +1,19 @@
|
|||||||
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:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:immich_mobile/constants/hive_box.dart';
|
import 'package:immich_mobile/constants/hive_box.dart';
|
||||||
import 'package:immich_mobile/routing/router.dart';
|
|
||||||
import 'package:immich_mobile/shared/models/album.dart';
|
import 'package:immich_mobile/shared/models/album.dart';
|
||||||
import 'package:immich_mobile/utils/image_url_builder.dart';
|
import 'package:immich_mobile/utils/image_url_builder.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
|
|
||||||
class AlbumThumbnailCard extends StatelessWidget {
|
class AlbumThumbnailCard extends StatelessWidget {
|
||||||
|
final Function()? onTap;
|
||||||
|
|
||||||
const AlbumThumbnailCard({
|
const AlbumThumbnailCard({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.album,
|
required this.album,
|
||||||
|
this.onTap,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final Album album;
|
final Album album;
|
||||||
@ -20,89 +21,94 @@ class AlbumThumbnailCard extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var box = Hive.box(userInfoBox);
|
var box = Hive.box(userInfoBox);
|
||||||
var cardSize = MediaQuery.of(context).size.width / 2 - 18;
|
|
||||||
var isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
var isDarkMode = Theme.of(context).brightness == Brightness.dark;
|
||||||
|
return LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
var cardSize = constraints.maxWidth;
|
||||||
|
|
||||||
buildEmptyThumbnail() {
|
buildEmptyThumbnail() {
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: isDarkMode ? Colors.grey[800] : Colors.grey[200],
|
|
||||||
),
|
|
||||||
child: SizedBox(
|
|
||||||
height: cardSize,
|
height: cardSize,
|
||||||
width: cardSize,
|
width: cardSize,
|
||||||
child: const Center(
|
decoration: BoxDecoration(
|
||||||
child: Icon(Icons.no_photography),
|
color: isDarkMode ? Colors.grey[800] : Colors.grey[200],
|
||||||
),
|
),
|
||||||
),
|
child: Center(
|
||||||
);
|
child: Icon(
|
||||||
}
|
Icons.no_photography,
|
||||||
|
size: cardSize * .15,
|
||||||
buildAlbumThumbnail() {
|
|
||||||
return CachedNetworkImage(
|
|
||||||
width: cardSize,
|
|
||||||
height: cardSize,
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
fadeInDuration: const Duration(milliseconds: 200),
|
|
||||||
imageUrl: getAlbumThumbnailUrl(
|
|
||||||
album,
|
|
||||||
type: ThumbnailFormat.JPEG,
|
|
||||||
),
|
|
||||||
httpHeaders: {"Authorization": "Bearer ${box.get(accessTokenKey)}"},
|
|
||||||
cacheKey: getAlbumThumbNailCacheKey(album, type: ThumbnailFormat.JPEG),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
AutoRouter.of(context).push(AlbumViewerRoute(albumId: album.id));
|
|
||||||
},
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 32.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
child: album.albumThumbnailAssetId == null
|
|
||||||
? buildEmptyThumbnail()
|
|
||||||
: buildAlbumThumbnail(),
|
|
||||||
),
|
),
|
||||||
Padding(
|
),
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
);
|
||||||
child: SizedBox(
|
}
|
||||||
width: cardSize,
|
|
||||||
child: Text(
|
buildAlbumThumbnail() {
|
||||||
album.name,
|
return CachedNetworkImage(
|
||||||
style: const TextStyle(
|
width: cardSize,
|
||||||
fontWeight: FontWeight.bold,
|
height: cardSize,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
fadeInDuration: const Duration(milliseconds: 200),
|
||||||
|
imageUrl: getAlbumThumbnailUrl(
|
||||||
|
album,
|
||||||
|
type: ThumbnailFormat.JPEG,
|
||||||
|
),
|
||||||
|
httpHeaders: {"Authorization": "Bearer ${box.get(accessTokenKey)}"},
|
||||||
|
cacheKey: getAlbumThumbNailCacheKey(album, type: ThumbnailFormat.JPEG),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: onTap,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 32.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: album.albumThumbnailAssetId == null
|
||||||
|
? buildEmptyThumbnail()
|
||||||
|
: buildAlbumThumbnail(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 8.0),
|
||||||
|
child: SizedBox(
|
||||||
|
width: cardSize,
|
||||||
|
child: Text(
|
||||||
|
album.name,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Row(
|
||||||
Row(
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisSize: MainAxisSize.min,
|
children: [
|
||||||
children: [
|
Text(
|
||||||
Text(
|
album.assetCount == 1
|
||||||
album.assetCount == 1
|
? 'album_thumbnail_card_item'
|
||||||
? 'album_thumbnail_card_item'
|
: 'album_thumbnail_card_items',
|
||||||
: 'album_thumbnail_card_items',
|
style: const TextStyle(
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
).tr(args: ['${album.assetCount}']),
|
|
||||||
if (album.shared)
|
|
||||||
const Text(
|
|
||||||
'album_thumbnail_card_shared',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
),
|
),
|
||||||
).tr()
|
).tr(args: ['${album.assetCount}']),
|
||||||
],
|
if (album.shared)
|
||||||
)
|
const Text(
|
||||||
],
|
'album_thumbnail_card_shared',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
).tr()
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,37 +112,43 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
AutoRouter.of(context).push(CreateAlbumRoute(isSharedAlbum: false));
|
AutoRouter.of(context).push(CreateAlbumRoute(isSharedAlbum: false));
|
||||||
},
|
},
|
||||||
child: Column(
|
child: Padding(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
padding: const EdgeInsets.only(bottom: 32),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: Column(
|
||||||
children: [
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
Container(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
width: MediaQuery.of(context).size.width / 2 - 18,
|
children: [
|
||||||
height: MediaQuery.of(context).size.width / 2 - 18,
|
Expanded(
|
||||||
decoration: BoxDecoration(
|
child: Container(
|
||||||
border: Border.all(
|
decoration: BoxDecoration(
|
||||||
color: Colors.grey,
|
border: Border.all(
|
||||||
),
|
color: Colors.grey,
|
||||||
borderRadius: BorderRadius.circular(8),
|
),
|
||||||
),
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: Center(
|
),
|
||||||
child: Icon(
|
child: Center(
|
||||||
Icons.add_rounded,
|
child: Icon(
|
||||||
size: 28,
|
Icons.add_rounded,
|
||||||
color: Theme.of(context).primaryColor,
|
size: 28,
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
Padding(
|
||||||
Padding(
|
padding: const EdgeInsets.only(
|
||||||
padding: const EdgeInsets.only(top: 8.0),
|
top: 8.0,
|
||||||
child: const Text(
|
bottom: 16,
|
||||||
'library_page_new_album',
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
),
|
||||||
).tr(),
|
child: const Text(
|
||||||
)
|
'library_page_new_album',
|
||||||
],
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
).tr(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -185,6 +191,8 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final sorted = sortedAlbums();
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: buildAppBar(),
|
appBar: buildAppBar(),
|
||||||
body: CustomScrollView(
|
body: CustomScrollView(
|
||||||
@ -234,20 +242,33 @@ class LibraryPage extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
SliverPadding(
|
SliverPadding(
|
||||||
padding: const EdgeInsets.only(left: 12.0, right: 12, bottom: 50),
|
padding: const EdgeInsets.all(12.0),
|
||||||
sliver: SliverToBoxAdapter(
|
sliver: SliverGrid(
|
||||||
child: Wrap(
|
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
spacing: 12,
|
maxCrossAxisExtent: 250,
|
||||||
children: [
|
mainAxisSpacing: 12,
|
||||||
buildCreateAlbumButton(),
|
crossAxisSpacing: 12,
|
||||||
for (var album in sortedAlbums())
|
childAspectRatio: .7,
|
||||||
AlbumThumbnailCard(
|
),
|
||||||
album: album,
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
childCount: sorted.length + 1,
|
||||||
|
(context, index) {
|
||||||
|
if (index == 0) {
|
||||||
|
return buildCreateAlbumButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
return AlbumThumbnailCard(
|
||||||
|
album: sorted[index - 1],
|
||||||
|
onTap: () => AutoRouter.of(context).push(
|
||||||
|
AlbumViewerRoute(
|
||||||
|
albumId: sorted[index - 1].id,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -66,11 +66,6 @@ class ImmichAssetGridState extends State<ImmichAssetGrid> {
|
|||||||
assets.firstWhereOrNull((e) => !_selectedAssets.contains(e.id)) == null;
|
assets.firstWhereOrNull((e) => !_selectedAssets.contains(e.id)) == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
double _getItemSize(BuildContext context) {
|
|
||||||
return MediaQuery.of(context).size.width / widget.assetsPerRow -
|
|
||||||
widget.margin * (widget.assetsPerRow - 1) / widget.assetsPerRow;
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildThumbnailOrPlaceholder(
|
Widget _buildThumbnailOrPlaceholder(
|
||||||
Asset asset,
|
Asset asset,
|
||||||
bool placeholder,
|
bool placeholder,
|
||||||
@ -97,24 +92,29 @@ class ImmichAssetGridState extends State<ImmichAssetGrid> {
|
|||||||
RenderAssetGridRow row,
|
RenderAssetGridRow row,
|
||||||
bool scrolling,
|
bool scrolling,
|
||||||
) {
|
) {
|
||||||
double size = _getItemSize(context);
|
|
||||||
|
|
||||||
return Row(
|
return LayoutBuilder(
|
||||||
key: Key("asset-row-${row.assets.first.id}"),
|
builder: (context, constraints) {
|
||||||
children: row.assets.map((Asset asset) {
|
final size = constraints.maxWidth / widget.assetsPerRow -
|
||||||
bool last = asset.id == row.assets.last.id;
|
widget.margin * (widget.assetsPerRow - 1) / widget.assetsPerRow;
|
||||||
|
return Row(
|
||||||
|
key: Key("asset-row-${row.assets.first.id}"),
|
||||||
|
children: row.assets.map((Asset asset) {
|
||||||
|
bool last = asset.id == row.assets.last.id;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
key: Key("asset-${asset.id}"),
|
key: Key("asset-${asset.id}"),
|
||||||
width: size,
|
width: size,
|
||||||
height: size,
|
height: size,
|
||||||
margin: EdgeInsets.only(
|
margin: EdgeInsets.only(
|
||||||
top: widget.margin,
|
top: widget.margin,
|
||||||
right: last ? 0.0 : widget.margin,
|
right: last ? 0.0 : widget.margin,
|
||||||
),
|
),
|
||||||
child: _buildThumbnailOrPlaceholder(asset, scrolling),
|
child: _buildThumbnailOrPlaceholder(asset, scrolling),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
);
|
);
|
||||||
}).toList(),
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,96 @@ class TabControllerPage extends ConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
|
||||||
|
navigationRail(TabsRouter tabsRouter) {
|
||||||
|
return NavigationRail(
|
||||||
|
labelType: NavigationRailLabelType.all,
|
||||||
|
selectedIndex: tabsRouter.activeIndex,
|
||||||
|
onDestinationSelected: (index) {
|
||||||
|
HapticFeedback.selectionClick();
|
||||||
|
tabsRouter.setActiveIndex(index);
|
||||||
|
},
|
||||||
|
selectedIconTheme: IconThemeData(
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
),
|
||||||
|
selectedLabelTextStyle: TextStyle(
|
||||||
|
color: Theme.of(context).primaryColor,
|
||||||
|
),
|
||||||
|
useIndicator: false,
|
||||||
|
destinations: [
|
||||||
|
NavigationRailDestination(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
top: MediaQuery.of(context).padding.top + 4,
|
||||||
|
left: 4,
|
||||||
|
right: 4,
|
||||||
|
bottom: 4,
|
||||||
|
),
|
||||||
|
icon: const Icon(Icons.photo_outlined),
|
||||||
|
selectedIcon: const Icon(Icons.photo),
|
||||||
|
label: const Text('tab_controller_nav_photos').tr(),
|
||||||
|
),
|
||||||
|
NavigationRailDestination(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
icon: const Icon(Icons.search_rounded),
|
||||||
|
selectedIcon: const Icon(Icons.search),
|
||||||
|
label: const Text('tab_controller_nav_search').tr(),
|
||||||
|
),
|
||||||
|
NavigationRailDestination(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
icon: const Icon(Icons.share_rounded),
|
||||||
|
selectedIcon: const Icon(Icons.share),
|
||||||
|
label: const Text('tab_controller_nav_sharing').tr(),
|
||||||
|
),
|
||||||
|
NavigationRailDestination(
|
||||||
|
padding: const EdgeInsets.all(4),
|
||||||
|
icon: const Icon(Icons.photo_album_outlined),
|
||||||
|
selectedIcon: const Icon(Icons.photo_album),
|
||||||
|
label: const Text('tab_controller_nav_library').tr(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bottomNavigationBar(TabsRouter tabsRouter) {
|
||||||
|
return BottomNavigationBar(
|
||||||
|
selectedLabelStyle: const TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
unselectedLabelStyle: const TextStyle(
|
||||||
|
fontSize: 13,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
currentIndex: tabsRouter.activeIndex,
|
||||||
|
onTap: (index) {
|
||||||
|
HapticFeedback.selectionClick();
|
||||||
|
tabsRouter.setActiveIndex(index);
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
label: 'tab_controller_nav_photos'.tr(),
|
||||||
|
icon: const Icon(Icons.photo_outlined),
|
||||||
|
activeIcon: const Icon(Icons.photo),
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
label: 'tab_controller_nav_search'.tr(),
|
||||||
|
icon: const Icon(Icons.search_rounded),
|
||||||
|
activeIcon: const Icon(Icons.search),
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
label: 'tab_controller_nav_sharing'.tr(),
|
||||||
|
icon: const Icon(Icons.group_outlined),
|
||||||
|
activeIcon: const Icon(Icons.group),
|
||||||
|
),
|
||||||
|
BottomNavigationBarItem(
|
||||||
|
label: 'tab_controller_nav_library'.tr(),
|
||||||
|
icon: const Icon(Icons.photo_album_outlined),
|
||||||
|
activeIcon: const Icon(Icons.photo_album_rounded),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final multiselectEnabled = ref.watch(multiselectProvider);
|
final multiselectEnabled = ref.watch(multiselectProvider);
|
||||||
return AutoTabsRouter(
|
return AutoTabsRouter(
|
||||||
routes: [
|
routes: [
|
||||||
@ -32,51 +122,39 @@ class TabControllerPage extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
return atHomeTab;
|
return atHomeTab;
|
||||||
},
|
},
|
||||||
child: Scaffold(
|
child: LayoutBuilder(
|
||||||
body: FadeTransition(
|
builder: (context, constraints) {
|
||||||
opacity: animation,
|
const medium = 600;
|
||||||
child: child,
|
final Widget? bottom;
|
||||||
),
|
final Widget body;
|
||||||
bottomNavigationBar: multiselectEnabled
|
if (constraints.maxWidth < medium) {
|
||||||
? null
|
// Normal phone width
|
||||||
: BottomNavigationBar(
|
bottom = bottomNavigationBar(tabsRouter);
|
||||||
selectedLabelStyle: const TextStyle(
|
body = FadeTransition(
|
||||||
fontSize: 13,
|
opacity: animation,
|
||||||
fontWeight: FontWeight.w600,
|
child: child,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Medium tablet width
|
||||||
|
bottom = null;
|
||||||
|
body = Row(
|
||||||
|
children: [
|
||||||
|
navigationRail(tabsRouter),
|
||||||
|
Expanded(
|
||||||
|
child: FadeTransition(
|
||||||
|
opacity: animation,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
unselectedLabelStyle: const TextStyle(
|
],
|
||||||
fontSize: 13,
|
);
|
||||||
fontWeight: FontWeight.w600,
|
} return Scaffold(
|
||||||
),
|
body: body,
|
||||||
currentIndex: tabsRouter.activeIndex,
|
bottomNavigationBar: multiselectEnabled
|
||||||
onTap: (index) {
|
? null
|
||||||
HapticFeedback.selectionClick();
|
: bottom,
|
||||||
tabsRouter.setActiveIndex(index);
|
);
|
||||||
},
|
},),
|
||||||
items: [
|
|
||||||
BottomNavigationBarItem(
|
|
||||||
label: 'tab_controller_nav_photos'.tr(),
|
|
||||||
icon: const Icon(Icons.photo_outlined),
|
|
||||||
activeIcon: const Icon(Icons.photo),
|
|
||||||
),
|
|
||||||
BottomNavigationBarItem(
|
|
||||||
label: 'tab_controller_nav_search'.tr(),
|
|
||||||
icon: const Icon(Icons.search_rounded),
|
|
||||||
activeIcon: const Icon(Icons.search),
|
|
||||||
),
|
|
||||||
BottomNavigationBarItem(
|
|
||||||
label: 'tab_controller_nav_sharing'.tr(),
|
|
||||||
icon: const Icon(Icons.group_outlined),
|
|
||||||
activeIcon: const Icon(Icons.group),
|
|
||||||
),
|
|
||||||
BottomNavigationBarItem(
|
|
||||||
label: 'tab_controller_nav_library'.tr(),
|
|
||||||
icon: const Icon(Icons.photo_album_outlined),
|
|
||||||
activeIcon: const Icon(Icons.photo_album_rounded),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user