migrate: riverpod + freezed (#870)

This commit is contained in:
lollipopkit🏳️‍⚧️
2025-08-31 00:55:54 +08:00
committed by GitHub
parent 9cb705f8dd
commit 53a7c0d8ff
67 changed files with 5012 additions and 1328 deletions

View File

@@ -66,7 +66,8 @@ extension _Init on SSHPageState {
// Mark status connected for notifications / live activities
TermSessionManager.updateStatus(_sessionId, TermSessionStatus.connected);
for (final snippet in SnippetProvider.snippets.value) {
final snippets = ref.read(snippetNotifierProvider.select((p) => p.snippets));
for (final snippet in snippets) {
if (snippet.autoRunOn?.contains(widget.args.spi.id) == true) {
snippet.runInTerm(_terminal, widget.args.spi);
}

View File

@@ -7,9 +7,8 @@ import 'package:dartssh2/dartssh2.dart';
import 'package:fl_lib/fl_lib.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:icons_plus/icons_plus.dart';
import 'package:provider/provider.dart';
import 'package:server_box/core/chan.dart';
import 'package:server_box/core/extension/context/locale.dart';
import 'package:server_box/core/utils/server.dart';
@@ -17,6 +16,7 @@ import 'package:server_box/core/utils/ssh_auth.dart';
import 'package:server_box/data/model/server/server_private_info.dart';
import 'package:server_box/data/model/server/snippet.dart';
import 'package:server_box/data/model/ssh/virtual_key.dart';
import 'package:server_box/data/provider/server.dart';
import 'package:server_box/data/provider/snippet.dart';
import 'package:server_box/data/provider/virtual_keyboard.dart';
import 'package:server_box/data/res/store.dart';
@@ -52,23 +52,22 @@ final class SshPageArgs {
});
}
class SSHPage extends StatefulWidget {
class SSHPage extends ConsumerStatefulWidget {
final SshPageArgs args;
const SSHPage({super.key, required this.args});
@override
State<SSHPage> createState() => SSHPageState();
ConsumerState<SSHPage> createState() => SSHPageState();
static const route = AppRouteArg<void, SshPageArgs>(page: SSHPage.new, path: '/ssh/page');
}
const _horizonPadding = 7.0;
class SSHPageState extends State<SSHPage>
class SSHPageState extends ConsumerState<SSHPage>
with AutomaticKeepAliveClientMixin, AfterLayoutMixin, TickerProviderStateMixin {
final _keyboard = VirtKeyProvider();
late final _terminal = Terminal(inputHandler: _keyboard);
late final _terminal = Terminal();
late final TerminalController _terminalController = TerminalController(vsync: this);
final List<List<VirtKey>> _virtKeysList = [];
late final _termKey = widget.args.terminalKey ?? GlobalKey<TerminalViewState>();
@@ -81,7 +80,7 @@ class SSHPageState extends State<SSHPage>
bool _isDark = false;
Timer? _virtKeyLongPressTimer;
late SSHClient? _client = widget.args.spi.server?.value.client;
SSHClient? _client;
SSHSession? _session;
Timer? _discontinuityTimer;
@@ -117,6 +116,10 @@ class SSHPageState extends State<SSHPage>
_initStoredCfg();
_initVirtKeys();
_setupDiscontinuityTimer();
// Initialize client from provider
final serverState = ref.read(individualServerNotifierProvider(widget.args.spi.id));
_client = serverState.client;
if (++_sshConnCount == 1) {
WakelockPlus.enable();
@@ -262,19 +265,22 @@ class SSHPageState extends State<SSHPage>
child: Container(
color: _terminalTheme.background,
height: _virtKeysHeight + _media.padding.bottom,
child: ChangeNotifierProvider(
create: (_) => _keyboard,
builder: (_, _) => Consumer<VirtKeyProvider>(
builder: (_, _, _) {
return _buildVirtualKey();
},
),
child: Consumer(
builder: (context, ref, child) {
final virtKeyState = ref.watch(virtKeyboardProvider);
final virtKeyNotifier = ref.read(virtKeyboardProvider.notifier);
// Set the terminal input handler
_terminal.inputHandler = virtKeyNotifier;
return _buildVirtualKey(virtKeyState, virtKeyNotifier);
},
),
),
);
}
Widget _buildVirtualKey() {
Widget _buildVirtualKey(VirtKeyState virtKeyState, VirtKeyboard virtKeyNotifier) {
final count = _horizonVirtKeys ? _virtKeysList.length : _virtKeysList.firstOrNull?.length ?? 0;
if (count == 0) return UIs.placeholder;
return LayoutBuilder(
@@ -286,30 +292,30 @@ class SSHPageState extends State<SSHPage>
child: Row(
children: _virtKeysList
.expand((e) => e)
.map((e) => _buildVirtKeyItem(e, virtKeyWidth))
.map((e) => _buildVirtKeyItem(e, virtKeyWidth, virtKeyState, virtKeyNotifier))
.toList(),
),
);
}
final rows = _virtKeysList
.map((e) => Row(children: e.map((e) => _buildVirtKeyItem(e, virtKeyWidth)).toList()))
.map((e) => Row(children: e.map((e) => _buildVirtKeyItem(e, virtKeyWidth, virtKeyState, virtKeyNotifier)).toList()))
.toList();
return Column(mainAxisSize: MainAxisSize.min, children: rows);
},
);
}
Widget _buildVirtKeyItem(VirtKey item, double virtKeyWidth) {
Widget _buildVirtKeyItem(VirtKey item, double virtKeyWidth, VirtKeyState virtKeyState, VirtKeyboard virtKeyNotifier) {
var selected = false;
switch (item.key) {
case TerminalKey.control:
selected = _keyboard.ctrl;
selected = virtKeyState.ctrl;
break;
case TerminalKey.alt:
selected = _keyboard.alt;
selected = virtKeyState.alt;
break;
case TerminalKey.shift:
selected = _keyboard.shift;
selected = virtKeyState.shift;
break;
default:
break;
@@ -326,12 +332,12 @@ class SSHPageState extends State<SSHPage>
);
return InkWell(
onTap: () => _doVirtualKey(item),
onTap: () => _doVirtualKey(item, virtKeyNotifier),
onTapDown: (details) {
if (item.canLongPress) {
_virtKeyLongPressTimer = Timer.periodic(
const Duration(milliseconds: 137),
(_) => _doVirtualKey(item),
(_) => _doVirtualKey(item, virtKeyNotifier),
);
}
},

View File

@@ -1,7 +1,7 @@
part of 'page.dart';
extension _VirtKey on SSHPageState {
void _doVirtualKey(VirtKey item) {
void _doVirtualKey(VirtKey item, VirtKeyboard virtKeyNotifier) {
if (item.func != null) {
HapticFeedback.mediumImpact();
_doVirtualKeyFunc(item.func!);
@@ -9,7 +9,7 @@ extension _VirtKey on SSHPageState {
}
if (item.key != null) {
HapticFeedback.mediumImpact();
_doVirtualKeyInput(item.key!);
_doVirtualKeyInput(item.key!, virtKeyNotifier);
}
final inputRaw = item.inputRaw;
if (inputRaw != null) {
@@ -18,16 +18,16 @@ extension _VirtKey on SSHPageState {
}
}
void _doVirtualKeyInput(TerminalKey key) {
void _doVirtualKeyInput(TerminalKey key, VirtKeyboard virtKeyNotifier) {
switch (key) {
case TerminalKey.control:
_keyboard.ctrl = !_keyboard.ctrl;
virtKeyNotifier.setCtrl(!virtKeyNotifier.ctrl);
break;
case TerminalKey.alt:
_keyboard.alt = !_keyboard.alt;
virtKeyNotifier.setAlt(!virtKeyNotifier.alt);
break;
case TerminalKey.shift:
_keyboard.shift = !_keyboard.shift;
virtKeyNotifier.setShift(!virtKeyNotifier.shift);
break;
default:
_terminal.keyInput(key);
@@ -52,14 +52,15 @@ extension _VirtKey on SSHPageState {
}
break;
case VirtualKeyFunc.snippet:
final snippetState = ref.read(snippetNotifierProvider);
final snippets = await context.showPickWithTagDialog<Snippet>(
title: l10n.snippet,
tags: SnippetProvider.tags,
tags: snippetState.tags.vn,
itemsBuilder: (e) {
if (e == TagSwitcher.kDefaultTag) {
return SnippetProvider.snippets.value;
return snippetState.snippets;
}
return SnippetProvider.snippets.value
return snippetState.snippets
.where((element) => element.tags?.contains(e) ?? false)
.toList();
},

View File

@@ -3,6 +3,7 @@ import 'dart:math';
import 'package:fl_lib/fl_lib.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:icons_plus/icons_plus.dart';
import 'package:server_box/core/extension/context/locale.dart';
import 'package:server_box/data/model/server/server_private_info.dart';
@@ -10,18 +11,18 @@ import 'package:server_box/data/provider/server.dart';
import 'package:server_box/view/page/server/edit.dart';
import 'package:server_box/view/page/ssh/page/page.dart';
class SSHTabPage extends StatefulWidget {
class SSHTabPage extends ConsumerStatefulWidget {
const SSHTabPage({super.key});
@override
State<SSHTabPage> createState() => _SSHTabPageState();
ConsumerState<SSHTabPage> createState() => _SSHTabPageState();
static const route = AppRouteNoArg(page: SSHTabPage.new, path: '/ssh');
}
typedef _TabMap = Map<String, ({Widget page, FocusNode? focus})>;
class _SSHTabPageState extends State<SSHTabPage>
class _SSHTabPageState extends ConsumerState<SSHTabPage>
with TickerProviderStateMixin, AutomaticKeepAliveClientMixin {
late final _TabMap _tabMap = {libL10n.add: (page: _AddPage(onTapInitCard: _onTapInitCard), focus: null)};
final _pageCtrl = PageController();
@@ -236,7 +237,7 @@ final class _TabBar extends StatelessWidget implements PreferredSizeWidget {
}
}
class _AddPage extends StatelessWidget {
class _AddPage extends ConsumerWidget {
const _AddPage({required this.onTapInitCard});
final void Function(Spi spi) onTapInitCard;
@@ -244,11 +245,12 @@ class _AddPage extends StatelessWidget {
Widget get _placeholder => const Expanded(child: UIs.placeholder);
@override
Widget build(BuildContext context) {
Widget build(BuildContext context, WidgetRef ref) {
const viewPadding = 7.0;
final viewWidth = context.mediaQuery.size.width - 2 * viewPadding;
final viewWidth = context.windowSize.width - 2 * viewPadding;
final itemCount = ServerProvider.servers.length;
final serverState = ref.watch(serverNotifierProvider);
final itemCount = serverState.servers.length;
const itemPadding = 1.0;
const itemWidth = 150.0;
const itemHeight = 50.0;
@@ -257,53 +259,53 @@ class _AddPage extends StatelessWidget {
final crossCount = max(viewWidth ~/ (visualCrossCount * itemPadding + itemWidth), 1);
final mainCount = itemCount ~/ crossCount + 1;
return ServerProvider.serverOrder.listenVal((order) {
if (order.isEmpty) {
return Center(child: Text(libL10n.empty, textAlign: TextAlign.center));
}
final order = serverState.serverOrder;
if (order.isEmpty) {
return Center(child: Text(libL10n.empty, textAlign: TextAlign.center));
}
// Custom grid
return ListView(
padding: const EdgeInsets.all(viewPadding),
children: List.generate(
mainCount,
(rowIndex) => Row(
children: List.generate(crossCount, (columnIndex) {
final idx = rowIndex * crossCount + columnIndex;
final id = order.elementAtOrNull(idx);
final spi = ServerProvider.pick(id: id)?.value.spi;
if (spi == null) return _placeholder;
// Custom grid
return ListView(
padding: const EdgeInsets.all(viewPadding),
children: List.generate(
mainCount,
(rowIndex) => Row(
children: List.generate(crossCount, (columnIndex) {
final idx = rowIndex * crossCount + columnIndex;
final id = order.elementAtOrNull(idx);
final spi = serverState.servers[id];
if (spi == null) return _placeholder;
return Expanded(
child: Padding(
padding: const EdgeInsets.all(itemPadding),
child: InkWell(
onTap: () => onTapInitCard(spi),
child: Container(
height: itemHeight,
alignment: Alignment.centerLeft,
padding: const EdgeInsets.only(left: 17, right: 7),
child: Row(
children: [
Expanded(
child: Text(
spi.name,
style: UIs.text18,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
return Expanded(
child: Padding(
padding: const EdgeInsets.all(itemPadding),
child: InkWell(
onTap: () => onTapInitCard(spi),
child: Container(
height: itemHeight,
alignment: Alignment.centerLeft,
padding: const EdgeInsets.only(left: 17, right: 7),
child: Row(
children: [
Expanded(
child: Text(
spi.name,
style: UIs.text18,
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const Icon(Icons.chevron_right),
],
),
),
const Icon(Icons.chevron_right),
],
),
).cardx,
),
);
}),
),
),
).cardx,
),
);
}),
),
);
});
),
);
}
}