mirror of
https://github.com/lollipopkit/flutter_server_box.git
synced 2025-12-17 07:14:28 +01:00
@@ -47,11 +47,11 @@ final class PveProvider extends ChangeNotifier {
|
|||||||
final client = HttpClient();
|
final client = HttpClient();
|
||||||
client.connectionFactory = cf;
|
client.connectionFactory = cf;
|
||||||
if (_ignoreCert) {
|
if (_ignoreCert) {
|
||||||
client.badCertificateCallback = (_, __, ___) => true;
|
client.badCertificateCallback = (_, _, _) => true;
|
||||||
}
|
}
|
||||||
return client;
|
return client;
|
||||||
},
|
},
|
||||||
validateCertificate: _ignoreCert ? (_, __, ___) => true : null,
|
validateCertificate: _ignoreCert ? (_, _, _) => true : null,
|
||||||
);
|
);
|
||||||
|
|
||||||
final data = ValueNotifier<PveRes?>(null);
|
final data = ValueNotifier<PveRes?>(null);
|
||||||
|
|||||||
@@ -12,9 +12,6 @@ class SettingStore extends HiveStore {
|
|||||||
|
|
||||||
static final instance = SettingStore._();
|
static final instance = SettingStore._();
|
||||||
|
|
||||||
/// Discussion #146
|
|
||||||
late final serverTabUseOldUI = propertyDefault('serverTabUseOldUI', false);
|
|
||||||
|
|
||||||
/// Time out for server connect and more...
|
/// Time out for server connect and more...
|
||||||
late final timeout = propertyDefault('timeOut', 5);
|
late final timeout = propertyDefault('timeOut', 5);
|
||||||
|
|
||||||
|
|||||||
@@ -890,6 +890,12 @@ abstract class AppLocalizations {
|
|||||||
/// **'Port'**
|
/// **'Port'**
|
||||||
String get port;
|
String get port;
|
||||||
|
|
||||||
|
/// No description provided for @preferDiskAmount.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Prioritize displaying disk capacity'**
|
||||||
|
String get preferDiskAmount;
|
||||||
|
|
||||||
/// No description provided for @preview.
|
/// No description provided for @preview.
|
||||||
///
|
///
|
||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
|
|||||||
@@ -440,6 +440,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get port => 'Port';
|
String get port => 'Port';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get preferDiskAmount => 'Festplattenkapazität vorrangig anzeigen';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get preview => 'Vorschau';
|
String get preview => 'Vorschau';
|
||||||
|
|
||||||
|
|||||||
@@ -438,6 +438,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get port => 'Port';
|
String get port => 'Port';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get preferDiskAmount => 'Prioritize displaying disk capacity';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get preview => 'Preview';
|
String get preview => 'Preview';
|
||||||
|
|
||||||
|
|||||||
@@ -441,6 +441,10 @@ class AppLocalizationsEs extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get port => 'Puerto';
|
String get port => 'Puerto';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get preferDiskAmount =>
|
||||||
|
'Priorizar la visualización de la capacidad del disco';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get preview => 'Vista previa';
|
String get preview => 'Vista previa';
|
||||||
|
|
||||||
|
|||||||
@@ -442,6 +442,10 @@ class AppLocalizationsFr extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get port => 'Port';
|
String get port => 'Port';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get preferDiskAmount =>
|
||||||
|
'Prioriser l’affichage de la capacité du disque';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get preview => 'Aperçu';
|
String get preview => 'Aperçu';
|
||||||
|
|
||||||
|
|||||||
@@ -438,6 +438,9 @@ class AppLocalizationsId extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get port => 'Port';
|
String get port => 'Port';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get preferDiskAmount => 'Prioritaskan tampilan kapasitas disk';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get preview => 'Pratinjau';
|
String get preview => 'Pratinjau';
|
||||||
|
|
||||||
|
|||||||
@@ -424,6 +424,9 @@ class AppLocalizationsJa extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get port => 'ポート';
|
String get port => 'ポート';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get preferDiskAmount => 'ディスク容量を優先的に表示';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get preview => 'プレビュー';
|
String get preview => 'プレビュー';
|
||||||
|
|
||||||
|
|||||||
@@ -438,6 +438,10 @@ class AppLocalizationsNl extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get port => 'Poort';
|
String get port => 'Poort';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get preferDiskAmount =>
|
||||||
|
'Geef de schijfcapaciteit prioriteit bij weergave';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get preview => 'Voorbeeld';
|
String get preview => 'Voorbeeld';
|
||||||
|
|
||||||
|
|||||||
@@ -439,6 +439,9 @@ class AppLocalizationsPt extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get port => 'Porta';
|
String get port => 'Porta';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get preferDiskAmount => 'Priorizar a exibição da capacidade do disco';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get preview => 'Pré-visualização';
|
String get preview => 'Pré-visualização';
|
||||||
|
|
||||||
|
|||||||
@@ -440,6 +440,9 @@ class AppLocalizationsRu extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get port => 'Порт';
|
String get port => 'Порт';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get preferDiskAmount => 'Приоритетное отображение объёма диска';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get preview => 'Предпросмотр';
|
String get preview => 'Предпросмотр';
|
||||||
|
|
||||||
|
|||||||
@@ -437,6 +437,9 @@ class AppLocalizationsTr extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get port => 'Port';
|
String get port => 'Port';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get preferDiskAmount => 'Disk kapasitesini öncelikli olarak göster';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get preview => 'Önizleme';
|
String get preview => 'Önizleme';
|
||||||
|
|
||||||
|
|||||||
@@ -442,6 +442,9 @@ class AppLocalizationsUk extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get port => 'Порт';
|
String get port => 'Порт';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get preferDiskAmount => 'Пріоритетно показувати ємність диска';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get preview => 'Попередній перегляд';
|
String get preview => 'Попередній перегляд';
|
||||||
|
|
||||||
|
|||||||
@@ -419,6 +419,9 @@ class AppLocalizationsZh extends AppLocalizations {
|
|||||||
@override
|
@override
|
||||||
String get port => '端口';
|
String get port => '端口';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get preferDiskAmount => '优先显示硬盘容量';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get preview => '预览';
|
String get preview => '预览';
|
||||||
|
|
||||||
@@ -1147,6 +1150,9 @@ class AppLocalizationsZhTw extends AppLocalizationsZh {
|
|||||||
@override
|
@override
|
||||||
String get port => '埠';
|
String get port => '埠';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get preferDiskAmount => '優先顯示硬碟容量';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get preview => '預覽';
|
String get preview => '預覽';
|
||||||
|
|
||||||
|
|||||||
@@ -128,6 +128,7 @@
|
|||||||
"pkg": "Pkg",
|
"pkg": "Pkg",
|
||||||
"plugInType": "Einfügetyp",
|
"plugInType": "Einfügetyp",
|
||||||
"port": "Port",
|
"port": "Port",
|
||||||
|
"preferDiskAmount": "Festplattenkapazität vorrangig anzeigen",
|
||||||
"preview": "Vorschau",
|
"preview": "Vorschau",
|
||||||
"privateKey": "Private Key",
|
"privateKey": "Private Key",
|
||||||
"process": "Prozess",
|
"process": "Prozess",
|
||||||
|
|||||||
@@ -128,6 +128,7 @@
|
|||||||
"pkg": "Pkg",
|
"pkg": "Pkg",
|
||||||
"plugInType": "Insertion Type",
|
"plugInType": "Insertion Type",
|
||||||
"port": "Port",
|
"port": "Port",
|
||||||
|
"preferDiskAmount": "Prioritize displaying disk capacity",
|
||||||
"preview": "Preview",
|
"preview": "Preview",
|
||||||
"privateKey": "Private Key",
|
"privateKey": "Private Key",
|
||||||
"process": "Process",
|
"process": "Process",
|
||||||
|
|||||||
@@ -128,6 +128,7 @@
|
|||||||
"pkg": "Gestión de paquetes",
|
"pkg": "Gestión de paquetes",
|
||||||
"plugInType": "Tipo de inserción",
|
"plugInType": "Tipo de inserción",
|
||||||
"port": "Puerto",
|
"port": "Puerto",
|
||||||
|
"preferDiskAmount": "Priorizar la visualización de la capacidad del disco",
|
||||||
"preview": "Vista previa",
|
"preview": "Vista previa",
|
||||||
"privateKey": "Llave privada",
|
"privateKey": "Llave privada",
|
||||||
"process": "Proceso",
|
"process": "Proceso",
|
||||||
|
|||||||
@@ -128,6 +128,7 @@
|
|||||||
"pkg": "Pkg",
|
"pkg": "Pkg",
|
||||||
"plugInType": "Type d'insertion",
|
"plugInType": "Type d'insertion",
|
||||||
"port": "Port",
|
"port": "Port",
|
||||||
|
"preferDiskAmount": "Prioriser l’affichage de la capacité du disque",
|
||||||
"preview": "Aperçu",
|
"preview": "Aperçu",
|
||||||
"privateKey": "Clé privée",
|
"privateKey": "Clé privée",
|
||||||
"process": "Processus",
|
"process": "Processus",
|
||||||
|
|||||||
@@ -128,6 +128,7 @@
|
|||||||
"pkg": "Pkg",
|
"pkg": "Pkg",
|
||||||
"plugInType": "Jenis Penyisipan",
|
"plugInType": "Jenis Penyisipan",
|
||||||
"port": "Port",
|
"port": "Port",
|
||||||
|
"preferDiskAmount": "Prioritaskan tampilan kapasitas disk",
|
||||||
"preview": "Pratinjau",
|
"preview": "Pratinjau",
|
||||||
"privateKey": "Kunci Pribadi",
|
"privateKey": "Kunci Pribadi",
|
||||||
"process": "Proses",
|
"process": "Proses",
|
||||||
|
|||||||
@@ -128,6 +128,7 @@
|
|||||||
"pkg": "パッケージ管理",
|
"pkg": "パッケージ管理",
|
||||||
"plugInType": "挿入タイプ",
|
"plugInType": "挿入タイプ",
|
||||||
"port": "ポート",
|
"port": "ポート",
|
||||||
|
"preferDiskAmount": "ディスク容量を優先的に表示",
|
||||||
"preview": "プレビュー",
|
"preview": "プレビュー",
|
||||||
"privateKey": "秘密鍵",
|
"privateKey": "秘密鍵",
|
||||||
"process": "プロセス",
|
"process": "プロセス",
|
||||||
|
|||||||
@@ -128,6 +128,7 @@
|
|||||||
"pkg": "Pkg",
|
"pkg": "Pkg",
|
||||||
"plugInType": "Invoegingstype",
|
"plugInType": "Invoegingstype",
|
||||||
"port": "Poort",
|
"port": "Poort",
|
||||||
|
"preferDiskAmount": "Geef de schijfcapaciteit prioriteit bij weergave",
|
||||||
"preview": "Voorbeeld",
|
"preview": "Voorbeeld",
|
||||||
"privateKey": "Privésleutel",
|
"privateKey": "Privésleutel",
|
||||||
"process": "Proces",
|
"process": "Proces",
|
||||||
|
|||||||
@@ -128,6 +128,7 @@
|
|||||||
"pkg": "Gerenciamento de pacotes",
|
"pkg": "Gerenciamento de pacotes",
|
||||||
"plugInType": "Tipo de Inserção",
|
"plugInType": "Tipo de Inserção",
|
||||||
"port": "Porta",
|
"port": "Porta",
|
||||||
|
"preferDiskAmount": "Priorizar a exibição da capacidade do disco",
|
||||||
"preview": "Pré-visualização",
|
"preview": "Pré-visualização",
|
||||||
"privateKey": "Chave privada",
|
"privateKey": "Chave privada",
|
||||||
"process": "Processo",
|
"process": "Processo",
|
||||||
|
|||||||
@@ -128,6 +128,7 @@
|
|||||||
"pkg": "Менеджер пакетов",
|
"pkg": "Менеджер пакетов",
|
||||||
"plugInType": "Тип вставки",
|
"plugInType": "Тип вставки",
|
||||||
"port": "Порт",
|
"port": "Порт",
|
||||||
|
"preferDiskAmount": "Приоритетное отображение объёма диска",
|
||||||
"preview": "Предпросмотр",
|
"preview": "Предпросмотр",
|
||||||
"privateKey": "Приватный ключ",
|
"privateKey": "Приватный ключ",
|
||||||
"process": "Процесс",
|
"process": "Процесс",
|
||||||
|
|||||||
@@ -128,6 +128,7 @@
|
|||||||
"pkg": "Paket",
|
"pkg": "Paket",
|
||||||
"plugInType": "Eklenti Türü",
|
"plugInType": "Eklenti Türü",
|
||||||
"port": "Port",
|
"port": "Port",
|
||||||
|
"preferDiskAmount": "Disk kapasitesini öncelikli olarak göster",
|
||||||
"preview": "Önizleme",
|
"preview": "Önizleme",
|
||||||
"privateKey": "Özel Anahtar",
|
"privateKey": "Özel Anahtar",
|
||||||
"process": "İşlem",
|
"process": "İşlem",
|
||||||
|
|||||||
@@ -128,6 +128,7 @@
|
|||||||
"pkg": "Пакет",
|
"pkg": "Пакет",
|
||||||
"plugInType": "Тип вставки",
|
"plugInType": "Тип вставки",
|
||||||
"port": "Порт",
|
"port": "Порт",
|
||||||
|
"preferDiskAmount": "Пріоритетно показувати ємність диска",
|
||||||
"preview": "Попередній перегляд",
|
"preview": "Попередній перегляд",
|
||||||
"privateKey": "Приватний ключ",
|
"privateKey": "Приватний ключ",
|
||||||
"process": "Процес",
|
"process": "Процес",
|
||||||
|
|||||||
@@ -128,6 +128,7 @@
|
|||||||
"pkg": "包管理",
|
"pkg": "包管理",
|
||||||
"plugInType": "插入类型",
|
"plugInType": "插入类型",
|
||||||
"port": "端口",
|
"port": "端口",
|
||||||
|
"preferDiskAmount": "优先显示硬盘容量",
|
||||||
"preview": "预览",
|
"preview": "预览",
|
||||||
"privateKey": "私钥",
|
"privateKey": "私钥",
|
||||||
"process": "进程",
|
"process": "进程",
|
||||||
|
|||||||
@@ -128,6 +128,7 @@
|
|||||||
"pkg": "包管理",
|
"pkg": "包管理",
|
||||||
"plugInType": "插入類型",
|
"plugInType": "插入類型",
|
||||||
"port": "埠",
|
"port": "埠",
|
||||||
|
"preferDiskAmount": "優先顯示硬碟容量",
|
||||||
"preview": "預覽",
|
"preview": "預覽",
|
||||||
"privateKey": "私鑰",
|
"privateKey": "私鑰",
|
||||||
"process": "行程",
|
"process": "行程",
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class _ContainerPageState extends State<ContainerPage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Consumer<ContainerProvider>(
|
return Consumer<ContainerProvider>(
|
||||||
builder: (_, ___, __) {
|
builder: (_, _, _) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: CustomAppBar(
|
appBar: CustomAppBar(
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
|
|||||||
@@ -15,14 +15,10 @@ class PingPage extends StatefulWidget {
|
|||||||
@override
|
@override
|
||||||
State<PingPage> createState() => _PingPageState();
|
State<PingPage> createState() => _PingPageState();
|
||||||
|
|
||||||
static const route = AppRouteNoArg(
|
static const route = AppRouteNoArg(page: PingPage.new, path: '/ping');
|
||||||
page: PingPage.new,
|
|
||||||
path: '/ping',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PingPageState extends State<PingPage>
|
class _PingPageState extends State<PingPage> with AutomaticKeepAliveClientMixin {
|
||||||
with AutomaticKeepAliveClientMixin {
|
|
||||||
late TextEditingController _textEditingController;
|
late TextEditingController _textEditingController;
|
||||||
final _results = ValueNotifier(<PingResult>[]);
|
final _results = ValueNotifier(<PingResult>[]);
|
||||||
bool get isInit => _results.value.isEmpty;
|
bool get isInit => _results.value.isEmpty;
|
||||||
@@ -43,13 +39,7 @@ class _PingPageState extends State<PingPage>
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
super.build(context);
|
super.build(context);
|
||||||
return Scaffold(
|
return Scaffold(body: _results.listenVal(_buildBody), floatingActionButton: _buildFAB());
|
||||||
body: ListenableBuilder(
|
|
||||||
listenable: _results,
|
|
||||||
builder: (_, __) => _buildBody(),
|
|
||||||
),
|
|
||||||
floatingActionButton: _buildFAB(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildFAB() {
|
Widget _buildFAB() {
|
||||||
@@ -81,26 +71,21 @@ class _PingPageState extends State<PingPage>
|
|||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: libL10n.error,
|
title: libL10n.error,
|
||||||
child: Text(e.toString()),
|
child: Text(e.toString()),
|
||||||
actions: [
|
actions: [TextButton(onPressed: () => Pfs.copy(e.toString()), child: Text(libL10n.copy))],
|
||||||
TextButton(
|
|
||||||
onPressed: () => Pfs.copy(e.toString()),
|
|
||||||
child: Text(libL10n.copy),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody() {
|
Widget _buildBody(List<PingResult> results) {
|
||||||
if (isInit) {
|
if (isInit) {
|
||||||
return Center(child: Text(libL10n.empty));
|
return Center(child: Text(libL10n.empty));
|
||||||
}
|
}
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
padding: const EdgeInsets.all(11),
|
padding: const EdgeInsets.all(11),
|
||||||
controller: ScrollController(),
|
controller: ScrollController(),
|
||||||
itemCount: _results.value.length,
|
itemCount: results.length,
|
||||||
itemBuilder: (_, index) => _buildResultItem(_results.value[index]),
|
itemBuilder: (_, index) => _buildResultItem(results[index]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,22 +97,12 @@ class _PingPageState extends State<PingPage>
|
|||||||
contentPadding: const EdgeInsets.symmetric(vertical: 7, horizontal: 17),
|
contentPadding: const EdgeInsets.symmetric(vertical: 7, horizontal: 17),
|
||||||
title: Text(
|
title: Text(
|
||||||
result.serverName,
|
result.serverName,
|
||||||
style: TextStyle(
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: UIs.primaryColor),
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
color: UIs.primaryColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
subtitle: Text(
|
|
||||||
_buildPingSummary(result, unknown, ms),
|
|
||||||
style: UIs.text11,
|
|
||||||
),
|
),
|
||||||
|
subtitle: Text(_buildPingSummary(result, unknown, ms), style: UIs.text11),
|
||||||
trailing: Text(
|
trailing: Text(
|
||||||
'${l10n.pingAvg}${result.statistic?.avg?.toStringAsFixed(2) ?? l10n.unknown} $ms',
|
'${l10n.pingAvg}${result.statistic?.avg?.toStringAsFixed(2) ?? l10n.unknown} $ms',
|
||||||
style: TextStyle(
|
style: TextStyle(fontSize: 14, color: UIs.primaryColor),
|
||||||
fontSize: 14,
|
|
||||||
color: UIs.primaryColor,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -165,7 +140,8 @@ class _PingPageState extends State<PingPage>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Future.wait(ServerProvider.servers.values.map((v) async {
|
await Future.wait(
|
||||||
|
ServerProvider.servers.values.map((v) async {
|
||||||
final e = v.value;
|
final e = v.value;
|
||||||
if (e.client == null) {
|
if (e.client == null) {
|
||||||
return;
|
return;
|
||||||
@@ -178,7 +154,8 @@ class _PingPageState extends State<PingPage>
|
|||||||
//
|
//
|
||||||
// ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member
|
// ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member
|
||||||
_results.notifyListeners();
|
_results.notifyListeners();
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -20,10 +20,7 @@ class ServerEditPage extends StatefulWidget {
|
|||||||
|
|
||||||
const ServerEditPage({super.key, this.args});
|
const ServerEditPage({super.key, this.args});
|
||||||
|
|
||||||
static const route = AppRoute<bool, SpiRequiredArgs>(
|
static const route = AppRoute<bool, SpiRequiredArgs>(page: ServerEditPage.new, path: '/servers/edit');
|
||||||
page: ServerEditPage.new,
|
|
||||||
path: '/servers/edit',
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ServerEditPage> createState() => _ServerEditPageState();
|
State<ServerEditPage> createState() => _ServerEditPageState();
|
||||||
@@ -118,15 +115,9 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildForm() {
|
Widget _buildForm() {
|
||||||
final topItems = [
|
final topItems = [_buildWriteScriptTip(), if (isMobile) _buildQrScan()];
|
||||||
_buildWriteScriptTip(),
|
|
||||||
if (isMobile) _buildQrScan(),
|
|
||||||
];
|
|
||||||
final children = [
|
final children = [
|
||||||
Row(
|
Row(mainAxisAlignment: MainAxisAlignment.center, children: topItems.joinWith(UIs.width13).toList()),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: topItems.joinWith(UIs.width13).toList(),
|
|
||||||
),
|
|
||||||
Input(
|
Input(
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
controller: _nameController,
|
controller: _nameController,
|
||||||
@@ -173,10 +164,9 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
TagTile(tags: _tags, allTags: ServerProvider.tags.value).cardx,
|
TagTile(tags: _tags, allTags: ServerProvider.tags.value).cardx,
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(l10n.autoConnect),
|
title: Text(l10n.autoConnect),
|
||||||
trailing: ListenableBuilder(
|
trailing: _autoConnect.listenVal(
|
||||||
listenable: _autoConnect,
|
(val) => Switch(
|
||||||
builder: (_, __) => Switch(
|
value: val,
|
||||||
value: _autoConnect.value,
|
|
||||||
onChanged: (val) {
|
onChanged: (val) {
|
||||||
_autoConnect.value = val;
|
_autoConnect.value = val;
|
||||||
},
|
},
|
||||||
@@ -193,10 +183,9 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
Widget _buildAuth() {
|
Widget _buildAuth() {
|
||||||
final switch_ = ListTile(
|
final switch_ = ListTile(
|
||||||
title: Text(l10n.keyAuth),
|
title: Text(l10n.keyAuth),
|
||||||
trailing: ListenableBuilder(
|
trailing: _keyIdx.listenVal(
|
||||||
listenable: _keyIdx,
|
(v) => Switch(
|
||||||
builder: (_, __) => Switch(
|
value: v != null,
|
||||||
value: _keyIdx.value != null,
|
|
||||||
onChanged: (val) {
|
onChanged: (val) {
|
||||||
if (val) {
|
if (val) {
|
||||||
_keyIdx.value = -1;
|
_keyIdx.value = -1;
|
||||||
@@ -209,14 +198,13 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/// Put [switch_] out of [ValueBuilder] to avoid rebuild
|
/// Put [switch_] out of [ValueBuilder] to avoid rebuild
|
||||||
return ListenableBuilder(
|
return _keyIdx.listenVal((v) {
|
||||||
listenable: _keyIdx,
|
|
||||||
builder: (_, __) {
|
|
||||||
final children = <Widget>[switch_];
|
final children = <Widget>[switch_];
|
||||||
if (_keyIdx.value != null) {
|
if (v != null) {
|
||||||
children.add(_buildKeyAuth());
|
children.add(_buildKeyAuth());
|
||||||
} else {
|
} else {
|
||||||
children.add(Input(
|
children.add(
|
||||||
|
Input(
|
||||||
controller: _passwordController,
|
controller: _passwordController,
|
||||||
obscureText: true,
|
obscureText: true,
|
||||||
type: TextInputType.text,
|
type: TextInputType.text,
|
||||||
@@ -225,16 +213,15 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
hint: l10n.pwd,
|
hint: l10n.pwd,
|
||||||
suggestion: false,
|
suggestion: false,
|
||||||
onSubmitted: (_) => _onSave(),
|
onSubmitted: (_) => _onSave(),
|
||||||
));
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return Column(children: children);
|
return Column(children: children);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildKeyAuth() {
|
Widget _buildKeyAuth() {
|
||||||
return PrivateKeyProvider.pkis.listenVal(
|
return PrivateKeyProvider.pkis.listenVal((pkis) {
|
||||||
(pkis) {
|
|
||||||
final tiles = List<Widget>.generate(pkis.length, (index) {
|
final tiles = List<Widget>.generate(pkis.length, (index) {
|
||||||
final e = pkis[index];
|
final e = pkis[index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
@@ -245,17 +232,10 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
onChanged: (value) => _keyIdx.value = value,
|
onChanged: (value) => _keyIdx.value = value,
|
||||||
),
|
),
|
||||||
title: Text(e.id, textAlign: TextAlign.start),
|
title: Text(e.id, textAlign: TextAlign.start),
|
||||||
subtitle: Text(
|
subtitle: Text(e.type ?? l10n.unknown, textAlign: TextAlign.start, style: UIs.textGrey),
|
||||||
e.type ?? l10n.unknown,
|
|
||||||
textAlign: TextAlign.start,
|
|
||||||
style: UIs.textGrey,
|
|
||||||
),
|
|
||||||
trailing: Btn.icon(
|
trailing: Btn.icon(
|
||||||
icon: const Icon(Icons.edit),
|
icon: const Icon(Icons.edit),
|
||||||
onTap: () => PrivateKeyEditPage.route.go(
|
onTap: () => PrivateKeyEditPage.route.go(context, args: PrivateKeyEditPageArgs(pki: e)),
|
||||||
context,
|
|
||||||
args: PrivateKeyEditPageArgs(pki: e),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
onTap: () => _keyIdx.value = index,
|
onTap: () => _keyIdx.value = index,
|
||||||
);
|
);
|
||||||
@@ -269,8 +249,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
return _keyIdx.listenVal((_) => Column(children: tiles)).cardx;
|
return _keyIdx.listenVal((_) => Column(children: tiles)).cardx;
|
||||||
},
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildEnvs() {
|
Widget _buildEnvs() {
|
||||||
@@ -282,10 +261,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
title: Text(l10n.envVars),
|
title: Text(l10n.envVars),
|
||||||
trailing: const Icon(Icons.keyboard_arrow_right),
|
trailing: const Icon(Icons.keyboard_arrow_right),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final res = await KvEditor.route.go(
|
final res = await KvEditor.route.go(context, KvEditorArgs(data: spi?.envs ?? {}));
|
||||||
context,
|
|
||||||
KvEditorArgs(data: spi?.envs ?? {}),
|
|
||||||
);
|
|
||||||
if (res == null) return;
|
if (res == null) return;
|
||||||
_env.value = res;
|
_env.value = res;
|
||||||
},
|
},
|
||||||
@@ -385,10 +361,9 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(MingCute.certificate_line),
|
leading: const Icon(MingCute.certificate_line),
|
||||||
title: TipText('PVE ${l10n.ignoreCert}', l10n.pveIgnoreCertTip),
|
title: TipText('PVE ${l10n.ignoreCert}', l10n.pveIgnoreCertTip),
|
||||||
trailing: ListenableBuilder(
|
trailing: _pveIgnoreCert.listenVal(
|
||||||
listenable: _pveIgnoreCert,
|
(v) => Switch(
|
||||||
builder: (_, __) => Switch(
|
value: v,
|
||||||
value: _pveIgnoreCert.value,
|
|
||||||
onChanged: (val) {
|
onChanged: (val) {
|
||||||
_pveIgnoreCert.value = val;
|
_pveIgnoreCert.value = val;
|
||||||
},
|
},
|
||||||
@@ -404,8 +379,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
CenterGreyTitle(l10n.customCmd),
|
CenterGreyTitle(l10n.customCmd),
|
||||||
_customCmds.listenVal(
|
_customCmds.listenVal((vals) {
|
||||||
(vals) {
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: const Icon(BoxIcons.bxs_file_json),
|
leading: const Icon(BoxIcons.bxs_file_json),
|
||||||
title: const Text('JSON'),
|
title: const Text('JSON'),
|
||||||
@@ -413,8 +387,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
trailing: const Icon(Icons.keyboard_arrow_right),
|
trailing: const Icon(Icons.keyboard_arrow_right),
|
||||||
onTap: _onTapCustomItem,
|
onTap: _onTapCustomItem,
|
||||||
);
|
);
|
||||||
},
|
}).cardx,
|
||||||
).cardx,
|
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(MingCute.doc_line),
|
leading: const Icon(MingCute.doc_line),
|
||||||
title: Text(libL10n.doc),
|
title: Text(libL10n.doc),
|
||||||
@@ -464,10 +437,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildFAB() {
|
Widget _buildFAB() {
|
||||||
return FloatingActionButton(
|
return FloatingActionButton(onPressed: _onSave, child: const Icon(Icons.save));
|
||||||
onPressed: _onSave,
|
|
||||||
child: const Icon(Icons.save),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildJumpServer() {
|
Widget _buildJumpServer() {
|
||||||
@@ -477,17 +447,14 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
.where((e) => e.spi.jumpId == null)
|
.where((e) => e.spi.jumpId == null)
|
||||||
.where((e) => e.spi.id != spi?.id)
|
.where((e) => e.spi.id != spi?.id)
|
||||||
.toList();
|
.toList();
|
||||||
final choice = _jumpServer.listenVal(
|
final choice = _jumpServer.listenVal((val) {
|
||||||
(val) {
|
|
||||||
final srv = srvs.firstWhereOrNull((e) => e.id == _jumpServer.value);
|
final srv = srvs.firstWhereOrNull((e) => e.id == _jumpServer.value);
|
||||||
return Choice<Server>(
|
return Choice<Server>(
|
||||||
multiple: false,
|
multiple: false,
|
||||||
clearable: true,
|
clearable: true,
|
||||||
value: srv != null ? [srv] : [],
|
value: srv != null ? [srv] : [],
|
||||||
builder: (state, _) => Wrap(
|
builder: (state, _) => Wrap(
|
||||||
children: List<Widget>.generate(
|
children: List<Widget>.generate(srvs.length, (index) {
|
||||||
srvs.length,
|
|
||||||
(index) {
|
|
||||||
final item = srvs[index];
|
final item = srvs[index];
|
||||||
return ChoiceChipX<Server>(
|
return ChoiceChipX<Server>(
|
||||||
label: item.spi.name,
|
label: item.spi.name,
|
||||||
@@ -501,12 +468,10 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
return ExpandTile(
|
return ExpandTile(
|
||||||
leading: const Icon(Icons.map),
|
leading: const Icon(Icons.map),
|
||||||
initiallyExpanded: _jumpServer.value != null,
|
initiallyExpanded: _jumpServer.value != null,
|
||||||
@@ -537,10 +502,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
text: libL10n.import,
|
text: libL10n.import,
|
||||||
icon: const Icon(Icons.qr_code, color: Colors.grey),
|
icon: const Icon(Icons.qr_code, color: Colors.grey),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final ret = await BarcodeScannerPage.route.go(
|
final ret = await BarcodeScannerPage.route.go(context, args: const BarcodeScannerPageArgs());
|
||||||
context,
|
|
||||||
args: const BarcodeScannerPageArgs(),
|
|
||||||
);
|
|
||||||
final code = ret?.text;
|
final code = ret?.text;
|
||||||
if (code == null) return;
|
if (code == null) return;
|
||||||
try {
|
try {
|
||||||
@@ -560,9 +522,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
title: libL10n.attention,
|
title: libL10n.attention,
|
||||||
child: Text(libL10n.askContinue(
|
child: Text(libL10n.askContinue('${libL10n.delete} ${l10n.server}(${spi!.name})')),
|
||||||
'${libL10n.delete} ${l10n.server}(${spi!.name})',
|
|
||||||
)),
|
|
||||||
actions: Btn.ok(
|
actions: Btn.ok(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
context.pop();
|
context.pop();
|
||||||
@@ -587,10 +547,7 @@ class _ServerEditPageState extends State<ServerEditPage> with AfterLayoutMixin {
|
|||||||
|
|
||||||
extension on _ServerEditPageState {
|
extension on _ServerEditPageState {
|
||||||
void _onTapCustomItem() async {
|
void _onTapCustomItem() async {
|
||||||
final res = await KvEditor.route.go(
|
final res = await KvEditor.route.go(context, KvEditorArgs(data: _customCmds.value));
|
||||||
context,
|
|
||||||
KvEditorArgs(data: _customCmds.value),
|
|
||||||
);
|
|
||||||
if (res == null) return;
|
if (res == null) return;
|
||||||
_customCmds.value = res;
|
_customCmds.value = res;
|
||||||
}
|
}
|
||||||
@@ -602,21 +559,12 @@ extension on _ServerEditPageState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_keyIdx.value == null && _passwordController.text.isEmpty) {
|
if (_keyIdx.value == null && _passwordController.text.isEmpty) {
|
||||||
final cancel = await context.showRoundDialog<bool>(
|
final ok = await context.showRoundDialog<bool>(
|
||||||
title: libL10n.attention,
|
title: libL10n.attention,
|
||||||
child: Text(libL10n.askContinue(l10n.useNoPwd)),
|
child: Text(libL10n.askContinue(l10n.useNoPwd)),
|
||||||
actions: [
|
actions: Btnx.cancelRedOk,
|
||||||
TextButton(
|
|
||||||
onPressed: () => context.pop(false),
|
|
||||||
child: Text(libL10n.ok),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => context.pop(true),
|
|
||||||
child: Text(libL10n.cancel),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
if (cancel != false) return;
|
if (ok != true) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If [_pubKeyIndex] is -1, it means that the user has not selected
|
// If [_pubKeyIndex] is -1, it means that the user has not selected
|
||||||
@@ -644,11 +592,7 @@ extension on _ServerEditPageState {
|
|||||||
final wolEmpty = _wolMacCtrl.text.isEmpty && _wolIpCtrl.text.isEmpty && _wolPwdCtrl.text.isEmpty;
|
final wolEmpty = _wolMacCtrl.text.isEmpty && _wolIpCtrl.text.isEmpty && _wolPwdCtrl.text.isEmpty;
|
||||||
final wol = wolEmpty
|
final wol = wolEmpty
|
||||||
? null
|
? null
|
||||||
: WakeOnLanCfg(
|
: WakeOnLanCfg(mac: _wolMacCtrl.text, ip: _wolIpCtrl.text, pwd: _wolPwdCtrl.text.selfNotEmptyOrNull);
|
||||||
mac: _wolMacCtrl.text,
|
|
||||||
ip: _wolIpCtrl.text,
|
|
||||||
pwd: _wolPwdCtrl.text.selfNotEmptyOrNull,
|
|
||||||
);
|
|
||||||
if (wol != null) {
|
if (wol != null) {
|
||||||
final wolValidation = wol.validate();
|
final wolValidation = wol.validate();
|
||||||
if (!wolValidation.$2) {
|
if (!wolValidation.$2) {
|
||||||
@@ -696,9 +640,7 @@ extension on _ServerEditPageState {
|
|||||||
if (spi.keyId == null) {
|
if (spi.keyId == null) {
|
||||||
_passwordController.text = spi.pwd ?? '';
|
_passwordController.text = spi.pwd ?? '';
|
||||||
} else {
|
} else {
|
||||||
_keyIdx.value = PrivateKeyProvider.pkis.value.indexWhere(
|
_keyIdx.value = PrivateKeyProvider.pkis.value.indexWhere((e) => e.id == spi.keyId);
|
||||||
(e) => e.id == spi.keyId,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// List in dart is passed by pointer, so you need to copy it here
|
/// List in dart is passed by pointer, so you need to copy it here
|
||||||
|
|||||||
@@ -85,29 +85,26 @@ ${ss.err?.message ?? 'null'}
|
|||||||
|
|
||||||
Widget _buildDisk(ServerStatus ss, String id) {
|
Widget _buildDisk(ServerStatus ss, String id) {
|
||||||
final cardNoti = _getCardNoti(id);
|
final cardNoti = _getCardNoti(id);
|
||||||
return ListenableBuilder(
|
return cardNoti.listenVal((v) {
|
||||||
listenable: cardNoti,
|
final isSpeed = v.diskIO ?? !Stores.setting.serverTabPreferDiskAmount.fetch();
|
||||||
builder: (_, __) {
|
|
||||||
final isSpeed = cardNoti.value.diskIO ?? !Stores.setting.serverTabPreferDiskAmount.fetch();
|
|
||||||
|
|
||||||
final (r, w) = ss.diskIO.cachedAllSpeed;
|
final (r, w) = ss.diskIO.cachedAllSpeed;
|
||||||
|
|
||||||
return AnimatedSwitcher(
|
return AnimatedSwitcher(
|
||||||
duration: const Duration(milliseconds: 377),
|
duration: const Duration(milliseconds: 377),
|
||||||
transitionBuilder: (Widget child, Animation<double> animation) {
|
transitionBuilder: (child, animation) {
|
||||||
return FadeTransition(opacity: animation, child: child);
|
return FadeTransition(opacity: animation, child: child);
|
||||||
},
|
},
|
||||||
child: _buildIOData(
|
child: _buildIOData(
|
||||||
isSpeed ? '${l10n.read}:\n$r' : 'Total:\n${ss.diskUsage?.size.kb2Str}',
|
isSpeed ? '${l10n.read}:\n$r' : 'Total:\n${ss.diskUsage?.size.kb2Str}',
|
||||||
isSpeed ? '${l10n.write}:\n$w' : 'Used:\n${ss.diskUsage?.used.kb2Str}',
|
isSpeed ? '${l10n.write}:\n$w' : 'Used:\n${ss.diskUsage?.used.kb2Str}',
|
||||||
onTap: () {
|
onTap: () {
|
||||||
cardNoti.value = cardNoti.value.copyWith(diskIO: !isSpeed);
|
cardNoti.value = v.copyWith(diskIO: !isSpeed);
|
||||||
},
|
},
|
||||||
key: ValueKey(isSpeed),
|
key: ValueKey(isSpeed),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildNet(ServerStatus ss, String id) {
|
Widget _buildNet(ServerStatus ss, String id) {
|
||||||
|
|||||||
@@ -42,17 +42,14 @@ extension on _ServerPageState {
|
|||||||
final title = _buildServerCardTitle(srv);
|
final title = _buildServerCardTitle(srv);
|
||||||
final List<Widget> children = [title, _buildNormalCard(srv.status, srv.spi)];
|
final List<Widget> children = [title, _buildNormalCard(srv.status, srv.spi)];
|
||||||
|
|
||||||
return ListenableBuilder(
|
return _getCardNoti(id).listenVal((_) {
|
||||||
listenable: _getCardNoti(id),
|
|
||||||
builder: (_, __) {
|
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: children,
|
children: children,
|
||||||
);
|
);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -319,9 +319,7 @@ class _ServerPageState extends State<ServerPage> with AutomaticKeepAliveClientMi
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
UIs.height13,
|
UIs.height13,
|
||||||
if (Stores.setting.moveServerFuncs.fetch() &&
|
if (Stores.setting.moveServerFuncs.fetch())
|
||||||
// Discussion #146
|
|
||||||
!Stores.setting.serverTabUseOldUI.fetch())
|
|
||||||
SizedBox(height: 27, child: ServerFuncBtns(spi: spi)),
|
SizedBox(height: 27, child: ServerFuncBtns(spi: spi)),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -100,9 +100,7 @@ extension _Utils on _ServerPageState {
|
|||||||
if (flip) {
|
if (flip) {
|
||||||
return _ServerPageState._kCardHeightFlip;
|
return _ServerPageState._kCardHeightFlip;
|
||||||
}
|
}
|
||||||
if (Stores.setting.moveServerFuncs.fetch() &&
|
if (Stores.setting.moveServerFuncs.fetch()) {
|
||||||
// Discussion #146
|
|
||||||
!Stores.setting.serverTabUseOldUI.fetch()) {
|
|
||||||
return _ServerPageState._kCardHeightMoveOutFuncs;
|
return _ServerPageState._kCardHeightMoveOutFuncs;
|
||||||
}
|
}
|
||||||
return _ServerPageState._kCardHeightNormal;
|
return _ServerPageState._kCardHeightNormal;
|
||||||
|
|||||||
@@ -173,6 +173,7 @@ extension _Server on _AppSettingsPageState {
|
|||||||
title: Text(l10n.more),
|
title: Text(l10n.more),
|
||||||
initiallyExpanded: false,
|
initiallyExpanded: false,
|
||||||
children: [
|
children: [
|
||||||
|
_buildServerTabPreferDiskAmount(),
|
||||||
_buildRememberPwdInMem(),
|
_buildRememberPwdInMem(),
|
||||||
_buildTextScaler(),
|
_buildTextScaler(),
|
||||||
_buildKeepStatusWhenErr(),
|
_buildKeepStatusWhenErr(),
|
||||||
@@ -298,4 +299,11 @@ extension _Server on _AppSettingsPageState {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildServerTabPreferDiskAmount() {
|
||||||
|
return ListTile(
|
||||||
|
title: Text(l10n.preferDiskAmount),
|
||||||
|
trailing: StoreSwitch(prop: Stores.setting.serverTabPreferDiskAmount),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ abstract final class PlatformPublicSettings {
|
|||||||
title: Text(libL10n.bioAuth),
|
title: Text(libL10n.bioAuth),
|
||||||
subtitle: const Text('...', style: UIs.textGrey),
|
subtitle: const Text('...', style: UIs.textGrey),
|
||||||
),
|
),
|
||||||
error: (e, __) => ListTile(
|
error: (e, _) => ListTile(
|
||||||
title: Text(libL10n.bioAuth),
|
title: Text(libL10n.bioAuth),
|
||||||
subtitle: Text('${libL10n.fail}: $e', style: UIs.textGrey),
|
subtitle: Text('${libL10n.fail}: $e', style: UIs.textGrey),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ class SSHPageState extends State<SSHPage>
|
|||||||
if (hasBg) {
|
if (hasBg) {
|
||||||
children.add(
|
children.add(
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: Image.file(file, fit: BoxFit.cover, errorBuilder: (_, __, ___) => const SizedBox()),
|
child: Image.file(file, fit: BoxFit.cover, errorBuilder: (_, _, _) => const SizedBox()),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (blur > 0) {
|
if (blur > 0) {
|
||||||
@@ -247,8 +247,8 @@ class SSHPageState extends State<SSHPage>
|
|||||||
height: _virtKeysHeight + _media.padding.bottom,
|
height: _virtKeysHeight + _media.padding.bottom,
|
||||||
child: ChangeNotifierProvider(
|
child: ChangeNotifierProvider(
|
||||||
create: (_) => _keyboard,
|
create: (_) => _keyboard,
|
||||||
builder: (_, __) => Consumer<VirtKeyProvider>(
|
builder: (_, _) => Consumer<VirtKeyProvider>(
|
||||||
builder: (_, __, ___) {
|
builder: (_, _, _) {
|
||||||
return _buildVirtualKey();
|
return _buildVirtualKey();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ final class _TabBar extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 5),
|
padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 5),
|
||||||
itemCount: names.length,
|
itemCount: names.length,
|
||||||
itemBuilder: (_, idx) => _buildItem(idx),
|
itemBuilder: (_, idx) => _buildItem(idx),
|
||||||
separatorBuilder: (_, __) => Padding(
|
separatorBuilder: (_, _) => Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 17),
|
padding: const EdgeInsets.symmetric(vertical: 17),
|
||||||
child: Container(
|
child: Container(
|
||||||
color: const Color.fromARGB(61, 158, 158, 158),
|
color: const Color.fromARGB(61, 158, 158, 158),
|
||||||
|
|||||||
@@ -26,28 +26,18 @@ final class SftpPageArgs {
|
|||||||
final bool isSelect;
|
final bool isSelect;
|
||||||
final String? initPath;
|
final String? initPath;
|
||||||
|
|
||||||
const SftpPageArgs({
|
const SftpPageArgs({required this.spi, this.isSelect = false, this.initPath});
|
||||||
required this.spi,
|
|
||||||
this.isSelect = false,
|
|
||||||
this.initPath,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SftpPage extends StatefulWidget {
|
class SftpPage extends StatefulWidget {
|
||||||
final SftpPageArgs args;
|
final SftpPageArgs args;
|
||||||
|
|
||||||
const SftpPage({
|
const SftpPage({super.key, required this.args});
|
||||||
super.key,
|
|
||||||
required this.args,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<SftpPage> createState() => _SftpPageState();
|
State<SftpPage> createState() => _SftpPageState();
|
||||||
|
|
||||||
static const route = AppRouteArg<String, SftpPageArgs>(
|
static const route = AppRouteArg<String, SftpPageArgs>(page: SftpPage.new, path: '/sftp');
|
||||||
page: SftpPage.new,
|
|
||||||
path: '/sftp',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
|
class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
|
||||||
@@ -64,20 +54,14 @@ class _SftpPageState extends State<SftpPage> with AfterLayoutMixin {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final children = [
|
final children = [
|
||||||
Btn.icon(
|
Btn.icon(icon: const Icon(Icons.downloading), onTap: () => SftpMissionPage.route.go(context)),
|
||||||
icon: const Icon(Icons.downloading),
|
|
||||||
onTap: () => SftpMissionPage.route.go(context),
|
|
||||||
),
|
|
||||||
_buildSortMenu(),
|
_buildSortMenu(),
|
||||||
_buildSearchBtn(),
|
_buildSearchBtn(),
|
||||||
];
|
];
|
||||||
if (isDesktop) children.add(_buildRefreshBtn());
|
if (isDesktop) children.add(_buildRefreshBtn());
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: CustomAppBar(
|
appBar: CustomAppBar(title: Text(widget.args.spi.name), actions: children),
|
||||||
title: Text(widget.args.spi.name),
|
|
||||||
actions: children,
|
|
||||||
),
|
|
||||||
body: _buildFileView(),
|
body: _buildFileView(),
|
||||||
bottomNavigationBar: _buildBottom(),
|
bottomNavigationBar: _buildBottom(),
|
||||||
);
|
);
|
||||||
@@ -105,8 +89,7 @@ extension _UI on _SftpPageState {
|
|||||||
(_SortType.size, l10n.size),
|
(_SortType.size, l10n.size),
|
||||||
(_SortType.time, l10n.time),
|
(_SortType.time, l10n.time),
|
||||||
];
|
];
|
||||||
return _sortOption.listenVal(
|
return _sortOption.listenVal((value) {
|
||||||
(value) {
|
|
||||||
return PopupMenuButton<_SortType>(
|
return PopupMenuButton<_SortType>(
|
||||||
icon: const Icon(Icons.sort),
|
icon: const Icon(Icons.sort),
|
||||||
itemBuilder: (context) {
|
itemBuilder: (context) {
|
||||||
@@ -135,26 +118,16 @@ extension _UI on _SftpPageState {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBottom() {
|
Widget _buildBottom() {
|
||||||
final children = widget.args.isSelect
|
final children = widget.args.isSelect
|
||||||
? [
|
? [
|
||||||
IconButton(
|
IconButton(onPressed: () => context.pop(_status.path.path), icon: const Icon(Icons.done)),
|
||||||
onPressed: () => context.pop(_status.path.path),
|
|
||||||
icon: const Icon(Icons.done),
|
|
||||||
),
|
|
||||||
_buildSearchBtn(),
|
_buildSearchBtn(),
|
||||||
]
|
]
|
||||||
: [
|
: [_buildBackBtn(), _buildHomeBtn(), _buildAddBtn(), _buildGotoBtn(), _buildUploadBtn()];
|
||||||
_buildBackBtn(),
|
|
||||||
_buildHomeBtn(),
|
|
||||||
_buildAddBtn(),
|
|
||||||
_buildGotoBtn(),
|
|
||||||
_buildUploadBtn(),
|
|
||||||
];
|
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.fromLTRB(11, 7, 11, 11),
|
padding: const EdgeInsets.fromLTRB(11, 7, 11, 11),
|
||||||
@@ -162,10 +135,7 @@ extension _UI on _SftpPageState {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
OmitStartText(_status.path.path),
|
OmitStartText(_status.path.path),
|
||||||
Row(
|
Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: children),
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
||||||
children: children,
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -182,10 +152,7 @@ extension _UI on _SftpPageState {
|
|||||||
child: ValBuilder(
|
child: ValBuilder(
|
||||||
listenable: _sortOption,
|
listenable: _sortOption,
|
||||||
builder: (sortOption) {
|
builder: (sortOption) {
|
||||||
final files = sortOption.sortBy.sort(
|
final files = sortOption.sortBy.sort(_status.files, reversed: sortOption.reversed);
|
||||||
_status.files,
|
|
||||||
reversed: sortOption.reversed,
|
|
||||||
);
|
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
itemCount: files.length,
|
itemCount: files.length,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 3),
|
padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 3),
|
||||||
@@ -209,12 +176,7 @@ extension _UI on _SftpPageState {
|
|||||||
leading: Icon(isDir ? Icons.folder_outlined : Icons.insert_drive_file),
|
leading: Icon(isDir ? Icons.folder_outlined : Icons.insert_drive_file),
|
||||||
title: Text(file.filename),
|
title: Text(file.filename),
|
||||||
trailing: trailing,
|
trailing: trailing,
|
||||||
subtitle: isDir
|
subtitle: isDir ? null : Text((file.attr.size ?? 0).bytes2Str, style: UIs.textGrey),
|
||||||
? null
|
|
||||||
: Text(
|
|
||||||
(file.attr.size ?? 0).bytes2Str,
|
|
||||||
style: UIs.textGrey,
|
|
||||||
),
|
|
||||||
onTap: () {
|
onTap: () {
|
||||||
beforeTap?.call();
|
beforeTap?.call();
|
||||||
if (isDir) {
|
if (isDir) {
|
||||||
@@ -236,16 +198,8 @@ extension _UI on _SftpPageState {
|
|||||||
extension _Actions on _SftpPageState {
|
extension _Actions on _SftpPageState {
|
||||||
void _onItemPress(SftpName file, bool notDir) {
|
void _onItemPress(SftpName file, bool notDir) {
|
||||||
final children = [
|
final children = [
|
||||||
ListTile(
|
ListTile(leading: const Icon(Icons.delete), title: Text(libL10n.delete), onTap: () => _delete(file)),
|
||||||
leading: const Icon(Icons.delete),
|
ListTile(leading: const Icon(Icons.abc), title: Text(libL10n.rename), onTap: () => _rename(file)),
|
||||||
title: Text(libL10n.delete),
|
|
||||||
onTap: () => _delete(file),
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
leading: const Icon(Icons.abc),
|
|
||||||
title: Text(libL10n.rename),
|
|
||||||
onTap: () => _rename(file),
|
|
||||||
),
|
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(MingCute.copy_line),
|
leading: const Icon(MingCute.copy_line),
|
||||||
title: Text(l10n.copyPath),
|
title: Text(l10n.copyPath),
|
||||||
@@ -270,21 +224,19 @@ extension _Actions on _SftpPageState {
|
|||||||
|
|
||||||
final permStr = newPerm.perm;
|
final permStr = newPerm.perm;
|
||||||
if (ok == true && permStr != perm.perm) {
|
if (ok == true && permStr != perm.perm) {
|
||||||
await context.showLoadingDialog(fn: () async {
|
await context.showLoadingDialog(
|
||||||
|
fn: () async {
|
||||||
await _client.run('chmod $permStr "${_getRemotePath(file)}"');
|
await _client.run('chmod $permStr "${_getRemotePath(file)}"');
|
||||||
await _listDir();
|
await _listDir();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
if (notDir) {
|
if (notDir) {
|
||||||
children.addAll([
|
children.addAll([
|
||||||
ListTile(
|
ListTile(leading: const Icon(Icons.edit), title: Text(libL10n.edit), onTap: () => _edit(file)),
|
||||||
leading: const Icon(Icons.edit),
|
|
||||||
title: Text(libL10n.edit),
|
|
||||||
onTap: () => _edit(file),
|
|
||||||
),
|
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.download),
|
leading: const Icon(Icons.download),
|
||||||
title: Text(libL10n.download),
|
title: Text(libL10n.download),
|
||||||
@@ -300,10 +252,7 @@ extension _Actions on _SftpPageState {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(
|
||||||
child: Column(
|
child: Column(mainAxisSize: MainAxisSize.min, children: children),
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: children,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,27 +272,16 @@ extension _Actions on _SftpPageState {
|
|||||||
|
|
||||||
final size = name.attr.size;
|
final size = name.attr.size;
|
||||||
if (size == null || size > Miscs.editorMaxSize) {
|
if (size == null || size > Miscs.editorMaxSize) {
|
||||||
context.showSnackBar(l10n.fileTooLarge(
|
context.showSnackBar(l10n.fileTooLarge(name.filename, size ?? 0, Miscs.editorMaxSize));
|
||||||
name.filename,
|
|
||||||
size ?? 0,
|
|
||||||
Miscs.editorMaxSize,
|
|
||||||
));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final remotePath = _getRemotePath(name);
|
final remotePath = _getRemotePath(name);
|
||||||
final localPath = _getLocalPath(remotePath);
|
final localPath = _getLocalPath(remotePath);
|
||||||
final completer = Completer();
|
final completer = Completer();
|
||||||
final req = SftpReq(
|
final req = SftpReq(widget.args.spi, remotePath, localPath, SftpReqType.download);
|
||||||
widget.args.spi,
|
|
||||||
remotePath,
|
|
||||||
localPath,
|
|
||||||
SftpReqType.download,
|
|
||||||
);
|
|
||||||
SftpProvider.add(req, completer: completer);
|
SftpProvider.add(req, completer: completer);
|
||||||
final (suc, err) = await context.showLoadingDialog(
|
final (suc, err) = await context.showLoadingDialog(fn: () => completer.future);
|
||||||
fn: () => completer.future,
|
|
||||||
);
|
|
||||||
if (suc == null || err != null) return;
|
if (suc == null || err != null) return;
|
||||||
|
|
||||||
await EditorPage.route.go(
|
await EditorPage.route.go(
|
||||||
@@ -351,12 +289,7 @@ extension _Actions on _SftpPageState {
|
|||||||
args: EditorPageArgs(
|
args: EditorPageArgs(
|
||||||
path: localPath,
|
path: localPath,
|
||||||
onSave: (_) {
|
onSave: (_) {
|
||||||
SftpProvider.add(SftpReq(
|
SftpProvider.add(SftpReq(req.spi, remotePath, localPath, SftpReqType.upload));
|
||||||
req.spi,
|
|
||||||
remotePath,
|
|
||||||
localPath,
|
|
||||||
SftpReqType.upload,
|
|
||||||
));
|
|
||||||
context.showSnackBar(l10n.added2List);
|
context.showSnackBar(l10n.added2List);
|
||||||
},
|
},
|
||||||
closeAfterSave: SettingStore.instance.closeAfterSave.fetch(),
|
closeAfterSave: SettingStore.instance.closeAfterSave.fetch(),
|
||||||
@@ -371,28 +304,20 @@ extension _Actions on _SftpPageState {
|
|||||||
title: libL10n.attention,
|
title: libL10n.attention,
|
||||||
child: Text('${l10n.dl2Local(name.filename)}\n${l10n.keepForeground}'),
|
child: Text('${l10n.dl2Local(name.filename)}\n${l10n.keepForeground}'),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(onPressed: () => context.pop(), child: Text(libL10n.cancel)),
|
||||||
onPressed: () => context.pop(),
|
|
||||||
child: Text(libL10n.cancel),
|
|
||||||
),
|
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
context.pop();
|
context.pop();
|
||||||
final remotePath = _getRemotePath(name);
|
final remotePath = _getRemotePath(name);
|
||||||
|
|
||||||
SftpProvider.add(
|
SftpProvider.add(
|
||||||
SftpReq(
|
SftpReq(widget.args.spi, remotePath, _getLocalPath(remotePath), SftpReqType.download),
|
||||||
widget.args.spi,
|
|
||||||
remotePath,
|
|
||||||
_getLocalPath(remotePath),
|
|
||||||
SftpReqType.download,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
context.pop();
|
context.pop();
|
||||||
},
|
},
|
||||||
child: Text(libL10n.download),
|
child: Text(libL10n.download),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -416,9 +341,7 @@ extension _Actions on _SftpPageState {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
ListTile(
|
ListTile(title: Text(text)),
|
||||||
title: Text(text),
|
|
||||||
),
|
|
||||||
if (!useRmr)
|
if (!useRmr)
|
||||||
StatefulBuilder(
|
StatefulBuilder(
|
||||||
builder: (_, setState) {
|
builder: (_, setState) {
|
||||||
@@ -436,10 +359,7 @@ extension _Actions on _SftpPageState {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(onPressed: () => context.pop(), child: Text(libL10n.cancel)),
|
||||||
onPressed: () => context.pop(),
|
|
||||||
child: Text(libL10n.cancel),
|
|
||||||
),
|
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
context.pop();
|
context.pop();
|
||||||
@@ -474,10 +394,7 @@ extension _Actions on _SftpPageState {
|
|||||||
void onSubmitted() async {
|
void onSubmitted() async {
|
||||||
final text = textController.text.trim();
|
final text = textController.text.trim();
|
||||||
if (text.isEmpty) {
|
if (text.isEmpty) {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(child: Text(libL10n.empty), actions: Btnx.oks);
|
||||||
child: Text(libL10n.empty),
|
|
||||||
actions: Btnx.oks,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context.pop();
|
context.pop();
|
||||||
@@ -504,10 +421,7 @@ extension _Actions on _SftpPageState {
|
|||||||
suggestion: true,
|
suggestion: true,
|
||||||
onSubmitted: (_) => onSubmitted(),
|
onSubmitted: (_) => onSubmitted(),
|
||||||
),
|
),
|
||||||
actions: Btn.ok(
|
actions: Btn.ok(onTap: onSubmitted, red: true).toList,
|
||||||
onTap: onSubmitted,
|
|
||||||
red: true,
|
|
||||||
).toList,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,11 +432,7 @@ extension _Actions on _SftpPageState {
|
|||||||
void onSubmitted() async {
|
void onSubmitted() async {
|
||||||
final text = textController.text.trim();
|
final text = textController.text.trim();
|
||||||
if (text.isEmpty) {
|
if (text.isEmpty) {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(title: libL10n.attention, child: Text(libL10n.empty), actions: Btnx.oks);
|
||||||
title: libL10n.attention,
|
|
||||||
child: Text(libL10n.empty),
|
|
||||||
actions: Btnx.oks,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context.pop();
|
context.pop();
|
||||||
@@ -560,11 +470,7 @@ extension _Actions on _SftpPageState {
|
|||||||
void onSubmitted() async {
|
void onSubmitted() async {
|
||||||
final text = textController.text.trim();
|
final text = textController.text.trim();
|
||||||
if (text.isEmpty) {
|
if (text.isEmpty) {
|
||||||
context.showRoundDialog(
|
context.showRoundDialog(title: libL10n.attention, child: Text(libL10n.empty), actions: Btnx.oks);
|
||||||
title: libL10n.attention,
|
|
||||||
child: Text(libL10n.empty),
|
|
||||||
actions: Btnx.oks,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context.pop();
|
context.pop();
|
||||||
@@ -685,10 +591,7 @@ extension _Actions on _SftpPageState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBackBtn() {
|
Widget _buildBackBtn() {
|
||||||
return Btn.icon(
|
return Btn.icon(onTap: _backward, icon: const Icon(Icons.arrow_back));
|
||||||
onTap: _backward,
|
|
||||||
icon: const Icon(Icons.arrow_back),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSearchBtn() {
|
Widget _buildSearchBtn() {
|
||||||
@@ -721,23 +624,13 @@ extension _Actions on _SftpPageState {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Btn.tile(
|
Btn.tile(icon: const Icon(Icons.open_in_new), text: l10n.system, onTap: () => context.pop(1)),
|
||||||
icon: const Icon(Icons.open_in_new),
|
Btn.tile(icon: const Icon(Icons.folder), text: l10n.inner, onTap: () => context.pop(0)),
|
||||||
text: l10n.system,
|
|
||||||
onTap: () => context.pop(1),
|
|
||||||
),
|
|
||||||
Btn.tile(
|
|
||||||
icon: const Icon(Icons.folder),
|
|
||||||
text: l10n.inner,
|
|
||||||
onTap: () => context.pop(0),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
));
|
|
||||||
final path = switch (idx) {
|
|
||||||
0 => await LocalFilePage.route.go(
|
|
||||||
context,
|
|
||||||
args: const LocalFilePageArgs(isPickFile: true),
|
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
final path = switch (idx) {
|
||||||
|
0 => await LocalFilePage.route.go(context, args: const LocalFilePageArgs(isPickFile: true)),
|
||||||
1 => await Pfs.pickFilePath(),
|
1 => await Pfs.pickFilePath(),
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
@@ -747,9 +640,7 @@ extension _Actions on _SftpPageState {
|
|||||||
final fileName = path.split(Platform.pathSeparator).lastOrNull;
|
final fileName = path.split(Platform.pathSeparator).lastOrNull;
|
||||||
final remotePath = '$remoteDir/$fileName';
|
final remotePath = '$remoteDir/$fileName';
|
||||||
Loggers.app.info('SFTP upload local: $path, remote: $remotePath');
|
Loggers.app.info('SFTP upload local: $path, remote: $remotePath');
|
||||||
SftpProvider.add(
|
SftpProvider.add(SftpReq(widget.args.spi, remotePath, path, SftpReqType.upload));
|
||||||
SftpReq(widget.args.spi, remotePath, path, SftpReqType.upload),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.upload_file),
|
icon: const Icon(Icons.upload_file),
|
||||||
);
|
);
|
||||||
@@ -761,16 +652,8 @@ extension _Actions on _SftpPageState {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Btn.tile(
|
Btn.tile(icon: const Icon(Icons.folder), text: libL10n.folder, onTap: _mkdir),
|
||||||
icon: const Icon(Icons.folder),
|
Btn.tile(icon: const Icon(Icons.insert_drive_file), text: libL10n.file, onTap: _newFile),
|
||||||
text: libL10n.folder,
|
|
||||||
onTap: _mkdir,
|
|
||||||
),
|
|
||||||
Btn.tile(
|
|
||||||
icon: const Icon(Icons.insert_drive_file),
|
|
||||||
text: libL10n.file,
|
|
||||||
onTap: _newFile,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -788,11 +671,9 @@ extension _Actions on _SftpPageState {
|
|||||||
if (!Stores.setting.recordHistory.fetch()) {
|
if (!Stores.setting.recordHistory.fetch()) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return Stores.history.sftpGoPath.all.cast<String>().where(
|
return Stores.history.sftpGoPath.all.cast<String>().where((e) => e.contains(val.text));
|
||||||
(element) => element.contains(val.text),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
fieldViewBuilder: (_, controller, node, __) {
|
fieldViewBuilder: (_, controller, node, _) {
|
||||||
return Input(
|
return Input(
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
icon: Icons.abc,
|
icon: Icons.abc,
|
||||||
@@ -821,10 +702,7 @@ extension _Actions on _SftpPageState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildRefreshBtn() {
|
Widget _buildRefreshBtn() {
|
||||||
return Btn.icon(
|
return Btn.icon(onTap: _listDir, icon: const Icon(Icons.refresh));
|
||||||
onTap: _listDir,
|
|
||||||
icon: const Icon(Icons.refresh),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildHomeBtn() {
|
Widget _buildHomeBtn() {
|
||||||
@@ -913,8 +791,7 @@ String _getTime(int? unixMill) {
|
|||||||
enum _SortType {
|
enum _SortType {
|
||||||
name,
|
name,
|
||||||
time,
|
time,
|
||||||
size,
|
size;
|
||||||
;
|
|
||||||
|
|
||||||
List<SftpName> sort(List<SftpName> files, {bool reversed = false}) {
|
List<SftpName> sort(List<SftpName> files, {bool reversed = false}) {
|
||||||
var comparator = ChainComparator<SftpName>.create();
|
var comparator = ChainComparator<SftpName>.create();
|
||||||
@@ -933,24 +810,10 @@ enum _SortType {
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case _SortType.time:
|
case _SortType.time:
|
||||||
files.sort(
|
files.sort(comparator.thenCompareBy<num>((x) => x.attr.modifyTime ?? 0, reversed: reversed).compare);
|
||||||
comparator
|
|
||||||
.thenCompareBy<num>(
|
|
||||||
(x) => x.attr.modifyTime ?? 0,
|
|
||||||
reversed: reversed,
|
|
||||||
)
|
|
||||||
.compare,
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
case _SortType.size:
|
case _SortType.size:
|
||||||
files.sort(
|
files.sort(comparator.thenCompareBy<num>((x) => x.attr.size ?? 0, reversed: reversed).compare);
|
||||||
comparator
|
|
||||||
.thenCompareBy<num>(
|
|
||||||
(x) => x.attr.size ?? 0,
|
|
||||||
reversed: reversed,
|
|
||||||
)
|
|
||||||
.compare,
|
|
||||||
);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return files;
|
return files;
|
||||||
@@ -963,13 +826,7 @@ class _SortOption {
|
|||||||
|
|
||||||
_SortOption({this.sortBy = _SortType.name, this.reversed = false});
|
_SortOption({this.sortBy = _SortType.name, this.reversed = false});
|
||||||
|
|
||||||
_SortOption copyWith({
|
_SortOption copyWith({_SortType? sortBy, bool? reversed}) {
|
||||||
_SortType? sortBy,
|
return _SortOption(sortBy: sortBy ?? this.sortBy, reversed: reversed ?? this.reversed);
|
||||||
bool? reversed,
|
|
||||||
}) {
|
|
||||||
return _SortOption(
|
|
||||||
sortBy: sortBy ?? this.sortBy,
|
|
||||||
reversed: reversed ?? this.reversed,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
67
pubspec.lock
67
pubspec.lock
@@ -5,26 +5,26 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _fe_analyzer_shared
|
name: _fe_analyzer_shared
|
||||||
sha256: dc27559385e905ad30838356c5f5d574014ba39872d732111cd07ac0beff4c57
|
sha256: e55636ed79578b9abca5fecf9437947798f5ef7456308b5cb85720b793eac92f
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "80.0.0"
|
version: "82.0.0"
|
||||||
analyzer:
|
analyzer:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: analyzer
|
name: analyzer
|
||||||
sha256: "192d1c5b944e7e53b24b5586db760db934b177d4147c42fbca8c8c5f1eb8d11e"
|
sha256: "904ae5bb474d32c38fb9482e2d925d5454cda04ddd0e55d2e6826bc72f6ba8c0"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.3.0"
|
version: "7.4.5"
|
||||||
analyzer_plugin:
|
analyzer_plugin:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: analyzer_plugin
|
name: analyzer_plugin
|
||||||
sha256: b3075265c5ab222f8b3188342dcb50b476286394a40323e85d1fa725035d40a4
|
sha256: ee188b6df6c85f1441497c7171c84f1392affadc0384f71089cb10a3bc508cef
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.13.0"
|
version: "0.13.1"
|
||||||
animations:
|
animations:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -189,10 +189,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: camera_android_camerax
|
name: camera_android_camerax
|
||||||
sha256: "0bd3d1645df00af2540a22df13ba466ac5fb2838a09bce4089cecdb1712a9e94"
|
sha256: "68d7ec97439108ac22cfba34bb74d0ab53adbc017175116d2cbc5a3d8fc8ea5e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.18"
|
version: "0.6.18+2"
|
||||||
camera_avfoundation:
|
camera_avfoundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -237,10 +237,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: checked_yaml
|
name: checked_yaml
|
||||||
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
|
sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.3"
|
version: "2.0.4"
|
||||||
choice:
|
choice:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -311,10 +311,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: coverage
|
name: coverage
|
||||||
sha256: "4b8701e48a58f7712492c9b1f7ba0bb9d525644dd66d023b62e1fc8cdb560c8a"
|
sha256: aa07dbe5f2294c827b7edb9a87bba44a9c15a3cc81bc8da2ca19b37322d30080
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.14.0"
|
version: "1.14.1"
|
||||||
cross_file:
|
cross_file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -351,10 +351,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: custom_lint_visitor
|
name: custom_lint_visitor
|
||||||
sha256: "36282d85714af494ee2d7da8c8913630aa6694da99f104fb2ed4afcf8fc857d8"
|
sha256: cba5b6d7a6217312472bf4468cdf68c949488aed7ffb0eab792cd0b6c435054d
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0+7.3.0"
|
version: "1.0.0+7.4.5"
|
||||||
dart_style:
|
dart_style:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -367,8 +367,8 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: "v1.0.283"
|
ref: "v1.0.285"
|
||||||
resolved-ref: f9d00c98c2047c7012f5fbce39cf01d386ca136a
|
resolved-ref: "18fb1ad15ee6d2c8c5ec67722bf8b90fe0f4746d"
|
||||||
url: "https://github.com/lollipopkit/dartssh2"
|
url: "https://github.com/lollipopkit/dartssh2"
|
||||||
source: git
|
source: git
|
||||||
version: "2.12.0"
|
version: "2.12.0"
|
||||||
@@ -432,10 +432,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: extended_image_library
|
name: extended_image_library
|
||||||
sha256: ae468c31c375064964de11cbb31310a58c4462df6e3bae1a0bc0066f586795d5
|
sha256: "1f9a24d3a00c2633891c6a7b5cab2807999eb2d5b597e5133b63f49d113811fe"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.0"
|
version: "5.0.1"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -497,8 +497,8 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: "v1.0.319"
|
ref: "v1.0.321"
|
||||||
resolved-ref: d45c47a24303a2e937fee6753f1d0755805b8483
|
resolved-ref: e0b3338be10fa71c96d017d873f5e10bb4374709
|
||||||
url: "https://github.com/lppcg/fl_lib"
|
url: "https://github.com/lppcg/fl_lib"
|
||||||
source: git
|
source: git
|
||||||
version: "0.0.1"
|
version: "0.0.1"
|
||||||
@@ -527,10 +527,10 @@ packages:
|
|||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: flutter_lints
|
name: flutter_lints
|
||||||
sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1"
|
sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.0"
|
version: "6.0.0"
|
||||||
flutter_localizations:
|
flutter_localizations:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -553,13 +553,12 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.4"
|
version: "0.3.4"
|
||||||
flutter_math_fork:
|
flutter_math_fork:
|
||||||
dependency: "direct overridden"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
path: "."
|
name: flutter_math_fork
|
||||||
ref: HEAD
|
sha256: "6d5f2f1aa57ae539ffb0a04bb39d2da67af74601d685a161aff7ce5bda5fa407"
|
||||||
resolved-ref: "2f270aee06d3ca02ca6d108420921472fd10e5cb"
|
url: "https://pub.dev"
|
||||||
url: "https://github.com/simpleclub/flutter_math"
|
source: hosted
|
||||||
source: git
|
|
||||||
version: "0.7.4"
|
version: "0.7.4"
|
||||||
flutter_native_splash:
|
flutter_native_splash:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
@@ -839,10 +838,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: lints
|
name: lints
|
||||||
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
|
sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.1.1"
|
version: "6.0.0"
|
||||||
local_auth:
|
local_auth:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1168,10 +1167,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: qr_code_dart_scan
|
name: qr_code_dart_scan
|
||||||
sha256: bc4fc6f400b4350c6946d123c7871e156459703a61f8fa57d7144df9bbb46610
|
sha256: "6e1aab64b8f5f768416b471dbc3fb0fc94969c3e236157a96b52a70f9fe12ebb"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.10.0"
|
version: "0.10.1"
|
||||||
quiver:
|
quiver:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1807,10 +1806,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: zxing_lib
|
name: zxing_lib
|
||||||
sha256: "870a63610be3f20009ca9201f7ba2d53d7eaefa675c154b3e8c1f6fc55984d04"
|
sha256: d5d81917be2e18b06a2cf4ca12927f3ab957dfbd25bd7b8175b3e9a0ce5c2e2b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.1.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.8.0 <4.0.0"
|
dart: ">=3.8.0 <4.0.0"
|
||||||
flutter: ">=3.32.1"
|
flutter: ">=3.32.1"
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ dependencies:
|
|||||||
dartssh2:
|
dartssh2:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/lollipopkit/dartssh2
|
url: https://github.com/lollipopkit/dartssh2
|
||||||
ref: v1.0.283
|
ref: v1.0.285
|
||||||
circle_chart:
|
circle_chart:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/lollipopkit/circle_chart
|
url: https://github.com/lollipopkit/circle_chart
|
||||||
@@ -62,7 +62,7 @@ dependencies:
|
|||||||
fl_lib:
|
fl_lib:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/lppcg/fl_lib
|
url: https://github.com/lppcg/fl_lib
|
||||||
ref: v1.0.319
|
ref: v1.0.321
|
||||||
|
|
||||||
dependency_overrides:
|
dependency_overrides:
|
||||||
# webdav_client_plus:
|
# webdav_client_plus:
|
||||||
@@ -75,16 +75,13 @@ dependency_overrides:
|
|||||||
# path: ../fl_lib
|
# path: ../fl_lib
|
||||||
# fl_build:
|
# fl_build:
|
||||||
# path: ../fl_build
|
# path: ../fl_build
|
||||||
flutter_math_fork: # Refer to https://github.com/simpleclub/flutter_math/issues/110
|
|
||||||
git:
|
|
||||||
url: https://github.com/simpleclub/flutter_math
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
analyzer: ^7.3.0
|
analyzer: ^7.3.0
|
||||||
flutter_native_splash: ^2.1.6
|
flutter_native_splash: ^2.1.6
|
||||||
hive_ce_generator: ^1.9.2
|
hive_ce_generator: ^1.9.2
|
||||||
build_runner: ^2.4.15
|
build_runner: ^2.4.15
|
||||||
flutter_lints: ^5.0.0
|
flutter_lints: ^6.0.0
|
||||||
json_serializable: ^6.8.0
|
json_serializable: ^6.8.0
|
||||||
freezed: ^2.5.7
|
freezed: ^2.5.7
|
||||||
riverpod_generator: ^2.6.3
|
riverpod_generator: ^2.6.3
|
||||||
|
|||||||
Reference in New Issue
Block a user