import "dart:async"; import "package:bus_running_record/models/channels/base_channel.dart"; import "package:bus_running_record/models/channels/operations_channel.dart"; import "package:bus_running_record/models/channels/text_channel.dart"; import "package:bus_running_record/pages/home/channels/operations_channel_view.dart"; import "package:bus_running_record/pages/home/channels/text_channel_view.dart"; import "package:bus_running_record/pages/home/widgets/swiper.dart"; import "package:bus_running_record/pages/home/widgets/channel_header.dart"; import "package:bus_running_record/pages/home/widgets/home_left_sidebar.dart"; import "package:bus_running_record/provider/collaboration_state.dart"; import "package:bus_running_record/provider/supabase_state.dart"; import "package:go_router/go_router.dart"; import "package:provider/provider.dart"; import "package:shadcn_flutter/shadcn_flutter.dart"; class HomePage extends StatefulWidget { static GoRoute rootRoute = GoRoute( path: "/", builder: (context, state) => const HomePage(), ); static GoRoute channelRoute = GoRoute( path: "/channel/:orgId/:channelId", builder: (context, state) => HomePage( organizationId: state.pathParameters["orgId"], channelId: state.pathParameters["channelId"], ), ); const HomePage({this.organizationId, this.channelId, super.key}); final String? organizationId; final String? channelId; @override State createState() => _HomePageState(); } class _HomePageState extends State { String? _lastSyncedRouteKey; Future _syncRouteSelection() async { final orgId = widget.organizationId; final channelId = widget.channelId; if (orgId == null || channelId == null) return; final routeKey = "$orgId/$channelId"; if (_lastSyncedRouteKey == routeKey) return; _lastSyncedRouteKey = routeKey; final collab = context.read(); if (collab.selectedOrganizationId != orgId) { await collab.selectOrganization(orgId); } final channels = collab.channelsForOrganization(orgId); if (channels.any((channel) => channel.id == channelId)) { collab.selectChannel(channelId); } } @override Widget build(BuildContext context) { if (widget.organizationId != null && widget.channelId != null) { WidgetsBinding.instance.addPostFrameCallback((_) { if (!mounted) return; unawaited(_syncRouteSelection()); }); } else { _lastSyncedRouteKey = null; } final isMobile = MediaQuery.of(context).size.width < 600; if (isMobile) { return const SidebarSwiper( sidebar: HomeLeftSidebar(), child: Scaffold( child: Row(children: [Expanded(child: _HomeChannelPane())]), ), ); } return const Scaffold( child: Row( children: [ HomeLeftSidebar(), VerticalDivider(), Expanded(child: _HomeChannelPane()), ], ), ); } } class _HomeChannelPane extends StatelessWidget { const _HomeChannelPane(); ChannelSummary? _findChannel( CollaborationProvider collab, String? organizationId, String? channelId, ) { if (organizationId == null || channelId == null) return null; final channels = collab.channelsForOrganization(organizationId); for (final channel in channels) { if (channel.id == channelId) { return channel; } } return null; } BaseChannel? _buildChannelModel( BuildContext context, ChannelSummary? selectedChannel, ) { if (selectedChannel == null) return null; final client = context.read().client; if (selectedChannel.type == "operations") { return OperationsChannel( client: client, id: selectedChannel.id, organizationId: selectedChannel.organizationId, name: selectedChannel.name, description: selectedChannel.description, slug: selectedChannel.slug, isPrivate: selectedChannel.isPrivate, position: selectedChannel.position, ); } return TextChannel( client: client, id: selectedChannel.id, organizationId: selectedChannel.organizationId, name: selectedChannel.name, description: selectedChannel.description, slug: selectedChannel.slug, isPrivate: selectedChannel.isPrivate, position: selectedChannel.position, ); } Widget _buildChannelContent({ required BaseChannel? channel, }) { if (channel == null) { return Center( child: Text("Pick a channel to start chatting.").small.muted, ); } if (channel is OperationsChannel) { return OperationsChannelView(channel: channel); } final textChannel = channel as TextChannel; return TextChannelView( key: ValueKey("text-channel-${textChannel.id}"), channel: textChannel, ); } @override Widget build(BuildContext context) { final collab = context.watch(); final selectedOrg = collab.selectedOrganizationId; final selectedChannelId = collab.selectedChannelId; final selectedChannel = _findChannel( collab, selectedOrg, selectedChannelId, ); final channel = _buildChannelModel(context, selectedChannel); final channelBody = _buildChannelContent( channel: channel, ); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (channel != null) ...[ ChannelHeader(channel: channel), ], Expanded(child: channelBody), ], ); } }