Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 194 additions & 0 deletions lib/game/game_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
import 'dart:convert';
import 'dart:io' show Socket;
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/shared/widgets/app_scaffold.dart';

final mcServerStatusProvider = FutureProvider.autoDispose<McServerStatus>((
ref,
) async {
const host = '07f4acdef99b.ofalias.net';
const port = 52062;
final socket = await Socket.connect(
host,
port,
timeout: const Duration(seconds: 5),
);
try {
socket.write('LIST\n');
final response = await socket.timeout(const Duration(seconds: 5)).first;
final data = utf8.decode(response).trim();
final parts = data.split('\x00');
if (parts.length >= 2) {
final json = jsonDecode(parts[1]);
final description = json['description'] ?? '';
final players = json['players']?['sample'] as List? ?? [];
return McServerStatus(
online: true,
description: description is Map
? description['text'] ?? ''
: description.toString(),
playerCount: json['players']?['online'] ?? 0,
maxPlayers: json['players']?['max'] ?? 0,
players: players.map((p) => p['name'] as String).toList(),
);
}
throw Exception('Invalid response');
} finally {
await socket.close();
}
});

class McServerStatus {
final bool online;
final String description;
final int playerCount;
final int maxPlayers;
final List<String> players;

McServerStatus({
required this.online,
required this.description,
required this.playerCount,
required this.maxPlayers,
required this.players,
});
}

@RoutePage()
class GameScreen extends ConsumerWidget {
const GameScreen({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
return AppScaffold(
appBar: AppBar(title: Text('game').tr()),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [_ServerStatusCard(), const Gap(16), _BlueMapCard()],
),
),
);
}
}

class _ServerStatusCard extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final statusAsync = ref.watch(mcServerStatusProvider);

return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.dns, color: Theme.of(context).colorScheme.primary),
const Gap(8),
Text(
'mc_server_status',
style: Theme.of(context).textTheme.titleMedium,
).tr(),
],
),
const Gap(12),
statusAsync.when(
data: (status) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
width: 12,
height: 12,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: status.online ? Colors.green : Colors.red,
),
),
const Gap(8),
Text(status.online ? 'online' : 'offline').tr(),
if (status.online) ...[
const Gap(8),
Text('(${status.playerCount}/${status.maxPlayers})'),
],
],
),
if (status.online && status.players.isNotEmpty) ...[
const Gap(12),
Text(
'players_online',
style: Theme.of(context).textTheme.bodySmall,
).tr(),
const Gap(8),
Wrap(
spacing: 8,
runSpacing: 8,
children: status.players.map((player) {
return Chip(
avatar: const Icon(Icons.person, size: 16),
label: Text(player),
);
}).toList(),
),
],
],
),
loading: () => const Center(child: CircularProgressIndicator()),
error: (e, _) => Text(
'server_unavailable',
style: TextStyle(color: Theme.of(context).colorScheme.error),
).tr(),
),
],
),
),
);
}
}

class _BlueMapCard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Icon(Icons.map, color: Theme.of(context).colorScheme.primary),
const Gap(8),
Text(
'bluemap',
style: Theme.of(context).textTheme.titleMedium,
).tr(),
],
),
),
SizedBox(
height: 400,
child: InAppWebView(
initialUrlRequest: URLRequest(
url: WebUri('https://playmc.solsynth.dev/'),
),
initialSettings: InAppWebViewSettings(
mediaPlaybackRequiresUserGesture: true,
allowsInlineMediaPlayback: true,
),
),
),
],
),
);
}
}
10 changes: 10 additions & 0 deletions lib/misc/tabs_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,16 @@ class _TabsScreenContentState extends ConsumerState<_TabsScreenContent> {
);
}),
const Divider(),
ListTile(
leading: const Icon(Symbols.games_rounded),
title: const Text('Game'),
contentPadding: const EdgeInsets.symmetric(horizontal: 28),
onTap: () {
Navigator.of(context).pop();
context.router.push(const GameRoute());
},
),
const Divider(),
ListTile(
leading: const Icon(Symbols.tune_rounded),
title: Text('Customize Navigation'),
Expand Down
114 changes: 91 additions & 23 deletions lib/route.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/route.gr.dart';

bool get supportsAnalytics => kIsWeb || Platform.isAndroid || Platform.isIOS || Platform.isMacOS;
bool get supportsAnalytics =>
kIsWeb || Platform.isAndroid || Platform.isIOS || Platform.isMacOS;

// Provider for the router
final routerProvider = Provider((ref) {
Expand All @@ -14,7 +15,9 @@ final routerProvider = Provider((ref) {
@AutoRouterConfig()
class AppRouter extends RootStackRouter {
@override
RouteType get defaultRouteType => (!kIsWeb && Platform.isIOS) ? RouteType.cupertino() : RouteType.material();
RouteType get defaultRouteType => (!kIsWeb && Platform.isIOS)
? RouteType.cupertino()
: RouteType.material();

@override
List<AutoRoute> get routes => [
Expand All @@ -38,10 +41,16 @@ class AppRouter extends RootStackRouter {
AutoRoute(page: CheckInRoute.page, path: '/check-in'),
AutoRoute(page: PostShuffleRoute.page, path: '/posts/shuffle'),
AutoRoute(page: PostCategoriesListRoute.page, path: '/posts/categories'),
AutoRoute(page: PostCategoryDetailRoute.page, path: '/posts/categories/:slug'),
AutoRoute(
page: PostCategoryDetailRoute.page,
path: '/posts/categories/:slug',
),
AutoRoute(page: PostDetailRoute.page, path: '/posts/:id'),
AutoRoute(page: PublisherProfileRoute.page, path: '/publishers/:name'),
AutoRoute(page: FediverseActorProfileRoute.page, path: '/fediverse/actors/:id'),
AutoRoute(
page: FediverseActorProfileRoute.page,
path: '/fediverse/actors/:id',
),
AutoRoute(page: AccountProfileRoute.page, path: '/accounts/:name'),
AutoRoute(page: UniversalSearchRoute.page, path: '/search'),

Expand All @@ -50,6 +59,7 @@ class AppRouter extends RootStackRouter {
AutoRoute(page: LivestreamWatchRoute.page, path: '/livestreams/:id'),

AutoRoute(page: RealmDetailRoute.page, path: '/realms/:slug'),
AutoRoute(page: GameRoute.page, path: '/game'),

// Main tabs shell route
AutoRoute(
Expand Down Expand Up @@ -90,9 +100,15 @@ class AppRouter extends RootStackRouter {
// Default child route -> Account list
AutoRoute(page: AccountListRoute.page, path: '', initial: true),
AutoRoute(page: StickerMarketplaceRoute.page, path: 'stickers'),
AutoRoute(page: StickerMarketplacePackDetailRoute.page, path: 'stickers/:id'),
AutoRoute(
page: StickerMarketplacePackDetailRoute.page,
path: 'stickers/:id',
),
AutoRoute(page: FeedMarketplaceRoute.page, path: 'feeds'),
AutoRoute(page: FeedMarketplaceDetailRoute.page, path: 'feeds/:feedId'),
AutoRoute(
page: FeedMarketplaceDetailRoute.page,
path: 'feeds/:feedId',
),
AutoRoute(page: WalletRoute.page, path: 'wallet'),
AutoRoute(page: RelationshipRoute.page, path: 'relationships'),
AutoRoute(page: AccountUpdateProfileRoute.page, path: 'me/update'),
Expand All @@ -103,7 +119,10 @@ class AppRouter extends RootStackRouter {
AutoRoute(page: MeetRoute.page, path: 'me/meet'),
AutoRoute(page: MeetDetailRoute.page, path: 'me/meet/:id'),
AutoRoute(page: ActionLogsRoute.page, path: 'me/action-logs'),
AutoRoute(page: PhysicalPassportRoute.page, path: 'me/physical-passports'),
AutoRoute(
page: PhysicalPassportRoute.page,
path: 'me/physical-passports',
),
// Ticket routes
AutoRoute(page: TicketListRoute.page, path: 'tickets'),
AutoRoute(page: TicketDetailRoute.page, path: 'tickets/:ticketId'),
Expand All @@ -114,7 +133,10 @@ class AppRouter extends RootStackRouter {
AutoRoute(page: GoalDetailRoute.page, path: 'fitness/goals/:id'),
AutoRoute(page: GoalCreateRoute.page, path: 'fitness/goals/create'),
AutoRoute(page: MetricsRoute.page, path: 'fitness/metrics'),
AutoRoute(page: MetricDetailRoute.page, path: 'fitness/metrics/:type'),
AutoRoute(
page: MetricDetailRoute.page,
path: 'fitness/metrics/:type',
),
AutoRoute(page: HealthSyncRoute.page, path: 'fitness/sync'),
AutoRoute(page: PunishmentsRoute.page, path: 'me/punishments'),
],
Expand All @@ -134,14 +156,29 @@ class AppRouter extends RootStackRouter {
// Default child route -> Creator hub list
AutoRoute(page: CreatorHubListRoute.page, path: '', initial: true),
AutoRoute(page: CreatorFeedListRoute.page, path: ':pubName/feeds'),
AutoRoute(page: CreatorLivestreamListRoute.page, path: ':pubName/livestreams'),
AutoRoute(
page: CreatorLivestreamListRoute.page,
path: ':pubName/livestreams',
),
AutoRoute(page: CreatorPostListRoute.page, path: ':pubName/posts'),
AutoRoute(page: CreatorPostCollectionsRoute.page, path: ':pubName/collections'),
AutoRoute(
page: CreatorPostCollectionsRoute.page,
path: ':pubName/collections',
),
AutoRoute(page: CreatorPollListRoute.page, path: ':pubName/polls'),
AutoRoute(page: CreatorSiteListRoute.page, path: ':pubName/sites'),
AutoRoute(page: CreatorSiteDetailRoute.page, path: ':pubName/sites/:siteSlug'),
AutoRoute(page: CreatorStickerListRoute.page, path: ':pubName/stickers'),
AutoRoute(page: CreatorStickerPackDetailRoute.page, path: ':pubName/stickers/:packId'),
AutoRoute(
page: CreatorSiteDetailRoute.page,
path: ':pubName/sites/:siteSlug',
),
AutoRoute(
page: CreatorStickerListRoute.page,
path: ':pubName/stickers',
),
AutoRoute(
page: CreatorStickerPackDetailRoute.page,
path: ':pubName/stickers/:packId',
),
],
),

Expand All @@ -151,16 +188,47 @@ class AppRouter extends RootStackRouter {
path: 'developers',
children: [
// Default child route -> Developer hub list
AutoRoute(page: DeveloperHubListRoute.page, path: '', initial: true),
AutoRoute(page: DeveloperProjectNewRoute.page, path: ':pubName/projects/new'),
AutoRoute(page: DeveloperProjectEditRoute.page, path: ':pubName/projects/:id/edit'),
AutoRoute(page: DeveloperAppListRoute.page, path: ':pubName/projects/:projectId'),
AutoRoute(page: DeveloperAppDetailRoute.page, path: ':pubName/projects/:projectId/apps/:appId'),
AutoRoute(page: DeveloperAppNewRoute.page, path: ':pubName/projects/:projectId/apps/new'),
AutoRoute(page: DeveloperAppEditRoute.page, path: ':pubName/projects/:projectId/apps/:appId/edit'),
AutoRoute(page: DeveloperBotDetailRoute.page, path: ':pubName/projects/:projectId/bots/:botId'),
AutoRoute(page: DeveloperBotNewRoute.page, path: ':pubName/projects/:projectId/bots/new'),
AutoRoute(page: DeveloperBotEditRoute.page, path: ':pubName/projects/:projectId/bots/:botId/edit'),
AutoRoute(
page: DeveloperHubListRoute.page,
path: '',
initial: true,
),
AutoRoute(
page: DeveloperProjectNewRoute.page,
path: ':pubName/projects/new',
),
AutoRoute(
page: DeveloperProjectEditRoute.page,
path: ':pubName/projects/:id/edit',
),
AutoRoute(
page: DeveloperAppListRoute.page,
path: ':pubName/projects/:projectId',
),
AutoRoute(
page: DeveloperAppDetailRoute.page,
path: ':pubName/projects/:projectId/apps/:appId',
),
AutoRoute(
page: DeveloperAppNewRoute.page,
path: ':pubName/projects/:projectId/apps/new',
),
AutoRoute(
page: DeveloperAppEditRoute.page,
path: ':pubName/projects/:projectId/apps/:appId/edit',
),
AutoRoute(
page: DeveloperBotDetailRoute.page,
path: ':pubName/projects/:projectId/bots/:botId',
),
AutoRoute(
page: DeveloperBotNewRoute.page,
path: ':pubName/projects/:projectId/bots/new',
),
AutoRoute(
page: DeveloperBotEditRoute.page,
path: ':pubName/projects/:projectId/bots/:botId/edit',
),
],
),
],
Expand Down
Loading
Loading