2022-11-30 18:58:07 +02:00
import ' dart:async ' ;
2022-11-06 03:21:55 +02:00
import ' package:auto_route/auto_route.dart ' ;
import ' package:easy_localization/easy_localization.dart ' ;
2022-02-03 18:06:44 +02:00
import ' package:flutter/material.dart ' ;
import ' package:flutter_hooks/flutter_hooks.dart ' ;
2022-11-08 19:00:24 +02:00
import ' package:fluttertoast/fluttertoast.dart ' ;
2022-02-03 18:06:44 +02:00
import ' package:hooks_riverpod/hooks_riverpod.dart ' ;
2022-11-06 03:21:55 +02:00
import ' package:immich_mobile/modules/album/providers/album.provider.dart ' ;
import ' package:immich_mobile/modules/album/services/album.service.dart ' ;
2022-09-28 18:30:38 +02:00
import ' package:immich_mobile/modules/home/providers/home_page_render_list_provider.dart ' ;
2022-10-14 22:37:15 +02:00
import ' package:immich_mobile/modules/home/providers/multiselect.provider.dart ' ;
2022-10-01 10:33:06 +02:00
import ' package:immich_mobile/modules/home/ui/asset_grid/immich_asset_grid.dart ' ;
2022-02-09 20:41:02 +02:00
import ' package:immich_mobile/modules/home/ui/control_bottom_app_bar.dart ' ;
2022-02-03 18:06:44 +02:00
import ' package:immich_mobile/modules/home/ui/immich_sliver_appbar.dart ' ;
2022-08-13 22:51:09 +02:00
import ' package:immich_mobile/modules/home/ui/profile_drawer/profile_drawer.dart ' ;
2022-08-20 23:19:40 +02:00
import ' package:immich_mobile/modules/settings/providers/app_settings.provider.dart ' ;
import ' package:immich_mobile/modules/settings/services/app_settings.service.dart ' ;
2022-11-06 03:21:55 +02:00
import ' package:immich_mobile/routing/router.dart ' ;
2022-11-08 19:00:24 +02:00
import ' package:immich_mobile/shared/models/asset.dart ' ;
2022-04-24 04:08:45 +02:00
import ' package:immich_mobile/shared/providers/asset.provider.dart ' ;
2022-03-22 08:22:04 +02:00
import ' package:immich_mobile/shared/providers/server_info.provider.dart ' ;
2022-02-14 18:40:41 +02:00
import ' package:immich_mobile/shared/providers/websocket.provider.dart ' ;
2022-10-06 22:41:56 +02:00
import ' package:immich_mobile/shared/services/share.service.dart ' ;
2022-11-30 18:58:07 +02:00
import ' package:immich_mobile/shared/ui/immich_loading_indicator.dart ' ;
2022-11-06 03:21:55 +02:00
import ' package:immich_mobile/shared/ui/immich_toast.dart ' ;
2022-10-06 22:41:56 +02:00
import ' package:openapi/api.dart ' ;
2022-02-03 18:06:44 +02:00
class HomePage extends HookConsumerWidget {
const HomePage ( { Key ? key } ) : super ( key: key ) ;
@ override
Widget build ( BuildContext context , WidgetRef ref ) {
2022-08-20 23:19:40 +02:00
final appSettingService = ref . watch ( appSettingsServiceProvider ) ;
2022-09-28 18:30:38 +02:00
var renderList = ref . watch ( renderListProvider ) ;
2022-10-14 22:37:15 +02:00
final multiselectEnabled = ref . watch ( multiselectProvider . notifier ) ;
2022-11-06 03:21:55 +02:00
final selectionEnabledHook = useState ( false ) ;
2022-11-08 19:00:24 +02:00
final selection = useState ( < Asset > { } ) ;
2022-11-06 03:21:55 +02:00
final albums = ref . watch ( albumProvider ) ;
final albumService = ref . watch ( albumServiceProvider ) ;
2022-02-04 06:08:22 +02:00
2022-11-30 18:58:07 +02:00
final tipOneOpacity = useState ( 0.0 ) ;
2022-07-13 14:23:48 +02:00
useEffect (
( ) {
ref . read ( websocketProvider . notifier ) . connect ( ) ;
ref . read ( assetProvider . notifier ) . getAllAsset ( ) ;
2022-11-06 03:21:55 +02:00
ref . read ( albumProvider . notifier ) . getAllAlbums ( ) ;
2022-07-13 14:23:48 +02:00
ref . watch ( serverInfoProvider . notifier ) . getServerVersion ( ) ;
2022-11-06 03:21:55 +02:00
selectionEnabledHook . addListener ( ( ) {
multiselectEnabled . state = selectionEnabledHook . value ;
} ) ;
return ( ) {
selectionEnabledHook . dispose ( ) ;
} ;
2022-07-13 14:23:48 +02:00
} ,
[ ] ,
) ;
2022-02-04 05:01:14 +02:00
2022-04-03 19:31:45 +02:00
void reloadAllAsset ( ) {
ref . read ( assetProvider . notifier ) . getAllAsset ( ) ;
}
2022-10-01 10:33:06 +02:00
Widget buildBody ( ) {
2022-10-06 22:41:56 +02:00
void selectionListener (
2022-10-14 22:37:15 +02:00
bool multiselect ,
2022-11-08 19:00:24 +02:00
Set < Asset > selectedAssets ,
2022-10-14 22:37:15 +02:00
) {
2022-11-06 03:21:55 +02:00
selectionEnabledHook . value = multiselect ;
2022-10-06 22:41:56 +02:00
selection . value = selectedAssets ;
2022-04-30 17:55:27 +02:00
}
2022-10-06 22:41:56 +02:00
void onShareAssets ( ) {
ref . watch ( shareServiceProvider ) . shareAssets ( selection . value . toList ( ) ) ;
2022-11-06 03:21:55 +02:00
selectionEnabledHook . value = false ;
2022-10-06 22:41:56 +02:00
}
void onDelete ( ) {
ref . watch ( assetProvider . notifier ) . deleteAssets ( selection . value ) ;
2022-11-06 03:21:55 +02:00
selectionEnabledHook . value = false ;
}
2022-11-08 19:00:24 +02:00
Iterable < Asset > remoteOnlySelection ( ) {
final Set < Asset > assets = selection . value ;
final bool onlyRemote = assets . every ( ( e ) = > e . isRemote ) ;
if ( ! onlyRemote ) {
ImmichToast . show (
context: context ,
msg: " Can not add local assets to albums yet, skipping " ,
gravity: ToastGravity . BOTTOM ,
) ;
return assets . where ( ( a ) = > a . isRemote ) ;
}
return assets ;
}
2022-11-06 03:21:55 +02:00
void onAddToAlbum ( AlbumResponseDto album ) async {
2022-11-08 19:00:24 +02:00
final Iterable < Asset > assets = remoteOnlySelection ( ) ;
if ( assets . isEmpty ) {
return ;
}
2022-11-06 03:21:55 +02:00
final result = await albumService . addAdditionalAssetToAlbum (
2022-11-08 19:00:24 +02:00
assets ,
2022-11-07 04:41:10 +02:00
album . id ,
) ;
2022-11-06 03:21:55 +02:00
if ( result ! = null ) {
if ( result . alreadyInAlbum . isNotEmpty ) {
ImmichToast . show (
context: context ,
msg: " home_page_add_to_album_conflicts " . tr (
namedArgs: {
" album " : album . albumName ,
" added " : result . successfullyAdded . toString ( ) ,
" failed " : result . alreadyInAlbum . length . toString ( )
} ,
) ,
) ;
} else {
ImmichToast . show (
context: context ,
msg: " home_page_add_to_album_success " . tr (
namedArgs: {
" album " : album . albumName ,
" added " : result . successfullyAdded . toString ( ) ,
} ,
) ,
2022-11-08 19:00:24 +02:00
toastType: ToastType . success ,
2022-11-06 03:21:55 +02:00
) ;
}
selectionEnabledHook . value = false ;
}
}
void onCreateNewAlbum ( ) async {
2022-11-08 19:00:24 +02:00
final Iterable < Asset > assets = remoteOnlySelection ( ) ;
if ( assets . isEmpty ) {
return ;
}
final result = await albumService . createAlbumWithGeneratedName ( assets ) ;
2022-11-06 03:21:55 +02:00
if ( result ! = null ) {
ref . watch ( albumProvider . notifier ) . getAllAlbums ( ) ;
selectionEnabledHook . value = false ;
AutoRouter . of ( context ) . push ( AlbumViewerRoute ( albumId: result . id ) ) ;
}
2022-10-01 19:19:40 +02:00
}
2022-11-30 18:58:07 +02:00
buildLoadingIndicator ( ) {
Timer ( const Duration ( seconds: 2 ) , ( ) {
tipOneOpacity . value = 1 ;
} ) ;
return Center (
child: Column (
mainAxisAlignment: MainAxisAlignment . center ,
children: [
const ImmichLoadingIndicator ( ) ,
Padding (
padding: const EdgeInsets . only ( top: 16.0 ) ,
child: Text (
' Building the timeline ' ,
style: TextStyle (
fontWeight: FontWeight . w600 ,
fontSize: 16 ,
color: Theme . of ( context ) . primaryColor ,
) ,
) ,
) ,
AnimatedOpacity (
duration: const Duration ( milliseconds: 500 ) ,
opacity: tipOneOpacity . value ,
child: const SizedBox (
width: 250 ,
child: Padding (
padding: EdgeInsets . only ( top: 8.0 ) ,
child: Text (
' If this is your first time using the app, please make sure to choose a backup album(s) so that the timeline can populate photos and videos in the album(s). ' ,
textAlign: TextAlign . justify ,
style: TextStyle (
fontSize: 12 ,
) ,
) ,
) ,
) ,
)
] ,
) ,
) ;
}
2022-02-04 06:18:21 +02:00
return SafeArea (
2022-10-14 22:37:15 +02:00
bottom: ! multiselectEnabled . state ,
2022-11-06 03:21:55 +02:00
top: true ,
2022-02-09 20:41:02 +02:00
child: Stack (
children: [
2022-05-01 00:03:45 +02:00
CustomScrollView (
slivers: [
2022-11-06 03:21:55 +02:00
if ( ! multiselectEnabled . state )
2022-11-07 04:41:10 +02:00
ImmichSliverAppBar (
onPopBack: reloadAllAsset ,
) ,
2022-05-01 00:03:45 +02:00
] ,
) ,
Padding (
2022-11-06 03:21:55 +02:00
padding: EdgeInsets . only (
2022-11-07 04:41:10 +02:00
top: selectionEnabledHook . value ? 0 : 60 ,
bottom: 0.0 ,
) ,
2022-11-30 18:58:07 +02:00
child: ref . watch ( assetProvider ) . isEmpty
? buildLoadingIndicator ( )
: ImmichAssetGrid (
renderList: renderList ,
assetsPerRow: appSettingService
. getSetting ( AppSettingsEnum . tilesPerRow ) ,
showStorageIndicator: appSettingService
. getSetting ( AppSettingsEnum . storageIndicator ) ,
listener: selectionListener ,
selectionActive: selectionEnabledHook . value ,
) ,
2022-02-09 20:41:02 +02:00
) ,
2022-11-07 04:41:10 +02:00
if ( selectionEnabledHook . value )
2022-10-06 22:41:56 +02:00
ControlBottomAppBar (
onShare: onShareAssets ,
onDelete: onDelete ,
2022-11-06 03:21:55 +02:00
onAddToAlbum: onAddToAlbum ,
albums: albums ,
onCreateNewAlbum: onCreateNewAlbum ,
2022-10-06 22:41:56 +02:00
) ,
2022-02-09 20:41:02 +02:00
] ,
2022-02-04 06:08:22 +02:00
) ,
2022-02-04 05:01:14 +02:00
) ;
2022-02-03 18:06:44 +02:00
}
return Scaffold (
drawer: const ProfileDrawer ( ) ,
2022-10-01 10:33:06 +02:00
body: buildBody ( ) ,
2022-02-04 06:08:22 +02:00
) ;
}
}