diff --git a/lib/pages/chat_list/navi_rail_item.dart b/lib/pages/chat_list/navi_rail_item.dart index 8e8722dc0..177985464 100644 --- a/lib/pages/chat_list/navi_rail_item.dart +++ b/lib/pages/chat_list/navi_rail_item.dart @@ -17,6 +17,7 @@ class NaviRailItem extends StatelessWidget { // #Pangea final Color? backgroundColor; final BorderRadius? borderRadius; + final bool expanded; // Pangea# const NaviRailItem({ @@ -29,6 +30,7 @@ class NaviRailItem extends StatelessWidget { // #Pangea this.backgroundColor, this.borderRadius, + this.expanded = false, // Pangea# super.key, }); @@ -52,91 +54,118 @@ class NaviRailItem extends StatelessWidget { // #Pangea // return SizedBox( // height: 72, - return SizedBox( - height: width - (isColumnMode ? 16.0 : 12.0), - width: width, - // width: FluffyThemes.navRailWidth, - // Pangea# - child: Stack( - children: [ - Positioned( - top: 8, - bottom: 8, - left: 0, - child: AnimatedContainer( - width: isSelected - ? FluffyThemes.isColumnMode(context) - ? 8 - : 4 - : 0, - duration: FluffyThemes.animationDuration, - curve: FluffyThemes.animationCurve, - decoration: BoxDecoration( - color: theme.colorScheme.primary, - borderRadius: const BorderRadius.only( - topRight: Radius.circular(90), - bottomRight: Radius.circular(90), - ), - ), - ), - ), - Center( - child: AnimatedScale( - scale: hovered ? 1.1 : 1.0, - duration: FluffyThemes.animationDuration, - curve: FluffyThemes.animationCurve, - // #Pangea - // child: Material( - // borderRadius: borderRadius, - // color: isSelected - // ? theme.colorScheme.primaryContainer - // : theme.colorScheme.surfaceContainerHigh, - child: UnreadRoomsBadge( - filter: unreadBadgeFilter ?? (_) => false, - badgePosition: BadgePosition.topEnd( - top: 1, - end: isColumnMode ? 8 : 4, - ), - child: Container( - alignment: Alignment.center, + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + SizedBox( + height: width - (isColumnMode ? 16.0 : 12.0), + width: width, + // width: FluffyThemes.navRailWidth, + // Pangea# + child: Stack( + children: [ + Positioned( + top: 8, + bottom: 8, + left: 0, + child: AnimatedContainer( + width: isSelected + ? FluffyThemes.isColumnMode(context) + ? 8 + : 4 + : 0, + duration: FluffyThemes.animationDuration, + curve: FluffyThemes.animationCurve, decoration: BoxDecoration( - color: backgroundColor ?? - (isSelected - ? theme.colorScheme.primaryContainer - : theme.colorScheme.surfaceContainerHigh), - borderRadius: borderRadius, - ), - margin: EdgeInsets.symmetric( - horizontal: isColumnMode ? 16.0 : 12.0, - vertical: isColumnMode ? 8.0 : 6.0, - ), - // Pangea# - child: Tooltip( - message: toolTip, - child: InkWell( - borderRadius: borderRadius, - onTap: onTap, - // #Pangea - child: icon, - // child: unreadBadgeFilter == null - // ? icon - // : UnreadRoomsBadge( - // filter: unreadBadgeFilter, - // badgePosition: BadgePosition.topEnd( - // top: -12, - // end: -8, - // ), - // child: icon, - // ), - // Pangea# + color: theme.colorScheme.primary, + borderRadius: const BorderRadius.only( + topRight: Radius.circular(90), + bottomRight: Radius.circular(90), ), ), ), ), + Center( + child: AnimatedScale( + scale: hovered ? 1.1 : 1.0, + duration: FluffyThemes.animationDuration, + curve: FluffyThemes.animationCurve, + // #Pangea + // child: Material( + // borderRadius: borderRadius, + // color: isSelected + // ? theme.colorScheme.primaryContainer + // : theme.colorScheme.surfaceContainerHigh, + child: UnreadRoomsBadge( + filter: unreadBadgeFilter ?? (_) => false, + badgePosition: BadgePosition.topEnd( + top: 1, + end: isColumnMode ? 8 : 4, + ), + child: Container( + alignment: Alignment.center, + decoration: BoxDecoration( + color: backgroundColor ?? + (isSelected + ? theme.colorScheme.primaryContainer + : theme.colorScheme.surfaceContainerHigh), + borderRadius: borderRadius, + ), + margin: EdgeInsets.symmetric( + horizontal: isColumnMode ? 16.0 : 12.0, + vertical: isColumnMode ? 8.0 : 6.0, + ), + // Pangea# + child: Tooltip( + message: toolTip, + child: InkWell( + borderRadius: borderRadius, + onTap: onTap, + // #Pangea + child: icon, + // child: unreadBadgeFilter == null + // ? icon + // : UnreadRoomsBadge( + // filter: unreadBadgeFilter, + // badgePosition: BadgePosition.topEnd( + // top: -12, + // end: -8, + // ), + // child: icon, + // ), + // Pangea# + ), + ), + ), + ), + ), + ), + ], + ), + ), + if (expanded) + Flexible( + child: Padding( + padding: const EdgeInsets.only(right: 16.0), + child: ListTile( + title: Text( + toolTip, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: theme.textTheme.bodyMedium, + ), + onTap: onTap, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.0), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 8.0, + vertical: 0.0, + ), + ), ), ), - ], - ), + ], ); }, ); diff --git a/lib/pangea/spaces/space_navigation_column.dart b/lib/pangea/spaces/space_navigation_column.dart new file mode 100644 index 000000000..a8dbed70e --- /dev/null +++ b/lib/pangea/spaces/space_navigation_column.dart @@ -0,0 +1,180 @@ +import 'package:flutter/material.dart'; + +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:go_router/go_router.dart'; + +import 'package:fluffychat/config/app_config.dart'; +import 'package:fluffychat/config/themes.dart'; +import 'package:fluffychat/pages/chat_list/chat_list.dart'; +import 'package:fluffychat/pages/settings/settings.dart'; +import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup.dart'; +import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart'; +import 'package:fluffychat/pangea/analytics_page/activity_archive.dart'; +import 'package:fluffychat/pangea/analytics_summary/level_analytics_details_content.dart'; +import 'package:fluffychat/pangea/spaces/space_constants.dart'; +import 'package:fluffychat/widgets/hover_builder.dart'; +import 'package:fluffychat/widgets/navigation_rail.dart'; + +class SpaceNavigationColumn extends StatefulWidget { + final GoRouterState state; + const SpaceNavigationColumn({ + required this.state, + super.key, + }); + + @override + State createState() => SpaceNavigationColumnState(); +} + +class SpaceNavigationColumnState extends State { + bool _expand = false; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final isColumnMode = FluffyThemes.isColumnMode(context); + bool showNavRail = isColumnMode; + if (!showNavRail) { + final roomID = widget.state.pathParameters['roomid']; + final spaceID = widget.state.pathParameters['spaceid']; + + if (roomID == null && spaceID == null) { + showNavRail = !["newcourse", ":construct"].any( + (p) => widget.state.fullPath?.contains(p) ?? false, + ); + } else if (roomID == null) { + showNavRail = widget.state.fullPath?.endsWith(':spaceid') == true; + } + } + + final navRailWidth = isColumnMode + ? FluffyThemes.navRailWidth + : FluffyThemes.navRailWidth - 8.0; + + final double navRailExtraWidth = showNavRail ? 250.0 : 0.0; + final double columnWidth = + isColumnMode ? FluffyThemes.columnWidth + 1.0 : 0; + + final double railWidth = showNavRail ? navRailWidth + 1.0 : 0; + final double baseWidth = columnWidth + railWidth; + final double expandedWidth = baseWidth < navRailExtraWidth + ? navRailExtraWidth + railWidth + : baseWidth; + + return AnimatedContainer( + duration: FluffyThemes.animationDuration, + width: _expand ? expandedWidth : baseWidth, + child: Stack( + children: [ + if (isColumnMode) + Positioned( + left: navRailWidth + 1.0, + child: SizedBox( + height: MediaQuery.heightOf(context), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + clipBehavior: Clip.antiAlias, + decoration: const BoxDecoration(), + width: FluffyThemes.columnWidth, + child: _MainView(state: widget.state), + ), + Container( + width: 1.0, + color: theme.dividerColor, + ), + ], + ), + ), + ), + if (showNavRail) + HoverBuilder( + builder: (context, hovered) { + if (_expand != hovered) { + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + _expand = hovered; + }); + }); + } + + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + SpacesNavigationRail( + activeSpaceId: widget.state.pathParameters['spaceid'], + path: widget.state.fullPath, + railWidth: _expand + ? navRailWidth + navRailExtraWidth + : navRailWidth, + expanded: _expand, + ), + Container( + width: 1, + color: Theme.of(context).dividerColor, + ), + ], + ); + }, + ), + ], + ), + ); + } +} + +class _MainView extends StatelessWidget { + final GoRouterState state; + + const _MainView({ + required this.state, + }); + + @override + Widget build(BuildContext context) { + final path = state.fullPath; + if (path == null) { + return ChatList( + activeChat: state.pathParameters['roomid'], + activeSpaceId: state.pathParameters['spaceid'], + ); + } + + if (path.contains("analytics")) { + if (path.contains("analytics/level")) { + return const LevelAnalyticsDetailsContent(); + } else if (path.contains("analytics/activities")) { + return const ActivityArchive(); + } else if (path.contains("analytics/${ConstructTypeEnum.morph.string}")) { + return const ConstructAnalyticsView(view: ConstructTypeEnum.morph); + } + return const ConstructAnalyticsView(view: ConstructTypeEnum.vocab); + } + + if (path.contains("settings")) { + return Settings(key: state.pageKey); + } + + if (path.contains('course')) { + return Center( + child: SizedBox( + width: 250.0, + child: CachedNetworkImage( + imageUrl: + "${AppConfig.assetsBaseURL}/${SpaceConstants.sideBearFileName}", + errorWidget: (context, url, error) => const SizedBox(), + placeholder: (context, url) => const Center( + child: CircularProgressIndicator.adaptive(), + ), + ), + ), + ); + } + + return ChatList( + activeChat: state.pathParameters['roomid'], + activeSpaceId: state.pathParameters['spaceid'], + ); + } +} diff --git a/lib/widgets/layouts/two_column_layout.dart b/lib/widgets/layouts/two_column_layout.dart index 6d9f3fc95..0fda63949 100644 --- a/lib/widgets/layouts/two_column_layout.dart +++ b/lib/widgets/layouts/two_column_layout.dart @@ -1,18 +1,8 @@ import 'package:flutter/material.dart'; -import 'package:cached_network_image/cached_network_image.dart'; import 'package:go_router/go_router.dart'; -import 'package:fluffychat/config/app_config.dart'; -import 'package:fluffychat/config/themes.dart'; -import 'package:fluffychat/pages/chat_list/chat_list.dart'; -import 'package:fluffychat/pages/settings/settings.dart'; -import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup.dart'; -import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart'; -import 'package:fluffychat/pangea/analytics_page/activity_archive.dart'; -import 'package:fluffychat/pangea/analytics_summary/level_analytics_details_content.dart'; -import 'package:fluffychat/pangea/spaces/space_constants.dart'; -import 'package:fluffychat/widgets/navigation_rail.dart'; +import 'package:fluffychat/pangea/spaces/space_navigation_column.dart'; class TwoColumnLayout extends StatelessWidget { // #Pangea @@ -31,123 +21,27 @@ class TwoColumnLayout extends StatelessWidget { }); @override Widget build(BuildContext context) { - final theme = Theme.of(context); - // #Pangea - bool showNavRail = FluffyThemes.isColumnMode(context); - if (!showNavRail) { - final roomID = state.pathParameters['roomid']; - final spaceID = state.pathParameters['spaceid']; - - if (roomID == null && spaceID == null) { - showNavRail = !["newcourse", ":construct"].any( - (p) => state.fullPath?.contains(p) ?? false, - ); - } else if (roomID == null) { - showNavRail = state.fullPath?.endsWith(':spaceid') == true; - } - } + // final theme = Theme.of(context); // Pangea# - return ScaffoldMessenger( child: Scaffold( body: Row( children: [ // #Pangea - if (showNavRail) ...[ - SpacesNavigationRail( - activeSpaceId: state.pathParameters['spaceid'], - path: state.fullPath, - ), - Container( - color: Theme.of(context).dividerColor, - width: 1, - ), - ], - if (FluffyThemes.isColumnMode(context)) ...[ - // Pangea# - Container( - clipBehavior: Clip.antiAlias, - decoration: const BoxDecoration(), - // #Pangea - // width: FluffyThemes.columnWidth + FluffyThemes.navRailWidth, - // child: mainView, - width: FluffyThemes.columnWidth, - child: _MainView(state: state), - // Pangea# - ), - Container( - width: 1.0, - color: theme.dividerColor, - ), - // Pangea# - ], + SpaceNavigationColumn(state: state), + // Container( + // clipBehavior: Clip.antiAlias, + // decoration: const BoxDecoration(), + // width: FluffyThemes.columnWidth + FluffyThemes.navRailWidth, + // child: mainView, + // ), + // Container(width: 1.0, color: theme.dividerColor), // Pangea# - Expanded( - child: ClipRRect( - child: sideView, - ), - ), + Expanded(child: ClipRRect(child: sideView)), ], ), ), ); } } - -// #Pangea -class _MainView extends StatelessWidget { - final GoRouterState state; - - const _MainView({ - required this.state, - }); - - @override - Widget build(BuildContext context) { - final path = state.fullPath; - if (path == null) { - return ChatList( - activeChat: state.pathParameters['roomid'], - activeSpaceId: state.pathParameters['spaceid'], - ); - } - - if (path.contains("analytics")) { - if (path.contains("analytics/level")) { - return const LevelAnalyticsDetailsContent(); - } else if (path.contains("analytics/activities")) { - return const ActivityArchive(); - } else if (path.contains("analytics/${ConstructTypeEnum.morph.string}")) { - return const ConstructAnalyticsView(view: ConstructTypeEnum.morph); - } - return const ConstructAnalyticsView(view: ConstructTypeEnum.vocab); - } - - if (path.contains("settings")) { - return Settings(key: state.pageKey); - } - - if (path.contains('course')) { - return Center( - child: SizedBox( - width: 250.0, - child: CachedNetworkImage( - imageUrl: - "${AppConfig.assetsBaseURL}/${SpaceConstants.sideBearFileName}", - errorWidget: (context, url, error) => const SizedBox(), - placeholder: (context, url) => const Center( - child: CircularProgressIndicator.adaptive(), - ), - ), - ), - ); - } - - return ChatList( - activeChat: state.pathParameters['roomid'], - activeSpaceId: state.pathParameters['spaceid'], - ); - } -} -// Pangea# diff --git a/lib/widgets/navigation_rail.dart b/lib/widgets/navigation_rail.dart index 650d7dcdf..7c6b887eb 100644 --- a/lib/widgets/navigation_rail.dart +++ b/lib/widgets/navigation_rail.dart @@ -22,6 +22,8 @@ class SpacesNavigationRail extends StatelessWidget { // final void Function() onGoToChats; // final void Function(String) onGoToSpaceId; final String? path; + final double railWidth; + final bool expanded; // Pangea# const SpacesNavigationRail({ @@ -30,6 +32,8 @@ class SpacesNavigationRail extends StatelessWidget { // required this.onGoToChats, // required this.onGoToSpaceId, required this.path, + required this.railWidth, + this.expanded = false, // Pangea# super.key, }); @@ -73,10 +77,12 @@ class SpacesNavigationRail extends StatelessWidget { ) .toList(); - return SizedBox( - // #Pangea + // #Pangea + // return SizedBox( + return AnimatedContainer( // width: FluffyThemes.navRailWidth, - width: width, + width: railWidth, + duration: FluffyThemes.animationDuration, // Pangea# child: Column( children: [ @@ -118,6 +124,9 @@ class SpacesNavigationRail extends StatelessWidget { ), ), toolTip: L10n.of(context).home, + // #Pangea + expanded: expanded, + // Pangea# ); } i--; @@ -147,6 +156,7 @@ class SpacesNavigationRail extends StatelessWidget { toolTip: L10n.of(context).directMessages, unreadBadgeFilter: (room) => room.firstSpaceParent == null, + expanded: expanded, // Pangea# ); } @@ -183,6 +193,7 @@ class SpacesNavigationRail extends StatelessWidget { ), ), toolTip: L10n.of(context).addCourse, + expanded: expanded, // Pangea# ); } @@ -260,6 +271,7 @@ class SpacesNavigationRail extends StatelessWidget { ), ), ), + expanded: expanded, // Pangea# ); }, @@ -279,6 +291,7 @@ class SpacesNavigationRail extends StatelessWidget { // ), icon: const Icon(Icons.settings_outlined), selectedIcon: const Icon(Icons.settings), + expanded: expanded, // Pangea# toolTip: L10n.of(context).settings, ),