192 lines
5.5 KiB
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),
|
|
],
|
|
);
|
|
}
|
|
}
|