#35 new: servers tab reorderable

This commit is contained in:
lollipopkit
2023-05-12 18:35:56 +08:00
parent 2ee0c6f995
commit cbeaa9705f
6 changed files with 70 additions and 41 deletions

View File

@@ -360,7 +360,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 295; CURRENT_PROJECT_VERSION = 300;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -368,7 +368,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.295; MARKETING_VERSION = 1.0.300;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -491,7 +491,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 295; CURRENT_PROJECT_VERSION = 300;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -499,7 +499,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.295; MARKETING_VERSION = 1.0.300;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -516,7 +516,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements; CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 295; CURRENT_PROJECT_VERSION = 300;
DEVELOPMENT_TEAM = BA88US33G6; DEVELOPMENT_TEAM = BA88US33G6;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist"; INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
@@ -524,7 +524,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 1.0.295; MARKETING_VERSION = 1.0.300;
PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox; PRODUCT_BUNDLE_IDENTIFIER = com.lollipopkit.toolbox;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";

View File

@@ -18,10 +18,31 @@ import '../store/server.dart';
import '../store/setting.dart'; import '../store/setting.dart';
typedef ServersMap = Map<String, Server>; typedef ServersMap = Map<String, Server>;
typedef ServerOrder = List<String>;
extension ServerOrderX on ServerOrder {
void move(int oldIndex, int newIndex) {
if (oldIndex == newIndex) return;
if (oldIndex < newIndex) {
newIndex -= 1;
}
final item = this[oldIndex];
removeAt(oldIndex);
insert(newIndex, item);
locator<SettingStore>().serverOrder.put(this);
}
void update(String id, String newId) {
final index = indexOf(id);
if (index == -1) return;
this[index] = newId;
}
}
class ServerProvider extends BusyProvider { class ServerProvider extends BusyProvider {
final ServersMap _servers = {}; final ServersMap _servers = {};
ServersMap get servers => _servers; ServersMap get servers => _servers;
final ServerOrder serverOrder = [];
final _limiter = TryLimiter(); final _limiter = TryLimiter();
@@ -29,14 +50,21 @@ class ServerProvider extends BusyProvider {
final _logger = Logger('SERVER'); final _logger = Logger('SERVER');
final _store = locator<ServerStore>(); final _serverStore = locator<ServerStore>();
final _settingStore = locator<SettingStore>();
Future<void> loadLocalData() async { Future<void> loadLocalData() async {
setBusyState(true); setBusyState(true);
final infos = _store.fetch(); final infos = _serverStore.fetch();
for (final info in infos) { for (final info in infos) {
_servers[info.id] = genServer(info); _servers[info.id] = genServer(info);
} }
final serverOrder_ = _settingStore.serverOrder.fetch();
if (serverOrder_ != null) {
serverOrder.addAll(serverOrder_);
} else {
serverOrder.addAll(_servers.keys);
}
setBusyState(false); setBusyState(false);
notifyListeners(); notifyListeners();
} }
@@ -107,14 +135,18 @@ class ServerProvider extends BusyProvider {
void addServer(ServerPrivateInfo spi) { void addServer(ServerPrivateInfo spi) {
_servers[spi.id] = genServer(spi); _servers[spi.id] = genServer(spi);
notifyListeners(); notifyListeners();
_store.put(spi); _serverStore.put(spi);
serverOrder.add(spi.id);
_settingStore.serverOrder.put(serverOrder);
refreshData(spi: spi); refreshData(spi: spi);
} }
void delServer(String id) { void delServer(String id) {
_servers.remove(id); _servers.remove(id);
serverOrder.remove(id);
_settingStore.serverOrder.put(serverOrder);
notifyListeners(); notifyListeners();
_store.delete(id); _serverStore.delete(id);
} }
Future<void> updateServer( Future<void> updateServer(
@@ -122,9 +154,11 @@ class ServerProvider extends BusyProvider {
ServerPrivateInfo newSpi, ServerPrivateInfo newSpi,
) async { ) async {
_servers.remove(old.id); _servers.remove(old.id);
_store.update(old, newSpi); _serverStore.update(old, newSpi);
_servers[newSpi.id] = genServer(newSpi); _servers[newSpi.id] = genServer(newSpi);
_servers[newSpi.id]?.client = await genClient(newSpi); _servers[newSpi.id]?.client = await genClient(newSpi);
serverOrder.update(old.id, newSpi.id);
_settingStore.serverOrder.put(serverOrder);
await refreshData(spi: newSpi); await refreshData(spi: newSpi);
} }

View File

@@ -2,8 +2,8 @@
class BuildData { class BuildData {
static const String name = "ServerBox"; static const String name = "ServerBox";
static const int build = 295; static const int build = 300;
static const String engine = "3.10.0"; static const String engine = "3.10.0";
static const String buildAt = "2023-05-11 12:17:12.803987"; static const String buildAt = "2023-05-12 16:42:47.988995";
static const int modifications = 3; static const int modifications = 1;
} }

View File

@@ -39,4 +39,8 @@ class SettingStore extends PersistentStore {
/// Backgroud running (Android) /// Backgroud running (Android)
StoreProperty<bool> get bgRun => property('bgRun', defaultValue: isAndroid); StoreProperty<bool> get bgRun => property('bgRun', defaultValue: isAndroid);
// Server order
StoreProperty<List<String>> get serverOrder =>
property('serverOrder', defaultValue: null);
} }

View File

@@ -83,7 +83,7 @@ class _ServerPageState extends State<ServerPage>
await _serverProvider.refreshData(onlyFailed: true), await _serverProvider.refreshData(onlyFailed: true),
child: Consumer<ServerProvider>( child: Consumer<ServerProvider>(
builder: (_, pro, __) { builder: (_, pro, __) {
if (pro.servers.isEmpty) { if (pro.serverOrder.isEmpty) {
return Center( return Center(
child: Text( child: Text(
_s.serverTabEmpty, _s.serverTabEmpty,
@@ -91,21 +91,15 @@ class _ServerPageState extends State<ServerPage>
), ),
); );
} }
final keys = pro.servers.keys.toList(); return ReorderableListView(
return ListView.separated(
padding: const EdgeInsets.fromLTRB(7, 10, 7, 7), padding: const EdgeInsets.fromLTRB(7, 10, 7, 7),
controller: ScrollController(),
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
itemBuilder: (ctx, idx) { onReorder: (oldIndex, newIndex) => setState(() {
if (idx == pro.servers.length) { pro.serverOrder.move(oldIndex, newIndex);
return SizedBox(height: _media.padding.bottom); }),
} children: pro.serverOrder
return _buildEachServerCard(pro.servers[keys[idx]]); .map((e) => _buildEachServerCard(pro.servers[e]))
}, .toList(),
itemCount: pro.servers.length,
separatorBuilder: (_, __) => const SizedBox(
height: 3,
),
); );
}, },
), ),
@@ -116,21 +110,18 @@ class _ServerPageState extends State<ServerPage>
if (si == null) { if (si == null) {
return const SizedBox(); return const SizedBox();
} }
return GestureDetector( return RoundRectCard(
onLongPress: () => AppRoute( GestureDetector(
ServerEditPage(spi: si.spi), child: Padding(
'Edit server info page',
).go(context),
child: RoundRectCard(
Padding(
padding: const EdgeInsets.all(13), padding: const EdgeInsets.all(13),
child: _buildRealServerCard(si.status, si.spi.name, si.state, si.spi), child: _buildRealServerCard(si.status, si.spi.name, si.state, si.spi),
), ),
),
onTap: () => AppRoute( onTap: () => AppRoute(
ServerDetailPage(si.spi.id), ServerDetailPage(si.spi.id),
'server detail page', 'server detail page',
).go(context), ).go(context),
),
key: Key(si.spi.id),
); );
} }

View File

@@ -10,7 +10,7 @@ PODS:
DEPENDENCIES: DEPENDENCIES:
- FlutterMacOS (from `Flutter/ephemeral`) - FlutterMacOS (from `Flutter/ephemeral`)
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos`) - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
- share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
@@ -18,7 +18,7 @@ EXTERNAL SOURCES:
FlutterMacOS: FlutterMacOS:
:path: Flutter/ephemeral :path: Flutter/ephemeral
path_provider_foundation: path_provider_foundation:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/macos :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
share_plus: share_plus:
:path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos :path: Flutter/ephemeral/.symlinks/plugins/share_plus/macos
url_launcher_macos: url_launcher_macos: