mirror of
https://github.com/immich-app/immich.git
synced 2025-12-17 01:11:13 +03:00
chore: bump dart sdk to 3.8 (#20355)
* chore: bump dart sdk to 3.8 * chore: make build * make pigeon * chore: format files --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
@@ -34,10 +34,7 @@ class AdvancedSettings extends HookConsumerWidget {
|
||||
|
||||
final logLevel = Level.LEVELS[levelId.value].name;
|
||||
|
||||
useValueChanged(
|
||||
levelId.value,
|
||||
(_, __) => LogService.I.setLogLevel(Level.LEVELS[levelId.value].toLogLevel()),
|
||||
);
|
||||
useValueChanged(levelId.value, (_, __) => LogService.I.setLogLevel(Level.LEVELS[levelId.value].toLogLevel()));
|
||||
|
||||
Future<bool> checkAndroidVersion() async {
|
||||
if (Platform.isAndroid) {
|
||||
|
||||
@@ -11,9 +11,7 @@ import 'package:immich_mobile/widgets/settings/settings_radio_list_tile.dart';
|
||||
import 'package:immich_mobile/widgets/settings/settings_sub_title.dart';
|
||||
|
||||
class GroupSettings extends HookConsumerWidget {
|
||||
const GroupSettings({
|
||||
super.key,
|
||||
});
|
||||
const GroupSettings({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@@ -21,10 +19,7 @@ class GroupSettings extends HookConsumerWidget {
|
||||
final groupBy = GroupAssetsBy.values[groupByIndex.value];
|
||||
|
||||
Future<void> updateAppSettings(GroupAssetsBy groupBy) async {
|
||||
await ref.watch(appSettingsServiceProvider).setSetting(
|
||||
AppSettingsEnum.groupAssetsBy,
|
||||
groupBy.index,
|
||||
);
|
||||
await ref.watch(appSettingsServiceProvider).setSetting(AppSettingsEnum.groupAssetsBy, groupBy.index);
|
||||
ref.invalidate(appSettingsServiceProvider);
|
||||
}
|
||||
|
||||
@@ -41,18 +36,9 @@ class GroupSettings extends HookConsumerWidget {
|
||||
SettingsSubTitle(title: "asset_list_group_by_sub_title".tr()),
|
||||
SettingsRadioListTile(
|
||||
groups: [
|
||||
SettingsRadioGroup(
|
||||
title: 'asset_list_layout_settings_group_by_month_day'.tr(),
|
||||
value: GroupAssetsBy.day,
|
||||
),
|
||||
SettingsRadioGroup(
|
||||
title: 'month'.tr(),
|
||||
value: GroupAssetsBy.month,
|
||||
),
|
||||
SettingsRadioGroup(
|
||||
title: 'asset_list_layout_settings_group_automatically'.tr(),
|
||||
value: GroupAssetsBy.auto,
|
||||
),
|
||||
SettingsRadioGroup(title: 'asset_list_layout_settings_group_by_month_day'.tr(), value: GroupAssetsBy.day),
|
||||
SettingsRadioGroup(title: 'month'.tr(), value: GroupAssetsBy.month),
|
||||
SettingsRadioGroup(title: 'asset_list_layout_settings_group_automatically'.tr(), value: GroupAssetsBy.auto),
|
||||
],
|
||||
groupBy: groupBy,
|
||||
onRadioChanged: changeGroupValue,
|
||||
|
||||
@@ -9,9 +9,7 @@ import 'package:immich_mobile/widgets/settings/settings_sub_title.dart';
|
||||
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
|
||||
|
||||
class LayoutSettings extends HookConsumerWidget {
|
||||
const LayoutSettings({
|
||||
super.key,
|
||||
});
|
||||
const LayoutSettings({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
||||
@@ -10,9 +10,7 @@ import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
|
||||
import 'asset_list_layout_settings.dart';
|
||||
|
||||
class AssetListSettings extends HookConsumerWidget {
|
||||
const AssetListSettings({
|
||||
super.key,
|
||||
});
|
||||
const AssetListSettings({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@@ -28,9 +26,6 @@ class AssetListSettings extends HookConsumerWidget {
|
||||
const GroupSettings(),
|
||||
];
|
||||
|
||||
return SettingsSubPageScaffold(
|
||||
settings: assetListSetting,
|
||||
showDivider: true,
|
||||
);
|
||||
return SettingsSubPageScaffold(settings: assetListSetting, showDivider: true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,20 +4,12 @@ import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart';
|
||||
import 'video_viewer_settings.dart';
|
||||
|
||||
class AssetViewerSettings extends StatelessWidget {
|
||||
const AssetViewerSettings({
|
||||
super.key,
|
||||
});
|
||||
const AssetViewerSettings({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final assetViewerSetting = [
|
||||
const ImageViewerQualitySetting(),
|
||||
const VideoViewerSettings(),
|
||||
];
|
||||
final assetViewerSetting = [const ImageViewerQualitySetting(), const VideoViewerSettings()];
|
||||
|
||||
return SettingsSubPageScaffold(
|
||||
settings: assetViewerSetting,
|
||||
showDivider: true,
|
||||
);
|
||||
return SettingsSubPageScaffold(settings: assetViewerSetting, showDivider: true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,7 @@ import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
|
||||
import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
|
||||
|
||||
class ImageViewerQualitySetting extends HookConsumerWidget {
|
||||
const ImageViewerQualitySetting({
|
||||
super.key,
|
||||
});
|
||||
const ImageViewerQualitySetting({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@@ -24,10 +22,7 @@ class ImageViewerQualitySetting extends HookConsumerWidget {
|
||||
SettingsSubTitle(title: "setting_image_viewer_title".tr()),
|
||||
ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
title: Text(
|
||||
'setting_image_viewer_help',
|
||||
style: context.textTheme.bodyMedium,
|
||||
).tr(),
|
||||
title: Text('setting_image_viewer_help', style: context.textTheme.bodyMedium).tr(),
|
||||
),
|
||||
SettingsSwitchListTile(
|
||||
valueNotifier: isPreview,
|
||||
|
||||
@@ -8,9 +8,7 @@ import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
|
||||
import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
|
||||
|
||||
class VideoViewerSettings extends HookConsumerWidget {
|
||||
const VideoViewerSettings({
|
||||
super.key,
|
||||
});
|
||||
const VideoViewerSettings({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
||||
@@ -24,12 +24,7 @@ class BackgroundBackupSettings extends ConsumerWidget {
|
||||
|
||||
void showErrorToUser(String msg) {
|
||||
final snackBar = SnackBar(
|
||||
content: Text(
|
||||
msg.tr(),
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
color: context.primaryColor,
|
||||
),
|
||||
),
|
||||
content: Text(msg.tr(), style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor)),
|
||||
backgroundColor: Colors.red,
|
||||
);
|
||||
context.scaffoldMessenger.showSnackBar(snackBar);
|
||||
@@ -41,20 +36,14 @@ class BackgroundBackupSettings extends ConsumerWidget {
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext ctx) {
|
||||
return AlertDialog(
|
||||
title: const Text(
|
||||
'backup_controller_page_background_battery_info_title',
|
||||
).tr(),
|
||||
title: const Text('backup_controller_page_background_battery_info_title').tr(),
|
||||
content: SingleChildScrollView(
|
||||
child: const Text(
|
||||
'backup_controller_page_background_battery_info_message',
|
||||
).tr(),
|
||||
child: const Text('backup_controller_page_background_battery_info_message').tr(),
|
||||
),
|
||||
actions: [
|
||||
ElevatedButton(
|
||||
onPressed: () => launchUrl(
|
||||
Uri.parse('https://dontkillmyapp.com'),
|
||||
mode: LaunchMode.externalApplication,
|
||||
),
|
||||
onPressed: () =>
|
||||
launchUrl(Uri.parse('https://dontkillmyapp.com'), mode: LaunchMode.externalApplication),
|
||||
child: const Text(
|
||||
"backup_controller_page_background_battery_info_link",
|
||||
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
|
||||
@@ -79,7 +68,9 @@ class BackgroundBackupSettings extends ConsumerWidget {
|
||||
title: 'backup_controller_page_background_is_off'.tr(),
|
||||
subtileText: 'backup_controller_page_background_description'.tr(),
|
||||
buttonText: 'backup_controller_page_background_turn_on'.tr(),
|
||||
onButtonTap: () => ref.read(backupProvider.notifier).configureBackgroundBackup(
|
||||
onButtonTap: () => ref
|
||||
.read(backupProvider.notifier)
|
||||
.configureBackgroundBackup(
|
||||
enabled: true,
|
||||
onError: showErrorToUser,
|
||||
onBatteryInfo: showBatteryOptimizationInfoToUser,
|
||||
@@ -90,10 +81,7 @@ class BackgroundBackupSettings extends ConsumerWidget {
|
||||
return Column(
|
||||
children: [
|
||||
if (!Platform.isIOS || iosSettings?.appRefreshEnabled == true)
|
||||
_BackgroundSettingsEnabled(
|
||||
onError: showErrorToUser,
|
||||
onBatteryInfo: showBatteryOptimizationInfoToUser,
|
||||
),
|
||||
_BackgroundSettingsEnabled(onError: showErrorToUser, onBatteryInfo: showBatteryOptimizationInfoToUser),
|
||||
if (Platform.isIOS && iosSettings?.appRefreshEnabled != true) const _IOSBackgroundRefreshDisabled(),
|
||||
if (Platform.isIOS && iosSettings != null) IosDebugInfoTile(settings: iosSettings),
|
||||
],
|
||||
@@ -120,10 +108,7 @@ class _BackgroundSettingsEnabled extends HookConsumerWidget {
|
||||
final void Function(String msg) onError;
|
||||
final void Function() onBatteryInfo;
|
||||
|
||||
const _BackgroundSettingsEnabled({
|
||||
required this.onError,
|
||||
required this.onBatteryInfo,
|
||||
});
|
||||
const _BackgroundSettingsEnabled({required this.onError, required this.onBatteryInfo});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@@ -131,41 +116,45 @@ class _BackgroundSettingsEnabled extends HookConsumerWidget {
|
||||
final isWifiRequiredNotifier = useValueNotifier(isWifiRequired);
|
||||
useValueChanged(
|
||||
isWifiRequired,
|
||||
(_, __) => WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) => isWifiRequiredNotifier.value = isWifiRequired,
|
||||
),
|
||||
(_, __) => WidgetsBinding.instance.addPostFrameCallback((_) => isWifiRequiredNotifier.value = isWifiRequired),
|
||||
);
|
||||
|
||||
final isChargingRequired = ref.watch(backupProvider.select((s) => s.backupRequireCharging));
|
||||
final isChargingRequiredNotifier = useValueNotifier(isChargingRequired);
|
||||
useValueChanged(
|
||||
isChargingRequired,
|
||||
(_, __) => WidgetsBinding.instance.addPostFrameCallback(
|
||||
(_) => isChargingRequiredNotifier.value = isChargingRequired,
|
||||
),
|
||||
(_, __) =>
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => isChargingRequiredNotifier.value = isChargingRequired),
|
||||
);
|
||||
|
||||
int backupDelayToSliderValue(int ms) => switch (ms) {
|
||||
5000 => 0,
|
||||
30000 => 1,
|
||||
120000 => 2,
|
||||
_ => 3,
|
||||
};
|
||||
5000 => 0,
|
||||
30000 => 1,
|
||||
120000 => 2,
|
||||
_ => 3,
|
||||
};
|
||||
|
||||
int backupDelayToMilliseconds(int v) => switch (v) { 0 => 5000, 1 => 30000, 2 => 120000, _ => 600000 };
|
||||
int backupDelayToMilliseconds(int v) => switch (v) {
|
||||
0 => 5000,
|
||||
1 => 30000,
|
||||
2 => 120000,
|
||||
_ => 600000,
|
||||
};
|
||||
|
||||
String formatBackupDelaySliderValue(int v) => switch (v) {
|
||||
0 => 'setting_notifications_notify_seconds'.tr(namedArgs: {'count': '5'}),
|
||||
1 => 'setting_notifications_notify_seconds'.tr(namedArgs: {'count': '30'}),
|
||||
2 => 'setting_notifications_notify_minutes'.tr(namedArgs: {'count': '2'}),
|
||||
_ => 'setting_notifications_notify_minutes'.tr(namedArgs: {'count': '10'}),
|
||||
};
|
||||
0 => 'setting_notifications_notify_seconds'.tr(namedArgs: {'count': '5'}),
|
||||
1 => 'setting_notifications_notify_seconds'.tr(namedArgs: {'count': '30'}),
|
||||
2 => 'setting_notifications_notify_minutes'.tr(namedArgs: {'count': '2'}),
|
||||
_ => 'setting_notifications_notify_minutes'.tr(namedArgs: {'count': '10'}),
|
||||
};
|
||||
|
||||
final backupTriggerDelay = ref.watch(backupProvider.select((s) => s.backupTriggerDelay));
|
||||
final triggerDelay = useState(backupDelayToSliderValue(backupTriggerDelay));
|
||||
useValueChanged(
|
||||
triggerDelay.value,
|
||||
(_, __) => ref.read(backupProvider.notifier).configureBackgroundBackup(
|
||||
(_, __) => ref
|
||||
.read(backupProvider.notifier)
|
||||
.configureBackgroundBackup(
|
||||
triggerDelay: backupDelayToMilliseconds(triggerDelay.value),
|
||||
onError: onError,
|
||||
onBatteryInfo: onBatteryInfo,
|
||||
@@ -177,40 +166,32 @@ class _BackgroundSettingsEnabled extends HookConsumerWidget {
|
||||
iconColor: context.primaryColor,
|
||||
title: 'backup_controller_page_background_is_on'.tr(),
|
||||
buttonText: 'backup_controller_page_background_turn_off'.tr(),
|
||||
onButtonTap: () => ref.read(backupProvider.notifier).configureBackgroundBackup(
|
||||
enabled: false,
|
||||
onError: onError,
|
||||
onBatteryInfo: onBatteryInfo,
|
||||
),
|
||||
onButtonTap: () => ref
|
||||
.read(backupProvider.notifier)
|
||||
.configureBackgroundBackup(enabled: false, onError: onError, onBatteryInfo: onBatteryInfo),
|
||||
subtitle: Column(
|
||||
children: [
|
||||
SettingsSwitchListTile(
|
||||
valueNotifier: isWifiRequiredNotifier,
|
||||
title: 'backup_controller_page_background_wifi'.tr(),
|
||||
icon: Icons.wifi,
|
||||
onChanged: (enabled) => ref.read(backupProvider.notifier).configureBackgroundBackup(
|
||||
requireWifi: enabled,
|
||||
onError: onError,
|
||||
onBatteryInfo: onBatteryInfo,
|
||||
),
|
||||
onChanged: (enabled) => ref
|
||||
.read(backupProvider.notifier)
|
||||
.configureBackgroundBackup(requireWifi: enabled, onError: onError, onBatteryInfo: onBatteryInfo),
|
||||
),
|
||||
SettingsSwitchListTile(
|
||||
valueNotifier: isChargingRequiredNotifier,
|
||||
title: 'backup_controller_page_background_charging'.tr(),
|
||||
icon: Icons.charging_station,
|
||||
onChanged: (enabled) => ref.read(backupProvider.notifier).configureBackgroundBackup(
|
||||
requireCharging: enabled,
|
||||
onError: onError,
|
||||
onBatteryInfo: onBatteryInfo,
|
||||
),
|
||||
onChanged: (enabled) => ref
|
||||
.read(backupProvider.notifier)
|
||||
.configureBackgroundBackup(requireCharging: enabled, onError: onError, onBatteryInfo: onBatteryInfo),
|
||||
),
|
||||
if (Platform.isAndroid)
|
||||
SettingsSliderListTile(
|
||||
valueNotifier: triggerDelay,
|
||||
text: 'backup_controller_page_background_delay'.tr(
|
||||
namedArgs: {
|
||||
'duration': formatBackupDelaySliderValue(triggerDelay.value),
|
||||
},
|
||||
namedArgs: {'duration': formatBackupDelaySliderValue(triggerDelay.value)},
|
||||
),
|
||||
maxValue: 3.0,
|
||||
noDivisons: 3,
|
||||
|
||||
@@ -15,9 +15,7 @@ import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
|
||||
import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
|
||||
|
||||
class BackupSettings extends HookConsumerWidget {
|
||||
const BackupSettings({
|
||||
super.key,
|
||||
});
|
||||
const BackupSettings({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@@ -71,22 +69,14 @@ class BackupSettings extends HookConsumerWidget {
|
||||
SettingsButtonListTile(
|
||||
icon: Icons.photo_album_outlined,
|
||||
title: 'sync_albums'.tr(),
|
||||
subtitle: Text(
|
||||
"sync_albums_manual_subtitle".tr(),
|
||||
),
|
||||
subtitle: Text("sync_albums_manual_subtitle".tr()),
|
||||
buttonText: 'sync_albums'.tr(),
|
||||
child: isAlbumSyncInProgress.value
|
||||
? const CircularProgressIndicator()
|
||||
: ElevatedButton(
|
||||
onPressed: syncAlbums,
|
||||
child: Text('sync'.tr()),
|
||||
),
|
||||
: ElevatedButton(onPressed: syncAlbums, child: Text('sync'.tr())),
|
||||
),
|
||||
];
|
||||
|
||||
return SettingsSubPageScaffold(
|
||||
settings: backupSettings,
|
||||
showDivider: true,
|
||||
);
|
||||
return SettingsSubPageScaffold(settings: backupSettings, showDivider: true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,7 @@ import 'package:path_provider/path_provider.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
class BetaSyncSettings extends HookConsumerWidget {
|
||||
const BetaSyncSettings({
|
||||
super.key,
|
||||
});
|
||||
const BetaSyncSettings({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@@ -35,17 +33,11 @@ class BetaSyncSettings extends HookConsumerWidget {
|
||||
final memoryCount = memoryService.getCount();
|
||||
final getLocalHashedCount = assetService.getLocalHashedCount();
|
||||
|
||||
return await Future.wait([
|
||||
assetCounts,
|
||||
localAlbumCounts,
|
||||
remoteAlbumCounts,
|
||||
memoryCount,
|
||||
getLocalHashedCount,
|
||||
]);
|
||||
return await Future.wait([assetCounts, localAlbumCounts, remoteAlbumCounts, memoryCount, getLocalHashedCount]);
|
||||
}
|
||||
|
||||
Future<void> resetDatabase() async {
|
||||
// https://github.com/simolus3/drift/commit/bd80a46264b6dd833ef4fd87fffc03f5a832ab41#diff-3f879e03b4a35779344ef16170b9353608dd9c42385f5402ec6035aac4dd8a04R76-R94
|
||||
// https://github.com/simolus3/drift/commit/bd80a46264b6dd833ef4fd87fffc03f5a832ab41#diff-3f879e03b4a35779344ef16170b9353608dd9c42385f5402ec6035aac4dd8a04R76-R94
|
||||
final drift = ref.read(driftProvider);
|
||||
final database = drift.attachedDatabase;
|
||||
await database.exclusively(() async {
|
||||
@@ -62,14 +54,10 @@ class BetaSyncSettings extends HookConsumerWidget {
|
||||
database.resolvedEngine.executor,
|
||||
drift_db.OpeningDetails(null, database.schemaVersion),
|
||||
);
|
||||
await database.customStatement(
|
||||
'PRAGMA user_version = ${database.schemaVersion}',
|
||||
);
|
||||
await database.customStatement('PRAGMA user_version = ${database.schemaVersion}');
|
||||
|
||||
// Refresh all stream queries
|
||||
database.notifyUpdates({
|
||||
for (final table in database.allTables) drift_db.TableUpdate.onTable(table),
|
||||
});
|
||||
database.notifyUpdates({for (final table in database.allTables) drift_db.TableUpdate.onTable(table)});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -83,28 +71,18 @@ class BetaSyncSettings extends HookConsumerWidget {
|
||||
if (!await dbFile.exists()) {
|
||||
if (context.mounted) {
|
||||
context.scaffoldMessenger.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text("Database file not found".t(context: context)),
|
||||
),
|
||||
SnackBar(content: Text("Database file not found".t(context: context))),
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final timestamp = DateTime.now().millisecondsSinceEpoch;
|
||||
final exportFile = File(
|
||||
path.join(
|
||||
documentsDir.path,
|
||||
'immich_export_$timestamp.sqlite',
|
||||
),
|
||||
);
|
||||
final exportFile = File(path.join(documentsDir.path, 'immich_export_$timestamp.sqlite'));
|
||||
|
||||
await dbFile.copy(exportFile.path);
|
||||
|
||||
await Share.shareXFiles(
|
||||
[XFile(exportFile.path)],
|
||||
text: 'Immich Database Export',
|
||||
);
|
||||
await Share.shareXFiles([XFile(exportFile.path)], text: 'Immich Database Export');
|
||||
|
||||
Future.delayed(const Duration(seconds: 30), () async {
|
||||
if (await exportFile.exists()) {
|
||||
@@ -114,17 +92,13 @@ class BetaSyncSettings extends HookConsumerWidget {
|
||||
|
||||
if (context.mounted) {
|
||||
context.scaffoldMessenger.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text("Database exported successfully".t(context: context)),
|
||||
),
|
||||
SnackBar(content: Text("Database exported successfully".t(context: context))),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
context.scaffoldMessenger.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text("Failed to export database: $e".t(context: context)),
|
||||
),
|
||||
SnackBar(content: Text("Failed to export database: $e".t(context: context))),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -225,27 +199,17 @@ class BetaSyncSettings extends HookConsumerWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
const Divider(
|
||||
height: 1,
|
||||
indent: 16,
|
||||
endIndent: 16,
|
||||
),
|
||||
const Divider(height: 1, indent: 16, endIndent: 16),
|
||||
const SizedBox(height: 24),
|
||||
_SectionHeaderText(text: "jobs".t(context: context)),
|
||||
ListTile(
|
||||
title: Text(
|
||||
"sync_local".t(context: context),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
"tap_to_run_job".t(context: context),
|
||||
style: const TextStyle(fontWeight: FontWeight.w500),
|
||||
),
|
||||
subtitle: Text("tap_to_run_job".t(context: context)),
|
||||
leading: const Icon(Icons.sync),
|
||||
trailing: _SyncStatusIcon(
|
||||
status: ref.watch(syncStatusProvider).localSyncStatus,
|
||||
),
|
||||
trailing: _SyncStatusIcon(status: ref.watch(syncStatusProvider).localSyncStatus),
|
||||
onTap: () {
|
||||
ref.read(backgroundSyncProvider).syncLocal(full: true);
|
||||
},
|
||||
@@ -253,17 +217,11 @@ class BetaSyncSettings extends HookConsumerWidget {
|
||||
ListTile(
|
||||
title: Text(
|
||||
"sync_remote".t(context: context),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
"tap_to_run_job".t(context: context),
|
||||
style: const TextStyle(fontWeight: FontWeight.w500),
|
||||
),
|
||||
subtitle: Text("tap_to_run_job".t(context: context)),
|
||||
leading: const Icon(Icons.cloud_sync),
|
||||
trailing: _SyncStatusIcon(
|
||||
status: ref.watch(syncStatusProvider).remoteSyncStatus,
|
||||
),
|
||||
trailing: _SyncStatusIcon(status: ref.watch(syncStatusProvider).remoteSyncStatus),
|
||||
onTap: () {
|
||||
ref.read(backgroundSyncProvider).syncRemote();
|
||||
},
|
||||
@@ -271,64 +229,40 @@ class BetaSyncSettings extends HookConsumerWidget {
|
||||
ListTile(
|
||||
title: Text(
|
||||
"hash_asset".t(context: context),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
style: const TextStyle(fontWeight: FontWeight.w500),
|
||||
),
|
||||
leading: const Icon(Icons.tag),
|
||||
subtitle: Text(
|
||||
"tap_to_run_job".t(context: context),
|
||||
),
|
||||
trailing: _SyncStatusIcon(
|
||||
status: ref.watch(syncStatusProvider).hashJobStatus,
|
||||
),
|
||||
subtitle: Text("tap_to_run_job".t(context: context)),
|
||||
trailing: _SyncStatusIcon(status: ref.watch(syncStatusProvider).hashJobStatus),
|
||||
onTap: () {
|
||||
ref.read(backgroundSyncProvider).hashAssets();
|
||||
},
|
||||
),
|
||||
const Divider(
|
||||
height: 1,
|
||||
indent: 16,
|
||||
endIndent: 16,
|
||||
),
|
||||
const Divider(height: 1, indent: 16, endIndent: 16),
|
||||
const SizedBox(height: 24),
|
||||
_SectionHeaderText(text: "actions".t(context: context)),
|
||||
ListTile(
|
||||
title: Text(
|
||||
"export_database".t(context: context),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
"export_database_description".t(context: context),
|
||||
style: const TextStyle(fontWeight: FontWeight.w500),
|
||||
),
|
||||
subtitle: Text("export_database_description".t(context: context)),
|
||||
leading: const Icon(Icons.download),
|
||||
onTap: exportDatabase,
|
||||
),
|
||||
ListTile(
|
||||
title: Text(
|
||||
"reset_sqlite".t(context: context),
|
||||
style: TextStyle(
|
||||
color: context.colorScheme.error,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
leading: Icon(
|
||||
Icons.settings_backup_restore_rounded,
|
||||
color: context.colorScheme.error,
|
||||
style: TextStyle(color: context.colorScheme.error, fontWeight: FontWeight.w500),
|
||||
),
|
||||
leading: Icon(Icons.settings_backup_restore_rounded, color: context.colorScheme.error),
|
||||
onTap: () async {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
"reset_sqlite".t(context: context),
|
||||
),
|
||||
content: Text(
|
||||
"reset_sqlite_confirmation".t(context: context),
|
||||
),
|
||||
title: Text("reset_sqlite".t(context: context)),
|
||||
content: Text("reset_sqlite_confirmation".t(context: context)),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => context.pop(),
|
||||
@@ -339,18 +273,12 @@ class BetaSyncSettings extends HookConsumerWidget {
|
||||
await resetDatabase();
|
||||
context.pop();
|
||||
context.scaffoldMessenger.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
"reset_sqlite_success".t(context: context),
|
||||
),
|
||||
),
|
||||
SnackBar(content: Text("reset_sqlite_success".t(context: context))),
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
"confirm".t(context: context),
|
||||
style: TextStyle(
|
||||
color: context.colorScheme.error,
|
||||
),
|
||||
style: TextStyle(color: context.colorScheme.error),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -370,31 +298,15 @@ class BetaSyncSettings extends HookConsumerWidget {
|
||||
class _SyncStatusIcon extends StatelessWidget {
|
||||
final SyncStatus status;
|
||||
|
||||
const _SyncStatusIcon({
|
||||
required this.status,
|
||||
});
|
||||
const _SyncStatusIcon({required this.status});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return switch (status) {
|
||||
SyncStatus.idle => const Icon(
|
||||
Icons.pause_circle_outline_rounded,
|
||||
),
|
||||
SyncStatus.syncing => const SizedBox(
|
||||
height: 24,
|
||||
width: 24,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
),
|
||||
),
|
||||
SyncStatus.success => const Icon(
|
||||
Icons.check_circle_outline,
|
||||
color: Colors.green,
|
||||
),
|
||||
SyncStatus.error => Icon(
|
||||
Icons.error_outline,
|
||||
color: context.colorScheme.error,
|
||||
),
|
||||
SyncStatus.idle => const Icon(Icons.pause_circle_outline_rounded),
|
||||
SyncStatus.syncing => const SizedBox(height: 24, width: 24, child: CircularProgressIndicator(strokeWidth: 2)),
|
||||
SyncStatus.success => const Icon(Icons.check_circle_outline, color: Colors.green),
|
||||
SyncStatus.error => Icon(Icons.error_outline, color: context.colorScheme.error),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -402,9 +314,7 @@ class _SyncStatusIcon extends StatelessWidget {
|
||||
class _SectionHeaderText extends StatelessWidget {
|
||||
final String text;
|
||||
|
||||
const _SectionHeaderText({
|
||||
required this.text,
|
||||
});
|
||||
const _SectionHeaderText({required this.text});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
@@ -7,12 +7,7 @@ class EntitiyCountTile extends StatelessWidget {
|
||||
final String label;
|
||||
final IconData icon;
|
||||
|
||||
const EntitiyCountTile({
|
||||
super.key,
|
||||
required this.count,
|
||||
required this.label,
|
||||
required this.icon,
|
||||
});
|
||||
const EntitiyCountTile({super.key, required this.count, required this.label, required this.icon});
|
||||
|
||||
String zeroPadding(int number, int targetWidth) {
|
||||
final numStr = number.toString();
|
||||
@@ -31,10 +26,7 @@ class EntitiyCountTile extends StatelessWidget {
|
||||
decoration: BoxDecoration(
|
||||
color: context.colorScheme.surfaceContainerLow,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||
border: Border.all(
|
||||
width: 0.5,
|
||||
color: context.colorScheme.outline.withAlpha(25),
|
||||
),
|
||||
border: Border.all(width: 0.5, color: context.colorScheme.outline.withAlpha(25)),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -44,18 +36,11 @@ class EntitiyCountTile extends StatelessWidget {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
color: context.primaryColor,
|
||||
),
|
||||
Icon(icon, color: context.primaryColor),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color: context.primaryColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
style: TextStyle(color: context.primaryColor, fontWeight: FontWeight.bold, fontSize: 16),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -66,23 +51,15 @@ class EntitiyCountTile extends StatelessWidget {
|
||||
final maxDigits = calculateMaxDigits(constraints.maxWidth);
|
||||
return RichText(
|
||||
text: TextSpan(
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'OverpassMono',
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
style: const TextStyle(fontSize: 18, fontFamily: 'OverpassMono', fontWeight: FontWeight.w600),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: zeroPadding(count, maxDigits),
|
||||
style: TextStyle(
|
||||
color: context.colorScheme.onSurfaceSecondary.withAlpha(75),
|
||||
),
|
||||
style: TextStyle(color: context.colorScheme.onSurfaceSecondary.withAlpha(75)),
|
||||
),
|
||||
TextSpan(
|
||||
text: count.toString(),
|
||||
style: TextStyle(
|
||||
color: context.primaryColor,
|
||||
),
|
||||
style: TextStyle(color: context.primaryColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -13,9 +13,7 @@ import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/services/app_settings.service.dart';
|
||||
|
||||
class BetaTimelineListTile extends ConsumerStatefulWidget {
|
||||
const BetaTimelineListTile({
|
||||
super.key,
|
||||
});
|
||||
const BetaTimelineListTile({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState<BetaTimelineListTile> createState() => _BetaTimelineListTileState();
|
||||
@@ -30,31 +28,22 @@ class _BetaTimelineListTileState extends ConsumerState<BetaTimelineListTile> wit
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_animationController = AnimationController(
|
||||
duration: const Duration(seconds: 3),
|
||||
vsync: this,
|
||||
);
|
||||
_animationController = AnimationController(duration: const Duration(seconds: 3), vsync: this);
|
||||
|
||||
_rotationAnimation = Tween<double>(begin: 0, end: 2 * math.pi).animate(
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: Curves.linear,
|
||||
),
|
||||
);
|
||||
_rotationAnimation = Tween<double>(
|
||||
begin: 0,
|
||||
end: 2 * math.pi,
|
||||
).animate(CurvedAnimation(parent: _animationController, curve: Curves.linear));
|
||||
|
||||
_pulseAnimation = Tween<double>(begin: 1, end: 1.1).animate(
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: Curves.easeInOut,
|
||||
),
|
||||
);
|
||||
_pulseAnimation = Tween<double>(
|
||||
begin: 1,
|
||||
end: 1.1,
|
||||
).animate(CurvedAnimation(parent: _animationController, curve: Curves.easeInOut));
|
||||
|
||||
_gradientAnimation = Tween<double>(begin: 0, end: 1).animate(
|
||||
CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: Curves.easeInOut,
|
||||
),
|
||||
);
|
||||
_gradientAnimation = Tween<double>(
|
||||
begin: 0,
|
||||
end: 1,
|
||||
).animate(CurvedAnimation(parent: _animationController, curve: Curves.easeInOut));
|
||||
|
||||
_animationController.repeat(reverse: true);
|
||||
}
|
||||
@@ -85,12 +74,8 @@ class _BetaTimelineListTileState extends ConsumerState<BetaTimelineListTile> wit
|
||||
return AlertDialog(
|
||||
title: value ? const Text("Enable Beta Timeline") : const Text("Disable Beta Timeline"),
|
||||
content: value
|
||||
? const Text(
|
||||
"Are you sure you want to enable the beta timeline?",
|
||||
)
|
||||
: const Text(
|
||||
"Are you sure you want to disable the beta timeline?",
|
||||
),
|
||||
? const Text("Are you sure you want to enable the beta timeline?")
|
||||
: const Text("Are you sure you want to disable the beta timeline?"),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
@@ -98,27 +83,16 @@ class _BetaTimelineListTileState extends ConsumerState<BetaTimelineListTile> wit
|
||||
},
|
||||
child: Text(
|
||||
"cancel".t(context: context),
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: context.colorScheme.outline,
|
||||
),
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: context.colorScheme.outline),
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
await ref.read(appSettingsServiceProvider).setSetting(
|
||||
AppSettingsEnum.betaTimeline,
|
||||
value,
|
||||
);
|
||||
context.router.replaceAll(
|
||||
[ChangeExperienceRoute(switchingToBeta: value)],
|
||||
);
|
||||
await ref.read(appSettingsServiceProvider).setSetting(AppSettingsEnum.betaTimeline, value);
|
||||
context.router.replaceAll([ChangeExperienceRoute(switchingToBeta: value)]);
|
||||
},
|
||||
child: Text(
|
||||
"ok".t(context: context),
|
||||
),
|
||||
child: Text("ok".t(context: context)),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -156,11 +130,7 @@ class _BetaTimelineListTileState extends ConsumerState<BetaTimelineListTile> wit
|
||||
transform: GradientRotation(_rotationAnimation.value * 0.5),
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: context.primaryColor.withValues(alpha: 0.1),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
BoxShadow(color: context.primaryColor.withValues(alpha: 0.1), blurRadius: 8, offset: const Offset(0, 2)),
|
||||
],
|
||||
),
|
||||
child: Container(
|
||||
@@ -193,11 +163,7 @@ class _BetaTimelineListTileState extends ConsumerState<BetaTimelineListTile> wit
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.auto_awesome,
|
||||
color: context.primaryColor,
|
||||
size: 20,
|
||||
),
|
||||
child: Icon(Icons.auto_awesome, color: context.primaryColor, size: 20),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -211,20 +177,13 @@ class _BetaTimelineListTileState extends ConsumerState<BetaTimelineListTile> wit
|
||||
children: [
|
||||
Text(
|
||||
"advanced_settings_beta_timeline_title".t(context: context),
|
||||
style: context.textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
style: context.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 2,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(8),
|
||||
),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
context.primaryColor.withValues(alpha: 0.8),
|
||||
|
||||
@@ -15,15 +15,11 @@ class CustomeProxyHeaderSettings extends StatelessWidget {
|
||||
dense: true,
|
||||
title: Text(
|
||||
"headers_settings_tile_title".tr(),
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500),
|
||||
),
|
||||
subtitle: Text(
|
||||
"headers_settings_tile_subtitle".tr(),
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: context.colorScheme.onSurfaceSecondary,
|
||||
),
|
||||
style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary),
|
||||
),
|
||||
onTap: () => context.pushRoute(const HeaderSettingsRoute()),
|
||||
);
|
||||
|
||||
@@ -48,9 +48,7 @@ class LanguageSettings extends HookConsumerWidget {
|
||||
filteredLocaleEntries.value = localeEntries;
|
||||
} else {
|
||||
filteredLocaleEntries.value = localeEntries
|
||||
.where(
|
||||
(entry) => entry.key.toLowerCase().contains(searchTerm.toLowerCase()),
|
||||
)
|
||||
.where((entry) => entry.key.toLowerCase().contains(searchTerm.toLowerCase()))
|
||||
.toList();
|
||||
}
|
||||
});
|
||||
@@ -61,17 +59,14 @@ class LanguageSettings extends HookConsumerWidget {
|
||||
onSearch('');
|
||||
}
|
||||
|
||||
useEffect(
|
||||
() {
|
||||
void searchListener() => onSearch(searchController.text);
|
||||
searchController.addListener(searchListener);
|
||||
return () {
|
||||
searchController.removeListener(searchListener);
|
||||
debounceTimer.value?.cancel();
|
||||
};
|
||||
},
|
||||
[searchController],
|
||||
);
|
||||
useEffect(() {
|
||||
void searchListener() => onSearch(searchController.text);
|
||||
searchController.addListener(searchListener);
|
||||
return () {
|
||||
searchController.removeListener(searchListener);
|
||||
debounceTimer.value?.cancel();
|
||||
};
|
||||
}, [searchController]);
|
||||
|
||||
return SafeArea(
|
||||
child: Column(
|
||||
@@ -111,11 +106,7 @@ class LanguageSettings extends HookConsumerWidget {
|
||||
_LanguageApplyButton(
|
||||
isDisabled: isButtonDisabled,
|
||||
isLoading: isLoading.value,
|
||||
onPressed: () => _applyLanguageChange(
|
||||
context,
|
||||
selectedLocale,
|
||||
isLoading,
|
||||
),
|
||||
onPressed: () => _applyLanguageChange(context, selectedLocale, isLoading),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -140,9 +131,7 @@ class _LanguageSearchBar extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.only(top: 16, bottom: 8, left: 50, right: 50),
|
||||
decoration: BoxDecoration(
|
||||
color: context.colorScheme.surface,
|
||||
),
|
||||
decoration: BoxDecoration(color: context.colorScheme.surface),
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(24)),
|
||||
@@ -162,10 +151,7 @@ class _LanguageSearchBar extends StatelessWidget {
|
||||
hintText: 'language_search_hint'.t(context: context),
|
||||
prefixIcon: const Icon(Icons.search_rounded),
|
||||
suffixIcon: controller.text.isNotEmpty
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.clear_rounded),
|
||||
onPressed: onClear,
|
||||
)
|
||||
? IconButton(icon: const Icon(Icons.clear_rounded), onPressed: onClear)
|
||||
: null,
|
||||
controller: controller,
|
||||
onChanged: onChanged,
|
||||
@@ -186,24 +172,16 @@ class _LanguageNotFound extends StatelessWidget {
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.search_off_rounded,
|
||||
size: 64,
|
||||
color: context.colorScheme.onSurface.withValues(alpha: 0.4),
|
||||
),
|
||||
Icon(Icons.search_off_rounded, size: 64, color: context.colorScheme.onSurface.withValues(alpha: 0.4)),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'language_no_results_title'.t(context: context),
|
||||
style: context.textTheme.titleMedium?.copyWith(
|
||||
color: context.colorScheme.onSurface,
|
||||
),
|
||||
style: context.textTheme.titleMedium?.copyWith(color: context.colorScheme.onSurface),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'language_no_results_subtitle'.t(context: context),
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: context.colorScheme.onSurface.withValues(alpha: 0.8),
|
||||
),
|
||||
style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurface.withValues(alpha: 0.8)),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -212,11 +190,7 @@ class _LanguageNotFound extends StatelessWidget {
|
||||
}
|
||||
|
||||
class _LanguageApplyButton extends StatelessWidget {
|
||||
const _LanguageApplyButton({
|
||||
required this.isDisabled,
|
||||
required this.isLoading,
|
||||
required this.onPressed,
|
||||
});
|
||||
const _LanguageApplyButton({required this.isDisabled, required this.isLoading, required this.onPressed});
|
||||
|
||||
final bool isDisabled;
|
||||
final bool isLoading;
|
||||
@@ -225,9 +199,7 @@ class _LanguageApplyButton extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: context.colorScheme.surface,
|
||||
),
|
||||
decoration: BoxDecoration(color: context.colorScheme.surface),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: SizedBox(
|
||||
@@ -236,18 +208,10 @@ class _LanguageApplyButton extends StatelessWidget {
|
||||
child: ElevatedButton(
|
||||
onPressed: isDisabled ? null : onPressed,
|
||||
child: isLoading
|
||||
? const SizedBox.square(
|
||||
dimension: 24,
|
||||
child: CircularProgressIndicator(
|
||||
strokeWidth: 2,
|
||||
),
|
||||
)
|
||||
? const SizedBox.square(dimension: 24, child: CircularProgressIndicator(strokeWidth: 2))
|
||||
: Text(
|
||||
'setting_languages_apply'.t(context: context),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16.0,
|
||||
),
|
||||
style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 16.0),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -273,20 +237,12 @@ class _LanguageItem extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4.0,
|
||||
horizontal: 8.0,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0),
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: context.colorScheme.surfaceContainerLowest.withValues(alpha: .6),
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(16.0),
|
||||
),
|
||||
border: Border.all(
|
||||
color: context.colorScheme.outlineVariant.withValues(alpha: .4),
|
||||
width: 1.0,
|
||||
),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
|
||||
border: Border.all(color: context.colorScheme.outlineVariant.withValues(alpha: .4), width: 1.0),
|
||||
),
|
||||
child: ListTile(
|
||||
title: Text(
|
||||
@@ -296,22 +252,12 @@ class _LanguageItem extends StatelessWidget {
|
||||
color: isSelected ? context.colorScheme.primary : context.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
trailing: isSelected
|
||||
? Icon(
|
||||
Icons.check,
|
||||
color: context.colorScheme.primary,
|
||||
size: 20,
|
||||
)
|
||||
: null,
|
||||
trailing: isSelected ? Icon(Icons.check, color: context.colorScheme.primary, size: 20) : null,
|
||||
onTap: onTap,
|
||||
selected: isSelected,
|
||||
selectedTileColor: context.colorScheme.primary.withValues(alpha: .15),
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(16.0)),
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
),
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -14,13 +14,10 @@ class LocalStorageSettings extends HookConsumerWidget {
|
||||
final isarDb = ref.watch(dbProvider);
|
||||
final cacheItemCount = useState(0);
|
||||
|
||||
useEffect(
|
||||
() {
|
||||
cacheItemCount.value = isarDb.duplicatedAssets.countSync();
|
||||
return null;
|
||||
},
|
||||
[],
|
||||
);
|
||||
useEffect(() {
|
||||
cacheItemCount.value = isarDb.duplicatedAssets.countSync();
|
||||
return null;
|
||||
}, []);
|
||||
|
||||
void clearCache() async {
|
||||
await isarDb.writeTxn(() => isarDb.duplicatedAssets.clear());
|
||||
@@ -32,15 +29,11 @@ class LocalStorageSettings extends HookConsumerWidget {
|
||||
dense: true,
|
||||
title: Text(
|
||||
"cache_settings_duplicated_assets_title",
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500),
|
||||
).tr(namedArgs: {'count': "${cacheItemCount.value}"}),
|
||||
subtitle: Text(
|
||||
"cache_settings_duplicated_assets_subtitle",
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: context.colorScheme.onSurfaceSecondary,
|
||||
),
|
||||
style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary),
|
||||
).tr(),
|
||||
trailing: TextButton(
|
||||
onPressed: cacheItemCount.value > 0 ? clearCache : null,
|
||||
|
||||
@@ -97,10 +97,7 @@ class EndpointInputState extends ConsumerState<EndpointInput> {
|
||||
color: Colors.red,
|
||||
alignment: Alignment.centerRight,
|
||||
padding: const EdgeInsets.only(right: 16),
|
||||
child: const Icon(
|
||||
Icons.delete,
|
||||
color: Colors.white,
|
||||
),
|
||||
child: const Icon(Icons.delete, color: Colors.white),
|
||||
),
|
||||
child: ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
@@ -120,27 +117,19 @@ class EndpointInputState extends ConsumerState<EndpointInput> {
|
||||
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||
validator: validateUrl,
|
||||
keyboardType: TextInputType.url,
|
||||
style: const TextStyle(
|
||||
fontFamily: 'Inconsolata',
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14,
|
||||
),
|
||||
style: const TextStyle(fontFamily: 'Inconsolata', fontWeight: FontWeight.w600, fontSize: 14),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'http(s)://immich.domain.com',
|
||||
contentPadding: const EdgeInsets.all(16),
|
||||
filled: true,
|
||||
fillColor: context.colorScheme.surfaceContainer,
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(16)),
|
||||
),
|
||||
border: const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(16))),
|
||||
errorBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.red[300]!),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||
),
|
||||
disabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: context.isDarkTheme ? Colors.grey[900]! : Colors.grey[300]!,
|
||||
),
|
||||
borderSide: BorderSide(color: context.isDarkTheme ? Colors.grey[900]! : Colors.grey[300]!),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -17,9 +17,7 @@ class ExternalNetworkPreference extends HookConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final entries = useState(
|
||||
[const AuxilaryEndpoint(url: '', status: AuxCheckStatus.unknown)],
|
||||
);
|
||||
final entries = useState([const AuxilaryEndpoint(url: '', status: AuxCheckStatus.unknown)]);
|
||||
final canSave = useState(false);
|
||||
|
||||
saveEndpointList() {
|
||||
@@ -29,10 +27,7 @@ class ExternalNetworkPreference extends HookConsumerWidget {
|
||||
|
||||
final jsonString = jsonEncode(endpointList);
|
||||
|
||||
Store.put(
|
||||
StoreKey.externalEndpointList,
|
||||
jsonString,
|
||||
);
|
||||
Store.put(StoreKey.externalEndpointList, jsonString);
|
||||
}
|
||||
|
||||
updateValidationStatus(String url, int index, AuxCheckStatus status) {
|
||||
@@ -59,11 +54,7 @@ class ExternalNetworkPreference extends HookConsumerWidget {
|
||||
saveEndpointList();
|
||||
}
|
||||
|
||||
Widget proxyDecorator(
|
||||
Widget child,
|
||||
int index,
|
||||
Animation<double> animation,
|
||||
) {
|
||||
Widget proxyDecorator(Widget child, int index, Animation<double> animation) {
|
||||
return AnimatedBuilder(
|
||||
animation: animation,
|
||||
builder: (BuildContext context, Widget? child) {
|
||||
@@ -77,20 +68,17 @@ class ExternalNetworkPreference extends HookConsumerWidget {
|
||||
);
|
||||
}
|
||||
|
||||
useEffect(
|
||||
() {
|
||||
final jsonString = Store.tryGet(StoreKey.externalEndpointList);
|
||||
useEffect(() {
|
||||
final jsonString = Store.tryGet(StoreKey.externalEndpointList);
|
||||
|
||||
if (jsonString == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final List<dynamic> jsonList = jsonDecode(jsonString);
|
||||
entries.value = jsonList.map((e) => AuxilaryEndpoint.fromJson(e)).toList();
|
||||
if (jsonString == null) {
|
||||
return null;
|
||||
},
|
||||
const [],
|
||||
);
|
||||
}
|
||||
|
||||
final List<dynamic> jsonList = jsonDecode(jsonString);
|
||||
entries.value = jsonList.map((e) => AuxilaryEndpoint.fromJson(e)).toList();
|
||||
return null;
|
||||
}, const []);
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
@@ -99,21 +87,14 @@ class ExternalNetworkPreference extends HookConsumerWidget {
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||
color: context.colorScheme.surfaceContainerLow,
|
||||
border: Border.all(
|
||||
color: context.colorScheme.surfaceContainerHighest,
|
||||
width: 1,
|
||||
),
|
||||
border: Border.all(color: context.colorScheme.surfaceContainerHighest, width: 1),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
bottom: -36,
|
||||
right: -36,
|
||||
child: Icon(
|
||||
Icons.dns_rounded,
|
||||
size: 120,
|
||||
color: context.primaryColor.withValues(alpha: 0.05),
|
||||
),
|
||||
child: Icon(Icons.dns_rounded, size: 120, color: context.primaryColor.withValues(alpha: 0.05)),
|
||||
),
|
||||
ListView(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
@@ -121,14 +102,8 @@ class ExternalNetworkPreference extends HookConsumerWidget {
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4.0,
|
||||
horizontal: 24,
|
||||
),
|
||||
child: Text(
|
||||
"external_network_sheet_info".tr(),
|
||||
style: context.textTheme.bodyMedium,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 24),
|
||||
child: Text("external_network_sheet_info".tr(), style: context.textTheme.bodyMedium),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Divider(color: context.colorScheme.surfaceContainerHighest),
|
||||
@@ -165,10 +140,7 @@ class ExternalNetworkPreference extends HookConsumerWidget {
|
||||
? () {
|
||||
entries.value = [
|
||||
...entries.value,
|
||||
const AuxilaryEndpoint(
|
||||
url: '',
|
||||
status: AuxCheckStatus.unknown,
|
||||
),
|
||||
const AuxilaryEndpoint(url: '', status: AuxCheckStatus.unknown),
|
||||
];
|
||||
}
|
||||
: null,
|
||||
|
||||
@@ -7,19 +7,11 @@ import 'package:immich_mobile/providers/auth.provider.dart';
|
||||
import 'package:immich_mobile/providers/network.provider.dart';
|
||||
|
||||
class LocalNetworkPreference extends HookConsumerWidget {
|
||||
const LocalNetworkPreference({
|
||||
super.key,
|
||||
required this.enabled,
|
||||
});
|
||||
const LocalNetworkPreference({super.key, required this.enabled});
|
||||
|
||||
final bool enabled;
|
||||
|
||||
Future<String?> _showEditDialog(
|
||||
BuildContext context,
|
||||
String title,
|
||||
String hintText,
|
||||
String initialValue,
|
||||
) {
|
||||
Future<String?> _showEditDialog(BuildContext context, String title, String hintText, String initialValue) {
|
||||
final controller = TextEditingController(text: initialValue);
|
||||
|
||||
return showDialog<String>(
|
||||
@@ -29,23 +21,14 @@ class LocalNetworkPreference extends HookConsumerWidget {
|
||||
content: TextField(
|
||||
controller: controller,
|
||||
autofocus: true,
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
hintText: hintText,
|
||||
),
|
||||
decoration: InputDecoration(border: const OutlineInputBorder(), hintText: hintText),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(
|
||||
'cancel'.tr().toUpperCase(),
|
||||
style: const TextStyle(color: Colors.red),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, controller.text),
|
||||
child: Text('save'.tr().toUpperCase()),
|
||||
child: Text('cancel'.tr().toUpperCase(), style: const TextStyle(color: Colors.red)),
|
||||
),
|
||||
TextButton(onPressed: () => Navigator.pop(context, controller.text), child: Text('save'.tr().toUpperCase())),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -56,23 +39,20 @@ class LocalNetworkPreference extends HookConsumerWidget {
|
||||
final wifiNameText = useState("");
|
||||
final localEndpointText = useState("");
|
||||
|
||||
useEffect(
|
||||
() {
|
||||
final wifiName = ref.read(authProvider.notifier).getSavedWifiName();
|
||||
final localEndpoint = ref.read(authProvider.notifier).getSavedLocalEndpoint();
|
||||
useEffect(() {
|
||||
final wifiName = ref.read(authProvider.notifier).getSavedWifiName();
|
||||
final localEndpoint = ref.read(authProvider.notifier).getSavedLocalEndpoint();
|
||||
|
||||
if (wifiName != null) {
|
||||
wifiNameText.value = wifiName;
|
||||
}
|
||||
if (wifiName != null) {
|
||||
wifiNameText.value = wifiName;
|
||||
}
|
||||
|
||||
if (localEndpoint != null) {
|
||||
localEndpointText.value = localEndpoint;
|
||||
}
|
||||
if (localEndpoint != null) {
|
||||
localEndpointText.value = localEndpoint;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
[],
|
||||
);
|
||||
return null;
|
||||
}, []);
|
||||
|
||||
saveWifiName(String wifiName) {
|
||||
wifiNameText.value = wifiName;
|
||||
@@ -85,12 +65,7 @@ class LocalNetworkPreference extends HookConsumerWidget {
|
||||
}
|
||||
|
||||
handleEditWifiName() async {
|
||||
final wifiName = await _showEditDialog(
|
||||
context,
|
||||
"wifi_name".tr(),
|
||||
"your_wifi_name".tr(),
|
||||
wifiNameText.value,
|
||||
);
|
||||
final wifiName = await _showEditDialog(context, "wifi_name".tr(), "your_wifi_name".tr(), wifiNameText.value);
|
||||
|
||||
if (wifiName != null) {
|
||||
await saveWifiName(wifiName);
|
||||
@@ -146,21 +121,14 @@ class LocalNetworkPreference extends HookConsumerWidget {
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||
color: context.colorScheme.surfaceContainerLow,
|
||||
border: Border.all(
|
||||
color: context.colorScheme.surfaceContainerHighest,
|
||||
width: 1,
|
||||
),
|
||||
border: Border.all(color: context.colorScheme.surfaceContainerHighest, width: 1),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
bottom: -36,
|
||||
right: -36,
|
||||
child: Icon(
|
||||
Icons.home_outlined,
|
||||
size: 120,
|
||||
color: context.primaryColor.withValues(alpha: 0.05),
|
||||
),
|
||||
child: Icon(Icons.home_outlined, size: 120, color: context.primaryColor.withValues(alpha: 0.05)),
|
||||
),
|
||||
ListView(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
@@ -168,19 +136,11 @@ class LocalNetworkPreference extends HookConsumerWidget {
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 4.0,
|
||||
horizontal: 24,
|
||||
),
|
||||
child: Text(
|
||||
"local_network_sheet_info".tr(),
|
||||
style: context.textTheme.bodyMedium,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 24),
|
||||
child: Text("local_network_sheet_info".tr(), style: context.textTheme.bodyMedium),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Divider(
|
||||
color: context.colorScheme.surfaceContainerHighest,
|
||||
),
|
||||
Divider(color: context.colorScheme.surfaceContainerHighest),
|
||||
ListTile(
|
||||
enabled: enabled,
|
||||
contentPadding: const EdgeInsets.only(left: 24, right: 8),
|
||||
@@ -223,9 +183,7 @@ class LocalNetworkPreference extends HookConsumerWidget {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24.0,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||
child: SizedBox(
|
||||
height: 48,
|
||||
child: OutlinedButton.icon(
|
||||
|
||||
@@ -77,15 +77,12 @@ class NetworkingSettings extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(
|
||||
() {
|
||||
if (featureEnabled.value == true) {
|
||||
checkWifiReadPermission();
|
||||
}
|
||||
return null;
|
||||
},
|
||||
[featureEnabled.value],
|
||||
);
|
||||
useEffect(() {
|
||||
if (featureEnabled.value == true) {
|
||||
checkWifiReadPermission();
|
||||
}
|
||||
return null;
|
||||
}, [featureEnabled.value]);
|
||||
|
||||
return ListView(
|
||||
padding: const EdgeInsets.only(bottom: 96),
|
||||
@@ -104,20 +101,12 @@ class NetworkingSettings extends HookConsumerWidget {
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||
side: BorderSide(
|
||||
color: context.colorScheme.surfaceContainerHighest,
|
||||
width: 1,
|
||||
),
|
||||
side: BorderSide(color: context.colorScheme.surfaceContainerHighest, width: 1),
|
||||
),
|
||||
child: ListTile(
|
||||
leading: currentEndpoint != null
|
||||
? const Icon(
|
||||
Icons.check_circle_rounded,
|
||||
color: Colors.green,
|
||||
)
|
||||
: const Icon(
|
||||
Icons.circle_outlined,
|
||||
),
|
||||
? const Icon(Icons.check_circle_rounded, color: Colors.green)
|
||||
: const Icon(Icons.circle_outlined),
|
||||
title: Text(
|
||||
currentEndpoint ?? "--",
|
||||
style: TextStyle(
|
||||
@@ -132,9 +121,7 @@ class NetworkingSettings extends HookConsumerWidget {
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10.0),
|
||||
child: Divider(
|
||||
color: context.colorScheme.surfaceContainerHighest,
|
||||
),
|
||||
child: Divider(color: context.colorScheme.surfaceContainerHighest),
|
||||
),
|
||||
SettingsSwitchListTile(
|
||||
enabled: true,
|
||||
@@ -144,35 +131,21 @@ class NetworkingSettings extends HookConsumerWidget {
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 8, left: 16, bottom: 16),
|
||||
child: NetworkPreferenceTitle(
|
||||
title: "local_network".tr().toUpperCase(),
|
||||
icon: Icons.home_outlined,
|
||||
),
|
||||
),
|
||||
LocalNetworkPreference(
|
||||
enabled: featureEnabled.value,
|
||||
child: NetworkPreferenceTitle(title: "local_network".tr().toUpperCase(), icon: Icons.home_outlined),
|
||||
),
|
||||
LocalNetworkPreference(enabled: featureEnabled.value),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 32, left: 16, bottom: 16),
|
||||
child: NetworkPreferenceTitle(
|
||||
title: "external_network".tr().toUpperCase(),
|
||||
icon: Icons.dns_outlined,
|
||||
),
|
||||
),
|
||||
ExternalNetworkPreference(
|
||||
enabled: featureEnabled.value,
|
||||
child: NetworkPreferenceTitle(title: "external_network".tr().toUpperCase(), icon: Icons.dns_outlined),
|
||||
),
|
||||
ExternalNetworkPreference(enabled: featureEnabled.value),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NetworkPreferenceTitle extends StatelessWidget {
|
||||
const NetworkPreferenceTitle({
|
||||
super.key,
|
||||
required this.icon,
|
||||
required this.title,
|
||||
});
|
||||
const NetworkPreferenceTitle({super.key, required this.icon, required this.title});
|
||||
|
||||
final IconData icon;
|
||||
final String title;
|
||||
@@ -181,10 +154,7 @@ class NetworkPreferenceTitle extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
color: context.colorScheme.onSurface.withAlpha(150),
|
||||
),
|
||||
Icon(icon, color: context.colorScheme.onSurface.withAlpha(150)),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
title,
|
||||
@@ -199,58 +169,37 @@ class NetworkPreferenceTitle extends StatelessWidget {
|
||||
}
|
||||
|
||||
class NetworkStatusIcon extends StatelessWidget {
|
||||
const NetworkStatusIcon({
|
||||
super.key,
|
||||
required this.status,
|
||||
this.enabled = true,
|
||||
}) : super();
|
||||
const NetworkStatusIcon({super.key, required this.status, this.enabled = true}) : super();
|
||||
|
||||
final AuxCheckStatus status;
|
||||
final bool enabled;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: _buildIcon(context),
|
||||
);
|
||||
return AnimatedSwitcher(duration: const Duration(milliseconds: 200), child: _buildIcon(context));
|
||||
}
|
||||
|
||||
Widget _buildIcon(BuildContext context) => switch (status) {
|
||||
AuxCheckStatus.loading => Padding(
|
||||
padding: const EdgeInsets.only(left: 4.0),
|
||||
child: SizedBox(
|
||||
width: 18,
|
||||
height: 18,
|
||||
child: CircularProgressIndicator(
|
||||
color: context.primaryColor,
|
||||
strokeWidth: 2,
|
||||
key: const ValueKey('loading'),
|
||||
),
|
||||
AuxCheckStatus.loading => Padding(
|
||||
padding: const EdgeInsets.only(left: 4.0),
|
||||
child: SizedBox(
|
||||
width: 18,
|
||||
height: 18,
|
||||
child: CircularProgressIndicator(color: context.primaryColor, strokeWidth: 2, key: const ValueKey('loading')),
|
||||
),
|
||||
),
|
||||
AuxCheckStatus.valid =>
|
||||
enabled
|
||||
? const Icon(Icons.check_circle_rounded, color: Colors.green, key: ValueKey('success'))
|
||||
: Icon(
|
||||
Icons.check_circle_rounded,
|
||||
color: context.colorScheme.onSurface.withAlpha(100),
|
||||
key: const ValueKey('success'),
|
||||
),
|
||||
),
|
||||
AuxCheckStatus.valid => enabled
|
||||
? const Icon(
|
||||
Icons.check_circle_rounded,
|
||||
color: Colors.green,
|
||||
key: ValueKey('success'),
|
||||
)
|
||||
: Icon(
|
||||
Icons.check_circle_rounded,
|
||||
color: context.colorScheme.onSurface.withAlpha(100),
|
||||
key: const ValueKey('success'),
|
||||
),
|
||||
AuxCheckStatus.error => enabled
|
||||
? const Icon(
|
||||
Icons.error_rounded,
|
||||
color: Colors.red,
|
||||
key: ValueKey('error'),
|
||||
)
|
||||
: const Icon(
|
||||
Icons.error_rounded,
|
||||
color: Colors.grey,
|
||||
key: ValueKey('error'),
|
||||
),
|
||||
_ => const Icon(Icons.circle_outlined, key: ValueKey('unknown')),
|
||||
};
|
||||
AuxCheckStatus.error =>
|
||||
enabled
|
||||
? const Icon(Icons.error_rounded, color: Colors.red, key: ValueKey('error'))
|
||||
: const Icon(Icons.error_rounded, color: Colors.grey, key: ValueKey('error')),
|
||||
_ => const Icon(Icons.circle_outlined, key: ValueKey('unknown')),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -12,9 +12,7 @@ import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
class NotificationSetting extends HookConsumerWidget {
|
||||
const NotificationSetting({
|
||||
super.key,
|
||||
});
|
||||
const NotificationSetting({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@@ -39,14 +37,8 @@ class NotificationSetting extends HookConsumerWidget {
|
||||
builder: (ctx) => AlertDialog(
|
||||
content: const Text('notification_permission_dialog_content').tr(),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: const Text('cancel').tr(),
|
||||
onPressed: () => ctx.pop(),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => openAppNotificationSettings(ctx),
|
||||
child: const Text('settings').tr(),
|
||||
),
|
||||
TextButton(child: const Text('cancel').tr(), onPressed: () => ctx.pop()),
|
||||
TextButton(onPressed: () => openAppNotificationSettings(ctx), child: const Text('settings').tr()),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -63,10 +55,10 @@ class NotificationSetting extends HookConsumerWidget {
|
||||
buttonText: 'notification_permission_list_tile_enable_button'.tr(),
|
||||
onButtonTap: () =>
|
||||
ref.watch(notificationPermissionProvider.notifier).requestNotificationPermission().then((permission) {
|
||||
if (permission == PermissionStatus.permanentlyDenied) {
|
||||
showPermissionsDialog();
|
||||
}
|
||||
}),
|
||||
if (permission == PermissionStatus.permanentlyDenied) {
|
||||
showPermissionsDialog();
|
||||
}
|
||||
}),
|
||||
),
|
||||
SettingsSwitchListTile(
|
||||
enabled: hasPermission,
|
||||
|
||||
@@ -8,9 +8,7 @@ import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
|
||||
import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
|
||||
|
||||
class HapticSetting extends HookConsumerWidget {
|
||||
const HapticSetting({
|
||||
super.key,
|
||||
});
|
||||
const HapticSetting({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
||||
@@ -4,20 +4,12 @@ import 'package:immich_mobile/widgets/settings/preference_settings/theme_setting
|
||||
import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart';
|
||||
|
||||
class PreferenceSetting extends StatelessWidget {
|
||||
const PreferenceSetting({
|
||||
super.key,
|
||||
});
|
||||
const PreferenceSetting({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const preferenceSettings = [
|
||||
ThemeSetting(),
|
||||
HapticSetting(),
|
||||
];
|
||||
const preferenceSettings = [ThemeSetting(), HapticSetting()];
|
||||
|
||||
return const SettingsSubPageScaffold(
|
||||
settings: preferenceSettings,
|
||||
showDivider: true,
|
||||
);
|
||||
return const SettingsSubPageScaffold(settings: preferenceSettings, showDivider: true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,7 @@ import 'package:immich_mobile/theme/dynamic_theme.dart';
|
||||
import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
|
||||
|
||||
class PrimaryColorSetting extends HookConsumerWidget {
|
||||
const PrimaryColorSetting({
|
||||
super.key,
|
||||
});
|
||||
const PrimaryColorSetting({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
@@ -70,20 +68,14 @@ class PrimaryColorSetting extends HookConsumerWidget {
|
||||
Container(
|
||||
height: tileSize,
|
||||
width: tileSize,
|
||||
decoration: BoxDecoration(
|
||||
color: bottomColor,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(100)),
|
||||
),
|
||||
decoration: BoxDecoration(color: bottomColor, borderRadius: const BorderRadius.all(Radius.circular(100))),
|
||||
),
|
||||
Container(
|
||||
height: tileSize / 2,
|
||||
width: tileSize,
|
||||
decoration: BoxDecoration(
|
||||
color: topColor,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(100),
|
||||
topRight: Radius.circular(100),
|
||||
),
|
||||
borderRadius: const BorderRadius.only(topLeft: Radius.circular(100), topRight: Radius.circular(100)),
|
||||
),
|
||||
),
|
||||
if (showSelector)
|
||||
@@ -99,11 +91,7 @@ class PrimaryColorSetting extends HookConsumerWidget {
|
||||
),
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(3),
|
||||
child: Icon(
|
||||
Icons.check_rounded,
|
||||
color: Colors.white,
|
||||
size: 25,
|
||||
),
|
||||
child: Icon(Icons.check_rounded, color: Colors.white, size: 25),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -118,10 +106,7 @@ class PrimaryColorSetting extends HookConsumerWidget {
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
"theme_setting_primary_color_title".tr(),
|
||||
style: context.textTheme.titleLarge,
|
||||
),
|
||||
child: Text("theme_setting_primary_color_title".tr(), style: context.textTheme.titleLarge),
|
||||
),
|
||||
if (DynamicTheme.isAvailable)
|
||||
Container(
|
||||
@@ -132,15 +117,10 @@ class PrimaryColorSetting extends HookConsumerWidget {
|
||||
dense: true,
|
||||
activeColor: context.primaryColor,
|
||||
tileColor: context.colorScheme.surfaceContainerHigh,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(15)),
|
||||
),
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(15))),
|
||||
title: Text(
|
||||
'theme_setting_system_primary_color_title'.tr(),
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
height: 1.5,
|
||||
),
|
||||
style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500, height: 1.5),
|
||||
),
|
||||
value: systemPrimaryColorSetting.value,
|
||||
onChanged: onUseSystemColorChange,
|
||||
@@ -175,10 +155,7 @@ class PrimaryColorSetting extends HookConsumerWidget {
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
builder: (BuildContext ctx) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 0),
|
||||
child: bottomSheetContent(),
|
||||
);
|
||||
return Padding(padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 0), child: bottomSheetContent());
|
||||
},
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
@@ -190,9 +167,7 @@ class PrimaryColorSetting extends HookConsumerWidget {
|
||||
children: [
|
||||
Text(
|
||||
"theme_setting_primary_color_title".tr(),
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500),
|
||||
),
|
||||
Text(
|
||||
"theme_setting_primary_color_subtitle".tr(),
|
||||
|
||||
@@ -11,9 +11,7 @@ import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
|
||||
import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
|
||||
|
||||
class ThemeSetting extends HookConsumerWidget {
|
||||
const ThemeSetting({
|
||||
super.key,
|
||||
});
|
||||
const ThemeSetting({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
||||
@@ -31,12 +31,7 @@ class SettingsButtonListTile extends StatelessWidget {
|
||||
horizontalTitleGap: 20,
|
||||
isThreeLine: true,
|
||||
leading: Icon(icon, color: iconColor),
|
||||
title: Text(
|
||||
title,
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
title: Text(title, style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500)),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -44,9 +39,7 @@ class SettingsButtonListTile extends StatelessWidget {
|
||||
if (subtileText != null)
|
||||
Text(
|
||||
subtileText!,
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: context.colorScheme.onSurfaceSecondary,
|
||||
),
|
||||
style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary),
|
||||
),
|
||||
if (subtitle != null) subtitle!,
|
||||
const SizedBox(height: 6),
|
||||
|
||||
@@ -19,21 +19,15 @@ class SettingsCard extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
child: Card(
|
||||
elevation: 0,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
color: context.colorScheme.surfaceContainer,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(16)),
|
||||
),
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))),
|
||||
margin: const EdgeInsets.symmetric(vertical: 4.0),
|
||||
child: ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0,
|
||||
),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||
leading: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||
@@ -44,15 +38,9 @@ class SettingsCard extends StatelessWidget {
|
||||
),
|
||||
title: Text(
|
||||
title,
|
||||
style: context.textTheme.titleMedium!.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: context.primaryColor,
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
subtitle,
|
||||
style: context.textTheme.labelLarge,
|
||||
style: context.textTheme.titleMedium!.copyWith(fontWeight: FontWeight.w600, color: context.primaryColor),
|
||||
),
|
||||
subtitle: Text(subtitle, style: context.textTheme.labelLarge),
|
||||
onTap: () => context.pushRoute(settingRoute),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -13,12 +13,7 @@ class SettingsRadioListTile<T> extends StatelessWidget {
|
||||
final T groupBy;
|
||||
final void Function(T?) onRadioChanged;
|
||||
|
||||
const SettingsRadioListTile({
|
||||
super.key,
|
||||
required this.groups,
|
||||
required this.groupBy,
|
||||
required this.onRadioChanged,
|
||||
});
|
||||
const SettingsRadioListTile({super.key, required this.groups, required this.groupBy, required this.onRadioChanged});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -29,12 +24,7 @@ class SettingsRadioListTile<T> extends StatelessWidget {
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
dense: true,
|
||||
activeColor: context.primaryColor,
|
||||
title: Text(
|
||||
g.title,
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
title: Text(g.title, style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500)),
|
||||
value: g.value,
|
||||
groupValue: groupBy,
|
||||
onChanged: onRadioChanged,
|
||||
|
||||
@@ -28,12 +28,7 @@ class SettingsSliderListTile extends StatelessWidget {
|
||||
return ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
dense: true,
|
||||
title: Text(
|
||||
text,
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
title: Text(text, style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500)),
|
||||
subtitle: Slider(
|
||||
value: valueNotifier.value.toDouble(),
|
||||
onChanged: (double v) => valueNotifier.value = v.toInt(),
|
||||
|
||||
@@ -4,11 +4,7 @@ class SettingsSubPageScaffold extends StatelessWidget {
|
||||
final List<Widget> settings;
|
||||
final bool showDivider;
|
||||
|
||||
const SettingsSubPageScaffold({
|
||||
super.key,
|
||||
required this.settings,
|
||||
this.showDivider = false,
|
||||
});
|
||||
const SettingsSubPageScaffold({super.key, required this.settings, this.showDivider = false});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -18,11 +14,7 @@ class SettingsSubPageScaffold extends StatelessWidget {
|
||||
itemBuilder: (ctx, index) => settings[index],
|
||||
separatorBuilder: (context, index) => showDivider
|
||||
? const Column(
|
||||
children: [
|
||||
SizedBox(height: 5),
|
||||
Divider(height: 10, indent: 15, endIndent: 15),
|
||||
SizedBox(height: 15),
|
||||
],
|
||||
children: [SizedBox(height: 5), Divider(height: 10, indent: 15, endIndent: 15), SizedBox(height: 15)],
|
||||
)
|
||||
: const SizedBox(height: 10),
|
||||
);
|
||||
|
||||
@@ -4,10 +4,7 @@ import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
class SettingsSubTitle extends StatelessWidget {
|
||||
final String title;
|
||||
|
||||
const SettingsSubTitle({
|
||||
super.key,
|
||||
required this.title,
|
||||
});
|
||||
const SettingsSubTitle({super.key, required this.title});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -15,10 +12,7 @@ class SettingsSubTitle extends StatelessWidget {
|
||||
padding: const EdgeInsets.only(left: 20),
|
||||
child: Text(
|
||||
title,
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
color: context.primaryColor,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
style: context.textTheme.bodyLarge?.copyWith(color: context.primaryColor, fontWeight: FontWeight.w700),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -42,15 +42,11 @@ class SettingsSwitchListTile extends StatelessWidget {
|
||||
onChanged: onSwitchChanged,
|
||||
activeColor: enabled ? context.primaryColor : context.themeData.disabledColor,
|
||||
dense: true,
|
||||
secondary: icon != null
|
||||
? Icon(
|
||||
icon!,
|
||||
color: valueNotifier.value ? context.primaryColor : null,
|
||||
)
|
||||
: null,
|
||||
secondary: icon != null ? Icon(icon!, color: valueNotifier.value ? context.primaryColor : null) : null,
|
||||
title: Text(
|
||||
title,
|
||||
style: titleStyle ??
|
||||
style:
|
||||
titleStyle ??
|
||||
context.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: enabled ? null : context.themeData.disabledColor,
|
||||
@@ -60,7 +56,8 @@ class SettingsSwitchListTile extends StatelessWidget {
|
||||
subtitle: subtitle != null
|
||||
? Text(
|
||||
subtitle!,
|
||||
style: subtitleStyle ??
|
||||
style:
|
||||
subtitleStyle ??
|
||||
context.textTheme.bodyMedium?.copyWith(
|
||||
color: enabled ? context.colorScheme.onSurfaceSecondary : context.themeData.disabledColor,
|
||||
),
|
||||
|
||||
@@ -30,24 +30,15 @@ class _SslClientCertSettingsState extends State<SslClientCertSettings> {
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 20),
|
||||
horizontalTitleGap: 20,
|
||||
isThreeLine: true,
|
||||
title: Text(
|
||||
"client_cert_title".tr(),
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
title: Text("client_cert_title".tr(), style: context.textTheme.bodyLarge?.copyWith(fontWeight: FontWeight.w500)),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"client_cert_subtitle".tr(),
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: context.colorScheme.onSurfaceSecondary,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 6,
|
||||
style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
@@ -57,9 +48,7 @@ class _SslClientCertSettingsState extends State<SslClientCertSettings> {
|
||||
onPressed: widget.isLoggedIn ? null : () => importCert(context),
|
||||
child: Text("client_cert_import".tr()),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 15,
|
||||
),
|
||||
const SizedBox(width: 15),
|
||||
ElevatedButton(
|
||||
onPressed: widget.isLoggedIn || !isCertExist ? null : () async => await removeCert(context),
|
||||
child: Text("remove".tr()),
|
||||
@@ -76,39 +65,25 @@ class _SslClientCertSettingsState extends State<SslClientCertSettings> {
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
content: Text(message),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => ctx.pop(),
|
||||
child: Text("client_cert_dialog_msg_confirm".tr()),
|
||||
),
|
||||
],
|
||||
actions: [TextButton(onPressed: () => ctx.pop(), child: Text("client_cert_dialog_msg_confirm".tr()))],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> storeCert(
|
||||
BuildContext context,
|
||||
Uint8List data,
|
||||
String? password,
|
||||
) async {
|
||||
Future<void> storeCert(BuildContext context, Uint8List data, String? password) async {
|
||||
if (password != null && password.isEmpty) {
|
||||
password = null;
|
||||
}
|
||||
final cert = SSLClientCertStoreVal(data, password);
|
||||
// Test whether the certificate is valid
|
||||
final isCertValid = HttpSSLCertOverride.setClientCert(
|
||||
SecurityContext(withTrustedRoots: true),
|
||||
cert,
|
||||
);
|
||||
final isCertValid = HttpSSLCertOverride.setClientCert(SecurityContext(withTrustedRoots: true), cert);
|
||||
if (!isCertValid) {
|
||||
showMessage(context, "client_cert_invalid_msg".tr());
|
||||
return;
|
||||
}
|
||||
await cert.save();
|
||||
HttpSSLOptions.apply();
|
||||
setState(
|
||||
() => isCertExist = true,
|
||||
);
|
||||
setState(() => isCertExist = true);
|
||||
showMessage(context, "client_cert_import_success_msg".tr());
|
||||
}
|
||||
|
||||
@@ -122,9 +97,7 @@ class _SslClientCertSettingsState extends State<SslClientCertSettings> {
|
||||
controller: password,
|
||||
obscureText: true,
|
||||
obscuringCharacter: "*",
|
||||
decoration: InputDecoration(
|
||||
hintText: "client_cert_enter_password".tr(),
|
||||
),
|
||||
decoration: InputDecoration(hintText: "client_cert_enter_password".tr()),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
@@ -139,10 +112,7 @@ class _SslClientCertSettingsState extends State<SslClientCertSettings> {
|
||||
Future<void> importCert(BuildContext ctx) async {
|
||||
FilePickerResult? res = await FilePicker.platform.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: [
|
||||
'p12',
|
||||
'pfx',
|
||||
],
|
||||
allowedExtensions: ['p12', 'pfx'],
|
||||
);
|
||||
if (res != null) {
|
||||
File file = File(res.files.single.path!);
|
||||
@@ -154,9 +124,7 @@ class _SslClientCertSettingsState extends State<SslClientCertSettings> {
|
||||
Future<void> removeCert(BuildContext context) async {
|
||||
await SSLClientCertStoreVal.delete();
|
||||
HttpSSLOptions.apply();
|
||||
setState(
|
||||
() => isCertExist = false,
|
||||
);
|
||||
setState(() => isCertExist = false);
|
||||
showMessage(context, "client_cert_remove_msg".tr());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user