add default pool selection with validation and fallback

- extend AppSettings with defaultPoolId
- add pool filtering utility to exclude media-only pools
- add resolveDefaultPoolId with fallback to safe pool
- update SettingsScreen with default pool dropdown
- integrate uploadAttachment with default pool resolution

Signed-off-by: Texas0295 <kimura@texas0295.top>
This commit is contained in:
Texas0295
2025-09-21 16:14:57 +08:00
parent 3621ea7744
commit 1a703b7eba
3 changed files with 50 additions and 14 deletions

View File

@@ -21,6 +21,7 @@ import 'package:path_provider/path_provider.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:island/pods/config.dart'; import 'package:island/pods/config.dart';
import 'package:island/pods/pool_provider.dart'; import 'package:island/pods/pool_provider.dart';
import 'package:island/utils/pool_utils.dart';
class SettingsScreen extends HookConsumerWidget { class SettingsScreen extends HookConsumerWidget {
const SettingsScreen({super.key}); const SettingsScreen({super.key});
@@ -368,8 +369,12 @@ class SettingsScreen extends HookConsumerWidget {
), ),
), ),
), ),
poolsAsync.when( poolsAsync.when(
data: (pools) { data: (pools) {
final validPools = filterValidPools(pools);
final currentPoolId = resolveDefaultPoolId(ref, pools);
return ListTile( return ListTile(
isThreeLine: true, isThreeLine: true,
minLeadingWidth: 48, minLeadingWidth: 48,
@@ -377,29 +382,23 @@ class SettingsScreen extends HookConsumerWidget {
contentPadding: const EdgeInsets.only(left: 24, right: 17), contentPadding: const EdgeInsets.only(left: 24, right: 17),
leading: const Icon(Symbols.cloud), leading: const Icon(Symbols.cloud),
subtitle: Text( subtitle: Text(
settings.defaultPoolId != null validPools
? pools .firstWhereOrNull((p) => p.id == currentPoolId)
.firstWhereOrNull(
(p) => p.id == settings.defaultPoolId,
)
?.description ?? ?.description ??
'settingsDefaultPoolHelper'.tr() 'settingsDefaultPoolHelper'.tr(),
: 'settingsDefaultPoolHelper'.tr(),
style: Theme.of(context).textTheme.bodySmall, style: Theme.of(context).textTheme.bodySmall,
), ),
trailing: DropdownButtonHideUnderline( trailing: DropdownButtonHideUnderline(
child: DropdownButton2<String>( child: DropdownButton2<String>(
isExpanded: true, isExpanded: true,
items: items:
pools.map((p) { validPools.map((p) {
return DropdownMenuItem<String>( return DropdownMenuItem<String>(
value: p.id, value: p.id,
child: Text(p.name).fontSize(14), child: Text(p.name).fontSize(14),
); );
}).toList(), }).toList(),
value: value: currentPoolId,
settings.defaultPoolId ??
(pools.isNotEmpty ? pools.first.id : null),
onChanged: (value) { onChanged: (value) {
ref ref
.read(appSettingsNotifierProvider.notifier) .read(appSettingsNotifierProvider.notifier)

35
lib/utils/pool_utils.dart Normal file
View File

@@ -0,0 +1,35 @@
import '../models/file_pool.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import '../pods/config.dart';
List<FilePool> filterValidPools(List<FilePool> pools) {
return pools.where((p) {
final accept = p.policyConfig['accept_types'];
if (accept != null) {
final acceptsOnlyMedia = accept.every((t) =>
t.startsWith('image/') ||
t.startsWith('video/') ||
t.startsWith('audio/'));
if (acceptsOnlyMedia) return false;
}
return true;
}).toList();
}
String resolveDefaultPoolId(WidgetRef ref, List<FilePool> pools) {
final settings = ref.watch(appSettingsNotifierProvider);
final validPools = filterValidPools(pools);
if (settings.defaultPoolId != null &&
validPools.any((p) => p.id == settings.defaultPoolId)) {
return settings.defaultPoolId!;
}
if (validPools.isNotEmpty) {
return validPools.first.id;
}
// DEFAULT: Solar Network Driver
return '500e5ed8-bd44-4359-bc0a-ec85e2adf447';
}

View File

@@ -20,6 +20,8 @@ import 'package:island/widgets/alert.dart';
import 'package:island/widgets/post/compose_link_attachments.dart'; import 'package:island/widgets/post/compose_link_attachments.dart';
import 'package:island/widgets/post/compose_poll.dart'; import 'package:island/widgets/post/compose_poll.dart';
import 'package:island/widgets/post/compose_recorder.dart'; import 'package:island/widgets/post/compose_recorder.dart';
import 'package:island/pods/pool_provider.dart';
import 'package:island/utils/pool_utils.dart';
import 'package:pasteboard/pasteboard.dart'; import 'package:pasteboard/pasteboard.dart';
import 'package:textfield_tags/textfield_tags.dart'; import 'package:textfield_tags/textfield_tags.dart';
import 'dart:async'; import 'dart:async';
@@ -522,8 +524,8 @@ class ComposeLogic {
SnCloudFile? cloudFile; SnCloudFile? cloudFile;
final settings = ref.watch(appSettingsNotifierProvider); final pools = await ref.read(poolsProvider.future);
final selectedPoolId = poolId ?? settings.defaultPoolId ?? '500e5ed8-bd44-4359-bc0a-ec85e2adf447'; final selectedPoolId = resolveDefaultPoolId(ref, pools);
if (attachment.type == UniversalFileType.file) { if (attachment.type == UniversalFileType.file) {
cloudFile = cloudFile =
await putFileToPool( await putFileToPool(