Roadbound-BRR/lib/pages/home/page.dart

192 lines
5.5 KiB
Dart

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<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
String? _lastSyncedRouteKey;
Future<void> _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<CollaborationProvider>();
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<SupabaseProvider>().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<CollaborationProvider>();
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),
],
);
}
}