migrate: riverpod + freezed (#870)
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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();
|
||||
},
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user