💄 Redesign the network status sheet
This commit is contained in:
@@ -143,6 +143,7 @@
|
|||||||
"connectionConnected": "Connected",
|
"connectionConnected": "Connected",
|
||||||
"connectionDisconnected": "Disconnected",
|
"connectionDisconnected": "Disconnected",
|
||||||
"connectionReconnecting": "Reconnecting",
|
"connectionReconnecting": "Reconnecting",
|
||||||
|
"connectionServerDown": "Unable to Connect",
|
||||||
"accountConnections": "Account Connections",
|
"accountConnections": "Account Connections",
|
||||||
"accountConnectionsDescription": "Manage your external account connections",
|
"accountConnectionsDescription": "Manage your external account connections",
|
||||||
"accountConnectionAdd": "Add Connection",
|
"accountConnectionAdd": "Add Connection",
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ class AppWrapper extends HookConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final networkStateShowing = useState(false);
|
final networkStateShowing = useState(false);
|
||||||
final wsNotifier = ref.watch(websocketStateProvider.notifier);
|
|
||||||
final websocketState = ref.watch(websocketStateProvider);
|
final websocketState = ref.watch(websocketStateProvider);
|
||||||
final isShowSnow = useState(false);
|
final isShowSnow = useState(false);
|
||||||
final isSnowGone = useState(false);
|
final isSnowGone = useState(false);
|
||||||
@@ -47,8 +46,7 @@ class AppWrapper extends HookConsumerWidget {
|
|||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
isDismissible: false,
|
isDismissible: false,
|
||||||
builder: (context) =>
|
builder: (context) => NetworkStatusSheet(autoClose: true),
|
||||||
NetworkStatusSheet(onReconnect: () => wsNotifier.connect()),
|
|
||||||
).then((_) => networkStateShowing.value = false);
|
).then((_) => networkStateShowing.value = false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,78 +1,117 @@
|
|||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/pods/websocket.dart';
|
import 'package:island/pods/websocket.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:island/widgets/content/sheet.dart';
|
import 'package:island/widgets/content/sheet.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
class NetworkStatusSheet extends HookConsumerWidget {
|
class NetworkStatusSheet extends HookConsumerWidget {
|
||||||
final VoidCallback onReconnect;
|
final bool autoClose;
|
||||||
|
const NetworkStatusSheet({super.key, this.autoClose = false});
|
||||||
const NetworkStatusSheet({super.key, required this.onReconnect});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final ws = ref.watch(websocketProvider);
|
final ws = ref.watch(websocketProvider);
|
||||||
final wsState = ref.watch(websocketStateProvider);
|
final wsState = ref.watch(websocketStateProvider);
|
||||||
|
|
||||||
|
final wsNotifier = ref.watch(websocketStateProvider.notifier);
|
||||||
|
|
||||||
|
useEffect(() {
|
||||||
|
if (!autoClose) return;
|
||||||
|
|
||||||
|
final checks = [wsState == WebSocketState.connected()];
|
||||||
|
if (!checks.any((e) => !e)) {
|
||||||
|
Future.delayed(Duration(seconds: 3), () {
|
||||||
|
if (context.mounted) Navigator.of(context).pop();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}, [wsState]);
|
||||||
|
|
||||||
return SheetScaffold(
|
return SheetScaffold(
|
||||||
heightFactor: 0.4,
|
heightFactor: 0.6,
|
||||||
titleText:
|
titleText: wsState == WebSocketState.connected()
|
||||||
wsState == WebSocketState.connected()
|
? 'Connection Status'
|
||||||
? 'Connection Status'
|
: 'Connection Issue',
|
||||||
: 'Connection Issue',
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
wsState.when(
|
Row(
|
||||||
connected:
|
spacing: 8,
|
||||||
() => Text(
|
children: [
|
||||||
'Connected to server',
|
Text('WebSocket').bold(),
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
wsState.when(
|
||||||
),
|
connected: () => Text('connectionConnected').tr(),
|
||||||
connecting:
|
connecting: () => Text('connectionReconnecting').tr(),
|
||||||
() => Text(
|
disconnected: () => Text('connectionDisconnected').tr(),
|
||||||
'Connecting to server...',
|
serverDown: () => Text('connectionServerDown').tr(),
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
duplicateDevice: () => Text(
|
||||||
),
|
|
||||||
disconnected:
|
|
||||||
() => Text(
|
|
||||||
'Disconnected from server',
|
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
|
||||||
),
|
|
||||||
serverDown:
|
|
||||||
() => Text(
|
|
||||||
'The server is not available right now... Please try again later...',
|
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
|
||||||
),
|
|
||||||
duplicateDevice:
|
|
||||||
() => Text(
|
|
||||||
'Another device has connected with the same account.',
|
'Another device has connected with the same account.',
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
|
||||||
),
|
),
|
||||||
error:
|
error: (message) => Text('Connection error: $message'),
|
||||||
(message) => Text(
|
),
|
||||||
'Connection error: $message',
|
if (ws.heartbeatDelay != null)
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
Text('${ws.heartbeatDelay!.inMilliseconds}ms'),
|
||||||
|
AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
child: wsState.when(
|
||||||
|
connected: () => Icon(
|
||||||
|
Symbols.check_circle,
|
||||||
|
key: ValueKey(WebSocketState.connected),
|
||||||
|
color: Colors.green,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
connecting: () => Icon(
|
||||||
|
Symbols.sync,
|
||||||
|
key: ValueKey(WebSocketState.connecting),
|
||||||
|
color: Colors.orange,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
disconnected: () => Icon(
|
||||||
|
Symbols.wifi_off,
|
||||||
|
key: ValueKey(WebSocketState.disconnected),
|
||||||
|
color: Colors.grey,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
serverDown: () => Icon(
|
||||||
|
Symbols.cloud_off,
|
||||||
|
key: ValueKey(WebSocketState.serverDown),
|
||||||
|
color: Colors.red,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
duplicateDevice: () => Icon(
|
||||||
|
Symbols.devices,
|
||||||
|
key: ValueKey(WebSocketState.duplicateDevice),
|
||||||
|
color: Colors.orange,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
error: (message) => Icon(
|
||||||
|
Symbols.error,
|
||||||
|
key: ValueKey(WebSocketState.error),
|
||||||
|
color: Colors.red,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
Row(
|
||||||
if (ws.heartbeatDelay != null)
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
Text(
|
spacing: 8,
|
||||||
'Last heartbeat: ${ws.heartbeatDelay!.inMilliseconds}ms',
|
children: [
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
FilledButton.icon(
|
||||||
),
|
icon: const Icon(Symbols.wifi),
|
||||||
const SizedBox(height: 24),
|
label: const Text('Reconnect'),
|
||||||
Center(
|
onPressed: () {
|
||||||
child: FilledButton.icon(
|
wsNotifier.manualReconnect();
|
||||||
icon: const Icon(Symbols.wifi),
|
},
|
||||||
label: const Text('Reconnect'),
|
),
|
||||||
onPressed: () {
|
],
|
||||||
onReconnect();
|
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import 'package:gap/gap.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/pods/message.dart';
|
import 'package:island/pods/message.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/pods/websocket.dart';
|
|
||||||
import 'package:island/services/update_service.dart';
|
import 'package:island/services/update_service.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
import 'package:island/widgets/content/network_status_sheet.dart';
|
import 'package:island/widgets/content/network_status_sheet.dart';
|
||||||
@@ -67,8 +66,6 @@ class DebugSheet extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final wsNotifier = ref.watch(websocketStateProvider.notifier);
|
|
||||||
|
|
||||||
return SheetScaffold(
|
return SheetScaffold(
|
||||||
titleText: 'Debug',
|
titleText: 'Debug',
|
||||||
heightFactor: 0.6,
|
heightFactor: 0.6,
|
||||||
@@ -111,10 +108,7 @@ class DebugSheet extends HookConsumerWidget {
|
|||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
builder:
|
builder: (context) => NetworkStatusSheet(),
|
||||||
(context) => NetworkStatusSheet(
|
|
||||||
onReconnect: () => wsNotifier.connect(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user