import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:badges/badges.dart'; import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart'; import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pages/chat/chat.dart'; import 'package:fluffychat/pages/chat/chat_app_bar_list_tile.dart'; import 'package:fluffychat/pages/chat/chat_app_bar_title.dart'; import 'package:fluffychat/pages/chat/chat_event_list.dart'; import 'package:fluffychat/pages/chat/pinned_events.dart'; import 'package:fluffychat/pangea/activity_sessions/activity_room_extension.dart'; import 'package:fluffychat/pangea/activity_sessions/activity_session_chat/activity_finished_status_message.dart'; import 'package:fluffychat/pangea/activity_sessions/activity_session_chat/activity_pinned_message.dart'; import 'package:fluffychat/pangea/activity_sessions/activity_session_chat/load_activity_summary_widget.dart'; import 'package:fluffychat/pangea/chat/widgets/chat_input_bar.dart'; import 'package:fluffychat/pangea/chat/widgets/chat_input_bar_header.dart'; import 'package:fluffychat/pangea/chat/widgets/chat_view_background.dart'; import 'package:fluffychat/utils/account_config.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/widgets/future_loading_dialog.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/mxc_image.dart'; import 'package:fluffychat/widgets/unread_rooms_badge.dart'; import '../../utils/stream_extension.dart'; // #Pangea // enum _EventContextAction { info, report } // Pangea# class ChatView extends StatelessWidget { final ChatController controller; const ChatView(this.controller, {super.key}); List _appBarActions(BuildContext context) { // #Pangea // if (controller.selectMode) { // return [ // if (controller.canEditSelectedEvents) // IconButton( // icon: const Icon(Icons.edit_outlined), // tooltip: L10n.of(context).edit, // onPressed: controller.editSelectedEventAction, // ), // IconButton( // icon: const Icon(Icons.copy_outlined), // tooltip: L10n.of(context).copy, // onPressed: controller.copyEventsAction, // ), // if (controller.canPinSelectedEvents) // IconButton( // icon: const Icon(Icons.push_pin_outlined), // onPressed: controller.pinEvent, // tooltip: L10n.of(context).pinMessage, // ), // if (controller.canRedactSelectedEvents) // IconButton( // icon: const Icon(Icons.delete_outlined), // tooltip: L10n.of(context).redactMessage, // onPressed: controller.redactEventsAction, // ), // if (controller.selectedEvents.length == 1) // PopupMenuButton<_EventContextAction>( // useRootNavigator: true, // onSelected: (action) { // switch (action) { // case _EventContextAction.info: // controller.showEventInfo(); // controller.clearSelectedEvents(); // break; // case _EventContextAction.report: // controller.reportEventAction(); // break; // } // }, // itemBuilder: (context) => [ // if (controller.canSaveSelectedEvent) // PopupMenuItem( // onTap: () => controller.saveSelectedEvent(context), // value: null, // child: Row( // mainAxisSize: MainAxisSize.min, // children: [ // const Icon(Icons.download_outlined), // const SizedBox(width: 12), // Text(L10n.of(context).downloadFile), // ], // ), // ), // PopupMenuItem( // value: _EventContextAction.info, // child: Row( // mainAxisSize: MainAxisSize.min, // children: [ // const Icon(Icons.info_outlined), // const SizedBox(width: 12), // Text(L10n.of(context).messageInfo), // ], // ), // ), // if (controller.selectedEvents.single.status.isSent) // PopupMenuItem( // value: _EventContextAction.report, // child: Row( // mainAxisSize: MainAxisSize.min, // children: [ // const Icon( // Icons.shield_outlined, // color: Colors.red, // ), // const SizedBox(width: 12), // Text(L10n.of(context).reportMessage), // ], // ), // ), // ], // ), // ]; // } else // Pangea# if (!controller.room.isArchived) { // #Pangea return [ if (controller.room.activityPlan == null || !controller.room.showActivityChatUI) IconButton( icon: const Icon(Icons.search_outlined), tooltip: L10n.of(context).search, onPressed: () { context.go('/rooms/${controller.room.id}/search'); }, ), IconButton( icon: const Icon(Icons.settings_outlined), tooltip: L10n.of(context).chatDetails, onPressed: () { if (GoRouterState.of(context).uri.path.endsWith('/details')) { context.go('/rooms/${controller.room.id}'); } else { context.go('/rooms/${controller.room.id}/details'); } }, ), ]; // return [ // if (AppConfig.experimentalVoip && // Matrix.of(context).voipPlugin != null && // controller.room.isDirectChat) // IconButton( // onPressed: controller.onPhoneButtonTap, // icon: const Icon(Icons.call_outlined), // tooltip: L10n.of(context).placeCall, // ), // EncryptionButton(controller.room), // ChatSettingsPopupMenu(controller.room, true), // ]; // Pangea# } return []; } @override Widget build(BuildContext context) { final theme = Theme.of(context); if (controller.room.membership == Membership.invite) { showFutureLoadingDialog( context: context, future: () => controller.room.join(), exceptionContext: ExceptionContext.joinRoom, ); } final bottomSheetPadding = FluffyThemes.isColumnMode(context) ? 16.0 : 8.0; final scrollUpBannerEventId = controller.scrollUpBannerEventId; final accountConfig = Matrix.of(context).client.applicationAccountConfig; return PopScope( canPop: controller.selectedEvents.isEmpty && !controller.showEmojiPicker, onPopInvokedWithResult: (pop, _) async { if (pop) return; if (controller.selectedEvents.isNotEmpty) { controller.clearSelectedEvents(); } else if (controller.showEmojiPicker) { controller.emojiPickerAction(); } }, child: StreamBuilder( stream: controller.room.client.onRoomState.stream .where((update) => update.roomId == controller.room.id) .rateLimit(const Duration(seconds: 1)), builder: (context, snapshot) => FutureBuilder( future: controller.loadTimelineFuture, builder: (BuildContext context, snapshot) { var appbarBottomHeight = 0.0; if (controller.room.pinnedEventIds.isNotEmpty) { appbarBottomHeight += ChatAppBarListTile.fixedHeight; } if (scrollUpBannerEventId != null) { appbarBottomHeight += ChatAppBarListTile.fixedHeight; } return Scaffold( appBar: AppBar( // #Pangea // actionsIconTheme: // IconThemeData( // #Pangea // color: controller.selectedEvents.isEmpty // ? null // : theme.colorScheme.onTertiaryContainer, // ), // backgroundColor: controller.selectedEvents.isEmpty // ? null // : theme.colorScheme.tertiaryContainer, // Pangea# automaticallyImplyLeading: false, leading: controller.selectMode ? IconButton( icon: const Icon(Icons.close), onPressed: controller.clearSelectedEvents, tooltip: L10n.of(context).close, color: theme.colorScheme.onTertiaryContainer, ) // #Pangea : controller.widget.backButton != null ? controller.widget.backButton! // Pangea# : FluffyThemes.isColumnMode(context) ? null : StreamBuilder( stream: Matrix.of(context) .client .onSync .stream .where( (syncUpdate) => syncUpdate.hasRoomUpdate, ), builder: (context, _) => UnreadRoomsBadge( filter: (r) => r.id != controller.roomId, badgePosition: BadgePosition.topEnd(end: 8, top: 4), child: const Center(child: BackButton()), ), ), titleSpacing: FluffyThemes.isColumnMode(context) ? 24 : 0, title: ChatAppBarTitle(controller), actions: _appBarActions(context), bottom: PreferredSize( preferredSize: Size.fromHeight(appbarBottomHeight), child: Column( mainAxisSize: MainAxisSize.min, children: [ PinnedEvents(controller), if (scrollUpBannerEventId != null) ChatAppBarListTile( leading: IconButton( color: theme.colorScheme.onSurfaceVariant, icon: const Icon(Icons.close), tooltip: L10n.of(context).close, onPressed: () { controller.discardScrollUpBannerEventId(); controller.setReadMarker(); }, ), title: L10n.of(context).jumpToLastReadMessage, trailing: TextButton( onPressed: () { controller.scrollToEventId( scrollUpBannerEventId, ); controller.discardScrollUpBannerEventId(); }, child: Text(L10n.of(context).jump), ), ), ], ), ), ), // #Pangea // floatingActionButtonLocation: // FloatingActionButtonLocation.miniCenterFloat, // floatingActionButton: controller.showScrollDownButton && // controller.selectedEvents.isEmpty // ? Padding( // padding: const EdgeInsets.only(bottom: 56.0), // child: FloatingActionButton( // onPressed: controller.scrollDown, // heroTag: null, // mini: true, // backgroundColor: theme.colorScheme.surface, // foregroundColor: theme.colorScheme.onSurface, // child: const Icon(Icons.arrow_downward_outlined), // ), // ) // : null, // body: DropTarget( // onDragDone: controller.onDragDone, // onDragEntered: controller.onDragEntered, // onDragExited: controller.onDragExited, // child: Stack( body: Stack( // Pangea# children: [ if (accountConfig.wallpaperUrl != null) Opacity( opacity: accountConfig.wallpaperOpacity ?? 0.5, child: ImageFiltered( imageFilter: ui.ImageFilter.blur( sigmaX: accountConfig.wallpaperBlur ?? 0.0, sigmaY: accountConfig.wallpaperBlur ?? 0.0, ), child: MxcImage( cacheKey: accountConfig.wallpaperUrl.toString(), uri: accountConfig.wallpaperUrl, fit: BoxFit.cover, height: MediaQuery.of(context).size.height, width: MediaQuery.of(context).size.width, isThumbnail: false, placeholder: (_) => Container(), ), ), ), SafeArea( // #Pangea // child: Column( child: Stack( children: [ Column( // Pangea# children: [ Expanded( child: GestureDetector( onTap: controller.clearSingleSelectedEvent, child: ChatEventList(controller: controller), ), ), // #Pangea // if (controller.showScrollDownButton) if (controller.showScrollDownButton && !controller.room.showActivityFinished) // Pangea# Divider( height: 1, color: theme.dividerColor, ), if (controller.room.isExtinct) Container( margin: EdgeInsets.all(bottomSheetPadding), width: double.infinity, child: ElevatedButton.icon( icon: const Icon(Icons.chevron_right), label: Text(L10n.of(context).enterNewChat), onPressed: controller.goToNewRoomAction, ), ) // #Pangea // else if (controller.room.canSendDefaultMessages && // controller.room.membership == Membership.join) else if (controller.room.canSendDefaultMessages && controller.room.membership == Membership.join && !controller.room.showActivityFinished) // Pangea# Container( margin: EdgeInsets.all(bottomSheetPadding), constraints: const BoxConstraints( maxWidth: FluffyThemes.maxTimelineWidth, ), alignment: Alignment.center, child: Material( clipBehavior: Clip.hardEdge, color: controller.selectedEvents.isNotEmpty ? theme.colorScheme.tertiaryContainer : theme.colorScheme.surfaceContainerHigh, borderRadius: const BorderRadius.all( Radius.circular(24), ), child: controller.room.isAbandonedDMRoom == true ? Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ TextButton.icon( style: TextButton.styleFrom( padding: const EdgeInsets.all( 16, ), foregroundColor: theme.colorScheme.error, ), icon: const Icon( Icons.archive_outlined, ), onPressed: controller.leaveChat, label: Text( L10n.of(context).leave, ), ), TextButton.icon( style: TextButton.styleFrom( padding: const EdgeInsets.all( 16, ), ), icon: const Icon( Icons.forum_outlined, ), onPressed: controller.recreateChat, label: Text( L10n.of(context).reopenChat, ), ), ], ) // #Pangea : null, // : Column( // mainAxisSize: MainAxisSize.min, // children: [ // ReplyDisplay(controller), // ChatInputRow(controller), // ChatEmojiPicker(controller), // ], // ), // Pangea# ), ), // #Pangea // Keep messages above minimum input bar height if (!controller.room.isAbandonedDMRoom && controller.room.canSendDefaultMessages && controller.room.membership == Membership.join && (controller.room.activityPlan == null || !controller.room.showActivityChatUI || controller.room.isActiveInActivity)) AnimatedSize( duration: const Duration(milliseconds: 200), child: SizedBox( height: controller.inputBarHeight, ), ), if (controller.room.activityIsFinished) LoadActivitySummaryWidget(room: controller.room), ActivityFinishedStatusMessage( controller: controller, ), // Pangea# ], ), // #Pangea ChatViewBackground(controller.choreographer), if (!controller.room.isAbandonedDMRoom && controller.room.canSendDefaultMessages && controller.room.membership == Membership.join && (controller.room.activityPlan == null || !controller.room.showActivityChatUI || controller.room.isActiveInActivity)) Positioned( left: 0, right: 0, bottom: 16, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ ChatInputBarHeader( controller: controller, padding: bottomSheetPadding, ), ChatInputBar( controller: controller, padding: bottomSheetPadding, ), ], ), ), ActivityPinnedMessage(controller), // Pangea# ], ), ), // #Pangea // if (controller.dragging) // Container( // color: theme.scaffoldBackgroundColor.withAlpha(230), // alignment: Alignment.center, // child: const Icon( // Icons.upload_outlined, // size: 100, // ), // ), // Pangea# ], ), ); }, ), ), ); } }