@ -8,6 +8,7 @@ import 'package:animations/animations.dart';
import ' package:flutter_gen/gen_l10n/l10n.dart ' ;
import ' package:flutter_gen/gen_l10n/l10n.dart ' ;
import ' package:keyboard_shortcuts/keyboard_shortcuts.dart ' ;
import ' package:keyboard_shortcuts/keyboard_shortcuts.dart ' ;
import ' package:matrix/matrix.dart ' ;
import ' package:matrix/matrix.dart ' ;
import ' package:snapping_sheet/snapping_sheet.dart ' ;
import ' package:vrouter/vrouter.dart ' ;
import ' package:vrouter/vrouter.dart ' ;
import ' package:fluffychat/config/app_config.dart ' ;
import ' package:fluffychat/config/app_config.dart ' ;
@ -28,203 +29,240 @@ class ChatListView extends StatelessWidget {
@ override
@ override
Widget build ( BuildContext context ) {
Widget build ( BuildContext context ) {
return StreamBuilder < Object ? > (
return StreamBuilder < Object ? > (
stream: Matrix . of ( context ) . onShareContentChanged . stream ,
stream: Matrix . of ( context ) . onShareContentChanged . stream ,
builder: ( _ , __ ) {
builder: ( _ , __ ) {
final selectMode = controller . selectMode ;
final selectMode = controller . selectMode ;
return VWidgetGuard (
final showSpaces =
onSystemPop: ( redirector ) async {
controller . spaces . isNotEmpty & & controller . selectedRoomIds . isEmpty ;
final selMode = controller . selectMode ;
return VWidgetGuard (
if ( selMode ! = SelectMode . normal ) controller . cancelAction ( ) ;
onSystemPop: ( redirector ) async {
if ( selMode = = SelectMode . select ) redirector . stopRedirection ( ) ;
final selMode = controller . selectMode ;
} ,
if ( selMode ! = SelectMode . normal ) controller . cancelAction ( ) ;
child: Scaffold (
if ( selMode = = SelectMode . select ) redirector . stopRedirection ( ) ;
appBar: AppBar (
} ,
elevation: controller . scrolledToTop ? 0 : null ,
child: Scaffold (
actionsIconTheme: IconThemeData (
appBar: AppBar (
color: controller . selectedRoomIds . isEmpty
elevation: controller . scrolledToTop ? 0 : null ,
? null
actionsIconTheme: IconThemeData (
: Theme . of ( context ) . colorScheme . primary ,
color: controller . selectedRoomIds . isEmpty
) ,
leading: Matrix . of ( context ) . isMultiAccount
? ClientChooserButton ( controller )
: selectMode = = SelectMode . normal
? null
: IconButton (
tooltip: L10n . of ( context ) ! . cancel ,
icon: const Icon ( Icons . close_outlined ) ,
onPressed: controller . cancelAction ,
color: Theme . of ( context ) . colorScheme . primary ,
) ,
centerTitle: false ,
actions: selectMode = = SelectMode . share
? null
? null
: selectMode = = SelectMode . select
: Theme . of ( context ) . colorScheme . primary ,
? [
) ,
if ( controller . spaces . isNotEmpty )
leading: Matrix . of ( context ) . isMultiAccount
IconButton (
? ClientChooserButton ( controller )
tooltip: L10n . of ( context ) ! . addToSpace ,
: selectMode = = SelectMode . normal
icon: const Icon ( Icons . group_work_outlined ) ,
? null
onPressed: controller . addOrRemoveToSpace ,
: IconButton (
) ,
tooltip: L10n . of ( context ) ! . cancel ,
IconButton (
icon: const Icon ( Icons . close_outlined ) ,
tooltip: L10n . of ( context ) ! . toggleUnread ,
onPressed: controller . cancelAction ,
icon: Icon (
color: Theme . of ( context ) . colorScheme . primary ,
controller . anySelectedRoomNotMarkedUnread
) ,
? Icons . mark_chat_read_outlined
centerTitle: false ,
: Icons . mark_chat_unread_outlined ) ,
actions: selectMode = = SelectMode . share
onPressed: controller . toggleUnread ,
? null
) ,
: selectMode = = SelectMode . select
? [
if ( controller . spaces . isNotEmpty )
IconButton (
IconButton (
tooltip: L10n . of ( context ) ! . toggleFavorite ,
tooltip: L10n . of ( context ) ! . addToSpace ,
icon: Icon ( controller . anySelectedRoomNotFavorite
icon: const Icon ( Icons . group_work_outlined ) ,
? Icons . push_pin_outlined
onPressed: controller . addOrRemoveToSpace ,
: Icons . push_pin ) ,
onPressed: controller . toggleFavouriteRoom ,
) ,
) ,
IconButton (
IconButton (
icon: Icon ( controller . anySelectedRoomNotMuted
tooltip: L10n . of ( context ) ! . toggleUnread ,
? Icons . notifications_off_outlined
icon: Icon ( controller . anySelectedRoomNotMarkedUnread
: Icons . notifications_outlined ) ,
? Icons . mark_chat_read_outlined
tooltip: L10n . of ( context ) ! . toggleMuted ,
: Icons . mark_chat_unread_outlined ) ,
onPressed: controller . toggleMuted ,
onPressed: controller . toggleUnread ,
) ,
IconButton (
tooltip: L10n . of ( context ) ! . toggleFavorite ,
icon: Icon ( controller . anySelectedRoomNotFavorite
? Icons . push_pin_outlined
: Icons . push_pin ) ,
onPressed: controller . toggleFavouriteRoom ,
) ,
IconButton (
icon: Icon ( controller . anySelectedRoomNotMuted
? Icons . notifications_off_outlined
: Icons . notifications_outlined ) ,
tooltip: L10n . of ( context ) ! . toggleMuted ,
onPressed: controller . toggleMuted ,
) ,
IconButton (
icon: const Icon ( Icons . delete_outlined ) ,
tooltip: L10n . of ( context ) ! . archive ,
onPressed: controller . archiveAction ,
) ,
]
: [
KeyBoardShortcuts (
keysToPress: {
LogicalKeyboardKey . controlLeft ,
LogicalKeyboardKey . keyF
} ,
onKeysPressed: ( ) = >
VRouter . of ( context ) . to ( ' /search ' ) ,
helpLabel: L10n . of ( context ) ! . search ,
child: IconButton (
icon: const Icon ( Icons . search_outlined ) ,
tooltip: L10n . of ( context ) ! . search ,
onPressed: ( ) = >
VRouter . of ( context ) . to ( ' /search ' ) ,
) ,
) ,
) ,
if ( selectMode = = SelectMode . normal )
IconButton (
IconButton (
icon: const Icon ( Icons . delete_outlined ) ,
icon: const Icon ( Icons . camera_alt_outlined ) ,
tooltip: L10n . of ( context ) ! . archive ,
tooltip: L10n . of ( context ) ! . addToStory ,
onPressed: controller . archiveAction ,
onPressed: ( ) = >
VRouter . of ( context ) . to ( ' /stories/create ' ) ,
) ,
) ,
]
PopupMenuButton < PopupMenuAction > (
: [
onSelected: controller . onPopupMenuSelect ,
KeyBoardShortcuts (
itemBuilder: ( _ ) = > [
keysToPress: {
PopupMenuItem (
LogicalKeyboardKey . controlLeft ,
value: PopupMenuAction . setStatus ,
LogicalKeyboardKey . keyF
child: Row (
} ,
mainAxisSize: MainAxisSize . min ,
onKeysPressed: ( ) = >
children: [
VRouter . of ( context ) . to ( ' /search ' ) ,
const Icon ( Icons . edit_outlined ) ,
helpLabel: L10n . of ( context ) ! . search ,
const SizedBox ( width: 12 ) ,
child: IconButton (
Text ( L10n . of ( context ) ! . setStatus ) ,
icon: const Icon ( Icons . search_outlined ) ,
] ,
tooltip: L10n . of ( context ) ! . search ,
onPressed: ( ) = >
VRouter . of ( context ) . to ( ' /search ' ) ,
) ,
) ,
if ( selectMode = = SelectMode . normal )
IconButton (
icon: const Icon ( Icons . camera_alt_outlined ) ,
tooltip: L10n . of ( context ) ! . addToStory ,
onPressed: ( ) = >
VRouter . of ( context ) . to ( ' /stories/create ' ) ,
) ,
PopupMenuButton < PopupMenuAction > (
onSelected: controller . onPopupMenuSelect ,
itemBuilder: ( _ ) = > [
PopupMenuItem (
value: PopupMenuAction . setStatus ,
child: Row (
mainAxisSize: MainAxisSize . min ,
children: [
const Icon ( Icons . edit_outlined ) ,
const SizedBox ( width: 12 ) ,
Text ( L10n . of ( context ) ! . setStatus ) ,
] ,
) ,
) ,
) ,
PopupMenuItem (
) ,
value: PopupMenuAction . newGroup ,
PopupMenuItem (
child: Row (
value: PopupMenuAction . newGroup ,
mainAxisSize: MainAxisSize . min ,
child: Row (
children: [
mainAxisSize: MainAxisSize . min ,
const Icon ( Icons . group_add_outlined ) ,
children: [
const SizedBox ( width: 12 ) ,
const Icon ( Icons . group_add_outlined ) ,
Text ( L10n . of ( context ) ! . createNewGroup ) ,
const SizedBox ( width: 12 ) ,
] ,
Text ( L10n . of ( context ) ! . createNewGroup ) ,
) ,
] ,
) ,
) ,
PopupMenuItem (
) ,
value: PopupMenuAction . newSpace ,
PopupMenuItem (
child: Row (
value: PopupMenuAction . newSpace ,
mainAxisSize: MainAxisSize . min ,
child: Row (
children: [
mainAxisSize: MainAxisSize . min ,
const Icon ( Icons . group_work_outlined ) ,
children: [
const SizedBox ( width: 12 ) ,
const Icon ( Icons . group_work_outlined ) ,
Text ( L10n . of ( context ) ! . createNewSpace ) ,
const SizedBox ( width: 12 ) ,
] ,
Text ( L10n . of ( context ) ! . createNewSpace ) ,
) ,
] ,
) ,
) ,
PopupMenuItem (
) ,
value: PopupMenuAction . invite ,
PopupMenuItem (
child: Row (
value: PopupMenuAction . invite ,
mainAxisSize: MainAxisSize . min ,
child: Row (
children: [
mainAxisSize: MainAxisSize . min ,
const Icon ( Icons . share_outlined ) ,
children: [
const SizedBox ( width: 12 ) ,
const Icon ( Icons . share_outlined ) ,
Text ( L10n . of ( context ) ! . inviteContact ) ,
const SizedBox ( width: 12 ) ,
] ,
Text ( L10n . of ( context ) ! . inviteContact ) ,
) ,
] ,
) ,
) ,
PopupMenuItem (
) ,
value: PopupMenuAction . archive ,
PopupMenuItem (
child: Row (
value: PopupMenuAction . archive ,
mainAxisSize: MainAxisSize . min ,
child: Row (
children: [
mainAxisSize: MainAxisSize . min ,
const Icon ( Icons . archive_outlined ) ,
children: [
const SizedBox ( width: 12 ) ,
const Icon ( Icons . archive_outlined ) ,
Text ( L10n . of ( context ) ! . archive ) ,
const SizedBox ( width: 12 ) ,
] ,
Text ( L10n . of ( context ) ! . archive ) ,
) ,
] ,
) ,
) ,
PopupMenuItem (
) ,
value: PopupMenuAction . settings ,
PopupMenuItem (
child: Row (
value: PopupMenuAction . settings ,
mainAxisSize: MainAxisSize . min ,
child: Row (
children: [
mainAxisSize: MainAxisSize . min ,
const Icon ( Icons . settings_outlined ) ,
children: [
const SizedBox ( width: 12 ) ,
const Icon ( Icons . settings_outlined ) ,
Text ( L10n . of ( context ) ! . settings ) ,
const SizedBox ( width: 12 ) ,
] ,
Text ( L10n . of ( context ) ! . settings ) ,
) ,
] ,
) ,
) ,
] ,
) ,
] ,
) ,
] ,
title: Text ( selectMode = = SelectMode . share
? L10n . of ( context ) ! . share
: selectMode = = SelectMode . select
? controller . selectedRoomIds . length . toString ( )
: controller . activeSpaceId = = null
? AppConfig . applicationName
: Matrix . of ( context )
. client
. getRoomById ( controller . activeSpaceId ! ) !
. displayname ) ,
) ,
body: LayoutBuilder (
builder: ( context , size ) {
controller . snappingSheetContainerSize = size ;
return SnappingSheet (
key: ValueKey ( Matrix . of ( context ) . client . userID . toString ( ) +
showSpaces . toString ( ) ) ,
controller: controller . snappingSheetController ,
child: Column (
children: [
AnimatedContainer (
height: controller . showChatBackupBanner ? 54 : 0 ,
duration: const Duration ( milliseconds: 300 ) ,
clipBehavior: Clip . hardEdge ,
curve: Curves . bounceInOut ,
decoration: const BoxDecoration ( ) ,
child: Material (
color: Theme . of ( context ) . colorScheme . surface ,
child: ListTile (
leading: Image . asset (
' assets/backup.png ' ,
fit: BoxFit . contain ,
width: 44 ,
) ,
) ,
] ,
title: Text ( L10n . of ( context ) ! . setupChatBackupNow ) ,
title: Text ( selectMode = = SelectMode . share
trailing: const Icon ( Icons . chevron_right_outlined ) ,
? L10n . of ( context ) ! . share
onTap: controller . firstRunBootstrapAction ,
: selectMode = = SelectMode . select
) ,
? controller . selectedRoomIds . length . toString ( )
) ,
: controller . activeSpaceId = = null
? AppConfig . applicationName
: Matrix . of ( context )
. client
. getRoomById ( controller . activeSpaceId ! ) !
. displayname ) ,
) ,
body: Column ( children: [
AnimatedContainer (
height: controller . showChatBackupBanner ? 54 : 0 ,
duration: const Duration ( milliseconds: 300 ) ,
clipBehavior: Clip . hardEdge ,
curve: Curves . bounceInOut ,
decoration: const BoxDecoration ( ) ,
child: Material (
color: Theme . of ( context ) . colorScheme . surface ,
child: ListTile (
leading: Image . asset (
' assets/backup.png ' ,
fit: BoxFit . contain ,
width: 44 ,
) ,
) ,
title: Text ( L10n . of ( context ) ! . setupChatBackupNow ) ,
Expanded ( child: _ChatListViewBody ( controller ) ) ,
trailing: const Icon ( Icons . chevron_right_outlined ) ,
] ,
onTap: controller . firstRunBootstrapAction ,
) ,
) ,
) ,
) ,
initialSnappingPosition: showSpaces
Expanded ( child: _ChatListViewBody ( controller ) ) ,
? const SnappingPosition . pixels (
] ) ,
positionPixels: kSpacesBottomBarHeight )
floatingActionButton: selectMode = = SelectMode . normal
: const SnappingPosition . factor ( positionFactor: 0.0 ) ,
? KeyBoardShortcuts (
snappingPositions: showSpaces
? const [
SnappingPosition . pixels (
positionPixels: kSpacesBottomBarHeight ) ,
SnappingPosition . factor ( positionFactor: 0.5 ) ,
SnappingPosition . factor ( positionFactor: 0.9 ) ,
]
: [ const SnappingPosition . factor ( positionFactor: 0.0 ) ] ,
sheetBelow: showSpaces
? SnappingSheetContent (
childScrollController:
controller . snappingSheetScrollContentController ,
draggable: true ,
child: SpacesBottomBar ( controller ) ,
)
: null ,
) ;
} ,
) ,
floatingActionButton: selectMode = = SelectMode . normal
? Padding (
padding: showSpaces
? const EdgeInsets . only ( bottom: 64.0 )
: const EdgeInsets . all ( 0 ) ,
child: KeyBoardShortcuts (
child: FloatingActionButton . extended (
child: FloatingActionButton . extended (
isExtended: controller . scrolledToTop ,
isExtended: controller . scrolledToTop ,
onPressed: ( ) = >
onPressed: ( ) = >
@ -239,20 +277,14 @@ class ChatListView extends StatelessWidget {
onKeysPressed: ( ) = >
onKeysPressed: ( ) = >
VRouter . of ( context ) . to ( ' /newprivatechat ' ) ,
VRouter . of ( context ) . to ( ' /newprivatechat ' ) ,
helpLabel: L10n . of ( context ) ! . newChat ,
helpLabel: L10n . of ( context ) ! . newChat ,
)
) ,
: null ,
)
bottomNavigationBar: Column (
: null ,
mainAxisSize: MainAxisSize . min ,
bottomNavigationBar: const ConnectionStatusHeader ( ) ,
children: [
) ,
const ConnectionStatusHeader ( ) ,
) ;
if ( controller . spaces . isNotEmpty & &
} ,
controller . selectedRoomIds . isEmpty )
) ;
SpacesBottomBar ( controller ) ,
] ,
) ,
) ,
) ;
} ) ;
}
}
}
}